Skip to content
Open
Show file tree
Hide file tree
Changes from 87 commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
b95ce23
add component based scaling gesture
stilnat Nov 13, 2025
4b8bc31
rename multi scale to scale
stilnat Nov 15, 2025
487e579
Delete my_tests_2 directory
stilnat Nov 15, 2025
01e81cd
Delete my_tests directory
stilnat Nov 15, 2025
8701f00
fix typo and format example
stilnat Nov 16, 2025
8b7105a
fix spelling
stilnat Nov 16, 2025
9723f97
remove TODO
stilnat Nov 16, 2025
28e24bf
format scale dispatcher
stilnat Nov 16, 2025
9c2acf6
remove automatically create multi drag dispatcher in Scale dispatcher
stilnat Nov 16, 2025
975bbdb
remove french
stilnat Nov 16, 2025
bea44fc
format scale dispatcher
stilnat Nov 16, 2025
d6f78cb
test first batch
stilnat Nov 19, 2025
987f977
add new test
stilnat Nov 21, 2025
f7b7153
format and change zoom api
stilnat Nov 21, 2025
cbc2333
fix name not recognised
stilnat Nov 21, 2025
6162fb3
format fix
stilnat Nov 21, 2025
528e665
Merge branch 'main' into scale-gesture
stilnat Nov 21, 2025
f945eea
fix melos analyse
stilnat Nov 21, 2025
8ddce28
format stuff
stilnat Nov 21, 2025
1ce9618
Merge remote-tracking branch 'upstream/main' into scale-gesture
stilnat Nov 21, 2025
c18fd0c
Merge branch 'main' into scale-gesture
spydon Nov 21, 2025
bf69b48
fix vector 2 creations
stilnat Nov 22, 2025
5369f79
add doc
stilnat Nov 22, 2025
c6e9b98
Merge branch 'main' into scale-gesture
stilnat Nov 22, 2025
0d10332
markdown fixes
stilnat Nov 22, 2025
4a8f8ad
Merge branch 'scale-gesture' of https://github.com/stilnat/flame into…
stilnat Nov 22, 2025
4441db2
fix markdown
stilnat Nov 22, 2025
47eb614
rename is scaled
stilnat Nov 22, 2025
64fe308
analyse fix
stilnat Nov 22, 2025
42f0d18
fix lint
stilnat Nov 22, 2025
d5b0086
add stuff about scale drag dispatcher
stilnat Nov 22, 2025
77df27a
add scale drag
stilnat Nov 23, 2025
bd6bd89
make gesture more than one sequence
stilnat Nov 23, 2025
d6995a8
add test
stilnat Nov 23, 2025
9a010d3
update recognizer
stilnat Nov 23, 2025
f1cd9eb
working recognizer pass all tests
stilnat Nov 24, 2025
b78a284
rewrite scale and drag callbacks without testing
stilnat Nov 24, 2025
0ff1070
make test pass without scaledrag callbacks
stilnat Nov 24, 2025
b21afe3
fix drag and scale callbacks to upgrade to scaleDragDispatcher
stilnat Nov 24, 2025
bf1398a
add a bunch of tests
stilnat Nov 24, 2025
58e986f
fix format and stuff
stilnat Nov 24, 2025
38d5e8c
make test include drag better
stilnat Nov 24, 2025
7e65ee6
factor test helper
stilnat Nov 24, 2025
2aa5be5
Merge remote-tracking branch 'upstream/main' into recognizer-v2
stilnat Nov 24, 2025
be53a17
rename scale example to scale drag
stilnat Nov 24, 2025
51b2308
remove french
stilnat Nov 25, 2025
31813e5
make consistent extension
stilnat Nov 25, 2025
5d58587
update doc
stilnat Nov 25, 2025
b34e0ca
fix small stuff
stilnat Nov 25, 2025
233d991
Update doc/flame/inputs/scale_events.md
stilnat Nov 27, 2025
b3c4b5b
Fix bugs, cleanup, and polish MultiDragScale recognizer PR
spydon Mar 2, 2026
c6a0b1c
Merge remote-tracking branch 'origin/main' into recognizer-v2
spydon Mar 2, 2026
b6e089e
test: Add dispatcher lifecycle and upgrade path tests
spydon Mar 2, 2026
7d260b3
feat: Add dynamic scale & drag example
spydon Mar 2, 2026
a77ceb0
docs: Document combining ScaleCallbacks and DragCallbacks
spydon Mar 2, 2026
9e23b3e
fix: Put control body on separate line in ScaleDispatcher
spydon Mar 2, 2026
82b4c3f
refactor: Remove unnecessary hide imports and run dart format
spydon Mar 2, 2026
77b94dc
Merge branch 'main' into recognizer-v2
spydon Mar 2, 2026
390a8cf
Update packages/flame/lib/src/events/multi_drag_scale_recognizer.dart
spydon Mar 3, 2026
03990fb
fix: Remove unused dragStartBehavior from MultiDragScaleGestureRecogn…
spydon Mar 3, 2026
3be0f7c
fix: Remove unused material.dart import from MultiDragDispatcher
spydon Mar 3, 2026
15a30aa
fix: Restore dt-based camera updates in scale_drag_example
spydon Mar 3, 2026
5904421
fix: Gate MultiDragDispatcher onStart callback when marked for removal
spydon Mar 3, 2026
2edf728
docs: Document markForRemoval gesture overlap behavior
spydon Mar 3, 2026
d980fb3
fix: Use scale focal point for drag updates during pinch gestures
spydon Mar 3, 2026
7968c39
fix: Compute focalPointDelta in global coordinates
spydon Mar 3, 2026
18276f0
chore: Rewrite timedZoomFrom test helper to remove CC BY-SA code
spydon Mar 3, 2026
31fa8ff
refactor: Remove abbreviations in timedZoomFrom test helper
spydon Mar 3, 2026
ad729ce
chore: Merge main into recognizer-v2
spydon May 17, 2026
acc0d12
fix: Remove markForRemoval in favor of immediate removal with cancel …
spydon May 17, 2026
6a16df8
fix: Restore markForRemoval - keep active gestures, reject new ones
spydon May 17, 2026
5f9cacb
fix: Re-initialize span baseline when second pointer is added
spydon May 17, 2026
cbfaf9e
test: Add rotation test for MultiDragScaleGestureRecognizer
spydon May 17, 2026
0d7017c
fix: Handle rejectGesture scale teardown and stale drag components
spydon May 17, 2026
47d51f2
fix: Each pointer fires its own drag update independently during scale
spydon May 17, 2026
fdf4b86
fix: Guard _dispose against double-resolving the arena entry
spydon May 17, 2026
f2a4163
Use Vector2.all everywhere in the example
spydon May 17, 2026
2e2623c
fix: Handle stale scale components in onScaleUpdate dispatchers
spydon May 17, 2026
a73da2e
fix: Prevent double translation in DragScaleBox example
spydon May 17, 2026
3a9a5e4
refactor: Extract dispatcher selection logic to shared helper
spydon May 17, 2026
9ebb9a2
refactor: Unify to single MultiDragScaleGestureRecognizer for all eve…
spydon May 17, 2026
7698025
fix: Update DynamicScaleDrag example to remove deleted dispatcher ref…
spydon May 17, 2026
e619fb9
fix: Remove dispatcher label from DynamicScaleDrag example
spydon May 17, 2026
b00f105
docs: Remove Dynamic addition sections from drag and scale event docs
spydon May 17, 2026
1498956
chore: Remove superseded scale_drag_example
spydon May 17, 2026
e442e1c
fix: Disable recognizer flags when last DragCallbacks/ScaleCallbacks …
spydon May 17, 2026
43defb4
refactor: Address review feedback on recognizer-v2 PR
spydon May 17, 2026
5dee1db
refactor: Address second round of review feedback
spydon May 18, 2026
c5de13f
Merge branch 'main' into recognizer-v2
spydon May 18, 2026
968bd09
fix: Address two review issues in recognizer
spydon May 18, 2026
511043b
fix: Measure scale from original finger positions, not threshold cros…
spydon May 18, 2026
9d5bfcf
docs: Document scaleThreshold and add configurable field to dispatcher
spydon May 18, 2026
966e5f4
fix: Make rotations final and remove configurable scaleThreshold for now
spydon May 18, 2026
c170e4f
feat: Add configurable scaleThreshold to MultiDragScaleDispatcher
spydon May 18, 2026
20dc872
docs: Rename InteractiveRect to InteractiveRectangle in examples
spydon May 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 25 additions & 12 deletions doc/flame/inputs/drag_events.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,26 +113,39 @@ method must be implemented manually.
If your component is a part of a larger hierarchy, then it will only receive drag events if its
ancestors have all implemented the `containsLocalPoint` correctly.

