diff options
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/documentwidget.c | 6 | ||||
-rw-r--r-- | src/ui/listwidget.c | 35 | ||||
-rw-r--r-- | src/ui/listwidget.h | 8 | ||||
-rw-r--r-- | src/ui/root.c | 106 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 271 | ||||
-rw-r--r-- | src/ui/sidebarwidget.h | 1 | ||||
-rw-r--r-- | src/ui/touch.c | 37 | ||||
-rw-r--r-- | src/ui/touch.h | 1 | ||||
-rw-r--r-- | src/ui/widget.c | 1 | ||||
-rw-r--r-- | src/ui/widget.h | 5 |
10 files changed, 340 insertions, 131 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 95286566..0ef80690 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -2620,9 +2620,9 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | |||
2620 | /* The temporary "swipeIn" will display the previous page until the finger is lifted. */ | 2620 | /* The temporary "swipeIn" will display the previous page until the finger is lifted. */ |
2621 | iDocumentWidget *swipeIn = findChild_Widget(swipeParent, "swipein"); | 2621 | iDocumentWidget *swipeIn = findChild_Widget(swipeParent, "swipein"); |
2622 | if (!swipeIn) { | 2622 | if (!swipeIn) { |
2623 | const iBool sidebarSwipe = (isPortraitPhone_App() && | 2623 | const iBool sidebarSwipe = iFalse; /* && (isPortraitPhone_App() && |
2624 | d->flags & openedFromSidebar_DocumentWidgetFlag && | 2624 | d->flags & openedFromSidebar_DocumentWidgetFlag && |
2625 | !isVisible_Widget(findWidget_App("sidebar"))); | 2625 | !isVisible_Widget(findWidget_App("sidebar"))); */ |
2626 | swipeIn = new_DocumentWidget(); | 2626 | swipeIn = new_DocumentWidget(); |
2627 | setId_Widget(as_Widget(swipeIn), "swipein"); | 2627 | setId_Widget(as_Widget(swipeIn), "swipein"); |
2628 | setFlags_Widget(as_Widget(swipeIn), | 2628 | setFlags_Widget(as_Widget(swipeIn), |
@@ -3235,6 +3235,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
3235 | return iTrue; | 3235 | return iTrue; |
3236 | } | 3236 | } |
3237 | else if (equal_Command(cmd, "navigate.back") && document_App() == d) { | 3237 | else if (equal_Command(cmd, "navigate.back") && document_App() == d) { |
3238 | #if 0 | ||
3238 | if (isPortraitPhone_App()) { | 3239 | if (isPortraitPhone_App()) { |
3239 | if (d->flags & openedFromSidebar_DocumentWidgetFlag && | 3240 | if (d->flags & openedFromSidebar_DocumentWidgetFlag && |
3240 | !isVisible_Widget(findWidget_App("sidebar"))) { | 3241 | !isVisible_Widget(findWidget_App("sidebar"))) { |
@@ -3247,6 +3248,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
3247 | } | 3248 | } |
3248 | d->flags &= ~openedFromSidebar_DocumentWidgetFlag; | 3249 | d->flags &= ~openedFromSidebar_DocumentWidgetFlag; |
3249 | } | 3250 | } |
3251 | #endif | ||
3250 | if (d->request) { | 3252 | if (d->request) { |
3251 | postCommandf_Root(w->root, | 3253 | postCommandf_Root(w->root, |
3252 | "document.request.cancelled doc:%p url:%s", d, cstr_String(d->mod.url)); | 3254 | "document.request.cancelled doc:%p url:%s", d, cstr_String(d->mod.url)); |
diff --git a/src/ui/listwidget.c b/src/ui/listwidget.c index 82e4e451..d12afc4c 100644 --- a/src/ui/listwidget.c +++ b/src/ui/listwidget.c | |||
@@ -81,6 +81,7 @@ void init_ListWidget(iListWidget *d) { | |||
81 | setThumb_ScrollWidget(d->scroll, 0, 0); | 81 | setThumb_ScrollWidget(d->scroll, 0, 0); |
82 | init_SmoothScroll(&d->scrollY, w, scrollBegan_ListWidget_); | 82 | init_SmoothScroll(&d->scrollY, w, scrollBegan_ListWidget_); |
83 | d->itemHeight = 0; | 83 | d->itemHeight = 0; |
84 | d->scrollMode = normal_ScrollMode; | ||
84 | d->noHoverWhileScrolling = iFalse; | 85 | d->noHoverWhileScrolling = iFalse; |
85 | init_PtrArray(&d->items); | 86 | init_PtrArray(&d->items); |
86 | d->hoverItem = iInvalidPos; | 87 | d->hoverItem = iInvalidPos; |
@@ -187,6 +188,10 @@ void setScrollPos_ListWidget(iListWidget *d, int pos) { | |||
187 | refresh_Widget(as_Widget(d)); | 188 | refresh_Widget(as_Widget(d)); |
188 | } | 189 | } |
189 | 190 | ||
191 | void setScrollMode_ListWidget(iListWidget *d, enum iScrollMode mode) { | ||
192 | d->scrollMode = mode; | ||
193 | } | ||
194 | |||
190 | void scrollOffset_ListWidget(iListWidget *d, int offset) { | 195 | void scrollOffset_ListWidget(iListWidget *d, int offset) { |
191 | moveSpan_SmoothScroll(&d->scrollY, offset, 0); | 196 | moveSpan_SmoothScroll(&d->scrollY, offset, 0); |
192 | } | 197 | } |
@@ -366,12 +371,28 @@ static iBool endDrag_ListWidget_(iListWidget *d, iInt2 endPos) { | |||
366 | return iTrue; | 371 | return iTrue; |
367 | } | 372 | } |
368 | 373 | ||
374 | static iBool isScrollDisabled_ListWidget_(const iListWidget *d, const SDL_Event *ev) { | ||
375 | int dir = 0; | ||
376 | if (ev->type == SDL_MOUSEWHEEL) { | ||
377 | dir = iSign(ev->wheel.y); | ||
378 | } | ||
379 | switch (d->scrollMode) { | ||
380 | case disabledAtTopBothDirections_ScrollMode: | ||
381 | return scrollPos_ListWidget(d) <= 0; | ||
382 | case disabledAtTopUpwards_ScrollMode: | ||
383 | return scrollPos_ListWidget(d) <= 0 && dir > 0; | ||
384 | default: | ||
385 | break; | ||
386 | } | ||
387 | return iFalse; | ||
388 | } | ||
389 | |||
369 | static iBool processEvent_ListWidget_(iListWidget *d, const SDL_Event *ev) { | 390 | static iBool processEvent_ListWidget_(iListWidget *d, const SDL_Event *ev) { |
370 | iWidget *w = as_Widget(d); | 391 | iWidget *w = as_Widget(d); |
371 | if (isMetricsChange_UserEvent(ev)) { | 392 | if (isMetricsChange_UserEvent(ev)) { |
372 | invalidate_ListWidget(d); | 393 | invalidate_ListWidget(d); |
373 | } | 394 | } |
374 | else if (processEvent_SmoothScroll(&d->scrollY, ev)) { | 395 | else if (!isScrollDisabled_ListWidget_(d, ev) && processEvent_SmoothScroll(&d->scrollY, ev)) { |
375 | return iTrue; | 396 | return iTrue; |
376 | } | 397 | } |
377 | else if (isCommand_SDLEvent(ev)) { | 398 | else if (isCommand_SDLEvent(ev)) { |
@@ -420,6 +441,18 @@ static iBool processEvent_ListWidget_(iListWidget *d, const SDL_Event *ev) { | |||
420 | } | 441 | } |
421 | } | 442 | } |
422 | if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { | 443 | if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { |
444 | if (isScrollDisabled_ListWidget_(d, ev)) { | ||
445 | if (ev->wheel.which == SDL_TOUCH_MOUSEID) { | ||
446 | /* TODO: Could generalize this selection of the scrollable parent. */ | ||
447 | extern iWidgetClass Class_SidebarWidget; | ||
448 | iWidget *sidebar = findParentClass_Widget(w, &Class_SidebarWidget); | ||
449 | if (sidebar) { | ||
450 | transferAffinity_Touch(w, sidebar); | ||
451 | d->noHoverWhileScrolling = iTrue; | ||
452 | } | ||
453 | } | ||
454 | return iFalse; | ||
455 | } | ||
423 | int amount = -ev->wheel.y; | 456 | int amount = -ev->wheel.y; |
424 | if (isPerPixel_MouseWheelEvent(&ev->wheel)) { | 457 | if (isPerPixel_MouseWheelEvent(&ev->wheel)) { |
425 | stop_Anim(&d->scrollY.pos); | 458 | stop_Anim(&d->scrollY.pos); |
diff --git a/src/ui/listwidget.h b/src/ui/listwidget.h index 7e6624a0..081109e8 100644 --- a/src/ui/listwidget.h +++ b/src/ui/listwidget.h | |||
@@ -51,6 +51,12 @@ iDeclareObjectConstruction(ListWidget) | |||
51 | 51 | ||
52 | iDeclareType(VisBuf) | 52 | iDeclareType(VisBuf) |
53 | 53 | ||
54 | enum iScrollMode { | ||
55 | normal_ScrollMode, | ||
56 | disabledAtTopBothDirections_ScrollMode, | ||
57 | disabledAtTopUpwards_ScrollMode, | ||
58 | }; | ||
59 | |||
54 | struct Impl_ListWidget { | 60 | struct Impl_ListWidget { |
55 | iWidget widget; | 61 | iWidget widget; |
56 | iScrollWidget *scroll; | 62 | iScrollWidget *scroll; |
@@ -63,6 +69,7 @@ struct Impl_ListWidget { | |||
63 | iClick click; | 69 | iClick click; |
64 | iIntSet invalidItems; | 70 | iIntSet invalidItems; |
65 | iVisBuf *visBuf; | 71 | iVisBuf *visBuf; |
72 | enum iScrollMode scrollMode; | ||
66 | iBool noHoverWhileScrolling; | 73 | iBool noHoverWhileScrolling; |
67 | }; | 74 | }; |
68 | 75 | ||
@@ -82,6 +89,7 @@ int itemHeight_ListWidget (const iListWidget *); | |||
82 | int scrollPos_ListWidget (const iListWidget *); | 89 | int scrollPos_ListWidget (const iListWidget *); |
83 | 90 | ||
84 | void setScrollPos_ListWidget (iListWidget *, int pos); | 91 | void setScrollPos_ListWidget (iListWidget *, int pos); |
92 | void setScrollMode_ListWidget (iListWidget *, enum iScrollMode mode); | ||
85 | void scrollToItem_ListWidget (iListWidget *, size_t index, uint32_t span); | 93 | void scrollToItem_ListWidget (iListWidget *, size_t index, uint32_t span); |
86 | void scrollOffset_ListWidget (iListWidget *, int offset); | 94 | void scrollOffset_ListWidget (iListWidget *, int offset); |
87 | void scrollOffsetSpan_ListWidget (iListWidget *, int offset, uint32_t span); | 95 | void scrollOffsetSpan_ListWidget (iListWidget *, int offset, uint32_t span); |
diff --git a/src/ui/root.c b/src/ui/root.c index f722df94..65fc11d1 100644 --- a/src/ui/root.c +++ b/src/ui/root.c | |||
@@ -487,11 +487,23 @@ static iBool handleRootCommands_(iWidget *root, const char *cmd) { | |||
487 | else if (deviceType_App() == phone_AppDeviceType && equal_Command(cmd, "window.resized")) { | 487 | else if (deviceType_App() == phone_AppDeviceType && equal_Command(cmd, "window.resized")) { |
488 | /* Place the sidebar next to or under doctabs depending on orientation. */ | 488 | /* Place the sidebar next to or under doctabs depending on orientation. */ |
489 | iSidebarWidget *sidebar = findChild_Widget(root, "sidebar"); | 489 | iSidebarWidget *sidebar = findChild_Widget(root, "sidebar"); |
490 | iSidebarWidget *sidebar2 = findChild_Widget(root, "sidebar2"); | ||
491 | removeChild_Widget(parent_Widget(sidebar), sidebar); | 490 | removeChild_Widget(parent_Widget(sidebar), sidebar); |
492 | // setBackgroundColor_Widget(findChild_Widget(as_Widget(sidebar), "buttons"), | 491 | if (isLandscape_App()) { |
493 | // isPortrait_App() ? uiBackgroundUnfocusedSelection_ColorId | 492 | addChildPos_Widget(findChild_Widget(root, "tabs.content"), iClob(sidebar), front_WidgetAddPos); |
494 | // : uiBackgroundSidebar_ColorId); | 493 | setWidth_SidebarWidget(sidebar, 73.0f); |
494 | setFlags_Widget(as_Widget(sidebar), fixedHeight_WidgetFlag, iFalse); | ||
495 | } | ||
496 | else { | ||
497 | addChild_Widget(root, iClob(sidebar)); | ||
498 | setWidth_SidebarWidget(sidebar, (float) width_Widget(root) / (float) gap_UI); | ||
499 | const int midHeight = height_Widget(root) / 2;// + lineHeight_Text(uiLabelLarge_FontId); | ||
500 | setMidHeight_SidebarWidget(sidebar, midHeight); | ||
501 | setFixedSize_Widget(as_Widget(sidebar), init_I2(-1, midHeight)); | ||
502 | setPos_Widget(as_Widget(sidebar), init_I2(0, height_Widget(root) - midHeight)); | ||
503 | } | ||
504 | #if 0 | ||
505 | iSidebarWidget *sidebar = findChild_Widget(root, "sidebar"); | ||
506 | iSidebarWidget *sidebar2 = findChild_Widget(root, "sidebar2"); | ||
495 | setFlags_Widget(findChild_Widget(as_Widget(sidebar), "buttons"), | 507 | setFlags_Widget(findChild_Widget(as_Widget(sidebar), "buttons"), |
496 | borderTop_WidgetFlag, | 508 | borderTop_WidgetFlag, |
497 | isPortrait_App()); | 509 | isPortrait_App()); |
@@ -507,6 +519,7 @@ static iBool handleRootCommands_(iWidget *root, const char *cmd) { | |||
507 | setWidth_SidebarWidget(sidebar, (float) width_Widget(root) / (float) gap_UI); | 519 | setWidth_SidebarWidget(sidebar, (float) width_Widget(root) / (float) gap_UI); |
508 | setWidth_SidebarWidget(sidebar2, (float) width_Widget(root) / (float) gap_UI); | 520 | setWidth_SidebarWidget(sidebar2, (float) width_Widget(root) / (float) gap_UI); |
509 | } | 521 | } |
522 | #endif | ||
510 | return iFalse; | 523 | return iFalse; |
511 | } | 524 | } |
512 | else if (handleCommand_App(cmd)) { | 525 | else if (handleCommand_App(cmd)) { |
@@ -609,14 +622,14 @@ void updatePadding_Root(iRoot *d) { | |||
609 | } | 622 | } |
610 | } | 623 | } |
611 | #endif | 624 | #endif |
612 | if (toolBar) { | 625 | // if (toolBar) { |
613 | /* TODO: get this from toolBar height, but it's buggy for some reason */ | 626 | /* TODO: get this from toolBar height, but it's buggy for some reason */ |
614 | const int sidebarBottomPad = isPortrait_App() ? 11 * gap_UI + bottom : 0; | 627 | // const int sidebarBottomPad = isPortrait_App() ? 11 * gap_UI + bottom : 0; |
615 | setPadding_Widget(findChild_Widget(d->widget, "sidebar"), 0, 0, 0, sidebarBottomPad); | 628 | // setPadding_Widget(findChild_Widget(d->widget, "sidebar"), 0, 0, 0, sidebarBottomPad); |
616 | setPadding_Widget(findChild_Widget(d->widget, "sidebar2"), 0, 0, 0, sidebarBottomPad); | 629 | //setPadding_Widget(findChild_Widget(d->widget, "sidebar2"), 0, 0, 0, sidebarBottomPad); |
617 | /* TODO: There seems to be unrelated layout glitch in the sidebar where its children | 630 | /* TODO: There seems to be unrelated layout glitch in the sidebar where its children |
618 | are not arranged correctly until it's hidden and reshown. */ | 631 | are not arranged correctly until it's hidden and reshown. */ |
619 | } | 632 | // } |
620 | /* Note that `handleNavBarCommands_` also adjusts padding and spacing. */ | 633 | /* Note that `handleNavBarCommands_` also adjusts padding and spacing. */ |
621 | } | 634 | } |
622 | 635 | ||
@@ -1015,30 +1028,17 @@ static iBool handleToolBarCommands_(iWidget *toolBar, const char *cmd) { | |||
1015 | } | 1028 | } |
1016 | else if (equal_Command(cmd, "toolbar.showview")) { | 1029 | else if (equal_Command(cmd, "toolbar.showview")) { |
1017 | /* TODO: Clean this up. */ | 1030 | /* TODO: Clean this up. */ |
1018 | iWidget *sidebar = findWidget_App("sidebar"); | 1031 | // iWidget *sidebar = findWidget_App("sidebar"); |
1019 | iWidget *sidebar2 = findWidget_App("sidebar2"); | 1032 | // iWidget *sidebar2 = findWidget_App("sidebar2"); |
1020 | dismissSidebar_(sidebar2, "toolbar.ident"); | 1033 | // dismissSidebar_(sidebar2, "toolbar.ident"); |
1021 | const iBool isVisible = isVisible_Widget(sidebar); | 1034 | // const iBool isVisible = isVisible_Widget(sidebar); |
1022 | // setFlags_Widget(findChild_Widget(toolBar, "toolbar.view"), noBackground_WidgetFlag, | ||
1023 | // isVisible); | ||
1024 | /* If a sidebar hasn't been shown yet, it's height is zero. */ | 1035 | /* If a sidebar hasn't been shown yet, it's height is zero. */ |
1025 | const int viewHeight = size_Root(get_Root()).y; | 1036 | // const int viewHeight = size_Root(get_Root()).y; |
1026 | if (arg_Command(cmd) >= 0) { | 1037 | if (arg_Command(cmd) >= 0) { |
1027 | postCommandf_App("sidebar.mode arg:%d show:1", arg_Command(cmd)); | 1038 | postCommandf_App("sidebar.mode arg:%d show:1", arg_Command(cmd)); |
1028 | // if (!isVisible) { | ||
1029 | // setVisualOffset_Widget(sidebar, viewHeight, 0, 0); | ||
1030 | // setVisualOffset_Widget(sidebar, 0, 400, easeOut_AnimFlag | softer_AnimFlag); | ||
1031 | // } | ||
1032 | } | 1039 | } |
1033 | else { | 1040 | else { |
1034 | postCommandf_App("sidebar.toggle"); | 1041 | postCommandf_App("sidebar.toggle"); |
1035 | // if (isVisible) { | ||
1036 | // setVisualOffset_Widget(sidebar, height_Widget(sidebar), 250, easeIn_AnimFlag); | ||
1037 | // } | ||
1038 | // else { | ||
1039 | // setVisualOffset_Widget(sidebar, viewHeight, 0, 0); | ||
1040 | // setVisualOffset_Widget(sidebar, 0, 400, easeOut_AnimFlag | softer_AnimFlag); | ||
1041 | // } | ||
1042 | } | 1042 | } |
1043 | return iTrue; | 1043 | return iTrue; |
1044 | } | 1044 | } |
@@ -1110,41 +1110,22 @@ void updateMetrics_Root(iRoot *d) { | |||
1110 | setFixedSize_Widget(appClose, appMin->rect.size); | 1110 | setFixedSize_Widget(appClose, appMin->rect.size); |
1111 | setFixedSize_Widget(appIcon, init_I2(appIconSize_Root(), appMin->rect.size.y)); | 1111 | setFixedSize_Widget(appIcon, init_I2(appIconSize_Root(), appMin->rect.size.y)); |
1112 | } | 1112 | } |
1113 | iWidget *navBar = findChild_Widget(d->widget, "navbar"); | 1113 | iWidget *navBar = findChild_Widget(d->widget, "navbar"); |
1114 | // iWidget *lock = findChild_Widget(navBar, "navbar.lock"); | 1114 | iWidget *url = findChild_Widget(d->widget, "url"); |
1115 | iWidget *url = findChild_Widget(d->widget, "url"); | 1115 | iWidget *rightEmbed = findChild_Widget(navBar, "url.rightembed"); |
1116 | iWidget *rightEmbed = findChild_Widget(navBar, "url.rightembed"); | 1116 | iWidget *embedPad = findChild_Widget(navBar, "url.embedpad"); |
1117 | iWidget *embedPad = findChild_Widget(navBar, "url.embedpad"); | 1117 | iWidget *urlButtons = findChild_Widget(navBar, "url.buttons"); |
1118 | iWidget *urlButtons = findChild_Widget(navBar, "url.buttons"); | 1118 | iLabelWidget *idName = findChild_Widget(d->widget, "toolbar.name"); |
1119 | setPadding_Widget(as_Widget(url), 0, gap_UI, 0, gap_UI); | 1119 | setPadding_Widget(as_Widget(url), 0, gap_UI, 0, gap_UI); |
1120 | navBar->rect.size.y = 0; /* recalculate height based on children (FIXME: shouldn't be needed) */ | 1120 | navBar->rect.size.y = 0; /* recalculate height based on children (FIXME: shouldn't be needed) */ |
1121 | // updateSize_LabelWidget((iLabelWidget *) lock); | ||
1122 | // updateSize_LabelWidget((iLabelWidget *) findChild_Widget(navBar, "reload")); | ||
1123 | // arrange_Widget(urlButtons); | ||
1124 | setFixedSize_Widget(embedPad, init_I2(width_Widget(urlButtons) + gap_UI / 2, 1)); | 1121 | setFixedSize_Widget(embedPad, init_I2(width_Widget(urlButtons) + gap_UI / 2, 1)); |
1125 | // setContentPadding_InputWidget((iInputWidget *) url, width_Widget(lock) * 0.75, | ||
1126 | // width_Widget(lock) * 0.75); | ||
1127 | rightEmbed->rect.pos.y = gap_UI; | 1122 | rightEmbed->rect.pos.y = gap_UI; |
1128 | updatePadding_Root(d); | 1123 | updatePadding_Root(d); |
1129 | arrange_Widget(d->widget); | 1124 | arrange_Widget(d->widget); |
1130 | updateUrlInputContentPadding_(navBar); | 1125 | updateUrlInputContentPadding_(navBar); |
1131 | /* Position the toolbar identity name label manually. */ { | 1126 | if (idName) { |
1132 | iLabelWidget *idName = findChild_Widget(d->widget, "toolbar.name"); | 1127 | setFixedSize_Widget(as_Widget(idName), |
1133 | if (idName) { | 1128 | init_I2(-1, 2 * gap_UI + lineHeight_Text(uiLabelTiny_FontId))); |
1134 | const iWidget *toolBar = findChild_Widget(d->widget, "toolbar"); | ||
1135 | const iWidget *viewButton = findChild_Widget(d->widget, "toolbar.view"); | ||
1136 | const iWidget *idButton = findChild_Widget(toolBar, "toolbar.ident"); | ||
1137 | // const int font = uiLabelTiny_FontId; | ||
1138 | setFixedSize_Widget(as_Widget(idName), init_I2(-1, 2 * gap_UI + lineHeight_Text(uiLabelTiny_FontId))); | ||
1139 | // setFont_LabelWidget(idName, font); | ||
1140 | /*setPos_Widget(as_Widget(idName), | ||
1141 | windowToLocal_Widget(as_Widget(idName), | ||
1142 | init_I2(left_Rect(bounds_Widget(idButton)), | ||
1143 | bottom_Rect(bounds_Widget(viewButton)) - | ||
1144 | lineHeight_Text(font) - gap_UI / 2))); | ||
1145 | setFixedSize_Widget(as_Widget(idName), init_I2(width_Widget(idButton), | ||
1146 | lineHeight_Text(font)));*/ | ||
1147 | } | ||
1148 | } | 1129 | } |
1149 | postRefresh_App(); | 1130 | postRefresh_App(); |
1150 | } | 1131 | } |
@@ -1168,11 +1149,9 @@ void createUserInterface_Root(iRoot *d) { | |||
1168 | setFlags_Widget( | 1149 | setFlags_Widget( |
1169 | root, resizeChildren_WidgetFlag | fixedSize_WidgetFlag | focusRoot_WidgetFlag, iTrue); | 1150 | root, resizeChildren_WidgetFlag | fixedSize_WidgetFlag | focusRoot_WidgetFlag, iTrue); |
1170 | setCommandHandler_Widget(root, handleRootCommands_); | 1151 | setCommandHandler_Widget(root, handleRootCommands_); |
1171 | |||
1172 | iWidget *div = makeVDiv_Widget(); | 1152 | iWidget *div = makeVDiv_Widget(); |
1173 | setId_Widget(div, "navdiv"); | 1153 | setId_Widget(div, "navdiv"); |
1174 | addChild_Widget(root, iClob(div)); | 1154 | addChild_Widget(root, iClob(div)); |
1175 | |||
1176 | #if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) | 1155 | #if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) |
1177 | /* Window title bar. */ | 1156 | /* Window title bar. */ |
1178 | if (prefs_App()->customFrame) { | 1157 | if (prefs_App()->customFrame) { |
@@ -1446,20 +1425,19 @@ void createUserInterface_Root(iRoot *d) { | |||
1446 | "newtab"); | 1425 | "newtab"); |
1447 | } | 1426 | } |
1448 | /* Sidebars. */ { | 1427 | /* Sidebars. */ { |
1449 | iWidget *content = findChild_Widget(root, "tabs.content"); | ||
1450 | iSidebarWidget *sidebar1 = new_SidebarWidget(left_SidebarSide); | 1428 | iSidebarWidget *sidebar1 = new_SidebarWidget(left_SidebarSide); |
1451 | addChildPos_Widget(content, iClob(sidebar1), front_WidgetAddPos); | ||
1452 | if (deviceType_App() != phone_AppDeviceType) { | 1429 | if (deviceType_App() != phone_AppDeviceType) { |
1430 | /* Sidebars are next to the tab content. */ | ||
1431 | iWidget *content = findChild_Widget(root, "tabs.content"); | ||
1432 | addChildPos_Widget(content, iClob(sidebar1), front_WidgetAddPos); | ||
1453 | iSidebarWidget *sidebar2 = new_SidebarWidget(right_SidebarSide); | 1433 | iSidebarWidget *sidebar2 = new_SidebarWidget(right_SidebarSide); |
1454 | addChildPos_Widget(content, iClob(sidebar2), back_WidgetAddPos); | 1434 | addChildPos_Widget(content, iClob(sidebar2), back_WidgetAddPos); |
1455 | } | 1435 | } |
1456 | #if 0 | ||
1457 | else { | 1436 | else { |
1458 | /* The identities sidebar is always in the main area. */ | 1437 | /* Sidebar is a slide-over. */ |
1459 | addChild_Widget(findChild_Widget(root, "stack"), iClob(sidebar2)); | 1438 | addChild_Widget(/*findChild_Widget(root, "stack")*/ root, iClob(sidebar1)); |
1460 | setFlags_Widget(as_Widget(sidebar2), hidden_WidgetFlag, iTrue); | 1439 | setFlags_Widget(as_Widget(sidebar1), hidden_WidgetFlag, iTrue); |
1461 | } | 1440 | } |
1462 | #endif | ||
1463 | } | 1441 | } |
1464 | /* Lookup results. */ { | 1442 | /* Lookup results. */ { |
1465 | iLookupWidget *lookup = new_LookupWidget(); | 1443 | iLookupWidget *lookup = new_LookupWidget(); |
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 13fc33b1..401c5d25 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c | |||
@@ -39,6 +39,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
39 | #include "paint.h" | 39 | #include "paint.h" |
40 | #include "root.h" | 40 | #include "root.h" |
41 | #include "scrollwidget.h" | 41 | #include "scrollwidget.h" |
42 | #include "touch.h" | ||
42 | #include "util.h" | 43 | #include "util.h" |
43 | #include "visited.h" | 44 | #include "visited.h" |
44 | 45 | ||
@@ -99,13 +100,15 @@ struct Impl_SidebarWidget { | |||
99 | iListWidget * list; | 100 | iListWidget * list; |
100 | iCertListWidget * certList; | 101 | iCertListWidget * certList; |
101 | iWidget * actions; /* below the list, area for buttons */ | 102 | iWidget * actions; /* below the list, area for buttons */ |
103 | int midHeight; /* on portrait phone, the height for the middle state */ | ||
104 | iBool isBeingDraggedVertically; /* on portrait phone, sidebar can be dragged up/down */ | ||
102 | int modeScroll[max_SidebarMode]; | 105 | int modeScroll[max_SidebarMode]; |
103 | iLabelWidget * modeButtons[max_SidebarMode]; | 106 | iLabelWidget * modeButtons[max_SidebarMode]; |
104 | int maxButtonLabelWidth; | 107 | int maxButtonLabelWidth; |
105 | float widthAsGaps; | 108 | float widthAsGaps; |
106 | int buttonFont; | 109 | int buttonFont; |
107 | int itemFonts[2]; | 110 | int itemFonts[2]; |
108 | size_t numUnreadEntries; | 111 | size_t numUnreadEntries; |
109 | iWidget * resizer; | 112 | iWidget * resizer; |
110 | iWidget * menu; /* context menu for an item */ | 113 | iWidget * menu; /* context menu for an item */ |
111 | iWidget * modeMenu; /* context menu for the sidebar mode (no item) */ | 114 | iWidget * modeMenu; /* context menu for the sidebar mode (no item) */ |
@@ -194,9 +197,9 @@ static iLabelWidget *addActionButton_SidebarWidget_(iSidebarWidget *d, const cha | |||
194 | //(deviceType_App() != desktop_AppDeviceType ? | 197 | //(deviceType_App() != desktop_AppDeviceType ? |
195 | // extraPadding_WidgetFlag : 0) | | 198 | // extraPadding_WidgetFlag : 0) | |
196 | flags); | 199 | flags); |
197 | setFont_LabelWidget(btn, deviceType_App() == phone_AppDeviceType && d->side == right_SidebarSide | 200 | setFont_LabelWidget(btn, /*deviceType_App() == phone_AppDeviceType && d->side == right_SidebarSide |
198 | ? uiLabelBig_FontId | 201 | ? uiLabelBig_FontId : */ |
199 | : d->buttonFont); | 202 | d->buttonFont); |
200 | checkIcon_LabelWidget(btn); | 203 | checkIcon_LabelWidget(btn); |
201 | return btn; | 204 | return btn; |
202 | } | 205 | } |
@@ -211,7 +214,12 @@ static iBool isBookmarkFolded_SidebarWidget_(const iSidebarWidget *d, const iBoo | |||
211 | return iFalse; | 214 | return iFalse; |
212 | } | 215 | } |
213 | 216 | ||
217 | static iBool isSlidingSheet_SidebarWidget_(const iSidebarWidget *d) { | ||
218 | return isPortraitPhone_App();// && scrollPos_ListWidget(d->list) <= 0; | ||
219 | } | ||
220 | |||
214 | static void updateItemsWithFlags_SidebarWidget_(iSidebarWidget *d, iBool keepActions) { | 221 | static void updateItemsWithFlags_SidebarWidget_(iSidebarWidget *d, iBool keepActions) { |
222 | const iBool isMobile = (deviceType_App() != desktop_AppDeviceType); | ||
215 | clear_ListWidget(d->list); | 223 | clear_ListWidget(d->list); |
216 | releaseChildren_Widget(d->blank); | 224 | releaseChildren_Widget(d->blank); |
217 | if (!keepActions) { | 225 | if (!keepActions) { |
@@ -299,9 +307,10 @@ static void updateItemsWithFlags_SidebarWidget_(iSidebarWidget *d, iBool keepAct | |||
299 | } | 307 | } |
300 | /* Actions. */ | 308 | /* Actions. */ |
301 | if (!keepActions) { | 309 | if (!keepActions) { |
302 | addActionButton_SidebarWidget_( | 310 | addActionButton_SidebarWidget_(d, |
303 | d, check_Icon " ${sidebar.action.feeds.markallread}", "feeds.markallread", expand_WidgetFlag | | 311 | check_Icon " ${sidebar.action.feeds.markallread}", |
304 | tight_WidgetFlag); | 312 | "feeds.markallread", |
313 | expand_WidgetFlag | tight_WidgetFlag); | ||
305 | updateSize_LabelWidget(addChildFlags_Widget(d->actions, | 314 | updateSize_LabelWidget(addChildFlags_Widget(d->actions, |
306 | iClob(new_LabelWidget("${sidebar.action.show}", NULL)), | 315 | iClob(new_LabelWidget("${sidebar.action.show}", NULL)), |
307 | frameless_WidgetFlag | tight_WidgetFlag)); | 316 | frameless_WidgetFlag | tight_WidgetFlag)); |
@@ -617,6 +626,10 @@ void setClosedFolders_SidebarWidget(iSidebarWidget *d, const iIntSet *closedFold | |||
617 | } | 626 | } |
618 | } | 627 | } |
619 | 628 | ||
629 | void setMidHeight_SidebarWidget(iSidebarWidget *d, int midHeight) { | ||
630 | d->midHeight = midHeight; | ||
631 | } | ||
632 | |||
620 | enum iSidebarMode mode_SidebarWidget(const iSidebarWidget *d) { | 633 | enum iSidebarMode mode_SidebarWidget(const iSidebarWidget *d) { |
621 | return d ? d->mode : 0; | 634 | return d ? d->mode : 0; |
622 | } | 635 | } |
@@ -686,6 +699,8 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | |||
686 | d->side = side; | 699 | d->side = side; |
687 | d->mode = -1; | 700 | d->mode = -1; |
688 | d->feedsMode = all_FeedsMode; | 701 | d->feedsMode = all_FeedsMode; |
702 | d->midHeight = 0; | ||
703 | d->isBeingDraggedVertically = iFalse; | ||
689 | d->numUnreadEntries = 0; | 704 | d->numUnreadEntries = 0; |
690 | d->buttonFont = uiLabel_FontId; /* wiil be changed later */ | 705 | d->buttonFont = uiLabel_FontId; /* wiil be changed later */ |
691 | d->itemFonts[0] = uiContent_FontId; | 706 | d->itemFonts[0] = uiContent_FontId; |
@@ -703,15 +718,24 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | |||
703 | iWidget *vdiv = makeVDiv_Widget(); | 718 | iWidget *vdiv = makeVDiv_Widget(); |
704 | addChildFlags_Widget(w, vdiv, resizeToParentWidth_WidgetFlag | resizeToParentHeight_WidgetFlag); | 719 | addChildFlags_Widget(w, vdiv, resizeToParentWidth_WidgetFlag | resizeToParentHeight_WidgetFlag); |
705 | iZap(d->modeButtons); | 720 | iZap(d->modeButtons); |
706 | d->resizer = NULL; | 721 | d->resizer = NULL; |
707 | d->list = NULL; | 722 | d->list = NULL; |
708 | d->certList = NULL; | 723 | d->certList = NULL; |
709 | d->actions = NULL; | 724 | d->actions = NULL; |
710 | d->closedFolders = new_IntSet(); | 725 | d->closedFolders = new_IntSet(); |
711 | /* On a phone, the right sidebar is not used. */ | 726 | /* On a phone, the right sidebar is not used. */ |
712 | const iBool isPhone = deviceType_App() == phone_AppDeviceType; | 727 | const iBool isPhone = (deviceType_App() == phone_AppDeviceType); |
713 | //if (!isPhone || d->side == left_SidebarSide) { | 728 | if (isPhone) { |
714 | iWidget *buttons = new_Widget(); | 729 | iLabelWidget *closeButton = |
730 | addChildFlags_Widget(vdiv, | ||
731 | iClob(new_LabelWidget("${sidebar.close}", "sidebar.toggle")), | ||
732 | collapse_WidgetFlag | alignRight_WidgetFlag | | ||
733 | extraPadding_WidgetFlag | frameless_WidgetFlag); | ||
734 | as_Widget(closeButton)->flags2 |= slidingSheetDraggable_WidgetFlag2; /* phone */ | ||
735 | setId_Widget(as_Widget(closeButton), "sidebar.close"); | ||
736 | setFont_LabelWidget(closeButton, uiLabelBigBold_FontId); | ||
737 | } | ||
738 | iWidget *buttons = new_Widget(); | ||
715 | setId_Widget(buttons, "buttons"); | 739 | setId_Widget(buttons, "buttons"); |
716 | setDrawBufferEnabled_Widget(buttons, iTrue); | 740 | setDrawBufferEnabled_Widget(buttons, iTrue); |
717 | for (int i = 0; i < max_SidebarMode; i++) { | 741 | for (int i = 0; i < max_SidebarMode; i++) { |
@@ -725,28 +749,14 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | |||
725 | tightModeLabels_[i], | 749 | tightModeLabels_[i], |
726 | format_CStr("%s.mode arg:%d", cstr_String(id_Widget(w)), i))), | 750 | format_CStr("%s.mode arg:%d", cstr_String(id_Widget(w)), i))), |
727 | frameless_WidgetFlag | noBackground_WidgetFlag); | 751 | frameless_WidgetFlag | noBackground_WidgetFlag); |
752 | as_Widget(d->modeButtons[i])->flags2 |= slidingSheetDraggable_WidgetFlag2; /* phone */ | ||
728 | } | 753 | } |
729 | setButtonFont_SidebarWidget(d, isPhone ? uiLabelBig_FontId : uiLabel_FontId); | 754 | setButtonFont_SidebarWidget(d, isPhone ? uiLabelBig_FontId : uiLabel_FontId); |
730 | addChildFlags_Widget(vdiv, | 755 | addChildFlags_Widget(vdiv, |
731 | iClob(buttons), | 756 | iClob(buttons), |
732 | arrangeHorizontal_WidgetFlag | | 757 | arrangeHorizontal_WidgetFlag | resizeWidthOfChildren_WidgetFlag | |
733 | resizeWidthOfChildren_WidgetFlag | | 758 | arrangeHeight_WidgetFlag | resizeToParentWidth_WidgetFlag); |
734 | arrangeHeight_WidgetFlag | resizeToParentWidth_WidgetFlag); // | | ||
735 | // drawBackgroundToHorizontalSafeArea_WidgetFlag); | ||
736 | setBackgroundColor_Widget(buttons, uiBackgroundSidebar_ColorId); | 759 | setBackgroundColor_Widget(buttons, uiBackgroundSidebar_ColorId); |
737 | // } | ||
738 | #if 0 | ||
739 | else { | ||
740 | iLabelWidget *heading = new_LabelWidget(person_Icon " ${sidebar.identities}", NULL); | ||
741 | checkIcon_LabelWidget(heading); | ||
742 | setBackgroundColor_Widget(as_Widget(heading), uiBackgroundSidebar_ColorId); | ||
743 | setTextColor_LabelWidget(heading, uiTextSelected_ColorId); | ||
744 | setFont_LabelWidget(addChildFlags_Widget(vdiv, iClob(heading), borderTop_WidgetFlag | | ||
745 | alignLeft_WidgetFlag | frameless_WidgetFlag | | ||
746 | drawBackgroundToHorizontalSafeArea_WidgetFlag), | ||
747 | uiLabelLargeBold_FontId); | ||
748 | } | ||
749 | #endif | ||
750 | iWidget *content = new_Widget(); | 760 | iWidget *content = new_Widget(); |
751 | setFlags_Widget(content, resizeChildren_WidgetFlag, iTrue); | 761 | setFlags_Widget(content, resizeChildren_WidgetFlag, iTrue); |
752 | iWidget *listAndActions = makeVDiv_Widget(); | 762 | iWidget *listAndActions = makeVDiv_Widget(); |
@@ -756,15 +766,17 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | |||
756 | d->list = new_ListWidget(); | 766 | d->list = new_ListWidget(); |
757 | setPadding_Widget(as_Widget(d->list), 0, gap_UI, 0, gap_UI); | 767 | setPadding_Widget(as_Widget(d->list), 0, gap_UI, 0, gap_UI); |
758 | addChild_Widget(listArea, iClob(d->list)); | 768 | addChild_Widget(listArea, iClob(d->list)); |
759 | d->certList = new_CertListWidget(); | 769 | if (!isPhone) { |
760 | setPadding_Widget(as_Widget(d->certList), 0, gap_UI, 0, gap_UI); | 770 | d->certList = new_CertListWidget(); |
761 | addChild_Widget(listArea, iClob(d->certList)); | 771 | setPadding_Widget(as_Widget(d->certList), 0, gap_UI, 0, gap_UI); |
772 | addChild_Widget(listArea, iClob(d->certList)); | ||
773 | } | ||
762 | addChildFlags_Widget(listAndActions, | 774 | addChildFlags_Widget(listAndActions, |
763 | iClob(listArea), | 775 | iClob(listArea), |
764 | expand_WidgetFlag); // | drawBackgroundToHorizontalSafeArea_WidgetFlag); | 776 | expand_WidgetFlag); // | drawBackgroundToHorizontalSafeArea_WidgetFlag); |
765 | setId_Widget(addChildPosFlags_Widget(listAndActions, | 777 | setId_Widget(addChildPosFlags_Widget(listAndActions, |
766 | iClob(d->actions = new_Widget()), | 778 | iClob(d->actions = new_Widget()), |
767 | isPhone ? front_WidgetAddPos : back_WidgetAddPos, | 779 | /*isPhone ? front_WidgetAddPos :*/ back_WidgetAddPos, |
768 | arrangeHorizontal_WidgetFlag | arrangeHeight_WidgetFlag | | 780 | arrangeHorizontal_WidgetFlag | arrangeHeight_WidgetFlag | |
769 | resizeWidthOfChildren_WidgetFlag), // | | 781 | resizeWidthOfChildren_WidgetFlag), // | |
770 | // drawBackgroundToHorizontalSafeArea_WidgetFlag), | 782 | // drawBackgroundToHorizontalSafeArea_WidgetFlag), |
@@ -891,7 +903,7 @@ static void checkModeButtonLayout_SidebarWidget_(iSidebarWidget *d) { | |||
891 | // updateMetrics_SidebarWidget_(d); | 903 | // updateMetrics_SidebarWidget_(d); |
892 | updateItemHeight_SidebarWidget_(d); | 904 | updateItemHeight_SidebarWidget_(d); |
893 | } | 905 | } |
894 | setButtonFont_SidebarWidget(d, isPortrait_App() ? uiLabelBig_FontId : uiLabel_FontId); | 906 | setButtonFont_SidebarWidget(d, isPortrait_App() ? uiLabelMedium_FontId : uiLabel_FontId); |
895 | } | 907 | } |
896 | const iBool isTight = | 908 | const iBool isTight = |
897 | (width_Rect(bounds_Widget(as_Widget(d->modeButtons[0]))) < d->maxButtonLabelWidth); | 909 | (width_Rect(bounds_Widget(as_Widget(d->modeButtons[0]))) < d->maxButtonLabelWidth); |
@@ -982,6 +994,52 @@ iBool handleBookmarkEditorCommands_SidebarWidget_(iWidget *editor, const char *c | |||
982 | return iFalse; | 994 | return iFalse; |
983 | } | 995 | } |
984 | 996 | ||
997 | static void animateSlidingSheetHeight_SidebarWidget_(iAny *sidebar) { | ||
998 | iWidget *d = sidebar; | ||
999 | const int oldSize = d->rect.size.y; | ||
1000 | const int newSize = bottom_Rect(safeRect_Root(d->root)) - top_Rect(bounds_Widget(d)); | ||
1001 | if (oldSize != newSize) { | ||
1002 | d->rect.size.y = newSize; | ||
1003 | arrange_Widget(d); | ||
1004 | } | ||
1005 | // printf("[%p] %u: %d animating %d\n", d, window_Widget(d)->frameTime, | ||
1006 | // (flags_Widget(sidebar) & visualOffset_WidgetFlag) != 0, | ||
1007 | // newSize); | ||
1008 | if (!isFinished_Anim(&d->visualOffset)) { | ||
1009 | addTicker_App(animateSlidingSheetHeight_SidebarWidget_, sidebar); | ||
1010 | } | ||
1011 | } | ||
1012 | |||
1013 | enum iSlidingSheetPos { | ||
1014 | top_SlidingSheetPos, | ||
1015 | middle_SlidingSheetPos, | ||
1016 | bottom_SlidingSheetPos, | ||
1017 | }; | ||
1018 | |||
1019 | static void setSlidingSheetPos_SidebarWidget_(iSidebarWidget *d, enum iSlidingSheetPos slide) { | ||
1020 | iWidget *w = as_Widget(d); | ||
1021 | const int pos = w->rect.pos.y; | ||
1022 | const iRect safeRect = safeRect_Root(w->root); | ||
1023 | if (slide == top_SlidingSheetPos) { | ||
1024 | w->rect.pos.y = top_Rect(safeRect); | ||
1025 | w->rect.size.y = height_Rect(safeRect); | ||
1026 | setVisualOffset_Widget(w, pos - w->rect.pos.y, 0, 0); | ||
1027 | setVisualOffset_Widget(w, 0, 200, easeOut_AnimFlag | softer_AnimFlag); | ||
1028 | setScrollMode_ListWidget(d->list, disabledAtTopUpwards_ScrollMode); | ||
1029 | } | ||
1030 | else if (slide == bottom_SlidingSheetPos) { | ||
1031 | postCommand_Widget(w, "sidebar.toggle"); | ||
1032 | } | ||
1033 | else { | ||
1034 | w->rect.size.y = d->midHeight; | ||
1035 | w->rect.pos.y = height_Rect(safeRect) - w->rect.size.y; | ||
1036 | setVisualOffset_Widget(w, pos - w->rect.pos.y, 0, 0); | ||
1037 | setVisualOffset_Widget(w, 0, 200, easeOut_AnimFlag | softer_AnimFlag); | ||
1038 | setScrollMode_ListWidget(d->list, disabledAtTopBothDirections_ScrollMode); | ||
1039 | } | ||
1040 | animateSlidingSheetHeight_SidebarWidget_(d); | ||
1041 | } | ||
1042 | |||
985 | static iBool handleSidebarCommand_SidebarWidget_(iSidebarWidget *d, const char *cmd) { | 1043 | static iBool handleSidebarCommand_SidebarWidget_(iSidebarWidget *d, const char *cmd) { |
986 | iWidget *w = as_Widget(d); | 1044 | iWidget *w = as_Widget(d); |
987 | if (equal_Command(cmd, "width")) { | 1045 | if (equal_Command(cmd, "width")) { |
@@ -1011,35 +1069,58 @@ static iBool handleSidebarCommand_SidebarWidget_(iSidebarWidget *d, const char * | |||
1011 | argLabel_Command(cmd, "noanim") == 0 && | 1069 | argLabel_Command(cmd, "noanim") == 0 && |
1012 | (d->side == left_SidebarSide || deviceType_App() != phone_AppDeviceType); | 1070 | (d->side == left_SidebarSide || deviceType_App() != phone_AppDeviceType); |
1013 | int visX = 0; | 1071 | int visX = 0; |
1072 | int visY = 0; | ||
1014 | if (isVisible_Widget(w)) { | 1073 | if (isVisible_Widget(w)) { |
1015 | visX = left_Rect(bounds_Widget(w)) - left_Rect(w->root->widget->rect); | 1074 | visX = left_Rect(bounds_Widget(w)) - left_Rect(w->root->widget->rect); |
1075 | visY = top_Rect(bounds_Widget(w)) - top_Rect(w->root->widget->rect); | ||
1016 | } | 1076 | } |
1017 | setFlags_Widget(w, hidden_WidgetFlag, isVisible_Widget(w)); | 1077 | const iBool isHiding = isVisible_Widget(w); |
1078 | setFlags_Widget(w, hidden_WidgetFlag, isHiding); | ||
1018 | /* Safe area inset for mobile. */ | 1079 | /* Safe area inset for mobile. */ |
1019 | const int safePad = (d->side == left_SidebarSide ? left_Rect(safeRect_Root(w->root)) : 0); | 1080 | const int safePad = (d->side == left_SidebarSide ? left_Rect(safeRect_Root(w->root)) : 0); |
1020 | if (isVisible_Widget(w)) { | 1081 | const int animFlags = easeOut_AnimFlag | softer_AnimFlag; |
1021 | setFlags_Widget(w, keepOnTop_WidgetFlag, iFalse); | 1082 | if (!isPortraitPhone_App()) { |
1022 | w->rect.size.x = d->widthAsGaps * gap_UI; | 1083 | if (!isHiding) { |
1023 | invalidate_ListWidget(d->list); | 1084 | setFlags_Widget(w, keepOnTop_WidgetFlag, iFalse); |
1024 | if (isAnimated) { | 1085 | w->rect.size.x = d->widthAsGaps * gap_UI; |
1086 | invalidate_ListWidget(d->list); | ||
1087 | if (isAnimated) { | ||
1088 | setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue); | ||
1089 | setVisualOffset_Widget( | ||
1090 | w, (d->side == left_SidebarSide ? -1 : 1) * (w->rect.size.x + safePad), 0, 0); | ||
1091 | setVisualOffset_Widget(w, 0, 300, animFlags); | ||
1092 | } | ||
1093 | } | ||
1094 | else if (isAnimated) { | ||
1025 | setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue); | 1095 | setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue); |
1026 | setVisualOffset_Widget( | 1096 | if (d->side == right_SidebarSide) { |
1027 | w, (d->side == left_SidebarSide ? -1 : 1) * (w->rect.size.x + safePad), 0, 0); | 1097 | setVisualOffset_Widget(w, visX, 0, 0); |
1028 | setVisualOffset_Widget(w, 0, 300, easeOut_AnimFlag | softer_AnimFlag); | 1098 | setVisualOffset_Widget( |
1099 | w, visX + w->rect.size.x + safePad, 300, animFlags); | ||
1100 | } | ||
1101 | else { | ||
1102 | setFlags_Widget(w, keepOnTop_WidgetFlag, iTrue); | ||
1103 | setVisualOffset_Widget( | ||
1104 | w, -w->rect.size.x - safePad, 300, animFlags); | ||
1105 | } | ||
1029 | } | 1106 | } |
1107 | setScrollMode_ListWidget(d->list, normal_ScrollMode); | ||
1030 | } | 1108 | } |
1031 | else if (isAnimated) { | 1109 | else { |
1032 | setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue); | 1110 | /* Portrait phone sidebar works differently: it slides up from the bottom. */ |
1033 | if (d->side == right_SidebarSide) { | 1111 | setFlags_Widget(w, horizontalOffset_WidgetFlag, iFalse); |
1034 | setVisualOffset_Widget(w, visX, 0, 0); | 1112 | if (!isHiding) { |
1035 | setVisualOffset_Widget( | 1113 | invalidate_ListWidget(d->list); |
1036 | w, visX + w->rect.size.x + safePad, 300, easeOut_AnimFlag | softer_AnimFlag); | 1114 | w->rect.pos.y = height_Rect(safeRect_Root(w->root)) - d->midHeight; |
1115 | setVisualOffset_Widget(w, bottom_Rect(rect_Root(w->root)) - w->rect.pos.y, 0, 0); | ||
1116 | setVisualOffset_Widget(w, 0, 300, animFlags); | ||
1117 | animateSlidingSheetHeight_SidebarWidget_(d); | ||
1118 | setScrollMode_ListWidget(d->list, disabledAtTopBothDirections_ScrollMode); | ||
1037 | } | 1119 | } |
1038 | else { | 1120 | else { |
1039 | setFlags_Widget(w, keepOnTop_WidgetFlag, iTrue); | 1121 | setVisualOffset_Widget(w, bottom_Rect(rect_Root(w->root)) - w->rect.pos.y, 300, animFlags); |
1040 | setVisualOffset_Widget( | ||
1041 | w, -w->rect.size.x - safePad, 300, easeOut_AnimFlag | softer_AnimFlag); | ||
1042 | } | 1122 | } |
1123 | showToolbar_Root(w->root, isHiding); | ||
1043 | } | 1124 | } |
1044 | updateToolbarColors_Root(w->root); | 1125 | updateToolbarColors_Root(w->root); |
1045 | arrange_Widget(w->parent); | 1126 | arrange_Widget(w->parent); |
@@ -1097,13 +1178,32 @@ static size_t numBookmarks_(const iPtrArray *bmList) { | |||
1097 | return num; | 1178 | return num; |
1098 | } | 1179 | } |
1099 | 1180 | ||
1181 | static iRangei SlidingSheetMiddleRegion_SidebarWidget_(const iSidebarWidget *d) { | ||
1182 | const iWidget *w = constAs_Widget(d); | ||
1183 | const iRect safeRect = safeRect_Root(w->root); | ||
1184 | const int midY = bottom_Rect(safeRect) - d->midHeight; | ||
1185 | const int topHalf = (top_Rect(safeRect) + midY) / 2; | ||
1186 | const int bottomHalf = (bottom_Rect(safeRect) + midY * 2) / 3; | ||
1187 | return (iRangei){ topHalf, bottomHalf }; | ||
1188 | } | ||
1189 | |||
1190 | static void gotoNearestSlidingSheetPos_SidebarWidget_(iSidebarWidget *d) { | ||
1191 | const iRangei midRegion = SlidingSheetMiddleRegion_SidebarWidget_(d); | ||
1192 | const int pos = top_Rect(d->widget.rect); | ||
1193 | setSlidingSheetPos_SidebarWidget_(d, pos < midRegion.start | ||
1194 | ? top_SlidingSheetPos | ||
1195 | : pos > midRegion.end ? bottom_SlidingSheetPos | ||
1196 | : middle_SlidingSheetPos); | ||
1197 | } | ||
1198 | |||
1100 | static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) { | 1199 | static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) { |
1101 | iWidget *w = as_Widget(d); | 1200 | iWidget *w = as_Widget(d); |
1102 | /* Handle commands. */ | 1201 | /* Handle commands. */ |
1103 | if (isResize_UserEvent(ev)) { | 1202 | if (isResize_UserEvent(ev)) { |
1104 | checkModeButtonLayout_SidebarWidget_(d); | 1203 | checkModeButtonLayout_SidebarWidget_(d); |
1105 | if (deviceType_App() == phone_AppDeviceType && d->side == left_SidebarSide) { | 1204 | if (deviceType_App() == phone_AppDeviceType) { // && d->side == left_SidebarSide) { |
1106 | setFlags_Widget(w, rightEdgeDraggable_WidgetFlag, isPortrait_App()); | 1205 | // setFlags_Widget(w, rightEdgeDraggable_WidgetFlag, isPortrait_App()); |
1206 | setFlags_Widget(findChild_Widget(w, "sidebar.close"), hidden_WidgetFlag, isLandscape_App()); | ||
1107 | /* In landscape, visibility of the toolbar is controlled separately. */ | 1207 | /* In landscape, visibility of the toolbar is controlled separately. */ |
1108 | if (isVisible_Widget(w)) { | 1208 | if (isVisible_Widget(w)) { |
1109 | postCommand_Widget(w, "sidebar.toggle"); | 1209 | postCommand_Widget(w, "sidebar.toggle"); |
@@ -1117,6 +1217,10 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) | |||
1117 | setFlags_Widget(as_Widget(d->list), | 1217 | setFlags_Widget(as_Widget(d->list), |
1118 | drawBackgroundToHorizontalSafeArea_WidgetFlag, | 1218 | drawBackgroundToHorizontalSafeArea_WidgetFlag, |
1119 | isLandscape_App()); | 1219 | isLandscape_App()); |
1220 | setFlags_Widget(w, | ||
1221 | drawBackgroundToBottom_WidgetFlag, | ||
1222 | isPortrait_App()); | ||
1223 | setBackgroundColor_Widget(w, isPortrait_App() ? uiBackgroundSidebar_ColorId : none_ColorId); | ||
1120 | return iFalse; | 1224 | return iFalse; |
1121 | } | 1225 | } |
1122 | } | 1226 | } |
@@ -1572,6 +1676,61 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) | |||
1572 | return iTrue; | 1676 | return iTrue; |
1573 | } | 1677 | } |
1574 | } | 1678 | } |
1679 | if (isSlidingSheet_SidebarWidget_(d)) { | ||
1680 | if (ev->type == SDL_MOUSEWHEEL) { | ||
1681 | enum iWidgetTouchMode touchMode = widgetMode_Touch(w); | ||
1682 | if (touchMode == momentum_WidgetTouchMode) { | ||
1683 | /* We don't do momentum. */ | ||
1684 | float swipe = stopWidgetMomentum_Touch(w); | ||
1685 | // printf("swipe: %f\n", swipe); | ||
1686 | const iRangei midRegion = SlidingSheetMiddleRegion_SidebarWidget_(d); | ||
1687 | const int pos = top_Rect(w->rect); | ||
1688 | if (swipe < 500) { | ||
1689 | gotoNearestSlidingSheetPos_SidebarWidget_(d); | ||
1690 | } | ||
1691 | else if (swipe > 6500 && ev->wheel.y > 0) { | ||
1692 | /* Fast swipe down will dismiss. */ | ||
1693 | setSlidingSheetPos_SidebarWidget_(d, bottom_SlidingSheetPos); | ||
1694 | } | ||
1695 | else if (ev->wheel.y < 0) { | ||
1696 | setSlidingSheetPos_SidebarWidget_(d, top_SlidingSheetPos); | ||
1697 | } | ||
1698 | else if (pos < (midRegion.start + midRegion.end) / 2) { | ||
1699 | setSlidingSheetPos_SidebarWidget_(d, middle_SlidingSheetPos); | ||
1700 | } | ||
1701 | else { | ||
1702 | setSlidingSheetPos_SidebarWidget_(d, bottom_SlidingSheetPos); | ||
1703 | } | ||
1704 | } | ||
1705 | else if (touchMode == touch_WidgetTouchMode) { | ||
1706 | /* Move with the finger. */ | ||
1707 | adjustEdges_Rect(&w->rect, ev->wheel.y, 0, 0, 0); | ||
1708 | /* Upon reaching the top, scrolling is switched back to the list. */ | ||
1709 | const iRect rootRect = safeRect_Root(w->root); | ||
1710 | const int top = top_Rect(rootRect); | ||
1711 | if (w->rect.pos.y < top) { | ||
1712 | setScrollMode_ListWidget(d->list, disabledAtTopUpwards_ScrollMode); | ||
1713 | setScrollPos_ListWidget(d->list, top - w->rect.pos.y); | ||
1714 | transferAffinity_Touch(w, as_Widget(d->list)); | ||
1715 | w->rect.pos.y = top; | ||
1716 | w->rect.size.y = height_Rect(rootRect); | ||
1717 | } | ||
1718 | else { | ||
1719 | setScrollMode_ListWidget(d->list, disabledAtTopBothDirections_ScrollMode); | ||
1720 | } | ||
1721 | arrange_Widget(w); | ||
1722 | refresh_Widget(w); | ||
1723 | } | ||
1724 | else { | ||
1725 | return iFalse; | ||
1726 | } | ||
1727 | return iTrue; | ||
1728 | } | ||
1729 | if (ev->type == SDL_USEREVENT && ev->user.code == widgetTouchEnds_UserEventCode) { | ||
1730 | gotoNearestSlidingSheetPos_SidebarWidget_(d); | ||
1731 | return iTrue; | ||
1732 | } | ||
1733 | } | ||
1575 | if (ev->type == SDL_MOUSEBUTTONDOWN && | 1734 | if (ev->type == SDL_MOUSEBUTTONDOWN && |
1576 | contains_Widget(as_Widget(d->list), init_I2(ev->button.x, ev->button.y))) { | 1735 | contains_Widget(as_Widget(d->list), init_I2(ev->button.x, ev->button.y))) { |
1577 | if (hoverItem_ListWidget(d->list) || isVisible_Widget(d->menu)) { | 1736 | if (hoverItem_ListWidget(d->list) || isVisible_Widget(d->menu)) { |
diff --git a/src/ui/sidebarwidget.h b/src/ui/sidebarwidget.h index 81c6681f..2a930a60 100644 --- a/src/ui/sidebarwidget.h +++ b/src/ui/sidebarwidget.h | |||
@@ -54,6 +54,7 @@ iBool setMode_SidebarWidget (iSidebarWidget *, enum iSidebar | |||
54 | void setWidth_SidebarWidget (iSidebarWidget *, float widthAsGaps); | 54 | void setWidth_SidebarWidget (iSidebarWidget *, float widthAsGaps); |
55 | iBool setButtonFont_SidebarWidget (iSidebarWidget *, int font); | 55 | iBool setButtonFont_SidebarWidget (iSidebarWidget *, int font); |
56 | void setClosedFolders_SidebarWidget (iSidebarWidget *, const iIntSet *closedFolders); | 56 | void setClosedFolders_SidebarWidget (iSidebarWidget *, const iIntSet *closedFolders); |
57 | void setMidHeight_SidebarWidget (iSidebarWidget *, int midHeight); /* phone layout */ | ||
57 | 58 | ||
58 | enum iSidebarMode mode_SidebarWidget (const iSidebarWidget *); | 59 | enum iSidebarMode mode_SidebarWidget (const iSidebarWidget *); |
59 | enum iFeedsMode feedsMode_SidebarWidget (const iSidebarWidget *); | 60 | enum iFeedsMode feedsMode_SidebarWidget (const iSidebarWidget *); |
diff --git a/src/ui/touch.c b/src/ui/touch.c index 195d1dff..aee5a383 100644 --- a/src/ui/touch.c +++ b/src/ui/touch.c | |||
@@ -589,9 +589,18 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
589 | divvf_F3(&touch->accum, 6); | 589 | divvf_F3(&touch->accum, 6); |
590 | divfv_I2(&pixels, 6); | 590 | divfv_I2(&pixels, 6); |
591 | /* Allow scrolling a scrollable widget. */ | 591 | /* Allow scrolling a scrollable widget. */ |
592 | iWidget *flow = findOverflowScrollable_Widget(touch->affinity); | 592 | if (touch->affinity && touch->affinity->flags2 & slidingSheetDraggable_WidgetFlag2) { |
593 | if (flow) { | 593 | extern iWidgetClass Class_SidebarWidget; /* The only type of sliding sheet for now. */ |
594 | touch->affinity = flow; | 594 | iWidget *slider = findParentClass_Widget(touch->affinity, &Class_SidebarWidget); |
595 | if (slider) { | ||
596 | touch->affinity = slider; | ||
597 | } | ||
598 | } | ||
599 | else { | ||
600 | iWidget *flow = findOverflowScrollable_Widget(touch->affinity); | ||
601 | if (flow) { | ||
602 | touch->affinity = flow; | ||
603 | } | ||
595 | } | 604 | } |
596 | } | 605 | } |
597 | else { | 606 | else { |
@@ -617,11 +626,13 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
617 | if (touch->axis == y_TouchAxis) { | 626 | if (touch->axis == y_TouchAxis) { |
618 | pixels.x = 0; | 627 | pixels.x = 0; |
619 | } | 628 | } |
620 | // printf("%p (%s) py: %i wy: %f acc: %f edge: %d\n", | 629 | #if 0 |
621 | // touch->affinity, | 630 | printf("%p (%s) py: %i wy: %f acc: %f edge: %d\n", |
622 | // class_Widget(touch->affinity)->name, | 631 | touch->affinity, |
623 | // pixels.y, y_F3(amount), y_F3(touch->accum), | 632 | class_Widget(touch->affinity)->name, |
624 | // touch->edge); | 633 | pixels.y, y_F3(amount), y_F3(touch->accum), |
634 | touch->edge); | ||
635 | #endif | ||
625 | if (pixels.x || pixels.y) { | 636 | if (pixels.x || pixels.y) { |
626 | //setFocus_Widget(NULL); | 637 | //setFocus_Widget(NULL); |
627 | dispatchMotion_Touch_(touch->startPos /*pos[0]*/, 0); | 638 | dispatchMotion_Touch_(touch->startPos /*pos[0]*/, 0); |
@@ -801,6 +812,16 @@ void widgetDestroyed_Touch(iWidget *widget) { | |||
801 | } | 812 | } |
802 | } | 813 | } |
803 | 814 | ||
815 | void transferAffinity_Touch(iWidget *src, iWidget *dst) { | ||
816 | iTouchState *d = touchState_(); | ||
817 | iForEach(Array, i, d->touches) { | ||
818 | iTouch *touch = i.value; | ||
819 | if (touch->affinity == src) { | ||
820 | touch->affinity = dst; | ||
821 | } | ||
822 | } | ||
823 | } | ||
824 | |||
804 | iInt2 latestPosition_Touch(void) { | 825 | iInt2 latestPosition_Touch(void) { |
805 | return touchState_()->currentTouchPos; | 826 | return touchState_()->currentTouchPos; |
806 | } | 827 | } |
diff --git a/src/ui/touch.h b/src/ui/touch.h index e048224a..c9c76d86 100644 --- a/src/ui/touch.h +++ b/src/ui/touch.h | |||
@@ -39,6 +39,7 @@ void update_Touch (void); | |||
39 | float stopWidgetMomentum_Touch (const iWidget *widget); | 39 | float stopWidgetMomentum_Touch (const iWidget *widget); |
40 | enum iWidgetTouchMode widgetMode_Touch (const iWidget *widget); | 40 | enum iWidgetTouchMode widgetMode_Touch (const iWidget *widget); |
41 | void widgetDestroyed_Touch (iWidget *widget); | 41 | void widgetDestroyed_Touch (iWidget *widget); |
42 | void transferAffinity_Touch (iWidget *src, iWidget *dst); | ||
42 | 43 | ||
43 | iInt2 latestPosition_Touch (void); /* valid during processing of current event */ | 44 | iInt2 latestPosition_Touch (void); /* valid during processing of current event */ |
44 | iBool isHovering_Touch (void); /* stationary touch or a long-press drag ongoing */ | 45 | iBool isHovering_Touch (void); /* stationary touch or a long-press drag ongoing */ |
diff --git a/src/ui/widget.c b/src/ui/widget.c index 210fe899..0d20cca9 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -124,6 +124,7 @@ void init_Widget(iWidget *d) { | |||
124 | init_String(&d->id); | 124 | init_String(&d->id); |
125 | d->root = get_Root(); /* never changes after this */ | 125 | d->root = get_Root(); /* never changes after this */ |
126 | d->flags = 0; | 126 | d->flags = 0; |
127 | d->flags2 = 0; | ||
127 | d->rect = zero_Rect(); | 128 | d->rect = zero_Rect(); |
128 | d->minSize = zero_I2(); | 129 | d->minSize = zero_I2(); |
129 | d->sizeRef = NULL; | 130 | d->sizeRef = NULL; |
diff --git a/src/ui/widget.h b/src/ui/widget.h index 4025f5c5..35be1bcb 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h | |||
@@ -123,6 +123,10 @@ enum iWidgetFlag { | |||
123 | #define refChildrenOffset_WidgetFlag iBit64(63) /* visual offset determined by the offset of referenced children */ | 123 | #define refChildrenOffset_WidgetFlag iBit64(63) /* visual offset determined by the offset of referenced children */ |
124 | #define nativeMenu_WidgetFlag iBit64(64) | 124 | #define nativeMenu_WidgetFlag iBit64(64) |
125 | 125 | ||
126 | enum iWidgetFlag2 { | ||
127 | slidingSheetDraggable_WidgetFlag2 = iBit(1), | ||
128 | }; | ||
129 | |||
126 | enum iWidgetAddPos { | 130 | enum iWidgetAddPos { |
127 | back_WidgetAddPos, | 131 | back_WidgetAddPos, |
128 | front_WidgetAddPos, | 132 | front_WidgetAddPos, |
@@ -139,6 +143,7 @@ struct Impl_Widget { | |||
139 | iObject object; | 143 | iObject object; |
140 | iString id; | 144 | iString id; |
141 | int64_t flags; | 145 | int64_t flags; |
146 | int flags2; | ||
142 | iRect rect; | 147 | iRect rect; |
143 | iInt2 minSize; | 148 | iInt2 minSize; |
144 | iWidget * sizeRef; | 149 | iWidget * sizeRef; |