1 module dlangui.platforms.dsfml.dsfmlapp;
2 
3 public import dlangui.core.config;
4 
5 static if (BACKEND_DSFML):
6 
7 import dlangui.platforms.common.platform;
8 import dsfml.graphics;
9 import std.array;
10 
11 import dlangui.core.collections;
12 import dlangui.core.logger;
13 import dlangui.widgets.widget;
14 import dlangui.widgets.popup;
15 import dlangui.graphics.drawbuf;
16 import dlangui.core.stdaction;
17 import dlangui.dialogs.msgbox;
18 
19 private import dlangui.graphics.gldrawbuf;
20 
21 /**
22  * Window abstraction layer. Widgets can be shown only inside window.
23  * 
24  */
25 class DSFMLWindow : dlangui.platforms.common.platform.Window {
26 
27     private RenderWindow _wnd;
28     private bool _ownRenderWindow;
29     static private bool _gl3Reloaded = false;
30 
31     @property RenderWindow wnd() { return _wnd; }
32 
33     this(RenderWindow wnd, bool own) {
34         _wnd = wnd;
35         _ownRenderWindow = own;
36         super();
37         auto sz = wnd.size;
38         onResize(sz.x, sz.y);
39     }
40 
41     ~this() {
42         if (_ownRenderWindow) {
43             destroy(_wnd);
44         }
45         _wnd = null;
46     }
47 
48     override void show() {
49     }
50 
51     /// returns window caption
52     override @property dstring windowCaption() {
53         // TODO
54         return ""d;
55     }
56     /// sets window caption
57     override @property void windowCaption(dstring caption) {
58         // TODO
59     }
60     /// sets window icon
61     override @property void windowIcon(DrawBufRef icon) {
62         // TODO
63     }
64     /// request window redraw
65     override void invalidate() {
66         // TODO
67     }
68     /// close window
69     override void close() {
70         // TODO
71     }
72 
73     void draw() {
74         paintUsingOpenGL();
75     }
76 
77     private void paintUsingOpenGL() {
78         import derelict.opengl3.gl3;
79 
80         glDisable(GL_DEPTH_TEST);
81         glViewport(0, 0, _dx, _dy);
82         float a = 1.0f;
83         float r = ((_backgroundColor >> 16) & 255) / 255.0f;
84         float g = ((_backgroundColor >> 8) & 255) / 255.0f;
85         float b = ((_backgroundColor >> 0) & 255) / 255.0f;
86         //glClearColor(r, g, b, a);
87         //glClear(GL_COLOR_BUFFER_BIT);
88 
89         GLDrawBuf buf = new GLDrawBuf(_dx, _dy, false);
90 
91         buf.beforeDrawing();
92         onDraw(buf);
93         buf.afterDrawing();
94     }
95 
96     private MouseButton translateButton(uint btn) {
97         switch(btn) with(Mouse.Button) {
98             default:
99             case Left:
100                 return MouseButton.Left;
101             case Right:
102                 return MouseButton.Right;
103             case Middle:
104                 return MouseButton.Middle;
105             case XButton1:
106                 return MouseButton.XButton1;
107             case XButton2:
108                 return MouseButton.XButton2;
109         }
110     }
111 
112     private uint translateKey(uint key) {
113         switch(key) with(Keyboard.Key)
114         {
115             case A: return KeyCode.KEY_A;
116             case B: return KeyCode.KEY_B;
117             case C: return KeyCode.KEY_C;
118             case D: return KeyCode.KEY_D;
119             case E: return KeyCode.KEY_E;
120             case F: return KeyCode.KEY_F;
121             case G: return KeyCode.KEY_G;
122             case H: return KeyCode.KEY_H;
123             case I: return KeyCode.KEY_I;
124             case J: return KeyCode.KEY_J;
125             case K: return KeyCode.KEY_K;
126             case L: return KeyCode.KEY_L;
127             case M: return KeyCode.KEY_M;
128             case N: return KeyCode.KEY_N;
129             case O: return KeyCode.KEY_O;
130             case P: return KeyCode.KEY_P;
131             case Q: return KeyCode.KEY_Q;
132             case R: return KeyCode.KEY_R;
133             case S: return KeyCode.KEY_S;
134             case T: return KeyCode.KEY_T;
135             case U: return KeyCode.KEY_U;
136             case V: return KeyCode.KEY_V;
137             case W: return KeyCode.KEY_W;
138             case X: return KeyCode.KEY_X;
139             case Y: return KeyCode.KEY_Y;
140             case Z: return KeyCode.KEY_Z;
141             case Num0: return KeyCode.KEY_0;
142             case Num1: return KeyCode.KEY_1;
143             case Num2: return KeyCode.KEY_2;
144             case Num3: return KeyCode.KEY_3;
145             case Num4: return KeyCode.KEY_4;
146             case Num5: return KeyCode.KEY_5;
147             case Num6: return KeyCode.KEY_6;
148             case Num7: return KeyCode.KEY_7;
149             case Num8: return KeyCode.KEY_8;
150             case Num9: return KeyCode.KEY_9;
151             case Escape: return KeyCode.ESCAPE;
152             case LControl: return KeyCode.LCONTROL;
153             case LShift: return KeyCode.LSHIFT;
154             case LAlt: return KeyCode.LALT;
155             case RControl: return KeyCode.RCONTROL;
156             case RShift: return KeyCode.RSHIFT;
157             case RAlt: return KeyCode.RALT;
158 
159             ///The [ key
160             case LBracket: return KeyCode.KEY_BRACKETOPEN;
161             ///The ] key
162             case RBracket: return KeyCode.KEY_BRACKETCLOSE;
163             ///The ; key
164             case SemiColon: return KeyCode.KEY_BRACKETOPEN;
165             ///The , key
166             case Comma: return KeyCode.KEY_COMMA;
167             ///The . key
168             case Period: return KeyCode.KEY_PERIOD;
169             ///The ' key
170             case Quote: return KeyCode.QUOTE;
171             ///The / key
172             case Slash: return KeyCode.KEY_DIVIDE;
173             ///The \ key
174             case BackSlash: return KeyCode.BACKSLASH;
175             ///The ~ key
176             case Tilde: return KeyCode.TILDE;
177             ///The = key
178             case Equal: return KeyCode.EQUAL;
179             ///The - key
180             case Dash: return KeyCode.SUB;
181             ///The Space key
182             case Space: return KeyCode.SPACE;
183 
184             case Numpad0: return KeyCode.NUM_0;
185             case Numpad1: return KeyCode.NUM_1;
186             case Numpad2: return KeyCode.NUM_2;
187             case Numpad3: return KeyCode.NUM_3;
188             case Numpad4: return KeyCode.NUM_4;
189             case Numpad5: return KeyCode.NUM_5;
190             case Numpad6: return KeyCode.NUM_6;
191             case Numpad7: return KeyCode.NUM_7;
192             case Numpad8: return KeyCode.NUM_8;
193             case Numpad9: return KeyCode.NUM_9;
194 
195             case F1: return KeyCode.F1;
196             case F2: return KeyCode.F2;
197             case F3: return KeyCode.F3;
198             case F4: return KeyCode.F4;
199             case F5: return KeyCode.F5;
200             case F6: return KeyCode.F6;
201             case F7: return KeyCode.F7;
202             case F8: return KeyCode.F8;
203             case F9: return KeyCode.F9;
204             case F10: return KeyCode.F10;
205             case F11: return KeyCode.F11;
206             case F12: return KeyCode.F12;
207             case F13: return KeyCode.F13;
208             case F14: return KeyCode.F14;
209             case F15: return KeyCode.F15;
210 
211             case Return: return KeyCode.RETURN;
212             case BackSpace: return KeyCode.BACK;
213             case Tab: return KeyCode.TAB;
214             case PageUp: return KeyCode.PAGEUP;
215             case PageDown: return KeyCode.PAGEDOWN;
216             case End: return KeyCode.END;
217             case Home: return KeyCode.HOME;
218             case Insert: return KeyCode.INS;
219             case Delete: return KeyCode.DEL;
220             case Add: return KeyCode.ADD;
221             case Subtract: return KeyCode.SUB;
222             case Multiply: return KeyCode.MUL;
223             case Divide: return KeyCode.DIV;
224             case Left: return KeyCode.LEFT;
225             case Right: return KeyCode.RIGHT;
226             case Up: return KeyCode.UP;
227             case Down: return KeyCode.DOWN;
228             default: return 0x8000_0000 | key;
229         }
230     }
231 
232     private ushort mouseFlags;
233     private ushort keyFlags;
234 
235     bool handleEvent(ref Event event) {
236         switch (event.type) with(event.EventType) {
237             case Closed: {
238                 break;
239             }
240             case Resized: {
241                 onResize(event.size.width, event.size.height);
242                 break;
243             }
244             case MouseButtonPressed: {
245                 auto btn = translateButton(event.mouseButton.button);
246                 mouseFlags |= mouseButtonToFlag(btn);
247                 MouseEvent ev = new MouseEvent(MouseAction.ButtonDown, btn, mouseFlags, cast(short)event.mouseButton.x, cast(short)event.mouseButton.y);
248                 return dispatchMouseEvent(ev);
249             }
250             case MouseButtonReleased: {
251                 auto btn = translateButton(event.mouseButton.button);
252                 mouseFlags &= ~mouseButtonToFlag(btn);
253                 MouseEvent ev = new MouseEvent(MouseAction.ButtonUp, btn, mouseFlags, cast(short)event.mouseButton.x, cast(short)event.mouseButton.y);
254                 return dispatchMouseEvent(ev);
255             }
256             case MouseMoved: {
257                 MouseEvent ev = new MouseEvent(MouseAction.Move, MouseButton.None, mouseFlags, cast(short)event.mouseMove.x, cast(short)event.mouseMove.y);
258                 return dispatchMouseEvent(ev);
259             }
260             case MouseEntered: {
261                 break;
262             }
263             case MouseLeft: {
264                 mouseFlags = 0;
265                 break;
266             }
267             case MouseWheelMoved: {
268                 break;
269             }
270             case TextEntered: {
271                 KeyEvent ev = new KeyEvent(KeyAction.Text, 0, 0, [event.text.unicode]);
272                 return dispatchKeyEvent(ev);
273             }
274             case KeyReleased: 
275             case KeyPressed: {
276                 keyFlags = 0;
277                 if (event.key.alt)
278                     keyFlags |= KeyFlag.Alt;
279                 if (event.key.control)
280                     keyFlags |= KeyFlag.Control;
281                 if (event.key.shift)
282                     keyFlags |= KeyFlag.Shift;
283                 KeyEvent ev = new KeyEvent(event.type == event.EventType.KeyPressed ? KeyAction.KeyDown : KeyAction.KeyUp, translateKey(event.key.code), keyFlags, [event.text.unicode]);
284                 return dispatchKeyEvent(ev);
285             }
286             default:
287                 break;
288         }
289         return true;
290     }
291 
292 }
293 
294 /**
295  * Platform abstraction layer.
296  * 
297  * Represents application.
298  * 
299  */
300 class DSFMLPlatform : Platform {
301 
302     private DSFMLWindow[] _activeWindows;
303 
304     /// register DSFML window created outside dlangui
305     DSFMLWindow registerWindow(RenderWindow window) {
306         DSFMLWindow w = new DSFMLWindow(window, false);
307         _activeWindows ~= w;
308         return w;
309     }
310 
311     /**
312      * create window
313      * Args:
314      *         windowCaption = window caption text
315      *         parent = parent Window, or null if no parent
316      *         flags = WindowFlag bit set, combination of Resizable, Modal, Fullscreen
317      * 
318      * Window w/o Resizable nor Fullscreen will be created with size based on measurement of its content widget
319      */
320     override dlangui.platforms.common.platform.Window createWindow(dstring windowCaption, 
321                                                                    dlangui.platforms.common.platform.Window parent, 
322                                                                    uint flags = WindowFlag.Resizable, uint width = 0, uint height = 0) {
323         auto window = new RenderWindow(VideoMode(800, 600, 32), "Hello DSFML!", dsfml.window.window.Window.Style.Titlebar | dsfml.window.window.Window.Style.Close | dsfml.window.window.Window.Style.Resize);
324         window.setFramerateLimit(60);
325         DSFMLWindow w = new DSFMLWindow(window, true);
326         _activeWindows ~= w;
327         return w;
328     }
329 
330     /**
331      * close window
332      * 
333      * Closes window earlier created with createWindow()
334      */
335     override void closeWindow(dlangui.platforms.common.platform.Window w) {
336         DSFMLWindow win = cast(DSFMLWindow)w;
337         // TODO: support more than one window
338         _activeWindows[0] = null;
339         _activeWindows.length = 0;// = _activeWindows.remove(win);
340         win.wnd.close();
341     }
342     /**
343      * Starts application message loop.
344      * 
345      * When returned from this method, application is shutting down.
346      */
347     override int enterMessageLoop() {
348         // TODO: support more than one window
349         if (_activeWindows.length < 1)
350             return 1;
351         DSFMLWindow w = _activeWindows[0];
352         RenderWindow window = w.wnd;
353 
354         while (window.isOpen())
355         {
356             Event event;
357         
358             while(window.pollEvent(event))
359             {
360                 if(event.type == event.EventType.Closed)
361                 {
362                     closeWindow(w);
363                     //window.close();
364                 }
365             }
366         
367             window.clear();
368         
369             //window.draw(head);
370             //window.draw(leftEye);
371             //window.draw(rightEye);
372             //window.draw(smile);
373             //window.draw(smileCover);
374         
375             window.display();
376         }
377         return 0;
378     }
379     /// retrieves text from clipboard (when mouseBuffer == true, use mouse selection clipboard - under linux)
380     override dstring getClipboardText(bool mouseBuffer = false) {
381         // TODO:
382         return ""d;
383     }
384     /// sets text to clipboard (when mouseBuffer == true, use mouse selection clipboard - under linux)
385     override void setClipboardText(dstring text, bool mouseBuffer = false) {
386         // TODO:
387     }
388 
389     /// calls request layout for all windows
390     override void requestLayout() {
391         // TODO:
392     }
393 
394 }
395 
396 /// shortcut to current DSFMLPlatform instance
397 @property DSFMLPlatform dsfmlPlatform() {
398     return cast(DSFMLPlatform)Platform.instance;
399 }
400 
401 // entry point
402 extern(C) int UIAppMain(string[] args);
403 
404 void initDSFMLApp() {
405     initLogs();
406     Log.d("Initializing DSFML platform");
407     DSFMLPlatform p = new DSFMLPlatform();
408     Platform.setInstance(p);
409     initResourceManagers();
410     initFontManager();
411 
412     currentTheme = createDefaultTheme();
413 
414     import dlangui.graphics.glsupport;
415     initGLSupport(false);
416 
417     Platform.instance.uiTheme = "theme_dark";
418 }
419 
420 
421 void uninitDSFMLApp() {
422     Log.d("Destroying DSFML platform");
423     Platform.setInstance(null);
424 
425     releaseResourcesOnAppExit();
426 }