diff options
Diffstat (limited to 'src/ui/widget.c')
-rw-r--r-- | src/ui/widget.c | 107 |
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 | ||
676 | iRect bounds_Widget(const iWidget *d) { | 676 | iRect 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 | |||
682 | iInt2 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 | |||
696 | iInt2 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 | ||
690 | iRect boundsWithoutVisualOffset_Widget(const iWidget *d) { | 704 | iRect 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 | ||
698 | iInt2 localCoord_Widget(const iWidget *d, iInt2 coord) { | 712 | iInt2 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 | |||
719 | iInt2 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 | ||
705 | iBool contains_Widget(const iWidget *d, iInt2 coord) { | 726 | iBool 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 | ||
709 | iBool containsExpanded_Widget(const iWidget *d, iInt2 coord, int expand) { | 730 | iBool 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 | ||
719 | iLocalDef iBool isKeyboardEvent_(const SDL_Event *ev) { | 740 | iLocalDef 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 | ||
740 | void unhover_Widget(void) { | 761 | void unhover_Widget(void) { |
741 | /* TODO: Which root? */ | 762 | get_Window()->hover = NULL; |
742 | get_Root()->hover = NULL; | ||
743 | } | 763 | } |
744 | 764 | ||
745 | iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) { | 765 | iBool 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 | ||
1269 | iBool isFocused_Widget(const iAnyObject *d) { | 1287 | iBool 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 | ||
1274 | iBool isHover_Widget(const iAnyObject *d) { | 1292 | iBool 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 | ||
1279 | iBool isSelected_Widget(const iAnyObject *d) { | 1297 | iBool isSelected_Widget(const iAnyObject *d) { |
@@ -1319,15 +1337,14 @@ iBool isAffectedByVisualOffset_Widget(const iWidget *d) { | |||
1319 | } | 1337 | } |
1320 | 1338 | ||
1321 | void setFocus_Widget(iWidget *d) { | 1339 | void 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 | ||
1337 | iWidget *focus_Widget(void) { | 1354 | iWidget *focus_Widget(void) { |
1338 | return get_Root()->focus; | 1355 | return get_Window()->focus; |
1339 | } | 1356 | } |
1340 | 1357 | ||
1341 | void setHover_Widget(iWidget *d) { | 1358 | void 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 | ||
1350 | iWidget *hover_Widget(void) { | 1362 | iWidget *hover_Widget(void) { |
1351 | return get_Root()->hover; | 1363 | return get_Window()->hover; |
1352 | } | 1364 | } |
1353 | 1365 | ||
1354 | static const iWidget *findFocusable_Widget_(const iWidget *d, const iWidget *startFrom, | 1366 | static 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 | ||
1406 | void setMouseGrab_Widget(iWidget *d) { | 1418 | void 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 | ||
1414 | iWidget *mouseGrab_Widget(void) { | 1425 | iWidget *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 | ||
1424 | void postCommand_Widget(const iAnyObject *d, const char *cmd, ...) { | 1429 | void 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 | ||