diff options
Diffstat (limited to 'src/ui/sidebarwidget.c')
-rw-r--r-- | src/ui/sidebarwidget.c | 271 |
1 files changed, 215 insertions, 56 deletions
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)) { |