diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-02-13 09:47:41 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-02-13 09:47:41 +0200 |
commit | 5d912fc85519e3d0f387a7183711bb5baf521e8a (patch) | |
tree | 1e460a5d735c9b28716ef16a87d174049ede2572 /src/ui | |
parent | 51a74dc9c66b76dff795a9da3874602f3f0f0285 (diff) |
Windows: Improved custom frame behavior
Windows-key shortcuts and cursor edge snapping.
Still missing: window shadow and saving the snap mode.
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/window.c | 95 | ||||
-rw-r--r-- | src/ui/window.h | 1 |
2 files changed, 83 insertions, 13 deletions
diff --git a/src/ui/window.c b/src/ui/window.c index 37586aab..65386e14 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -93,6 +93,10 @@ static iBool handleRootCommands_(iWidget *root, const char *cmd) { | |||
93 | setTextColor_LabelWidget(findWidget_App("winbar.title"), uiTextStrong_ColorId); | 93 | setTextColor_LabelWidget(findWidget_App("winbar.title"), uiTextStrong_ColorId); |
94 | return iFalse; | 94 | return iFalse; |
95 | } | 95 | } |
96 | else if (equal_Command(cmd, "window.restore")) { | ||
97 | setSnap_Window(get_Window(), none_WindowSnap); | ||
98 | return iTrue; | ||
99 | } | ||
96 | else if (equal_Command(cmd, "window.minimize")) { | 100 | else if (equal_Command(cmd, "window.minimize")) { |
97 | SDL_MinimizeWindow(get_Window()->win); | 101 | SDL_MinimizeWindow(get_Window()->win); |
98 | return iTrue; | 102 | return iTrue; |
@@ -553,9 +557,8 @@ static void setupUserInterface_Window(iWindow *d) { | |||
553 | setFont_LabelWidget(appButton, uiContentBold_FontId); | 557 | setFont_LabelWidget(appButton, uiContentBold_FontId); |
554 | setId_Widget(addChildFlags_Widget(winBar, | 558 | setId_Widget(addChildFlags_Widget(winBar, |
555 | iClob(appTitle = new_LabelWidget("", NULL)), | 559 | iClob(appTitle = new_LabelWidget("", NULL)), |
556 | expand_WidgetFlag | /*alignLeft_WidgetFlag |*/ | 560 | expand_WidgetFlag | fixedHeight_WidgetFlag | |
557 | fixedHeight_WidgetFlag | frameless_WidgetFlag | | 561 | frameless_WidgetFlag | commandOnClick_WidgetFlag), |
558 | commandOnClick_WidgetFlag), | ||
559 | "winbar.title"); | 562 | "winbar.title"); |
560 | setTextColor_LabelWidget(appTitle, uiTextStrong_ColorId); | 563 | setTextColor_LabelWidget(appTitle, uiTextStrong_ColorId); |
561 | iLabelWidget *appMin, *appMax, *appClose; | 564 | iLabelWidget *appMin, *appMax, *appClose; |
@@ -570,6 +573,7 @@ static void setupUserInterface_Window(iWindow *d) { | |||
570 | winBar, | 573 | winBar, |
571 | iClob(appMax = newLargeIcon_LabelWidget("\u25a1", "window.maximize toggle:1")), | 574 | iClob(appMax = newLargeIcon_LabelWidget("\u25a1", "window.maximize toggle:1")), |
572 | frameless_WidgetFlag); | 575 | frameless_WidgetFlag); |
576 | setId_Widget(as_Widget(appMax), "winbar.max"); | ||
573 | addChildFlags_Widget(winBar, | 577 | addChildFlags_Widget(winBar, |
574 | iClob(appClose = newLargeIcon_LabelWidget("\u2a2f", "window.close")), | 578 | iClob(appClose = newLargeIcon_LabelWidget("\u2a2f", "window.close")), |
575 | frameless_WidgetFlag); | 579 | frameless_WidgetFlag); |
@@ -785,7 +789,7 @@ static void drawBlank_Window_(iWindow *d) { | |||
785 | static SDL_HitTestResult hitTest_Window_(SDL_Window *win, const SDL_Point *pos, void *data) { | 789 | static SDL_HitTestResult hitTest_Window_(SDL_Window *win, const SDL_Point *pos, void *data) { |
786 | iWindow *d = data; | 790 | iWindow *d = data; |
787 | iAssert(d->win == win); | 791 | iAssert(d->win == win); |
788 | if (SDL_GetWindowFlags(d->win) & SDL_WINDOW_MOUSE_CAPTURE) { | 792 | if (SDL_GetWindowFlags(d->win) & (SDL_WINDOW_MOUSE_CAPTURE | SDL_WINDOW_FULLSCREEN_DESKTOP)) { |
789 | return SDL_HITTEST_NORMAL; | 793 | return SDL_HITTEST_NORMAL; |
790 | } | 794 | } |
791 | int w, h; | 795 | int w, h; |
@@ -979,10 +983,21 @@ static iBool isNormalPlacement_Window_(const iWindow *d) { | |||
979 | static iBool unsnap_Window_(iWindow *d, const iInt2 *newPos) { | 983 | static iBool unsnap_Window_(iWindow *d, const iInt2 *newPos) { |
980 | #if defined (LAGRANGE_CUSTOM_FRAME) | 984 | #if defined (LAGRANGE_CUSTOM_FRAME) |
981 | const int snap = snap_Window(d); | 985 | const int snap = snap_Window(d); |
982 | if (snap == yMaximized_WindowSnap && | 986 | if (snap == yMaximized_WindowSnap || snap == left_WindowSnap || snap == right_WindowSnap) { |
983 | (!newPos || (d->place.lastHit == SDL_HITTEST_RESIZE_LEFT || | 987 | if (!newPos || (d->place.lastHit == SDL_HITTEST_RESIZE_LEFT || |
984 | d->place.lastHit == SDL_HITTEST_RESIZE_RIGHT))) { | 988 | d->place.lastHit == SDL_HITTEST_RESIZE_RIGHT)) { |
985 | return iFalse; | 989 | return iFalse; |
990 | } | ||
991 | if (newPos) { | ||
992 | SDL_Rect usable; | ||
993 | SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(d->win), &usable); | ||
994 | /* Snap to top. */ | ||
995 | if (snap == yMaximized_WindowSnap && | ||
996 | iAbs(newPos->y - usable.y) < lineHeight_Text(uiContent_FontId) * 2) { | ||
997 | setSnap_Window(d, redo_WindowSnap | yMaximized_WindowSnap); | ||
998 | return iFalse; | ||
999 | } | ||
1000 | } | ||
986 | } | 1001 | } |
987 | if (snap && snap != fullscreen_WindowSnap) { | 1002 | if (snap && snap != fullscreen_WindowSnap) { |
988 | if (snap_Window(d) == yMaximized_WindowSnap && newPos) { | 1003 | if (snap_Window(d) == yMaximized_WindowSnap && newPos) { |
@@ -1027,6 +1042,33 @@ static iBool handleWindowEvent_Window_(iWindow *d, const SDL_WindowEvent *ev) { | |||
1027 | d->isMinimized = iTrue; | 1042 | d->isMinimized = iTrue; |
1028 | return iFalse; | 1043 | return iFalse; |
1029 | } | 1044 | } |
1045 | #if defined (LAGRANGE_CUSTOM_FRAME) | ||
1046 | /* Set the snap position depending on where the mouse cursor is. */ { | ||
1047 | SDL_Rect usable; | ||
1048 | iInt2 mouse = cursor_Win32(); /* SDL is unaware of the current cursor pos */ | ||
1049 | SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(d->win), &usable); | ||
1050 | const iBool isTop = iAbs(mouse.y - usable.y) < gap_UI * 20; | ||
1051 | const iBool isBottom = iAbs(usable.y + usable.h - mouse.y) < gap_UI * 20; | ||
1052 | if (iAbs(mouse.x - usable.x) < gap_UI) { | ||
1053 | setSnap_Window(d, | ||
1054 | redo_WindowSnap | left_WindowSnap | | ||
1055 | (isTop ? topBit_WindowSnap : 0) | | ||
1056 | (isBottom ? bottomBit_WindowSnap : 0)); | ||
1057 | return iTrue; | ||
1058 | } | ||
1059 | if (iAbs(mouse.x - usable.x - usable.w) < gap_UI) { | ||
1060 | setSnap_Window(d, | ||
1061 | redo_WindowSnap | right_WindowSnap | | ||
1062 | (isTop ? topBit_WindowSnap : 0) | | ||
1063 | (isBottom ? bottomBit_WindowSnap : 0)); | ||
1064 | return iTrue; | ||
1065 | } | ||
1066 | if (iAbs(mouse.y - usable.y) < 2) { | ||
1067 | setSnap_Window(d, redo_WindowSnap | maximized_WindowSnap); | ||
1068 | return iTrue; | ||
1069 | } | ||
1070 | } | ||
1071 | #endif | ||
1030 | //printf("MOVED: %d, %d\n", ev->data1, ev->data2); fflush(stdout); | 1072 | //printf("MOVED: %d, %d\n", ev->data1, ev->data2); fflush(stdout); |
1031 | if (unsnap_Window_(d, &newPos)) { | 1073 | if (unsnap_Window_(d, &newPos)) { |
1032 | return iTrue; | 1074 | return iTrue; |
@@ -1138,6 +1180,21 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { | |||
1138 | As a workaround, ignore these events. */ | 1180 | As a workaround, ignore these events. */ |
1139 | return iTrue; /* won't go to bindings, either */ | 1181 | return iTrue; /* won't go to bindings, either */ |
1140 | } | 1182 | } |
1183 | #if 0 //defined (LAGRANGE_CUSTOM_FRAME) | ||
1184 | if (event.type == SDL_KEYDOWN) { | ||
1185 | if (keyMods_Sym(event.key.keysym.mod) == KMOD_PRIMARY) { | ||
1186 | printf("got! %x\n", event.key.keysym.sym); fflush(stdout); | ||
1187 | /* Emulate window snapping keys. */ | ||
1188 | switch (event.key.keysym.sym) { | ||
1189 | default: | ||
1190 | break; | ||
1191 | case SDLK_LEFT: | ||
1192 | setSnap_Window(d, left_WindowSnap); | ||
1193 | return iTrue; | ||
1194 | } | ||
1195 | } | ||
1196 | } | ||
1197 | #endif | ||
1141 | /* Map mouse pointer coordinate to our coordinate system. */ | 1198 | /* Map mouse pointer coordinate to our coordinate system. */ |
1142 | if (event.type == SDL_MOUSEMOTION) { | 1199 | if (event.type == SDL_MOUSEMOTION) { |
1143 | setCursor_Window(d, SDL_SYSTEM_CURSOR_ARROW); /* default cursor */ | 1200 | setCursor_Window(d, SDL_SYSTEM_CURSOR_ARROW); /* default cursor */ |
@@ -1322,13 +1379,14 @@ void setSnap_Window(iWindow *d, int snapMode) { | |||
1322 | if (d->place.snap == snapMode) { | 1379 | if (d->place.snap == snapMode) { |
1323 | return; | 1380 | return; |
1324 | } | 1381 | } |
1382 | const int snapDist = gap_UI * 4; | ||
1325 | iRect newRect = zero_Rect(); | 1383 | iRect newRect = zero_Rect(); |
1326 | SDL_Rect usable; | 1384 | SDL_Rect usable; |
1327 | SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(d->win), &usable); | 1385 | SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(d->win), &usable); |
1328 | if (d->place.snap == fullscreen_WindowSnap) { | 1386 | if (d->place.snap == fullscreen_WindowSnap) { |
1329 | SDL_SetWindowFullscreen(d->win, 0); | 1387 | SDL_SetWindowFullscreen(d->win, 0); |
1330 | } | 1388 | } |
1331 | d->place.snap = snapMode; | 1389 | d->place.snap = snapMode & ~redo_WindowSnap; |
1332 | switch (snapMode & mask_WindowSnap) { | 1390 | switch (snapMode & mask_WindowSnap) { |
1333 | case none_WindowSnap: | 1391 | case none_WindowSnap: |
1334 | newRect = d->place.normalRect; | 1392 | newRect = d->place.normalRect; |
@@ -1337,7 +1395,8 @@ void setSnap_Window(iWindow *d, int snapMode) { | |||
1337 | newRect = init_Rect(usable.x, usable.y, usable.w / 2, usable.h); | 1395 | newRect = init_Rect(usable.x, usable.y, usable.w / 2, usable.h); |
1338 | break; | 1396 | break; |
1339 | case right_WindowSnap: | 1397 | case right_WindowSnap: |
1340 | newRect = init_Rect(usable.x, usable.y + usable.w / 2, usable.w / 2, usable.h); | 1398 | newRect = |
1399 | init_Rect(usable.x + usable.w / 2, usable.y, usable.w - usable.w / 2, usable.h); | ||
1341 | break; | 1400 | break; |
1342 | case maximized_WindowSnap: | 1401 | case maximized_WindowSnap: |
1343 | newRect = init_Rect(usable.x, usable.y, usable.w, usable.h); | 1402 | newRect = init_Rect(usable.x, usable.y, usable.w, usable.h); |
@@ -1345,8 +1404,15 @@ void setSnap_Window(iWindow *d, int snapMode) { | |||
1345 | case yMaximized_WindowSnap: | 1404 | case yMaximized_WindowSnap: |
1346 | newRect.pos.y = 0; | 1405 | newRect.pos.y = 0; |
1347 | newRect.size.y = usable.h; | 1406 | newRect.size.y = usable.h; |
1348 | SDL_GetWindowPosition(d->win, &newRect.pos.x, NULL); | ||
1349 | SDL_GetWindowSize(d->win, &newRect.size.x, NULL); | 1407 | SDL_GetWindowSize(d->win, &newRect.size.x, NULL); |
1408 | SDL_GetWindowPosition(d->win, &newRect.pos.x, NULL); | ||
1409 | /* Snap the window to left/right edges, if close by. */ | ||
1410 | if (iAbs(right_Rect(newRect) - (usable.x + usable.w)) < snapDist) { | ||
1411 | newRect.pos.x = usable.x + usable.w - width_Rect(newRect); | ||
1412 | } | ||
1413 | if (iAbs(newRect.pos.x - usable.x) < snapDist) { | ||
1414 | newRect.pos.x = usable.x; | ||
1415 | } | ||
1350 | break; | 1416 | break; |
1351 | case fullscreen_WindowSnap: | 1417 | case fullscreen_WindowSnap: |
1352 | SDL_SetWindowFullscreen(d->win, SDL_WINDOW_FULLSCREEN_DESKTOP); | 1418 | SDL_SetWindowFullscreen(d->win, SDL_WINDOW_FULLSCREEN_DESKTOP); |
@@ -1358,10 +1424,13 @@ void setSnap_Window(iWindow *d, int snapMode) { | |||
1358 | if (snapMode & bottomBit_WindowSnap) { | 1424 | if (snapMode & bottomBit_WindowSnap) { |
1359 | newRect.pos.y += newRect.size.y; | 1425 | newRect.pos.y += newRect.size.y; |
1360 | } | 1426 | } |
1361 | /* Show and hide the title bar. */ | 1427 | /* Update window controls. */ |
1362 | iWidget *winBar = findWidget_App("winbar"); | 1428 | iWidget *winBar = findWidget_App("winbar"); |
1429 | updateTextCStr_LabelWidget(findChild_Widget(winBar, "winbar.max"), | ||
1430 | d->place.snap == maximized_WindowSnap ? "\u25a2" : "\u25a1"); | ||
1431 | /* Show and hide the title bar. */ | ||
1363 | const iBool wasVisible = isVisible_Widget(winBar); | 1432 | const iBool wasVisible = isVisible_Widget(winBar); |
1364 | setFlags_Widget(winBar, hidden_WidgetFlag, snapMode == fullscreen_WindowSnap); | 1433 | setFlags_Widget(winBar, hidden_WidgetFlag, d->place.snap == fullscreen_WindowSnap); |
1365 | if (newRect.size.x) { | 1434 | if (newRect.size.x) { |
1366 | SDL_SetWindowPosition(d->win, newRect.pos.x, newRect.pos.y); | 1435 | SDL_SetWindowPosition(d->win, newRect.pos.x, newRect.pos.y); |
1367 | SDL_SetWindowSize(d->win, newRect.size.x, newRect.size.y); | 1436 | SDL_SetWindowSize(d->win, newRect.size.x, newRect.size.y); |
diff --git a/src/ui/window.h b/src/ui/window.h index ddb03847..6063df88 100644 --- a/src/ui/window.h +++ b/src/ui/window.h | |||
@@ -42,6 +42,7 @@ enum iWindowSnap { | |||
42 | mask_WindowSnap = 0xff, | 42 | mask_WindowSnap = 0xff, |
43 | topBit_WindowSnap = iBit(9), | 43 | topBit_WindowSnap = iBit(9), |
44 | bottomBit_WindowSnap = iBit(10), | 44 | bottomBit_WindowSnap = iBit(10), |
45 | redo_WindowSnap = iBit(11), | ||
45 | }; | 46 | }; |
46 | 47 | ||
47 | iDeclareType(WindowPlacement) | 48 | iDeclareType(WindowPlacement) |