```dart
class MyComponent extends PositionComponent with DragCallbacks {
MyComponent({super.size});

final _paint = Paint();
bool _isDragged = false;
### isDragged

@override
void onDragStart(DragStartEvent event) => _isDragged = true;
The `DragCallbacks` mixin provides an `isDragged` getter that returns `true` while the component is
actively being dragged. This is set to `true` at `onDragStart` and back to `false` at `onDragEnd`.
It can be used, for example, to change the component's visual appearance during a drag.


## Combining with ScaleCallbacks

A component can use both `DragCallbacks` and `ScaleCallbacks` at the same time. When both mixins are
present, single-finger gestures produce drag events and two-finger gestures produce both drag and
scale events. This is useful for components that should be draggable with one finger and
pinch-to-zoom or rotatable with two fingers.

```dart
class InteractiveRect extends RectangleComponent
with ScaleCallbacks, DragCallbacks {

@override
void onDragUpdate(DragUpdateEvent event) => position += event.delta;
void onDragUpdate(DragUpdateEvent event) {
position += event.localDelta;
}

@override
void onDragEnd(DragEndEvent event) => _isDragged = false;
void onScaleStart(ScaleStartEvent event) {
super.onScaleStart(event);
// store initial angle/scale for relative updates
}

@override
void render(Canvas canvas) {
_paint.color = _isDragged? Colors.red : Colors.white;
canvas.drawRect(size.toRect(), _paint);
void onScaleUpdate(ScaleUpdateEvent event) {
angle = initialAngle + event.rotation;
}
}
Comment thread
spydon marked this conversation as resolved.
```
2 changes: 2 additions & 0 deletions doc/flame/inputs/inputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ works, but adapted for Flame's component tree.

- [Tap Events](tap_events.md)
- [Drag Events](drag_events.md)
- [Scale Events](scale_events.md)
- [Long Press Events](long_press_events.md)
- [Gesture Input](gesture_input.md)
- [Keyboard Input](keyboard_input.md)
Expand All @@ -22,6 +23,7 @@ works, but adapted for Flame's component tree.

Tap Events <tap_events.md>
Drag Events <drag_events.md>
Scale Events <scale_events.md>
Long Press Events <long_press_events.md>
Gesture Input <gesture_input.md>
Keyboard Input <keyboard_input.md>
Expand Down
87 changes: 21 additions & 66 deletions doc/flame/inputs/scale_events.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,85 +100,40 @@ method must be implemented manually.
If your component is a part of a larger hierarchy, then it will only receive scale events if its
ancestors have all implemented the `containsLocalPoint` correctly.


### isScaling

The `ScaleCallbacks` mixin provides an `isScaling` getter that returns `true` while the component is
actively being scaled. This is set to `true` at the start of `onScaleStart` and back to `false` at
`onScaleEnd`. It can be used, for example, to change the component's visual appearance during a scale
gesture.


## Combining with DragCallbacks

A component can use both `ScaleCallbacks` and `DragCallbacks` at the same time. When both mixins are
present, single-finger gestures produce drag events and two-finger gestures produce both scale and
drag events. This is useful for components that should be draggable with one finger and
pinch-to-zoom or rotatable with two fingers.

```dart
class ScaleOnlyRectangle extends RectangleComponent with ScaleCallbacks {
ScaleOnlyRectangle({
required Vector2 position,
required Vector2 size,
Color color = Colors.blue,
Anchor anchor = Anchor.center,
}) : super(
position: position,
size: size,
anchor: anchor,
paint: Paint()..color = color,
);
class InteractiveRect extends RectangleComponent
with ScaleCallbacks, DragCallbacks {

@override
Future<void> onLoad() async {
final text = TextComponent(
text: 'scale',
textRenderer: TextPaint(
style: const TextStyle(fontSize: 25, color: Colors.white),
),
position: size / 2,
anchor: Anchor.center,
);
add(text);
void onDragUpdate(DragUpdateEvent event) {
position += event.localDelta;
}

bool isScaling = false;
double initialAngle = 0;
Vector2 initialScale = Vector2.all(1);
double lastScale = 1.0;

/// ScaleCallbacks overrides
@override
void onScaleStart(ScaleStartEvent event) {
super.onScaleStart(event);
isScaling = true;
initialAngle = angle;
initialScale = scale;
lastScale = 1.0;
debugPrint('Scale started at ${event.devicePosition}');
// store initial angle/scale for relative updates
}

@override
void onScaleUpdate(ScaleUpdateEvent event) {
super.onScaleUpdate(event);
// scale rectangle size by pinch
angle = initialAngle + event.rotation;
// delta scale since last frame
if (lastScale == 0) {
return;
}
final scaleDelta = event.scale / lastScale;
lastScale = event.scale; // update for next frame

// apply delta gently
scale *= sqrt(scaleDelta);

// clamp
scale.clamp(Vector2.all(0.8), Vector2.all(3));
}

@override
void onScaleEnd(ScaleEndEvent event) {
super.onScaleEnd(event);
isScaling = false;
debugPrint('Scale ended with velocity ${event.velocity}');
}
Comment thread
spydon marked this conversation as resolved.
}

```


## Scale and drag gestures interactions

A multi drag gesture can sometimes look exactly like a scale gesture.
This is the case for instance, if you try to move two components toward each other at the same time.
If you added both a component using ScaleCallbacks and
one using DragCallbacks (or one using both), this issue will arise.
The Scale gesture will win over the drag gesture
and prevent your user to perform the multi drag gesture as they wanted. This is a limitation
with the current implementation that devs need to be aware of.
Loading
Loading