flet-map 0.1.0.dev2__py3-none-any.whl → 0.2.0.dev45__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of flet-map might be problematic. Click here for more details.
- flet_map/__init__.py +30 -19
- flet_map/circle_layer.py +46 -139
- flet_map/map.py +462 -604
- flet_map/map_layer.py +14 -20
- flet_map/marker_layer.py +83 -169
- flet_map/polygon_layer.py +95 -232
- flet_map/polyline_layer.py +85 -262
- flet_map/rich_attribution.py +48 -126
- flet_map/simple_attribution.py +24 -75
- flet_map/source_attribution.py +73 -0
- flet_map/tile_layer.py +224 -266
- flet_map/types.py +953 -0
- flet_map-0.2.0.dev45.dist-info/METADATA +66 -0
- flet_map-0.2.0.dev45.dist-info/RECORD +35 -0
- {flet_map-0.1.0.dev2.dist-info → flet_map-0.2.0.dev45.dist-info}/WHEEL +1 -1
- flet_map-0.2.0.dev45.dist-info/licenses/LICENSE +201 -0
- flutter/flet_map/CHANGELOG.md +4 -0
- flutter/flet_map/lib/flet_map.dart +1 -1
- flutter/flet_map/lib/src/circle_layer.dart +15 -25
- flutter/flet_map/lib/src/extension.dart +37 -0
- flutter/flet_map/lib/src/map.dart +93 -105
- flutter/flet_map/lib/src/marker_layer.dart +21 -33
- flutter/flet_map/lib/src/polygon_layer.dart +32 -52
- flutter/flet_map/lib/src/polyline_layer.dart +41 -64
- flutter/flet_map/lib/src/rich_attribution.dart +34 -34
- flutter/flet_map/lib/src/simple_attribution.dart +9 -23
- flutter/flet_map/lib/src/tile_layer.dart +47 -60
- flutter/flet_map/lib/src/utils/attribution_alignment.dart +1 -3
- flutter/flet_map/lib/src/utils/map.dart +257 -203
- flutter/flet_map/pubspec.lock +179 -130
- flutter/flet_map/pubspec.yaml +10 -5
- flet_map/text_source_attribution.py +0 -87
- flet_map-0.1.0.dev2.dist-info/METADATA +0 -168
- flet_map-0.1.0.dev2.dist-info/RECORD +0 -34
- flutter/flet_map/lib/src/create_control.dart +0 -70
- flutter/flet_map/lib/src/text_source_attribution.dart +0 -29
- {flet_map-0.1.0.dev2.dist-info → flet_map-0.2.0.dev45.dist-info}/top_level.txt +0 -0
flet_map/types.py
ADDED
|
@@ -0,0 +1,953 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from enum import Enum, IntFlag
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
|
|
5
|
+
import flet as ft
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"TileLayerEvictErrorTileStrategy",
|
|
9
|
+
"AttributionAlignment",
|
|
10
|
+
"PatternFit",
|
|
11
|
+
"Camera",
|
|
12
|
+
"StrokePattern",
|
|
13
|
+
"SolidStrokePattern",
|
|
14
|
+
"DashedStrokePattern",
|
|
15
|
+
"DottedStrokePattern",
|
|
16
|
+
"MapLatitudeLongitude",
|
|
17
|
+
"MapLatitudeLongitudeBounds",
|
|
18
|
+
"InteractionFlag",
|
|
19
|
+
"MultiFingerGesture",
|
|
20
|
+
"InteractionConfiguration",
|
|
21
|
+
"MapEventSource",
|
|
22
|
+
"CameraFit",
|
|
23
|
+
"MapTapEvent",
|
|
24
|
+
"MapHoverEvent",
|
|
25
|
+
"MapPositionChangeEvent",
|
|
26
|
+
"MapPointerEvent",
|
|
27
|
+
"MapEvent",
|
|
28
|
+
"TileDisplay",
|
|
29
|
+
"InstantaneousTileDisplay",
|
|
30
|
+
"FadeInTileDisplay",
|
|
31
|
+
"KeyboardConfiguration",
|
|
32
|
+
"CursorRotationBehaviour",
|
|
33
|
+
"CursorKeyboardRotationConfiguration",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class TileLayerEvictErrorTileStrategy(Enum):
|
|
38
|
+
"""Strategies on how to handle tile errors."""
|
|
39
|
+
|
|
40
|
+
NONE = "none"
|
|
41
|
+
"""Never evict images for tiles which failed to load."""
|
|
42
|
+
|
|
43
|
+
DISPOSE = "dispose"
|
|
44
|
+
"""Evict images for tiles which failed to load when they are pruned."""
|
|
45
|
+
|
|
46
|
+
NOT_VISIBLE = "notVisible"
|
|
47
|
+
"""
|
|
48
|
+
Evict images for tiles which failed to load and:
|
|
49
|
+
- do not belong to the current zoom level AND/OR
|
|
50
|
+
- are not visible
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
NOT_VISIBLE_RESPECT_MARGIN = "notVisibleRespectMargin"
|
|
54
|
+
"""
|
|
55
|
+
Evict images for tiles which failed to load and:
|
|
56
|
+
- do not belong to the current zoom level AND/OR
|
|
57
|
+
- are not visible, respecting the pruning buffer (the maximum of the `keep_buffer` and `pan_buffer`).
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class AttributionAlignment(Enum):
|
|
62
|
+
"""Position to anchor [`RichAttribution`][(p).] control relative to the map."""
|
|
63
|
+
|
|
64
|
+
BOTTOM_LEFT = "bottomLeft"
|
|
65
|
+
"""The bottom left corner."""
|
|
66
|
+
|
|
67
|
+
BOTTOM_RIGHT = "bottomRight"
|
|
68
|
+
"""The bottom right corner."""
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class PatternFit(Enum):
|
|
72
|
+
"""
|
|
73
|
+
Determines how a non-solid [`StrokePattern`][(p).] should be fit to a line
|
|
74
|
+
when their lengths are not equal or multiples
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
NONE = "none"
|
|
78
|
+
"""
|
|
79
|
+
Don't apply any specific fit to the pattern - repeat exactly as specified,
|
|
80
|
+
and stop when the last point is reached.
|
|
81
|
+
|
|
82
|
+
Not recommended, as it may leave a gap between the final segment and the last
|
|
83
|
+
point, making it unclear where the line ends.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
SCALE_DOWN = "scaleDown"
|
|
87
|
+
"""
|
|
88
|
+
Scale the pattern to ensure it fits an integer number of times into the
|
|
89
|
+
polyline (smaller version regarding rounding, cf. [`SCALE_UP`][..]).
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
SCALE_UP = "scaleUp"
|
|
93
|
+
"""
|
|
94
|
+
Scale the pattern to ensure it fits an integer number of times into the
|
|
95
|
+
polyline (bigger version regarding rounding, cf. [`SCALE_DOWN`][..]).
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
APPEND_DOT = "appendDot"
|
|
99
|
+
"""
|
|
100
|
+
Uses the pattern exactly, truncating the final dash if it does not fit, or
|
|
101
|
+
adding a single dot at the last point if the final dash does not reach the
|
|
102
|
+
last point (there is a gap at that location).
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
EXTEND_FINAL_DASH = "extendFinalDash"
|
|
106
|
+
"""
|
|
107
|
+
Uses the pattern exactly, truncating the final dash if it does not fit, or
|
|
108
|
+
extending the final dash to the last point if it would not normally reach
|
|
109
|
+
that point (there is a gap at that location).
|
|
110
|
+
|
|
111
|
+
Only useful when working with [`DashedStrokePattern`][(p).].
|
|
112
|
+
Similar to `APPEND_DOT` for `DottedStrokePattern`.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@dataclass
|
|
117
|
+
class Camera:
|
|
118
|
+
center: "MapLatitudeLongitude"
|
|
119
|
+
"""
|
|
120
|
+
The center of this camera.
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
zoom: ft.Number
|
|
124
|
+
"""
|
|
125
|
+
Defines how far this camera is zoomed.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
min_zoom: ft.Number
|
|
129
|
+
"""
|
|
130
|
+
The minimum allowed zoom level.
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
max_zoom: ft.Number
|
|
134
|
+
"""
|
|
135
|
+
The maximum allowed zoom level.
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
rotation: ft.Number
|
|
139
|
+
"""
|
|
140
|
+
The rotation (in degrees) of the camera.
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@dataclass(kw_only=True)
|
|
145
|
+
class StrokePattern:
|
|
146
|
+
"""
|
|
147
|
+
Determines whether a stroke should be solid, dotted, or dashed,
|
|
148
|
+
and the exact characteristics of each.
|
|
149
|
+
|
|
150
|
+
This is an abstract class and shouldn't be used directly.
|
|
151
|
+
|
|
152
|
+
See usable derivatives:
|
|
153
|
+
- [`SolidStrokePattern`][(p).]
|
|
154
|
+
- [`DashedStrokePattern`][(p).]
|
|
155
|
+
- [`DottedStrokePattern`][(p).]
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
_type: str = ""
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@dataclass
|
|
162
|
+
class SolidStrokePattern(StrokePattern):
|
|
163
|
+
"""A solid/unbroken stroke pattern."""
|
|
164
|
+
|
|
165
|
+
def __post_init__(self):
|
|
166
|
+
self._type = "solid"
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
@dataclass
|
|
170
|
+
class DashedStrokePattern(StrokePattern):
|
|
171
|
+
"""
|
|
172
|
+
A stroke pattern of alternating dashes and gaps, defined by [`segments`][(c).].
|
|
173
|
+
|
|
174
|
+
Raises:
|
|
175
|
+
AssertionError: If `segments` does not contain at least two items, or has an odd length.
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
segments: List[ft.Number] = field(default_factory=list)
|
|
179
|
+
"""
|
|
180
|
+
A list of alternating dash and gap lengths, in pixels.
|
|
181
|
+
|
|
182
|
+
Note:
|
|
183
|
+
Must contain at least two items, and have an even length.
|
|
184
|
+
"""
|
|
185
|
+
pattern_fit: PatternFit = PatternFit.SCALE_UP
|
|
186
|
+
"""
|
|
187
|
+
Determines how this stroke pattern should be fit to a line when their lengths are not equal or multiples.
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
def __post_init__(self):
|
|
191
|
+
assert len(self.segments) >= 2, "segments must contain at least two items"
|
|
192
|
+
assert len(self.segments) % 2 == 0, "segments must have an even length"
|
|
193
|
+
self._type = "dashed"
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@dataclass
|
|
197
|
+
class DottedStrokePattern(StrokePattern):
|
|
198
|
+
"""
|
|
199
|
+
A stroke pattern of circular dots, spaced with [`spacing_factor`][(c).].
|
|
200
|
+
|
|
201
|
+
Raises:
|
|
202
|
+
AssertionError: If [`spacing_factor`][(c).] is negative.
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
spacing_factor: ft.Number = 1.5
|
|
206
|
+
"""
|
|
207
|
+
The multiplier used to calculate the spacing between dots in a dotted polyline,
|
|
208
|
+
with respect to `Polyline.stroke_width` / `Polygon.border_stroke_width`.
|
|
209
|
+
A value of `1.0` will result in spacing equal to the `stroke_width`.
|
|
210
|
+
Increasing the value increases the spacing with the same scaling.
|
|
211
|
+
|
|
212
|
+
May also be scaled by the use of [`PatternFit.SCALE_UP`][(p).].
|
|
213
|
+
|
|
214
|
+
Note:
|
|
215
|
+
Must be non-negative.
|
|
216
|
+
"""
|
|
217
|
+
pattern_fit: PatternFit = PatternFit.SCALE_UP
|
|
218
|
+
"""
|
|
219
|
+
Determines how this stroke pattern should be fit to a line when their lengths are not equal or multiples.
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
def __post_init__(self):
|
|
223
|
+
assert (
|
|
224
|
+
self.spacing_factor > 0
|
|
225
|
+
), "spacing_factor must be greater than or equal to 0.0"
|
|
226
|
+
self._type = "dotted"
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
@dataclass
|
|
230
|
+
class MapLatitudeLongitude:
|
|
231
|
+
"""Map coordinates in degrees."""
|
|
232
|
+
|
|
233
|
+
latitude: ft.Number
|
|
234
|
+
"""The latitude point of this coordinate."""
|
|
235
|
+
|
|
236
|
+
longitude: ft.Number
|
|
237
|
+
"""The longitude point of this coordinate."""
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@dataclass
|
|
241
|
+
class MapLatitudeLongitudeBounds:
|
|
242
|
+
"""
|
|
243
|
+
Both corners have to be on opposite sites, but it doesn't matter
|
|
244
|
+
which opposite corners or in what order the corners are provided.
|
|
245
|
+
"""
|
|
246
|
+
|
|
247
|
+
corner_1: MapLatitudeLongitude
|
|
248
|
+
"""The corner 1."""
|
|
249
|
+
|
|
250
|
+
corner_2: MapLatitudeLongitude
|
|
251
|
+
"""The corner 2."""
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class InteractionFlag(IntFlag):
|
|
255
|
+
"""
|
|
256
|
+
Flags to enable/disable certain interaction events on the map.
|
|
257
|
+
|
|
258
|
+
Example:
|
|
259
|
+
- `InteractionFlag.ALL` to enable all events
|
|
260
|
+
- `InteractionFlag.NONE` to disable all events
|
|
261
|
+
"""
|
|
262
|
+
|
|
263
|
+
NONE = 0
|
|
264
|
+
"""No interaction."""
|
|
265
|
+
|
|
266
|
+
DRAG = 1 << 0
|
|
267
|
+
"""Panning with a single finger or cursor."""
|
|
268
|
+
|
|
269
|
+
FLING_ANIMATION = 1 << 1
|
|
270
|
+
"""Fling animation after panning if velocity is great enough."""
|
|
271
|
+
|
|
272
|
+
PINCH_MOVE = 1 << 2
|
|
273
|
+
"""Panning with multiple fingers."""
|
|
274
|
+
|
|
275
|
+
PINCH_ZOOM = 1 << 3
|
|
276
|
+
"""Zooming with a multi-finger pinch gesture."""
|
|
277
|
+
|
|
278
|
+
DOUBLE_TAP_ZOOM = 1 << 4
|
|
279
|
+
"""Zooming with a single-finger double tap gesture."""
|
|
280
|
+
|
|
281
|
+
DOUBLE_TAP_DRAG_ZOOM = 1 << 5
|
|
282
|
+
"""Zooming with a single-finger double-tap-drag gesture."""
|
|
283
|
+
|
|
284
|
+
SCROLL_WHEEL_ZOOM = 1 << 6
|
|
285
|
+
"""Zooming with a mouse scroll wheel."""
|
|
286
|
+
|
|
287
|
+
ROTATE = 1 << 7
|
|
288
|
+
"""Rotation with two-finger twist gesture."""
|
|
289
|
+
|
|
290
|
+
ALL = (
|
|
291
|
+
(1 << 0)
|
|
292
|
+
| (1 << 1)
|
|
293
|
+
| (1 << 2)
|
|
294
|
+
| (1 << 3)
|
|
295
|
+
| (1 << 4)
|
|
296
|
+
| (1 << 5)
|
|
297
|
+
| (1 << 6)
|
|
298
|
+
| (1 << 7)
|
|
299
|
+
)
|
|
300
|
+
"""All available interactive flags."""
|
|
301
|
+
|
|
302
|
+
@staticmethod
|
|
303
|
+
def has_flag(left_flags: int, right_flags: int) -> bool:
|
|
304
|
+
"""
|
|
305
|
+
Returns:
|
|
306
|
+
`True` if `left_flags` has at least one member in `right_flags` (intersection).
|
|
307
|
+
"""
|
|
308
|
+
return left_flags & right_flags != 0
|
|
309
|
+
|
|
310
|
+
@staticmethod
|
|
311
|
+
def has_multi_finger(flags: int) -> bool:
|
|
312
|
+
"""
|
|
313
|
+
Returns:
|
|
314
|
+
`True` if any multi-finger gesture flags
|
|
315
|
+
([`MultiFingerGesture.PINCH_MOVE`][(p).], [`MultiFingerGesture.PINCH_ZOOM`][(p).], [`MultiFingerGesture.ROTATE`][(p).]) are enabled.
|
|
316
|
+
"""
|
|
317
|
+
return InteractionFlag.has_flag(
|
|
318
|
+
flags,
|
|
319
|
+
(
|
|
320
|
+
MultiFingerGesture.PINCH_MOVE
|
|
321
|
+
| MultiFingerGesture.PINCH_ZOOM
|
|
322
|
+
| MultiFingerGesture.ROTATE
|
|
323
|
+
),
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
@staticmethod
|
|
327
|
+
def has_drag(flags: int) -> bool:
|
|
328
|
+
"""
|
|
329
|
+
Returns:
|
|
330
|
+
`True` if the [`DRAG`][..] interactive flag is enabled.
|
|
331
|
+
"""
|
|
332
|
+
return InteractionFlag.has_flag(flags, InteractionFlag.DRAG)
|
|
333
|
+
|
|
334
|
+
@staticmethod
|
|
335
|
+
def has_fling_animation(flags: int) -> bool:
|
|
336
|
+
"""
|
|
337
|
+
Returns:
|
|
338
|
+
`True` if the [`FLING_ANIMATION`][..] interactive flag is enabled.
|
|
339
|
+
"""
|
|
340
|
+
return InteractionFlag.has_flag(flags, InteractionFlag.FLING_ANIMATION)
|
|
341
|
+
|
|
342
|
+
@staticmethod
|
|
343
|
+
def has_pinch_move(flags: int) -> bool:
|
|
344
|
+
"""
|
|
345
|
+
Returns:
|
|
346
|
+
`True` if the [`PINCH_MOVE`][..] interactive flag is enabled.
|
|
347
|
+
"""
|
|
348
|
+
return InteractionFlag.has_flag(flags, InteractionFlag.PINCH_MOVE)
|
|
349
|
+
|
|
350
|
+
@staticmethod
|
|
351
|
+
def has_fling_pinch_zoom(flags: int) -> bool:
|
|
352
|
+
"""
|
|
353
|
+
Returns:
|
|
354
|
+
`True` if the [`PINCH_ZOOM`][..] interactive flag is enabled.
|
|
355
|
+
"""
|
|
356
|
+
return InteractionFlag.has_flag(flags, InteractionFlag.PINCH_ZOOM)
|
|
357
|
+
|
|
358
|
+
@staticmethod
|
|
359
|
+
def has_double_tap_drag_zoom(flags: int) -> bool:
|
|
360
|
+
"""
|
|
361
|
+
Returns:
|
|
362
|
+
`True` if the [`DOUBLE_TAP_DRAG_ZOOM`][..] interactive flag is enabled.
|
|
363
|
+
"""
|
|
364
|
+
return InteractionFlag.has_flag(flags, InteractionFlag.DOUBLE_TAP_DRAG_ZOOM)
|
|
365
|
+
|
|
366
|
+
@staticmethod
|
|
367
|
+
def has_double_tap_zoom(flags: int) -> bool:
|
|
368
|
+
"""
|
|
369
|
+
Returns:
|
|
370
|
+
`True` if the [`DOUBLE_TAP_ZOOM`][..] interactive flag is enabled.
|
|
371
|
+
"""
|
|
372
|
+
return InteractionFlag.has_flag(flags, InteractionFlag.DOUBLE_TAP_ZOOM)
|
|
373
|
+
|
|
374
|
+
@staticmethod
|
|
375
|
+
def has_rotate(flags: int) -> bool:
|
|
376
|
+
"""
|
|
377
|
+
Returns:
|
|
378
|
+
`True` if the [`ROTATE`][..] interactive flag is enabled.
|
|
379
|
+
"""
|
|
380
|
+
return InteractionFlag.has_flag(flags, InteractionFlag.ROTATE)
|
|
381
|
+
|
|
382
|
+
@staticmethod
|
|
383
|
+
def has_scroll_wheel_zoom(flags: int) -> bool:
|
|
384
|
+
"""
|
|
385
|
+
Returns:
|
|
386
|
+
`True` if the [`SCROLL_WHEEL_ZOOM`][..] interactive flag is enabled.
|
|
387
|
+
"""
|
|
388
|
+
return InteractionFlag.has_flag(flags, InteractionFlag.SCROLL_WHEEL_ZOOM)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
class MultiFingerGesture(IntFlag):
|
|
392
|
+
"""Flags to enable/disable certain multi-finger gestures on the map."""
|
|
393
|
+
|
|
394
|
+
NONE = 0
|
|
395
|
+
"""No multi-finger gesture."""
|
|
396
|
+
|
|
397
|
+
PINCH_MOVE = 1 << 0
|
|
398
|
+
"""Pinch move gesture, which allows moving the map by dragging with two fingers."""
|
|
399
|
+
|
|
400
|
+
PINCH_ZOOM = 1 << 1
|
|
401
|
+
"""Pinch zoom gesture, which allows zooming in and out by pinching with two fingers."""
|
|
402
|
+
|
|
403
|
+
ROTATE = 1 << 2
|
|
404
|
+
"""Rotate gesture, which allows rotating the map by twisting two fingers."""
|
|
405
|
+
|
|
406
|
+
ALL = (1 << 0) | (1 << 1) | (1 << 2)
|
|
407
|
+
"""All multi-finger gestures defined in this enum."""
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
@dataclass
|
|
411
|
+
class InteractionConfiguration:
|
|
412
|
+
enable_multi_finger_gesture_race: bool = False
|
|
413
|
+
"""
|
|
414
|
+
If `True`, then [`rotation_threshold`][..] and [`pinch_zoom_threshold`][..] and [`pinch_move_threshold`][..] will race.
|
|
415
|
+
If multiple gestures win at the same time,
|
|
416
|
+
then precedence: [`pinch_zoom_win_gestures`][..] > [`rotation_win_gestures`][..] > [`pinch_move_win_gestures`][..]
|
|
417
|
+
"""
|
|
418
|
+
|
|
419
|
+
pinch_move_threshold: ft.Number = 40.0
|
|
420
|
+
"""
|
|
421
|
+
Map starts to move when `pinch_move_threshold` has been achieved
|
|
422
|
+
or another multi finger gesture wins which allows [`MultiFingerGesture.PINCH_MOVE`][(p).].
|
|
423
|
+
|
|
424
|
+
Note:
|
|
425
|
+
If [`InteractionConfiguration.flags`][(p).] doesn't contain [`InteractionFlag.PINCH_MOVE`][(p).]
|
|
426
|
+
or [`enable_multi_finger_gesture_race`][..] is false then pinch move cannot win.
|
|
427
|
+
"""
|
|
428
|
+
|
|
429
|
+
scroll_wheel_velocity: ft.Number = 0.005
|
|
430
|
+
"""
|
|
431
|
+
The used velocity how fast the map should zoom in or out by scrolling with the scroll wheel of a mouse.
|
|
432
|
+
"""
|
|
433
|
+
|
|
434
|
+
pinch_zoom_threshold: ft.Number = 0.5
|
|
435
|
+
"""
|
|
436
|
+
Map starts to zoom when `pinch_zoom_threshold` has been achieved or
|
|
437
|
+
another multi finger gesture wins which allows [`MultiFingerGesture.PINCH_ZOOM`][(p).].
|
|
438
|
+
|
|
439
|
+
Note:
|
|
440
|
+
If [`InteractionConfiguration.flags`][(p).] doesn't contain [`InteractionFlag.PINCH_ZOOM`][(p).]
|
|
441
|
+
or [`enable_multi_finger_gesture_race`][..] is false then zoom cannot win.
|
|
442
|
+
"""
|
|
443
|
+
|
|
444
|
+
rotation_threshold: ft.Number = 20.0
|
|
445
|
+
"""
|
|
446
|
+
Map starts to rotate when `rotation_threshold` has been achieved or
|
|
447
|
+
another multi finger gesture wins which allows [`MultiFingerGesture.ROTATE`][(p).].
|
|
448
|
+
|
|
449
|
+
Note:
|
|
450
|
+
If [`InteractionConfiguration.flags`][(p).] doesn't contain [`InteractionFlag.ROTATE`][(p).]
|
|
451
|
+
or [`enable_multi_finger_gesture_race`][..] is false then rotate cannot win.
|
|
452
|
+
"""
|
|
453
|
+
|
|
454
|
+
flags: InteractionFlag = InteractionFlag.ALL
|
|
455
|
+
"""
|
|
456
|
+
Defines the map events to be enabled/disabled.
|
|
457
|
+
"""
|
|
458
|
+
|
|
459
|
+
rotation_win_gestures: MultiFingerGesture = MultiFingerGesture.ROTATE
|
|
460
|
+
"""
|
|
461
|
+
When [`rotation_threshold`[..] wins over [`pinch_zoom_threshold`[..] and
|
|
462
|
+
[`pinch_move_threshold`[..] then `rotation_win_gestures` gestures will be used.
|
|
463
|
+
"""
|
|
464
|
+
|
|
465
|
+
pinch_move_win_gestures: MultiFingerGesture = (
|
|
466
|
+
MultiFingerGesture.PINCH_ZOOM | MultiFingerGesture.PINCH_MOVE
|
|
467
|
+
)
|
|
468
|
+
"""
|
|
469
|
+
When [`pinch_move_threshold`][..] wins over [`rotation_threshold`][..]
|
|
470
|
+
and [`pinch_zoom_threshold`][..] then `pinch_move_win_gestures` gestures will be used.
|
|
471
|
+
|
|
472
|
+
By default [`MultiFingerGesture.PINCH_MOVE`][(p).] and [`MultiFingerGesture.PINCH_ZOOM`][(p).]
|
|
473
|
+
gestures will take effect see [`MultiFingerGesture`][(p).] for custom settings.
|
|
474
|
+
"""
|
|
475
|
+
|
|
476
|
+
pinch_zoom_win_gestures: MultiFingerGesture = (
|
|
477
|
+
MultiFingerGesture.PINCH_ZOOM | MultiFingerGesture.PINCH_MOVE
|
|
478
|
+
)
|
|
479
|
+
"""
|
|
480
|
+
When [`pinch_zoom_threshold`][..] wins over [`rotation_threshold`][..] and [`pinch_move_threshold`][..]
|
|
481
|
+
then `pinch_zoom_win_gestures` gestures will be used.
|
|
482
|
+
|
|
483
|
+
By default [`MultiFingerGesture.PINCH_ZOOM`][(p).] and [`MultiFingerGesture.PINCH_MOVE`][(p).]
|
|
484
|
+
gestures will take effect see `MultiFingerGesture` for custom settings.
|
|
485
|
+
"""
|
|
486
|
+
|
|
487
|
+
keyboard_configuration: "KeyboardConfiguration" = field(
|
|
488
|
+
default_factory=lambda: KeyboardConfiguration()
|
|
489
|
+
)
|
|
490
|
+
"""
|
|
491
|
+
Options to configure how keyboard keys may be used to control the map.
|
|
492
|
+
|
|
493
|
+
Keyboard movements using the arrow keys are enabled by default.
|
|
494
|
+
"""
|
|
495
|
+
|
|
496
|
+
cursor_keyboard_rotation_configuration: "CursorKeyboardRotationConfiguration" = (
|
|
497
|
+
field(default_factory=lambda: CursorKeyboardRotationConfiguration())
|
|
498
|
+
)
|
|
499
|
+
"""
|
|
500
|
+
Options to control the keyboard and mouse cursor being used together to rotate the map.
|
|
501
|
+
"""
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
class MapEventSource(Enum):
|
|
505
|
+
"""Defines the source of a [`MapEvent`][(p).]."""
|
|
506
|
+
|
|
507
|
+
MAP_CONTROLLER = "mapController"
|
|
508
|
+
"""The `MapEvent` is caused programmatically by the `MapController`."""
|
|
509
|
+
|
|
510
|
+
TAP = "tap"
|
|
511
|
+
"""The `MapEvent` is caused by a tap gesture."""
|
|
512
|
+
|
|
513
|
+
SECONDARY_TAP = "secondaryTap"
|
|
514
|
+
"""The `MapEvent` is caused by a secondary tap gesture."""
|
|
515
|
+
|
|
516
|
+
LONG_PRESS = "longPress"
|
|
517
|
+
"""The `MapEvent` is caused by a long press gesture."""
|
|
518
|
+
|
|
519
|
+
DOUBLE_TAP = "doubleTap"
|
|
520
|
+
"""The `MapEvent` is caused by a double tap gesture."""
|
|
521
|
+
|
|
522
|
+
DOUBLE_TAP_HOLD = "doubleTapHold"
|
|
523
|
+
"""The `MapEvent` is caused by a double tap and hold gesture."""
|
|
524
|
+
|
|
525
|
+
DRAG_START = "dragStart"
|
|
526
|
+
"""The `MapEvent` is caused by the start of a drag gesture."""
|
|
527
|
+
|
|
528
|
+
ON_DRAG = "onDrag"
|
|
529
|
+
"""The `MapEvent` is caused by a drag update gesture."""
|
|
530
|
+
|
|
531
|
+
DRAG_END = "dragEnd"
|
|
532
|
+
"""The `MapEvent` is caused by the end of a drag gesture."""
|
|
533
|
+
|
|
534
|
+
MULTI_FINGER_GESTURE_START = "multiFingerGestureStart"
|
|
535
|
+
"""The `MapEvent` is caused by the start of a two finger gesture."""
|
|
536
|
+
|
|
537
|
+
ON_MULTI_FINGER = "onMultiFinger"
|
|
538
|
+
"""The `MapEvent` is caused by a two finger gesture update."""
|
|
539
|
+
|
|
540
|
+
MULTI_FINGER_GESTURE_END = "multiFingerEnd"
|
|
541
|
+
"""The `MapEvent` is caused by a the end of a two finger gesture."""
|
|
542
|
+
|
|
543
|
+
FLING_ANIMATION_CONTROLLER = "flingAnimationController"
|
|
544
|
+
"""
|
|
545
|
+
The `MapEvent` is caused by the `AnimationController` while performing the fling gesture.
|
|
546
|
+
"""
|
|
547
|
+
|
|
548
|
+
DOUBLE_TAP_ZOOM_ANIMATION_CONTROLLER = "doubleTapZoomAnimationController"
|
|
549
|
+
"""
|
|
550
|
+
The `MapEvent` is caused by the `AnimationController`
|
|
551
|
+
while performing the double tap zoom in animation.
|
|
552
|
+
"""
|
|
553
|
+
|
|
554
|
+
INTERACTIVE_FLAGS_CHANGED = "InteractionFlagsChanged"
|
|
555
|
+
"""The `MapEvent` is caused by a change of the interactive flags."""
|
|
556
|
+
|
|
557
|
+
FIT_CAMERA = "fitCamera"
|
|
558
|
+
"""The `MapEvent` is caused by calling fit_camera."""
|
|
559
|
+
|
|
560
|
+
CUSTOM = "custom"
|
|
561
|
+
"""The `MapEvent` is caused by a custom source."""
|
|
562
|
+
|
|
563
|
+
SCROLL_WHEEL = "scrollWheel"
|
|
564
|
+
"""The `MapEvent` is caused by a scroll wheel zoom gesture."""
|
|
565
|
+
|
|
566
|
+
NON_ROTATED_SIZE_CHANGE = "nonRotatedSizeChange"
|
|
567
|
+
"""The `MapEvent` is caused by a size change of the `Map` constraints."""
|
|
568
|
+
|
|
569
|
+
CURSOR_KEYBOARD_ROTATION = "cursorKeyboardRotation"
|
|
570
|
+
"""The `MapEvent` is caused by a 'CTRL + drag' rotation gesture."""
|
|
571
|
+
|
|
572
|
+
KEYBOARD = "keyboard"
|
|
573
|
+
"""The `MapEvent` is caused by a keyboard key. See [`KeyboardConfiguration`][(p).] for details."""
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
@dataclass
|
|
577
|
+
class CameraFit:
|
|
578
|
+
"""
|
|
579
|
+
Defines how the camera should fit the bounds or coordinates, depending on which one was provided.
|
|
580
|
+
|
|
581
|
+
Raises:
|
|
582
|
+
AssertionError: If both [`bounds`][(c).] and [`coordinates`][(c).] are `None` or not `None`.
|
|
583
|
+
"""
|
|
584
|
+
|
|
585
|
+
bounds: Optional[MapLatitudeLongitudeBounds] = None
|
|
586
|
+
"""
|
|
587
|
+
The bounds which the camera should contain once it is fitted.
|
|
588
|
+
|
|
589
|
+
Note:
|
|
590
|
+
If this is not `None`, [`coordinates`][..] should be `None`, and vice versa.
|
|
591
|
+
"""
|
|
592
|
+
|
|
593
|
+
coordinates: Optional[List[MapLatitudeLongitude]] = None
|
|
594
|
+
"""
|
|
595
|
+
The coordinates which the camera should contain once it is fitted.
|
|
596
|
+
|
|
597
|
+
Note:
|
|
598
|
+
If this is not `None`, [`bounds`][..] should be `None`, and vice versa.
|
|
599
|
+
"""
|
|
600
|
+
|
|
601
|
+
max_zoom: Optional[ft.Number] = None
|
|
602
|
+
"""
|
|
603
|
+
The inclusive upper zoom limit used for the resulting fit.
|
|
604
|
+
If the zoom level calculated for the fit exceeds the `max_zoom` value, `max_zoom` will be used instead.
|
|
605
|
+
"""
|
|
606
|
+
|
|
607
|
+
min_zoom: ft.Number = 0.0
|
|
608
|
+
"""
|
|
609
|
+
"""
|
|
610
|
+
|
|
611
|
+
padding: ft.PaddingValue = field(default_factory=lambda: ft.Padding.zero())
|
|
612
|
+
"""
|
|
613
|
+
Adds a constant/pixel-based padding to the normal fit.
|
|
614
|
+
"""
|
|
615
|
+
|
|
616
|
+
force_integer_zoom_level: bool = False
|
|
617
|
+
"""
|
|
618
|
+
Whether the zoom level of the resulting fit should be rounded to the nearest integer level.
|
|
619
|
+
"""
|
|
620
|
+
|
|
621
|
+
def __post_init__(self):
|
|
622
|
+
assert (self.bounds and not self.coordinates) or (
|
|
623
|
+
self.coordinates and not self.bounds
|
|
624
|
+
), "only one of bounds or coordinates must be provided, not both"
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
@dataclass
|
|
628
|
+
class MapTapEvent(ft.TapEvent):
|
|
629
|
+
coordinates: MapLatitudeLongitude
|
|
630
|
+
"""Coordinates of the point at which the tap occured."""
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
@dataclass
|
|
634
|
+
class MapHoverEvent(ft.HoverEvent):
|
|
635
|
+
coordinates: MapLatitudeLongitude
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
@dataclass
|
|
639
|
+
class MapPositionChangeEvent(ft.Event[ft.EventControlType]):
|
|
640
|
+
coordinates: MapLatitudeLongitude
|
|
641
|
+
camera: Camera
|
|
642
|
+
has_gesture: bool
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
@dataclass
|
|
646
|
+
class MapPointerEvent(ft.PointerEvent):
|
|
647
|
+
coordinates: MapLatitudeLongitude
|
|
648
|
+
"""Coordinates of the point at which the tap occured."""
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
@dataclass
|
|
652
|
+
class MapEvent(ft.Event[ft.EventControlType]):
|
|
653
|
+
source: MapEventSource
|
|
654
|
+
"""Who/what issued the event."""
|
|
655
|
+
|
|
656
|
+
camera: Camera
|
|
657
|
+
"""The map camera after the event."""
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
@dataclass(kw_only=True)
|
|
661
|
+
class TileDisplay:
|
|
662
|
+
"""
|
|
663
|
+
Defines how the tile should get displayed on the map.
|
|
664
|
+
|
|
665
|
+
This is an abstract class and shouldn't be used directly.
|
|
666
|
+
|
|
667
|
+
See usable derivatives:
|
|
668
|
+
- `InstantaneousTileDisplay`
|
|
669
|
+
- `FadeInTileDisplay`
|
|
670
|
+
"""
|
|
671
|
+
|
|
672
|
+
_type: str = ""
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
@dataclass
|
|
676
|
+
class InstantaneousTileDisplay(TileDisplay):
|
|
677
|
+
"""A `TileDisplay` that should get instantaneously displayed."""
|
|
678
|
+
|
|
679
|
+
opacity: ft.Number = 1.0
|
|
680
|
+
"""
|
|
681
|
+
The optional opacity of the tile.
|
|
682
|
+
"""
|
|
683
|
+
|
|
684
|
+
def __post_init__(self):
|
|
685
|
+
assert (
|
|
686
|
+
0.0 <= self.opacity <= 1.0
|
|
687
|
+
), "start_opacity must be between 0.0 and 1.0 (inclusive)"
|
|
688
|
+
self._type = "instantaneous"
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
@dataclass
|
|
692
|
+
class FadeInTileDisplay(TileDisplay):
|
|
693
|
+
"""A `TileDisplay` that should get faded in."""
|
|
694
|
+
|
|
695
|
+
duration: ft.DurationValue = field(
|
|
696
|
+
default_factory=lambda: ft.Duration(milliseconds=100)
|
|
697
|
+
)
|
|
698
|
+
"""
|
|
699
|
+
The duration of the fade in animation.
|
|
700
|
+
"""
|
|
701
|
+
|
|
702
|
+
start_opacity: ft.Number = 0.0
|
|
703
|
+
"""
|
|
704
|
+
Opacity start value when a tile is faded in.
|
|
705
|
+
"""
|
|
706
|
+
|
|
707
|
+
reload_start_opacity: ft.Number = 0.0
|
|
708
|
+
"""
|
|
709
|
+
Opacity start value when a tile is reloaded.
|
|
710
|
+
"""
|
|
711
|
+
|
|
712
|
+
def __post_init__(self):
|
|
713
|
+
assert (
|
|
714
|
+
0.0 <= self.start_opacity <= 1.0
|
|
715
|
+
), "start_opacity must be between 0.0 and 1.0 (inclusive)"
|
|
716
|
+
assert (
|
|
717
|
+
0.0 <= self.reload_start_opacity <= 1.0
|
|
718
|
+
), "reload_start_opacity must be between 0.0 and 1.0 (inclusive)"
|
|
719
|
+
self._type = "fadein"
|
|
720
|
+
|
|
721
|
+
|
|
722
|
+
@dataclass
|
|
723
|
+
class KeyboardConfiguration:
|
|
724
|
+
"""
|
|
725
|
+
Options to configure how keyboard keys may be used to control the map.
|
|
726
|
+
When a key is pushed down, an animation starts, consisting of a curved
|
|
727
|
+
portion which takes the animation to its maximum velocity, an indefinitely
|
|
728
|
+
long animation at maximum velocity, then ended on the key up with another
|
|
729
|
+
curved portion.
|
|
730
|
+
|
|
731
|
+
If a key is pressed and released quickly, it might trigger a short animation
|
|
732
|
+
called a 'leap'. The leap consists of a part of the curved portion, and also
|
|
733
|
+
scales the velocity of the concerned gesture.
|
|
734
|
+
|
|
735
|
+
Info:
|
|
736
|
+
See [`CursorKeyboardRotationConfiguration`][(p).] for options to control the keyboard and
|
|
737
|
+
mouse cursor being used together to rotate the map.
|
|
738
|
+
"""
|
|
739
|
+
|
|
740
|
+
autofocus: bool = True
|
|
741
|
+
"""
|
|
742
|
+
Whether to request focus as soon as the map control appears (and to enable keyboard controls).
|
|
743
|
+
"""
|
|
744
|
+
|
|
745
|
+
animation_curve_duration: ft.DurationValue = field(
|
|
746
|
+
default_factory=lambda: ft.Duration(milliseconds=450)
|
|
747
|
+
)
|
|
748
|
+
"""
|
|
749
|
+
Duration of the curved (`ft.Curve.EASE_IN`) portion of the animation occuring
|
|
750
|
+
after a key down event (and after a key up event if [`animation_curve_reverse_duration`][..] is `None`)
|
|
751
|
+
"""
|
|
752
|
+
|
|
753
|
+
animation_curve_reverse_duration: Optional[ft.DurationValue] = field(
|
|
754
|
+
default_factory=lambda: ft.Duration(milliseconds=600)
|
|
755
|
+
)
|
|
756
|
+
"""
|
|
757
|
+
Duration of the curved (reverse `ft.Curve.EASE_IN`) portion of the animation
|
|
758
|
+
occuring after a key up event.
|
|
759
|
+
|
|
760
|
+
Set to `None` to use [`animation_curve_duration`][..].
|
|
761
|
+
"""
|
|
762
|
+
|
|
763
|
+
animation_curve_curve: bool = True
|
|
764
|
+
"""
|
|
765
|
+
Curve of the curved portion of the animation occuring after key down and key up events.
|
|
766
|
+
"""
|
|
767
|
+
|
|
768
|
+
enable_arrow_keys_panning: bool = True
|
|
769
|
+
"""
|
|
770
|
+
Whether to allow arrow keys to pan the map (in their respective directions).
|
|
771
|
+
"""
|
|
772
|
+
|
|
773
|
+
enable_qe_rotating: bool = True
|
|
774
|
+
"""
|
|
775
|
+
Whether to allow the Q & E keys (*) to rotate the map (Q rotates anticlockwise, E rotates clockwise).
|
|
776
|
+
|
|
777
|
+
QE are only the physical and logical keys on QWERTY keyboards.
|
|
778
|
+
On non- QWERTY keyboards, such as AZERTY,
|
|
779
|
+
the keys in the same position as on the QWERTY keyboard is used (ie. AE on AZERTY).
|
|
780
|
+
"""
|
|
781
|
+
|
|
782
|
+
enable_rf_zooming: bool = True
|
|
783
|
+
"""
|
|
784
|
+
Whether to allow the R & F keys to zoom the map (R zooms IN (increases zoom level), F zooms OUT (decreases zoom level)).
|
|
785
|
+
|
|
786
|
+
RF are only the physical and logical keys on QWERTY keyboards.
|
|
787
|
+
On non- QWERTY keyboards, such as AZERTY,
|
|
788
|
+
the keys in the same position as on the QWERTY keyboard is used (ie. RF on AZERTY).
|
|
789
|
+
"""
|
|
790
|
+
|
|
791
|
+
enable_wasd_panning: bool = True
|
|
792
|
+
"""
|
|
793
|
+
Whether to allow the W, A, S, D keys (*) to pan the map (in the directions UP, LEFT, DOWN, RIGHT respectively).
|
|
794
|
+
|
|
795
|
+
WASD are only the physical and logical keys on QWERTY keyboards.
|
|
796
|
+
On non- QWERTY keyboards, such as AZERTY,
|
|
797
|
+
the keys in the same position as on the QWERTY keyboard is used (ie. ZQSD on AZERTY).
|
|
798
|
+
|
|
799
|
+
If enabled, it is recommended to enable `enable_arrow_keys_panning` to provide panning functionality easily for left handed users.
|
|
800
|
+
"""
|
|
801
|
+
|
|
802
|
+
leap_max_of_curve_component: ft.Number = 0.6
|
|
803
|
+
"""
|
|
804
|
+
The percentage (0.0 - 1.0) of the curve animation component that is driven
|
|
805
|
+
to (from 0), then in reverse from (to 0).
|
|
806
|
+
|
|
807
|
+
Reducing means the leap occurs quicker (assuming a consistent curve
|
|
808
|
+
animation duration). Also see `*_leap_velocity_multiplier` properties to
|
|
809
|
+
change the distance of the leap assuming a consistent leap duration.
|
|
810
|
+
|
|
811
|
+
For example, if set to 1, then the leap will take `animation_curve_duration + animation_curve_reverse_duration`
|
|
812
|
+
to complete.
|
|
813
|
+
|
|
814
|
+
Must be greater than 0 and less than or equal to 1.
|
|
815
|
+
To disable leaping, or change the maximum length of the key press
|
|
816
|
+
that will trigger a leap, see [`perform_leap_trigger_duration`[..].
|
|
817
|
+
"""
|
|
818
|
+
|
|
819
|
+
max_rotate_velocity: ft.Number = 3
|
|
820
|
+
"""
|
|
821
|
+
The maximum angular difference to apply per frame to the camera's rotation
|
|
822
|
+
during a rotation animation.
|
|
823
|
+
|
|
824
|
+
Measured in degrees. Negative numbers will flip the standard rotation keys.
|
|
825
|
+
"""
|
|
826
|
+
|
|
827
|
+
max_zoom_velocity: ft.Number = 0.03
|
|
828
|
+
"""
|
|
829
|
+
The maximum zoom level difference to apply per frame to the camera's zoom
|
|
830
|
+
level during a zoom animation.
|
|
831
|
+
|
|
832
|
+
Measured in zoom levels. Negative numbers will flip the standard zoom keys.
|
|
833
|
+
"""
|
|
834
|
+
|
|
835
|
+
pan_leap_velocity_multiplier: ft.Number = 5
|
|
836
|
+
"""
|
|
837
|
+
The amount to scale the panning offset velocity by during a leap animation.
|
|
838
|
+
|
|
839
|
+
The larger the number, the larger the movement during a leap.
|
|
840
|
+
To change the duration of a leap, see [`leap_max_of_curve_component`[..].
|
|
841
|
+
|
|
842
|
+
This may cause the pan velocity to exceed [`max_pan_velocity`[..].
|
|
843
|
+
"""
|
|
844
|
+
|
|
845
|
+
rotate_leap_velocity_multiplier: ft.Number = 3
|
|
846
|
+
"""
|
|
847
|
+
The amount to scale the rotation velocity by during a leap animation
|
|
848
|
+
|
|
849
|
+
The larger the number, the larger the rotation difference during a leap.
|
|
850
|
+
To change the duration of a leap, see [`leap_max_of_curve_component`[..].
|
|
851
|
+
|
|
852
|
+
This may cause the pan velocity to exceed [`max_rotate_velocity`[..].
|
|
853
|
+
"""
|
|
854
|
+
|
|
855
|
+
zoom_leap_velocity_multiplier: ft.Number = 3
|
|
856
|
+
"""
|
|
857
|
+
The amount to scale the zooming velocity by during a leap animation.
|
|
858
|
+
|
|
859
|
+
The larger the number, the larger the zoom difference during a leap. To
|
|
860
|
+
change the duration of a leap, see [`leap_max_of_curve_component`[..].
|
|
861
|
+
|
|
862
|
+
This may cause the pan velocity to exceed [`max_zoom_velocity`[..].
|
|
863
|
+
"""
|
|
864
|
+
|
|
865
|
+
perform_leap_trigger_duration: Optional[ft.DurationValue] = field(
|
|
866
|
+
default_factory=lambda: ft.Duration(milliseconds=100)
|
|
867
|
+
)
|
|
868
|
+
"""
|
|
869
|
+
Maximum duration between the key down and key up events of an animation
|
|
870
|
+
which will trigger a 'leap'.
|
|
871
|
+
|
|
872
|
+
To customize the leap itself, see the [`leap_max_of_curve_component`[..] &
|
|
873
|
+
`[*leap_velocity_multiplier`[..] properties.
|
|
874
|
+
|
|
875
|
+
Set to `None` to disable leaping.
|
|
876
|
+
"""
|
|
877
|
+
|
|
878
|
+
@classmethod
|
|
879
|
+
def disabled(cls) -> "KeyboardConfiguration":
|
|
880
|
+
"""
|
|
881
|
+
Disable keyboard control of the map.
|
|
882
|
+
|
|
883
|
+
Info:
|
|
884
|
+
`CursorKeyboardRotationConfiguration` may still be active, and is not disabled if this is disabled.
|
|
885
|
+
"""
|
|
886
|
+
return KeyboardConfiguration(
|
|
887
|
+
enable_arrow_keys_panning=False,
|
|
888
|
+
perform_leap_trigger_duration=None,
|
|
889
|
+
autofocus=False,
|
|
890
|
+
)
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
class CursorRotationBehaviour(Enum):
|
|
894
|
+
"""
|
|
895
|
+
The behaviour of the cursor/keyboard rotation function in terms of the angle
|
|
896
|
+
that the map is rotated to.
|
|
897
|
+
|
|
898
|
+
Does not disable cursor/keyboard rotation, or adjust its triggers: see
|
|
899
|
+
`CursorKeyboardRotationConfiguration.is_key_trriger`.
|
|
900
|
+
"""
|
|
901
|
+
|
|
902
|
+
OFFSET = "offset"
|
|
903
|
+
"""
|
|
904
|
+
Offset the current rotation of the map to the angle at which the user drags their cursor.
|
|
905
|
+
"""
|
|
906
|
+
|
|
907
|
+
SET_NORTH = "setNorth"
|
|
908
|
+
"""
|
|
909
|
+
Set the North of the map to the angle at which the user drags their cursor.
|
|
910
|
+
"""
|
|
911
|
+
|
|
912
|
+
|
|
913
|
+
@dataclass
|
|
914
|
+
class CursorKeyboardRotationConfiguration:
|
|
915
|
+
"""
|
|
916
|
+
Options to configure cursor/keyboard rotation.
|
|
917
|
+
|
|
918
|
+
Cursor/keyboard rotation is designed for desktop platforms,
|
|
919
|
+
and allows the cursor to be used to set the rotation of the map
|
|
920
|
+
whilst a keyboard key is held down (as triggered by `is_key_trriger`).
|
|
921
|
+
"""
|
|
922
|
+
|
|
923
|
+
set_north_on_click: bool = True
|
|
924
|
+
"""
|
|
925
|
+
Whether to set the North of the map to the clicked angle,
|
|
926
|
+
when the user clicks their mouse without dragging
|
|
927
|
+
(a `on_pointer_down` event followed by `on_pointer_up` without a change in rotation).
|
|
928
|
+
"""
|
|
929
|
+
|
|
930
|
+
behavior: CursorRotationBehaviour = CursorRotationBehaviour.OFFSET
|
|
931
|
+
"""
|
|
932
|
+
The behaviour of the cursor/keyboard rotation function in terms of the
|
|
933
|
+
angle that the map is rotated to.
|
|
934
|
+
|
|
935
|
+
Does not disable cursor/keyboard rotation, or adjust its triggers: see `is_key_trriger`.
|
|
936
|
+
"""
|
|
937
|
+
|
|
938
|
+
# TODO
|
|
939
|
+
trigger_keys: list = field(
|
|
940
|
+
default_factory=lambda: [
|
|
941
|
+
# ft.LogicalKeyboardKey.CONTROL,
|
|
942
|
+
# ft.LogicalKeyboardKey.CONTROL_LEFT,
|
|
943
|
+
# ft.LogicalKeyboardKey.CONTROL_RIGHT,
|
|
944
|
+
]
|
|
945
|
+
)
|
|
946
|
+
"""
|
|
947
|
+
List of keys that will trigger cursor/keyboard rotation, when pressed.
|
|
948
|
+
"""
|
|
949
|
+
|
|
950
|
+
@classmethod
|
|
951
|
+
def disabled(cls) -> "CursorKeyboardRotationConfiguration":
|
|
952
|
+
"""A disabled `CursorKeyboardRotationConfiguration`."""
|
|
953
|
+
return CursorKeyboardRotationConfiguration(trigger_keys=[])
|