From 26770254868b46ce9693c36f41e3b281b62e517f Mon Sep 17 00:00:00 2001 From: and3md Date: Thu, 30 Mar 2017 20:33:04 +0200 Subject: [PATCH 1/3] Implemented modal windows behavior in SDL. --- src/dlangui/platforms/sdl/sdlapp.d | 133 ++++++++++++++++++++++++++--- 1 file changed, 120 insertions(+), 13 deletions(-) diff --git a/src/dlangui/platforms/sdl/sdlapp.d b/src/dlangui/platforms/sdl/sdlapp.d index c88e5878..f2f8db06 100644 --- a/src/dlangui/platforms/sdl/sdlapp.d +++ b/src/dlangui/platforms/sdl/sdlapp.d @@ -79,18 +79,37 @@ class SDLWindow : Window { SDLPlatform _platform; SDL_Window * _win; SDL_Renderer* _renderer; + + SDLWindow[] _children; + SDLWindow _parent; + this(SDLPlatform platform, dstring caption, Window parent, uint flags, uint width = 0, uint height = 0) { _platform = platform; _caption = caption; + + _parent = cast(SDLWindow) parent; + if (_parent) + _parent._children~=this; + debug Log.d("Creating SDL window"); _dx = width; _dy = height; create(flags); + _children.reserve(20); Log.i(_enableOpengl ? "OpenGL is enabled" : "OpenGL is disabled"); } ~this() { debug Log.d("Destroying SDL window"); + + if (_parent) { + long index = countUntil(_parent._children,this); + if (index > -1 ) { + _parent._children=_parent._children.remove(index); + } + _parent = null; + } + if (_renderer) SDL_DestroyRenderer(_renderer); static if (ENABLE_OPENGL) { @@ -103,6 +122,63 @@ class SDLWindow : Window { destroy(_drawbuf); } + + bool hasModalChild() { + foreach (SDLWindow w;_children) { + if (w.flags & WindowFlag.Modal) + return true; + + if (w.hasModalChild()) + return true; + } + return false; + } + + void restoreModalChilds() { + foreach (SDLWindow w;_children) { + if (w.flags & WindowFlag.Modal) { + w.show(); + } + + w.restoreModalChilds(); + } + } + + void minimizeModalChilds() { + foreach (SDLWindow w;_children) { + if (w.flags & WindowFlag.Modal) + { + w.minimizeWindow(); + } + + w.minimizeModalChilds(); + } + } + + + void restoreParentWindows() { + SDLWindow[] tempWin; + if (!_platform) + return; + _platform._parentWindowRestoration = true; + scope(exit) {_platform._parentWindowRestoration = false;} + + SDLWindow w = this; + + while (true) { + if (w is null) + break; + + tempWin~=w; + + w = w._parent; + } + + for (size_t i = tempWin.length ; i-- > 0 ; ) { + tempWin[i].show(); + } + + } /// post event to handle in UI thread (this method can be used from background thread) override void postEvent(CustomEvent event) { @@ -1057,12 +1133,23 @@ class SDLPlatform : Platform { } return res; } + + override bool hasModalWindowsAbove(Window w) { + SDLWindow sdlWin = cast (SDLWindow) w; + if (sdlWin) { + return sdlWin.hasModalChild(); + } + return false; + } + //void redrawWindows() { // foreach(w; _windowMap) // w.redraw(); //} + private bool _parentWindowRestoration = false; + override int enterMessageLoop() { Log.i("entering message loop"); SDL_Event event; @@ -1114,37 +1201,51 @@ class SDLPlatform : Platform { w.redraw(); break; case SDL_WINDOWEVENT_CLOSE: - if (w.handleCanClose()) { - debug(DebugSDL) Log.d("SDL_WINDOWEVENT_CLOSE win=", event.window.windowID); - _windowMap.remove(windowID); - destroy(w); - } else { - skipNextQuit = true; + if (!w.hasModalChild()) { + if (w.handleCanClose()) { + debug(DebugSDL) Log.d("SDL_WINDOWEVENT_CLOSE win=", event.window.windowID); + _windowMap.remove(windowID); + destroy(w); + } else { + skipNextQuit = true; + } } break; case SDL_WINDOWEVENT_SHOWN: debug(DebugSDL) Log.d("SDL_WINDOWEVENT_SHOWN"); + if (w.hasModalChild()) + w.restoreModalChilds(); break; case SDL_WINDOWEVENT_HIDDEN: debug(DebugSDL) Log.d("SDL_WINDOWEVENT_HIDDEN"); break; case SDL_WINDOWEVENT_EXPOSED: debug(DebugSDL) Log.d("SDL_WINDOWEVENT_EXPOSED"); + if (w.hasModalChild()) + w.restoreModalChilds(); version(linux) { w.invalidate(); } break; case SDL_WINDOWEVENT_MOVED: debug(DebugSDL) Log.d("SDL_WINDOWEVENT_MOVED"); + if (w.hasModalChild()) + w.restoreModalChilds(); break; case SDL_WINDOWEVENT_MINIMIZED: debug(DebugSDL) Log.d("SDL_WINDOWEVENT_MINIMIZED"); + if (w.hasModalChild()) + w.minimizeModalChilds(); break; case SDL_WINDOWEVENT_MAXIMIZED: debug(DebugSDL) Log.d("SDL_WINDOWEVENT_MAXIMIZED"); break; case SDL_WINDOWEVENT_RESTORED: debug(DebugSDL) Log.d("SDL_WINDOWEVENT_RESTORED"); + if (!_parentWindowRestoration && w.flags & WindowFlag.Modal) + w.restoreParentWindows(); + if (!_parentWindowRestoration && w.hasModalChild()) + w.restoreModalChilds(); version(linux) { //not sure if needed on Windows or OSX. Also need to check on FreeBSD w.invalidate(); } @@ -1168,7 +1269,7 @@ class SDLPlatform : Platform { } case SDL_KEYDOWN: SDLWindow w = getWindow(event.key.windowID); - if (w) { + if (w && !w.hasModalChild()) { w.processKeyEvent(KeyAction.KeyDown, event.key.keysym.sym, event.key.keysym.mod); SDL_StartTextInput(); } @@ -1176,7 +1277,10 @@ class SDLPlatform : Platform { case SDL_KEYUP: SDLWindow w = getWindow(event.key.windowID); if (w) { - w.processKeyEvent(KeyAction.KeyUp, event.key.keysym.sym, event.key.keysym.mod); + if (w.hasModalChild()) + w.restoreModalChilds(); + else + w.processKeyEvent(KeyAction.KeyUp, event.key.keysym.sym, event.key.keysym.mod); } break; case SDL_TEXTEDITING: @@ -1185,31 +1289,34 @@ class SDLPlatform : Platform { case SDL_TEXTINPUT: debug(DebugSDL) Log.d("SDL_TEXTINPUT"); SDLWindow w = getWindow(event.text.windowID); - if (w) { + if (w && !w.hasModalChild()) { w.processTextInput(event.text.text.ptr); } break; case SDL_MOUSEMOTION: SDLWindow w = getWindow(event.motion.windowID); - if (w) { + if (w && !w.hasModalChild()) { w.processMouseEvent(MouseAction.Move, 0, event.motion.state, event.motion.x, event.motion.y); } break; case SDL_MOUSEBUTTONDOWN: SDLWindow w = getWindow(event.button.windowID); - if (w) { + if (w && !w.hasModalChild()) { w.processMouseEvent(MouseAction.ButtonDown, event.button.button, event.button.state, event.button.x, event.button.y); } break; case SDL_MOUSEBUTTONUP: SDLWindow w = getWindow(event.button.windowID); if (w) { - w.processMouseEvent(MouseAction.ButtonUp, event.button.button, event.button.state, event.button.x, event.button.y); + if (w.hasModalChild()) + w.restoreModalChilds(); + else + w.processMouseEvent(MouseAction.ButtonUp, event.button.button, event.button.state, event.button.x, event.button.y); } break; case SDL_MOUSEWHEEL: SDLWindow w = getWindow(event.wheel.windowID); - if (w) { + if (w && !w.hasModalChild()) { debug(DebugSDL) Log.d("SDL_MOUSEWHEEL x=", event.wheel.x, " y=", event.wheel.y); w.processMouseEvent(MouseAction.Wheel, 0, 0, event.wheel.x, event.wheel.y); } From 076b2a44e7d418af281ca9eaaf8b1e9bf7487cff Mon Sep 17 00:00:00 2001 From: and3md Date: Sat, 8 Apr 2017 17:02:07 +0200 Subject: [PATCH 2/3] Changed long to ptrdiff_t fix 32bit build --- src/dlangui/platforms/sdl/sdlapp.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dlangui/platforms/sdl/sdlapp.d b/src/dlangui/platforms/sdl/sdlapp.d index f2f8db06..9ad1d143 100644 --- a/src/dlangui/platforms/sdl/sdlapp.d +++ b/src/dlangui/platforms/sdl/sdlapp.d @@ -103,7 +103,7 @@ class SDLWindow : Window { debug Log.d("Destroying SDL window"); if (_parent) { - long index = countUntil(_parent._children,this); + ptrdiff_t index = countUntil(_parent._children,this); if (index > -1 ) { _parent._children=_parent._children.remove(index); } From 14c99be69cfb5e0056d95050ec66b91afff78467 Mon Sep 17 00:00:00 2001 From: and3md Date: Sat, 29 Apr 2017 17:11:21 +0200 Subject: [PATCH 3/3] SDL: strongly improved modal behavior. Window state handled correctly. --- src/dlangui/platforms/sdl/sdlapp.d | 113 +++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 32 deletions(-) diff --git a/src/dlangui/platforms/sdl/sdlapp.d b/src/dlangui/platforms/sdl/sdlapp.d index 9ad1d143..72fed45d 100644 --- a/src/dlangui/platforms/sdl/sdlapp.d +++ b/src/dlangui/platforms/sdl/sdlapp.d @@ -123,7 +123,7 @@ class SDLWindow : Window { } - bool hasModalChild() { + private bool hasModalChild() { foreach (SDLWindow w;_children) { if (w.flags & WindowFlag.Modal) return true; @@ -134,17 +134,21 @@ class SDLWindow : Window { return false; } - void restoreModalChilds() { + + private void restoreModalChilds() { foreach (SDLWindow w;_children) { if (w.flags & WindowFlag.Modal) { - w.show(); + if (w._windowState == WindowState.maximized) + w.activateWindow(); + else + w.restoreWindow(true); } w.restoreModalChilds(); } } - void minimizeModalChilds() { + private void minimizeModalChilds() { foreach (SDLWindow w;_children) { if (w.flags & WindowFlag.Modal) { @@ -156,12 +160,10 @@ class SDLWindow : Window { } - void restoreParentWindows() { + private void restoreParentWindows() { SDLWindow[] tempWin; if (!_platform) return; - _platform._parentWindowRestoration = true; - scope(exit) {_platform._parentWindowRestoration = false;} SDLWindow w = this; @@ -174,10 +176,28 @@ class SDLWindow : Window { w = w._parent; } - for (size_t i = tempWin.length ; i-- > 0 ; ) { - tempWin[i].show(); + for (size_t i = tempWin.length ; i-- > 0 ; ) + tempWin[i].restoreWindow(true); + } + + private void minimizeParentWindows() { + SDLWindow[] tempWin; + if (!_platform) + return; + + SDLWindow w = this; + + while (true) { + if (w is null) + break; + + tempWin~=w; + + w = w._parent; } + for (size_t i = tempWin.length ; i-- > 0 ; ) + tempWin[i].minimizeWindow(); } /// post event to handle in UI thread (this method can be used from background thread) @@ -319,7 +339,7 @@ class SDLWindow : Window { } override void show() { - Log.d("SDLWindow.show()"); + Log.d("SDLWindow.show() - ", windowCaption); if (_mainWidget && !(_flags & WindowFlag.Resizable)) { _mainWidget.measure(SIZE_UNSPECIFIED, SIZE_UNSPECIFIED); SDL_SetWindowSize(_win, _mainWidget.measuredWidth, _mainWidget.measuredHeight); @@ -347,27 +367,35 @@ class SDLWindow : Window { return false; bool res = false; + bool stateChanged = false; // change state switch(newState) { case WindowState.maximized: - if (_windowState != WindowState.maximized) + if (_windowState != WindowState.maximized) { SDL_MaximizeWindow(_win); + stateChanged = true; + } res = true; break; case WindowState.minimized: - if (_windowState != WindowState.minimized) + if (_windowState != WindowState.minimized) { SDL_MinimizeWindow(_win); + stateChanged = true; + } res = true; break; case WindowState.hidden: - if (_windowState != WindowState.hidden) + if (_windowState != WindowState.hidden) { SDL_HideWindow(_win); + stateChanged = true; + } res = true; break; case WindowState.normal: if (_windowState != WindowState.normal) { SDL_RestoreWindow(_win); + stateChanged = true; } res = true; break; @@ -375,18 +403,23 @@ class SDLWindow : Window { break; } // change size and/or position + + bool windowRectChanged = false; + if (newWindowRect != RECT_VALUE_IS_NOT_SET && (newState == WindowState.normal || newState == WindowState.unspecified)) { // change position if (newWindowRect.top != int.min && newWindowRect.left != int.min) { SDL_SetWindowPosition(_win, newWindowRect.left, newWindowRect.top); res = true; + windowRectChanged = true; } // change size if (newWindowRect.bottom != int.min && newWindowRect.right != int.min) { SDL_SetWindowSize(_win, newWindowRect.right, newWindowRect.bottom); res = true; + windowRectChanged = true; } } @@ -395,6 +428,8 @@ class SDLWindow : Window { res = true; } + handleWindowStateChange(stateChanged ? newState : WindowState.unspecified, windowRectChanged ? newWindowRect : RECT_VALUE_IS_NOT_SET); + return res; } @@ -1147,9 +1182,9 @@ class SDLPlatform : Platform { // foreach(w; _windowMap) // w.redraw(); //} - - private bool _parentWindowRestoration = false; + private bool _windowsMinimized = false; + override int enterMessageLoop() { Log.i("entering message loop"); SDL_Event event; @@ -1212,55 +1247,69 @@ class SDLPlatform : Platform { } break; case SDL_WINDOWEVENT_SHOWN: - debug(DebugSDL) Log.d("SDL_WINDOWEVENT_SHOWN"); - if (w.hasModalChild()) + debug(DebugSDL) Log.d("SDL_WINDOWEVENT_SHOWN - ", w.windowCaption); + if (!_windowsMinimized && w.hasModalChild()) w.restoreModalChilds(); break; case SDL_WINDOWEVENT_HIDDEN: - debug(DebugSDL) Log.d("SDL_WINDOWEVENT_HIDDEN"); + debug(DebugSDL) Log.d("SDL_WINDOWEVENT_HIDDEN - ", w.windowCaption); break; case SDL_WINDOWEVENT_EXPOSED: - debug(DebugSDL) Log.d("SDL_WINDOWEVENT_EXPOSED"); - if (w.hasModalChild()) + debug(DebugSDL) Log.d("SDL_WINDOWEVENT_EXPOSED - ", w.windowCaption); + if (!_windowsMinimized && w.hasModalChild()) w.restoreModalChilds(); version(linux) { w.invalidate(); } break; case SDL_WINDOWEVENT_MOVED: - debug(DebugSDL) Log.d("SDL_WINDOWEVENT_MOVED"); - if (w.hasModalChild()) + debug(DebugSDL) Log.d("SDL_WINDOWEVENT_MOVED- ", w.windowCaption); + if (!_windowsMinimized && w.hasModalChild()) w.restoreModalChilds(); break; case SDL_WINDOWEVENT_MINIMIZED: - debug(DebugSDL) Log.d("SDL_WINDOWEVENT_MINIMIZED"); - if (w.hasModalChild()) + debug(DebugSDL) Log.d("SDL_WINDOWEVENT_MINIMIZED - ", w.windowCaption); + w.handleWindowStateChange(WindowState.minimized); + + if (!_windowsMinimized && w.hasModalChild()) w.minimizeModalChilds(); + if (!_windowsMinimized && w.flags & WindowFlag.Modal) + w.minimizeParentWindows(); + + _windowsMinimized = true; break; case SDL_WINDOWEVENT_MAXIMIZED: - debug(DebugSDL) Log.d("SDL_WINDOWEVENT_MAXIMIZED"); + debug(DebugSDL) Log.d("SDL_WINDOWEVENT_MAXIMIZED - ", w.windowCaption); + w.handleWindowStateChange(WindowState.maximized); + _windowsMinimized = false; break; case SDL_WINDOWEVENT_RESTORED: - debug(DebugSDL) Log.d("SDL_WINDOWEVENT_RESTORED"); - if (!_parentWindowRestoration && w.flags & WindowFlag.Modal) + debug(DebugSDL) Log.d("SDL_WINDOWEVENT_RESTORED - ", w.windowCaption); + _windowsMinimized = false; + if (w.flags & WindowFlag.Modal) { w.restoreParentWindows(); - if (!_parentWindowRestoration && w.hasModalChild()) + w.restoreWindow(true); + } + w.handleWindowStateChange(WindowState.normal); + if (w.hasModalChild()) w.restoreModalChilds(); version(linux) { //not sure if needed on Windows or OSX. Also need to check on FreeBSD w.invalidate(); } break; case SDL_WINDOWEVENT_ENTER: - debug(DebugSDL) Log.d("SDL_WINDOWEVENT_ENTER"); + debug(DebugSDL) Log.d("SDL_WINDOWEVENT_ENTER - ", w.windowCaption); break; case SDL_WINDOWEVENT_LEAVE: - debug(DebugSDL) Log.d("SDL_WINDOWEVENT_LEAVE"); + debug(DebugSDL) Log.d("SDL_WINDOWEVENT_LEAVE - ", w.windowCaption); break; case SDL_WINDOWEVENT_FOCUS_GAINED: - debug(DebugSDL) Log.d("SDL_WINDOWEVENT_FOCUS_GAINED"); + debug(DebugSDL) Log.d("SDL_WINDOWEVENT_FOCUS_GAINED - ", w.windowCaption); + if (!_windowsMinimized) + w.restoreModalChilds(); break; case SDL_WINDOWEVENT_FOCUS_LOST: - debug(DebugSDL) Log.d("SDL_WINDOWEVENT_FOCUS_LOST"); + debug(DebugSDL) Log.d("SDL_WINDOWEVENT_FOCUS_LOST - ", w.windowCaption); break; default: break;