|
88 | 88 | import warnings |
89 | 89 | from collections.abc import Callable, Iterator, Mapping |
90 | 90 | from math import floor |
| 91 | +from pathlib import Path |
91 | 92 | from typing import TYPE_CHECKING, Any, Final, Generic, Literal, NamedTuple, TypeAlias, TypedDict, TypeVar, overload |
92 | 93 |
|
93 | 94 | import attrs |
@@ -1062,6 +1063,68 @@ def _from_sdl_event(cls, sdl_event: _C_SDL_Event) -> Self: |
1062 | 1063 | ) |
1063 | 1064 |
|
1064 | 1065 |
|
| 1066 | +@attrs.define(slots=True, kw_only=True) |
| 1067 | +class Drop(Event): |
| 1068 | + """Handle dropping text or files on the window. |
| 1069 | +
|
| 1070 | + Example:: |
| 1071 | +
|
| 1072 | + match event: |
| 1073 | + case tcod.event.Drop(type="BEGIN"): |
| 1074 | + print("Object dragged over the window") |
| 1075 | + case tcod.event.Drop(type="POSITION", position=position): |
| 1076 | + pass |
| 1077 | + case tcod.event.Drop(type="TEXT", position=position, text=text): |
| 1078 | + print(f"Dropped {text=} at {position=}") |
| 1079 | + case tcod.event.Drop(type="FILE", position=position, path=path): |
| 1080 | + print(f"Dropped {path=} at {position=}") |
| 1081 | + case tcod.event.Drop(type="COMPLETE"): |
| 1082 | + print("Drop handling finished") |
| 1083 | +
|
| 1084 | + .. versionadded:: Unreleased |
| 1085 | + """ |
| 1086 | + |
| 1087 | + type: Literal["BEGIN", "FILE", "TEXT", "COMPLETE", "POSITION"] |
| 1088 | + """The subtype of this event.""" |
| 1089 | + window_id: int |
| 1090 | + """The active window ID for this event.""" |
| 1091 | + position: Point[float] |
| 1092 | + """Mouse position relative to the window. Available in all subtypes except for ``type="BEGIN"``.""" |
| 1093 | + source: str |
| 1094 | + """The source app for this event, or an empty string if unavailable.""" |
| 1095 | + text: str |
| 1096 | + """The dropped data of a ``Drop(type="TEXT")`` or ``Drop(type="FILE")`` event. |
| 1097 | +
|
| 1098 | + - If ``Drop(type="TEXT")`` then `text` is the dropped string. |
| 1099 | + - If ``Drop(type="FILE")`` then `text` is the str path of the dropped file. |
| 1100 | + Alternatively :any:`path` can be used. |
| 1101 | + - Otherwise `text` is an empty string. |
| 1102 | + """ |
| 1103 | + |
| 1104 | + @property |
| 1105 | + def path(self) -> Path: |
| 1106 | + """Return the current `text` as a :any:`Path`.""" |
| 1107 | + return Path(self.text) |
| 1108 | + |
| 1109 | + @classmethod |
| 1110 | + def _from_sdl_event(cls, sdl_event: _C_SDL_Event) -> Self: |
| 1111 | + types: dict[int, Literal["BEGIN", "FILE", "TEXT", "COMPLETE", "POSITION"]] = { |
| 1112 | + lib.SDL_EVENT_DROP_BEGIN: "BEGIN", |
| 1113 | + lib.SDL_EVENT_DROP_FILE: "FILE", |
| 1114 | + lib.SDL_EVENT_DROP_TEXT: "TEXT", |
| 1115 | + lib.SDL_EVENT_DROP_COMPLETE: "COMPLETE", |
| 1116 | + lib.SDL_EVENT_DROP_POSITION: "POSITION", |
| 1117 | + } |
| 1118 | + return cls( |
| 1119 | + type=types[sdl_event.drop.type], |
| 1120 | + window_id=int(sdl_event.drop.windowID), |
| 1121 | + position=Point(float(sdl_event.drop.x), float(sdl_event.drop.y)), |
| 1122 | + source=str(ffi.string(sdl_event.drop.source), encoding="utf8") if sdl_event.drop.source else "", |
| 1123 | + text=str(ffi.string(sdl_event.drop.data), encoding="utf8") if sdl_event.drop.data else "", |
| 1124 | + **_unpack_sdl_event(sdl_event), |
| 1125 | + ) |
| 1126 | + |
| 1127 | + |
1065 | 1128 | @functools.cache |
1066 | 1129 | def _find_event_name(index: int, /) -> str: |
1067 | 1130 | """Return the SDL event name for this index.""" |
@@ -1107,6 +1170,11 @@ def __repr__(self) -> str: |
1107 | 1170 | lib.SDL_EVENT_GAMEPAD_REMOVED: ControllerDevice, |
1108 | 1171 | lib.SDL_EVENT_GAMEPAD_REMAPPED: ControllerDevice, |
1109 | 1172 | lib.SDL_EVENT_CLIPBOARD_UPDATE: ClipboardUpdate, |
| 1173 | + lib.SDL_EVENT_DROP_BEGIN: Drop, |
| 1174 | + lib.SDL_EVENT_DROP_FILE: Drop, |
| 1175 | + lib.SDL_EVENT_DROP_TEXT: Drop, |
| 1176 | + lib.SDL_EVENT_DROP_COMPLETE: Drop, |
| 1177 | + lib.SDL_EVENT_DROP_POSITION: Drop, |
1110 | 1178 | } |
1111 | 1179 |
|
1112 | 1180 |
|
|
0 commit comments