diff --git a/src/dlangui/platforms/android/androidapp.d b/src/dlangui/platforms/android/androidapp.d index 20be9955..e462659a 100644 --- a/src/dlangui/platforms/android/androidapp.d +++ b/src/dlangui/platforms/android/androidapp.d @@ -33,6 +33,10 @@ class AndroidWindow : Window { } bool _visible; + override @property Window parentWindow() { + return null; + } + protected dstring _caption; /// returns window caption override @property dstring windowCaption() { diff --git a/src/dlangui/platforms/common/platform.d b/src/dlangui/platforms/common/platform.d index 02736566..a16d3b7c 100644 --- a/src/dlangui/platforms/common/platform.d +++ b/src/dlangui/platforms/common/platform.d @@ -76,6 +76,14 @@ enum WindowState : int { closed, } +/// Flags to set start window position on show +enum ShowPosition { + /// do nothing just show + dontCare, + /// window will be centered on parent window + parentWindowCenter +} + /// Dialog display modes - used to configure dialogs should be showed as a popup or window enum DialogDisplayMode : ulong { /// show all types of dialogs in windows @@ -277,6 +285,18 @@ class Window : CustomEventTarget { } } + protected ShowPosition _showPosition = ShowPosition.parentWindowCenter; + + ///returns current window show position (don't care or parent center) + @property ShowPosition showPosition() { + return _showPosition; + } + + /// sets window position after show (don't care or parent center) + @property void showPosition(ShowPosition newPosition) { + _showPosition = newPosition; + } + // Abstract methods : override in platform implementation /// show window @@ -291,7 +311,9 @@ class Window : CustomEventTarget { abstract void invalidate(); /// close window abstract void close(); - + /// returns parent window + abstract @property Window parentWindow(); + protected WindowState _windowState = WindowState.normal; /// returns current window state @property WindowState windowState() { @@ -310,11 +332,19 @@ class Window : CustomEventTarget { Signal!OnWindowStateHandler windowStateChanged; /// update and signal window state and/or size/positon changes - for using in platform inplementations protected void handleWindowStateChange(WindowState newState, Rect newWindowRect = RECT_VALUE_IS_NOT_SET) { - if (newState != WindowState.unspecified) + bool signalWindow = false; + if (newState != WindowState.unspecified && newState != _windowState) { _windowState = newState; - if (newWindowRect != RECT_VALUE_IS_NOT_SET) + //Log.d("Window ", windowCaption, " has new state - ", newState); + signalWindow = true; + } + if (newWindowRect != RECT_VALUE_IS_NOT_SET && newWindowRect != _windowRect) { _windowRect = newWindowRect; - if (windowStateChanged.assigned) + //Log.d("Window ", windowCaption, " rect changed - ", newWindowRect); + signalWindow = true; + } + + if (signalWindow && windowStateChanged.assigned) windowStateChanged(this, newState, newWindowRect); } @@ -340,6 +370,29 @@ class Window : CustomEventTarget { /// set window rectangle bool moveAndResizeWindow(Rect rc, bool activate = false) { return setWindowState(WindowState.unspecified, activate, rc); } + /// centers window on parent window, do nothing if there is no parent window + void centerOnParentWindow() { + if (parentWindow) { + Rect parentRect = parentWindow.windowRect(); + Point newPos; + newPos.x = parentRect.left + (parentRect.right - _windowRect.right) / 2; + newPos.y = parentRect.top + (parentRect.bottom - _windowRect.bottom) / 2; + moveWindow(newPos); + } + } + + ///adjust window position during show() + protected void adjustPositionDuringShow() { + final switch (_showPosition) { + case ShowPosition.dontCare: + return; + case ShowPosition.parentWindowCenter: { + centerOnParentWindow(); + break; + } + } + } + // things needed for WindowOrContentResizeMode.scrollWindow: /// vertical scrollbar control protected ScrollBar _vScrollBar = null; diff --git a/src/dlangui/platforms/console/consoleapp.d b/src/dlangui/platforms/console/consoleapp.d index 6fb4e14c..3e3d4d7f 100644 --- a/src/dlangui/platforms/console/consoleapp.d +++ b/src/dlangui/platforms/console/consoleapp.d @@ -52,6 +52,11 @@ class ConsoleWindow : Window { Log.d("ConsoleWindow.close()"); _platform.closeWindow(this); } + + override @property Window parentWindow() { + return _parent; + } + protected bool _visible; /// returns true if window is shown @property bool visible() { diff --git a/src/dlangui/platforms/sdl/sdlapp.d b/src/dlangui/platforms/sdl/sdlapp.d index 9e47a5c0..bb124a7c 100644 --- a/src/dlangui/platforms/sdl/sdlapp.d +++ b/src/dlangui/platforms/sdl/sdlapp.d @@ -352,11 +352,13 @@ class SDLWindow : Window { } if (_mainWidget) { _mainWidget.measure(SIZE_UNSPECIFIED, SIZE_UNSPECIFIED); - if (flags & WindowFlag.MeasureSize) { + if (flags & WindowFlag.MeasureSize) resizeWindow(Point(_mainWidget.measuredWidth, _mainWidget.measuredHeight)); - } - adjustWindowOrContentSize(_mainWidget.measuredWidth, _mainWidget.measuredHeight); + else + adjustWindowOrContentSize(_mainWidget.measuredWidth, _mainWidget.measuredHeight); } + + adjustPositionDuringShow(); SDL_ShowWindow(_win); if (_mainWidget) @@ -420,19 +422,22 @@ class SDLWindow : Window { } // change size and/or position + bool rectChanged = 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); + rectChanged = true; res = true; } // change size if (newWindowRect.bottom != int.min && newWindowRect.right != int.min) { SDL_SetWindowSize(_win, newWindowRect.right, newWindowRect.bottom); + rectChanged = true; res = true; } + } if (activate) { @@ -440,10 +445,25 @@ class SDLWindow : Window { res = true; } + //needed here to make _windowRect and _windowState valid before SDL_WINDOWEVENT_RESIZED/SDL_WINDOWEVENT_MOVED/SDL_WINDOWEVENT_MINIMIZED/SDL_WINDOWEVENT_MAXIMIZED etc handled + //example: change size by resizeWindow() and make some calculations using windowRect + if (rectChanged) { + handleWindowStateChange(newState, Rect(newWindowRect.left == int.min ? _windowRect.left : newWindowRect.left, + newWindowRect.top == int.min ? _windowRect.top : newWindowRect.top, newWindowRect.right == int.min ? _windowRect.right : newWindowRect.right, + newWindowRect.bottom == int.min ? _windowRect.bottom : newWindowRect.bottom)); + } + else + handleWindowStateChange(newState, RECT_VALUE_IS_NOT_SET); + + return res; } - + + override @property Window parentWindow() { + return _parent; + } + protected dstring _caption; override @property dstring windowCaption() { diff --git a/src/dlangui/platforms/windows/winapp.d b/src/dlangui/platforms/windows/winapp.d index d1d4983e..16a9f6c1 100644 --- a/src/dlangui/platforms/windows/winapp.d +++ b/src/dlangui/platforms/windows/winapp.d @@ -240,6 +240,7 @@ class Win32Window : Window { HWND _hwnd; dstring _caption; Win32ColorDrawBuf _drawbuf; + private Win32Window _w32parent; bool useOpengl; /// win32 only - return window handle @@ -248,8 +249,8 @@ class Win32Window : Window { } this(Win32Platform platform, dstring windowCaption, Window parent, uint flags, uint width = 0, uint height = 0) { - Win32Window w32parent = cast(Win32Window)parent; - HWND parenthwnd = w32parent ? w32parent._hwnd : null; + _w32parent = cast(Win32Window)parent; + HWND parenthwnd = _w32parent ? _w32parent._hwnd : null; _dx = width; _dy = height; if (!_dx) @@ -258,6 +259,7 @@ class Win32Window : Window { _dy = 400; _platform = platform; _caption = windowCaption; + _windowState = WindowState.hidden; _flags = flags; uint ws = WS_CLIPCHILDREN | WS_CLIPSIBLINGS; if (flags & WindowFlag.Resizable) @@ -285,6 +287,10 @@ class Win32Window : Window { useOpengl = sharedGLContext.init(hDC); } } + + RECT rect; + GetWindowRect(_hwnd, &rect); + handleWindowStateChange(WindowState.unspecified, Rect(rect.left, rect.top, _dx, _dy)); } static if (ENABLE_OPENGL) { @@ -436,9 +442,12 @@ class Win32Window : Window { _mainWidget.measure(SIZE_UNSPECIFIED, SIZE_UNSPECIFIED); if (flags & WindowFlag.MeasureSize) resizeWindow(Point(_mainWidget.measuredWidth, _mainWidget.measuredHeight)); - adjustWindowOrContentSize(_mainWidget.measuredWidth, _mainWidget.measuredHeight); + else + adjustWindowOrContentSize(_mainWidget.measuredWidth, _mainWidget.measuredHeight); } + adjustPositionDuringShow(); + ShowWindow(_hwnd, SW_SHOWNORMAL); if (_mainWidget) _mainWidget.setFocus(); @@ -446,6 +455,10 @@ class Win32Window : Window { //UpdateWindow(_hwnd); } + override @property Window parentWindow() { + return _w32parent; + } + override @property dstring windowCaption() { return _caption; } @@ -520,6 +533,7 @@ class Win32Window : Window { break; } // change size and/or position + bool rectChanged = false; if (newWindowRect != RECT_VALUE_IS_NOT_SET && (newState == WindowState.normal || newState == WindowState.unspecified)) { UINT flags = SWP_NOOWNERZORDER | SWP_NOZORDER; if (!activate) @@ -529,20 +543,32 @@ class Win32Window : Window { if (newWindowRect.bottom != int.min && newWindowRect.right != int.min) { // change size only SetWindowPos(_hwnd, NULL, 0, 0, newWindowRect.right + 2 * GetSystemMetrics(SM_CXDLGFRAME), newWindowRect.bottom + GetSystemMetrics(SM_CYCAPTION) + 2 * GetSystemMetrics(SM_CYDLGFRAME), flags | SWP_NOMOVE); - return true; + rectChanged = true; + res = true; } } else { if (newWindowRect.bottom != int.min && newWindowRect.right != int.min) { // change size and position SetWindowPos(_hwnd, NULL, newWindowRect.left, newWindowRect.top, newWindowRect.right + 2 * GetSystemMetrics(SM_CXDLGFRAME), newWindowRect.bottom + GetSystemMetrics(SM_CYCAPTION) + 2 * GetSystemMetrics(SM_CYDLGFRAME), flags); - return true; + rectChanged = true; + res = true; } else { // change position only SetWindowPos(_hwnd, NULL, newWindowRect.left, newWindowRect.top, 0, 0, flags | SWP_NOSIZE); - return true; + rectChanged = true; + res = true; } } } + + if (rectChanged) { + handleWindowStateChange(newState, Rect(newWindowRect.left == int.min ? _windowRect.left : newWindowRect.left, + newWindowRect.top == int.min ? _windowRect.top : newWindowRect.top, newWindowRect.right == int.min ? _windowRect.right : newWindowRect.right, + newWindowRect.bottom == int.min ? _windowRect.bottom : newWindowRect.bottom)); + } + else + handleWindowStateChange(newState, RECT_VALUE_IS_NOT_SET); + return res; } @@ -560,6 +586,10 @@ class Win32Window : Window { Log.d("Window.close()"); _platform.closeWindow(this); } + + override protected void handleWindowStateChange(WindowState newState, Rect newWindowRect = RECT_VALUE_IS_NOT_SET) { + super.handleWindowStateChange(newState, newWindowRect); + } HICON _icon; @@ -1295,12 +1325,19 @@ LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_WINDOWPOSCHANGED: { if (window !is null) { - WINDOWPOS * pos = cast(WINDOWPOS*)lParam; - Log.d("WM_WINDOWPOSCHANGED: ", *pos); - GetClientRect(hwnd, &rect); - if (pos.x > -30000) {// to ignore minimized state + + if (IsIconic(hwnd)) { + window.handleWindowStateChange(WindowState.minimized); + } + else { + WINDOWPOS * pos = cast(WINDOWPOS*)lParam; + //Log.d("WM_WINDOWPOSCHANGED: ", *pos); + + GetClientRect(hwnd, &rect); int dx = rect.right - rect.left; int dy = rect.bottom - rect.top; + window.handleWindowStateChange( IsZoomed(hwnd) ? WindowState.maximized : IsWindowVisible(hwnd) ? WindowState.normal : WindowState.hidden, + Rect(pos.x, pos.y, dx, dy)); if (window.width != dx || window.height != dy) { window.onResize(dx, dy); InvalidateRect(hwnd, null, FALSE); diff --git a/src/dlangui/platforms/x11/x11app.d b/src/dlangui/platforms/x11/x11app.d index 211df819..c24c6c83 100644 --- a/src/dlangui/platforms/x11/x11app.d +++ b/src/dlangui/platforms/x11/x11app.d @@ -512,6 +512,10 @@ class X11Window : DWindow { return result; } + override @property DWindow parentWindow() { + return _parent; + } + override @property dstring windowCaption() { return _caption; }