mischief-sdl (empty) → 0.1.0.0
raw patch · 7 files changed
+631/−0 lines, 7 filesdep +basedep +containersdep +data-default
Dependencies added: base, containers, data-default, mischief-ecs, mischief-sdl, primitive, sdl3-bindgen-sys
Files
- CHANGELOG.md +5/−0
- LICENSE +29/−0
- mischief-sdl.cabal +135/−0
- src/Mischief/SDL.hs +66/−0
- src/Mischief/SDL/Events.hs +243/−0
- src/Mischief/SDL/Window.hs +122/−0
- test/Main.hs +31/−0
+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for mischief-sdl++## 0.1.0.0 ++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,29 @@+Copyright (c) 2026, Damon+++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of the copyright holder nor the names of its+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ mischief-sdl.cabal view
@@ -0,0 +1,135 @@+cabal-version: 3.0+-- The cabal-version field refers to the version of the .cabal specification,+-- and can be different from the cabal-install (the tool) version and the+-- Cabal (the library) version you are using. As such, the Cabal (the library)+-- version used must be equal or greater than the version stated in this field.+-- Starting from the specification version 2.2, the cabal-version field must be+-- the first thing in the cabal file.+-- Initial package description 'mischief' generated by+-- 'cabal init'. For further documentation, see:+-- http://haskell.org/cabal/users-guide/+--+-- The name of the package.+name: mischief-sdl+-- The package version.+-- See the Haskell package versioning policy (PVP) for standards+-- guiding when and how versions should be incremented.+-- https://pvp.haskell.org+-- PVP summary: +-+------- breaking API changes+-- | | +----- non-breaking API additions+-- | | | +--- code changes with no API change+version: 0.1.0.0+-- A short (one-line) description of the package.+-- synopsis:+-- A longer description of the package.+-- description:+-- The license under which the package is released.+homepage: https://codeberg.org/mischief/mischief+synopsis: Library providing SDL integration for the Mischief game engine.+description: Integrates SDL events into Mischief messages and contains windowing utilities.+license: BSD-3-Clause+-- The file containing the license text.+license-file: LICENSE+-- The package author(s).+author: Damon+-- An email address to which users can send suggestions, bug reports, and patches.+maintainer: pvdoriginal2019@gmail.com+-- A copyright notice.+-- copyright:+build-type: Simple+-- Extra doc files to be distributed with the package, such as a CHANGELOG or a README.+extra-doc-files:+ CHANGELOG.md++-- Extra source files to be distributed with the package, such as examples, or a tutorial module.+-- extra-source-files:+common warnings+ ghc-options:+ "-Wall,"+ -Wno-name-shadowing++library+ -- Import common warning flags.+ import: warnings+ -- Modules exported by the library.+ exposed-modules:+ Mischief.SDL+ Mischief.SDL.Events+ Mischief.SDL.Window++ -- Modules included in this library but not exported.+ -- other-modules:+ other-modules:+ -- LANGUAGE extensions used by modules in this package.z+ default-extensions:+ DefaultSignatures+ DeriveAnyClass+ DuplicateRecordFields+ FunctionalDependencies+ ImportQualifiedPost+ MagicHash+ NoFieldSelectors+ OverloadedRecordDot+ OverloadedStrings+ QuasiQuotes+ RequiredTypeArguments+ TemplateHaskell+ TypeFamilyDependencies+ UndecidableInstances++ -- other-extensions:+ -- Other library packages from which modules are imported.+ build-depends:+ base >=4.21.0 && <4.22,+ containers >=0.7 && <0.8,+ data-default >=0.8.0 && <0.9,+ mischief-ecs >=0.2.0 && <0.3,+ primitive >=0.9.1 && <0.10,+ sdl3-bindgen-sys >=0.0.1 && <0.1,++ -- Directories containing source files.+ hs-source-dirs:+ src++ -- Base language which the package is written in.+ default-language:+ GHC2024++ ghc-options: -fno-omit-yields++test-suite mischief-test+ -- Import common warning flags.+ import: warnings+ ghc-options: -fno-omit-yields+ -- Base language which the package is written in.+ default-language: GHC2024+ -- Modules included in this executable, other than Main.+ -- other-modules:+ -- LANGUAGE extensions used by modules in this package.+ default-extensions:+ DeriveAnyClass+ DuplicateRecordFields+ NoFieldSelectors+ NoGeneralizedNewtypeDeriving+ OverloadedRecordDot+ RequiredTypeArguments+ TypeFamilyDependencies++ -- other-extensions:+ -- The interface type and version of the test suite.+ type: exitcode-stdio-1.0+ -- Directories containing source files.+ hs-source-dirs: test+ -- The entrypoint to the test suite.+ main-is: Main.hs+ -- Test dependencies.+ build-depends:+ base,+ containers,+ data-default,+ mischief-ecs,+ mischief-sdl,+ primitive,++ pkgconfig-depends:+ sdl3
+ src/Mischief/SDL.hs view
@@ -0,0 +1,66 @@+-- | Provides SDL utlities for Mischief.+module Mischief.SDL+ ( -- * What is SDL?+ -- $whatis++ -- * Installing SDL+ -- $installing+ SDLPlugin,+ module Mischief.SDL.Events,+ module Mischief.SDL.Window,+ )+where++import Mischief.ECS (Plugin (..), dep)+import Mischief.SDL.Events+import Mischief.SDL.Window++data SDLPlugin++instance Plugin SDLPlugin where+ deps = [dep @SDLEventsPlugin, dep @WindowPlugin]++-- $whatis+-- [SDL](https://wiki.libsdl.org) is a C library offering low-level tools for windows, input, rendering, etc.+-- A lot of the official Mischief libraries (such as @mischief-input@ and @mischief-render@) use this library,+-- and therefore require SDL to be installed.++-- $installing+-- The current official version of SDL used is @sdl-3.4.18@. You should+-- find this pre-built for most Operating Systems, and installing it is relatively easy.+--+-- These install instructions are mostly copied from [sdl3-bindgen-sys](https://hackage.haskell.org/package/sdl3-bindgen-sys)'s readme.+--+-- * Debian / Ubuntu+--+-- @+-- apt install libsdl3-dev-3.4.18+-- @+--+-- * MacOS+--+-- @+-- -- uninstall sdl3 if you have it+-- brew tap-new $USER/local+-- brew extract --version=3.4.18 sdl3 $USER/local+-- brew install $USER/local/sdl3@3.4.18+-- @+--+-- * Arch+--+-- @+-- pacman -S sdl3@3.4.18+-- @+--+-- * Fedora+--+-- @+-- dnf install SDL3-devel-3.4.18+-- @+--+-- * Windows+--+-- @+-- pacman -Syyu # repeat/restart terminal if pacman asks you to+-- pacman -S mingw-w64-ucrt-x86_64-sdl3-3.4.18 mingw-w64-ucrt-x86_64-pkgconf+-- @
+ src/Mischief/SDL/Events.hs view
@@ -0,0 +1,243 @@+{-# LANGUAGE MultiWayIf #-}++module Mischief.SDL.Events+ ( -- $intro+ SDLEventsPlugin,+ SDLMessage (..),+ SDLWindow (..),+ handleEvents,+ )+where++import Control.Monad+import Control.Monad.IO.Class+import Data.Foldable+import Data.Primitive.Ptr+import Foreign (Storable (peek), castPtr)+import Mischief.ECS+import Mischief.ECS.App.Schedules (First)+import Mischief.ECS.Foreign as F+import Mischief.ECS.Messages (Message)+import Mischief.ECS.Messages qualified as Messages+import SDL3.Sys (destroyWindow)+import SDL3.Sys qualified as SDL3+import System.Exit++newtype SDLWindow = SDLWindow {ptr :: Ptr SDL3.SDL_Window}+ deriving anyclass (Component)++-- deriving newtype (Show)++initSdl :: IO ()+initSdl = do+ version <- SDL3.getVersion+ let (major, rest) = fromIntegral version `divMod` (1000000 :: Int)+ (minor, micro) = rest `divMod` 1000+ putStrLn+ ( "sdl3-raw: linked against SDL "+ <> show major+ <> "."+ <> show minor+ <> "."+ <> show micro+ )++ -- The curated layer types the macro constant at the SDL_InitFlags+ -- newtype (the raw sDL_INIT_VIDEO CUInt stays available under+ -- SDL3.Sys.Bindgen.Init).+ ok <- SDL3.init SDL3.SDL_INIT_VIDEO+ unless ok (die "SDL_Init")++-- window <- withCString "sdl3-raw" $ \title -> SDL3.createWindow (ConstPtr title) 640 360 0++-- when (window == nullPtr) (die "Couldn't create window")++-- pure window++data SDLMessage e = SDLMessage {eventType :: SDL3.SDL_EventType, event :: e}+ deriving anyclass (Message)+ deriving stock (Show)++data SDLEventsPlugin++instance Plugin SDLEventsPlugin where+ init = do+ liftIO initSdl++ systems handleEvents+ & schedule @First++ systems (handleQuit, handleWindowClose)+ & after handleEvents+ & schedule @First++-- addMessage @(SDLMessage SDL3.SDL_DisplayEvent)+-- addMessage @(SDLMessage SDl3.SDL_WindowEvent)+-- addMessage @(SDLMessage SDL3.SDL_KeyboardEvent)+-- addMessage @(SDLMessage SDLMouseButtonEvent)+-- addMessage @(SDLMessage SDLMouseMotionEvent)+-- addMessage @(SDLMessage SDLQuitEvent)++-- addSystems First handleEvents+-- addSystems First $ handleQuit `after` handleEvents++handleEvents :: System ()+handleEvents = F.alloca @SDL3.SDL_Event $ \event -> do+ pending <- liftIO $ SDL3.pollEvent event+ when pending $ do+ e <- liftIO $ peek event+ eventType <- liftIO $ peek (castPtr event :: Ptr SDL3.SDL_EventType)+ handleEvent eventType e+ handleEvents++-- alloca @SDL3.SDL_Event $ \event -> do+-- liftIO SDL3.pollEventSafe+-- case event of+-- Nothing -> do+-- return ()+-- Just event -> do+-- handleEvent event+-- handleEvents++-- these correspond to https://wiki.libsdl.org/SDL3/SDL_Event+handleEvent :: SDL3.SDL_EventType -> SDL3.SDL_Event -> System ()+handleEvent t e = case t of+ -- audio+ SDL3.SDL_EVENT_AUDIO_DEVICE_ADDED -> s t e.adevice+ SDL3.SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED -> s t e.adevice+ SDL3.SDL_EVENT_AUDIO_DEVICE_REMOVED -> s t e.adevice+ -- TODO: camera+ -- TODO: clipboard+ -- display+ SDL3.SDL_EVENT_DISPLAY_ADDED -> s t e.display+ SDL3.SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED -> s t e.display+ SDL3.SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED -> s t e.display+ SDL3.SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED -> s t e.display+ SDL3.SDL_EVENT_DISPLAY_FIRST -> s t e.display+ SDL3.SDL_EVENT_DISPLAY_LAST -> s t e.display+ SDL3.SDL_EVENT_DISPLAY_MOVED -> s t e.display+ SDL3.SDL_EVENT_DISPLAY_ORIENTATION -> s t e.display+ SDL3.SDL_EVENT_DISPLAY_REMOVED -> s t e.display+ SDL3.SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED -> s t e.display+ -- TODO: gamepad+ -- TODO: gamepad axis+ -- TODO: gamepad button+ -- TODO: gamepad touchpad+ -- TODO: gamepad sensor+ -- TODO: drop+ -- TODO: finger+ -- TODO: pinch+ -- keyboard+ SDL3.SDL_EVENT_KEYBOARD_ADDED -> s t e.kdevice+ SDL3.SDL_EVENT_KEYBOARD_REMOVED -> s t e.kdevice+ -- key+ SDL3.SDL_EVENT_KEY_DOWN -> s t e.key+ SDL3.SDL_EVENT_KEY_UP -> s t e.key+ -- TODO: joystick+ -- TODO: joystick axis+ -- TODO: joystick ball+ -- TODO: joystick hat+ -- TODO: joystick battery+ -- TODO: joystick button+ -- mouse+ SDL3.SDL_EVENT_MOUSE_ADDED -> s t e.mdevice+ SDL3.SDL_EVENT_MOUSE_REMOVED -> s t e.mdevice+ -- mouse motion+ SDL3.SDL_EVENT_MOUSE_MOTION -> s t e.motion+ -- mouse button+ SDL3.SDL_EVENT_MOUSE_BUTTON_DOWN -> s t e.button+ SDL3.SDL_EVENT_MOUSE_BUTTON_UP -> s t e.button+ -- mouse wheel+ SDL3.SDL_EVENT_MOUSE_WHEEL -> s t e.wheel+ -- TODO: pen proximity+ -- TODO: pen touch+ -- TODO: pen motion+ -- TODO: pen button+ -- TODO: pen axis+ -- quit+ SDL3.SDL_EVENT_QUIT -> s t e.quit+ -- TODO: sensor+ -- TODO: edit+ -- TODO: edit candidates+ -- text+ SDL3.SDL_EVENT_TEXT_INPUT -> s t e.text+ -- user+ SDL3.SDL_EVENT_USER -> s t e.user+ -- window+ SDL3.SDL_EVENT_WINDOW_CLOSE_REQUESTED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_DESTROYED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_DISPLAY_CHANGED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_ENTER_FULLSCREEN -> s t e.window+ SDL3.SDL_EVENT_WINDOW_EXPOSED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_FIRST -> s t e.window+ SDL3.SDL_EVENT_WINDOW_FOCUS_GAINED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_FOCUS_LOST -> s t e.window+ SDL3.SDL_EVENT_WINDOW_HDR_STATE_CHANGED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_HIDDEN -> s t e.window+ SDL3.SDL_EVENT_WINDOW_HIT_TEST -> s t e.window+ SDL3.SDL_EVENT_WINDOW_ICCPROF_CHANGED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_LAST -> s t e.window+ SDL3.SDL_EVENT_WINDOW_LEAVE_FULLSCREEN -> s t e.window+ SDL3.SDL_EVENT_WINDOW_MAXIMIZED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_METAL_VIEW_RESIZED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_MINIMIZED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_MOUSE_ENTER -> s t e.window+ SDL3.SDL_EVENT_WINDOW_MOUSE_LEAVE -> s t e.window+ SDL3.SDL_EVENT_WINDOW_MOVED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_OCCLUDED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_RESIZED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_RESTORED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_SAFE_AREA_CHANGED -> s t e.window+ SDL3.SDL_EVENT_WINDOW_SHOWN -> s t e.window+ -- common+ t -> s t e.common+ where+ s t a = Messages.write $ SDLMessage t a++handleQuit :: System ()+handleQuit = do+ messages <- Messages.read @(SDLMessage SDL3.SDL_QuitEvent)+ unless (null messages) $ liftIO exitSuccess++handleWindowClose :: System ()+handleWindowClose = do+ messages <- filter (\(SDLMessage t _) -> t == SDL3.SDL_EVENT_WINDOW_CLOSE_REQUESTED) <$> Messages.read @(SDLMessage SDL3.SDL_WindowEvent)++ for_ messages $ \(SDLMessage _ SDL3.SDL_WindowEvent {windowID}) -> do+ window <- liftIO $ SDL3.getWindowFromID windowID+ unless (window == nullPtr) $ do+ liftIO $ destroyWindow window++ a <-+ [q|(Entity, SDLWindow) / With SDLWindow|]+ & qfilter (\(_, SDLWindow p) -> p == window)+ & qmap fst+ & single++ traverse_ despawn a++-- $intro+-- This package provides the 'sdlPlugin' for @Mischief@, along with a few components.+--+-- These are necessary to run any SDL-based packages, such as @MischiefInput@, and @MischiefRender@.+--+-- In order to properly run this, you'll need to build / install SDL locally. This can be done via:+--+-- @+-- git clone --recurse-submodules https://github.com/PVDoriginal/mischief.git+-- cd mischief\/external\/SDL3+-- mkdir -p build && cd build+-- cmake -DCMAKE_BUILD_TYPE=Release -GNinja ..+-- cmake --build . --config Release --parallel+-- sudo cmake --install . --config Release # omit sudo on Windows+-- @+--+-- On @Windows@, ensure @SDL3.dll@ is available in @PATH@ (or next to your .exe). If @pkg-config@ cannot find SDL3, set:+--+-- @+-- set PKG_CONFIG_PATH=path\to\SDL3\lib\pkgconfig+-- # or+-- \$env:PKG_CONFIG_PATH="path\to\SDL3\lib\pkgconfig"+-- @
+ src/Mischief/SDL/Window.hs view
@@ -0,0 +1,122 @@+module Mischief.SDL.Window where++import Control.Monad.IO.Class+import Data.Bits ((.|.))+import Data.Default+import Data.Foldable (for_)+import Foreign.C+import Foreign.C.ConstPtr (ConstPtr (..))+import Mischief.ECS+import Mischief.ECS.App.Schedules (First)+import Mischief.ECS.Messages qualified as Messages+import Mischief.SDL.Events+import SDL3.Sys qualified as SDL3+import SDL3.Sys.Video++-- | A component that will create a new window when added to an entity, and destroy it when removed.+--+-- Windows can be configured by inserting a 'WindowSize', 'WindowTitle', 'WindowFlags' alongside this component.+data Window = Window++instance Component Window where+ onAdd = [hook handleNewWindow]+ onRemove = [hook handleWindowRemove]+ required = require @(WindowSize, WindowTitle, WindowFlags)++-- | The size of a window in pixels.+data WindowSize = WindowSize {width :: Int, height :: Int} deriving (Component)++instance Default WindowSize where+ def = WindowSize 600 400++-- | The displayed title (or name) of a window.+newtype WindowTitle = WindowTitle String deriving anyclass (Component)++instance Default WindowTitle where+ def = WindowTitle "Mischief Window"++handleNewWindow :: HookContext -> System ()+handleNewWindow (HookContext entity) = do+ Just (WindowSize w h, WindowTitle title, flags) <- single [q|entity. WindowSize, WindowTitle, WindowFlags|]+ window <- liftIO $ withCString title $ \title -> SDL3.createWindow (ConstPtr title) (fromIntegral w) (fromIntegral h) (flagsToBit flags)+ insert (SDLWindow window) entity++handleWindowRemove :: HookContext -> System ()+handleWindowRemove (HookContext entity) = do+ Just (SDLWindow p) <- single [q|entity. SDLWindow|]+ liftIO $ SDL3.destroyWindow p++-- | These correspond to the [SDL3 Window Flags](https://wiki.libsdl.org/SDL3/SDL_WindowFlags).+--+-- The most important ones are 'WindowFullscreen' and 'WindowResizable'.+data WindowFlag+ = WindowFullscreen+ | WindowHidden+ | WindowBorderless+ | WindowResizable+ | WindowMinimized+ | WindowMaximized+ | WindowModal+ | WindowHighPixelDensity+ | WindowMouseRelativeMode+ | WindowAlwaysOnTop+ | WindowUtility+ | WindowTooltip+ | WindowPopupMenu+ | WindowTransparent+ | WindowNotFocuable+ | WindowMetal++flagToBit :: WindowFlag -> SDL_WindowFlags+flagToBit WindowFullscreen = SDL_WINDOW_FULLSCREEN+flagToBit WindowHidden = SDL_WINDOW_HIDDEN+flagToBit WindowBorderless = SDL_WINDOW_BORDERLESS+flagToBit WindowResizable = SDL_WINDOW_RESIZABLE+flagToBit WindowMinimized = SDL_WINDOW_MINIMIZED+flagToBit WindowMaximized = SDL_WINDOW_MAXIMIZED+flagToBit WindowModal = SDL_WINDOW_MODAL+flagToBit WindowHighPixelDensity = SDL_WINDOW_HIGH_PIXEL_DENSITY+flagToBit WindowMouseRelativeMode = SDL_WINDOW_MOUSE_RELATIVE_MODE+flagToBit WindowAlwaysOnTop = SDL_WINDOW_ALWAYS_ON_TOP+flagToBit WindowUtility = SDL_WINDOW_UTILITY+flagToBit WindowTooltip = SDL_WINDOW_TOOLTIP+flagToBit WindowPopupMenu = SDL_WINDOW_POPUP_MENU+flagToBit WindowTransparent = SDL_WINDOW_TRANSPARENT+flagToBit WindowNotFocuable = SDL_WINDOW_NOT_FOCUSABLE+flagToBit WindowMetal = SDL_WINDOW_METAL++-- | A list of 'WindowFlag's specifying various configurations for the window. The only one set by default is 'WindowResizable'.+newtype WindowFlags = WindowFlags [WindowFlag] deriving anyclass (Component)++instance Default WindowFlags where+ def = WindowFlags [WindowResizable]++flagsToBit :: WindowFlags -> SDL_WindowFlags+flagsToBit (WindowFlags a) = foldr (\a b -> b .|. flagToBit a) 0 a++-- | Plugin adding windowing functionality.+data WindowPlugin++instance Plugin WindowPlugin where+ init = do+ systems handleWindowEvents+ & after handleEvents+ & schedule @First++handleWindowEvents :: System ()+handleWindowEvents = do+ messages <- Messages.read @(SDLMessage SDL3.SDL_WindowEvent)+ for_ messages handleWindowEvent++handleWindowEvent :: SDLMessage SDL3.SDL_WindowEvent -> System ()+handleWindowEvent (SDLMessage SDL3.SDL_EVENT_WINDOW_RESIZED w) = do+ let width :: Int = fromIntegral w.data1+ let height :: Int = fromIntegral w.data2++ window <- liftIO $ SDL3.getWindowFromID w.windowID++ [q|(Entity, SDLWindow) / With SDLWindow|]+ & qfilter (\(_, SDLWindow p) -> p == window)+ & qinsert (const $ WindowSize width height)+ & query_+handleWindowEvent _ = pure ()
+ test/Main.hs view
@@ -0,0 +1,31 @@+module Main where++import Data.Maybe+import Mischief.ECS+import Mischief.ECS.Components.Spawn+import Mischief.ECS.Systems qualified as Systems+import Mischief.SDL+import Mischief.SDL.Window++main :: IO ()+main = do+ app <- newApp+ addPlugin @MainPlugin app+ runApp app++data MainPlugin = MainPlugin deriving (Eq)++instance Plugin MainPlugin where+ init = do+ schedule @Update $ systems (pure () :: System ())+ schedule @Startup $ systems setup++ deps = [dep @SDLPlugin]++setup :: System ()+setup = do+ w1 <- spawn (Window, WindowSize 100 300)+ w2 <- spawn (Window, WindowTitle "Second Window", WindowSize 1000 40)+ w3 <- spawn Window++ pure ()