diff options
-rw-r--r-- | src/ui/documentwidget.c | 97 |
1 files changed, 78 insertions, 19 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index c9751fe3..70499ed5 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -584,6 +584,28 @@ static void animate_DocumentWidget_(void *ticker) { | |||
584 | } | 584 | } |
585 | } | 585 | } |
586 | 586 | ||
587 | static iBool isHoverAllowed_DocumentWidget_(const iDocumentWidget *d) { | ||
588 | if (!isHover_Widget(d)) { | ||
589 | return iFalse; | ||
590 | } | ||
591 | if (!(d->state == ready_RequestState || d->state == receivedPartialResponse_RequestState)) { | ||
592 | return iFalse; | ||
593 | } | ||
594 | if (d->flags & noHoverWhileScrolling_DocumentWidgetFlag) { | ||
595 | return iFalse; | ||
596 | } | ||
597 | if (d->flags & pinchZoom_DocumentWidgetFlag) { | ||
598 | return iFalse; | ||
599 | } | ||
600 | if (flags_Widget(constAs_Widget(d)) & touchDrag_WidgetFlag) { | ||
601 | return iFalse; | ||
602 | } | ||
603 | if (flags_Widget(constAs_Widget(d->scroll)) & pressed_WidgetFlag) { | ||
604 | return iFalse; | ||
605 | } | ||
606 | return iTrue; | ||
607 | } | ||
608 | |||
587 | static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) { | 609 | static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) { |
588 | const iWidget *w = constAs_Widget(d); | 610 | const iWidget *w = constAs_Widget(d); |
589 | const iRect docBounds = documentBounds_DocumentWidget_(d); | 611 | const iRect docBounds = documentBounds_DocumentWidget_(d); |
@@ -591,13 +613,11 @@ static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) { | |||
591 | d->hoverPre = NULL; | 613 | d->hoverPre = NULL; |
592 | d->hoverLink = NULL; | 614 | d->hoverLink = NULL; |
593 | const iInt2 hoverPos = addY_I2(sub_I2(mouse, topLeft_Rect(docBounds)), value_Anim(&d->scrollY)); | 615 | const iInt2 hoverPos = addY_I2(sub_I2(mouse, topLeft_Rect(docBounds)), value_Anim(&d->scrollY)); |
594 | if (isHover_Widget(w) && (~d->flags & noHoverWhileScrolling_DocumentWidgetFlag) && | 616 | if (isHoverAllowed_DocumentWidget_(d)) { |
595 | (d->state == ready_RequestState || d->state == receivedPartialResponse_RequestState)) { | ||
596 | iConstForEach(PtrArray, i, &d->visibleLinks) { | 617 | iConstForEach(PtrArray, i, &d->visibleLinks) { |
597 | const iGmRun *run = i.ptr; | 618 | const iGmRun *run = i.ptr; |
598 | /* Click targets are slightly expanded so there are no gaps between links. */ | 619 | /* Click targets are slightly expanded so there are no gaps between links. */ |
599 | if (~d->flags & pinchZoom_DocumentWidgetFlag && | 620 | if (contains_Rect(expanded_Rect(run->bounds, init1_I2(gap_Text / 2)), hoverPos)) { |
600 | contains_Rect(expanded_Rect(run->bounds, init1_I2(gap_Text / 2)), hoverPos)) { | ||
601 | d->hoverLink = run; | 621 | d->hoverLink = run; |
602 | break; | 622 | break; |
603 | } | 623 | } |
@@ -613,7 +633,7 @@ static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) { | |||
613 | refresh_Widget(w); | 633 | refresh_Widget(w); |
614 | } | 634 | } |
615 | /* Hovering over preformatted blocks. */ | 635 | /* Hovering over preformatted blocks. */ |
616 | if (isHover_Widget(w) && ~d->flags & pinchZoom_DocumentWidgetFlag) { | 636 | if (isHoverAllowed_DocumentWidget_(d)) { |
617 | iConstForEach(PtrArray, j, &d->visiblePre) { | 637 | iConstForEach(PtrArray, j, &d->visiblePre) { |
618 | const iGmRun *run = j.ptr; | 638 | const iGmRun *run = j.ptr; |
619 | if (contains_Rect(run->bounds, hoverPos)) { | 639 | if (contains_Rect(run->bounds, hoverPos)) { |
@@ -2230,6 +2250,9 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2230 | } | 2250 | } |
2231 | } | 2251 | } |
2232 | } | 2252 | } |
2253 | if (flags_Widget(w) & touchDrag_WidgetFlag) { | ||
2254 | postCommand_App("document.select arg:0"); /* we can't handle both at the same time */ | ||
2255 | } | ||
2233 | invalidateWideRunsWithNonzeroOffset_DocumentWidget_(d); /* markers don't support offsets */ | 2256 | invalidateWideRunsWithNonzeroOffset_DocumentWidget_(d); /* markers don't support offsets */ |
2234 | resetWideRuns_DocumentWidget_(d); | 2257 | resetWideRuns_DocumentWidget_(d); |
2235 | refresh_Widget(w); | 2258 | refresh_Widget(w); |
@@ -3085,6 +3108,8 @@ struct Impl_DrawContext { | |||
3085 | iBool inSelectMark; | 3108 | iBool inSelectMark; |
3086 | iBool inFoundMark; | 3109 | iBool inFoundMark; |
3087 | iBool showLinkNumbers; | 3110 | iBool showLinkNumbers; |
3111 | iRect firstMarkRect; | ||
3112 | iRect lastMarkRect; | ||
3088 | }; | 3113 | }; |
3089 | 3114 | ||
3090 | static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iColorId color, | 3115 | static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iColorId color, |
@@ -3119,8 +3144,15 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol | |||
3119 | if (~run->flags & decoration_GmRunFlag) { | 3144 | if (~run->flags & decoration_GmRunFlag) { |
3120 | const iInt2 visPos = | 3145 | const iInt2 visPos = |
3121 | add_I2(run->bounds.pos, addY_I2(d->viewPos, -value_Anim(&d->widget->scrollY))); | 3146 | add_I2(run->bounds.pos, addY_I2(d->viewPos, -value_Anim(&d->widget->scrollY))); |
3122 | fillRect_Paint(&d->paint, (iRect){ addX_I2(visPos, x), | 3147 | const iRect rangeRect = { addX_I2(visPos, x), init_I2(w, height_Rect(run->bounds)) }; |
3123 | init_I2(w, height_Rect(run->bounds)) }, color); | 3148 | if (rangeRect.size.x) { |
3149 | fillRect_Paint(&d->paint, rangeRect, color); | ||
3150 | /* Keep track of the first and last marked rects. */ | ||
3151 | if (d->firstMarkRect.size.x == 0) { | ||
3152 | d->firstMarkRect = rangeRect; | ||
3153 | } | ||
3154 | d->lastMarkRect = rangeRect; | ||
3155 | } | ||
3124 | } | 3156 | } |
3125 | } | 3157 | } |
3126 | /* Link URLs are not part of the visible document, so they are ignored above. Handle | 3158 | /* Link URLs are not part of the visible document, so they are ignored above. Handle |
@@ -3591,6 +3623,27 @@ static void drawMedia_DocumentWidget_(const iDocumentWidget *d, iPaint *p) { | |||
3591 | } | 3623 | } |
3592 | } | 3624 | } |
3593 | 3625 | ||
3626 | static void drawPin_(iPaint *p, iRect rangeRect, int dir) { | ||
3627 | const int pinColor = tmQuote_ColorId; | ||
3628 | const int height = height_Rect(rangeRect); | ||
3629 | iRect pin; | ||
3630 | if (dir == 0) { | ||
3631 | pin = (iRect){ | ||
3632 | add_I2(topLeft_Rect(rangeRect), init_I2(-gap_UI / 4, -gap_UI)), | ||
3633 | init_I2(gap_UI / 2, height_Rect(rangeRect) + gap_UI) | ||
3634 | }; | ||
3635 | } | ||
3636 | else { | ||
3637 | pin = (iRect){ | ||
3638 | addX_I2(topRight_Rect(rangeRect), -gap_UI / 4), | ||
3639 | init_I2(gap_UI / 2, height_Rect(rangeRect) + gap_UI) | ||
3640 | }; | ||
3641 | } | ||
3642 | fillRect_Paint(p, pin, pinColor); | ||
3643 | fillRect_Paint(p, initCentered_Rect(dir == 0 ? topMid_Rect(pin) : bottomMid_Rect(pin), | ||
3644 | init1_I2(gap_UI * 2)), pinColor); | ||
3645 | } | ||
3646 | |||
3594 | static void draw_DocumentWidget_(const iDocumentWidget *d) { | 3647 | static void draw_DocumentWidget_(const iDocumentWidget *d) { |
3595 | const iWidget *w = constAs_Widget(d); | 3648 | const iWidget *w = constAs_Widget(d); |
3596 | const iRect bounds = bounds_Widget(w); | 3649 | const iRect bounds = bounds_Widget(w); |
@@ -3613,6 +3666,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { | |||
3613 | .widget = d, | 3666 | .widget = d, |
3614 | .showLinkNumbers = (d->flags & showLinkNumbers_DocumentWidgetFlag) != 0, | 3667 | .showLinkNumbers = (d->flags & showLinkNumbers_DocumentWidgetFlag) != 0, |
3615 | }; | 3668 | }; |
3669 | const iBool isTouchSelecting = (flags_Widget(w) & touchDrag_WidgetFlag) != 0; | ||
3616 | /* Currently visible region. */ | 3670 | /* Currently visible region. */ |
3617 | const iRangei vis = visibleRange_DocumentWidget_(d); | 3671 | const iRangei vis = visibleRange_DocumentWidget_(d); |
3618 | const iRangei full = { 0, size_GmDocument(d->doc).y }; | 3672 | const iRangei full = { 0, size_GmDocument(d->doc).y }; |
@@ -3667,7 +3721,10 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { | |||
3667 | draw_VisBuf(visBuf, init_I2(bounds.pos.x, yTop)); | 3721 | draw_VisBuf(visBuf, init_I2(bounds.pos.x, yTop)); |
3668 | /* Text markers. */ | 3722 | /* Text markers. */ |
3669 | if (!isEmpty_Range(&d->foundMark) || !isEmpty_Range(&d->selectMark)) { | 3723 | if (!isEmpty_Range(&d->foundMark) || !isEmpty_Range(&d->selectMark)) { |
3670 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), | 3724 | SDL_Renderer *render = renderer_Window(get_Window()); |
3725 | ctx.firstMarkRect = zero_Rect(); | ||
3726 | ctx.lastMarkRect = zero_Rect(); | ||
3727 | SDL_SetRenderDrawBlendMode(render, | ||
3671 | isDark_ColorTheme(colorTheme_App()) ? SDL_BLENDMODE_ADD | 3728 | isDark_ColorTheme(colorTheme_App()) ? SDL_BLENDMODE_ADD |
3672 | : SDL_BLENDMODE_BLEND); | 3729 | : SDL_BLENDMODE_BLEND); |
3673 | ctx.viewPos = topLeft_Rect(docBounds); | 3730 | ctx.viewPos = topLeft_Rect(docBounds); |
@@ -3685,7 +3742,12 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { | |||
3685 | } | 3742 | } |
3686 | } | 3743 | } |
3687 | render_GmDocument(d->doc, vis, drawMark_DrawContext_, &ctx); | 3744 | render_GmDocument(d->doc, vis, drawMark_DrawContext_, &ctx); |
3688 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); | 3745 | SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE); |
3746 | /* Selection range pins. */ | ||
3747 | if (isTouchSelecting) { | ||
3748 | drawPin_(&ctx.paint, ctx.firstMarkRect, 0); | ||
3749 | drawPin_(&ctx.paint, ctx.lastMarkRect, 1); | ||
3750 | } | ||
3689 | } | 3751 | } |
3690 | drawMedia_DocumentWidget_(d, &ctx.paint); | 3752 | drawMedia_DocumentWidget_(d, &ctx.paint); |
3691 | unsetClip_Paint(&ctx.paint); | 3753 | unsetClip_Paint(&ctx.paint); |
@@ -3755,16 +3817,13 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { | |||
3755 | d->pinchZoomPosted); | 3817 | d->pinchZoomPosted); |
3756 | } | 3818 | } |
3757 | /* Touch selection indicator. */ | 3819 | /* Touch selection indicator. */ |
3758 | if (flags_Widget(w) & touchDrag_WidgetFlag) { | 3820 | if (isTouchSelecting) { |
3759 | iString msg; | 3821 | iRect rect = { topLeft_Rect(bounds), |
3760 | init_String(&msg); | 3822 | init_I2(width_Rect(bounds), lineHeight_Text(uiLabelBold_FontId)) }; |
3761 | format_String(&msg, "Selecting: drag and tap"); /* TODO: Needed? (N bytes selected?) */ | 3823 | fillRect_Paint(&ctx.paint, rect, uiTextAction_ColorId); |
3762 | fillRect_Paint(&ctx.paint, (iRect){ topLeft_Rect(bounds), | 3824 | const iRangecc mark = selectMark_DocumentWidget_(d); |
3763 | init_I2(width_Rect(bounds), lineHeight_Text(uiLabelBold_FontId))}, | 3825 | drawCentered_Text(uiLabelBold_FontId, rect, iFalse, uiBackground_ColorId, "%zu bytes selected", |
3764 | uiTextAction_ColorId); | 3826 | size_Range(&mark)); |
3765 | drawRange_Text(uiLabelBold_FontId, addX_I2(topLeft_Rect(bounds), 3 * gap_UI), | ||
3766 | uiBackground_ColorId, range_String(&msg)); | ||
3767 | deinit_String(&msg); | ||
3768 | } | 3827 | } |
3769 | } | 3828 | } |
3770 | 3829 | ||