summaryrefslogtreecommitdiff
path: root/src/ui/widget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/widget.c')
-rw-r--r--src/ui/widget.c107
1 files changed, 56 insertions, 51 deletions
diff --git a/src/ui/widget.c b/src/ui/widget.c
index 5d924b57..6d6bc202 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -99,7 +99,7 @@ static void aboutToBeDestroyed_Widget_(iWidget *d) {
99 removeOne_PtrArray(onTop_Root(d->root), d); 99 removeOne_PtrArray(onTop_Root(d->root), d);
100 } 100 }
101 if (isHover_Widget(d)) { 101 if (isHover_Widget(d)) {
102 d->root->hover = NULL; 102 get_Window()->hover = NULL;
103 } 103 }
104 iForEach(ObjectList, i, d->children) { 104 iForEach(ObjectList, i, d->children) {
105 aboutToBeDestroyed_Widget_(as_Widget(i.object)); 105 aboutToBeDestroyed_Widget_(as_Widget(i.object));
@@ -675,16 +675,30 @@ static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) {
675 675
676iRect bounds_Widget(const iWidget *d) { 676iRect bounds_Widget(const iWidget *d) {
677 iRect bounds = d->rect; 677 iRect bounds = d->rect;
678 applyVisualOffset_Widget_(d, &bounds.pos); 678 bounds.pos = localToWindow_Widget(d, bounds.pos);
679 return bounds;
680}
681
682iInt2 localToWindow_Widget(const iWidget *d, iInt2 localCoord) {
683 iInt2 window = localCoord;
684 applyVisualOffset_Widget_(d, &window);
679 for (const iWidget *w = d->parent; w; w = w->parent) { 685 for (const iWidget *w = d->parent; w; w = w->parent) {
680 iInt2 pos = w->rect.pos; 686 iInt2 pos = w->rect.pos;
681 applyVisualOffset_Widget_(w, &pos); 687 applyVisualOffset_Widget_(w, &pos);
682 addv_I2(&bounds.pos, pos); 688 addv_I2(&window, pos);
683 } 689 }
684#if defined (iPlatformMobile) 690#if defined (iPlatformMobile)
685 bounds.pos.y += value_Anim(&get_Window()->rootOffset); 691 window.y += value_Anim(&get_Window()->rootOffset);
686#endif 692#endif
687 return bounds; 693 return window;
694}
695
696iInt2 windowToLocal_Widget(const iWidget *d, iInt2 windowCoord) {
697 iInt2 local = windowCoord;
698 for (const iWidget *w = d->parent; w; w = w->parent) {
699 subv_I2(&local, w->rect.pos);
700 }
701 return local;
688} 702}
689 703
690iRect boundsWithoutVisualOffset_Widget(const iWidget *d) { 704iRect boundsWithoutVisualOffset_Widget(const iWidget *d) {
@@ -695,25 +709,32 @@ iRect boundsWithoutVisualOffset_Widget(const iWidget *d) {
695 return bounds; 709 return bounds;
696} 710}
697 711
698iInt2 localCoord_Widget(const iWidget *d, iInt2 coord) { 712iInt2 innerToWindow_Widget(const iWidget *d, iInt2 innerCoord) {
713 for (const iWidget *w = d; w; w = w->parent) {
714 addv_I2(&innerCoord, w->rect.pos);
715 }
716 return innerCoord;
717}
718
719iInt2 windowToInner_Widget(const iWidget *d, iInt2 windowCoord) {
699 for (const iWidget *w = d; w; w = w->parent) { 720 for (const iWidget *w = d; w; w = w->parent) {
700 subv_I2(&coord, w->rect.pos); 721 subv_I2(&windowCoord, w->rect.pos);
701 } 722 }
702 return coord; 723 return windowCoord;
703} 724}
704 725
705iBool contains_Widget(const iWidget *d, iInt2 coord) { 726iBool contains_Widget(const iWidget *d, iInt2 windowCoord) {
706 return containsExpanded_Widget(d, coord, 0); 727 return containsExpanded_Widget(d, windowCoord, 0);
707} 728}
708 729
709iBool containsExpanded_Widget(const iWidget *d, iInt2 coord, int expand) { 730iBool containsExpanded_Widget(const iWidget *d, iInt2 windowCoord, int expand) {
710 const iRect bounds = { 731 const iRect bounds = {
711 zero_I2(), 732 zero_I2(),
712 addY_I2(d->rect.size, 733 addY_I2(d->rect.size,
713 d->flags & drawBackgroundToBottom_WidgetFlag ? size_Root(d->root).y : 0) 734 d->flags & drawBackgroundToBottom_WidgetFlag ? size_Root(d->root).y : 0)
714 }; 735 };
715 return contains_Rect(expand ? expanded_Rect(bounds, init1_I2(expand)) : bounds, 736 return contains_Rect(expand ? expanded_Rect(bounds, init1_I2(expand)) : bounds,
716 localCoord_Widget(d, coord)); 737 windowToInner_Widget(d, windowCoord));
717} 738}
718 739
719iLocalDef iBool isKeyboardEvent_(const SDL_Event *ev) { 740iLocalDef iBool isKeyboardEvent_(const SDL_Event *ev) {
@@ -738,20 +759,15 @@ static iBool filterEvent_Widget_(const iWidget *d, const SDL_Event *ev) {
738} 759}
739 760
740void unhover_Widget(void) { 761void unhover_Widget(void) {
741 /* TODO: Which root? */ 762 get_Window()->hover = NULL;
742 get_Root()->hover = NULL;
743} 763}
744 764
745iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) { 765iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) {
746 iAssert(d->root == get_Root()); 766 iAssert(d->root == get_Root());
747 if (!d->parent) { 767 if (!d->parent) {
748 if (ev->type == SDL_MOUSEMOTION) { 768 if (get_Window()->focus && get_Window()->focus->root == d->root && isKeyboardEvent_(ev)) {
749 /* Hover widget may change. */
750 setHover_Widget(NULL);
751 }
752 if (d->root->focus && isKeyboardEvent_(ev)) {
753 /* Root dispatches keyboard events directly to the focused widget. */ 769 /* Root dispatches keyboard events directly to the focused widget. */
754 if (dispatchEvent_Widget(d->root->focus, ev)) { 770 if (dispatchEvent_Widget(get_Window()->focus, ev)) {
755 return iTrue; 771 return iTrue;
756 } 772 }
757 } 773 }
@@ -780,7 +796,7 @@ iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) {
780 } 796 }
781 } 797 }
782 else if (ev->type == SDL_MOUSEMOTION && 798 else if (ev->type == SDL_MOUSEMOTION &&
783 (!d->root->hover || hasParent_Widget(d, d->root->hover)) && 799 (!get_Window()->hover || hasParent_Widget(d, get_Window()->hover)) &&
784 flags_Widget(d) & hover_WidgetFlag && ~flags_Widget(d) & hidden_WidgetFlag && 800 flags_Widget(d) & hover_WidgetFlag && ~flags_Widget(d) & hidden_WidgetFlag &&
785 ~flags_Widget(d) & disabled_WidgetFlag) { 801 ~flags_Widget(d) & disabled_WidgetFlag) {
786 if (contains_Widget(d, init_I2(ev->motion.x, ev->motion.y))) { 802 if (contains_Widget(d, init_I2(ev->motion.x, ev->motion.y))) {
@@ -798,7 +814,8 @@ iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) {
798 handle the events first. */ 814 handle the events first. */
799 iReverseForEach(ObjectList, i, d->children) { 815 iReverseForEach(ObjectList, i, d->children) {
800 iWidget *child = as_Widget(i.object); 816 iWidget *child = as_Widget(i.object);
801 if (child == d->root->focus && isKeyboardEvent_(ev)) { 817 iAssert(child->root == d->root);
818 if (child == get_Window()->focus && isKeyboardEvent_(ev)) {
802 continue; /* Already dispatched. */ 819 continue; /* Already dispatched. */
803 } 820 }
804 if (isVisible_Widget(child) && child->flags & keepOnTop_WidgetFlag) { 821 if (isVisible_Widget(child) && child->flags & keepOnTop_WidgetFlag) {
@@ -870,7 +887,7 @@ static iBool scrollOverflow_Widget_(iWidget *d, int delta) {
870// else { 887// else {
871// bounds.pos.y = iMax(bounds.pos.y, ); 888// bounds.pos.y = iMax(bounds.pos.y, );
872// } 889// }
873 const iInt2 newPos = localCoord_Widget(d->parent, bounds.pos); 890 const iInt2 newPos = windowToInner_Widget(d->parent, bounds.pos);
874 if (!isEqual_I2(newPos, d->rect.pos)) { 891 if (!isEqual_I2(newPos, d->rect.pos)) {
875 d->rect.pos = newPos; 892 d->rect.pos = newPos;
876 refresh_Widget(d); 893 refresh_Widget(d);
@@ -1087,6 +1104,7 @@ iAny *addChildPosFlags_Widget(iWidget *d, iAnyObject *child, enum iWidgetAddPos
1087 iAssert(child); 1104 iAssert(child);
1088 iAssert(d != child); 1105 iAssert(d != child);
1089 iWidget *widget = as_Widget(child); 1106 iWidget *widget = as_Widget(child);
1107 iAssert(widget->root == d->root);
1090 iAssert(!widget->parent); 1108 iAssert(!widget->parent);
1091 if (!d->children) { 1109 if (!d->children) {
1092 d->children = new_ObjectList(); 1110 d->children = new_ObjectList();
@@ -1268,12 +1286,12 @@ iBool isDisabled_Widget(const iAnyObject *d) {
1268 1286
1269iBool isFocused_Widget(const iAnyObject *d) { 1287iBool isFocused_Widget(const iAnyObject *d) {
1270 iAssert(isInstance_Object(d, &Class_Widget)); 1288 iAssert(isInstance_Object(d, &Class_Widget));
1271 return ((const iWidget *) d)->root->focus == d; 1289 return get_Window()->focus == d;
1272} 1290}
1273 1291
1274iBool isHover_Widget(const iAnyObject *d) { 1292iBool isHover_Widget(const iAnyObject *d) {
1275 iAssert(isInstance_Object(d, &Class_Widget)); 1293 iAssert(isInstance_Object(d, &Class_Widget));
1276 return ((const iWidget *) d)->root->hover == d; 1294 return get_Window()->hover == d;
1277} 1295}
1278 1296
1279iBool isSelected_Widget(const iAnyObject *d) { 1297iBool isSelected_Widget(const iAnyObject *d) {
@@ -1319,15 +1337,14 @@ iBool isAffectedByVisualOffset_Widget(const iWidget *d) {
1319} 1337}
1320 1338
1321void setFocus_Widget(iWidget *d) { 1339void setFocus_Widget(iWidget *d) {
1322 iRoot *root = d ? d->root : get_Root(); 1340 iWindow *win = get_Window();
1323 if (root->focus != d) { 1341 if (win->focus != d) {
1324 if (root->focus) { 1342 if (win->focus) {
1325 iAssert(!contains_PtrSet(root->pendingDestruction, root->focus)); 1343 iAssert(!contains_PtrSet(win->focus->root->pendingDestruction, win->focus));
1326 postCommand_Widget(root->focus, "focus.lost"); 1344 postCommand_Widget(win->focus, "focus.lost");
1327 } 1345 }
1328 root->focus = d; 1346 win->focus = d;
1329 if (d) { 1347 if (d) {
1330 iAssert(root == d->root);
1331 iAssert(flags_Widget(d) & focusable_WidgetFlag); 1348 iAssert(flags_Widget(d) & focusable_WidgetFlag);
1332 postCommand_Widget(d, "focus.gained"); 1349 postCommand_Widget(d, "focus.gained");
1333 } 1350 }
@@ -1335,20 +1352,15 @@ void setFocus_Widget(iWidget *d) {
1335} 1352}
1336 1353
1337iWidget *focus_Widget(void) { 1354iWidget *focus_Widget(void) {
1338 return get_Root()->focus; 1355 return get_Window()->focus;
1339} 1356}
1340 1357
1341void setHover_Widget(iWidget *d) { 1358void setHover_Widget(iWidget *d) {
1342 if (d) { 1359 get_Window()->hover = d;
1343 d->root->hover = d;
1344 }
1345 else {
1346 get_Root()->hover = NULL;
1347 }
1348} 1360}
1349 1361
1350iWidget *hover_Widget(void) { 1362iWidget *hover_Widget(void) {
1351 return get_Root()->hover; 1363 return get_Window()->hover;
1352} 1364}
1353 1365
1354static const iWidget *findFocusable_Widget_(const iWidget *d, const iWidget *startFrom, 1366static const iWidget *findFocusable_Widget_(const iWidget *d, const iWidget *startFrom,
@@ -1404,21 +1416,14 @@ iAny *findFocusable_Widget(const iWidget *startFrom, enum iWidgetFocusDir focusD
1404} 1416}
1405 1417
1406void setMouseGrab_Widget(iWidget *d) { 1418void setMouseGrab_Widget(iWidget *d) {
1407 iRoot *root = d ? d->root : get_Root(); 1419 if (get_Window()->mouseGrab != d) {
1408 if (root->mouseGrab != d) { 1420 get_Window()->mouseGrab = d;
1409 root->mouseGrab = d;
1410 SDL_CaptureMouse(d != NULL); 1421 SDL_CaptureMouse(d != NULL);
1411 } 1422 }
1412} 1423}
1413 1424
1414iWidget *mouseGrab_Widget(void) { 1425iWidget *mouseGrab_Widget(void) {
1415 iWindow *win = get_Window(); 1426 return get_Window()->mouseGrab;
1416 iForIndices(i, win->roots) {
1417 if (win->roots[i] && win->roots[i]->mouseGrab) {
1418 return win->roots[i]->mouseGrab;
1419 }
1420 }
1421 return NULL;
1422} 1427}
1423 1428
1424void postCommand_Widget(const iAnyObject *d, const char *cmd, ...) { 1429void postCommand_Widget(const iAnyObject *d, const char *cmd, ...) {
@@ -1438,7 +1443,7 @@ void postCommand_Widget(const iAnyObject *d, const char *cmd, ...) {
1438 iAssert(isInstance_Object(d, &Class_Widget)); 1443 iAssert(isInstance_Object(d, &Class_Widget));
1439 appendFormat_String(&str, " ptr:%p", d); 1444 appendFormat_String(&str, " ptr:%p", d);
1440 } 1445 }
1441 postCommandString_App(&str); 1446 postCommandString_Root(((const iWidget *) d)->root, &str);
1442 deinit_String(&str); 1447 deinit_String(&str);
1443} 1448}
1444 1449