55"""
66from __future__ import annotations
77
8+ import enum
89import sys
910from typing import Any , Optional , Tuple
1011
1112import numpy as np
1213from numpy .typing import ArrayLike , NDArray
1314
1415from tcod .loader import ffi , lib
15- from tcod .sdl import _check_p
16+ from tcod .sdl import _check , _check_p , _required_version
1617
17- __all__ = ("Window" ,)
18+ __all__ = (
19+ "WindowFlags" ,
20+ "FlashOperation" ,
21+ "Window" ,
22+ "new_window" ,
23+ "get_grabbed_window" ,
24+ )
25+
26+
27+ class WindowFlags (enum .IntFlag ):
28+ """Bit flags which make up a windows state.
29+
30+ .. seealso::
31+ https://wiki.libsdl.org/SDL_WindowFlags
32+ """
33+
34+ FULLSCREEN = lib .SDL_WINDOW_FULLSCREEN or 0
35+ FULLSCREEN_DESKTOP = lib .SDL_WINDOW_FULLSCREEN_DESKTOP or 0
36+ OPENGL = lib .SDL_WINDOW_OPENGL or 0
37+ SHOWN = lib .SDL_WINDOW_SHOWN or 0
38+ HIDDEN = lib .SDL_WINDOW_HIDDEN or 0
39+ BORDERLESS = lib .SDL_WINDOW_BORDERLESS or 0
40+ RESIZABLE = lib .SDL_WINDOW_RESIZABLE or 0
41+ MINIMIZED = lib .SDL_WINDOW_MINIMIZED or 0
42+ MAXIMIZED = lib .SDL_WINDOW_MAXIMIZED or 0
43+ MOUSE_GRABBED = lib .SDL_WINDOW_INPUT_GRABBED or 0
44+ INPUT_FOCUS = lib .SDL_WINDOW_INPUT_FOCUS or 0
45+ MOUSE_FOCUS = lib .SDL_WINDOW_MOUSE_FOCUS or 0
46+ FOREIGN = lib .SDL_WINDOW_FOREIGN or 0
47+ ALLOW_HIGHDPI = lib .SDL_WINDOW_ALLOW_HIGHDPI or 0
48+ MOUSE_CAPTURE = lib .SDL_WINDOW_MOUSE_CAPTURE or 0
49+ ALWAYS_ON_TOP = lib .SDL_WINDOW_ALWAYS_ON_TOP or 0
50+ SKIP_TASKBAR = lib .SDL_WINDOW_SKIP_TASKBAR or 0
51+ UTILITY = lib .SDL_WINDOW_UTILITY or 0
52+ TOOLTIP = lib .SDL_WINDOW_TOOLTIP or 0
53+ POPUP_MENU = lib .SDL_WINDOW_POPUP_MENU or 0
54+ VULKAN = lib .SDL_WINDOW_VULKAN or 0
55+ METAL = getattr (lib , "SDL_WINDOW_METAL" , None ) or 0x20000000 # SDL >= 2.0.14
56+
57+
58+ class FlashOperation (enum .IntEnum ):
59+ CANCEL = 0
60+ BRIEFLY = 1
61+ UNTIL_FOCUSED = 2
1862
1963
2064class _TempSurface :
@@ -67,10 +111,7 @@ def set_icon(self, image: ArrayLike) -> None:
67111
68112 @property
69113 def allow_screen_saver (self ) -> bool :
70- """If True the operating system is allowed to display a screen saver.
71-
72- You can set this attribute to enable or disable the screen saver.
73- """
114+ """Get or set if the operating system is allowed to display a screen saver."""
74115 return bool (lib .SDL_IsScreenSaverEnabled (self .p ))
75116
76117 @allow_screen_saver .setter
@@ -82,11 +123,10 @@ def allow_screen_saver(self, value: bool) -> None:
82123
83124 @property
84125 def position (self ) -> Tuple [int , int ]:
85- """Return the (x, y) position of the window.
126+ """Get or set the (x, y) position of the window.
86127
87128 This attribute can be set the move the window.
88- The constants tcod.lib.SDL_WINDOWPOS_CENTERED or
89- tcod.lib.SDL_WINDOWPOS_UNDEFINED can be used.
129+ The constants tcod.lib.SDL_WINDOWPOS_CENTERED or tcod.lib.SDL_WINDOWPOS_UNDEFINED may be used.
90130 """
91131 xy = ffi .new ("int[2]" )
92132 lib .SDL_GetWindowPosition (self .p , xy , xy + 1 )
@@ -99,11 +139,10 @@ def position(self, xy: Tuple[int, int]) -> None:
99139
100140 @property
101141 def size (self ) -> Tuple [int , int ]:
102- """Return the pixel (width, height) of the window.
142+ """Get or set the pixel (width, height) of the window client area .
103143
104- This attribute can be set to change the size of the window but the
105- given size must be greater than (1, 1) or else an exception will be
106- raised.
144+ This attribute can be set to change the size of the window but the given size must be greater than (1, 1) or
145+ else ValueError will be raised.
107146 """
108147 xy = ffi .new ("int[2]" )
109148 lib .SDL_GetWindowSize (self .p , xy , xy + 1 )
@@ -112,19 +151,146 @@ def size(self) -> Tuple[int, int]:
112151 @size .setter
113152 def size (self , xy : Tuple [int , int ]) -> None :
114153 if any (i <= 0 for i in xy ):
115- raise ValueError ("Window size must be greater than zero, not %r" % ( xy ,) )
154+ raise ValueError (f "Window size must be greater than zero, not { xy } " )
116155 x , y = xy
117156 lib .SDL_SetWindowSize (self .p , x , y )
118157
158+ @property
159+ def min_size (self ) -> Tuple [int , int ]:
160+ """Get or set this windows minimum client area."""
161+ xy = ffi .new ("int[2]" )
162+ lib .SDL_GetWindowMinimumSize (self .p , xy , xy + 1 )
163+ return xy [0 ], xy [1 ]
164+
165+ @min_size .setter
166+ def min_size (self , xy : Tuple [int , int ]) -> None :
167+ lib .SDL_SetWindowMinimumSize (self .p , xy [0 ], xy [1 ])
168+
169+ @property
170+ def max_size (self ) -> Tuple [int , int ]:
171+ """Get or set this windows maximum client area."""
172+ xy = ffi .new ("int[2]" )
173+ lib .SDL_GetWindowMaximumSize (self .p , xy , xy + 1 )
174+ return xy [0 ], xy [1 ]
175+
176+ @max_size .setter
177+ def max_size (self , xy : Tuple [int , int ]) -> None :
178+ lib .SDL_SetWindowMaximumSize (self .p , xy [0 ], xy [1 ])
179+
119180 @property
120181 def title (self ) -> str :
121- """The title of the window. You may set this attribute to change it ."""
182+ """Get or set the title of the window ."""
122183 return str (ffi .string (lib .SDL_GetWindowtitle (self .p )), encoding = "utf-8" )
123184
124185 @title .setter
125186 def title (self , value : str ) -> None :
126187 lib .SDL_SetWindowtitle (self .p , value .encode ("utf-8" ))
127188
189+ @property
190+ def flags (self ) -> WindowFlags :
191+ """The current flags of this window, read-only."""
192+ return WindowFlags (lib .SDL_GetWindowFlags (self .p ))
193+
194+ @property
195+ def fullscreen (self ) -> int :
196+ """Get or set the fullscreen status of this window.
197+
198+ Can be set to :any:`WindowFlags.FULLSCREEN` or :any:`WindowFlags.FULLSCREEN_DESKTOP` flags
199+
200+ Example::
201+
202+ # Toggle fullscreen.
203+ window: tcod.sdl.video.Window
204+ if window.fullscreen:
205+ window.fullscreen = False # Set windowed mode.
206+ else:
207+ window.fullscreen = tcod.sdl.video.WindowFlags.FULLSCREEN_DESKTOP
208+ """
209+ return self .flags & (WindowFlags .FULLSCREEN | WindowFlags .FULLSCREEN_DESKTOP )
210+
211+ @fullscreen .setter
212+ def fullscreen (self , value : int ) -> None :
213+ _check (lib .SDL_SetWindowFullscreen (self .p , value ))
214+
215+ @property
216+ def resizable (self ) -> bool :
217+ """Get or set if this window can be resized."""
218+ return bool (self .flags & WindowFlags .RESIZABLE )
219+
220+ @resizable .setter
221+ def resizable (self , value : bool ) -> None :
222+ lib .SDL_SetWindowResizable (self .p , value )
223+
224+ @property
225+ def border_size (self ) -> Tuple [int , int , int , int ]:
226+ """Get the (top, left, bottom, right) size of the window decorations around the client area.
227+
228+ If this fails or the window doesn't have decorations yet then the value will be (0, 0, 0, 0).
229+
230+ .. seealso::
231+ https://wiki.libsdl.org/SDL_GetWindowBordersSize
232+ """
233+ borders = ffi .new ("int[4]" )
234+ # The return code is ignored.
235+ _ = lib .SDL_GetWindowBordersSize (self .p , borders , borders + 1 , borders + 2 , borders + 3 )
236+ return borders [0 ], borders [1 ], borders [2 ], borders [3 ]
237+
238+ @property
239+ def opacity (self ) -> float :
240+ """Get or set this windows opacity. 0.0 is fully transarpent and 1.0 is fully opaque.
241+
242+ Will error if you try to set this and opacity isn't supported.
243+ """
244+ out = ffi .new ("float*" )
245+ _check (lib .SDL_GetWindowOpacity (self .p , out ))
246+ return float (out [0 ])
247+
248+ @opacity .setter
249+ def opacity (self , value : float ) -> None :
250+ _check (lib .SDL_SetWindowOpacity (self .p , value ))
251+
252+ @property
253+ def grab (self ) -> bool :
254+ """Get or set this windows input grab mode.
255+
256+ .. seealso::
257+ https://wiki.libsdl.org/SDL_SetWindowGrab
258+ """
259+ return bool (lib .SDL_GetWindowGrab (self .p ))
260+
261+ @grab .setter
262+ def grab (self , value : bool ) -> None :
263+ lib .SDL_SetWindowGrab (self .p , value )
264+
265+ @_required_version ((2 , 0 , 16 ))
266+ def flash (self , operation : FlashOperation = FlashOperation .UNTIL_FOCUSED ) -> None :
267+ """Get the users attention."""
268+ _check (lib .SDL_FlashWindow (self .p , operation ))
269+
270+ def raise_window (self ) -> None :
271+ """Raise the window and set input focus."""
272+ lib .SDL_RaiseWindow (self .p )
273+
274+ def restore (self ) -> None :
275+ """Restore a minimized or maximized window to its original size and position."""
276+ lib .SDL_RestoreWindow (self .p )
277+
278+ def maximize (self ) -> None :
279+ """Make the window as big as possible."""
280+ lib .SDL_MaximizeWindow (self .p )
281+
282+ def minimize (self ) -> None :
283+ """Minimize the window to an iconic state."""
284+ lib .SDL_MinimizeWindow (self .p )
285+
286+ def show (self ) -> None :
287+ """Show this window."""
288+ lib .SDL_ShowWindow (self .p )
289+
290+ def hide (self ) -> None :
291+ """Hide this window."""
292+ lib .SDL_HideWindow (self .p )
293+
128294
129295def new_window (
130296 width : int ,
@@ -153,6 +319,12 @@ def new_window(
153319 return Window (_check_p (window_p ))
154320
155321
322+ def get_grabbed_window () -> Optional [Window ]:
323+ """Return the window which has input grab enabled, if any."""
324+ sdl_window_p = lib .SDL_GetGrabbedWindow ()
325+ return Window (sdl_window_p ) if sdl_window_p else None
326+
327+
156328def _get_active_window () -> Window :
157329 """Return the SDL2 window current managed by libtcod.
158330
0 commit comments