Typer2 0 Posted June 19, 2023 I am looking for a way to support the zoom gesture on a MacBook by using the trackpad, but even the basic ImageZoom demo doesn't seem to work. C:\Users\Public\Documents\Embarcadero\Studio\22.0\Samples\Object Pascal\Mobile Snippets\InteractiveGestures\ImageZoom The documentation says: "The interactive gestures are multi-touch gestures (Zoom, Rotate, and so on) that are equivalent to System Gestures on Windows, and to Gestures on macOS, iOS, and Android. Every time the fingers move on the touch surface, an OnGesture event is fired." Is this not supported, or am I missing something? Share this post Link to post
Alexander Halser 26 Posted December 14, 2023 I wonder if you found a solution for this. The rotate gesture seems to be the only gesture that works with a MacOS trackpad. Everything else - simply broken. Share this post Link to post
Dave Nottage 557 Posted December 14, 2023 1 hour ago, Alexander Halser said: Everything else - simply broken Zoom is "broken" because the code assumes there are touch events available when the magnifyWithEvent method (in FMX.Platform.Mac) is called. In theory, the same result could be implemented using individual touch events, but it would be more complex. magnifyWithEvent is supposed to be used in conjunction with the magnification property on the event parameter (an NSEvent). I didn't look into the other gestures. Share this post Link to post
Alexander Halser 26 Posted December 14, 2023 So, it's officially broken, despite documentation says the opposite? Quote On macOS: FireMonkey supports only the Zoom, Pan, and Rotate interactive gestures. Gestures in FireMonkey - RAD Studio (embarcadero.com) Share this post Link to post
Dave Nottage 557 Posted December 14, 2023 37 minutes ago, Alexander Halser said: So, it's officially broken, despite documentation says the opposite? For Zoom, definitely. You mentioned that Rotate works? Share this post Link to post
Alexander Halser 26 Posted December 14, 2023 (edited) Yes, rotate works as described in the docs. Zoom and pan do not. There's no event at all for these. The pan gesture (swiping up or down with 2 fingers) obviously gets translated into a mouse wheel message. Edited December 14, 2023 by Alexander Halser Share this post Link to post
Alexander Halser 26 Posted December 22, 2023 (edited) The problem is in FMX.Platform.Mac: procedure TFMXViewBase.magnifyWithEvent(event: NSEvent); var ... begin ... if FGestureControl <> nil then begin LTouches := event.touchesMatchingPhase(NSTouchPhaseTouching, NSView(Super)); {ECS/ALEX Here comes our problem: LTouches.count is zero, that's why the gesture event is not fired. I assume that we have to deal with "event.magnification" to determine "FEventInfo.Distance". } if LTouches.count >= 2 then begin LTouchesArray := LTouches.allObjects; LTouch := TNSTouch.Wrap(LTouchesArray.objectAtIndex(0)); LDeviceSize := LTouch.deviceSize; ... I am currently experimenting with the event.magnification value (which is a float value), to match FEventInfo.Distance in a way that the example from the official docs keeps working the way it promises, but doesn't. However, I have a hard time to believe that this has never worked. If Emba has dedicated examples, there must have been a time when this did work properly. It perhaps depends on the MacOS version. My own version of MacOS that I'm using for testing is relatively old (Big Sur), with a second Mac used by one of my colleagues running Sonoma. The gesture is not fired on either machine, but may have been working on OS versions < Big Sur. If it has never worked with touchpad gestures, it might have worked and still work with a real touch screen. Is anyone competent to comment on that - does the igiZoom gesture work as advertised with touch screen Mac (we don't have them here, so I cannot test this)? Edited December 22, 2023 by Alexander Halser Share this post Link to post
Dave Nottage 557 Posted December 22, 2023 10 minutes ago, Alexander Halser said: I am currently experimenting with the event.magnification value (which is a float value), to match FEventInfo.Distance in a way that the example from the official docs keeps working the way it promises, but doesn't. Have you investigated whether macOS sends regular touch events in addition to magnifyWithEvent when zooming? As I mentioned earlier, this may be a more reliable way, however it might be a bit complex. Share this post Link to post
Alexander Halser 26 Posted December 22, 2023 Quote Have you investigated whether macOS sends regular touch events in addition to magnifyWithEvent when zooming? No, I haven't. But the magnifyWithEvent comes reliably and this is what Delphi actually evaluates. I am not that deep into native MacOS development, so I rather stay with the methods that Delphi already implements. Share this post Link to post
Typer2 0 Posted December 28, 2023 I have just upgraded to Delphi 12 and the issue is indeed still not solved. Zoom is a vital part of my software as it is aimed at designers, so I will report this bug. Share this post Link to post
Alexander Halser 26 Posted December 28, 2023 (edited) IMO the gestures are designed for real touchscreens and not for touchpads. I believe this has never worked with touchpads. Anyway, I have implemented a solution for myself by patching FMX.Platform.Mac, which was already patched anyway to work around the Sonoma scaling bug on MacOS. This is certainly not for everyone, but works like a charm. It uses the Angle parameter for an alternative zoom gesture (Angle is used in rotation gestures, for zoom it's always zero). Your app needs to respond to this accordingly. Most importantly, it doesn't break regular zoom gestures coming from real touch screens. procedure TFMXViewBase.magnifyWithEvent(event: NSEvent); var ... begin ... if FGestureControl <> nil then begin LTouches := event.touchesMatchingPhase(NSTouchPhaseTouching, NSView(Super)); if LTouches.count >= 2 then begin LTouchesArray := LTouches.allObjects; LTouch := TNSTouch.Wrap(LTouchesArray.objectAtIndex(0)); LDeviceSize := LTouch.deviceSize; FEventInfo.Distance := 0; //reset the distance // Find the greatest distance between the touches. for I := 0 to LTouches.count - 2 do begin LTouch := TNSTouch.Wrap(LTouchesArray.objectAtIndex(I)); LPoint := LTouch.normalizedPosition; for J := 1 to LTouches.count - 1 do begin LTouch := TNSTouch.Wrap(LTouchesArray.objectAtIndex(J)); LPoint2 := LTouch.normalizedPosition; Distance := Round(Sqrt(Sqr(LPoint.x * LDeviceSize.width - LPoint2.x * LDeviceSize.width) + Sqr(LPoint.y * LDeviceSize.height - LPoint2.y * LDeviceSize.height))); if Distance > FEventInfo.Distance then FEventInfo.Distance := Distance; end; FEventInfo.GestureID := igiZoom; if Supports(FGestureControl, IGestureControl, GestureObj) then GestureObj.CMGesture(FEventInfo); FEventInfo.Flags := []; end end {ECS/ALEX} else if LTouches.count = 0 then begin FEventInfo.Distance := 0; FEventInfo.Angle := event.magnification; FEventInfo.GestureID := igiZoom; if Supports(FGestureControl, IGestureControl, GestureObj) then GestureObj.CMGesture(FEventInfo); FEventInfo.Flags := []; end; end {ECS/ALEX} else //send the message up the responder chain NSView(Super).magnifyWithEvent(event); end; Edited December 28, 2023 by Alexander Halser 1 Share this post Link to post