From de370a8d34f82accc6e849e6dace5be4be23f2e5 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 24 Sep 2024 18:36:34 +0200 Subject: [PATCH] feat: option to disable gestures (#44) - [x] update example app - [x] web implementation - [x] android implementation --- .../josxha/maplibre/MapLibreMapController.kt | 24 ++- .../com/github/josxha/maplibre/Pigeon.g.kt | 66 ++++++- example/lib/gestures_page.dart | 68 ++++++++ example/lib/main.dart | 2 + example/lib/menu_page.dart | 6 + ios/Classes/Pigeon.g.swift | 65 ++++++- lib/maplibre.dart | 1 + lib/src/map_gestures.dart | 60 +++++++ lib/src/map_options.dart | 6 +- lib/src/native/pigeon.g.dart | 66 ++++++- lib/src/native/widget_state.dart | 6 + lib/src/web/interop/gesture_handlers.dart | 80 +++++++++ lib/src/web/interop/interop.dart | 3 +- lib/src/web/interop/map.dart | 14 ++ lib/src/web/widget_state.dart | 43 +++++ linux/pigeon.g.cc | 165 +++++++++++++++--- linux/pigeon.g.h | 74 +++++++- macos/Classes/Pigeon.g.swift | 65 ++++++- pigeons/pigeon.dart | 27 +++ windows/runner/pigeon.g.cpp | 120 +++++++++++-- windows/runner/pigeon.g.h | 55 +++++- 21 files changed, 934 insertions(+), 82 deletions(-) create mode 100644 example/lib/gestures_page.dart create mode 100644 lib/src/map_gestures.dart create mode 100644 lib/src/web/interop/gesture_handlers.dart diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt index 4a5d00e6..ac6402b4 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt @@ -1,5 +1,6 @@ package com.github.josxha.maplibre +import CameraChangeReason import LngLat import LngLatBounds import MapCamera @@ -71,7 +72,7 @@ class MapLibreMapController( private var style: Style? = null init { - val channelSuffix = viewId.toString(); + val channelSuffix = viewId.toString() MapLibreHostApi.setUp(binaryMessenger, this, channelSuffix) flutterApi = MapLibreFlutterApi(binaryMessenger, channelSuffix) flutterApi.getOptions { result: Result -> @@ -165,7 +166,7 @@ class MapLibreMapController( if (bearing != null) camera.bearing(bearing) val cameraUpdate = CameraUpdateFactory.newCameraPosition(camera.build()) mapLibreMap.moveCamera(cameraUpdate) - callback(Result.success(Unit)); + callback(Result.success(Unit)) } override fun flyTo( @@ -198,7 +199,7 @@ class MapLibreMapController( lat: Double, callback: (Result) -> Unit ) { - val location = mapLibreMap.projection.toScreenLocation(LatLng(lat, lng)); + val location = mapLibreMap.projection.toScreenLocation(LatLng(lat, lng)) callback(Result.success(ScreenLocation(location.x.toDouble(), location.y.toDouble()))) } @@ -592,5 +593,22 @@ class MapLibreMapController( ) mapLibreMap.setLatLngBoundsForCameraTarget(bounds) } + + // gestures + if (options.gestures.rotate != mapOptions.gestures.rotate) { + mapLibreMap.uiSettings.isRotateGesturesEnabled = options.gestures.rotate + } + if (options.gestures.pan != mapOptions.gestures.pan) { + mapLibreMap.uiSettings.isRotateGesturesEnabled = options.gestures.pan + } + if (options.gestures.zoom != mapOptions.gestures.zoom) { + mapLibreMap.uiSettings.isZoomGesturesEnabled = options.gestures.zoom + mapLibreMap.uiSettings.isDoubleTapGesturesEnabled = options.gestures.zoom + mapLibreMap.uiSettings.isScrollGesturesEnabled = options.gestures.zoom + mapLibreMap.uiSettings.isQuickZoomGesturesEnabled = options.gestures.zoom + } + if (options.gestures.tilt != mapOptions.gestures.tilt) { + mapLibreMap.uiSettings.isTiltGesturesEnabled = options.gestures.tilt + } } } \ No newline at end of file diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt b/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt index 70076ba3..7ff01c81 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt @@ -124,7 +124,9 @@ data class MapOptions ( /** If the native map should listen to click events. */ val listensOnClick: Boolean, /** If the native map should listen to long click events. */ - val listensOnLongClick: Boolean + val listensOnLongClick: Boolean, + /** The map gestures. */ + val gestures: MapGestures ) { companion object { @@ -141,7 +143,8 @@ data class MapOptions ( val maxTilt = pigeonVar_list[9] as Double val listensOnClick = pigeonVar_list[10] as Boolean val listensOnLongClick = pigeonVar_list[11] as Boolean - return MapOptions(style, zoom, tilt, bearing, center, maxBounds, minZoom, maxZoom, minTilt, maxTilt, listensOnClick, listensOnLongClick) + val gestures = pigeonVar_list[12] as MapGestures + return MapOptions(style, zoom, tilt, bearing, center, maxBounds, minZoom, maxZoom, minTilt, maxTilt, listensOnClick, listensOnLongClick, gestures) } } fun toList(): List { @@ -158,6 +161,42 @@ data class MapOptions ( maxTilt, listensOnClick, listensOnLongClick, + gestures, + ) + } +} + +/** + * Map gestures + * + * Generated class from Pigeon that represents data sent in messages. + */ +data class MapGestures ( + /** Rotate the map bearing. */ + val rotate: Boolean, + /** Move the center of the map around. */ + val pan: Boolean, + /** Zoom the map in and out. */ + val zoom: Boolean, + /** Tilt (pitch) the map camera. */ + val tilt: Boolean +) + { + companion object { + fun fromList(pigeonVar_list: List): MapGestures { + val rotate = pigeonVar_list[0] as Boolean + val pan = pigeonVar_list[1] as Boolean + val zoom = pigeonVar_list[2] as Boolean + val tilt = pigeonVar_list[3] as Boolean + return MapGestures(rotate, pan, zoom, tilt) + } + } + fun toList(): List { + return listOf( + rotate, + pan, + zoom, + tilt, ) } } @@ -302,20 +341,25 @@ private open class PigeonPigeonCodec : StandardMessageCodec() { } 133.toByte() -> { return (readValue(buffer) as? List)?.let { - LngLat.fromList(it) + MapGestures.fromList(it) } } 134.toByte() -> { return (readValue(buffer) as? List)?.let { - ScreenLocation.fromList(it) + LngLat.fromList(it) } } 135.toByte() -> { return (readValue(buffer) as? List)?.let { - MapCamera.fromList(it) + ScreenLocation.fromList(it) } } 136.toByte() -> { + return (readValue(buffer) as? List)?.let { + MapCamera.fromList(it) + } + } + 137.toByte() -> { return (readValue(buffer) as? List)?.let { LngLatBounds.fromList(it) } @@ -341,22 +385,26 @@ private open class PigeonPigeonCodec : StandardMessageCodec() { stream.write(132) writeValue(stream, value.toList()) } - is LngLat -> { + is MapGestures -> { stream.write(133) writeValue(stream, value.toList()) } - is ScreenLocation -> { + is LngLat -> { stream.write(134) writeValue(stream, value.toList()) } - is MapCamera -> { + is ScreenLocation -> { stream.write(135) writeValue(stream, value.toList()) } - is LngLatBounds -> { + is MapCamera -> { stream.write(136) writeValue(stream, value.toList()) } + is LngLatBounds -> { + stream.write(137) + writeValue(stream, value.toList()) + } else -> super.writeValue(stream, value) } } diff --git a/example/lib/gestures_page.dart b/example/lib/gestures_page.dart new file mode 100644 index 00000000..8b19b31c --- /dev/null +++ b/example/lib/gestures_page.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:maplibre/maplibre.dart'; + +@immutable +class GesturesPage extends StatefulWidget { + const GesturesPage({super.key}); + + static const location = '/gestures'; + + @override + State createState() => _GesturesPageState(); +} + +class _GesturesPageState extends State { + final _selections = Map.fromEntries( + Gestures.values.map((e) => MapEntry(e, false)), + ); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Gestures')), + body: Column( + children: [ + Padding( + padding: const EdgeInsets.all(8), + child: Wrap( + spacing: 8, + runSpacing: 8, + children: Gestures.values + .map( + (e) => ChoiceChip( + label: Text(e.name), + selected: _selections[e]!, + onSelected: (value) => setState(() { + _selections[e] = !_selections[e]!; + }), + ), + ) + .toList(growable: false), + ), + ), + Expanded( + child: MapLibreMap( + options: MapOptions( + center: Position(9.17, 47.68), + zoom: 3, + gestures: MapGestures( + rotate: _selections[Gestures.rotate]!, + pan: _selections[Gestures.pan]!, + zoom: _selections[Gestures.zoom]!, + pitch: _selections[Gestures.tilt]!, + ), + ), + ), + ), + ], + ), + ); + } +} + +enum Gestures { + rotate, + pan, + zoom, + tilt; +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 1a60be53..739f97a0 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -3,6 +3,7 @@ import 'package:maplibre_example/animation_page.dart'; import 'package:maplibre_example/annotations_page.dart'; import 'package:maplibre_example/controller_page.dart'; import 'package:maplibre_example/events_page.dart'; +import 'package:maplibre_example/gestures_page.dart'; import 'package:maplibre_example/kiosk_page.dart'; import 'package:maplibre_example/layers_circle_page.dart'; import 'package:maplibre_example/layers_fill_extrusion_page.dart'; @@ -35,6 +36,7 @@ class MyApp extends StatelessWidget { MenuPage.location: (context) => const MenuPage(), KioskPage.location: (context) => const KioskPage(), AnimationPage.location: (context) => const AnimationPage(), + GesturesPage.location: (context) => const GesturesPage(), EventsPage.location: (context) => const EventsPage(), StyledMapPage.location: (context) => const StyledMapPage(), LayersSymbolPage.location: (context) => const LayersSymbolPage(), diff --git a/example/lib/menu_page.dart b/example/lib/menu_page.dart index 8a96fff2..52525711 100644 --- a/example/lib/menu_page.dart +++ b/example/lib/menu_page.dart @@ -4,6 +4,7 @@ import 'package:maplibre_example/animation_page.dart'; import 'package:maplibre_example/annotations_page.dart'; import 'package:maplibre_example/controller_page.dart'; import 'package:maplibre_example/events_page.dart'; +import 'package:maplibre_example/gestures_page.dart'; import 'package:maplibre_example/layers_circle_page.dart'; import 'package:maplibre_example/layers_fill_extrusion_page.dart'; import 'package:maplibre_example/layers_fill_page.dart'; @@ -48,6 +49,11 @@ class MenuPage extends StatelessWidget { iconData: Icons.build, location: ParametersPage.location, ), + ItemCard( + label: 'Gestures', + iconData: Icons.back_hand, + location: GesturesPage.location, + ), ItemCard( label: 'Events', iconData: Icons.notifications, diff --git a/ios/Classes/Pigeon.g.swift b/ios/Classes/Pigeon.g.swift index e0a6b482..37d10641 100644 --- a/ios/Classes/Pigeon.g.swift +++ b/ios/Classes/Pigeon.g.swift @@ -125,6 +125,8 @@ struct MapOptions { var listensOnClick: Bool /// If the native map should listen to long click events. var listensOnLongClick: Bool + /// The map gestures. + var gestures: MapGestures @@ -142,6 +144,7 @@ struct MapOptions { let maxTilt = pigeonVar_list[9] as! Double let listensOnClick = pigeonVar_list[10] as! Bool let listensOnLongClick = pigeonVar_list[11] as! Bool + let gestures = pigeonVar_list[12] as! MapGestures return MapOptions( style: style, @@ -155,7 +158,8 @@ struct MapOptions { minTilt: minTilt, maxTilt: maxTilt, listensOnClick: listensOnClick, - listensOnLongClick: listensOnLongClick + listensOnLongClick: listensOnLongClick, + gestures: gestures ) } func toList() -> [Any?] { @@ -172,6 +176,46 @@ struct MapOptions { maxTilt, listensOnClick, listensOnLongClick, + gestures, + ] + } +} + +/// Map gestures +/// +/// Generated class from Pigeon that represents data sent in messages. +struct MapGestures { + /// Rotate the map bearing. + var rotate: Bool + /// Move the center of the map around. + var pan: Bool + /// Zoom the map in and out. + var zoom: Bool + /// Tilt (pitch) the map camera. + var tilt: Bool + + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> MapGestures? { + let rotate = pigeonVar_list[0] as! Bool + let pan = pigeonVar_list[1] as! Bool + let zoom = pigeonVar_list[2] as! Bool + let tilt = pigeonVar_list[3] as! Bool + + return MapGestures( + rotate: rotate, + pan: pan, + zoom: zoom, + tilt: tilt + ) + } + func toList() -> [Any?] { + return [ + rotate, + pan, + zoom, + tilt, ] } } @@ -328,12 +372,14 @@ private class PigeonPigeonCodecReader: FlutterStandardReader { case 132: return MapOptions.fromList(self.readValue() as! [Any?]) case 133: - return LngLat.fromList(self.readValue() as! [Any?]) + return MapGestures.fromList(self.readValue() as! [Any?]) case 134: - return ScreenLocation.fromList(self.readValue() as! [Any?]) + return LngLat.fromList(self.readValue() as! [Any?]) case 135: - return MapCamera.fromList(self.readValue() as! [Any?]) + return ScreenLocation.fromList(self.readValue() as! [Any?]) case 136: + return MapCamera.fromList(self.readValue() as! [Any?]) + case 137: return LngLatBounds.fromList(self.readValue() as! [Any?]) default: return super.readValue(ofType: type) @@ -355,18 +401,21 @@ private class PigeonPigeonCodecWriter: FlutterStandardWriter { } else if let value = value as? MapOptions { super.writeByte(132) super.writeValue(value.toList()) - } else if let value = value as? LngLat { + } else if let value = value as? MapGestures { super.writeByte(133) super.writeValue(value.toList()) - } else if let value = value as? ScreenLocation { + } else if let value = value as? LngLat { super.writeByte(134) super.writeValue(value.toList()) - } else if let value = value as? MapCamera { + } else if let value = value as? ScreenLocation { super.writeByte(135) super.writeValue(value.toList()) - } else if let value = value as? LngLatBounds { + } else if let value = value as? MapCamera { super.writeByte(136) super.writeValue(value.toList()) + } else if let value = value as? LngLatBounds { + super.writeByte(137) + super.writeValue(value.toList()) } else { super.writeValue(value) } diff --git a/lib/maplibre.dart b/lib/maplibre.dart index c352fc39..42fae419 100644 --- a/lib/maplibre.dart +++ b/lib/maplibre.dart @@ -8,6 +8,7 @@ export 'src/map.dart'; export 'src/map_camera.dart'; export 'src/map_controller.dart'; export 'src/map_events.dart'; +export 'src/map_gestures.dart'; export 'src/map_options.dart'; export 'src/style/style.dart'; export 'src/utils.dart'; diff --git a/lib/src/map_gestures.dart b/lib/src/map_gestures.dart new file mode 100644 index 00000000..479cae2b --- /dev/null +++ b/lib/src/map_gestures.dart @@ -0,0 +1,60 @@ +import 'package:flutter/foundation.dart'; + +/// Configure gestures that are enabled on the map. +@immutable +class MapGestures { + /// Create a new [MapGestures] object by setting all gestures. + const MapGestures({ + required this.rotate, + required this.pan, + required this.zoom, + required this.pitch, + }); + + /// Create a new [MapGestures] object by enabling all gestures or disabling + /// just some gestures. + const MapGestures.all({ + this.rotate = true, + this.pan = true, + this.zoom = true, + this.pitch = true, + }); + + /// Create a new [MapGestures] object by disable all gestures or enabling just + /// some gestures. + const MapGestures.none({ + this.rotate = false, + this.pan = false, + this.zoom = false, + this.pitch = false, + }); + + /// Rotate the map bearing. + final bool rotate; + + /// Move the center of the map around. + final bool pan; + + /// Zoom the map in and out. + final bool zoom; + + /// Tilt (pitch) the map camera. + final bool pitch; + + /// Returns true if all gestures are active + bool get allEnabled => rotate && pan && zoom && pitch; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is MapGestures && + runtimeType == other.runtimeType && + rotate == other.rotate && + pan == other.pan && + zoom == other.zoom && + pitch == other.pitch; + + @override + int get hashCode => + rotate.hashCode ^ pan.hashCode ^ zoom.hashCode ^ pitch.hashCode; +} diff --git a/lib/src/map_options.dart b/lib/src/map_options.dart index cef9f324..f1ff4c52 100644 --- a/lib/src/map_options.dart +++ b/lib/src/map_options.dart @@ -22,6 +22,7 @@ class MapOptions { @Deprecated('Use the onEvent() callback instead.') this.onSecondaryClick, @Deprecated('Use the onEvent() callback instead.') this.onLongClick, this.maxBounds, + this.gestures = const MapGestures.all(), }); /// The style URL that should get used. If not set, the default MapLibre style @@ -59,13 +60,16 @@ class MapOptions { final double minTilt; /// The maximum camera tilt (pitch). Allowed values on web are 0-85. Allowed - // /// values on other platforms are 0-60, bigger values will get ignored. + /// values on other platforms are 0-60, bigger values will get ignored. final double maxTilt; /// The maximum bounding box of the map camera. No constraints are in place /// if set to `null`. final LngLatBounds? maxBounds; + /// Enable and disable some or all map gestures. + final MapGestures gestures; + /// A callback that fires when the user clicks on the map. @Deprecated('Use the onEvent() callback instead.') final OnClickCallback? onClick; diff --git a/lib/src/native/pigeon.g.dart b/lib/src/native/pigeon.g.dart index e6d83d3a..5bf95b1a 100644 --- a/lib/src/native/pigeon.g.dart +++ b/lib/src/native/pigeon.g.dart @@ -75,6 +75,7 @@ class MapOptions { required this.maxTilt, required this.listensOnClick, required this.listensOnLongClick, + required this.gestures, }); /// The URL of the used map style. @@ -113,6 +114,9 @@ class MapOptions { /// If the native map should listen to long click events. bool listensOnLongClick; + /// The map gestures. + MapGestures gestures; + Object encode() { return [ style, @@ -127,6 +131,7 @@ class MapOptions { maxTilt, listensOnClick, listensOnLongClick, + gestures, ]; } @@ -145,6 +150,48 @@ class MapOptions { maxTilt: result[9]! as double, listensOnClick: result[10]! as bool, listensOnLongClick: result[11]! as bool, + gestures: result[12]! as MapGestures, + ); + } +} + +/// Map gestures +class MapGestures { + MapGestures({ + required this.rotate, + required this.pan, + required this.zoom, + required this.tilt, + }); + + /// Rotate the map bearing. + bool rotate; + + /// Move the center of the map around. + bool pan; + + /// Zoom the map in and out. + bool zoom; + + /// Tilt (pitch) the map camera. + bool tilt; + + Object encode() { + return [ + rotate, + pan, + zoom, + tilt, + ]; + } + + static MapGestures decode(Object result) { + result as List; + return MapGestures( + rotate: result[0]! as bool, + pan: result[1]! as bool, + zoom: result[2]! as bool, + tilt: result[3]! as bool, ); } } @@ -300,18 +347,21 @@ class _PigeonCodec extends StandardMessageCodec { } else if (value is MapOptions) { buffer.putUint8(132); writeValue(buffer, value.encode()); - } else if (value is LngLat) { + } else if (value is MapGestures) { buffer.putUint8(133); writeValue(buffer, value.encode()); - } else if (value is ScreenLocation) { + } else if (value is LngLat) { buffer.putUint8(134); writeValue(buffer, value.encode()); - } else if (value is MapCamera) { + } else if (value is ScreenLocation) { buffer.putUint8(135); writeValue(buffer, value.encode()); - } else if (value is LngLatBounds) { + } else if (value is MapCamera) { buffer.putUint8(136); writeValue(buffer, value.encode()); + } else if (value is LngLatBounds) { + buffer.putUint8(137); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -332,12 +382,14 @@ class _PigeonCodec extends StandardMessageCodec { case 132: return MapOptions.decode(readValue(buffer)!); case 133: - return LngLat.decode(readValue(buffer)!); + return MapGestures.decode(readValue(buffer)!); case 134: - return ScreenLocation.decode(readValue(buffer)!); + return LngLat.decode(readValue(buffer)!); case 135: - return MapCamera.decode(readValue(buffer)!); + return ScreenLocation.decode(readValue(buffer)!); case 136: + return MapCamera.decode(readValue(buffer)!); + case 137: return LngLatBounds.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); diff --git a/lib/src/native/widget_state.dart b/lib/src/native/widget_state.dart index e3bcc5d7..f2ca6a43 100644 --- a/lib/src/native/widget_state.dart +++ b/lib/src/native/widget_state.dart @@ -81,6 +81,12 @@ final class MapLibreMapStateNative extends State maxBounds: _options.maxBounds?.toLngLatBounds(), listensOnClick: widget.onEvent != null, listensOnLongClick: widget.onEvent != null, + gestures: pigeon.MapGestures( + rotate: _options.gestures.rotate, + pan: _options.gestures.pan, + zoom: _options.gestures.zoom, + tilt: _options.gestures.pitch, + ), ); @override diff --git a/lib/src/web/interop/gesture_handlers.dart b/lib/src/web/interop/gesture_handlers.dart new file mode 100644 index 00000000..35ef56a5 --- /dev/null +++ b/lib/src/web/interop/gesture_handlers.dart @@ -0,0 +1,80 @@ +part of 'interop.dart'; + +/// https://maplibre.org/maplibre-gl-js/docs/API/classes/DragRotateHandler/ +extension type DragRotateHandler._(JSObject _) implements JSObject { + /// Disable the gesture. + external void disable(); + + /// Enable the gesture. + external void enable(); +} + +/// https://maplibre.org/maplibre-gl-js/docs/API/classes/DragPanHandler/ +extension type DragPanHandler._(JSObject _) implements JSObject { + /// Disable the gesture. + external void disable(); + + /// Enable the gesture. + external void enable(); +} + +/// https://maplibre.org/maplibre-gl-js/docs/API/classes/DoubleClickZoomHandler/ +extension type DoubleClickZoomHandler._(JSObject _) implements JSObject { + /// Disable the gesture. + external void disable(); + + /// Enable the gesture. + external void enable(); +} + +/// https://maplibre.org/maplibre-gl-js/docs/API/classes/KeyboardHandler/ +extension type KeyboardHandler._(JSObject _) implements JSObject { + /// Disable the gesture. + external void disable(); + + /// Enable the gesture. + external void enable(); +} + +/// https://maplibre.org/maplibre-gl-js/docs/API/classes/ScrollZoomHandler/ +extension type ScrollZoomHandler._(JSObject _) implements JSObject { + /// Disable the gesture. + external void disable(); + + /// Enable the gesture. + external void enable(); +} + +/// https://maplibre.org/maplibre-gl-js/docs/API/classes/BoxZoomHandler/ +extension type BoxZoomHandler._(JSObject _) implements JSObject { + /// Disable the gesture. + external void disable(); + + /// Enable the gesture. + external void enable(); +} + +/// https://maplibre.org/maplibre-gl-js/docs/API/classes/TwoFingersTouchPitchHandler/ +extension type TwoFingersTouchPitchHandler._(JSObject _) implements JSObject { + /// Disable the gesture. + external void disable(); + + /// Enable the gesture. + external void enable(); +} + +/// https://maplibre.org/maplibre-gl-js/docs/API/classes/TwoFingersTouchZoomRotateHandler/ +extension type TwoFingersTouchZoomRotateHandler._(JSObject _) + implements JSObject { + /// Disable the gesture. + external void disable(); + + /// Enable the gesture. + external void enable(); + + /// Enable the rotation. + external void enableRotation(); + + /// Disable the rotation. + external void disableRotation(); +} diff --git a/lib/src/web/interop/interop.dart b/lib/src/web/interop/interop.dart index 8c1c4618..fb1c6335 100644 --- a/lib/src/web/interop/interop.dart +++ b/lib/src/web/interop/interop.dart @@ -9,8 +9,9 @@ import 'package:web/web.dart'; part 'camera.dart'; part 'controls.dart'; part 'events.dart'; -part 'marker.dart'; +part 'gesture_handlers.dart'; part 'map.dart'; +part 'marker.dart'; /// A simple x/y [Point] class for JavaScript. @anonymous diff --git a/lib/src/web/interop/map.dart b/lib/src/web/interop/map.dart index cc4b1dd6..0a3d1a69 100644 --- a/lib/src/web/interop/map.dart +++ b/lib/src/web/interop/map.dart @@ -92,6 +92,20 @@ extension type JsMap._(Camera _) implements Camera { /// Get a Source by its id. external SourceSpecification getSource(String id); + + external DoubleClickZoomHandler doubleClickZoom; + external DragPanHandler dragPan; + external DragRotateHandler dragRotate; + external KeyboardHandler keyboard; + external ScrollZoomHandler scrollZoom; + + /// Shift and drag to draw a box to zoom in + external BoxZoomHandler boxZoom; + + /// Pitch with rotate + external bool pitchWithRotate; + external TwoFingersTouchPitchHandler touchPitch; + external TwoFingersTouchZoomRotateHandler touchZoomRotate; } /// Anonymous MapOptions for the MapLibre JavaScript [JsMap]. diff --git a/lib/src/web/widget_state.dart b/lib/src/web/widget_state.dart index 31940149..0c65b1f7 100644 --- a/lib/src/web/widget_state.dart +++ b/lib/src/web/widget_state.dart @@ -61,6 +61,7 @@ final class MapLibreMapStateWeb extends State _map.setMinPitch(_options.minTilt); _map.setMaxPitch(_options.maxTilt); _map.setMaxBounds(_options.maxBounds?.toJsLngLatBounds()); + _updateGestures(_options.gestures); // add controls for (final control in _options.controls) { @@ -228,6 +229,9 @@ final class MapLibreMapStateWeb extends State if (_options.maxBounds != oldWidget.options.maxBounds) { _map.setMaxBounds(_options.maxBounds?.toJsLngLatBounds()); } + if (_options.gestures != oldWidget.options.gestures) { + _updateGestures(_options.gestures); + } super.didUpdateWidget(oldWidget); } @@ -568,4 +572,43 @@ final class MapLibreMapStateWeb extends State final source = _map.getSource(id); source.setData(parse(data)); } + + void _updateGestures(MapGestures gestures) { + if (gestures.pan) { + _map.dragPan.enable(); + } else { + _map.dragPan.disable(); + } + if (gestures.zoom) { + _map.touchZoomRotate.enable(); + _map.doubleClickZoom.enable(); + _map.scrollZoom.enable(); + _map.boxZoom.enable(); + } else { + _map.touchZoomRotate.disable(); // this disables rotation as well + _map.doubleClickZoom.disable(); + _map.scrollZoom.disable(); + _map.boxZoom.disable(); + } + if (gestures.rotate) { + _map.dragRotate.enable(); + _map.touchZoomRotate.disableRotation(); + } else { + _map.touchZoomRotate.enableRotation(); + _map.dragRotate.disable(); + } + if (gestures.pitch) { + // TODO dragRotate allows to pitch too but has no option to disable pitch. + _map.touchPitch.enable(); + } else { + _map.touchPitch.disable(); + } + // It's not possible to disable just some gestures for the KeyboardHandler. + // That's why we disable it completely if not all gestures are enabled. + if (gestures.allEnabled) { + _map.keyboard.enable(); + } else { + _map.keyboard.disable(); + } + } } diff --git a/linux/pigeon.g.cc b/linux/pigeon.g.cc index 0e9f4dce..675e19d5 100644 --- a/linux/pigeon.g.cc +++ b/linux/pigeon.g.cc @@ -18,6 +18,7 @@ struct _MaplibreMapOptions { double max_tilt; gboolean listens_on_click; gboolean listens_on_long_click; + MaplibreMapGestures* gestures; }; G_DEFINE_TYPE(MaplibreMapOptions, maplibre_map_options, G_TYPE_OBJECT) @@ -27,6 +28,7 @@ static void maplibre_map_options_dispose(GObject* object) { g_clear_pointer(&self->style, g_free); g_clear_object(&self->center); g_clear_object(&self->max_bounds); + g_clear_object(&self->gestures); G_OBJECT_CLASS(maplibre_map_options_parent_class)->dispose(object); } @@ -37,7 +39,7 @@ static void maplibre_map_options_class_init(MaplibreMapOptionsClass* klass) { G_OBJECT_CLASS(klass)->dispose = maplibre_map_options_dispose; } -MaplibreMapOptions* maplibre_map_options_new(const gchar* style, double zoom, double tilt, double bearing, MaplibreLngLat* center, MaplibreLngLatBounds* max_bounds, double min_zoom, double max_zoom, double min_tilt, double max_tilt, gboolean listens_on_click, gboolean listens_on_long_click) { +MaplibreMapOptions* maplibre_map_options_new(const gchar* style, double zoom, double tilt, double bearing, MaplibreLngLat* center, MaplibreLngLatBounds* max_bounds, double min_zoom, double max_zoom, double min_tilt, double max_tilt, gboolean listens_on_click, gboolean listens_on_long_click, MaplibreMapGestures* gestures) { MaplibreMapOptions* self = MAPLIBRE_MAP_OPTIONS(g_object_new(maplibre_map_options_get_type(), nullptr)); self->style = g_strdup(style); self->zoom = zoom; @@ -61,6 +63,7 @@ MaplibreMapOptions* maplibre_map_options_new(const gchar* style, double zoom, do self->max_tilt = max_tilt; self->listens_on_click = listens_on_click; self->listens_on_long_click = listens_on_long_click; + self->gestures = MAPLIBRE_MAP_GESTURES(g_object_ref(gestures)); return self; } @@ -124,20 +127,26 @@ gboolean maplibre_map_options_get_listens_on_long_click(MaplibreMapOptions* self return self->listens_on_long_click; } +MaplibreMapGestures* maplibre_map_options_get_gestures(MaplibreMapOptions* self) { + g_return_val_if_fail(MAPLIBRE_IS_MAP_OPTIONS(self), nullptr); + return self->gestures; +} + static FlValue* maplibre_map_options_to_list(MaplibreMapOptions* self) { FlValue* values = fl_value_new_list(); fl_value_append_take(values, fl_value_new_string(self->style)); fl_value_append_take(values, fl_value_new_float(self->zoom)); fl_value_append_take(values, fl_value_new_float(self->tilt)); fl_value_append_take(values, fl_value_new_float(self->bearing)); - fl_value_append_take(values, self->center != nullptr ? fl_value_new_custom_object(133, G_OBJECT(self->center)) : fl_value_new_null()); - fl_value_append_take(values, self->max_bounds != nullptr ? fl_value_new_custom_object(136, G_OBJECT(self->max_bounds)) : fl_value_new_null()); + fl_value_append_take(values, self->center != nullptr ? fl_value_new_custom_object(134, G_OBJECT(self->center)) : fl_value_new_null()); + fl_value_append_take(values, self->max_bounds != nullptr ? fl_value_new_custom_object(137, G_OBJECT(self->max_bounds)) : fl_value_new_null()); fl_value_append_take(values, fl_value_new_float(self->min_zoom)); fl_value_append_take(values, fl_value_new_float(self->max_zoom)); fl_value_append_take(values, fl_value_new_float(self->min_tilt)); fl_value_append_take(values, fl_value_new_float(self->max_tilt)); fl_value_append_take(values, fl_value_new_bool(self->listens_on_click)); fl_value_append_take(values, fl_value_new_bool(self->listens_on_long_click)); + fl_value_append_take(values, fl_value_new_custom_object(133, G_OBJECT(self->gestures))); return values; } @@ -172,7 +181,81 @@ static MaplibreMapOptions* maplibre_map_options_new_from_list(FlValue* values) { gboolean listens_on_click = fl_value_get_bool(value10); FlValue* value11 = fl_value_get_list_value(values, 11); gboolean listens_on_long_click = fl_value_get_bool(value11); - return maplibre_map_options_new(style, zoom, tilt, bearing, center, max_bounds, min_zoom, max_zoom, min_tilt, max_tilt, listens_on_click, listens_on_long_click); + FlValue* value12 = fl_value_get_list_value(values, 12); + MaplibreMapGestures* gestures = MAPLIBRE_MAP_GESTURES(fl_value_get_custom_value_object(value12)); + return maplibre_map_options_new(style, zoom, tilt, bearing, center, max_bounds, min_zoom, max_zoom, min_tilt, max_tilt, listens_on_click, listens_on_long_click, gestures); +} + +struct _MaplibreMapGestures { + GObject parent_instance; + + gboolean rotate; + gboolean pan; + gboolean zoom; + gboolean tilt; +}; + +G_DEFINE_TYPE(MaplibreMapGestures, maplibre_map_gestures, G_TYPE_OBJECT) + +static void maplibre_map_gestures_dispose(GObject* object) { + G_OBJECT_CLASS(maplibre_map_gestures_parent_class)->dispose(object); +} + +static void maplibre_map_gestures_init(MaplibreMapGestures* self) { +} + +static void maplibre_map_gestures_class_init(MaplibreMapGesturesClass* klass) { + G_OBJECT_CLASS(klass)->dispose = maplibre_map_gestures_dispose; +} + +MaplibreMapGestures* maplibre_map_gestures_new(gboolean rotate, gboolean pan, gboolean zoom, gboolean tilt) { + MaplibreMapGestures* self = MAPLIBRE_MAP_GESTURES(g_object_new(maplibre_map_gestures_get_type(), nullptr)); + self->rotate = rotate; + self->pan = pan; + self->zoom = zoom; + self->tilt = tilt; + return self; +} + +gboolean maplibre_map_gestures_get_rotate(MaplibreMapGestures* self) { + g_return_val_if_fail(MAPLIBRE_IS_MAP_GESTURES(self), FALSE); + return self->rotate; +} + +gboolean maplibre_map_gestures_get_pan(MaplibreMapGestures* self) { + g_return_val_if_fail(MAPLIBRE_IS_MAP_GESTURES(self), FALSE); + return self->pan; +} + +gboolean maplibre_map_gestures_get_zoom(MaplibreMapGestures* self) { + g_return_val_if_fail(MAPLIBRE_IS_MAP_GESTURES(self), FALSE); + return self->zoom; +} + +gboolean maplibre_map_gestures_get_tilt(MaplibreMapGestures* self) { + g_return_val_if_fail(MAPLIBRE_IS_MAP_GESTURES(self), FALSE); + return self->tilt; +} + +static FlValue* maplibre_map_gestures_to_list(MaplibreMapGestures* self) { + FlValue* values = fl_value_new_list(); + fl_value_append_take(values, fl_value_new_bool(self->rotate)); + fl_value_append_take(values, fl_value_new_bool(self->pan)); + fl_value_append_take(values, fl_value_new_bool(self->zoom)); + fl_value_append_take(values, fl_value_new_bool(self->tilt)); + return values; +} + +static MaplibreMapGestures* maplibre_map_gestures_new_from_list(FlValue* values) { + FlValue* value0 = fl_value_get_list_value(values, 0); + gboolean rotate = fl_value_get_bool(value0); + FlValue* value1 = fl_value_get_list_value(values, 1); + gboolean pan = fl_value_get_bool(value1); + FlValue* value2 = fl_value_get_list_value(values, 2); + gboolean zoom = fl_value_get_bool(value2); + FlValue* value3 = fl_value_get_list_value(values, 3); + gboolean tilt = fl_value_get_bool(value3); + return maplibre_map_gestures_new(rotate, pan, zoom, tilt); } struct _MaplibreLngLat { @@ -334,7 +417,7 @@ double maplibre_map_camera_get_bearing(MaplibreMapCamera* self) { static FlValue* maplibre_map_camera_to_list(MaplibreMapCamera* self) { FlValue* values = fl_value_new_list(); - fl_value_append_take(values, fl_value_new_custom_object(133, G_OBJECT(self->center))); + fl_value_append_take(values, fl_value_new_custom_object(134, G_OBJECT(self->center))); fl_value_append_take(values, fl_value_new_float(self->zoom)); fl_value_append_take(values, fl_value_new_float(self->tilt)); fl_value_append_take(values, fl_value_new_float(self->bearing)); @@ -459,29 +542,36 @@ static gboolean maplibre_message_codec_write_maplibre_map_options(FlStandardMess return fl_standard_message_codec_write_value(codec, buffer, values, error); } -static gboolean maplibre_message_codec_write_maplibre_lng_lat(FlStandardMessageCodec* codec, GByteArray* buffer, MaplibreLngLat* value, GError** error) { +static gboolean maplibre_message_codec_write_maplibre_map_gestures(FlStandardMessageCodec* codec, GByteArray* buffer, MaplibreMapGestures* value, GError** error) { uint8_t type = 133; g_byte_array_append(buffer, &type, sizeof(uint8_t)); + g_autoptr(FlValue) values = maplibre_map_gestures_to_list(value); + return fl_standard_message_codec_write_value(codec, buffer, values, error); +} + +static gboolean maplibre_message_codec_write_maplibre_lng_lat(FlStandardMessageCodec* codec, GByteArray* buffer, MaplibreLngLat* value, GError** error) { + uint8_t type = 134; + g_byte_array_append(buffer, &type, sizeof(uint8_t)); g_autoptr(FlValue) values = maplibre_lng_lat_to_list(value); return fl_standard_message_codec_write_value(codec, buffer, values, error); } static gboolean maplibre_message_codec_write_maplibre_screen_location(FlStandardMessageCodec* codec, GByteArray* buffer, MaplibreScreenLocation* value, GError** error) { - uint8_t type = 134; + uint8_t type = 135; g_byte_array_append(buffer, &type, sizeof(uint8_t)); g_autoptr(FlValue) values = maplibre_screen_location_to_list(value); return fl_standard_message_codec_write_value(codec, buffer, values, error); } static gboolean maplibre_message_codec_write_maplibre_map_camera(FlStandardMessageCodec* codec, GByteArray* buffer, MaplibreMapCamera* value, GError** error) { - uint8_t type = 135; + uint8_t type = 136; g_byte_array_append(buffer, &type, sizeof(uint8_t)); g_autoptr(FlValue) values = maplibre_map_camera_to_list(value); return fl_standard_message_codec_write_value(codec, buffer, values, error); } static gboolean maplibre_message_codec_write_maplibre_lng_lat_bounds(FlStandardMessageCodec* codec, GByteArray* buffer, MaplibreLngLatBounds* value, GError** error) { - uint8_t type = 136; + uint8_t type = 137; g_byte_array_append(buffer, &type, sizeof(uint8_t)); g_autoptr(FlValue) values = maplibre_lng_lat_bounds_to_list(value); return fl_standard_message_codec_write_value(codec, buffer, values, error); @@ -499,12 +589,14 @@ static gboolean maplibre_message_codec_write_value(FlStandardMessageCodec* codec case 132: return maplibre_message_codec_write_maplibre_map_options(codec, buffer, MAPLIBRE_MAP_OPTIONS(fl_value_get_custom_value_object(value)), error); case 133: - return maplibre_message_codec_write_maplibre_lng_lat(codec, buffer, MAPLIBRE_LNG_LAT(fl_value_get_custom_value_object(value)), error); + return maplibre_message_codec_write_maplibre_map_gestures(codec, buffer, MAPLIBRE_MAP_GESTURES(fl_value_get_custom_value_object(value)), error); case 134: - return maplibre_message_codec_write_maplibre_screen_location(codec, buffer, MAPLIBRE_SCREEN_LOCATION(fl_value_get_custom_value_object(value)), error); + return maplibre_message_codec_write_maplibre_lng_lat(codec, buffer, MAPLIBRE_LNG_LAT(fl_value_get_custom_value_object(value)), error); case 135: - return maplibre_message_codec_write_maplibre_map_camera(codec, buffer, MAPLIBRE_MAP_CAMERA(fl_value_get_custom_value_object(value)), error); + return maplibre_message_codec_write_maplibre_screen_location(codec, buffer, MAPLIBRE_SCREEN_LOCATION(fl_value_get_custom_value_object(value)), error); case 136: + return maplibre_message_codec_write_maplibre_map_camera(codec, buffer, MAPLIBRE_MAP_CAMERA(fl_value_get_custom_value_object(value)), error); + case 137: return maplibre_message_codec_write_maplibre_lng_lat_bounds(codec, buffer, MAPLIBRE_LNG_LAT_BOUNDS(fl_value_get_custom_value_object(value)), error); } } @@ -539,6 +631,21 @@ static FlValue* maplibre_message_codec_read_maplibre_map_options(FlStandardMessa return fl_value_new_custom_object(132, G_OBJECT(value)); } +static FlValue* maplibre_message_codec_read_maplibre_map_gestures(FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, GError** error) { + g_autoptr(FlValue) values = fl_standard_message_codec_read_value(codec, buffer, offset, error); + if (values == nullptr) { + return nullptr; + } + + g_autoptr(MaplibreMapGestures) value = maplibre_map_gestures_new_from_list(values); + if (value == nullptr) { + g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED, "Invalid data received for MessageData"); + return nullptr; + } + + return fl_value_new_custom_object(133, G_OBJECT(value)); +} + static FlValue* maplibre_message_codec_read_maplibre_lng_lat(FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, GError** error) { g_autoptr(FlValue) values = fl_standard_message_codec_read_value(codec, buffer, offset, error); if (values == nullptr) { @@ -551,7 +658,7 @@ static FlValue* maplibre_message_codec_read_maplibre_lng_lat(FlStandardMessageCo return nullptr; } - return fl_value_new_custom_object(133, G_OBJECT(value)); + return fl_value_new_custom_object(134, G_OBJECT(value)); } static FlValue* maplibre_message_codec_read_maplibre_screen_location(FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, GError** error) { @@ -566,7 +673,7 @@ static FlValue* maplibre_message_codec_read_maplibre_screen_location(FlStandardM return nullptr; } - return fl_value_new_custom_object(134, G_OBJECT(value)); + return fl_value_new_custom_object(135, G_OBJECT(value)); } static FlValue* maplibre_message_codec_read_maplibre_map_camera(FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, GError** error) { @@ -581,7 +688,7 @@ static FlValue* maplibre_message_codec_read_maplibre_map_camera(FlStandardMessag return nullptr; } - return fl_value_new_custom_object(135, G_OBJECT(value)); + return fl_value_new_custom_object(136, G_OBJECT(value)); } static FlValue* maplibre_message_codec_read_maplibre_lng_lat_bounds(FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, GError** error) { @@ -596,7 +703,7 @@ static FlValue* maplibre_message_codec_read_maplibre_lng_lat_bounds(FlStandardMe return nullptr; } - return fl_value_new_custom_object(136, G_OBJECT(value)); + return fl_value_new_custom_object(137, G_OBJECT(value)); } static FlValue* maplibre_message_codec_read_value_of_type(FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, int type, GError** error) { @@ -610,12 +717,14 @@ static FlValue* maplibre_message_codec_read_value_of_type(FlStandardMessageCodec case 132: return maplibre_message_codec_read_maplibre_map_options(codec, buffer, offset, error); case 133: - return maplibre_message_codec_read_maplibre_lng_lat(codec, buffer, offset, error); + return maplibre_message_codec_read_maplibre_map_gestures(codec, buffer, offset, error); case 134: - return maplibre_message_codec_read_maplibre_screen_location(codec, buffer, offset, error); + return maplibre_message_codec_read_maplibre_lng_lat(codec, buffer, offset, error); case 135: - return maplibre_message_codec_read_maplibre_map_camera(codec, buffer, offset, error); + return maplibre_message_codec_read_maplibre_screen_location(codec, buffer, offset, error); case 136: + return maplibre_message_codec_read_maplibre_map_camera(codec, buffer, offset, error); + case 137: return maplibre_message_codec_read_maplibre_lng_lat_bounds(codec, buffer, offset, error); default: return FL_STANDARD_MESSAGE_CODEC_CLASS(maplibre_message_codec_parent_class)->read_value_of_type(codec, buffer, offset, type, error); @@ -769,7 +878,7 @@ static void maplibre_map_libre_host_api_get_camera_response_class_init(MaplibreM static MaplibreMapLibreHostApiGetCameraResponse* maplibre_map_libre_host_api_get_camera_response_new(MaplibreMapCamera* return_value) { MaplibreMapLibreHostApiGetCameraResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_GET_CAMERA_RESPONSE(g_object_new(maplibre_map_libre_host_api_get_camera_response_get_type(), nullptr)); self->value = fl_value_new_list(); - fl_value_append_take(self->value, fl_value_new_custom_object(135, G_OBJECT(return_value))); + fl_value_append_take(self->value, fl_value_new_custom_object(136, G_OBJECT(return_value))); return self; } @@ -808,7 +917,7 @@ static void maplibre_map_libre_host_api_get_visible_region_response_class_init(M static MaplibreMapLibreHostApiGetVisibleRegionResponse* maplibre_map_libre_host_api_get_visible_region_response_new(MaplibreLngLatBounds* return_value) { MaplibreMapLibreHostApiGetVisibleRegionResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_GET_VISIBLE_REGION_RESPONSE(g_object_new(maplibre_map_libre_host_api_get_visible_region_response_get_type(), nullptr)); self->value = fl_value_new_list(); - fl_value_append_take(self->value, fl_value_new_custom_object(136, G_OBJECT(return_value))); + fl_value_append_take(self->value, fl_value_new_custom_object(137, G_OBJECT(return_value))); return self; } @@ -847,7 +956,7 @@ static void maplibre_map_libre_host_api_to_screen_location_response_class_init(M static MaplibreMapLibreHostApiToScreenLocationResponse* maplibre_map_libre_host_api_to_screen_location_response_new(MaplibreScreenLocation* return_value) { MaplibreMapLibreHostApiToScreenLocationResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_TO_SCREEN_LOCATION_RESPONSE(g_object_new(maplibre_map_libre_host_api_to_screen_location_response_get_type(), nullptr)); self->value = fl_value_new_list(); - fl_value_append_take(self->value, fl_value_new_custom_object(134, G_OBJECT(return_value))); + fl_value_append_take(self->value, fl_value_new_custom_object(135, G_OBJECT(return_value))); return self; } @@ -886,7 +995,7 @@ static void maplibre_map_libre_host_api_to_lng_lat_response_class_init(MaplibreM static MaplibreMapLibreHostApiToLngLatResponse* maplibre_map_libre_host_api_to_lng_lat_response_new(MaplibreLngLat* return_value) { MaplibreMapLibreHostApiToLngLatResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_TO_LNG_LAT_RESPONSE(g_object_new(maplibre_map_libre_host_api_to_lng_lat_response_get_type(), nullptr)); self->value = fl_value_new_list(); - fl_value_append_take(self->value, fl_value_new_custom_object(133, G_OBJECT(return_value))); + fl_value_append_take(self->value, fl_value_new_custom_object(134, G_OBJECT(return_value))); return self; } @@ -3220,7 +3329,7 @@ static void maplibre_map_libre_flutter_api_on_click_cb(GObject* object, GAsyncRe void maplibre_map_libre_flutter_api_on_click(MaplibreMapLibreFlutterApi* self, MaplibreLngLat* point, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_autoptr(FlValue) args = fl_value_new_list(); - fl_value_append_take(args, fl_value_new_custom_object(133, G_OBJECT(point))); + fl_value_append_take(args, fl_value_new_custom_object(134, G_OBJECT(point))); g_autofree gchar* channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreFlutterApi.onClick%s", self->suffix); g_autoptr(MaplibreMessageCodec) codec = maplibre_message_codec_new(); FlBasicMessageChannel* channel = fl_basic_message_channel_new(self->messenger, channel_name, FL_MESSAGE_CODEC(codec)); @@ -3455,7 +3564,7 @@ static void maplibre_map_libre_flutter_api_on_secondary_click_cb(GObject* object void maplibre_map_libre_flutter_api_on_secondary_click(MaplibreMapLibreFlutterApi* self, MaplibreLngLat* point, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_autoptr(FlValue) args = fl_value_new_list(); - fl_value_append_take(args, fl_value_new_custom_object(133, G_OBJECT(point))); + fl_value_append_take(args, fl_value_new_custom_object(134, G_OBJECT(point))); g_autofree gchar* channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreFlutterApi.onSecondaryClick%s", self->suffix); g_autoptr(MaplibreMessageCodec) codec = maplibre_message_codec_new(); FlBasicMessageChannel* channel = fl_basic_message_channel_new(self->messenger, channel_name, FL_MESSAGE_CODEC(codec)); @@ -3534,7 +3643,7 @@ static void maplibre_map_libre_flutter_api_on_double_click_cb(GObject* object, G void maplibre_map_libre_flutter_api_on_double_click(MaplibreMapLibreFlutterApi* self, MaplibreLngLat* point, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_autoptr(FlValue) args = fl_value_new_list(); - fl_value_append_take(args, fl_value_new_custom_object(133, G_OBJECT(point))); + fl_value_append_take(args, fl_value_new_custom_object(134, G_OBJECT(point))); g_autofree gchar* channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreFlutterApi.onDoubleClick%s", self->suffix); g_autoptr(MaplibreMessageCodec) codec = maplibre_message_codec_new(); FlBasicMessageChannel* channel = fl_basic_message_channel_new(self->messenger, channel_name, FL_MESSAGE_CODEC(codec)); @@ -3613,7 +3722,7 @@ static void maplibre_map_libre_flutter_api_on_long_click_cb(GObject* object, GAs void maplibre_map_libre_flutter_api_on_long_click(MaplibreMapLibreFlutterApi* self, MaplibreLngLat* point, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_autoptr(FlValue) args = fl_value_new_list(); - fl_value_append_take(args, fl_value_new_custom_object(133, G_OBJECT(point))); + fl_value_append_take(args, fl_value_new_custom_object(134, G_OBJECT(point))); g_autofree gchar* channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreFlutterApi.onLongClick%s", self->suffix); g_autoptr(MaplibreMessageCodec) codec = maplibre_message_codec_new(); FlBasicMessageChannel* channel = fl_basic_message_channel_new(self->messenger, channel_name, FL_MESSAGE_CODEC(codec)); @@ -3692,7 +3801,7 @@ static void maplibre_map_libre_flutter_api_on_move_camera_cb(GObject* object, GA void maplibre_map_libre_flutter_api_on_move_camera(MaplibreMapLibreFlutterApi* self, MaplibreMapCamera* camera, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_autoptr(FlValue) args = fl_value_new_list(); - fl_value_append_take(args, fl_value_new_custom_object(135, G_OBJECT(camera))); + fl_value_append_take(args, fl_value_new_custom_object(136, G_OBJECT(camera))); g_autofree gchar* channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreFlutterApi.onMoveCamera%s", self->suffix); g_autoptr(MaplibreMessageCodec) codec = maplibre_message_codec_new(); FlBasicMessageChannel* channel = fl_basic_message_channel_new(self->messenger, channel_name, FL_MESSAGE_CODEC(codec)); diff --git a/linux/pigeon.g.h b/linux/pigeon.g.h index ad6dc6b1..6ff38ec8 100644 --- a/linux/pigeon.g.h +++ b/linux/pigeon.g.h @@ -79,12 +79,13 @@ G_DECLARE_FINAL_TYPE(MaplibreMapOptions, maplibre_map_options, MAPLIBRE, MAP_OPT * max_tilt: field in this object. * listens_on_click: field in this object. * listens_on_long_click: field in this object. + * gestures: field in this object. * * Creates a new #MapOptions object. * * Returns: a new #MaplibreMapOptions */ -MaplibreMapOptions* maplibre_map_options_new(const gchar* style, double zoom, double tilt, double bearing, MaplibreLngLat* center, MaplibreLngLatBounds* max_bounds, double min_zoom, double max_zoom, double min_tilt, double max_tilt, gboolean listens_on_click, gboolean listens_on_long_click); +MaplibreMapOptions* maplibre_map_options_new(const gchar* style, double zoom, double tilt, double bearing, MaplibreLngLat* center, MaplibreLngLatBounds* max_bounds, double min_zoom, double max_zoom, double min_tilt, double max_tilt, gboolean listens_on_click, gboolean listens_on_long_click, MaplibreMapGestures* gestures); /** * maplibre_map_options_get_style @@ -206,6 +207,77 @@ gboolean maplibre_map_options_get_listens_on_click(MaplibreMapOptions* object); */ gboolean maplibre_map_options_get_listens_on_long_click(MaplibreMapOptions* object); +/** + * maplibre_map_options_get_gestures + * @object: a #MaplibreMapOptions. + * + * The map gestures. + * + * Returns: the field value. + */ +MaplibreMapGestures* maplibre_map_options_get_gestures(MaplibreMapOptions* object); + +/** + * MaplibreMapGestures: + * + * Map gestures + */ + +G_DECLARE_FINAL_TYPE(MaplibreMapGestures, maplibre_map_gestures, MAPLIBRE, MAP_GESTURES, GObject) + +/** + * maplibre_map_gestures_new: + * rotate: field in this object. + * pan: field in this object. + * zoom: field in this object. + * tilt: field in this object. + * + * Creates a new #MapGestures object. + * + * Returns: a new #MaplibreMapGestures + */ +MaplibreMapGestures* maplibre_map_gestures_new(gboolean rotate, gboolean pan, gboolean zoom, gboolean tilt); + +/** + * maplibre_map_gestures_get_rotate + * @object: a #MaplibreMapGestures. + * + * Rotate the map bearing. + * + * Returns: the field value. + */ +gboolean maplibre_map_gestures_get_rotate(MaplibreMapGestures* object); + +/** + * maplibre_map_gestures_get_pan + * @object: a #MaplibreMapGestures. + * + * Move the center of the map around. + * + * Returns: the field value. + */ +gboolean maplibre_map_gestures_get_pan(MaplibreMapGestures* object); + +/** + * maplibre_map_gestures_get_zoom + * @object: a #MaplibreMapGestures. + * + * Zoom the map in and out. + * + * Returns: the field value. + */ +gboolean maplibre_map_gestures_get_zoom(MaplibreMapGestures* object); + +/** + * maplibre_map_gestures_get_tilt + * @object: a #MaplibreMapGestures. + * + * Tilt (pitch) the map camera. + * + * Returns: the field value. + */ +gboolean maplibre_map_gestures_get_tilt(MaplibreMapGestures* object); + /** * MaplibreLngLat: * diff --git a/macos/Classes/Pigeon.g.swift b/macos/Classes/Pigeon.g.swift index e0a6b482..37d10641 100644 --- a/macos/Classes/Pigeon.g.swift +++ b/macos/Classes/Pigeon.g.swift @@ -125,6 +125,8 @@ struct MapOptions { var listensOnClick: Bool /// If the native map should listen to long click events. var listensOnLongClick: Bool + /// The map gestures. + var gestures: MapGestures @@ -142,6 +144,7 @@ struct MapOptions { let maxTilt = pigeonVar_list[9] as! Double let listensOnClick = pigeonVar_list[10] as! Bool let listensOnLongClick = pigeonVar_list[11] as! Bool + let gestures = pigeonVar_list[12] as! MapGestures return MapOptions( style: style, @@ -155,7 +158,8 @@ struct MapOptions { minTilt: minTilt, maxTilt: maxTilt, listensOnClick: listensOnClick, - listensOnLongClick: listensOnLongClick + listensOnLongClick: listensOnLongClick, + gestures: gestures ) } func toList() -> [Any?] { @@ -172,6 +176,46 @@ struct MapOptions { maxTilt, listensOnClick, listensOnLongClick, + gestures, + ] + } +} + +/// Map gestures +/// +/// Generated class from Pigeon that represents data sent in messages. +struct MapGestures { + /// Rotate the map bearing. + var rotate: Bool + /// Move the center of the map around. + var pan: Bool + /// Zoom the map in and out. + var zoom: Bool + /// Tilt (pitch) the map camera. + var tilt: Bool + + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> MapGestures? { + let rotate = pigeonVar_list[0] as! Bool + let pan = pigeonVar_list[1] as! Bool + let zoom = pigeonVar_list[2] as! Bool + let tilt = pigeonVar_list[3] as! Bool + + return MapGestures( + rotate: rotate, + pan: pan, + zoom: zoom, + tilt: tilt + ) + } + func toList() -> [Any?] { + return [ + rotate, + pan, + zoom, + tilt, ] } } @@ -328,12 +372,14 @@ private class PigeonPigeonCodecReader: FlutterStandardReader { case 132: return MapOptions.fromList(self.readValue() as! [Any?]) case 133: - return LngLat.fromList(self.readValue() as! [Any?]) + return MapGestures.fromList(self.readValue() as! [Any?]) case 134: - return ScreenLocation.fromList(self.readValue() as! [Any?]) + return LngLat.fromList(self.readValue() as! [Any?]) case 135: - return MapCamera.fromList(self.readValue() as! [Any?]) + return ScreenLocation.fromList(self.readValue() as! [Any?]) case 136: + return MapCamera.fromList(self.readValue() as! [Any?]) + case 137: return LngLatBounds.fromList(self.readValue() as! [Any?]) default: return super.readValue(ofType: type) @@ -355,18 +401,21 @@ private class PigeonPigeonCodecWriter: FlutterStandardWriter { } else if let value = value as? MapOptions { super.writeByte(132) super.writeValue(value.toList()) - } else if let value = value as? LngLat { + } else if let value = value as? MapGestures { super.writeByte(133) super.writeValue(value.toList()) - } else if let value = value as? ScreenLocation { + } else if let value = value as? LngLat { super.writeByte(134) super.writeValue(value.toList()) - } else if let value = value as? MapCamera { + } else if let value = value as? ScreenLocation { super.writeByte(135) super.writeValue(value.toList()) - } else if let value = value as? LngLatBounds { + } else if let value = value as? MapCamera { super.writeByte(136) super.writeValue(value.toList()) + } else if let value = value as? LngLatBounds { + super.writeByte(137) + super.writeValue(value.toList()) } else { super.writeValue(value) } diff --git a/pigeons/pigeon.dart b/pigeons/pigeon.dart index 9e305004..ef2ae227 100644 --- a/pigeons/pigeon.dart +++ b/pigeons/pigeon.dart @@ -298,6 +298,7 @@ class MapOptions { required this.maxTilt, required this.listensOnClick, required this.listensOnLongClick, + required this.gestures, }); /// The URL of the used map style. @@ -335,6 +336,32 @@ class MapOptions { /// If the native map should listen to long click events. final bool listensOnLongClick; + + /// The map gestures. + final MapGestures gestures; +} + +/// Map gestures +class MapGestures { + /// Create a new [MapGestures] object by setting all gestures. + const MapGestures({ + required this.rotate, + required this.pan, + required this.zoom, + required this.tilt, + }); + + /// Rotate the map bearing. + final bool rotate; + + /// Move the center of the map around. + final bool pan; + + /// Zoom the map in and out. + final bool zoom; + + /// Tilt (pitch) the map camera. + final bool tilt; } /// A longitude/latitude coordinate object. diff --git a/windows/runner/pigeon.g.cpp b/windows/runner/pigeon.g.cpp index 91f1f344..2143b60a 100644 --- a/windows/runner/pigeon.g.cpp +++ b/windows/runner/pigeon.g.cpp @@ -40,7 +40,8 @@ MapOptions::MapOptions( double min_tilt, double max_tilt, bool listens_on_click, - bool listens_on_long_click) + bool listens_on_long_click, + const MapGestures& gestures) : style_(style), zoom_(zoom), tilt_(tilt), @@ -50,7 +51,8 @@ MapOptions::MapOptions( min_tilt_(min_tilt), max_tilt_(max_tilt), listens_on_click_(listens_on_click), - listens_on_long_click_(listens_on_long_click) {} + listens_on_long_click_(listens_on_long_click), + gestures_(std::make_unique(gestures)) {} MapOptions::MapOptions( const std::string& style, @@ -64,7 +66,8 @@ MapOptions::MapOptions( double min_tilt, double max_tilt, bool listens_on_click, - bool listens_on_long_click) + bool listens_on_long_click, + const MapGestures& gestures) : style_(style), zoom_(zoom), tilt_(tilt), @@ -76,7 +79,8 @@ MapOptions::MapOptions( min_tilt_(min_tilt), max_tilt_(max_tilt), listens_on_click_(listens_on_click), - listens_on_long_click_(listens_on_long_click) {} + listens_on_long_click_(listens_on_long_click), + gestures_(std::make_unique(gestures)) {} MapOptions::MapOptions(const MapOptions& other) : style_(other.style_), @@ -90,7 +94,8 @@ MapOptions::MapOptions(const MapOptions& other) min_tilt_(other.min_tilt_), max_tilt_(other.max_tilt_), listens_on_click_(other.listens_on_click_), - listens_on_long_click_(other.listens_on_long_click_) {} + listens_on_long_click_(other.listens_on_long_click_), + gestures_(std::make_unique(*other.gestures_)) {} MapOptions& MapOptions::operator=(const MapOptions& other) { style_ = other.style_; @@ -105,6 +110,7 @@ MapOptions& MapOptions::operator=(const MapOptions& other) { max_tilt_ = other.max_tilt_; listens_on_click_ = other.listens_on_click_; listens_on_long_click_ = other.listens_on_long_click_; + gestures_ = std::make_unique(*other.gestures_); return *this; } @@ -224,9 +230,18 @@ void MapOptions::set_listens_on_long_click(bool value_arg) { } +const MapGestures& MapOptions::gestures() const { + return *gestures_; +} + +void MapOptions::set_gestures(const MapGestures& value_arg) { + gestures_ = std::make_unique(value_arg); +} + + EncodableList MapOptions::ToEncodableList() const { EncodableList list; - list.reserve(12); + list.reserve(13); list.push_back(EncodableValue(style_)); list.push_back(EncodableValue(zoom_)); list.push_back(EncodableValue(tilt_)); @@ -239,6 +254,7 @@ EncodableList MapOptions::ToEncodableList() const { list.push_back(EncodableValue(max_tilt_)); list.push_back(EncodableValue(listens_on_click_)); list.push_back(EncodableValue(listens_on_long_click_)); + list.push_back(CustomEncodableValue(*gestures_)); return list; } @@ -253,7 +269,8 @@ MapOptions MapOptions::FromEncodableList(const EncodableList& list) { std::get(list[8]), std::get(list[9]), std::get(list[10]), - std::get(list[11])); + std::get(list[11]), + std::any_cast(std::get(list[12]))); auto& encodable_center = list[4]; if (!encodable_center.IsNull()) { decoded.set_center(std::any_cast(std::get(encodable_center))); @@ -265,6 +282,73 @@ MapOptions MapOptions::FromEncodableList(const EncodableList& list) { return decoded; } +// MapGestures + +MapGestures::MapGestures( + bool rotate, + bool pan, + bool zoom, + bool tilt) + : rotate_(rotate), + pan_(pan), + zoom_(zoom), + tilt_(tilt) {} + +bool MapGestures::rotate() const { + return rotate_; +} + +void MapGestures::set_rotate(bool value_arg) { + rotate_ = value_arg; +} + + +bool MapGestures::pan() const { + return pan_; +} + +void MapGestures::set_pan(bool value_arg) { + pan_ = value_arg; +} + + +bool MapGestures::zoom() const { + return zoom_; +} + +void MapGestures::set_zoom(bool value_arg) { + zoom_ = value_arg; +} + + +bool MapGestures::tilt() const { + return tilt_; +} + +void MapGestures::set_tilt(bool value_arg) { + tilt_ = value_arg; +} + + +EncodableList MapGestures::ToEncodableList() const { + EncodableList list; + list.reserve(4); + list.push_back(EncodableValue(rotate_)); + list.push_back(EncodableValue(pan_)); + list.push_back(EncodableValue(zoom_)); + list.push_back(EncodableValue(tilt_)); + return list; +} + +MapGestures MapGestures::FromEncodableList(const EncodableList& list) { + MapGestures decoded( + std::get(list[0]), + std::get(list[1]), + std::get(list[2]), + std::get(list[3])); + return decoded; +} + // LngLat LngLat::LngLat( @@ -521,15 +605,18 @@ EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( return CustomEncodableValue(MapOptions::FromEncodableList(std::get(ReadValue(stream)))); } case 133: { - return CustomEncodableValue(LngLat::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(MapGestures::FromEncodableList(std::get(ReadValue(stream)))); } case 134: { - return CustomEncodableValue(ScreenLocation::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(LngLat::FromEncodableList(std::get(ReadValue(stream)))); } case 135: { - return CustomEncodableValue(MapCamera::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(ScreenLocation::FromEncodableList(std::get(ReadValue(stream)))); } case 136: { + return CustomEncodableValue(MapCamera::FromEncodableList(std::get(ReadValue(stream)))); + } + case 137: { return CustomEncodableValue(LngLatBounds::FromEncodableList(std::get(ReadValue(stream)))); } default: @@ -561,23 +648,28 @@ void PigeonInternalCodecSerializer::WriteValue( WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } - if (custom_value->type() == typeid(LngLat)) { + if (custom_value->type() == typeid(MapGestures)) { stream->WriteByte(133); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(LngLat)) { + stream->WriteByte(134); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(ScreenLocation)) { - stream->WriteByte(134); + stream->WriteByte(135); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(MapCamera)) { - stream->WriteByte(135); + stream->WriteByte(136); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(LngLatBounds)) { - stream->WriteByte(136); + stream->WriteByte(137); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } diff --git a/windows/runner/pigeon.g.h b/windows/runner/pigeon.g.h index a05a8d62..5ff26cb1 100644 --- a/windows/runner/pigeon.g.h +++ b/windows/runner/pigeon.g.h @@ -103,7 +103,8 @@ class MapOptions { double min_tilt, double max_tilt, bool listens_on_click, - bool listens_on_long_click); + bool listens_on_long_click, + const MapGestures& gestures); // Constructs an object setting all fields. explicit MapOptions( @@ -118,7 +119,8 @@ class MapOptions { double min_tilt, double max_tilt, bool listens_on_click, - bool listens_on_long_click); + bool listens_on_long_click, + const MapGestures& gestures); ~MapOptions() = default; MapOptions(const MapOptions& other); @@ -175,6 +177,10 @@ class MapOptions { bool listens_on_long_click() const; void set_listens_on_long_click(bool value_arg); + // The map gestures. + const MapGestures& gestures() const; + void set_gestures(const MapGestures& value_arg); + private: static MapOptions FromEncodableList(const flutter::EncodableList& list); @@ -194,6 +200,51 @@ class MapOptions { double max_tilt_; bool listens_on_click_; bool listens_on_long_click_; + std::unique_ptr gestures_; + +}; + + +// Map gestures +// +// Generated class from Pigeon that represents data sent in messages. +class MapGestures { + public: + // Constructs an object setting all fields. + explicit MapGestures( + bool rotate, + bool pan, + bool zoom, + bool tilt); + + // Rotate the map bearing. + bool rotate() const; + void set_rotate(bool value_arg); + + // Move the center of the map around. + bool pan() const; + void set_pan(bool value_arg); + + // Zoom the map in and out. + bool zoom() const; + void set_zoom(bool value_arg); + + // Tilt (pitch) the map camera. + bool tilt() const; + void set_tilt(bool value_arg); + + + private: + static MapGestures FromEncodableList(const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class MapOptions; + friend class MapLibreHostApi; + friend class MapLibreFlutterApi; + friend class PigeonInternalCodecSerializer; + bool rotate_; + bool pan_; + bool zoom_; + bool tilt_; };