From b8c07107fa332651cf2281fe8d2f90dfc122b588 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Wed, 19 May 2021 14:20:58 +0300 Subject: Cleanup --- src/ui/widget.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/ui/widget.c') diff --git a/src/ui/widget.c b/src/ui/widget.c index 64f586ce..d31f7577 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -323,7 +323,6 @@ static iBool setWidth_Widget_(iWidget *d, int width) { d->rect.size.x = width; TRACE(d, "width has changed to %d", width); if (class_Widget(d)->sizeChanged) { - const int oldHeight = d->rect.size.y; class_Widget(d)->sizeChanged(d); } return iTrue; -- cgit v1.2.3 From 7a27cf99aecfb3112af1d61b908d62d1808f43e5 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 12 Jun 2021 20:02:32 +0300 Subject: Touch: Revising edge swiping events Edge swiping now has its own set of commands that are posted, allowing widgets to respond more flexibly. --- src/ui/mobile.c | 3 +-- src/ui/touch.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++-------- src/ui/util.c | 1 + src/ui/widget.c | 30 +++++++++++++++++++--- 4 files changed, 96 insertions(+), 16 deletions(-) (limited to 'src/ui/widget.c') diff --git a/src/ui/mobile.c b/src/ui/mobile.c index 580cc355..7794d686 100644 --- a/src/ui/mobile.c +++ b/src/ui/mobile.c @@ -150,8 +150,7 @@ static iBool topPanelHandler_(iWidget *topPanel, const char *cmd) { setFlags_Widget(button, selected_WidgetFlag, iTrue); return iTrue; } - if (equal_Command(cmd, "mouse.clicked") && arg_Command(cmd) && - argLabel_Command(cmd, "button") == SDL_BUTTON_X1) { + if (equal_Command(cmd, "swipe.back")) { postCommand_App("panel.close"); return iTrue; } diff --git a/src/ui/touch.c b/src/ui/touch.c index 74a22baf..c7c5a410 100644 --- a/src/ui/touch.c +++ b/src/ui/touch.c @@ -40,6 +40,10 @@ iDeclareType(TouchState) #define numHistory_Touch_ 5 #define lastIndex_Touch_ (numHistory_Touch_ - 1) +static const uint32_t longPressSpanMs_ = 500; +static const uint32_t shortPressSpanMs_ = 250; +static const int tapRadiusPt_ = 10; + enum iTouchEdge { none_TouchEdge, left_TouchEdge, @@ -55,7 +59,7 @@ enum iTouchAxis { struct Impl_Touch { SDL_FingerID id; iWidget *affinity; /* widget on which the touch started */ - iWidget *edgeDragging; +// iWidget *edgeDragging; iBool hasMoved; iBool isTapBegun; iBool isLeftDown; @@ -132,9 +136,6 @@ static iTouch *find_TouchState_(iTouchState *d, SDL_FingerID id) { return NULL; } -static const uint32_t longPressSpanMs_ = 500; -static const int tapRadiusPt_ = 10; - iLocalDef float distance_Touch_(const iTouch *d) { return length_F3(sub_F3(d->pos[0], d->startPos)); } @@ -246,6 +247,11 @@ iLocalDef double accurateTicks_(void) { return 1000.0 * (double) count / (double) freq; } +static iFloat3 gestureVector_Touch_(const iTouch *d) { + const size_t lastIndex = iMin(d->posCount - 1, lastIndex_Touch_); + return sub_F3(d->pos[0], d->pos[lastIndex]); +} + static void update_TouchState_(void *ptr) { iTouchState *d = ptr; /* Check for long presses to simulate right clicks. */ @@ -255,6 +261,22 @@ static void update_TouchState_(void *ptr) { if (touch->pinchId || touch->isTouchDrag) { continue; } + if (touch->edge) { + const iFloat3 pos = touch->pos[0]; + /* Cancel the swipe if the finger doesn't move or moves mostly vertically. */ + const iFloat3 gestureVector = gestureVector_Touch_(touch); + if (fabsf(2 * x_F3(gestureVector)) < fabsf(y_F3(gestureVector)) || + (isStationary_Touch_(touch) && nowTime - touch->startTime > shortPressSpanMs_)) { + //const int swipeDir = x_F3(gestureVector) > 0 ? +1 : -1; + //dispatchClick_Touch_(touch, +// touch->edge == left_TouchEdge && swipeDir > 0 ? SDL_BUTTON_X1 : +// touch->edge == right_TouchEdge && swipeDir < 0 ? SDL_BUTTON_X2 : 0); +// setHover_Widget(NULL); + postCommandf_App("edgeswipe.ended abort:1 side:%d id:%llu", touch->edge, touch->id); + touch->edge = none_TouchEdge; + } + else continue; + } /* Holding a touch will reset previous momentum for this widget. */ if (isStationary_Touch_(touch)) { const int elapsed = nowTime - touch->startTime; @@ -450,8 +472,10 @@ iBool processEvent_Touch(const SDL_Event *ev) { } else if (x > rootSize.x - edgeWidth) { edge = right_TouchEdge; +// puts("DOWN on right edge"); } iWidget *aff = hitChild_Window(window, init_I2(iRound(x), iRound(y_F3(pos)))); +#if 0 if (edge == left_TouchEdge) { dragging = findSlidePanel_Widget_(aff); if (dragging) { @@ -460,6 +484,7 @@ iBool processEvent_Touch(const SDL_Event *ev) { setFlags_Widget(dragging, dragged_WidgetFlag, iTrue); } } +#endif /* TODO: We must retain a reference to the affinity widget, or otherwise it might be destroyed during the gesture. */ // printf("aff:[%p] %s:'%s'\n", aff, aff ? class_Widget(aff)->name : "-", @@ -469,7 +494,7 @@ iBool processEvent_Touch(const SDL_Event *ev) { iTouch newTouch = { .id = fing->fingerId, .affinity = aff, - .edgeDragging = dragging, +// .edgeDragging = dragging, .didBeginOnTouchDrag = (flags_Widget(aff) & touchDrag_WidgetFlag) != 0, .edge = edge, .startTime = nowTime, @@ -487,6 +512,14 @@ iBool processEvent_Touch(const SDL_Event *ev) { } else if (ev->type == SDL_FINGERMOTION) { iTouch *touch = find_TouchState_(d, fing->fingerId); + if (touch && touch->edge) { + pushPos_Touch_(touch, pos, nowTime); + postCommandf_App("edgeswipe.moved arg:%d side:%d id:%llu", + (int) (x_F3(pos) - x_F3(touch->startPos)), + touch->edge, + touch->id); + return iTrue; + } if (touch && touch->affinity) { if (touch->isTouchDrag) { dispatchMotion_Touch_(pos, SDL_BUTTON_LMASK); @@ -556,6 +589,8 @@ iBool processEvent_Touch(const SDL_Event *ev) { touch->axis = y_TouchAxis; } } + iAssert(touch->edge == none_TouchEdge); +#if 0 /* Edge swipe aborted? */ if (touch->edge == left_TouchEdge) { if (fing->dx < 0 && x_F3(touch->pos[0]) < tapRadiusPt_ * window->pixelRatio) { @@ -570,22 +605,35 @@ iBool processEvent_Touch(const SDL_Event *ev) { setVisualOffset_Widget(touch->edgeDragging, x_F3(pos) - x_F3(touch->startPos), 10, 0); } } - if (touch->edge == right_TouchEdge && fing->dx > 0) { - touch->edge = none_TouchEdge; + if (touch->edge == right_TouchEdge) { + if (fing->dx > 0 && x_F3(touch->pos[0]) > window->size.x - tapRadiusPt_ * window->pixelRatio) { + puts("touch->edge==right returned to right edge, aborted"); + touch->edge = none_TouchEdge; + if (touch->edgeDragging) { + setFlags_Widget(touch->edgeDragging, dragged_WidgetFlag, iFalse); + setVisualOffset_Widget(touch->edgeDragging, 0, 200, easeOut_AnimFlag); + touch->edgeDragging = NULL; + } + } + else if (touch->edgeDragging) { + setVisualOffset_Widget(touch->edgeDragging, x_F3(pos) - x_F3(touch->startPos), 10, 0); + } } if (touch->edge) { pixels.y = 0; } +#endif if (touch->axis == x_TouchAxis) { pixels.y = 0; } if (touch->axis == y_TouchAxis) { pixels.x = 0; } -// printf("%p (%s) py: %i wy: %f acc: %f\n", +// printf("%p (%s) py: %i wy: %f acc: %f edge: %d\n", // touch->affinity, // class_Widget(touch->affinity)->name, -// pixels.y, y_F3(amount), y_F3(touch->accum)); +// pixels.y, y_F3(amount), y_F3(touch->accum), +// touch->edge); if (pixels.x || pixels.y) { setFocus_Widget(NULL); dispatchMotion_Touch_(touch->pos[0], 0); @@ -612,9 +660,16 @@ iBool processEvent_Touch(const SDL_Event *ev) { endPinch_TouchState_(d, touch->pinchId); break; } +#if 0 if (touch->edgeDragging) { setFlags_Widget(touch->edgeDragging, dragged_WidgetFlag, iFalse); } +#endif + if (touch->edge && !isStationary_Touch_(touch)) { + postCommandf_App("edgeswipe.ended side:%d id:%llu", touch->edge, touch->id); + remove_ArrayIterator(&i); + continue; + } if (flags_Widget(touch->affinity) & touchDrag_WidgetFlag) { if (!touch->isLeftDown && !touch->isTapAndHold) { /* This will be a click on a touchDrag widget. */ @@ -638,6 +693,7 @@ iBool processEvent_Touch(const SDL_Event *ev) { const uint32_t duration = nowTime - touch->startTime; const iFloat3 gestureVector = sub_F3(pos, touch->pos[lastIndex]); iFloat3 velocity = zero_F3(); +#if 0 if (touch->edge && fabsf(2 * x_F3(gestureVector)) > fabsf(y_F3(gestureVector)) && !isStationary_Touch_(touch)) { const int swipeDir = x_F3(gestureVector) > 0 ? +1 : -1; @@ -646,7 +702,9 @@ iBool processEvent_Touch(const SDL_Event *ev) { touch->edge == right_TouchEdge && swipeDir < 0 ? SDL_BUTTON_X2 : 0); setHover_Widget(NULL); } - else { + else +#endif + { const uint32_t elapsed = fing->timestamp - touch->posTime[lastIndex]; const float minVelocity = 400.0f; if (elapsed < 150) { diff --git a/src/ui/util.c b/src/ui/util.c index 6c6e62a5..9cc848de 100644 --- a/src/ui/util.c +++ b/src/ui/util.c @@ -1326,6 +1326,7 @@ static iBool messageHandler_(iWidget *msg, const char *cmd) { equal_Command(cmd, "document.request.updated") || equal_Command(cmd, "scrollbar.fade") || equal_Command(cmd, "widget.overflow") || + equal_Command(cmd, "edgeswipe.ended") || startsWith_CStr(cmd, "window."))) { setupSheetTransition_Mobile(msg, iFalse); destroy_Widget(msg); diff --git a/src/ui/widget.c b/src/ui/widget.c index 4eac7ecf..bedcb146 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -1056,10 +1056,32 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { isCommand_UserEvent(ev, "widget.overflow")) { scrollOverflow_Widget(d, 0); /* check bounds */ } - if (ev->user.code == command_UserEventCode && d->commandHandler && - d->commandHandler(d, ev->user.data1)) { - iAssert(get_Root() == d->root); - return iTrue; + if (ev->user.code == command_UserEventCode) { + const char *cmd = command_UserEvent(ev); + if (d->flags & edgeDraggable_WidgetFlag && + isVisible_Widget(d) && + ~d->flags & disabled_WidgetFlag && + equal_Command(cmd, "edgeswipe.moved")) { + if (~d->flags & dragged_WidgetFlag) { + setFlags_Widget(d, dragged_WidgetFlag, iTrue); + } + setVisualOffset_Widget(d, arg_Command(command_UserEvent(ev)), 10, 0); + return iTrue; + } + if (d->flags & dragged_WidgetFlag && equal_Command(cmd, "edgeswipe.ended")) { + if (argLabel_Command(cmd, "abort")) { + setVisualOffset_Widget(d, 0, 200, easeOut_AnimFlag); + setFlags_Widget(d, dragged_WidgetFlag, iFalse); + } + else { + postCommand_Widget( + d, argLabel_Command(cmd, "side") == 1 ? "swipe.back" : "swipe.forward"); + } + } + if (d->commandHandler && d->commandHandler(d, ev->user.data1)) { + iAssert(get_Root() == d->root); + return iTrue; + } } break; } -- cgit v1.2.3 From d24775473c5e95043481457b061660caac8a1524 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sun, 13 Jun 2021 06:52:36 +0300 Subject: Touch: Swiping away the sidebar --- src/ui/mobile.c | 4 ++-- src/ui/root.c | 4 ++-- src/ui/sidebarwidget.c | 34 ++++++++++++++++++++-------------- src/ui/sidebarwidget.h | 4 ++-- src/ui/touch.c | 5 ++++- src/ui/util.c | 2 +- src/ui/widget.c | 18 +++++++++++------- src/ui/widget.h | 4 ++-- 8 files changed, 44 insertions(+), 31 deletions(-) (limited to 'src/ui/widget.c') diff --git a/src/ui/mobile.c b/src/ui/mobile.c index 7794d686..1bf289a7 100644 --- a/src/ui/mobile.c +++ b/src/ui/mobile.c @@ -120,7 +120,7 @@ static iBool mainDetailSplitHandler_(iWidget *mainDetailSplit, const char *cmd) } iForEach(ObjectList, i, children_Widget(detailStack)) { iWidget *panel = i.object; - setFlags_Widget(panel, edgeDraggable_WidgetFlag, !isSideBySide); + setFlags_Widget(panel, leftEdgeDraggable_WidgetFlag, !isSideBySide); if (isSideBySide) { setVisualOffset_Widget(panel, 0, 0, 0); } @@ -414,7 +414,7 @@ void finalizeSheet_Mobile(iWidget *sheet) { setFlags_Widget(sheet, frameless_WidgetFlag | //resizeWidthOfChildren_WidgetFlag | - edgeDraggable_WidgetFlag | + leftEdgeDraggable_WidgetFlag | commandOnClick_WidgetFlag, iTrue); iPtrArray * contents = collect_PtrArray(new_PtrArray()); /* two-column pages */ diff --git a/src/ui/root.c b/src/ui/root.c index 76f4c0d7..2d69970d 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -1185,9 +1185,9 @@ void createUserInterface_Root(iRoot *d) { } /* Sidebars. */ { iWidget *content = findChild_Widget(root, "tabs.content"); - iSidebarWidget *sidebar1 = new_SidebarWidget(left_SideBarSide); + iSidebarWidget *sidebar1 = new_SidebarWidget(left_SidebarSide); addChildPos_Widget(content, iClob(sidebar1), front_WidgetAddPos); - iSidebarWidget *sidebar2 = new_SidebarWidget(right_SideBarSide); + iSidebarWidget *sidebar2 = new_SidebarWidget(right_SidebarSide); if (deviceType_App() != phone_AppDeviceType) { addChildPos_Widget(content, iClob(sidebar2), back_WidgetAddPos); } diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 2e1e138e..4f3ea637 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -625,7 +625,7 @@ static void updateMetrics_SidebarWidget_(iSidebarWidget *d) { void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { iWidget *w = as_Widget(d); init_Widget(w); - setId_Widget(w, side == left_SideBarSide ? "sidebar" : "sidebar2"); + setId_Widget(w, side == left_SidebarSide ? "sidebar" : "sidebar2"); initCopy_String(&d->cmdPrefix, id_Widget(w)); appendChar_String(&d->cmdPrefix, '.'); setBackgroundColor_Widget(w, none_ColorId); @@ -659,7 +659,7 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { d->actions = NULL; /* On a phone, the right sidebar is used exclusively for Identities. */ const iBool isPhone = deviceType_App() == phone_AppDeviceType; - if (!isPhone || d->side == left_SideBarSide) { + if (!isPhone || d->side == left_SidebarSide) { iWidget *buttons = new_Widget(); setId_Widget(buttons, "buttons"); for (int i = 0; i < max_SidebarMode; i++) { @@ -715,24 +715,24 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { addChildFlags_Widget(content, iClob(d->blank), resizeChildren_WidgetFlag); addChildFlags_Widget(vdiv, iClob(content), expand_WidgetFlag); setMode_SidebarWidget(d, - deviceType_App() == phone_AppDeviceType && d->side == right_SideBarSide ? + deviceType_App() == phone_AppDeviceType && d->side == right_SidebarSide ? identities_SidebarMode : bookmarks_SidebarMode); d->resizer = addChildFlags_Widget(w, iClob(new_Widget()), hover_WidgetFlag | commandOnClick_WidgetFlag | fixedWidth_WidgetFlag | resizeToParentHeight_WidgetFlag | - (side == left_SideBarSide ? moveToParentRightEdge_WidgetFlag + (side == left_SidebarSide ? moveToParentRightEdge_WidgetFlag : moveToParentLeftEdge_WidgetFlag)); if (deviceType_App() == phone_AppDeviceType) { setFlags_Widget(d->resizer, hidden_WidgetFlag | disabled_WidgetFlag, iTrue); } - setId_Widget(d->resizer, side == left_SideBarSide ? "sidebar.grab" : "sidebar2.grab"); + setId_Widget(d->resizer, side == left_SidebarSide ? "sidebar.grab" : "sidebar2.grab"); setBackgroundColor_Widget(d->resizer, none_ColorId); d->menu = NULL; addAction_Widget(w, SDLK_r, KMOD_PRIMARY | KMOD_SHIFT, "feeds.refresh"); updateMetrics_SidebarWidget_(d); - if (side == left_SideBarSide) { + if (side == left_SidebarSide) { postCommand_App("~sidebar.update"); /* unread count */ } } @@ -799,7 +799,7 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, iSidebarItem *item, si updateContextMenu_SidebarWidget_(d); arrange_Widget(d->menu); openMenu_Widget(d->menu, - d->side == left_SideBarSide + d->side == left_SidebarSide ? topRight_Rect(itemRect_ListWidget(d->list, itemIndex)) : addX_I2(topLeft_Rect(itemRect_ListWidget(d->list, itemIndex)), -width_Widget(d->menu))); @@ -857,7 +857,7 @@ void setWidth_SidebarWidget(iSidebarWidget *d, float widthAsGaps) { if (!isFixedWidth) { /* Even less space if the other sidebar is visible, too. */ const int otherWidth = - width_Widget(findWidget_App(d->side == left_SideBarSide ? "sidebar2" : "sidebar")); + width_Widget(findWidget_App(d->side == left_SidebarSide ? "sidebar2" : "sidebar")); width = iClamp(width, 30 * gap_UI, size_Root(w->root).x - 50 * gap_UI - otherWidth); } d->widthAsGaps = (float) width / (float) gap_UI; @@ -938,7 +938,7 @@ static iBool handleSidebarCommand_SidebarWidget_(iSidebarWidget *d, const char * } const iBool isAnimated = prefs_App()->uiAnimations && argLabel_Command(cmd, "noanim") == 0 && - (d->side == left_SideBarSide || deviceType_App() != phone_AppDeviceType); + (d->side == left_SidebarSide || deviceType_App() != phone_AppDeviceType); int visX = 0; if (isVisible_Widget(w)) { visX = left_Rect(bounds_Widget(w)) - left_Rect(w->root->widget->rect); @@ -950,13 +950,13 @@ static iBool handleSidebarCommand_SidebarWidget_(iSidebarWidget *d, const char * invalidate_ListWidget(d->list); if (isAnimated) { setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue); - setVisualOffset_Widget(w, (d->side == left_SideBarSide ? -1 : 1) * w->rect.size.x, 0, 0); + setVisualOffset_Widget(w, (d->side == left_SidebarSide ? -1 : 1) * w->rect.size.x, 0, 0); setVisualOffset_Widget(w, 0, 300, easeOut_AnimFlag | softer_AnimFlag); } } else if (isAnimated) { setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue); - if (d->side == right_SideBarSide) { + if (d->side == right_SidebarSide) { setVisualOffset_Widget(w, visX, 0, 0); setVisualOffset_Widget(w, visX + w->rect.size.x, 300, easeOut_AnimFlag | softer_AnimFlag); } @@ -984,7 +984,8 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) /* Handle commands. */ if (isResize_UserEvent(ev)) { checkModeButtonLayout_SidebarWidget_(d); - if (deviceType_App() == phone_AppDeviceType && d->side == left_SideBarSide) { + if (deviceType_App() == phone_AppDeviceType && d->side == left_SidebarSide) { + setFlags_Widget(w, rightEdgeDraggable_WidgetFlag, isPortrait_App()); /* In landscape, visibility of the toolbar is controlled separately. */ if (isVisible_Widget(w)) { postCommand_Widget(w, "sidebar.toggle"); @@ -1038,6 +1039,11 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) postCommandf_App("sidebar.mode arg:%d toggle:1", identities_SidebarMode); return iTrue; } + else if (isPortraitPhone_App() && isVisible_Widget(w) && d->side == left_SidebarSide && + equal_Command(cmd, "swipe.forward")) { + postCommand_App("sidebar.toggle"); + return iTrue; + } else if (startsWith_CStr(cmd, cstr_String(&d->cmdPrefix))) { if (handleSidebarCommand_SidebarWidget_(d, cmd + size_String(&d->cmdPrefix))) { return iTrue; @@ -1068,7 +1074,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) const int resMid = d->resizer->rect.size.x / 2; setWidth_SidebarWidget( d, - ((d->side == left_SideBarSide + ((d->side == left_SidebarSide ? inner.x : (right_Rect(rect_Root(w->root)) - coord_Command(cmd).x)) + resMid) / (float) gap_UI); @@ -1547,7 +1553,7 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) { if (isVisible_Widget(w)) { drawVLine_Paint( &p, - addX_I2(d->side == left_SideBarSide ? topRight_Rect(bounds) : topLeft_Rect(bounds), -1), + addX_I2(d->side == left_SidebarSide ? topRight_Rect(bounds) : topLeft_Rect(bounds), -1), height_Rect(bounds), uiSeparator_ColorId); } diff --git a/src/ui/sidebarwidget.h b/src/ui/sidebarwidget.h index 2e418aa4..130242ab 100644 --- a/src/ui/sidebarwidget.h +++ b/src/ui/sidebarwidget.h @@ -36,8 +36,8 @@ enum iSidebarMode { const char * icon_SidebarMode (enum iSidebarMode mode); enum iSidebarSide { - left_SideBarSide, - right_SideBarSide, + left_SidebarSide, + right_SidebarSide, }; enum iFeedsMode { diff --git a/src/ui/touch.c b/src/ui/touch.c index c7c5a410..236601e8 100644 --- a/src/ui/touch.c +++ b/src/ui/touch.c @@ -274,8 +274,9 @@ static void update_TouchState_(void *ptr) { // setHover_Widget(NULL); postCommandf_App("edgeswipe.ended abort:1 side:%d id:%llu", touch->edge, touch->id); touch->edge = none_TouchEdge; + remove_ArrayIterator(&i); } - else continue; + continue; } /* Holding a touch will reset previous momentum for this widget. */ if (isStationary_Touch_(touch)) { @@ -362,6 +363,7 @@ static void update_TouchState_(void *ptr) { } } +#if 0 static iWidget *findSlidePanel_Widget_(iWidget *d) { for (iWidget *w = d; w; w = parent_Widget(w)) { if (isVisible_Widget(w) && flags_Widget(w) & edgeDraggable_WidgetFlag) { @@ -370,6 +372,7 @@ static iWidget *findSlidePanel_Widget_(iWidget *d) { } return NULL; } +#endif static void checkNewPinch_TouchState_(iTouchState *d, iTouch *newTouch) { iWidget *affinity = newTouch->affinity; diff --git a/src/ui/util.c b/src/ui/util.c index 9cc848de..f2449096 100644 --- a/src/ui/util.c +++ b/src/ui/util.c @@ -1317,7 +1317,7 @@ void updateValueInput_Widget(iWidget *d, const char *title, const char *prompt) static iBool messageHandler_(iWidget *msg, const char *cmd) { /* Almost any command dismisses the sheet. */ - /* TODO: Use a "notification" prefix (like `) to ignore all types of commands line this? */ + /* TODO: Add a "notification" type of user events to separate them from user actions. */ if (!(equal_Command(cmd, "media.updated") || equal_Command(cmd, "media.player.update") || equal_Command(cmd, "bookmarks.request.finished") || diff --git a/src/ui/widget.c b/src/ui/widget.c index bedcb146..f1d1dae4 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -1058,15 +1058,19 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { } if (ev->user.code == command_UserEventCode) { const char *cmd = command_UserEvent(ev); - if (d->flags & edgeDraggable_WidgetFlag && - isVisible_Widget(d) && - ~d->flags & disabled_WidgetFlag && + if (d->flags & (leftEdgeDraggable_WidgetFlag | rightEdgeDraggable_WidgetFlag) && + isVisible_Widget(d) && ~d->flags & disabled_WidgetFlag && equal_Command(cmd, "edgeswipe.moved")) { - if (~d->flags & dragged_WidgetFlag) { - setFlags_Widget(d, dragged_WidgetFlag, iTrue); + /* Check the side. */ + const int side = argLabel_Command(cmd, "side"); + if ((side == 1 && d->flags & leftEdgeDraggable_WidgetFlag) || + (side == 2 && d->flags & rightEdgeDraggable_WidgetFlag)) { + if (~d->flags & dragged_WidgetFlag) { + setFlags_Widget(d, dragged_WidgetFlag, iTrue); + } + setVisualOffset_Widget(d, arg_Command(command_UserEvent(ev)), 10, 0); + return iTrue; } - setVisualOffset_Widget(d, arg_Command(command_UserEvent(ev)), 10, 0); - return iTrue; } if (d->flags & dragged_WidgetFlag && equal_Command(cmd, "edgeswipe.ended")) { if (argLabel_Command(cmd, "abort")) { diff --git a/src/ui/widget.h b/src/ui/widget.h index 8de62b7a..7255b975 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h @@ -87,7 +87,7 @@ enum iWidgetFlag { }; /* 64-bit extended flags */ -//#define wasCollapsed_WidgetFlag iBit64(32) +#define rightEdgeDraggable_WidgetFlag iBit64(32) #define disabledWhenHidden_WidgetFlag iBit64(32) #define centerHorizontal_WidgetFlag iBit64(33) #define moveToParentLeftEdge_WidgetFlag iBit64(34) @@ -118,7 +118,7 @@ enum iWidgetFlag { #define ignoreForParentWidth_WidgetFlag iBit64(59) #define noFadeBackground_WidgetFlag iBit64(60) #define destroyPending_WidgetFlag iBit64(61) /* TODO: needed? */ -#define edgeDraggable_WidgetFlag iBit64(62) +#define leftEdgeDraggable_WidgetFlag iBit64(62) #define refChildrenOffset_WidgetFlag iBit64(63) /* visual offset determined by the offset of referenced children */ enum iWidgetAddPos { -- cgit v1.2.3 From eb04ac7a1921b7c7f534a7a63cffc4c7a35c0900 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sun, 13 Jun 2021 15:28:58 +0300 Subject: Mobile: Working on swipe navigation Swipes back and forward are now working, although there are some glitches remaining. Most notably, when swiping back the previous document does not appear until the finger is released. --- src/history.c | 30 ++++++++++ src/history.h | 2 + src/ui/documentwidget.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++- src/ui/mobile.c | 2 +- src/ui/root.c | 13 +++-- src/ui/touch.c | 6 +- src/ui/widget.c | 15 ++++- src/ui/widget.h | 2 + 8 files changed, 202 insertions(+), 12 deletions(-) (limited to 'src/ui/widget.c') diff --git a/src/history.c b/src/history.c index 740830e9..f6ad4771 100644 --- a/src/history.c +++ b/src/history.c @@ -284,6 +284,36 @@ void add_History(iHistory *d, const iString *url ){ unlock_Mutex(d->mtx); } +iBool preceding_History(iHistory *d, iRecentUrl *recent_out) { + iBool ok = iFalse; + lock_Mutex(d->mtx); + if (!isEmpty_Array(&d->recent) && d->recentPos < size_Array(&d->recent) - 1) { + const iRecentUrl *recent = constAt_Array(&d->recent, d->recentPos + 1); + set_String(&recent_out->url, &recent->url); + recent_out->normScrollY = recent->normScrollY; + recent_out->cachedDoc = ref_Object(recent->cachedDoc); + /* Cached response is not returned, would involve a deep copy. */ + ok = iTrue; + } + unlock_Mutex(d->mtx); + return ok; +} + +iBool following_History(iHistory *d, iRecentUrl *recent_out) { + iBool ok = iFalse; + lock_Mutex(d->mtx); + if (!isEmpty_Array(&d->recent) && d->recentPos > 0) { + const iRecentUrl *recent = constAt_Array(&d->recent, d->recentPos - 1); + set_String(&recent_out->url, &recent->url); + recent_out->normScrollY = recent->normScrollY; + recent_out->cachedDoc = ref_Object(recent->cachedDoc); + /* Cached response is not returned, would involve a deep copy. */ + ok = iTrue; + } + unlock_Mutex(d->mtx); + return ok; +} + iBool goBack_History(iHistory *d) { lock_Mutex(d->mtx); if (!isEmpty_Array(&d->recent) && d->recentPos < size_Array(&d->recent) - 1) { diff --git a/src/history.h b/src/history.h index eb35b1df..9c900b82 100644 --- a/src/history.h +++ b/src/history.h @@ -63,6 +63,8 @@ void setCachedResponse_History (iHistory *, const iGmResponse *response void setCachedDocument_History (iHistory *, iGmDocument *doc); iBool goBack_History (iHistory *); iBool goForward_History (iHistory *); +iBool preceding_History (iHistory *d, iRecentUrl *recent_out); +iBool following_History (iHistory *d, iRecentUrl *recent_out); iRecentUrl *recentUrl_History (iHistory *, size_t pos); iRecentUrl *mostRecentUrl_History (iHistory *); iRecentUrl *findUrl_History (iHistory *, const iString *url); diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 936c3cb7..70201d7b 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -315,6 +315,10 @@ void init_DocumentWidget(iDocumentWidget *d) { init_Widget(w); setId_Widget(w, format_CStr("document%03d", ++docEnum_)); setFlags_Widget(w, hover_WidgetFlag | noBackground_WidgetFlag, iTrue); + if (deviceType_App() != desktop_AppDeviceType) { + setFlags_Widget(w, leftEdgeDraggable_WidgetFlag | rightEdgeDraggable_WidgetFlag | + horizontalOffset_WidgetFlag, iTrue); + } init_PersistentDocumentState(&d->mod); d->flags = 0; d->phoneToolbar = NULL; @@ -977,6 +981,9 @@ static void updateTimestampBuf_DocumentWidget_(const iDocumentWidget *d) { } static void invalidate_DocumentWidget_(iDocumentWidget *d) { + if (flags_Widget(as_Widget(d)) & destroyPending_WidgetFlag) { + return; + } invalidate_VisBuf(d->visBuf); clear_PtrSet(d->invalidRuns); } @@ -2237,6 +2244,133 @@ static iBool handlePinch_DocumentWidget_(iDocumentWidget *d, const char *cmd) { return iTrue; } +static void swap_DocumentWidget_(iDocumentWidget *d, iGmDocument *doc, + iDocumentWidget *swapBuffersWith) { + if (doc) { + iAssert(isInstance_Object(doc, &Class_GmDocument)); + iGmDocument *copy = ref_Object(doc); + iRelease(d->doc); + d->doc = copy; + d->scrollY = swapBuffersWith->scrollY; + updateVisible_DocumentWidget_(d); + iSwap(iVisBuf *, d->visBuf, swapBuffersWith->visBuf); + iSwap(iVisBufMeta *, d->visBufMeta, swapBuffersWith->visBufMeta); + iSwap(iDrawBufs *, d->drawBufs, swapBuffersWith->drawBufs); + invalidate_DocumentWidget_(swapBuffersWith); + } +} + +static iWidget *swipeParent_DocumentWidget_(iDocumentWidget *d) { + return findChild_Widget(as_Widget(d)->root->widget, "doctabs"); +} + +static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { + iWidget *w = as_Widget(d); + if (equal_Command(cmd, "edgeswipe.moved")) { + as_Widget(d)->offsetRef = NULL; + const int side = argLabel_Command(cmd, "side"); + const int offset = arg_Command(cmd); + if (side == 1) { + if (atOldest_History(d->mod.history)) { + return iTrue; + } + iWidget *swipeParent = swipeParent_DocumentWidget_(d); + /* The temporary "swipeIn" will display the previous page until the finger is lifted. */ + iDocumentWidget *swipeIn = findChild_Widget(swipeParent, "swipein"); + if (!swipeIn) { + swipeIn = new_DocumentWidget(); + setId_Widget(as_Widget(swipeIn), "swipein"); + setFlags_Widget(as_Widget(swipeIn), + disabled_WidgetFlag | refChildrenOffset_WidgetFlag | + fixedPosition_WidgetFlag | fixedSize_WidgetFlag, iTrue); + swipeIn->widget.rect.pos = windowToInner_Widget(swipeParent, localToWindow_Widget(w, w->rect.pos)); + swipeIn->widget.rect.size = d->widget.rect.size; + swipeIn->widget.offsetRef = w; + iRecentUrl *recent = new_RecentUrl(); + preceding_History(d->mod.history, recent); + if (recent->cachedDoc) { + iChangeRef(swipeIn->doc, recent->cachedDoc); + updateScrollMax_DocumentWidget_(d); + setValue_Anim(&swipeIn->scrollY.pos, size_GmDocument(swipeIn->doc).y * recent->normScrollY, 0); + updateVisible_DocumentWidget_(swipeIn); + } + delete_RecentUrl(recent); + addChildPos_Widget(swipeParent, iClob(swipeIn), front_WidgetAddPos); + } + } + if (side == 2) { + if (offset < -get_Window()->pixelRatio * 10) { + if (!atLatest_History(d->mod.history) && + ~flags_Widget(w) & dragged_WidgetFlag) { + postCommand_Widget(d, "navigate.forward"); + setFlags_Widget(w, dragged_WidgetFlag, iTrue); + /* Set up the swipe dummy. */ + iWidget *swipeParent = swipeParent_DocumentWidget_(d); + iDocumentWidget *target = new_DocumentWidget(); + setId_Widget(as_Widget(target), "swipeout"); + /* The target takes the old document and jumps on top. */ + target->widget.rect.pos = windowToInner_Widget(swipeParent, localToWindow_Widget(w, w->rect.pos)); + target->widget.rect.size = d->widget.rect.size; + setFlags_Widget(as_Widget(target), fixedPosition_WidgetFlag | fixedSize_WidgetFlag, iTrue); + swap_DocumentWidget_(target, d->doc, d); + addChildPos_Widget(swipeParent, iClob(target), front_WidgetAddPos); + setFlags_Widget(as_Widget(target), refChildrenOffset_WidgetFlag, iTrue); + as_Widget(target)->offsetRef = parent_Widget(w); + destroy_Widget(as_Widget(target)); /* will be actually deleted after animation finishes */ + } + if (flags_Widget(w) & dragged_WidgetFlag) { + setVisualOffset_Widget(w, width_Widget(w) + offset, 10, 0); + } + else { + setVisualOffset_Widget(w, offset / 4, 10, 0); + } + } + return iTrue; + } + } + if (equal_Command(cmd, "edgeswipe.ended") && argLabel_Command(cmd, "side") == 2) { + if (argLabel_Command(cmd, "abort") && flags_Widget(w) & dragged_WidgetFlag) { + postCommand_Widget(d, "navigate.back"); + } + setFlags_Widget(w, dragged_WidgetFlag, iFalse); + setVisualOffset_Widget(w, 0, 100, 0); + return iTrue; + } + if (equal_Command(cmd, "edgeswipe.ended") && argLabel_Command(cmd, "side") == 1) { + iWidget *swipeParent = swipeParent_DocumentWidget_(d); + iWidget *swipeIn = findChild_Widget(swipeParent, "swipein"); + if (swipeIn) { + swipeIn->offsetRef = NULL; + destroy_Widget(swipeIn); + } + } + if (equal_Command(cmd, "swipe.back")) { + if (atOldest_History(d->mod.history)) { + setVisualOffset_Widget(w, 0, 100, 0); + return iTrue; + } + iWidget *swipeParent = swipeParent_DocumentWidget_(d); + iDocumentWidget *target = new_DocumentWidget(); + setId_Widget(as_Widget(target), "swipeout"); + /* The target takes the old document and jumps on top. */ + target->widget.rect.pos = windowToInner_Widget(swipeParent, innerToWindow_Widget(w, zero_I2())); + /* Note: `innerToWindow_Widget` does not apply visual offset. */ + target->widget.rect.size = w->rect.size; + setFlags_Widget(as_Widget(target), fixedPosition_WidgetFlag | fixedSize_WidgetFlag, iTrue); + swap_DocumentWidget_(target, d->doc, d); + addChildPos_Widget(swipeParent, iClob(target), back_WidgetAddPos); + setFlags_Widget(as_Widget(d), refChildrenOffset_WidgetFlag, iTrue); + as_Widget(d)->offsetRef = swipeParent; + setVisualOffset_Widget(as_Widget(target), value_Anim(&w->visualOffset), 0, 0); + setVisualOffset_Widget(as_Widget(target), width_Widget(target), 150, 0); + destroy_Widget(as_Widget(target)); /* will be actually deleted after animation finishes */ + setVisualOffset_Widget(w, 0, 0, 0); + postCommand_Widget(d, "navigate.back"); + return iTrue; + } + return iFalse; +} + static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { iWidget *w = as_Widget(d); if (equal_Command(cmd, "document.openurls.changed")) { @@ -2842,7 +2976,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) uiHeading_ColorEscape "${heading.import.bookmarks}", formatCStrs_Lang("dlg.import.found.n", count), (iMenuItem[]){ { "${cancel}", 0, 0, NULL }, - { format_CStr(cstrCount_Lang("dlg.import.add.n", count), + { format_CStr(cstrCount_Lang("dlg.import.add.n", (int) count), uiTextAction_ColorEscape, count), 0, @@ -2901,6 +3035,10 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) else if (startsWith_CStr(cmd, "pinch.") && document_Command(cmd) == d) { return handlePinch_DocumentWidget_(d, cmd); } + else if ((startsWith_CStr(cmd, "edgeswipe.") || startsWith_CStr(cmd, "swipe.")) && + document_App() == d) { + return handleSwipe_DocumentWidget_(d, cmd); + } return iFalse; } @@ -4306,7 +4444,8 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx, /* Swap buffers around to have room available both before and after the visible region. */ allocVisBuffer_DocumentWidget_(d); reposition_VisBuf(visBuf, vis); - /* Redraw the invalid ranges. */ { + /* Redraw the invalid ranges. */ + if (~flags_Widget(constAs_Widget(d)) & destroyPending_WidgetFlag) { iPaint *p = &ctx->paint; init_Paint(p); iForIndices(i, visBuf->buffers) { @@ -4490,6 +4629,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { .vis = vis, .showLinkNumbers = (d->flags & showLinkNumbers_DocumentWidgetFlag) != 0, }; + init_Paint(&ctx.paint); render_DocumentWidget_(d, &ctx, iFalse /* just the mandatory parts */); setClip_Paint(&ctx.paint, bounds); int yTop = docBounds.pos.y - pos_SmoothScroll(&d->scrollY); diff --git a/src/ui/mobile.c b/src/ui/mobile.c index 1bf289a7..7c0c8b60 100644 --- a/src/ui/mobile.c +++ b/src/ui/mobile.c @@ -447,7 +447,7 @@ void finalizeSheet_Mobile(iWidget *sheet) { } addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_())))); /* Slide top panel with detail panels. */ { - setFlags_Widget(topPanel, refChildrenOffset_WidgetFlag, iTrue); + setFlags_Widget(topPanel, refChildrenOffset_WidgetFlag, iTrue); topPanel->offsetRef = detailStack; } if (prefsTabs) { diff --git a/src/ui/root.c b/src/ui/root.c index 2d69970d..e279a048 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -271,7 +271,8 @@ void destroyPending_Root(iRoot *d) { setCurrent_Root(d); iForEach(PtrSet, i, d->pendingDestruction) { iWidget *widget = *i.value; - if (!isFinished_Anim(&widget->visualOffset)) { + if (!isFinished_Anim(&widget->visualOffset) || + isBeingVisuallyOffsetByReference_Widget(widget)) { continue; } if (widget->flags & keepOnTop_WidgetFlag) { @@ -1169,11 +1170,11 @@ void createUserInterface_Root(iRoot *d) { setId_Widget(mainStack, "stack"); addChildFlags_Widget(div, iClob(mainStack), resizeChildren_WidgetFlag | expand_WidgetFlag | unhittable_WidgetFlag); - iWidget *tabBar = makeTabs_Widget(mainStack); - setId_Widget(tabBar, "doctabs"); - setBackgroundColor_Widget(tabBar, uiBackground_ColorId); - appendTabPage_Widget(tabBar, iClob(new_DocumentWidget()), "Document", 0, 0); - iWidget *buttons = findChild_Widget(tabBar, "tabs.buttons"); + iWidget *docTabs = makeTabs_Widget(mainStack); + setId_Widget(docTabs, "doctabs"); + setBackgroundColor_Widget(docTabs, uiBackground_ColorId); + appendTabPage_Widget(docTabs, iClob(new_DocumentWidget()), "Document", 0, 0); + iWidget *buttons = findChild_Widget(docTabs, "tabs.buttons"); setFlags_Widget(buttons, collapse_WidgetFlag | hidden_WidgetFlag | drawBackgroundToHorizontalSafeArea_WidgetFlag, iTrue); if (deviceType_App() == phone_AppDeviceType) { diff --git a/src/ui/touch.c b/src/ui/touch.c index 236601e8..36bac267 100644 --- a/src/ui/touch.c +++ b/src/ui/touch.c @@ -273,8 +273,9 @@ static void update_TouchState_(void *ptr) { // touch->edge == right_TouchEdge && swipeDir < 0 ? SDL_BUTTON_X2 : 0); // setHover_Widget(NULL); postCommandf_App("edgeswipe.ended abort:1 side:%d id:%llu", touch->edge, touch->id); - touch->edge = none_TouchEdge; - remove_ArrayIterator(&i); + touch->edge = none_TouchEdge; + /* May be a regular drag along the edge so don't remove. */ + //remove_ArrayIterator(&i); } continue; } @@ -516,6 +517,7 @@ iBool processEvent_Touch(const SDL_Event *ev) { else if (ev->type == SDL_FINGERMOTION) { iTouch *touch = find_TouchState_(d, fing->fingerId); if (touch && touch->edge) { + clear_Array(d->moms); pushPos_Touch_(touch, pos, nowTime); postCommandf_App("edgeswipe.moved arg:%d side:%d id:%llu", (int) (x_F3(pos) - x_F3(touch->startPos)), diff --git a/src/ui/widget.c b/src/ui/widget.c index f1d1dae4..3b67684b 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -759,6 +759,19 @@ void arrange_Widget(iWidget *d) { } } +iBool isBeingVisuallyOffsetByReference_Widget(const iWidget *d) { + if (d->flags & refChildrenOffset_WidgetFlag) { + iConstForEach(ObjectList, i, children_Widget(d->offsetRef)) { + const iWidget *child = i.object; + if (child == d) continue; + if (child->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) { + return iTrue; + } + } + } + return iFalse; +} + static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) { if (d->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) { const int off = iRound(value_Anim(&d->visualOffset)); @@ -1075,12 +1088,12 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { if (d->flags & dragged_WidgetFlag && equal_Command(cmd, "edgeswipe.ended")) { if (argLabel_Command(cmd, "abort")) { setVisualOffset_Widget(d, 0, 200, easeOut_AnimFlag); - setFlags_Widget(d, dragged_WidgetFlag, iFalse); } else { postCommand_Widget( d, argLabel_Command(cmd, "side") == 1 ? "swipe.back" : "swipe.forward"); } + setFlags_Widget(d, dragged_WidgetFlag, iFalse); } if (d->commandHandler && d->commandHandler(d, ev->user.data1)) { iAssert(get_Root() == d->root); diff --git a/src/ui/widget.h b/src/ui/widget.h index 7255b975..b2310f21 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h @@ -244,6 +244,8 @@ iBool isCommand_Widget (const iWidget *d, const SDL_Event *ev, cons iBool hasParent_Widget (const iWidget *d, const iWidget *someParent); iBool isAffectedByVisualOffset_Widget (const iWidget *); +iBool isBeingVisuallyOffsetByReference_Widget + (const iWidget *); void setId_Widget (iWidget *, const char *id); void setFlags_Widget (iWidget *, int64_t flags, iBool set); void setPos_Widget (iWidget *, iInt2 pos); -- cgit v1.2.3 From 203426a88b2d94ed56f7d3f8f8eb18a7457cab11 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sun, 13 Jun 2021 17:29:35 +0300 Subject: Mobile: Swipe navigation Swipes are working much better. Todo: - Pinch must always cancel/override edge swipes. - Use the right palette for the "swipein" placeholder. --- src/history.c | 7 +++++-- src/history.h | 2 +- src/ui/documentwidget.c | 17 ++++++++++++----- src/ui/root.c | 2 +- src/ui/widget.c | 8 ++++---- 5 files changed, 23 insertions(+), 13 deletions(-) (limited to 'src/ui/widget.c') diff --git a/src/history.c b/src/history.c index f6ad4771..d23fb290 100644 --- a/src/history.c +++ b/src/history.c @@ -288,10 +288,11 @@ iBool preceding_History(iHistory *d, iRecentUrl *recent_out) { iBool ok = iFalse; lock_Mutex(d->mtx); if (!isEmpty_Array(&d->recent) && d->recentPos < size_Array(&d->recent) - 1) { - const iRecentUrl *recent = constAt_Array(&d->recent, d->recentPos + 1); + const iRecentUrl *recent = constAt_Array(&d->recent, size_Array(&d->recent) - 1 - + (d->recentPos + 1)); set_String(&recent_out->url, &recent->url); recent_out->normScrollY = recent->normScrollY; - recent_out->cachedDoc = ref_Object(recent->cachedDoc); + iChangeRef(recent_out->cachedDoc, recent->cachedDoc); /* Cached response is not returned, would involve a deep copy. */ ok = iTrue; } @@ -299,6 +300,7 @@ iBool preceding_History(iHistory *d, iRecentUrl *recent_out) { return ok; } +#if 0 iBool following_History(iHistory *d, iRecentUrl *recent_out) { iBool ok = iFalse; lock_Mutex(d->mtx); @@ -313,6 +315,7 @@ iBool following_History(iHistory *d, iRecentUrl *recent_out) { unlock_Mutex(d->mtx); return ok; } +#endif iBool goBack_History(iHistory *d) { lock_Mutex(d->mtx); diff --git a/src/history.h b/src/history.h index 9c900b82..838ca9ef 100644 --- a/src/history.h +++ b/src/history.h @@ -64,7 +64,7 @@ void setCachedDocument_History (iHistory *, iGmDocument *doc); iBool goBack_History (iHistory *); iBool goForward_History (iHistory *); iBool preceding_History (iHistory *d, iRecentUrl *recent_out); -iBool following_History (iHistory *d, iRecentUrl *recent_out); +//iBool following_History (iHistory *d, iRecentUrl *recent_out); iRecentUrl *recentUrl_History (iHistory *, size_t pos); iRecentUrl *mostRecentUrl_History (iHistory *); iRecentUrl *findUrl_History (iHistory *, const iString *url); diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 70201d7b..eae5d713 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -2266,11 +2266,15 @@ static iWidget *swipeParent_DocumentWidget_(iDocumentWidget *d) { static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { iWidget *w = as_Widget(d); + /* Swipe animations are rather complex and utilize both cached GmDocument content + and temporary DocumentWidgets. Depending on the swipe direction, this DocumentWidget + may wait until the finger is released to actually perform the navigation action. */ if (equal_Command(cmd, "edgeswipe.moved")) { + //printf("[%p] responds to edgeswipe.moved\n", d); as_Widget(d)->offsetRef = NULL; const int side = argLabel_Command(cmd, "side"); const int offset = arg_Command(cmd); - if (side == 1) { + if (side == 1) { /* left edge */ if (atOldest_History(d->mod.history)) { return iTrue; } @@ -2285,7 +2289,7 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { fixedPosition_WidgetFlag | fixedSize_WidgetFlag, iTrue); swipeIn->widget.rect.pos = windowToInner_Widget(swipeParent, localToWindow_Widget(w, w->rect.pos)); swipeIn->widget.rect.size = d->widget.rect.size; - swipeIn->widget.offsetRef = w; + swipeIn->widget.offsetRef = parent_Widget(w); iRecentUrl *recent = new_RecentUrl(); preceding_History(d->mod.history, recent); if (recent->cachedDoc) { @@ -2293,15 +2297,18 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { updateScrollMax_DocumentWidget_(d); setValue_Anim(&swipeIn->scrollY.pos, size_GmDocument(swipeIn->doc).y * recent->normScrollY, 0); updateVisible_DocumentWidget_(swipeIn); + swipeIn->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag | updateSideBuf_DrawBufsFlag; } delete_RecentUrl(recent); addChildPos_Widget(swipeParent, iClob(swipeIn), front_WidgetAddPos); } } - if (side == 2) { + if (side == 2) { /* right edge */ if (offset < -get_Window()->pixelRatio * 10) { + int animSpan = 10; if (!atLatest_History(d->mod.history) && ~flags_Widget(w) & dragged_WidgetFlag) { + animSpan = 0; postCommand_Widget(d, "navigate.forward"); setFlags_Widget(w, dragged_WidgetFlag, iTrue); /* Set up the swipe dummy. */ @@ -2319,10 +2326,10 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { destroy_Widget(as_Widget(target)); /* will be actually deleted after animation finishes */ } if (flags_Widget(w) & dragged_WidgetFlag) { - setVisualOffset_Widget(w, width_Widget(w) + offset, 10, 0); + setVisualOffset_Widget(w, width_Widget(w) + offset, animSpan, 0); } else { - setVisualOffset_Widget(w, offset / 4, 10, 0); + setVisualOffset_Widget(w, offset / 4, animSpan, 0); } } return iTrue; diff --git a/src/ui/root.c b/src/ui/root.c index e279a048..0a5eb96e 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -281,7 +281,7 @@ void destroyPending_Root(iRoot *d) { if (widget->parent) { removeChild_Widget(widget->parent, widget); } - iAssert(widget->parent == NULL); + iAssert(widget->parent == NULL); iRelease(widget); remove_PtrSetIterator(&i); } diff --git a/src/ui/widget.c b/src/ui/widget.c index 3b67684b..11ec1b07 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -82,10 +82,10 @@ static void visualOffsetAnimation_Widget_(void *ptr) { void deinit_Widget(iWidget *d) { releaseChildren_Widget(d); -//#if !defined (NDEBUG) -// printf("widget %p (%s) deleted (on top:%d)\n", d, cstr_String(&d->id), -// d->flags & keepOnTop_WidgetFlag ? 1 : 0); -//#endif +#if 0 && !defined (NDEBUG) + printf("widget %p (%s) deleted (on top:%d)\n", d, cstr_String(&d->id), + d->flags & keepOnTop_WidgetFlag ? 1 : 0); +#endif deinit_String(&d->id); if (d->flags & keepOnTop_WidgetFlag) { removeAll_PtrArray(onTop_Root(d->root), d); -- cgit v1.2.3 From fe238b29132b43f07aa88cf6bb60bec1ff0d3f8d Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Mon, 14 Jun 2021 15:36:48 +0300 Subject: Swiping and sidebar; various tweaks When a page is opened from the sidebar, swiping back will now reopen the sidebar. Another swipe will dismiss the sidebar and navigate back as usual. Attempted to cache theme colors in GmDocument, but there were issues with theme changes. --- src/app.c | 7 +++- src/defs.h | 3 +- src/gmdocument.c | 18 +++++++++ src/gmdocument.h | 2 + src/gmutil.c | 4 +- src/history.c | 31 +++++++++++++-- src/history.h | 6 ++- src/ui/documentwidget.c | 103 +++++++++++++++++++++++++++++++++++++----------- src/ui/documentwidget.h | 8 +++- src/ui/sidebarwidget.c | 14 +++++-- src/ui/text.c | 4 +- src/ui/touch.c | 49 +++++++---------------- src/ui/widget.c | 55 +++++++++++++------------- src/ui/widget.h | 9 +++-- 14 files changed, 207 insertions(+), 106 deletions(-) (limited to 'src/ui/widget.c') diff --git a/src/app.c b/src/app.c index c2bd3da0..4d96b5ef 100644 --- a/src/app.c +++ b/src/app.c @@ -2244,7 +2244,8 @@ iBool handleCommand_App(const char *cmd) { } else if (equal_Command(cmd, "open")) { iString *url = collectNewCStr_String(suffixPtr_Command(cmd, "url")); - const iBool noProxy = argLabel_Command(cmd, "noproxy"); + const iBool noProxy = argLabel_Command(cmd, "noproxy") != 0; + const iBool fromSidebar = argLabel_Command(cmd, "fromsidebar") != 0; iUrl parts; init_Url(&parts, url); if (argLabel_Command(cmd, "default") || equalCase_Rangecc(parts.scheme, "mailto") || @@ -2295,7 +2296,9 @@ iBool handleCommand_App(const char *cmd) { else { urlEncodePath_String(url); } - setUrlFromCache_DocumentWidget(doc, url, isHistory); + setUrlFlags_DocumentWidget(doc, url, + (isHistory ? useCachedContentIfAvailable_DocumentWidgetSetUrlFlag : 0) | + (fromSidebar ? openedFromSidebar_DocumentWidgetSetUrlFlag : 0)); /* Optionally, jump to a text in the document. This will only work if the document is already available, e.g., it's from "about:" or restored from cache. */ const iRangecc gotoHeading = range_Command(cmd, "gotoheading"); diff --git a/src/defs.h b/src/defs.h index 950da394..3ea28e95 100644 --- a/src/defs.h +++ b/src/defs.h @@ -35,9 +35,10 @@ enum iFileVersion { addedResponseTimestamps_FileVersion = 1, multipleRoots_FileVersion = 2, serializedSidebarState_FileVersion = 3, + addedRecentUrlFlags_FileVersion = 4, /* meta */ idents_FileVersion = 1, /* version used by GmCerts/idents.lgr */ - latest_FileVersion = 3, + latest_FileVersion = 4, }; /* Icons */ diff --git a/src/gmdocument.c b/src/gmdocument.c index 5d02ee05..0ab09604 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c @@ -92,6 +92,8 @@ struct Impl_GmDocument { iChar siteIcon; iMedia * media; iStringSet *openURLs; /* currently open URLs for highlighting links */ + iBool isPaletteValid; + iColor palette[tmMax_ColorId]; /* copy of the color palette */ }; iDefineObjectConstruction(GmDocument) @@ -889,6 +891,8 @@ void init_GmDocument(iGmDocument *d) { d->siteIcon = 0; d->media = new_Media(); d->openURLs = NULL; + d->isPaletteValid = iFalse; + iZap(d->palette); } void deinit_GmDocument(iGmDocument *d) { @@ -1401,6 +1405,20 @@ void setThemeSeed_GmDocument(iGmDocument *d, const iBlock *seed) { } printf("---\n"); #endif + /* Color functions operate on the global palette for convenience, but we may need to switch + palettes on the fly if more than one GmDocument is being displayed simultaneously. */ + memcpy(d->palette, get_Root()->tmPalette, sizeof(d->palette)); + d->isPaletteValid = iTrue; +} + +void makePaletteGlobal_GmDocument(const iGmDocument *d) { + if (d->isPaletteValid) { + memcpy(get_Root()->tmPalette, d->palette, sizeof(d->palette)); + } +} + +void invalidatePalette_GmDocument(iGmDocument *d) { + d->isPaletteValid = iFalse; } void setFormat_GmDocument(iGmDocument *d, enum iSourceFormat format) { diff --git a/src/gmdocument.h b/src/gmdocument.h index 943a408c..221e5c00 100644 --- a/src/gmdocument.h +++ b/src/gmdocument.h @@ -170,6 +170,8 @@ void setUrl_GmDocument (iGmDocument *, const iString *url); void setSource_GmDocument (iGmDocument *, const iString *source, int width, enum iGmDocumentUpdate updateType); void foldPre_GmDocument (iGmDocument *, uint16_t preId); +void invalidatePalette_GmDocument(iGmDocument *); +void makePaletteGlobal_GmDocument(const iGmDocument *); /* copies document colors to the global palette */ //void reset_GmDocument (iGmDocument *); /* free images */ diff --git a/src/gmutil.c b/src/gmutil.c index 3ca93901..7a1ae938 100644 --- a/src/gmutil.c +++ b/src/gmutil.c @@ -556,7 +556,7 @@ const iString *feedEntryOpenCommand_String(const iString *url, int newTab) { iString *head = newRange_String( (iRangecc){ constBegin_String(url) + fragPos + 1, constEnd_String(url) }); format_String(cmd, - "open newtab:%d gotourlheading:%s url:%s", + "open fromsidebar:1 newtab:%d gotourlheading:%s url:%s", newTab, cstr_String(head), cstr_Rangecc((iRangecc){ constBegin_String(url), @@ -564,7 +564,7 @@ const iString *feedEntryOpenCommand_String(const iString *url, int newTab) { delete_String(head); } else { - format_String(cmd, "open newtab:%d url:%s", newTab, cstr_String(url)); + format_String(cmd, "open fromsidebar:1 newtab:%d url:%s", newTab, cstr_String(url)); } return cmd; } diff --git a/src/history.c b/src/history.c index d23fb290..c592838e 100644 --- a/src/history.c +++ b/src/history.c @@ -37,6 +37,7 @@ void init_RecentUrl(iRecentUrl *d) { d->normScrollY = 0; d->cachedResponse = NULL; d->cachedDoc = NULL; + d->flags.openedFromSidebar = iFalse; } void deinit_RecentUrl(iRecentUrl *d) { @@ -53,6 +54,7 @@ iRecentUrl *copy_RecentUrl(const iRecentUrl *d) { copy->normScrollY = d->normScrollY; copy->cachedResponse = d->cachedResponse ? copy_GmResponse(d->cachedResponse) : NULL; copy->cachedDoc = ref_Object(d->cachedDoc); + copy->flags = d->flags; return copy; } @@ -171,6 +173,7 @@ void serialize_History(const iHistory *d, iStream *outs) { const iRecentUrl *item = i.value; serialize_String(&item->url, outs); write32_Stream(outs, item->normScrollY * 1.0e6f); + writeU16_Stream(outs, item->flags.openedFromSidebar ? iBit(1) : 0); if (item->cachedResponse) { write8_Stream(outs, 1); serialize_GmResponse(item->cachedResponse, outs); @@ -192,6 +195,12 @@ void deserialize_History(iHistory *d, iStream *ins) { init_RecentUrl(&item); deserialize_String(&item.url, ins); item.normScrollY = (float) read32_Stream(ins) / 1.0e6f; + if (version_Stream(ins) >= addedRecentUrlFlags_FileVersion) { + uint16_t flags = readU16_Stream(ins); + if (flags & iBit(1)) { + item.flags.openedFromSidebar = iTrue; + } + } if (read8_Stream(ins)) { item.cachedResponse = new_GmResponse(); deserialize_GmResponse(item.cachedResponse, ins); @@ -378,12 +387,15 @@ void setCachedResponse_History(iHistory *d, const iGmResponse *response) { unlock_Mutex(d->mtx); } -void setCachedDocument_History(iHistory *d, iGmDocument *doc) { +void setCachedDocument_History(iHistory *d, iGmDocument *doc, iBool openedFromSidebar) { lock_Mutex(d->mtx); iRecentUrl *item = mostRecentUrl_History(d); - if (item && item->cachedDoc != doc) { - iRelease(item->cachedDoc); - item->cachedDoc = ref_Object(doc); + if (item) { + item->flags.openedFromSidebar = openedFromSidebar; + if (item->cachedDoc != doc) { + iRelease(item->cachedDoc); + item->cachedDoc = ref_Object(doc); + } } unlock_Mutex(d->mtx); } @@ -487,6 +499,17 @@ size_t pruneLeastImportantMemory_History(iHistory *d) { return delta; } +void invalidateTheme_History(iHistory *d) { + lock_Mutex(d->mtx); + iForEach(Array, i, &d->recent) { + iRecentUrl *r = i.value; + if (r->cachedDoc) { + invalidatePalette_GmDocument(r->cachedDoc); + } + } + unlock_Mutex(d->mtx); +} + const iStringArray *searchContents_History(const iHistory *d, const iRegExp *pattern) { iStringArray *urls = iClob(new_StringArray()); lock_Mutex(d->mtx); diff --git a/src/history.h b/src/history.h index 838ca9ef..7dad72df 100644 --- a/src/history.h +++ b/src/history.h @@ -39,6 +39,9 @@ struct Impl_RecentUrl { float normScrollY; /* normalized to document height */ iGmResponse *cachedResponse; /* kept in memory for quicker back navigation */ iGmDocument *cachedDoc; /* cached copy of the presentation: layout and media (not serialized) */ + struct { + uint8_t openedFromSidebar : 1; + } flags; }; iDeclareType(MemInfo) @@ -60,7 +63,7 @@ void clear_History (iHistory *); void add_History (iHistory *, const iString *url); void replace_History (iHistory *, const iString *url); void setCachedResponse_History (iHistory *, const iGmResponse *response); -void setCachedDocument_History (iHistory *, iGmDocument *doc); +void setCachedDocument_History (iHistory *, iGmDocument *doc, iBool openedFromSidebar); iBool goBack_History (iHistory *); iBool goForward_History (iHistory *); iBool preceding_History (iHistory *d, iRecentUrl *recent_out); @@ -72,6 +75,7 @@ iRecentUrl *findUrl_History (iHistory *, const iString *url); void clearCache_History (iHistory *); size_t pruneLeastImportant_History (iHistory *); size_t pruneLeastImportantMemory_History (iHistory *); +void invalidateTheme_History (iHistory *); /* theme has changed, cached contents need updating */ iBool atLatest_History (const iHistory *); iBool atOldest_History (const iHistory *); diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index eae5d713..3fc22bdf 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -130,7 +130,8 @@ void deinit_PersistentDocumentState(iPersistentDocumentState *d) { void serialize_PersistentDocumentState(const iPersistentDocumentState *d, iStream *outs) { serialize_String(d->url, outs); - writeU16_Stream(outs, d->reloadInterval & 7); + uint16_t params = d->reloadInterval & 7; + writeU16_Stream(outs, params); serialize_History(d->history, outs); } @@ -223,6 +224,7 @@ enum iDocumentWidgetFlag { movingSelectMarkEnd_DocumentWidgetFlag = iBit(11), otherRootByDefault_DocumentWidgetFlag = iBit(12), /* links open to other root by default */ urlChanged_DocumentWidgetFlag = iBit(13), + openedFromSidebar_DocumentWidgetFlag = iBit(14), }; enum iDocumentLinkOrdinalMode { @@ -1606,7 +1608,8 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n format_String(&d->sourceHeader, cstr_Lang("pageinfo.header.cached")); set_Block(&d->sourceContent, &resp->body); updateDocument_DocumentWidget_(d, resp, cachedDoc, iTrue); - setCachedDocument_History(d->mod.history, d->doc); + setCachedDocument_History(d->mod.history, d->doc, + (d->flags & openedFromSidebar_DocumentWidgetFlag) != 0); } d->state = ready_RequestState; postProcessRequestContent_DocumentWidget_(d, iTrue); @@ -1626,6 +1629,9 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { const iRecentUrl *recent = findUrl_History(d->mod.history, withSpacesEncoded_String(d->mod.url)); if (recent && recent->cachedResponse) { + iChangeFlags(d->flags, + openedFromSidebar_DocumentWidgetFlag, + recent->flags.openedFromSidebar); updateFromCachedResponse_DocumentWidget_( d, recent->normScrollY, recent->cachedResponse, recent->cachedDoc); return iTrue; @@ -2282,6 +2288,9 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { /* The temporary "swipeIn" will display the previous page until the finger is lifted. */ iDocumentWidget *swipeIn = findChild_Widget(swipeParent, "swipein"); if (!swipeIn) { + const iBool sidebarSwipe = (isPortraitPhone_App() && + d->flags & openedFromSidebar_DocumentWidgetFlag && + !isVisible_Widget(findWidget_App("sidebar"))); swipeIn = new_DocumentWidget(); setId_Widget(as_Widget(swipeIn), "swipein"); setFlags_Widget(as_Widget(swipeIn), @@ -2290,16 +2299,18 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { swipeIn->widget.rect.pos = windowToInner_Widget(swipeParent, localToWindow_Widget(w, w->rect.pos)); swipeIn->widget.rect.size = d->widget.rect.size; swipeIn->widget.offsetRef = parent_Widget(w); - iRecentUrl *recent = new_RecentUrl(); - preceding_History(d->mod.history, recent); - if (recent->cachedDoc) { - iChangeRef(swipeIn->doc, recent->cachedDoc); - updateScrollMax_DocumentWidget_(d); - setValue_Anim(&swipeIn->scrollY.pos, size_GmDocument(swipeIn->doc).y * recent->normScrollY, 0); - updateVisible_DocumentWidget_(swipeIn); - swipeIn->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag | updateSideBuf_DrawBufsFlag; + if (!sidebarSwipe) { + iRecentUrl *recent = new_RecentUrl(); + preceding_History(d->mod.history, recent); + if (recent->cachedDoc) { + iChangeRef(swipeIn->doc, recent->cachedDoc); + updateScrollMax_DocumentWidget_(d); + setValue_Anim(&swipeIn->scrollY.pos, size_GmDocument(swipeIn->doc).y * recent->normScrollY, 0); + updateVisible_DocumentWidget_(swipeIn); + swipeIn->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag | updateSideBuf_DrawBufsFlag; + } + delete_RecentUrl(recent); } - delete_RecentUrl(recent); addChildPos_Widget(swipeParent, iClob(swipeIn), front_WidgetAddPos); } } @@ -2326,7 +2337,9 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { destroy_Widget(as_Widget(target)); /* will be actually deleted after animation finishes */ } if (flags_Widget(w) & dragged_WidgetFlag) { - setVisualOffset_Widget(w, width_Widget(w) + offset, animSpan, 0); + setVisualOffset_Widget(w, width_Widget(w) + + width_Widget(d) * offset / size_Root(w->root).x, + animSpan, 0); } else { setVisualOffset_Widget(w, offset / 4, animSpan, 0); @@ -2426,6 +2439,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) return iFalse; } else if (equal_Command(cmd, "theme.changed") && document_App() == d) { +// invalidateTheme_History(d->mod.history); /* cached colors */ updateTheme_DocumentWidget_(d); updateVisible_DocumentWidget_(d); updateTrust_DocumentWidget_(d, NULL); @@ -2691,7 +2705,8 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) (startsWithCase_String(meta_GmRequest(d->request), "text/") || !cmp_String(&d->sourceMime, mimeType_Gempub))) { setCachedResponse_History(d->mod.history, lockResponse_GmRequest(d->request)); - setCachedDocument_History(d->mod.history, d->doc); /* keeps a ref */ + setCachedDocument_History(d->mod.history, d->doc, /* keeps a ref */ + (d->flags & openedFromSidebar_DocumentWidgetFlag) != 0); unlockResponse_GmRequest(d->request); } } @@ -2821,6 +2836,15 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) return iTrue; } else if (equal_Command(cmd, "navigate.back") && document_App() == d) { + if (isPortraitPhone_App()) { + if (d->flags & openedFromSidebar_DocumentWidgetFlag && + !isVisible_Widget(findWidget_App("sidebar"))) { + postCommand_App("sidebar.toggle"); + showToolbars_Root(get_Root(), iTrue); + return iTrue; + } + d->flags &= ~openedFromSidebar_DocumentWidgetFlag; + } if (d->request) { postCommandf_Root(w->root, "document.request.cancelled doc:%p url:%s", d, cstr_String(d->mod.url)); @@ -3499,7 +3523,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e pushBack_Array( &items, &(iMenuItem){ delete_Icon " " uiTextCaution_ColorEscape - " ${link.file.delete}", + "${link.file.delete}", 0, 0, format_CStr("!file.delete confirm:1 path:%s", @@ -4366,7 +4390,7 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { iDrawBufs * dbuf = d->drawBufs; iPaint p; init_Paint(&p); - setClip_Paint(&p, bounds); + setClip_Paint(&p, boundsWithoutVisualOffset_Widget(w)); /* Side icon and current heading. */ if (prefs_App()->sideIcon && opacity > 0 && dbuf->sideIconBuf) { const iInt2 texSize = size_SDLTexture(dbuf->sideIconBuf); @@ -4616,12 +4640,17 @@ static void prerender_DocumentWidget_(iAny *context) { } static void draw_DocumentWidget_(const iDocumentWidget *d) { - const iWidget *w = constAs_Widget(d); - const iRect bounds = bounds_Widget(w); + const iWidget *w = constAs_Widget(d); + const iRect bounds = bounds_Widget(w); + const iRect boundsWithoutVisOff = boundsWithoutVisualOffset_Widget(w); + const iRect clipBounds = intersect_Rect(bounds, boundsWithoutVisOff); if (width_Rect(bounds) <= 0) { return; } -// draw_Widget(w); + /* TODO: Come up with a better palette caching system. + It should be able to recompute cached colors in `History` when the theme has changed. + Cache the theme seed in `GmDocument`? */ +// makePaletteGlobal_GmDocument(d->doc); if (d->drawBufs->flags & updateTimestampBuf_DrawBufsFlag) { updateTimestampBuf_DocumentWidget_(d); } @@ -4638,7 +4667,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { }; init_Paint(&ctx.paint); render_DocumentWidget_(d, &ctx, iFalse /* just the mandatory parts */); - setClip_Paint(&ctx.paint, bounds); + setClip_Paint(&ctx.paint, clipBounds); int yTop = docBounds.pos.y - pos_SmoothScroll(&d->scrollY); draw_VisBuf(d->visBuf, init_I2(bounds.pos.x, yTop), ySpan_Rect(bounds)); /* Text markers. */ @@ -4673,7 +4702,6 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { } } drawMedia_DocumentWidget_(d, &ctx.paint); - unsetClip_Paint(&ctx.paint); /* Fill the top and bottom, in case the document is short. */ if (yTop > top_Rect(bounds)) { fillRect_Paint(&ctx.paint, @@ -4687,6 +4715,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { init_Rect(bounds.pos.x, yBottom, bounds.size.x, bottom_Rect(bounds) - yBottom), tmBackground_ColorId); } + unsetClip_Paint(&ctx.paint); drawSideElements_DocumentWidget_(d); if (prefs_App()->hoverLink && d->hoverLink) { const int font = uiLabel_FontId; @@ -4748,6 +4777,23 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { drawCentered_Text(uiLabelBold_FontId, rect, iFalse, uiBackground_ColorId, "%zu bytes selected", size_Range(&mark)); } + if (w->offsetRef) { + const int offX = visualOffsetByReference_Widget(w); + if (offX) { + setClip_Paint(&ctx.paint, clipBounds); + SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); + ctx.paint.alpha = iAbs(offX) / (float) get_Window()->size.x * 300; + fillRect_Paint(&ctx.paint, bounds, backgroundFadeColor_Widget()); + SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); + unsetClip_Paint(&ctx.paint); + } + else { + /* TODO: Should have a better place to do this; drawing is supposed to be immutable. */ + iWidget *mut = iConstCast(iWidget *, w); + mut->offsetRef = NULL; + mut->flags &= ~refChildrenOffset_WidgetFlag; + } + } } /*----------------------------------------------------------------------------------------------*/ @@ -4814,10 +4860,13 @@ static void setUrl_DocumentWidget_(iDocumentWidget *d, const iString *url) { if (!equal_String(d->mod.url, url)) { d->flags |= urlChanged_DocumentWidgetFlag; set_String(d->mod.url, url); -} + } } -void setUrlFromCache_DocumentWidget(iDocumentWidget *d, const iString *url, iBool isFromCache) { +void setUrlFlags_DocumentWidget(iDocumentWidget *d, const iString *url, int setUrlFlags) { + iChangeFlags(d->flags, openedFromSidebar_DocumentWidgetFlag, + (setUrlFlags & openedFromSidebar_DocumentWidgetSetUrlFlag) != 0); + const iBool isFromCache = (setUrlFlags & useCachedContentIfAvailable_DocumentWidgetSetUrlFlag) != 0; setLinkNumberMode_DocumentWidget_(d, iFalse); setUrl_DocumentWidget_(d, urlFragmentStripped_String(url)); /* See if there a username in the URL. */ @@ -4829,6 +4878,7 @@ void setUrlFromCache_DocumentWidget(iDocumentWidget *d, const iString *url, iBoo void setUrlAndSource_DocumentWidget(iDocumentWidget *d, const iString *url, const iString *mime, const iBlock *source) { + d->flags &= ~openedFromSidebar_DocumentWidgetFlag; setLinkNumberMode_DocumentWidget_(d, iFalse); setUrl_DocumentWidget_(d, url); parseUser_DocumentWidget_(d); @@ -4846,12 +4896,12 @@ iDocumentWidget *duplicate_DocumentWidget(const iDocumentWidget *orig) { delete_History(d->mod.history); d->initNormScrollY = normScrollPos_DocumentWidget_(d); d->mod.history = copy_History(orig->mod.history); - setUrlFromCache_DocumentWidget(d, orig->mod.url, iTrue); + setUrlFlags_DocumentWidget(d, orig->mod.url, useCachedContentIfAvailable_DocumentWidgetSetUrlFlag); return d; } void setUrl_DocumentWidget(iDocumentWidget *d, const iString *url) { - setUrlFromCache_DocumentWidget(d, url, iFalse); + setUrlFlags_DocumentWidget(d, url, 0); } void setInitialScroll_DocumentWidget(iDocumentWidget *d, float normScrollY) { @@ -4862,6 +4912,11 @@ void setRedirectCount_DocumentWidget(iDocumentWidget *d, int count) { d->redirectCount = count; } +void setOpenedFromSidebar_DocumentWidget(iDocumentWidget *d, iBool fromSidebar) { + iChangeFlags(d->flags, openedFromSidebar_DocumentWidgetFlag, fromSidebar); + setCachedDocument_History(d->mod.history, d->doc, fromSidebar); +} + iBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) { return d->request != NULL; } diff --git a/src/ui/documentwidget.h b/src/ui/documentwidget.h index c038f981..1921b25a 100644 --- a/src/ui/documentwidget.h +++ b/src/ui/documentwidget.h @@ -45,11 +45,17 @@ const iString * bookmarkTitle_DocumentWidget (const iDocumentWidget *); const iString * feedTitle_DocumentWidget (const iDocumentWidget *); int documentWidth_DocumentWidget (const iDocumentWidget *); +enum iDocumentWidgetSetUrlFlags { + useCachedContentIfAvailable_DocumentWidgetSetUrlFlag = iBit(1), + openedFromSidebar_DocumentWidgetSetUrlFlag = iBit(2), +}; + void setUrl_DocumentWidget (iDocumentWidget *, const iString *url); -void setUrlFromCache_DocumentWidget (iDocumentWidget *, const iString *url, iBool isFromCache); +void setUrlFlags_DocumentWidget (iDocumentWidget *, const iString *url, int setUrlFlags); void setUrlAndSource_DocumentWidget (iDocumentWidget *, const iString *url, const iString *mime, const iBlock *source); void setInitialScroll_DocumentWidget (iDocumentWidget *, float normScrollY); /* set after content received */ void setRedirectCount_DocumentWidget (iDocumentWidget *, int count); void setSource_DocumentWidget (iDocumentWidget *, const iString *sourceText); +void setOpenedFromSidebar_DocumentWidget(iDocumentWidget *, iBool fromSidebar); void updateSize_DocumentWidget (iDocumentWidget *); diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 4f3ea637..f7181037 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -773,6 +773,7 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, iSidebarItem *item, si const iGmHeading *head = constAt_Array(headings_GmDocument(doc), item->id); postCommandf_App("document.goto loc:%p", head->text.start); dismissPortraitPhoneSidebars_Root(as_Widget(d)->root); + setOpenedFromSidebar_DocumentWidget(document_App(), iTrue); break; } case feeds_SidebarMode: { @@ -783,7 +784,7 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, iSidebarItem *item, si case bookmarks_SidebarMode: case history_SidebarMode: { if (!isEmpty_String(&item->url)) { - postCommandf_Root(get_Root(), "open newtab:%d url:%s", + postCommandf_Root(get_Root(), "open fromsidebar:1 newtab:%d url:%s", openTabMode_Sym(modState_Keys()), cstr_String(&item->url)); } @@ -944,13 +945,16 @@ static iBool handleSidebarCommand_SidebarWidget_(iSidebarWidget *d, const char * visX = left_Rect(bounds_Widget(w)) - left_Rect(w->root->widget->rect); } setFlags_Widget(w, hidden_WidgetFlag, isVisible_Widget(w)); + /* Safe area inset for mobile. */ + const int safePad = (d->side == left_SidebarSide ? left_Rect(safeRect_Root(w->root)) : 0); if (isVisible_Widget(w)) { setFlags_Widget(w, keepOnTop_WidgetFlag, iFalse); w->rect.size.x = d->widthAsGaps * gap_UI; invalidate_ListWidget(d->list); if (isAnimated) { setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue); - setVisualOffset_Widget(w, (d->side == left_SidebarSide ? -1 : 1) * w->rect.size.x, 0, 0); + setVisualOffset_Widget( + w, (d->side == left_SidebarSide ? -1 : 1) * (w->rect.size.x + safePad), 0, 0); setVisualOffset_Widget(w, 0, 300, easeOut_AnimFlag | softer_AnimFlag); } } @@ -958,11 +962,13 @@ static iBool handleSidebarCommand_SidebarWidget_(iSidebarWidget *d, const char * setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue); if (d->side == right_SidebarSide) { setVisualOffset_Widget(w, visX, 0, 0); - setVisualOffset_Widget(w, visX + w->rect.size.x, 300, easeOut_AnimFlag | softer_AnimFlag); + setVisualOffset_Widget( + w, visX + w->rect.size.x + safePad, 300, easeOut_AnimFlag | softer_AnimFlag); } else { setFlags_Widget(w, keepOnTop_WidgetFlag, iTrue); - setVisualOffset_Widget(w, -w->rect.size.x, 300, easeOut_AnimFlag | softer_AnimFlag); + setVisualOffset_Widget( + w, -w->rect.size.x - safePad, 300, easeOut_AnimFlag | softer_AnimFlag); } } arrange_Widget(w->parent); diff --git a/src/ui/text.c b/src/ui/text.c index ffe08fca..8a2a9ff8 100644 --- a/src/ui/text.c +++ b/src/ui/text.c @@ -389,7 +389,9 @@ static void initCache_Text_(iText *d) { d->cacheRowAllocStep = iMax(2, textSize / 6); /* Allocate initial (empty) rows. These will be assigned actual locations in the cache once at least one glyph is stored. */ - for (int h = d->cacheRowAllocStep; h <= 2 * textSize + d->cacheRowAllocStep; h += d->cacheRowAllocStep) { + for (int h = d->cacheRowAllocStep; + h <= 2.5 * textSize + d->cacheRowAllocStep; + h += d->cacheRowAllocStep) { pushBack_Array(&d->cacheRows, &(iCacheRow){ .height = 0 }); } d->cacheBottom = 0; diff --git a/src/ui/touch.c b/src/ui/touch.c index 36bac267..dac1152e 100644 --- a/src/ui/touch.c +++ b/src/ui/touch.c @@ -65,6 +65,7 @@ struct Impl_Touch { iBool isLeftDown; iBool isTouchDrag; iBool isTapAndHold; + iBool didPostEdgeMove; iBool didBeginOnTouchDrag; int pinchId; enum iTouchEdge edge; @@ -391,6 +392,12 @@ static void checkNewPinch_TouchState_(iTouchState *d, iTouch *newTouch) { pinch.touchIds[1] = other->id; newTouch->pinchId = other->pinchId = pinch.id; clearWidgetMomentum_TouchState_(d, affinity); + if (other->edge && other->didPostEdgeMove) { + postCommandf_App("edgeswipe.ended abort:1 side:%d id:%llu", other->edge, other->id); + other->didPostEdgeMove = iFalse; + } + other->edge = none_TouchEdge; + newTouch->edge = none_TouchEdge; /* Remember current positions to determine pinch amount. */ newTouch->startPos = newTouch->pos[0]; other->startPos = other->pos[0]; @@ -476,7 +483,6 @@ iBool processEvent_Touch(const SDL_Event *ev) { } else if (x > rootSize.x - edgeWidth) { edge = right_TouchEdge; -// puts("DOWN on right edge"); } iWidget *aff = hitChild_Window(window, init_I2(iRound(x), iRound(y_F3(pos)))); #if 0 @@ -523,6 +529,7 @@ iBool processEvent_Touch(const SDL_Event *ev) { (int) (x_F3(pos) - x_F3(touch->startPos)), touch->edge, touch->id); + touch->didPostEdgeMove = iTrue; return iTrue; } if (touch && touch->affinity) { @@ -595,39 +602,6 @@ iBool processEvent_Touch(const SDL_Event *ev) { } } iAssert(touch->edge == none_TouchEdge); -#if 0 - /* Edge swipe aborted? */ - if (touch->edge == left_TouchEdge) { - if (fing->dx < 0 && x_F3(touch->pos[0]) < tapRadiusPt_ * window->pixelRatio) { - touch->edge = none_TouchEdge; - if (touch->edgeDragging) { - setFlags_Widget(touch->edgeDragging, dragged_WidgetFlag, iFalse); - setVisualOffset_Widget(touch->edgeDragging, 0, 200, easeOut_AnimFlag); - touch->edgeDragging = NULL; - } - } - else if (touch->edgeDragging) { - setVisualOffset_Widget(touch->edgeDragging, x_F3(pos) - x_F3(touch->startPos), 10, 0); - } - } - if (touch->edge == right_TouchEdge) { - if (fing->dx > 0 && x_F3(touch->pos[0]) > window->size.x - tapRadiusPt_ * window->pixelRatio) { - puts("touch->edge==right returned to right edge, aborted"); - touch->edge = none_TouchEdge; - if (touch->edgeDragging) { - setFlags_Widget(touch->edgeDragging, dragged_WidgetFlag, iFalse); - setVisualOffset_Widget(touch->edgeDragging, 0, 200, easeOut_AnimFlag); - touch->edgeDragging = NULL; - } - } - else if (touch->edgeDragging) { - setVisualOffset_Widget(touch->edgeDragging, x_F3(pos) - x_F3(touch->startPos), 10, 0); - } - } - if (touch->edge) { - pixels.y = 0; - } -#endif if (touch->axis == x_TouchAxis) { pixels.y = 0; } @@ -671,7 +645,12 @@ iBool processEvent_Touch(const SDL_Event *ev) { } #endif if (touch->edge && !isStationary_Touch_(touch)) { - postCommandf_App("edgeswipe.ended side:%d id:%llu", touch->edge, touch->id); + const iFloat3 gesture = gestureVector_Touch_(touch); + const float pixel = window->pixelRatio; + const int moveDir = x_F3(gesture) < -pixel ? -1 : x_F3(gesture) > pixel ? +1 : 0; + const int didAbort = (touch->edge == left_TouchEdge && moveDir < 0) || + (touch->edge == right_TouchEdge && moveDir > 0); + postCommandf_App("edgeswipe.ended abort:%d side:%d id:%llu", didAbort, touch->edge, touch->id); remove_ArrayIterator(&i); continue; } diff --git a/src/ui/widget.c b/src/ui/widget.c index 11ec1b07..85672c04 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -760,16 +760,24 @@ void arrange_Widget(iWidget *d) { } iBool isBeingVisuallyOffsetByReference_Widget(const iWidget *d) { - if (d->flags & refChildrenOffset_WidgetFlag) { + return visualOffsetByReference_Widget(d) != 0; +} + +int visualOffsetByReference_Widget(const iWidget *d) { + if (d->offsetRef && d->flags & refChildrenOffset_WidgetFlag) { + int offX = 0; iConstForEach(ObjectList, i, children_Widget(d->offsetRef)) { const iWidget *child = i.object; if (child == d) continue; if (child->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) { - return iTrue; +// const float factor = width_Widget(d) / (float) size_Root(d->root).x; + const int invOff = width_Widget(d) - iRound(value_Anim(&child->visualOffset)); + offX -= invOff / 4; } } + return offX; } - return iFalse; + return 0; } static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) { @@ -786,14 +794,7 @@ static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) { pos->y -= value_Anim(d->animOffsetRef); } if (d->flags & refChildrenOffset_WidgetFlag) { - iConstForEach(ObjectList, i, children_Widget(d->offsetRef)) { - const iWidget *child = i.object; - if (child == d) continue; - if (child->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) { - const int invOff = size_Root(d->root).x - iRound(value_Anim(&child->visualOffset)); - pos->x -= invOff / 4; - } - } + pos->x += visualOffsetByReference_Widget(d); } } @@ -1081,7 +1082,9 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { if (~d->flags & dragged_WidgetFlag) { setFlags_Widget(d, dragged_WidgetFlag, iTrue); } - setVisualOffset_Widget(d, arg_Command(command_UserEvent(ev)), 10, 0); + setVisualOffset_Widget(d, arg_Command(command_UserEvent(ev)) * + width_Widget(d) / size_Root(d->root).x, + 10, 0); return iTrue; } } @@ -1129,6 +1132,17 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { return iFalse; } +int backgroundFadeColor_Widget(void) { + switch (colorTheme_App()) { + case light_ColorTheme: + return gray25_ColorId; + case pureWhite_ColorTheme: + return gray50_ColorId; + default: + return black_ColorId; + } +} + void drawBackground_Widget(const iWidget *d) { if (d->flags & noBackground_WidgetFlag) { return; @@ -1151,8 +1165,7 @@ void drawBackground_Widget(const iWidget *d) { drawSoftShadow_Paint(&p, bounds_Widget(d), 12 * gap_UI, black_ColorId, 30); } const iBool isFaded = fadeBackground && - ~d->flags & noFadeBackground_WidgetFlag;/* && - ~d->flags & destroyPending_WidgetFlag;*/ + ~d->flags & noFadeBackground_WidgetFlag; if (isFaded) { iPaint p; init_Paint(&p); @@ -1163,19 +1176,7 @@ void drawBackground_Widget(const iWidget *d) { p.alpha *= (area > 0 ? visibleArea / area : 0.0f); } SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); - int fadeColor; - switch (colorTheme_App()) { - default: - fadeColor = black_ColorId; - break; - case light_ColorTheme: - fadeColor = gray25_ColorId; - break; - case pureWhite_ColorTheme: - fadeColor = gray50_ColorId; - break; - } - fillRect_Paint(&p, rect_Root(d->root), fadeColor); + fillRect_Paint(&p, rect_Root(d->root), backgroundFadeColor_Widget()); SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); } if (d->bgColor >= 0 || d->frameColor >= 0) { diff --git a/src/ui/widget.h b/src/ui/widget.h index b2310f21..acb8fa9d 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h @@ -242,10 +242,9 @@ iBool isSelected_Widget (const iAnyObject *); iBool isUnderKeyRoot_Widget (const iAnyObject *); iBool isCommand_Widget (const iWidget *d, const SDL_Event *ev, const char *cmd); iBool hasParent_Widget (const iWidget *d, const iWidget *someParent); -iBool isAffectedByVisualOffset_Widget - (const iWidget *); -iBool isBeingVisuallyOffsetByReference_Widget - (const iWidget *); +iBool isAffectedByVisualOffset_Widget (const iWidget *); +iBool isBeingVisuallyOffsetByReference_Widget (const iWidget *); +int visualOffsetByReference_Widget (const iWidget *); void setId_Widget (iWidget *, const char *id); void setFlags_Widget (iWidget *, int64_t flags, iBool set); void setPos_Widget (iWidget *, iInt2 pos); @@ -278,6 +277,8 @@ void refresh_Widget (const iAnyObject *); iBool equalWidget_Command (const char *cmd, const iWidget *widget, const char *checkCommand); +int backgroundFadeColor_Widget (void); + void setFocus_Widget (iWidget *); iWidget * focus_Widget (void); void setHover_Widget (iWidget *); -- cgit v1.2.3 From 379c1100995fbc841df863027871ee91c77deedf Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Tue, 15 Jun 2021 13:18:57 +0300 Subject: Mobile: Show identity name in toolbar Shuffled the widget flags a bit to make room for a new one. --- src/ui/labelwidget.c | 8 +++++++- src/ui/labelwidget.h | 1 + src/ui/root.c | 29 +++++++++++++++++++++++++++-- src/ui/text.c | 1 + src/ui/text.h | 1 + src/ui/util.c | 4 ++-- src/ui/widget.c | 5 +++++ src/ui/widget.h | 6 +++--- 8 files changed, 47 insertions(+), 8 deletions(-) (limited to 'src/ui/widget.c') diff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c index 09c5812b..46ef5d1f 100644 --- a/src/ui/labelwidget.c +++ b/src/ui/labelwidget.c @@ -45,6 +45,7 @@ struct Impl_LabelWidget { uint8_t alignVisual : 1; /* align according to visible bounds, not font metrics */ uint8_t noAutoMinHeight : 1; /* minimum height is not set automatically */ uint8_t drawAsOutline : 1; /* draw as outline, filled with background color */ + uint8_t noTopFrame : 1; } flags; }; @@ -290,7 +291,7 @@ static void draw_LabelWidget_(const iLabelWidget *d) { }; drawLines_Paint(&p, points + 2, 3, frame2); drawLines_Paint( - &p, points, !isHover && flags & noTopFrame_WidgetFlag ? 2 : 3, frame); + &p, points, !isHover && flags & d->flags.noTopFrame ? 2 : 3, frame); } } setClip_Paint(&p, rect); @@ -444,6 +445,7 @@ void init_LabelWidget(iLabelWidget *d, const char *label, const char *cmd) { d->flags.alignVisual = iFalse; d->flags.noAutoMinHeight = iFalse; d->flags.drawAsOutline = iFalse; + d->flags.noTopFrame = iFalse; updateSize_LabelWidget(d); updateKey_LabelWidget_(d); /* could be bound to another key */ } @@ -483,6 +485,10 @@ void setNoAutoMinHeight_LabelWidget(iLabelWidget *d, iBool noAutoMinHeight) { } } +void setNoTopFrame_LabelWidget(iLabelWidget *d, iBool noTopFrame) { + d->flags.noTopFrame = noTopFrame; +} + void setOutline_LabelWidget(iLabelWidget *d, iBool drawAsOutline) { d->flags.drawAsOutline = drawAsOutline; } diff --git a/src/ui/labelwidget.h b/src/ui/labelwidget.h index 25c873fc..f6343273 100644 --- a/src/ui/labelwidget.h +++ b/src/ui/labelwidget.h @@ -31,6 +31,7 @@ iDeclareObjectConstructionArgs(LabelWidget, const char *label, const char *comma void setAlignVisually_LabelWidget(iLabelWidget *, iBool alignVisual); void setNoAutoMinHeight_LabelWidget(iLabelWidget *, iBool noAutoMinHeight); +void setNoTopFrame_LabelWidget (iLabelWidget *, iBool noTopFrame); void setOutline_LabelWidget (iLabelWidget *, iBool drawAsOutline); void setFont_LabelWidget (iLabelWidget *, int fontId); void setTextColor_LabelWidget (iLabelWidget *, int color); diff --git a/src/ui/root.c b/src/ui/root.c index 71f51ef0..9f4aeb7f 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -443,6 +443,10 @@ static void updateNavBarIdentity_(iWidget *navBar) { subjectName ? format_CStr(uiTextAction_ColorEscape "%s", cstr_String(subjectName)) : "${menu.identity.notactive}"); setFlags_Widget(as_Widget(idItem), disabled_WidgetFlag, !ident); + iLabelWidget *toolName = findWidget_App("toolbar.name"); + if (toolName) { + updateTextCStr_LabelWidget(toolName, subjectName ? cstr_String(subjectName) : ""); + } } static void updateNavDirButtons_(iWidget *navBar) { @@ -951,6 +955,19 @@ void updateMetrics_Root(iRoot *d) { updatePadding_Root(d); arrange_Widget(d->widget); updateUrlInputContentPadding_(navBar); + /* Position the toolbar identity name label manually. */ { + iLabelWidget *idName = findChild_Widget(d->widget, "toolbar.name"); + if (idName) { + const iWidget *idButton = findChild_Widget(d->widget, "toolbar.ident"); + const int font = defaultSmall_FontId; + setFont_LabelWidget(idName, font); + setPos_Widget(as_Widget(idName), + windowToLocal_Widget(as_Widget(idName), + addY_I2(bottomLeft_Rect(bounds_Widget(idButton)), -gap_UI * 2))); + setFixedSize_Widget(as_Widget(idName), init_I2(width_Widget(idButton), + lineHeight_Text(font))); + } + } postRefresh_App(); } @@ -1284,16 +1301,24 @@ void createUserInterface_Root(iRoot *d) { iClob(newLargeIcon_LabelWidget(book_Icon, "toolbar.showview arg:-1")), frameless_WidgetFlag | commandOnClick_WidgetFlag), "toolbar.view"); + setId_Widget(addChildFlags_Widget(toolBar, + iClob(new_LabelWidget("", NULL)), + frameless_WidgetFlag | + noBackground_WidgetFlag | + disabled_WidgetFlag | + fixedPosition_WidgetFlag | + fixedSize_WidgetFlag | + ignoreForParentWidth_WidgetFlag | + ignoreForParentHeight_WidgetFlag), + "toolbar.name"); iLabelWidget *menuButton = makeMenuButton_LabelWidget(menu_Icon, phoneNavMenuItems_, iElemCount(phoneNavMenuItems_)); setFont_LabelWidget(menuButton, uiLabelLarge_FontId); setId_Widget(as_Widget(menuButton), "toolbar.navmenu"); addChildFlags_Widget(toolBar, iClob(menuButton), frameless_WidgetFlag); -// setBackgroundColor_Widget(toolBar, tmBannerBackground_ColorId); iForEach(ObjectList, i, children_Widget(toolBar)) { iLabelWidget *btn = i.object; setFlags_Widget(i.object, noBackground_WidgetFlag, iTrue); -// setTextColor_LabelWidget(i.object, tmBannerIcon_ColorId); } updateToolbarColors_Root(d); const iMenuItem items[] = { diff --git a/src/ui/text.c b/src/ui/text.c index 8a70e4db..fcd944d6 100644 --- a/src/ui/text.c +++ b/src/ui/text.c @@ -306,6 +306,7 @@ static void initFonts_Text_(iText *d) { { &fontSourceSans3Regular_Embedded, uiSize * 1.125f, 1.0f, uiMedium_FontSize }, { &fontSourceSans3Regular_Embedded, uiSize * 1.333f, 1.0f, uiBig_FontSize }, { &fontSourceSans3Regular_Embedded, uiSize * 1.666f, 1.0f, uiLarge_FontSize }, + { &fontSourceSans3Regular_Embedded, uiSize * 0.8f, 1.0f, uiNormal_FontSize }, /* UI fonts: bold weight */ { &fontSourceSans3Bold_Embedded, uiSize, 1.0f, uiNormal_FontSize }, { &fontSourceSans3Bold_Embedded, uiSize * 1.125f, 1.0f, uiMedium_FontSize }, diff --git a/src/ui/text.h b/src/ui/text.h index 64a8352f..dd377247 100644 --- a/src/ui/text.h +++ b/src/ui/text.h @@ -50,6 +50,7 @@ enum iFontId { defaultMedium_FontId, defaultBig_FontId, defaultLarge_FontId, + defaultSmall_FontId, /* UI fonts: bold weight */ defaultBold_FontId, defaultMediumBold_FontId, diff --git a/src/ui/util.c b/src/ui/util.c index f094bdf9..3a9bc400 100644 --- a/src/ui/util.c +++ b/src/ui/util.c @@ -979,8 +979,8 @@ static void addTabPage_Widget_(iWidget *tabs, enum iWidgetAddPos addPos, iWidget iClob(newKeyMods_LabelWidget(label, key, kmods, format_CStr("tabs.switch page:%p", page))), addPos); setFlags_Widget(button, selected_WidgetFlag, isSel); - setFlags_Widget( - button, noTopFrame_WidgetFlag | commandOnClick_WidgetFlag | expand_WidgetFlag, iTrue); + setFlags_Widget(button, commandOnClick_WidgetFlag | expand_WidgetFlag, iTrue); + setNoTopFrame_LabelWidget((iLabelWidget *) button, iTrue); addChildPos_Widget(pages, page, addPos); if (tabCount_Widget(tabs) > 1) { setFlags_Widget(buttons, hidden_WidgetFlag, iFalse); diff --git a/src/ui/widget.c b/src/ui/widget.c index 85672c04..4e1c9119 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -406,6 +406,11 @@ static void boundsOfChildren_Widget_(const iWidget *d, iRect *bounds_out) { iRect childRect = child->rect; if (child->flags & ignoreForParentWidth_WidgetFlag) { childRect.size.x = 0; + childRect.pos.x = bounds_out->pos.x; + } + if (child->flags & ignoreForParentHeight_WidgetFlag) { + childRect.size.y = 0; + childRect.pos.y = bounds_out->pos.y; } if (isEmpty_Rect(*bounds_out)) { *bounds_out = childRect; diff --git a/src/ui/widget.h b/src/ui/widget.h index acb8fa9d..79565483 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h @@ -87,7 +87,7 @@ enum iWidgetFlag { }; /* 64-bit extended flags */ -#define rightEdgeDraggable_WidgetFlag iBit64(32) +#define rightEdgeDraggable_WidgetFlag iBit64(31) #define disabledWhenHidden_WidgetFlag iBit64(32) #define centerHorizontal_WidgetFlag iBit64(33) #define moveToParentLeftEdge_WidgetFlag iBit64(34) @@ -103,7 +103,7 @@ enum iWidgetFlag { #define drawBackgroundToVerticalSafeArea_WidgetFlag iBit64(44) #define visualOffset_WidgetFlag iBit64(45) #define parentCannotResize_WidgetFlag iBit64(46) -#define noTopFrame_WidgetFlag iBit64(47) +#define ignoreForParentHeight_WidgetFlag iBit64(47) #define unpadded_WidgetFlag iBit64(48) /* ignore parent's padding */ #define extraPadding_WidgetFlag iBit64(49) #define borderBottom_WidgetFlag iBit64(50) @@ -117,7 +117,7 @@ enum iWidgetFlag { #define parentCannotResizeHeight_WidgetFlag iBit64(58) #define ignoreForParentWidth_WidgetFlag iBit64(59) #define noFadeBackground_WidgetFlag iBit64(60) -#define destroyPending_WidgetFlag iBit64(61) /* TODO: needed? */ +#define destroyPending_WidgetFlag iBit64(61) #define leftEdgeDraggable_WidgetFlag iBit64(62) #define refChildrenOffset_WidgetFlag iBit64(63) /* visual offset determined by the offset of referenced children */ -- cgit v1.2.3 From a8fa5c21f0bc81f3f144ee29e16deab3f91296d4 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Tue, 15 Jun 2021 17:51:04 +0300 Subject: Fixed visual artifact during sidebar animation The sidebars are not supposed to have borders or background fades. --- src/ui/labelwidget.c | 26 +++++++++++++++++++------- src/ui/labelwidget.h | 2 ++ src/ui/sidebarwidget.c | 9 ++++++--- src/ui/util.c | 5 +++-- src/ui/widget.c | 2 +- src/ui/widget.h | 2 +- 6 files changed, 32 insertions(+), 14 deletions(-) (limited to 'src/ui/widget.c') diff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c index 46ef5d1f..b68ab793 100644 --- a/src/ui/labelwidget.c +++ b/src/ui/labelwidget.c @@ -46,6 +46,7 @@ struct Impl_LabelWidget { uint8_t noAutoMinHeight : 1; /* minimum height is not set automatically */ uint8_t drawAsOutline : 1; /* draw as outline, filled with background color */ uint8_t noTopFrame : 1; + uint8_t wrap : 1; } flags; }; @@ -317,7 +318,7 @@ static void draw_LabelWidget_(const iLabelWidget *d) { cstr_String(&str)); deinit_String(&str); } - if (flags & wrapText_WidgetFlag) { + if (d->flags.wrap) { const iRect inner = adjusted_Rect(innerBounds_Widget(w), init_I2(iconPad, 0), zero_I2()); const int wrap = inner.size.x; drawWrapRange_Text(d->font, topLeft_Rect(inner), wrap, fg, range_String(&d->label)); @@ -372,7 +373,7 @@ static void draw_LabelWidget_(const iLabelWidget *d) { static void sizeChanged_LabelWidget_(iLabelWidget *d) { iWidget *w = as_Widget(d); - if (flags_Widget(w) & wrapText_WidgetFlag) { + if (d->flags.wrap) { if (flags_Widget(w) & fixedHeight_WidgetFlag) { /* Calculate a new height based on the wrapping. */ w->rect.size.y = advanceWrapRange_Text( @@ -410,7 +411,7 @@ void updateSize_LabelWidget(iLabelWidget *d) { w->minSize.y = size.y; /* vertically text must remain visible */ } /* Wrapped text implies that width must be defined by arrangement. */ - if (!(flags & (fixedWidth_WidgetFlag | wrapText_WidgetFlag))) { + if (~flags & fixedWidth_WidgetFlag && !d->flags.wrap) { w->rect.size.x = size.x; } if (~flags & fixedHeight_WidgetFlag) { @@ -442,10 +443,11 @@ void init_LabelWidget(iLabelWidget *d, const char *label, const char *cmd) { d->kmods = 0; init_Click(&d->click, d, !isEmpty_String(&d->command) ? SDL_BUTTON_LEFT : 0); setFlags_Widget(w, hover_WidgetFlag, d->click.button != 0); - d->flags.alignVisual = iFalse; + d->flags.alignVisual = iFalse; d->flags.noAutoMinHeight = iFalse; - d->flags.drawAsOutline = iFalse; - d->flags.noTopFrame = iFalse; + d->flags.drawAsOutline = iFalse; + d->flags.noTopFrame = iFalse; + d->flags.wrap = iFalse; updateSize_LabelWidget(d); updateKey_LabelWidget_(d); /* could be bound to another key */ } @@ -489,8 +491,14 @@ void setNoTopFrame_LabelWidget(iLabelWidget *d, iBool noTopFrame) { d->flags.noTopFrame = noTopFrame; } +void setWrap_LabelWidget(iLabelWidget *d, iBool wrap) { + d->flags.wrap = wrap; +} + void setOutline_LabelWidget(iLabelWidget *d, iBool drawAsOutline) { - d->flags.drawAsOutline = drawAsOutline; + if (d) { + d->flags.drawAsOutline = drawAsOutline; + } } void updateText_LabelWidget(iLabelWidget *d, const iString *text) { @@ -554,6 +562,10 @@ iChar icon_LabelWidget(const iLabelWidget *d) { return d->icon; } +iBool isWrapped_LabelWidget(const iLabelWidget *d) { + return d->flags.wrap; +} + const iString *text_LabelWidget(const iLabelWidget *d) { if (!d) return collectNew_String(); return &d->label; diff --git a/src/ui/labelwidget.h b/src/ui/labelwidget.h index f6343273..b8b6fd87 100644 --- a/src/ui/labelwidget.h +++ b/src/ui/labelwidget.h @@ -32,6 +32,7 @@ iDeclareObjectConstructionArgs(LabelWidget, const char *label, const char *comma void setAlignVisually_LabelWidget(iLabelWidget *, iBool alignVisual); void setNoAutoMinHeight_LabelWidget(iLabelWidget *, iBool noAutoMinHeight); void setNoTopFrame_LabelWidget (iLabelWidget *, iBool noTopFrame); +void setWrap_LabelWidget (iLabelWidget *, iBool wrap); void setOutline_LabelWidget (iLabelWidget *, iBool drawAsOutline); void setFont_LabelWidget (iLabelWidget *, int fontId); void setTextColor_LabelWidget (iLabelWidget *, int color); @@ -53,6 +54,7 @@ const iString * text_LabelWidget (const iLabelWidget *); const iString * sourceText_LabelWidget (const iLabelWidget *); /* untranslated */ const iString * command_LabelWidget (const iLabelWidget *); iChar icon_LabelWidget (const iLabelWidget *); +iBool isWrapped_LabelWidget (const iLabelWidget *); iLabelWidget *newKeyMods_LabelWidget(const char *label, int key, int kmods, const char *command); iLabelWidget *newColor_LabelWidget (const char *text, int color); diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index b4948821..c0a22e99 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -523,15 +523,17 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { addChild_Widget(div, iClob(makePadding_Widget(gap_UI))); addChild_Widget(div, iClob(new_LabelWidget("${menu.identity.import}", "ident.import"))); addChildFlags_Widget(div, iClob(new_Widget()), expand_WidgetFlag); /* pad */ + iLabelWidget *linkLabel; setBackgroundColor_Widget( addChildFlags_Widget( div, - iClob(new_LabelWidget(format_CStr(cstr_Lang("ident.gotohelp"), + iClob(linkLabel = new_LabelWidget(format_CStr(cstr_Lang("ident.gotohelp"), uiTextStrong_ColorEscape, restore_ColorEscape), "!open newtab:1 gotoheading:1.6 url:about:help")), - frameless_WidgetFlag | fixedHeight_WidgetFlag | wrapText_WidgetFlag), + frameless_WidgetFlag | fixedHeight_WidgetFlag), uiBackgroundSidebar_ColorId); + setWrap_LabelWidget(linkLabel, iTrue); addChild_Widget(d->blank, iClob(div)); } // arrange_Widget(d->blank); @@ -631,7 +633,8 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { setBackgroundColor_Widget(w, none_ColorId); setFlags_Widget(w, collapse_WidgetFlag | hidden_WidgetFlag | arrangeHorizontal_WidgetFlag | - resizeWidthOfChildren_WidgetFlag, + resizeWidthOfChildren_WidgetFlag | noFadeBackground_WidgetFlag | + noShadowBorder_WidgetFlag, iTrue); iZap(d->modeScroll); d->side = side; diff --git a/src/ui/util.c b/src/ui/util.c index 3a9bc400..e0b05a44 100644 --- a/src/ui/util.c +++ b/src/ui/util.c @@ -710,7 +710,8 @@ iWidget *makeMenu_Widget(iWidget *parent, const iMenuItem *items, size_t n) { menu, iClob(newKeyMods_LabelWidget(labelText, item->key, item->kmods, item->command)), noBackground_WidgetFlag | frameless_WidgetFlag | alignLeft_WidgetFlag | - drawKey_WidgetFlag | (isInfo ? wrapText_WidgetFlag : 0) | itemFlags); + drawKey_WidgetFlag | itemFlags); + setWrap_LabelWidget(label, isInfo); haveIcons |= checkIcon_LabelWidget(label); updateSize_LabelWidget(label); /* drawKey was set */ if (isInfo) { @@ -776,7 +777,7 @@ void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, iBool postCommands) { if (isInstance_Object(i.object, &Class_LabelWidget)) { iLabelWidget *label = i.object; const iBool isCaution = startsWith_String(text_LabelWidget(label), uiTextCaution_ColorEscape); - if (flags_Widget(as_Widget(label)) & wrapText_WidgetFlag) { + if (isWrapped_LabelWidget(label)) { continue; } if (deviceType_App() == desktop_AppDeviceType) { diff --git a/src/ui/widget.c b/src/ui/widget.c index 4e1c9119..992f115d 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -1164,7 +1164,7 @@ void drawBackground_Widget(const iWidget *d) { shadowBorder = iFalse; } } - if (shadowBorder) { + if (shadowBorder && ~d->flags & noShadowBorder_WidgetFlag) { iPaint p; init_Paint(&p); drawSoftShadow_Paint(&p, bounds_Widget(d), 12 * gap_UI, black_ColorId, 30); diff --git a/src/ui/widget.h b/src/ui/widget.h index 79565483..41784b99 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h @@ -92,7 +92,7 @@ enum iWidgetFlag { #define centerHorizontal_WidgetFlag iBit64(33) #define moveToParentLeftEdge_WidgetFlag iBit64(34) #define moveToParentRightEdge_WidgetFlag iBit64(35) -#define wrapText_WidgetFlag iBit64(36) +#define noShadowBorder_WidgetFlag iBit64(36) #define borderTop_WidgetFlag iBit64(37) #define overflowScrollable_WidgetFlag iBit64(38) #define focusRoot_WidgetFlag iBit64(39) -- cgit v1.2.3