Source code for moderngl_window.context.sdl2.window

from typing import Tuple
from ctypes import c_int, c_char_p
import sdl2
import sdl2.ext
import sdl2.video

from moderngl_window.context.base import BaseWindow
from moderngl_window.context.sdl2.keys import Keys


class Window(BaseWindow):
    """
    Basic window implementation using SDL2.
    """

    #: Name of the window
    name = "sdl2"
    #: SDL2 specific key constants
    keys = Keys

    _mouse_button_map = {
        1: 1,
        3: 2,
        2: 3,
    }

[docs] def __init__(self, **kwargs): super().__init__(**kwargs) if sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO) != 0: raise ValueError("Failed to initialize sdl2") sdl2.video.SDL_GL_SetAttribute( sdl2.SDL_GL_CONTEXT_MAJOR_VERSION, self.gl_version[0] ) sdl2.video.SDL_GL_SetAttribute( sdl2.SDL_GL_CONTEXT_MINOR_VERSION, self.gl_version[1] ) sdl2.video.SDL_GL_SetAttribute( sdl2.SDL_GL_CONTEXT_PROFILE_MASK, sdl2.SDL_GL_CONTEXT_PROFILE_CORE ) sdl2.video.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG, 1) sdl2.video.SDL_GL_SetAttribute(sdl2.SDL_GL_DOUBLEBUFFER, 1) sdl2.video.SDL_GL_SetAttribute(sdl2.SDL_GL_DEPTH_SIZE, 24) sdl2.video.SDL_GL_SetAttribute(sdl2.SDL_GL_STENCIL_SIZE, 8) self.cursor = self._cursor if self.samples > 1: sdl2.video.SDL_GL_SetAttribute(sdl2.SDL_GL_MULTISAMPLEBUFFERS, 1) sdl2.video.SDL_GL_SetAttribute(sdl2.SDL_GL_MULTISAMPLESAMPLES, self.samples) flags = sdl2.SDL_WINDOW_OPENGL | sdl2.SDL_WINDOW_ALLOW_HIGHDPI if self.fullscreen: flags |= sdl2.SDL_WINDOW_FULLSCREEN_DESKTOP else: if self.resizable: flags |= sdl2.SDL_WINDOW_RESIZABLE self._window = sdl2.SDL_CreateWindow( self.title.encode(), sdl2.SDL_WINDOWPOS_UNDEFINED, sdl2.SDL_WINDOWPOS_UNDEFINED, self.width, self.height, flags, ) if not self._window: raise ValueError("Failed to create window:", sdl2.SDL_GetError()) self._context = sdl2.SDL_GL_CreateContext(self._window) sdl2.video.SDL_GL_SetSwapInterval(1 if self.vsync else 0) self._buffer_width, self._buffer_height = self._get_drawable_size() self.init_mgl_context() self.set_default_viewport()
def _set_fullscreen(self, value: bool) -> None: sdl2.SDL_SetWindowFullscreen( self._window, sdl2.SDL_WINDOW_FULLSCREEN_DESKTOP if value else 0 ) def _set_vsync(self, value: bool) -> None: sdl2.video.SDL_GL_SetSwapInterval(1 if value else 0) def _get_drawable_size(self): x = c_int() y = c_int() sdl2.video.SDL_GL_GetDrawableSize(self._window, x, y) return x.value, y.value @property def size(self) -> Tuple[int, int]: """Tuple[int, int]: current window size. This property also support assignment:: # Resize the window to 1000 x 1000 window.size = 1000, 1000 """ return self._width, self._height @size.setter def size(self, value: Tuple[int, int]): sdl2.SDL_SetWindowSize(self._window, value[0], value[1]) # SDL_SetWindowSize don't trigger a resize event self.resize(value[0], value[1]) @property def position(self) -> Tuple[int, int]: """Tuple[int, int]: The current window position. This property can also be set to move the window:: # Move window to 100, 100 window.position = 100, 100 """ x = c_int(0) y = c_int(0) sdl2.SDL_GetWindowPosition(self._window, x, y) return x.value, y.value @position.setter def position(self, value: Tuple[int, int]): sdl2.SDL_SetWindowPosition(self._window, value[0], value[1]) @property def cursor(self) -> bool: """bool: Should the mouse cursor be visible inside the window? This property can also be assigned to:: # Disable cursor window.cursor = False """ return self._cursor @cursor.setter def cursor(self, value: bool): sdl2.SDL_ShowCursor(sdl2.SDL_ENABLE if value else sdl2.SDL_DISABLE) self._cursor = value @property def mouse_exclusivity(self) -> bool: """bool: If mouse exclusivity is enabled. When you enable mouse-exclusive mode, the mouse cursor is no longer available. It is not merely hidden – no amount of mouse movement will make it leave your application. This is for example useful when you don't want the mouse leaving the screen when rotating a 3d scene. This property can also be set:: window.mouse_exclusivity = True """ return self._mouse_exclusivity @mouse_exclusivity.setter def mouse_exclusivity(self, value: bool): if value is True: sdl2.SDL_SetRelativeMouseMode(sdl2.SDL_TRUE) else: sdl2.SDL_SetRelativeMouseMode(sdl2.SDL_FALSE) self._mouse_exclusivity = value @property def title(self) -> str: """str: Window title. This property can also be set:: window.title = "New Title" """ return self._title @title.setter def title(self, value: str): data = c_char_p(value.encode()) sdl2.SDL_SetWindowTitle(self._window, data) self._title = value
[docs] def swap_buffers(self) -> None: """Swap buffers, set viewport, trigger events and increment frame counter""" sdl2.SDL_GL_SwapWindow(self._window) self.set_default_viewport() self.process_events() self._frames += 1
[docs] def resize(self, width, height) -> None: """Resize callback. Args: width: New window width height: New window height """ self._width = width self._height = height self._buffer_width, self._buffer_height = self._get_drawable_size() self.set_default_viewport() super().resize(self._buffer_width, self._buffer_height)
def _handle_mods(self) -> None: """Update key mods""" mods = sdl2.SDL_GetModState() self._modifiers.shift = mods & sdl2.KMOD_SHIFT self._modifiers.ctrl = mods & sdl2.KMOD_CTRL self._modifiers.alt = mods & sdl2.KMOD_ALT def _set_icon(self, icon_path: str) -> None: sdl2.SDL_SetWindowIcon(self._window, sdl2.ext.load_image(icon_path))
[docs] def process_events(self) -> None: """Handle all queued events in sdl2 dispatching events to standard methods""" for event in sdl2.ext.get_events(): if event.type == sdl2.SDL_MOUSEMOTION: if self.mouse_states.any: self._mouse_drag_event_func( event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel, ) else: self._mouse_position_event_func( event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel, ) elif event.type == sdl2.SDL_MOUSEBUTTONDOWN: self._handle_mods() button = self._mouse_button_map.get(event.button.button, None) if button is not None: self._handle_mouse_button_state_change(button, True) self._mouse_press_event_func( event.motion.x, event.motion.y, button, ) elif event.type == sdl2.SDL_MOUSEBUTTONUP: self._handle_mods() button = self._mouse_button_map.get(event.button.button, None) if button is not None: self._handle_mouse_button_state_change(button, False) self._mouse_release_event_func( event.motion.x, event.motion.y, button, ) elif event.type in [sdl2.SDL_KEYDOWN, sdl2.SDL_KEYUP]: self._handle_mods() if ( self._exit_key is not None and event.key.keysym.sym == self._exit_key ): self.close() if self._fs_key is not None and event.key.keysym.sym == self._fs_key and event.type == sdl2.SDL_KEYDOWN: self.fullscreen = not self.fullscreen if event.type == sdl2.SDL_KEYDOWN: self._key_pressed_map[event.key.keysym.sym] = True elif event.type == sdl2.SDL_KEYUP: self._key_pressed_map[event.key.keysym.sym] = False self._key_event_func(event.key.keysym.sym, event.type, self._modifiers) elif event.type == sdl2.SDL_TEXTINPUT: self._unicode_char_entered_func(event.text.text.decode()) elif event.type == sdl2.SDL_MOUSEWHEEL: self._handle_mods() self._mouse_scroll_event_func( float(event.wheel.x), float(event.wheel.y) ) elif event.type == sdl2.SDL_QUIT: self.close() elif event.type == sdl2.SDL_WINDOWEVENT: if event.window.event in [sdl2.SDL_WINDOWEVENT_RESIZED, sdl2.SDL_WINDOWEVENT_SIZE_CHANGED]: self.resize(event.window.data1, event.window.data2) elif event.window.event == sdl2.SDL_WINDOWEVENT_MINIMIZED: self._iconify_func(True) elif event.window.event == sdl2.SDL_WINDOWEVENT_RESTORED: self._iconify_func(False)
[docs] def close(self): """Close the window""" super().close() self._close_func()
[docs] def destroy(self) -> None: """Gracefully close the window""" sdl2.SDL_GL_DeleteContext(self._context) sdl2.SDL_DestroyWindow(self._window) sdl2.SDL_Quit()