summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--po/en.po3
-rw-r--r--res/lang/cs.binbin31081 -> 31100 bytes
-rw-r--r--res/lang/de.binbin30088 -> 30107 bytes
-rw-r--r--res/lang/en.binbin26185 -> 26204 bytes
-rw-r--r--res/lang/eo.binbin25139 -> 25158 bytes
-rw-r--r--res/lang/es.binbin29912 -> 29931 bytes
-rw-r--r--res/lang/es_MX.binbin27244 -> 27263 bytes
-rw-r--r--res/lang/fi.binbin29745 -> 29764 bytes
-rw-r--r--res/lang/fr.binbin30892 -> 30911 bytes
-rw-r--r--res/lang/gl.binbin29097 -> 29116 bytes
-rw-r--r--res/lang/hu.binbin30917 -> 30936 bytes
-rw-r--r--res/lang/ia.binbin28244 -> 28263 bytes
-rw-r--r--res/lang/ie.binbin28832 -> 28851 bytes
-rw-r--r--res/lang/isv.binbin24905 -> 24924 bytes
-rw-r--r--res/lang/pl.binbin29520 -> 29539 bytes
-rw-r--r--res/lang/ru.binbin44280 -> 44299 bytes
-rw-r--r--res/lang/sk.binbin25241 -> 25260 bytes
-rw-r--r--res/lang/sr.binbin43706 -> 43725 bytes
-rw-r--r--res/lang/tok.binbin26954 -> 26973 bytes
-rw-r--r--res/lang/tr.binbin29138 -> 29157 bytes
-rw-r--r--res/lang/uk.binbin43625 -> 43644 bytes
-rw-r--r--res/lang/zh_Hans.binbin25139 -> 25158 bytes
-rw-r--r--res/lang/zh_Hant.binbin25337 -> 25356 bytes
-rw-r--r--src/ui/documentwidget.c6
-rw-r--r--src/ui/listwidget.c35
-rw-r--r--src/ui/listwidget.h8
-rw-r--r--src/ui/root.c106
-rw-r--r--src/ui/sidebarwidget.c271
-rw-r--r--src/ui/sidebarwidget.h1
-rw-r--r--src/ui/touch.c37
-rw-r--r--src/ui/touch.h1
-rw-r--r--src/ui/widget.c1
-rw-r--r--src/ui/widget.h5
33 files changed, 343 insertions, 131 deletions
diff --git a/po/en.po b/po/en.po
index 6b604d61..6996d28c 100644
--- a/po/en.po
+++ b/po/en.po
@@ -401,6 +401,9 @@ msgstr "Manage Identities"
401msgid "menu.identity.notactive" 401msgid "menu.identity.notactive"
402msgstr "No Active Identity" 402msgstr "No Active Identity"
403 403
404msgid "sidebar.close"
405msgstr "Done"
406
404msgid "sidebar.bookmarks" 407msgid "sidebar.bookmarks"
405msgstr "Bookmarks" 408msgstr "Bookmarks"
406 409
diff --git a/res/lang/cs.bin b/res/lang/cs.bin
index cf37c7de..a8981bd4 100644
--- a/res/lang/cs.bin
+++ b/res/lang/cs.bin
Binary files differ
diff --git a/res/lang/de.bin b/res/lang/de.bin
index a9d497d7..6d17ff3b 100644
--- a/res/lang/de.bin
+++ b/res/lang/de.bin
Binary files differ
diff --git a/res/lang/en.bin b/res/lang/en.bin
index 5e24ab94..4749f358 100644
--- a/res/lang/en.bin
+++ b/res/lang/en.bin
Binary files differ
diff --git a/res/lang/eo.bin b/res/lang/eo.bin
index 789c01c2..b3e06797 100644
--- a/res/lang/eo.bin
+++ b/res/lang/eo.bin
Binary files differ
diff --git a/res/lang/es.bin b/res/lang/es.bin
index 7ca8e297..2265ddf1 100644
--- a/res/lang/es.bin
+++ b/res/lang/es.bin
Binary files differ
diff --git a/res/lang/es_MX.bin b/res/lang/es_MX.bin
index 43a5bb77..810bc543 100644
--- a/res/lang/es_MX.bin
+++ b/res/lang/es_MX.bin
Binary files differ
diff --git a/res/lang/fi.bin b/res/lang/fi.bin
index 5a0ec586..ccc61bd4 100644
--- a/res/lang/fi.bin
+++ b/res/lang/fi.bin
Binary files differ
diff --git a/res/lang/fr.bin b/res/lang/fr.bin
index 329cae2b..355073bd 100644
--- a/res/lang/fr.bin
+++ b/res/lang/fr.bin
Binary files differ
diff --git a/res/lang/gl.bin b/res/lang/gl.bin
index 527de83b..30c5fb5f 100644
--- a/res/lang/gl.bin
+++ b/res/lang/gl.bin
Binary files differ
diff --git a/res/lang/hu.bin b/res/lang/hu.bin
index 82257541..90f32f47 100644
--- a/res/lang/hu.bin
+++ b/res/lang/hu.bin
Binary files differ
diff --git a/res/lang/ia.bin b/res/lang/ia.bin
index 5f1d7ab2..a9672e07 100644
--- a/res/lang/ia.bin
+++ b/res/lang/ia.bin
Binary files differ
diff --git a/res/lang/ie.bin b/res/lang/ie.bin
index 0d866d47..058ab7ff 100644
--- a/res/lang/ie.bin
+++ b/res/lang/ie.bin
Binary files differ
diff --git a/res/lang/isv.bin b/res/lang/isv.bin
index d30dcf4f..ccf1f206 100644
--- a/res/lang/isv.bin
+++ b/res/lang/isv.bin
Binary files differ
diff --git a/res/lang/pl.bin b/res/lang/pl.bin
index e9fd8460..d49b1fdd 100644
--- a/res/lang/pl.bin
+++ b/res/lang/pl.bin
Binary files differ
diff --git a/res/lang/ru.bin b/res/lang/ru.bin
index f8a69f51..cb2baebc 100644
--- a/res/lang/ru.bin
+++ b/res/lang/ru.bin
Binary files differ
diff --git a/res/lang/sk.bin b/res/lang/sk.bin
index 9d0e9f04..50ee11ce 100644
--- a/res/lang/sk.bin
+++ b/res/lang/sk.bin
Binary files differ
diff --git a/res/lang/sr.bin b/res/lang/sr.bin
index bbaba1e9..d27c1c48 100644
--- a/res/lang/sr.bin
+++ b/res/lang/sr.bin
Binary files differ
diff --git a/res/lang/tok.bin b/res/lang/tok.bin
index 517194d1..89e9526c 100644
--- a/res/lang/tok.bin
+++ b/res/lang/tok.bin
Binary files differ
diff --git a/res/lang/tr.bin b/res/lang/tr.bin
index e0aef190..ef7f8f61 100644
--- a/res/lang/tr.bin
+++ b/res/lang/tr.bin
Binary files differ
diff --git a/res/lang/uk.bin b/res/lang/uk.bin
index 0c261c00..cff8fb7d 100644
--- a/res/lang/uk.bin
+++ b/res/lang/uk.bin
Binary files differ
diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin
index d31b280b..e8dafce4 100644
--- a/res/lang/zh_Hans.bin
+++ b/res/lang/zh_Hans.bin
Binary files differ
diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin
index e06f4339..898bbddc 100644
--- a/res/lang/zh_Hant.bin
+++ b/res/lang/zh_Hant.bin
Binary files differ
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
191void setScrollMode_ListWidget(iListWidget *d, enum iScrollMode mode) {
192 d->scrollMode = mode;
193}
194
190void scrollOffset_ListWidget(iListWidget *d, int offset) { 195void 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
374static 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
369static iBool processEvent_ListWidget_(iListWidget *d, const SDL_Event *ev) { 390static 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
52iDeclareType(VisBuf) 52iDeclareType(VisBuf)
53 53
54enum iScrollMode {
55 normal_ScrollMode,
56 disabledAtTopBothDirections_ScrollMode,
57 disabledAtTopUpwards_ScrollMode,
58};
59
54struct Impl_ListWidget { 60struct 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 *);
82int scrollPos_ListWidget (const iListWidget *); 89int scrollPos_ListWidget (const iListWidget *);
83 90
84void setScrollPos_ListWidget (iListWidget *, int pos); 91void setScrollPos_ListWidget (iListWidget *, int pos);
92void setScrollMode_ListWidget (iListWidget *, enum iScrollMode mode);
85void scrollToItem_ListWidget (iListWidget *, size_t index, uint32_t span); 93void scrollToItem_ListWidget (iListWidget *, size_t index, uint32_t span);
86void scrollOffset_ListWidget (iListWidget *, int offset); 94void scrollOffset_ListWidget (iListWidget *, int offset);
87void scrollOffsetSpan_ListWidget (iListWidget *, int offset, uint32_t span); 95void 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
217static iBool isSlidingSheet_SidebarWidget_(const iSidebarWidget *d) {
218 return isPortraitPhone_App();// && scrollPos_ListWidget(d->list) <= 0;
219}
220
214static void updateItemsWithFlags_SidebarWidget_(iSidebarWidget *d, iBool keepActions) { 221static 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
629void setMidHeight_SidebarWidget(iSidebarWidget *d, int midHeight) {
630 d->midHeight = midHeight;
631}
632
620enum iSidebarMode mode_SidebarWidget(const iSidebarWidget *d) { 633enum 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
997static 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
1013enum iSlidingSheetPos {
1014 top_SlidingSheetPos,
1015 middle_SlidingSheetPos,
1016 bottom_SlidingSheetPos,
1017};
1018
1019static 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
985static iBool handleSidebarCommand_SidebarWidget_(iSidebarWidget *d, const char *cmd) { 1043static 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
1181static 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
1190static 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
1100static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) { 1199static 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
54void setWidth_SidebarWidget (iSidebarWidget *, float widthAsGaps); 54void setWidth_SidebarWidget (iSidebarWidget *, float widthAsGaps);
55iBool setButtonFont_SidebarWidget (iSidebarWidget *, int font); 55iBool setButtonFont_SidebarWidget (iSidebarWidget *, int font);
56void setClosedFolders_SidebarWidget (iSidebarWidget *, const iIntSet *closedFolders); 56void setClosedFolders_SidebarWidget (iSidebarWidget *, const iIntSet *closedFolders);
57void setMidHeight_SidebarWidget (iSidebarWidget *, int midHeight); /* phone layout */
57 58
58enum iSidebarMode mode_SidebarWidget (const iSidebarWidget *); 59enum iSidebarMode mode_SidebarWidget (const iSidebarWidget *);
59enum iFeedsMode feedsMode_SidebarWidget (const iSidebarWidget *); 60enum 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
815void 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
804iInt2 latestPosition_Touch(void) { 825iInt2 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);
39float stopWidgetMomentum_Touch (const iWidget *widget); 39float stopWidgetMomentum_Touch (const iWidget *widget);
40enum iWidgetTouchMode widgetMode_Touch (const iWidget *widget); 40enum iWidgetTouchMode widgetMode_Touch (const iWidget *widget);
41void widgetDestroyed_Touch (iWidget *widget); 41void widgetDestroyed_Touch (iWidget *widget);
42void transferAffinity_Touch (iWidget *src, iWidget *dst);
42 43
43iInt2 latestPosition_Touch (void); /* valid during processing of current event */ 44iInt2 latestPosition_Touch (void); /* valid during processing of current event */
44iBool isHovering_Touch (void); /* stationary touch or a long-press drag ongoing */ 45iBool 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
126enum iWidgetFlag2 {
127 slidingSheetDraggable_WidgetFlag2 = iBit(1),
128};
129
126enum iWidgetAddPos { 130enum 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;