1 module des.gui.sdlgl.window;
2 
3 import des.gui.sdlgl.base;
4 
5 import des.gui.event;
6 import des.gui.sdlgl.context;
7 import des.gui.sdlgl.canvas;
8 
9 import std.conv;
10 
11 class NotInputEventException : Exception
12 { this() @safe pure nothrow { super( "service exception" ); } }
13 
14 /// SDL window with open gl
15 class DiSDLGLWindow : DesObject
16 {
17     mixin DES;
18 
19 package:
20 
21     SDL_Window* win = null;
22 
23     void prepare()
24     {
25         _canvas.prepare();
26     }
27 
28 protected:
29 
30     ivec2 _size;
31 
32     DiSDLGLContext ctx;
33 
34     DiWidget _widget;
35     DiGLCanvas _canvas;
36 
37 public:
38 
39     enum Flag : uint
40     {
41         FULLSCREEN         = SDL_WINDOW_FULLSCREEN,         /// `SDL_WINDOW_FULLSCREEN`
42         FULLSCREEN_DESKTOP = SDL_WINDOW_FULLSCREEN_DESKTOP, /// `SDL_WINDOW_FULLSCREEN_DESKTOP`
43         OPENGL             = SDL_WINDOW_OPENGL,             /// `SDL_WINDOW_OPENGL`
44         SHOWN              = SDL_WINDOW_SHOWN,              /// `SDL_WINDOW_SHOWN`
45         HIDDEN             = SDL_WINDOW_HIDDEN,             /// `SDL_WINDOW_HIDDEN`
46         BORDERLESS         = SDL_WINDOW_BORDERLESS,         /// `SDL_WINDOW_BORDERLESS`
47         RESIZABLE          = SDL_WINDOW_RESIZABLE,          /// `SDL_WINDOW_RESIZABLE`
48         MINIMIZED          = SDL_WINDOW_MINIMIZED,          /// `SDL_WINDOW_MINIMIZED`
49         MAXIMIZED          = SDL_WINDOW_MAXIMIZED,          /// `SDL_WINDOW_MAXIMIZED`
50         INPUT_GRABBED      = SDL_WINDOW_INPUT_GRABBED,      /// `SDL_WINDOW_INPUT_GRABBED`
51         INPUT_FOCUS        = SDL_WINDOW_INPUT_FOCUS,        /// `SDL_WINDOW_INPUT_FOCUS`
52         MOUSE_FOCUS        = SDL_WINDOW_MOUSE_FOCUS,        /// `SDL_WINDOW_MOUSE_FOCUS`
53         FOREIGN            = SDL_WINDOW_FOREIGN,            /// `SDL_WINDOW_FOREIGN`
54         ALLOW_HIGHDPI      = SDL_WINDOW_ALLOW_HIGHDPI,      /// `SDL_WINDOW_ALLOW_HIGHDPI`
55     }
56 
57     this( DiSDLGLContext ctx, DiWidget w )
58     {
59         bool fullscreen = false;
60         int display = 0;
61 
62         _widget = w;
63         this.ctx = ctx;
64 
65         createWindow( to!string(w.name), w.size, fullscreen, display );
66 
67         _canvas = newEMM!DiGLCanvas;
68 
69         logger.Debug( "pass" );
70     }
71 
72     ///
73     DiWidget widget() @property { return _widget; }
74 
75     ///
76     DiCanvas canvas() @property { return _canvas; }
77 
78     ///
79     //Предполагается, что входящее событие предназначено именно этому окну
80     void procEvent( in SDL_Event ev )
81     {
82         try widget.processInput( convToInputEvent(ev) );
83         catch( NotInputEventException )
84         {
85             /+ TODO: process window, user, quit etc +/
86         }
87 
88         if( ev.type == SDL_WINDOWEVENT &&
89             ev.window.event == SDL_WINDOWEVENT_RESIZED )
90         {
91             _size = ivec2( ev.window.data1, ev.window.data2 );
92             _canvas.resize( _size );
93             widget.shape.rect = DiRect( 0, 0, _size );
94         }
95     }
96 
97     void step()
98     {
99         makeCurrent();
100         widget.update();
101 
102         preDraw();
103         widget.render();
104         postDraw();
105     }
106 
107     @property
108     {
109         ///
110         uint id() { return SDL_GetWindowID( win ); }
111 
112         ///
113         ivec2 size() const { return _size; }
114 
115         ///
116         float brightness() const
117         { return SDL_GetWindowBrightness( cast(SDL_Window*)win ); }
118 
119         ///
120         float brightness( float v )
121         {
122             SDL_SetWindowBrightness( win, v );
123             return v;
124         }
125 
126         ///
127         int displayIndex() const
128         { return SDL_GetWindowDisplayIndex( cast(SDL_Window*)win ); }
129     }
130 
131     ///
132     void show() { SDL_ShowWindow( win ); }
133     ///
134     void hide() { SDL_HideWindow( win ); }
135 
136     ///
137     bool checkFlag( Flag flag ) const { return cast(bool)( SDLFlags & flag ); }
138 
139     const @property
140     {
141         ///
142         bool isFullscreen()        { return checkFlag( Flag.FULLSCREEN ); }
143         ///
144         bool isFullscreenDesktop() { return checkFlag( Flag.FULLSCREEN_DESKTOP ); }
145         ///
146         bool isOpenGL()            { return checkFlag( Flag.OPENGL ); }
147         ///
148         bool isShown()             { return checkFlag( Flag.SHOWN ); }
149         ///
150         bool isHidden()            { return checkFlag( Flag.HIDDEN ); }
151         ///
152         bool isBorderless()        { return checkFlag( Flag.BORDERLESS ); }
153         ///
154         bool isResizable()         { return checkFlag( Flag.RESIZABLE ); }
155         ///
156         bool isMinimized()         { return checkFlag( Flag.MINIMIZED ); }
157         ///
158         bool isMaximized()         { return checkFlag( Flag.MAXIMIZED ); }
159         ///
160         bool isInputGrabbed()      { return checkFlag( Flag.INPUT_GRABBED ); }
161         ///
162         bool isInputFocus()        { return checkFlag( Flag.INPUT_FOCUS ); }
163         ///
164         bool isMouseFocus()        { return checkFlag( Flag.MOUSE_FOCUS ); }
165         ///
166         bool isForeign()           { return checkFlag( Flag.FOREIGN ); }
167         ///
168         bool isAllowHighdpi()      { return checkFlag( Flag.ALLOW_HIGHDPI ); }
169     }
170 
171     void startTextInput() { ctx.startTextInput(); }
172     void stopTextInput() { ctx.stopTextInput(); }
173 
174 protected:
175 
176     DiInputEvent convToInputEvent( in SDL_Event ev ) const
177     {
178         switch( ev.type )
179         {
180             case SDL_KEYDOWN:
181             case SDL_KEYUP:
182             case SDL_MOUSEMOTION:
183             case SDL_MOUSEBUTTONDOWN:
184             case SDL_MOUSEBUTTONUP:
185             case SDL_MOUSEWHEEL:
186             case SDL_TEXTINPUT:
187             case SDL_TEXTEDITING:
188             case SDL_JOYAXISMOTION:
189             case SDL_JOYBALLMOTION:
190             case SDL_JOYHATMOTION:
191             case SDL_JOYBUTTONUP:
192             case SDL_JOYBUTTONDOWN:
193             case SDL_JOYDEVICEADDED:
194             case SDL_JOYDEVICEREMOVED:
195             case SDL_FINGERDOWN:
196             case SDL_FINGERUP:
197             case SDL_FINGERMOTION:
198             case SDL_DROPFILE:
199                 return cast(DiInputEvent)ev;
200             default:
201                 throw new NotInputEventException;
202         }
203     }
204 
205     void preDraw() { canvas.preDraw(); }
206     void postDraw()
207     {
208         canvas.postDraw();
209         SDL_GL_SwapWindow( win );
210     }
211     void makeCurrent() { SDL_GL_MakeCurrent( win, ctx.context ); }
212 
213     ///
214     uint SDLFlags() const @property
215     { return SDL_GetWindowFlags( cast(SDL_Window*)win ); }
216 
217     void createWindow( string title, ivec2 sz, bool fullscreen, int display )
218     {
219         _size = sz;
220         if( display != -1 && display > SDL_GetNumVideoDisplays() - 1 )
221             throw new DiException( format( "No such display: display%d", display ) );
222 
223         auto flags = Flag.OPENGL | Flag.SHOWN | ( fullscreen ? Flag.FULLSCREEN : Flag.RESIZABLE );
224 
225         auto pos = ivec2( SDL_WINDOWPOS_CENTERED );
226 
227         if( display != -1 )
228             pos = ivec2( SDL_WINDOWPOS_CENTERED_DISPLAY( display ) );
229 
230         win = SDL_CreateWindow( title.toStringz, pos.x, pos.y, _size.x, _size.y, flags );
231         if( win is null )
232             throw new DiException( "Couldn't create SDL widnow: " ~ toDString( SDL_GetError() ) );
233     }
234 
235     override void selfDestroy()
236     {
237         if( win !is null )
238             SDL_DestroyWindow( win );
239         win = null;
240         debug logger.Debug("pass");
241     }
242 }