geometry_kit_widgets 0.2.0
geometry_kit_widgets: ^0.2.0 copied to clipboard
Flutter widgets for geometry_kit shapes — CustomPainter-backed, styled, themable, and composable. Includes circle, ellipse, rectangle, triangle, polygon, line, and a multi-shape canvas.
0.2.0 #
Bundles three internal milestones (decorative styling, theme merge + animation, widget clipping) into one published release on top of 0.1.1.
Breaking #
ShapeStyle.strokeWidth,opacity,strokeCap,strokeJoinare now nullable (double?/StrokeCap?/StrokeJoin?). Constructor defaults are unchanged (1.0/1.0/StrokeCap.butt/StrokeJoin.miter), so most call sites compile unmodified. Code that reads these fields unconditionally (e.g.style.strokeWidth.toString()) must adoptstyle.strokeWidth ?? 1.0for the equivalent fallback. Painters inside the package already do this.ShapeStyleTheme.resolve(context, fallback)is nowresolve(context, explicit, {fallback}). Whenexplicitis non-null the resolver returnsexplicit.merge(ambient)— fields the override leavesnullfall back to the ambient theme rather than fully replacing it. Whenexplicitisnull, the ambient theme (or the optionalfallback) is returned, matching the previous behaviour. All built-inGeo*widgets switched fromstyle ?? ShapeStyleTheme.resolve(context, const ShapeStyle())toShapeStyleTheme.resolve(context, style).
Added #
- Decorative styling
ShapeStyle.fillGradientandShapeStyle.strokeGradient— accept any FlutterGradient(linear, radial, sweep). Gradients win over solid colors when both are set on the same channel. Resolved against the painted shape's axis-aligned bounding rect at paint time.ShapeStyle.gradientFilled(Gradient)convenience constructor.PaintBuildertypedef +ShapeStyle.fillPaintBuilder/ShapeStyle.strokePaintBuilder— escape hatch for advanced Skia features (MaskFilter,ImageFilter,BlendMode, custom shaders) without expanding the primary style surface.
- Theme merge + animation
ShapeStyle.merge(ShapeStyle? base)— field-level fallback. Used byShapeStyleTheme.resolveso a child override and an ambient theme combine per-field instead of all-or-nothing.ShapeStyle.lerp(a, b, t)static method. Smoothly interpolates colors and thestrokeWidth/opacityscalars; gradients, dash patterns, enum fields, andPaintBuilders snap att >= 0.5.ShapeStyleTween—Tween<ShapeStyle?>drivingShapeStyle.lerp.AnimatedShapeStylewidget — sibling ofAnimatedDefaultTextStyle. Animates aShapeStyleover aDurationand supplies the interpolated value to descendants throughShapeStyleTheme.
- Widget clipping
shapeToPath(Shape, CoordinateMapper)— top-level helper that returns the canvas-spacePathfor any supportedgeometry_kitshape (Circle,Ellipse,Rectangle,Triangle,Quadrilateral,Polygon,Line). Uses the same path bodies the painters render; throwsUnsupportedErrorfor unhandled shape types.ShapeClipper—CustomClipper<Path>wrapping a shape for direct use with Flutter'sClipPath. Accepts anygeometry_kitShapeplus aCoordinateMapper(defaults toidentity).ShapeWidget— host widget that composes a shape outline, an optional clipped child, and an optionalShapeStyleoverlay. Stroke draws above the clipped child so clip-edge anti-aliasing does not eat the outline.
- Tap + hover interactivity
GeoCircle,GeoEllipse,GeoRectangle,GeoTriangle,GeoQuadrilateral,GeoPolygongain optionalonTapandonHoverChangedparameters. Hit-test is shape-precise viashapeToPath(...).contains(localPosition)— pointer events outside the shape outline are ignored even when they land in the host widget rect.StyledShapegains matchingonTap/onHoverChanged.GeometryCanvaswalks shapes top-down on each pointer event and dispatches to the first hit; the topmost (last-painted) shape wins both tap and hover.- Hover supports both mouse pointers (via
MouseRegion) and stylus/touch hover (viaListener.onPointerHover).GeoLinedoes not expose interaction in v1 (zero-area path makes shape-precise hit-test degenerate; reach for aGeo*filled shape orGestureDetectorif line interaction is needed).
- Examples
- Solar system demo upgraded with radial-gradient sun, gradient-shaded
planets (sun-tracking day/night highlight), pulsing halo via
MaskFilter.blur, and live sliders for orbit speed and planet scale. - Clipping demo gains a "ShapeWidget" section (gradient circle, text in triangle, pentagon over grid) plus an interactive image-clip playground (vertex-count + rotation sliders, source picker for network photo / Flutter logo / gradient).
- Solar system demo upgraded with radial-gradient sun, gradient-shaded
planets (sun-tracking day/night highlight), pulsing halo via
Changed #
ShapeStyle.opacitynow applies only to solid colors — encode alpha into gradient color stops directly.- Painters refactored to share path construction via the new
shapeToPathhelper. Behaviour identical; rectangle'scornerRadiusbranch stays inRectanglePaintersince corner radius is a widget-level concept, not a field ongeo.Rectangle.LinePainterretains its own path build.
Notes #
GeoLinedoes not supportstrokeGradient(zero-area bounds make shader resolution degenerate). Asserted in debug, ignored in release.GeoLinedoes supportstrokePaintBuilderfor blur / mask effects.PaintBuilderequality is by function identity. Use top-level orstaticbuilders when value-equality matters forshouldRepaint.- Field-level theme merging only kicks in when an override explicitly sets
fields to
null(the constructor's non-null defaults otherwise win). Use the raw constructor — notcopyWith— to writenullinto a field, sincecopyWithcannot transition a value to null. ShapeWidgetdoes not auto-fit a shape to widget bounds. Geometry coordinates must already match the rendered widget space, or be transformed viamapper. Sizing happens through the optionalsizeparameter or the parent's bounded constraints.- Clipping a
Lineis degenerate (zero-area path);ShapeClipperdocuments the case rather than asserting. - Hit-test arena:
Geo*widgets andGeometryCanvasuse opaqueGestureDetectors. Taps inside the host widget rect but outside the shape outline are still consumed (no callback fires) — siblings under the widget rect won't see those taps. Set the widget's size tightly to the shape if pass-through is needed.
0.1.1 #
- update git info
0.1.0 #
Initial release. Phase 1 of the widget library.
Widgets #
GeoCircle,GeoEllipse,GeoRectangle,GeoTriangle,GeoQuadrilateral,GeoPolygon,GeoLine— declarativeCustomPainter-backed widgets, each with flat and.fromGeometryconstructors.GeometryCanvas+StyledShape— multi-shape rendering on a single canvas with type-switch dispatch.
Styling #
ShapeStyle— fill, stroke, opacity, dash pattern, cap, join (value equality,copyWith).ShapeStyle.filled/ShapeStyle.strokedconvenience constructors.ShapeStyleTheme—InheritedWidgetfor default style inheritance viaShapeStyle.of(context)/ShapeStyleTheme.resolve.DashPattern— sharedPathMetrics-based dash drawing across all painters.- Color opacity uses
withValues(alpha:)(Flutter 3.27+).
Coordinates #
CoordinateMapper—identity(default, Y-down),yUp(size),centered(size, {yUp}).- Locked into v0.1 so painter signatures stay stable.
Composition #
- Every widget exposes
clipBehavior(defaultClip.hardEdge) — shapes never bleed past widget bounds unless explicitly opted in withClip.none. GeometryCanvas.backgroundColordefaults tonull— transparent canvas layers cleanly over other widgets.- Internal
GeoShapeContainerkeepsClipRect+RepaintBoundary+Semanticsconsistent across every widget.
Other #
- Dartdoc on every public class, constructor, and parameter.
Semantics(label: ...)on every widget for accessibility.RepaintBoundarywraps everyCustomPaint.- Eight passing widget + unit tests.