2015-05-14 19:40:41 -05:00
// 27 april 2015
2016-04-23 10:22:46 -05:00
# include "uipriv_windows.hpp"
2015-05-14 19:40:41 -05:00
# define windowClass L"libui_uiWindowClass"
2015-08-30 18:32:05 -05:00
struct uiWindow {
uiWindowsControl c ;
2015-05-14 19:40:41 -05:00
HWND hwnd ;
HMENU menubar ;
2016-04-26 21:44:40 -05:00
uiControl * child ;
2015-05-14 19:40:41 -05:00
BOOL shownOnce ;
2016-04-26 21:44:40 -05:00
int visible ;
2015-05-14 19:40:41 -05:00
int ( * onClosing ) ( uiWindow * , void * ) ;
void * onClosingData ;
int margined ;
2015-09-02 15:02:06 -05:00
BOOL hasMenubar ;
2016-06-15 20:55:42 -05:00
void ( * onPositionChanged ) ( uiWindow * , void * ) ;
void * onPositionChangedData ;
2016-06-15 21:52:35 -05:00
BOOL changingPosition ; // to avoid triggering the above when programmatically doing this
void ( * onContentSizeChanged ) ( uiWindow * , void * ) ;
void * onContentSizeChangedData ;
BOOL changingSize ;
2016-06-16 09:30:44 -05:00
int fullscreen ;
WINDOWPLACEMENT fsPrevPlacement ;
2016-06-16 10:20:28 -05:00
int borderless ;
2015-05-14 19:40:41 -05:00
} ;
2016-04-26 23:54:22 -05:00
// from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
# define windowMargin 7
static void windowMargins ( uiWindow * w , int * mx , int * my )
{
uiWindowsSizing sizing ;
* mx = 0 ;
* my = 0 ;
if ( ! w - > margined )
return ;
uiWindowsGetSizing ( w - > hwnd , & sizing ) ;
* mx = windowMargin ;
* my = windowMargin ;
uiWindowsSizingDlgUnitsToPixels ( & sizing , mx , my ) ;
}
2016-04-26 21:44:40 -05:00
static void windowRelayout ( uiWindow * w )
{
int x , y , width , height ;
RECT r ;
int mx , my ;
2016-04-27 11:18:58 -05:00
HWND child ;
2015-08-30 18:32:05 -05:00
2016-04-26 21:44:40 -05:00
if ( w - > child = = NULL )
return ;
x = 0 ;
y = 0 ;
2016-04-28 15:59:26 -05:00
uiWindowsEnsureGetClientRect ( w - > hwnd , & r ) ;
2016-04-26 21:44:40 -05:00
width = r . right - r . left ;
height = r . bottom - r . top ;
2016-04-26 23:54:22 -05:00
windowMargins ( w , & mx , & my ) ;
x + = mx ;
y + = my ;
width - = 2 * mx ;
height - = 2 * my ;
2016-04-27 11:18:58 -05:00
child = ( HWND ) uiControlHandle ( w - > child ) ;
uiWindowsEnsureMoveWindowDuringResize ( child , x , y , width , height ) ;
2016-04-26 21:44:40 -05:00
}
2015-05-29 21:44:48 -05:00
2015-05-14 19:40:41 -05:00
static LRESULT CALLBACK windowWndProc ( HWND hwnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
2015-09-01 12:51:25 -05:00
LONG_PTR ww ;
2015-08-30 18:32:05 -05:00
uiWindow * w ;
2015-05-14 19:40:41 -05:00
CREATESTRUCTW * cs = ( CREATESTRUCTW * ) lParam ;
WINDOWPOS * wp = ( WINDOWPOS * ) lParam ;
2015-09-02 15:02:06 -05:00
MINMAXINFO * mmi = ( MINMAXINFO * ) lParam ;
2016-06-13 20:54:15 -05:00
int width , height ;
2015-05-18 08:52:37 -05:00
LRESULT lResult ;
2015-05-14 19:40:41 -05:00
2015-09-01 12:51:25 -05:00
ww = GetWindowLongPtrW ( hwnd , GWLP_USERDATA ) ;
if ( ww = = 0 ) {
2015-05-14 19:40:41 -05:00
if ( uMsg = = WM_CREATE )
SetWindowLongPtrW ( hwnd , GWLP_USERDATA , ( LONG_PTR ) ( cs - > lpCreateParams ) ) ;
// fall through to DefWindowProc() anyway
return DefWindowProcW ( hwnd , uMsg , wParam , lParam ) ;
}
2015-09-01 12:51:25 -05:00
w = uiWindow ( ( void * ) ww ) ;
2015-05-18 08:52:37 -05:00
if ( handleParentMessages ( hwnd , uMsg , wParam , lParam , & lResult ) ! = FALSE )
return lResult ;
2015-05-14 19:40:41 -05:00
switch ( uMsg ) {
case WM_COMMAND :
// not a menu
if ( lParam ! = 0 )
break ;
if ( HIWORD ( wParam ) ! = 0 )
break ;
runMenuEvent ( LOWORD ( wParam ) , uiWindow ( w ) ) ;
return 0 ;
case WM_WINDOWPOSCHANGED :
2016-06-15 20:55:42 -05:00
if ( ( wp - > flags & SWP_NOMOVE ) = = 0 )
if ( ! w - > changingPosition )
( * ( w - > onPositionChanged ) ) ( w , w - > onPositionChangedData ) ;
// and continue anyway
2015-05-14 19:40:41 -05:00
if ( ( wp - > flags & SWP_NOSIZE ) ! = 0 )
break ;
2016-06-15 21:52:35 -05:00
if ( w - > onContentSizeChanged ! = NULL ) // TODO figure out why this is happening too early
if ( ! w - > changingSize )
( * ( w - > onContentSizeChanged ) ) ( w , w - > onContentSizeChangedData ) ;
2016-04-26 21:44:40 -05:00
windowRelayout ( w ) ;
2015-05-14 19:40:41 -05:00
return 0 ;
2015-09-02 15:02:06 -05:00
case WM_GETMINMAXINFO :
// ensure the user cannot resize the window smaller than its minimum size
lResult = DefWindowProcW ( hwnd , uMsg , wParam , lParam ) ;
2016-04-26 21:44:40 -05:00
uiWindowsControlMinimumSize ( uiWindowsControl ( w ) , & width , & height ) ;
2015-09-02 15:02:06 -05:00
// width and height are in client coordinates; ptMinTrackSize is in window coordinates
clientSizeToWindowSize ( w - > hwnd , & width , & height , w - > hasMenubar ) ;
mmi - > ptMinTrackSize . x = width ;
mmi - > ptMinTrackSize . y = height ;
return lResult ;
2015-06-07 21:06:41 -05:00
case WM_PRINTCLIENT :
// we do no special painting; just erase the background
// don't worry about the return value; we let DefWindowProcW() handle this message
SendMessageW ( hwnd , WM_ERASEBKGND , wParam , lParam ) ;
return 0 ;
2015-05-14 19:40:41 -05:00
case WM_CLOSE :
2015-08-30 18:32:05 -05:00
if ( ( * ( w - > onClosing ) ) ( w , w - > onClosingData ) )
2015-05-14 19:40:41 -05:00
uiControlDestroy ( uiControl ( w ) ) ;
return 0 ; // we destroyed it already
}
return DefWindowProcW ( hwnd , uMsg , wParam , lParam ) ;
}
ATOM registerWindowClass ( HICON hDefaultIcon , HCURSOR hDefaultCursor )
{
WNDCLASSW wc ;
ZeroMemory ( & wc , sizeof ( WNDCLASSW ) ) ;
wc . lpszClassName = windowClass ;
wc . lpfnWndProc = windowWndProc ;
wc . hInstance = hInstance ;
wc . hIcon = hDefaultIcon ;
wc . hCursor = hDefaultCursor ;
wc . hbrBackground = ( HBRUSH ) ( COLOR_BTNFACE + 1 ) ;
return RegisterClassW ( & wc ) ;
}
void unregisterWindowClass ( void )
{
if ( UnregisterClassW ( windowClass , hInstance ) = = 0 )
2016-04-23 10:22:46 -05:00
logLastError ( L " error unregistering uiWindow window class " ) ;
2015-05-14 19:40:41 -05:00
}
static int defaultOnClosing ( uiWindow * w , void * data )
{
return 0 ;
}
2016-06-15 21:52:35 -05:00
static void defaultOnPositionContentSizeChanged ( uiWindow * w , void * data )
2016-06-15 20:55:42 -05:00
{
// do nothing
}
2016-05-15 18:22:15 -05:00
static std : : map < uiWindow * , bool > windows ;
2016-04-26 21:44:40 -05:00
static void uiWindowDestroy ( uiControl * c )
2015-05-14 19:40:41 -05:00
{
2016-04-26 21:44:40 -05:00
uiWindow * w = uiWindow ( c ) ;
2015-05-14 19:40:41 -05:00
// first hide ourselves
ShowWindow ( w - > hwnd , SW_HIDE ) ;
// now destroy the child
2016-04-26 21:44:40 -05:00
if ( w - > child ! = NULL ) {
uiControlSetParent ( w - > child , NULL ) ;
uiControlDestroy ( w - > child ) ;
}
2015-05-14 19:40:41 -05:00
// now free the menubar, if any
if ( w - > menubar ! = NULL )
freeMenubar ( w - > menubar ) ;
2016-04-26 21:44:40 -05:00
// and finally free ourselves
2016-05-15 18:22:15 -05:00
windows . erase ( w ) ;
2016-04-26 21:44:40 -05:00
uiWindowsEnsureDestroyWindow ( w - > hwnd ) ;
uiFreeControl ( uiControl ( w ) ) ;
2015-05-15 14:39:45 -05:00
}
2016-04-26 21:44:40 -05:00
uiWindowsControlDefaultHandle ( uiWindow )
2016-05-22 19:02:47 -05:00
uiControl * uiWindowParent ( uiControl * c )
{
return NULL ;
}
void uiWindowSetParent ( uiControl * c , uiControl * parent )
{
uiUserBugCannotSetParentOnToplevel ( " uiWindow " ) ;
}
2016-04-26 21:44:40 -05:00
static int uiWindowToplevel ( uiControl * c )
{
return 1 ;
}
// TODO initial state of windows is hidden; ensure this here and make it so on other platforms
static int uiWindowVisible ( uiControl * c )
2015-05-15 14:39:45 -05:00
{
2015-08-30 18:32:05 -05:00
uiWindow * w = uiWindow ( c ) ;
2015-05-15 14:39:45 -05:00
2016-04-26 21:44:40 -05:00
return w - > visible ;
}
static void uiWindowShow ( uiControl * c )
{
uiWindow * w = uiWindow ( c ) ;
w - > visible = 1 ;
2016-04-28 16:11:32 -05:00
// just in case the window's minimum size wasn't recalculated already
2015-09-02 15:26:54 -05:00
ensureMinimumWindowSize ( w ) ;
2015-05-15 14:39:45 -05:00
if ( w - > shownOnce ) {
ShowWindow ( w - > hwnd , SW_SHOW ) ;
return ;
}
w - > shownOnce = TRUE ;
2015-05-16 10:37:45 -05:00
// make sure the child is the correct size
2016-04-29 11:20:41 -05:00
uiWindowsControlMinimumSizeChanged ( uiWindowsControl ( w ) ) ;
2015-05-15 14:39:45 -05:00
ShowWindow ( w - > hwnd , nCmdShow ) ;
if ( UpdateWindow ( w - > hwnd ) = = 0 )
2016-04-23 10:22:46 -05:00
logLastError ( L " error calling UpdateWindow() after showing uiWindow for the first time " ) ;
2015-05-15 14:39:45 -05:00
}
2016-04-26 21:44:40 -05:00
static void uiWindowHide ( uiControl * c )
2015-06-03 16:57:04 -05:00
{
2015-08-30 18:32:05 -05:00
uiWindow * w = uiWindow ( c ) ;
2015-06-03 16:57:04 -05:00
2016-04-26 21:44:40 -05:00
w - > visible = 0 ;
ShowWindow ( w - > hwnd , SW_HIDE ) ;
2015-09-01 06:21:18 -05:00
}
2016-04-26 21:44:40 -05:00
// TODO we don't want the window to be disabled completely; that would prevent it from being moved! ...would it?
uiWindowsControlDefaultEnabled ( uiWindow )
uiWindowsControlDefaultEnable ( uiWindow )
uiWindowsControlDefaultDisable ( uiWindow )
// TODO we need to do something about undocumented fields in the OS control types
uiWindowsControlDefaultSyncEnableState ( uiWindow )
// TODO
uiWindowsControlDefaultSetParentHWND ( uiWindow )
2016-06-13 20:54:15 -05:00
static void uiWindowMinimumSize ( uiWindowsControl * c , int * width , int * height )
2015-09-01 06:21:18 -05:00
{
2015-09-01 12:51:25 -05:00
uiWindow * w = uiWindow ( c ) ;
2016-04-26 21:44:40 -05:00
int mx , my ;
2015-09-01 12:51:25 -05:00
* width = 0 ;
* height = 0 ;
if ( w - > child ! = NULL )
2016-04-26 21:44:40 -05:00
uiWindowsControlMinimumSize ( uiWindowsControl ( w - > child ) , width , height ) ;
2016-04-26 23:54:22 -05:00
windowMargins ( w , & mx , & my ) ;
* width + = 2 * mx ;
* height + = 2 * my ;
2015-06-03 16:57:04 -05:00
}
2015-05-15 14:39:45 -05:00
2016-04-28 16:11:32 -05:00
static void uiWindowMinimumSizeChanged ( uiWindowsControl * c )
2015-09-01 07:42:42 -05:00
{
uiWindow * w = uiWindow ( c ) ;
2016-04-29 16:08:31 -05:00
if ( uiWindowsControlTooSmall ( uiWindowsControl ( w ) ) ) {
2016-04-28 16:11:32 -05:00
// TODO figure out what to do with this function
// maybe split it into two so WM_GETMINMAXINFO can use it?
ensureMinimumWindowSize ( w ) ;
2016-04-26 23:54:22 -05:00
return ;
2016-04-28 16:11:32 -05:00
}
// otherwise we only need to re-layout everything
windowRelayout ( w ) ;
}
2016-04-29 16:08:31 -05:00
static void uiWindowLayoutRect ( uiWindowsControl * c , RECT * r )
2016-04-28 16:11:32 -05:00
{
uiWindow * w = uiWindow ( c ) ;
// the layout rect is the client rect in this case
uiWindowsEnsureGetClientRect ( w - > hwnd , r ) ;
2015-09-01 07:42:42 -05:00
}
2016-04-29 16:08:31 -05:00
uiWindowsControlDefaultAssignControlIDZOrder ( uiWindow )
2015-09-02 11:59:57 -05:00
2016-06-14 14:55:24 -05:00
static void uiWindowChildVisibilityChanged ( uiWindowsControl * c )
{
// TODO eliminate the redundancy
uiWindowsControlMinimumSizeChanged ( c ) ;
}
2015-08-30 18:32:05 -05:00
char * uiWindowTitle ( uiWindow * w )
2015-05-14 19:40:41 -05:00
{
2016-04-22 19:04:30 -05:00
return uiWindowsWindowText ( w - > hwnd ) ;
2015-05-14 19:40:41 -05:00
}
2015-08-30 18:32:05 -05:00
void uiWindowSetTitle ( uiWindow * w , const char * title )
2015-05-14 19:40:41 -05:00
{
2016-04-22 19:04:30 -05:00
uiWindowsSetWindowText ( w - > hwnd , title ) ;
2015-06-03 14:49:44 -05:00
// don't queue resize; the caption isn't part of what affects layout and sizing of the client area (it'll be ellipsized if too long)
2015-05-14 19:40:41 -05:00
}
2016-06-15 20:55:42 -05:00
void uiWindowPosition ( uiWindow * w , int * x , int * y )
{
RECT r ;
uiWindowsEnsureGetWindowRect ( w - > hwnd , & r ) ;
* x = r . left ;
* y = r . top ;
}
void uiWindowSetPosition ( uiWindow * w , int x , int y )
{
w - > changingPosition = TRUE ;
if ( SetWindowPos ( w - > hwnd , NULL , x , y , 0 , 0 , SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER ) = = 0 )
logLastError ( L " error moving window " ) ;
w - > changingPosition = FALSE ;
}
// this is used for both fullscreening and centering
// see also https://blogs.msdn.microsoft.com/oldnewthing/20100412-00/?p=14353 and https://blogs.msdn.microsoft.com/oldnewthing/20050505-04/?p=35703
static void windowMonitorRect ( HWND hwnd , RECT * r )
{
HMONITOR monitor ;
MONITORINFO mi ;
monitor = MonitorFromWindow ( hwnd , MONITOR_DEFAULTTOPRIMARY ) ;
ZeroMemory ( & mi , sizeof ( MONITORINFO ) ) ;
mi . cbSize = sizeof ( MONITORINFO ) ;
if ( GetMonitorInfoW ( monitor , & mi ) = = 0 ) {
logLastError ( L " error getting window monitor rect " ) ;
// default to SM_CXSCREEN x SM_CYSCREEN to be safe
r - > left = 0 ;
r - > top = 0 ;
r - > right = GetSystemMetrics ( SM_CXSCREEN ) ;
r - > bottom = GetSystemMetrics ( SM_CYSCREEN ) ;
return ;
}
* r = mi . rcMonitor ;
}
// TODO use the work rect instead?
void uiWindowCenter ( uiWindow * w )
{
RECT wr , mr ;
int x , y ;
LONG wwid , mwid ;
LONG wht , mht ;
uiWindowsEnsureGetWindowRect ( w - > hwnd , & wr ) ;
windowMonitorRect ( w - > hwnd , & mr ) ;
wwid = wr . right - wr . left ;
mwid = mr . right - mr . left ;
x = ( mwid - wwid ) / 2 ;
wht = wr . bottom - wr . top ;
mht = mr . bottom - mr . top ;
y = ( mht - wht ) / 2 ;
// y is now evenly divided, however https://msdn.microsoft.com/en-us/library/windows/desktop/dn742502(v=vs.85).aspx says that 45% should go above and 55% should go below
// so just move 5% of the way up
2016-06-15 22:00:26 -05:00
// TODO should this be on the work area?
// TODO is this calculation correct?
2016-06-15 20:55:42 -05:00
y - = y / 20 ;
uiWindowSetPosition ( w , x , y ) ;
}
2016-06-16 09:30:44 -05:00
void uiWindowOnPositionChanged ( uiWindow * w , void ( * f ) ( uiWindow * , void * ) , void * data )
{
w - > onPositionChanged = f ;
w - > onPositionChangedData = data ;
}
2016-06-15 21:52:35 -05:00
void uiWindowContentSize ( uiWindow * w , int * width , int * height )
{
RECT r ;
uiWindowsEnsureGetClientRect ( w - > hwnd , & r ) ;
* width = r . right - r . left ;
* height = r . bottom - r . top ;
}
// TODO should this disallow too small?
void uiWindowSetContentSize ( uiWindow * w , int width , int height )
{
w - > changingSize = TRUE ;
clientSizeToWindowSize ( w - > hwnd , & width , & height , w - > hasMenubar ) ;
if ( SetWindowPos ( w - > hwnd , NULL , 0 , 0 , width , height , SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER ) = = 0 )
logLastError ( L " error resizing window " ) ;
w - > changingSize = FALSE ;
}
2016-06-16 09:30:44 -05:00
int uiWindowFullscreen ( uiWindow * w )
2016-06-15 21:52:35 -05:00
{
2016-06-16 09:30:44 -05:00
return w - > fullscreen ;
2016-06-15 21:52:35 -05:00
}
2016-06-16 09:30:44 -05:00
void uiWindowSetFullscreen ( uiWindow * w , int fullscreen )
2016-06-15 20:55:42 -05:00
{
2016-06-16 09:30:44 -05:00
RECT r ;
if ( w - > fullscreen & & fullscreen )
return ;
if ( ! w - > fullscreen & & ! fullscreen )
return ;
w - > fullscreen = fullscreen ;
w - > changingSize = TRUE ;
if ( w - > fullscreen ) {
ZeroMemory ( & ( w - > fsPrevPlacement ) , sizeof ( WINDOWPLACEMENT ) ) ;
w - > fsPrevPlacement . length = sizeof ( WINDOWPLACEMENT ) ;
if ( GetWindowPlacement ( w - > hwnd , & ( w - > fsPrevPlacement ) ) = = 0 )
logLastError ( L " error getting old window placement " ) ;
windowMonitorRect ( w - > hwnd , & r ) ;
setStyle ( w - > hwnd , getStyle ( w - > hwnd ) & ~ WS_OVERLAPPEDWINDOW ) ;
if ( SetWindowPos ( w - > hwnd , HWND_TOP ,
r . left , r . top ,
r . right - r . left , r . bottom - r . top ,
SWP_FRAMECHANGED | SWP_NOOWNERZORDER ) = = 0 )
logLastError ( L " error making window fullscreen " ) ;
} else {
2016-06-16 10:20:28 -05:00
if ( ! w - > borderless ) // keep borderless until that is turned off
setStyle ( w - > hwnd , getStyle ( w - > hwnd ) | WS_OVERLAPPEDWINDOW ) ;
2016-06-16 09:30:44 -05:00
if ( SetWindowPlacement ( w - > hwnd , & ( w - > fsPrevPlacement ) ) = = 0 )
logLastError ( L " error leaving fullscreen " ) ;
if ( SetWindowPos ( w - > hwnd , NULL ,
0 , 0 , 0 , 0 ,
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER ) = = 0 )
logLastError ( L " error restoring window border after fullscreen " ) ;
}
w - > changingSize = FALSE ;
}
void uiWindowOnContentSizeChanged ( uiWindow * w , void ( * f ) ( uiWindow * , void * ) , void * data )
{
w - > onContentSizeChanged = f ;
w - > onContentSizeChangedData = data ;
2016-06-15 20:55:42 -05:00
}
2015-08-31 16:50:23 -05:00
void uiWindowOnClosing ( uiWindow * w , int ( * f ) ( uiWindow * , void * ) , void * data )
2015-05-14 19:40:41 -05:00
{
w - > onClosing = f ;
w - > onClosingData = data ;
}
2016-06-16 10:20:28 -05:00
int uiWindowBorderless ( uiWindow * w )
{
return w - > borderless ;
}
void uiWindowSetBorderless ( uiWindow * w , int borderless )
{
w - > borderless = borderless ;
if ( w - > borderless )
setStyle ( w - > hwnd , getStyle ( w - > hwnd ) & ~ WS_OVERLAPPEDWINDOW ) ;
else
if ( ! w - > fullscreen ) // keep borderless until leaving fullscreen
setStyle ( w - > hwnd , getStyle ( w - > hwnd ) | WS_OVERLAPPEDWINDOW ) ;
}
2015-08-30 18:32:05 -05:00
void uiWindowSetChild ( uiWindow * w , uiControl * child )
2015-05-14 19:40:41 -05:00
{
2015-09-02 08:18:49 -05:00
if ( w - > child ! = NULL ) {
2016-04-26 23:54:22 -05:00
uiControlSetParent ( w - > child , NULL ) ;
uiWindowsControlSetParentHWND ( uiWindowsControl ( w - > child ) , NULL ) ;
}
w - > child = child ;
if ( w - > child ! = NULL ) {
uiControlSetParent ( w - > child , uiControl ( w ) ) ;
uiWindowsControlSetParentHWND ( uiWindowsControl ( w - > child ) , w - > hwnd ) ;
2016-04-27 16:51:33 -05:00
uiWindowsControlAssignSoleControlIDZOrder ( uiWindowsControl ( w - > child ) ) ;
2016-04-26 23:54:22 -05:00
windowRelayout ( w ) ;
2015-09-02 08:18:49 -05:00
}
2015-05-14 19:40:41 -05:00
}
2015-08-30 18:32:05 -05:00
int uiWindowMargined ( uiWindow * w )
2015-05-14 19:40:41 -05:00
{
return w - > margined ;
}
2015-08-30 18:32:05 -05:00
void uiWindowSetMargined ( uiWindow * w , int margined )
2015-05-14 19:40:41 -05:00
{
w - > margined = margined ;
2016-04-26 23:54:22 -05:00
windowRelayout ( w ) ;
2015-05-17 20:15:39 -05:00
}
2015-05-14 19:40:41 -05:00
// see http://blogs.msdn.com/b/oldnewthing/archive/2003/09/11/54885.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2003/09/13/54917.aspx
2015-09-02 15:26:54 -05:00
// TODO use clientSizeToWindowSize()
2015-08-30 18:32:05 -05:00
static void setClientSize ( uiWindow * w , int width , int height , BOOL hasMenubar , DWORD style , DWORD exstyle )
2015-05-14 19:40:41 -05:00
{
RECT window ;
window . left = 0 ;
window . top = 0 ;
window . right = width ;
window . bottom = height ;
if ( AdjustWindowRectEx ( & window , style , hasMenubar , exstyle ) = = 0 )
2016-04-23 10:22:46 -05:00
logLastError ( L " error getting real window coordinates " ) ;
2015-05-14 19:40:41 -05:00
if ( hasMenubar ) {
RECT temp ;
temp = window ;
temp . bottom = 0x7FFF ; // infinite height
SendMessageW ( w - > hwnd , WM_NCCALCSIZE , ( WPARAM ) FALSE , ( LPARAM ) ( & temp ) ) ;
window . bottom + = temp . top ;
}
if ( SetWindowPos ( w - > hwnd , NULL , 0 , 0 , window . right - window . left , window . bottom - window . top , SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER ) = = 0 )
2016-04-23 10:22:46 -05:00
logLastError ( L " error resizing window " ) ;
2015-05-14 19:40:41 -05:00
}
uiWindow * uiNewWindow ( const char * title , int width , int height , int hasMenubar )
{
2015-08-30 18:32:05 -05:00
uiWindow * w ;
2015-05-14 19:40:41 -05:00
WCHAR * wtitle ;
BOOL hasMenubarBOOL ;
2016-04-26 23:54:22 -05:00
uiWindowsNewControl ( uiWindow , w ) ;
2015-05-14 19:40:41 -05:00
hasMenubarBOOL = FALSE ;
if ( hasMenubar )
hasMenubarBOOL = TRUE ;
2015-09-02 15:02:06 -05:00
w - > hasMenubar = hasMenubarBOOL ;
2015-05-14 19:40:41 -05:00
# define style WS_OVERLAPPEDWINDOW
# define exstyle 0
wtitle = toUTF16 ( title ) ;
w - > hwnd = CreateWindowExW ( exstyle ,
windowClass , wtitle ,
style ,
CW_USEDEFAULT , CW_USEDEFAULT ,
// use the raw width and height for now
// this will get CW_USEDEFAULT (hopefully) predicting well
// even if it doesn't, we're adjusting it later
width , height ,
NULL , NULL , hInstance , w ) ;
if ( w - > hwnd = = NULL )
2016-04-23 10:22:46 -05:00
logLastError ( L " error creating window " ) ;
2015-05-14 19:40:41 -05:00
uiFree ( wtitle ) ;
if ( hasMenubar ) {
w - > menubar = makeMenubar ( ) ;
if ( SetMenu ( w - > hwnd , w - > menubar ) = = 0 )
2016-04-23 10:22:46 -05:00
logLastError ( L " error giving menu to window " ) ;
2015-05-14 19:40:41 -05:00
}
// and use the proper size
setClientSize ( w , width , height , hasMenubarBOOL , style , exstyle ) ;
2015-09-01 06:21:18 -05:00
uiWindowOnClosing ( w , defaultOnClosing , NULL ) ;
2016-06-15 21:52:35 -05:00
uiWindowOnPositionChanged ( w , defaultOnPositionContentSizeChanged , NULL ) ;
uiWindowOnContentSizeChanged ( w , defaultOnPositionContentSizeChanged , NULL ) ;
2015-05-14 19:40:41 -05:00
2016-05-15 18:22:15 -05:00
windows [ w ] = true ;
2015-08-30 18:32:05 -05:00
return w ;
2015-05-14 19:40:41 -05:00
}
2015-09-02 15:26:54 -05:00
2016-04-23 14:46:39 -05:00
// this cannot queue a resize because it's called by the resize handler
2015-09-02 15:26:54 -05:00
void ensureMinimumWindowSize ( uiWindow * w )
{
2016-06-13 20:54:15 -05:00
int width , height ;
2015-09-02 15:26:54 -05:00
RECT r ;
2016-04-26 23:54:22 -05:00
uiWindowsControlMinimumSize ( uiWindowsControl ( w ) , & width , & height ) ;
2016-04-28 15:59:26 -05:00
uiWindowsEnsureGetClientRect ( w - > hwnd , & r ) ;
2015-09-02 15:26:54 -05:00
if ( width < ( r . right - r . left ) ) // preserve width if larger
width = r . right - r . left ;
if ( height < ( r . bottom - r . top ) ) // preserve height if larger
height = r . bottom - r . top ;
clientSizeToWindowSize ( w - > hwnd , & width , & height , w - > hasMenubar ) ;
if ( SetWindowPos ( w - > hwnd , NULL , 0 , 0 , width , height , SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER ) = = 0 )
2016-04-23 10:22:46 -05:00
logLastError ( L " error resizing window " ) ;
2015-09-02 15:26:54 -05:00
}
2016-05-15 18:22:15 -05:00
void disableAllWindowsExcept ( uiWindow * which )
{
for ( auto & w : windows ) {
if ( w . first = = which )
continue ;
EnableWindow ( w . first - > hwnd , FALSE ) ;
}
}
void enableAllWindowsExcept ( uiWindow * which )
{
for ( auto & w : windows ) {
if ( w . first = = which )
continue ;
2016-05-15 18:38:45 -05:00
if ( ! uiControlEnabled ( uiControl ( w . first ) ) )
2016-05-15 18:22:15 -05:00
continue ;
EnableWindow ( w . first - > hwnd , TRUE ) ;
}
}