summaryrefslogtreecommitdiff
path: root/src/ui/documentwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r--src/ui/documentwidget.c97
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
587static 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
587static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) { 609static 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
3090static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iColorId color, 3115static 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
3626static 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
3594static void draw_DocumentWidget_(const iDocumentWidget *d) { 3647static 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