From 0e7060d5306fef1f585982cc78223250d3ee8551 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sun, 12 Sep 2021 21:00:44 +0300 Subject: Mobile: Better Settings tap targets; fixed safe area drawing --- src/ui/inputwidget.c | 11 ++++---- src/ui/listwidget.c | 1 + src/ui/mobile.c | 33 ++++++++++++++++++++++- src/ui/paint.c | 25 +++++++++++++++++- src/ui/root.c | 4 ++- src/ui/touch.c | 7 +++++ src/ui/util.c | 9 ++++++- src/ui/widget.c | 75 ++++++++++++++++++++++++++++++++++++++++++++-------- src/ui/widget.h | 1 + src/ui/window.c | 11 ++++---- 10 files changed, 152 insertions(+), 25 deletions(-) (limited to 'src/ui') diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c index 802a2d6c..59d62544 100644 --- a/src/ui/inputwidget.c +++ b/src/ui/inputwidget.c @@ -27,6 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "keys.h" #include "prefs.h" #include "lang.h" +#include "touch.h" #include "app.h" #include @@ -1565,11 +1566,11 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { } switch (processEvent_Click(&d->click, ev)) { case none_ClickResult: - if (ev->type == SDL_MOUSEBUTTONUP && - deviceType_App() != desktop_AppDeviceType && isFocused_Widget(d)) { - setFocus_Widget(NULL); - return iTrue; - } +// if (ev->type == SDL_MOUSEBUTTONUP && +// deviceType_App() != desktop_AppDeviceType && isFocused_Widget(d)) { +// setFocus_Widget(NULL); +// return iTrue; +// } break; case started_ClickResult: { setFocus_Widget(w); diff --git a/src/ui/listwidget.c b/src/ui/listwidget.c index 46d32e9a..6fa23986 100644 --- a/src/ui/listwidget.c +++ b/src/ui/listwidget.c @@ -391,6 +391,7 @@ static void draw_ListWidget_(const iListWidget *d) { const int scrollY = pos_SmoothScroll(&d->scrollY); iPaint p; init_Paint(&p); + drawLayerEffects_Widget(w); drawBackground_Widget(w); alloc_VisBuf(d->visBuf, bounds.size, d->itemHeight); /* Update invalid regions/items. */ { diff --git a/src/ui/mobile.c b/src/ui/mobile.c index 9e2dc4f7..4c183ffa 100644 --- a/src/ui/mobile.c +++ b/src/ui/mobile.c @@ -129,6 +129,12 @@ static iBool mainDetailSplitHandler_(iWidget *mainDetailSplit, const char *cmd) } arrange_Widget(mainDetailSplit); } + else if (equal_Command(cmd, "mouse.clicked") && arg_Command(cmd)) { + if (focus_Widget() && class_Widget(focus_Widget()) == &Class_InputWidget) { + setFocus_Widget(NULL); + return iTrue; + } + } return iFalse; } @@ -331,7 +337,7 @@ static iWidget *makeValuePaddingWithHeading_(iLabelWidget *heading, iWidget *val //setFixedSize_Widget(as_Widget(heading), init_I2(-1, height_Widget(value))); setFont_LabelWidget(heading, labelFont_()); setTextColor_LabelWidget(heading, uiTextStrong_ColorId); - if (isInput) { + if (isInput && ~value->flags & fixedWidth_WidgetFlag) { addChildFlags_Widget(div, iClob(value), expand_WidgetFlag); } else if (isInstance_Object(value, &Class_LabelWidget) && @@ -388,6 +394,27 @@ static size_t countItems_(const iMenuItem *itemsNullTerminated) { return num; } +static iBool dropdownHeadingHandler_(iWidget *d, const char *cmd) { + if (isVisible_Widget(d) && + equal_Command(cmd, "mouse.clicked") && contains_Widget(d, coord_Command(cmd)) && + arg_Command(cmd)) { + postCommand_Widget(userData_Object(d), + cstr_String(command_LabelWidget(userData_Object(d)))); + return iTrue; + } + return iFalse; +} + +static iBool inputHeadingHandler_(iWidget *d, const char *cmd) { + if (isVisible_Widget(d) && + equal_Command(cmd, "mouse.clicked") && contains_Widget(d, coord_Command(cmd)) && + arg_Command(cmd)) { + setFocus_Widget(userData_Object(d)); + return iTrue; + } + return iFalse; +} + void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) { iWidget * widget = NULL; iLabelWidget *heading = NULL; @@ -434,6 +461,8 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) { frameless_WidgetFlag, iTrue); setId_Widget(as_Widget(drop), id); widget = makeValuePaddingWithHeading_(heading = makeHeading_Widget(label), as_Widget(drop)); + setCommandHandler_Widget(widget, dropdownHeadingHandler_); + setUserData_Object(widget, drop); } else if (equal_Command(spec, "radio") || equal_Command(spec, "buttons")) { const iBool isRadio = equal_Command(spec, "radio"); @@ -504,6 +533,8 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) { } widget = makeValuePaddingWithHeading_(heading = makeHeading_Widget(label), as_Widget(input)); + setCommandHandler_Widget(widget, inputHeadingHandler_); + setUserData_Object(widget, input); } } else if (equal_Command(spec, "button")) { diff --git a/src/ui/paint.c b/src/ui/paint.c index af62f908..71ebb81d 100644 --- a/src/ui/paint.c +++ b/src/ui/paint.c @@ -65,10 +65,33 @@ void endTarget_Paint(iPaint *d) { void setClip_Paint(iPaint *d, iRect rect) { //rect = intersect_Rect(rect, rect_Root(get_Root())); + addv_I2(&rect.pos, origin_Paint); if (isEmpty_Rect(rect)) { rect = init_Rect(0, 0, 1, 1); } - addv_I2(&rect.pos, origin_Paint); +// iRect root = rect_Root(get_Root()); + iRect targetRect = zero_Rect(); + SDL_Texture *target = SDL_GetRenderTarget(renderer_Paint_(d)); + if (target) { + SDL_QueryTexture(target, NULL, NULL, &targetRect.size.x, &targetRect.size.y); + rect = intersect_Rect(rect, targetRect); + } + else { + rect = intersect_Rect(rect, rect_Root(get_Root())); + } + + /*if (rect.pos.x < 0) { + adjustEdges_Rect(&rect, 0, 0, 0, -rect.pos.x); + } + if (rect.pos.y < 0) { + adjustEdges_Rect(&rect, -rect.pos.y, 0, 0, 0); + } + if (right_Rect(rect) > right_Rect(root)) { + adjustEdges_Rect(&rect, 0, right_Rect(root) - right_Rect(rect), 0, 0); + } + if (bottom_Rect(rect) > bottom_Rect(root)) { + adjustEdges_Rect(&rect, 0, bottom_Rect(root) - bottom_Rect(rect), 0, 0); + }*/ SDL_RenderSetClipRect(renderer_Paint_(d), (const SDL_Rect *) &rect); } diff --git a/src/ui/root.c b/src/ui/root.c index 7b2b5b15..59f98aa4 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -525,7 +525,9 @@ void updateToolbarColors_Root(iRoot *d) { #if defined (iPlatformMobile) iWidget *toolBar = findChild_Widget(d->widget, "toolbar"); if (toolBar) { - const iBool isSidebarVisible = isVisible_Widget(findChild_Widget(d->widget, "sidebar")); + const iBool isSidebarVisible = + isVisible_Widget(findChild_Widget(d->widget, "sidebar")) || + isVisible_Widget(findChild_Widget(d->widget, "sidebar2")); const int bg = isSidebarVisible ? uiBackgroundSidebar_ColorId : tmBannerBackground_ColorId; setBackgroundColor_Widget(toolBar, bg); diff --git a/src/ui/touch.c b/src/ui/touch.c index f0456acb..5fc8f245 100644 --- a/src/ui/touch.c +++ b/src/ui/touch.c @@ -254,6 +254,8 @@ static iFloat3 gestureVector_Touch_(const iTouch *d) { } static void update_TouchState_(void *ptr) { + iWindow *win = get_Window(); + const iWidget *oldHover = win->hover; iTouchState *d = ptr; /* Check for long presses to simulate right clicks. */ const uint32_t nowTime = SDL_GetTicks(); @@ -293,6 +295,7 @@ static void update_TouchState_(void *ptr) { /* Looks like a possible tap. */ dispatchNotification_Touch_(touch, widgetTapBegins_UserEventCode); dispatchMotion_Touch_(touch->pos[0], 0); + refresh_Widget(touch->affinity); touch->isTapBegun = iTrue; } if (!touch->isTapAndHold && nowTime - touch->startTime >= longPressSpanMs_ && @@ -363,6 +366,10 @@ static void update_TouchState_(void *ptr) { if (!isEmpty_Array(d->touches) || !isEmpty_Array(d->moms)) { addTickerRoot_App(update_TouchState_, NULL, ptr); } + if (oldHover != win->hover) { + refresh_Widget(oldHover); + refresh_Widget(win->hover); + } } #if 0 diff --git a/src/ui/util.c b/src/ui/util.c index 05d39c01..48ed41a6 100644 --- a/src/ui/util.c +++ b/src/ui/util.c @@ -1349,10 +1349,17 @@ iWidget *makeValueInput_Widget(iWidget *parent, const iString *initialValue, con 2))); // finalizeSheet_Mobile(dlg); arrange_Widget(dlg); - setupSheetTransition_Mobile(dlg, incoming_TransitionFlag | top_TransitionDir); if (parent) { setFocus_Widget(as_Widget(input)); } + /* Check that the top is in the safe area. */ { + int top = top_Rect(bounds_Widget(dlg)); + int delta = top - top_Rect(safeRect_Root(dlg->root)); + if (delta < 0) { + dlg->rect.pos.y -= delta; + } + } + setupSheetTransition_Mobile(dlg, incoming_TransitionFlag | top_TransitionDir); return dlg; } diff --git a/src/ui/widget.c b/src/ui/widget.c index 7665c5bc..0765bf9f 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -89,7 +89,7 @@ static void release_WidgetDrawBuffer(iWidgetDrawBuffer *d) { static iRect boundsForDraw_Widget_(const iWidget *d) { iRect bounds = bounds_Widget(d); if (d->flags & drawBackgroundToBottom_WidgetFlag) { - bounds.size.y = iMaxi(bounds.size.y, size_Root(d->root).y - top_Rect(bounds)); + bounds.size.y = iMax(bounds.size.y, size_Root(d->root).y); } return bounds; } @@ -1218,7 +1218,7 @@ iLocalDef iBool isDrawn_Widget_(const iWidget *d) { return ~d->flags & hidden_WidgetFlag || d->flags & visualOffset_WidgetFlag; } -static void drawLayerEffects_Widget_(const iWidget *d) { +void drawLayerEffects_Widget(const iWidget *d) { /* Layered effects are not buffered, so they are drawn here separately. */ iAssert(isDrawn_Widget_(d)); iBool shadowBorder = (d->flags & keepOnTop_WidgetFlag && ~d->flags & mouseModal_WidgetFlag) != 0; @@ -1248,6 +1248,48 @@ static void drawLayerEffects_Widget_(const iWidget *d) { fillRect_Paint(&p, rect_Root(d->root), backgroundFadeColor_Widget()); SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); } +#if defined (iPlatformAppleMobile) + if (d->bgColor >= 0 && d->flags & (drawBackgroundToHorizontalSafeArea_WidgetFlag | + drawBackgroundToVerticalSafeArea_WidgetFlag)) { + iPaint p; + init_Paint(&p); + const iRect rect = bounds_Widget(d); + const iInt2 rootSize = size_Root(d->root); + const iInt2 center = divi_I2(rootSize, 2); + int top = 0, right = 0, bottom = 0, left = 0; + if (d->flags & drawBackgroundToHorizontalSafeArea_WidgetFlag) { + const iBool isWide = width_Rect(rect) > rootSize.x * 9 / 10; + if (isWide || mid_Rect(rect).x < center.x) { + left = -left_Rect(rect); + } + if (isWide || mid_Rect(rect).x > center.x) { + right = rootSize.x - right_Rect(rect); + } + } + if (d->flags & drawBackgroundToVerticalSafeArea_WidgetFlag) { + if (top_Rect(rect) > center.y) { + bottom = rootSize.y - bottom_Rect(rect); + } + if (bottom_Rect(rect) < center.y) { + top = -top_Rect(rect); + } + } + if (top < 0) { + fillRect_Paint(&p, (iRect){ init_I2(left_Rect(rect), 0), + init_I2(width_Rect(rect), top_Rect(rect)) }, + d->bgColor); + } + if (left < 0) { + fillRect_Paint(&p, (iRect){ init_I2(0, top_Rect(rect)), + init_I2(left_Rect(rect), height_Rect(rect)) }, d->bgColor); + } + if (right > 0) { + fillRect_Paint(&p, (iRect){ init_I2(right_Rect(rect), top_Rect(rect)), + init_I2(right, height_Rect(rect)) }, d->bgColor); + } +// adjustEdges_Rect(&rect, iMin(0, top), iMax(0, right), iMax(0, bottom), iMin(0, left)); + } +#endif } void drawBackground_Widget(const iWidget *d) { @@ -1261,12 +1303,13 @@ void drawBackground_Widget(const iWidget *d) { if (d->bgColor >= 0 || d->frameColor >= 0) { iRect rect = bounds_Widget(d); if (d->flags & drawBackgroundToBottom_WidgetFlag) { - rect.size.y = iMax(rect.size.y, size_Root(d->root).y - top_Rect(rect)); + rect.size.y += size_Root(d->root).y; // = iMax(rect.size.y, size_Root(d->root).y - top_Rect(rect)); } iPaint p; init_Paint(&p); if (d->bgColor >= 0) { -#if defined (iPlatformAppleMobile) +#if 0 && defined (iPlatformAppleMobile) + /* TODO: This is part of the unbuffered draw (layer effects). */ if (d->flags & (drawBackgroundToHorizontalSafeArea_WidgetFlag | drawBackgroundToVerticalSafeArea_WidgetFlag)) { const iInt2 rootSize = size_Root(d->root); @@ -1289,7 +1332,7 @@ void drawBackground_Widget(const iWidget *d) { top = -top_Rect(rect); } } - adjustEdges_Rect(&rect, top, right, bottom, left); + adjustEdges_Rect(&rect, iMin(0, top), iMax(0, right), iMax(0, bottom), iMin(0, left)); } #endif fillRect_Paint(&p, rect, d->bgColor); @@ -1339,7 +1382,7 @@ static void addToPotentiallyVisible_Widget_(const iWidget *d, iPtrArray *pvs, iR if (isDrawn_Widget_(d)) { iRect bounds = bounds_Widget(d); if (d->flags & drawBackgroundToBottom_WidgetFlag) { - bounds.size.y = size_Root(d->root).y - top_Rect(bounds); + bounds.size.y += size_Root(d->root).y; // iMax(bounds.size.y, size_Root(d->root).y - top_Rect(bounds)); } if (isFullyContainedByOther_Rect(bounds, *fullyMasked)) { return; /* can't be seen */ @@ -1411,14 +1454,21 @@ void setDrawBufferEnabled_Widget(iWidget *d, iBool enable) { static void beginBufferDraw_Widget_(const iWidget *d) { if (d->drawBuf) { -// printf("[%p] drawbuffer update %d\n", d, d->drawBuf->isValid); + printf("[%p] drawbuffer update %d\n", d, d->drawBuf->isValid); + if (d->drawBuf->isValid) { + iAssert(!isEqual_I2(d->drawBuf->size, boundsForDraw_Widget_(d).size)); +// printf(" drawBuf:%dx%d boundsForDraw:%dx%d\n", +// d->drawBuf->size.x, d->drawBuf->size.y, +// boundsForDraw_Widget_(d).size.x, +// boundsForDraw_Widget_(d).size.y); + } const iRect bounds = bounds_Widget(d); SDL_Renderer *render = renderer_Window(get_Window()); d->drawBuf->oldTarget = SDL_GetRenderTarget(render); d->drawBuf->oldOrigin = origin_Paint; realloc_WidgetDrawBuffer(d->drawBuf, render, boundsForDraw_Widget_(d).size); SDL_SetRenderTarget(render, d->drawBuf->texture); - //SDL_SetRenderDrawColor(render, 255, 0, 0, 128); +// SDL_SetRenderDrawColor(render, 255, 0, 0, 128); SDL_SetRenderDrawColor(render, 0, 0, 0, 0); SDL_RenderClear(render); origin_Paint = neg_I2(bounds.pos); /* with current visual offset */ @@ -1445,7 +1495,7 @@ void draw_Widget(const iWidget *d) { } return; } - drawLayerEffects_Widget_(d); + drawLayerEffects_Widget(d); if (!d->drawBuf || !checkDrawBuffer_Widget_(d)) { beginBufferDraw_Widget_(d); drawBackground_Widget(d); @@ -1755,7 +1805,9 @@ iWidget *focus_Widget(void) { } void setHover_Widget(iWidget *d) { - get_Window()->hover = d; + iWindow *win = get_Window(); + iAssert(win); + win->hover = d; } iWidget *hover_Widget(void) { @@ -1850,7 +1902,8 @@ void postCommand_Widget(const iAnyObject *d, const char *cmd, ...) { deinit_String(&str); } -void refresh_Widget(const iAnyObject *d) { +void refresh_Widget(const iAnyObject *d) { + if (!d) return; /* TODO: Could be widget specific, if parts of the tree are cached. */ /* TODO: The visbuffer in DocumentWidget and ListWidget could be moved to be a general purpose feature of Widget. */ diff --git a/src/ui/widget.h b/src/ui/widget.h index fd4d8898..b46e5177 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h @@ -204,6 +204,7 @@ iAny * findFocusable_Widget (const iWidget *startFrom, enum iWidgetF iAny * findOverflowScrollable_Widget (iWidget *); size_t childCount_Widget (const iWidget *); void draw_Widget (const iWidget *); +void drawLayerEffects_Widget (const iWidget *); void drawBackground_Widget (const iWidget *); void drawChildren_Widget (const iWidget *); void drawRoot_Widget (const iWidget *); /* root only */ diff --git a/src/ui/window.c b/src/ui/window.c index 3385f436..8034d858 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -875,7 +875,7 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { } } } - const iWidget *oldHover = d->hover; +// const iWidget *oldHover = d->hover; iBool wasUsed = iFalse; /* Dispatch first to the mouse-grabbed widget. */ // iWidget *widget = d->root.widget; @@ -929,9 +929,10 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { } } } - if (oldHover != d->hover) { - postRefresh_App(); - } +// if (oldHover != d->hover) { +// refresh_Widget(oldHover); +// refresh_Widget(d->hover); +// } if (event.type == SDL_MOUSEMOTION) { applyCursor_Window_(d); } @@ -1107,7 +1108,7 @@ void draw_Window(iWindow *d) { } setCurrent_Root(NULL); #if !defined (NDEBUG) - draw_Text(defaultBold_FontId, zero_I2(), red_ColorId, "%d", drawCount_); + draw_Text(defaultBold_FontId, safeRect_Root(d->roots[0]).pos, red_ColorId, "%d", drawCount_); drawCount_ = 0; #endif } -- cgit v1.2.3