diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-09-26 13:51:14 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-09-26 13:51:14 +0300 |
commit | 1449337bde58999838b34edcaf998d72b2eb1f32 (patch) | |
tree | f99c2f9f30643606dd0f093d8b9755bbd7dc5689 /src | |
parent | 790a2c49a0290ce872ec8929b063337eacde9880 (diff) |
DocumentWidget: Show top heading on the side
Diffstat (limited to 'src')
-rw-r--r-- | src/ui/documentwidget.c | 94 |
1 files changed, 60 insertions, 34 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index ec6288d5..3fbedb9a 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -173,6 +173,7 @@ struct Impl_DocumentWidget { | |||
173 | const iGmRun * contextLink; | 173 | const iGmRun * contextLink; |
174 | iBool noHoverWhileScrolling; | 174 | iBool noHoverWhileScrolling; |
175 | iBool showLinkNumbers; | 175 | iBool showLinkNumbers; |
176 | const iGmRun * firstVisibleRun; | ||
176 | const iGmRun * lastVisibleRun; | 177 | const iGmRun * lastVisibleRun; |
177 | iClick click; | 178 | iClick click; |
178 | float initNormScrollY; | 179 | float initNormScrollY; |
@@ -222,6 +223,7 @@ void init_DocumentWidget(iDocumentWidget *d) { | |||
222 | d->contextLink = NULL; | 223 | d->contextLink = NULL; |
223 | d->noHoverWhileScrolling = iFalse; | 224 | d->noHoverWhileScrolling = iFalse; |
224 | d->showLinkNumbers = iFalse; | 225 | d->showLinkNumbers = iFalse; |
226 | d->firstVisibleRun = NULL; | ||
225 | d->lastVisibleRun = NULL; | 227 | d->lastVisibleRun = NULL; |
226 | d->visBuf = new_VisBuf(); | 228 | d->visBuf = new_VisBuf(); |
227 | d->invalidRuns = new_PtrSet(); | 229 | d->invalidRuns = new_PtrSet(); |
@@ -332,7 +334,12 @@ static iRangei visibleRange_DocumentWidget_(const iDocumentWidget *d) { | |||
332 | 334 | ||
333 | static void addVisibleLink_DocumentWidget_(void *context, const iGmRun *run) { | 335 | static void addVisibleLink_DocumentWidget_(void *context, const iGmRun *run) { |
334 | iDocumentWidget *d = context; | 336 | iDocumentWidget *d = context; |
335 | d->lastVisibleRun = run; | 337 | if (~run->flags & decoration_GmRunFlag && !run->imageId) { |
338 | if (!d->firstVisibleRun) { | ||
339 | d->firstVisibleRun = run; | ||
340 | } | ||
341 | d->lastVisibleRun = run; | ||
342 | } | ||
336 | if (run->linkId && linkFlags_GmDocument(d->doc, run->linkId) & supportedProtocol_GmLinkFlag) { | 343 | if (run->linkId && linkFlags_GmDocument(d->doc, run->linkId) & supportedProtocol_GmLinkFlag) { |
337 | pushBack_PtrArray(&d->visibleLinks, run); | 344 | pushBack_PtrArray(&d->visibleLinks, run); |
338 | } | 345 | } |
@@ -422,7 +429,7 @@ static void updateOutlineOpacity_DocumentWidget_(iDocumentWidget *d) { | |||
422 | if (contains_Widget(constAs_Widget(d->scroll), mouseCoord_Window(get_Window()))) { | 429 | if (contains_Widget(constAs_Widget(d->scroll), mouseCoord_Window(get_Window()))) { |
423 | opacity = 1.0f; | 430 | opacity = 1.0f; |
424 | } | 431 | } |
425 | setValue_Anim(&d->outlineOpacity, opacity, opacity > 0.5f? 166 : 333); | 432 | setValue_Anim(&d->outlineOpacity, opacity, opacity > 0.5f? 100 : 166); |
426 | animate_DocumentWidget_(d); | 433 | animate_DocumentWidget_(d); |
427 | } | 434 | } |
428 | 435 | ||
@@ -435,6 +442,7 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { | |||
435 | d->scrollY, | 442 | d->scrollY, |
436 | docSize > 0 ? height_Rect(bounds) * size_Range(&visRange) / docSize : 0); | 443 | docSize > 0 ? height_Rect(bounds) * size_Range(&visRange) / docSize : 0); |
437 | clear_PtrArray(&d->visibleLinks); | 444 | clear_PtrArray(&d->visibleLinks); |
445 | d->firstVisibleRun = NULL; | ||
438 | render_GmDocument(d->doc, visRange, addVisibleLink_DocumentWidget_, d); | 446 | render_GmDocument(d->doc, visRange, addVisibleLink_DocumentWidget_, d); |
439 | updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window())); | 447 | updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window())); |
440 | updateSideOpacity_DocumentWidget_(d); | 448 | updateSideOpacity_DocumentWidget_(d); |
@@ -1496,6 +1504,11 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1496 | return iFalse; | 1504 | return iFalse; |
1497 | } | 1505 | } |
1498 | 1506 | ||
1507 | static int outlineHeight_DocumentWidget_(const iDocumentWidget *d) { | ||
1508 | if (isEmpty_Array(&d->outline)) return 0; | ||
1509 | return bottom_Rect(((const iOutlineItem *) constBack_Array(&d->outline))->rect); | ||
1510 | } | ||
1511 | |||
1499 | static size_t visibleLinkOrdinal_DocumentWidget_(const iDocumentWidget *d, iGmLinkId linkId) { | 1512 | static size_t visibleLinkOrdinal_DocumentWidget_(const iDocumentWidget *d, iGmLinkId linkId) { |
1500 | size_t ord = 0; | 1513 | size_t ord = 0; |
1501 | const iRangei visRange = visibleRange_DocumentWidget_(d); | 1514 | const iRangei visRange = visibleRange_DocumentWidget_(d); |
@@ -1632,9 +1645,17 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
1632 | } | 1645 | } |
1633 | } | 1646 | } |
1634 | else if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { | 1647 | else if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { |
1648 | float acceleration = 1.0f; | ||
1649 | if (prefs_App()->hoverOutline && | ||
1650 | contains_Widget(constAs_Widget(d->scroll), mouseCoord_Window(get_Window()))) { | ||
1651 | const int outHeight = outlineHeight_DocumentWidget_(d); | ||
1652 | if (outHeight > height_Rect(bounds_Widget(w))) { | ||
1653 | acceleration = (float) size_GmDocument(d->doc).y / (float) outHeight; | ||
1654 | } | ||
1655 | } | ||
1635 | #if defined (iPlatformApple) | 1656 | #if defined (iPlatformApple) |
1636 | /* Momentum scrolling. */ | 1657 | /* Momentum scrolling. */ |
1637 | scroll_DocumentWidget_(d, -ev->wheel.y * get_Window()->pixelRatio); | 1658 | scroll_DocumentWidget_(d, -ev->wheel.y * get_Window()->pixelRatio * acceleration); |
1638 | #else | 1659 | #else |
1639 | if (keyMods_Sym(SDL_GetModState()) == KMOD_PRIMARY) { | 1660 | if (keyMods_Sym(SDL_GetModState()) == KMOD_PRIMARY) { |
1640 | postCommandf_App("zoom.delta arg:%d", ev->wheel.y > 0 ? 10 : -10); | 1661 | postCommandf_App("zoom.delta arg:%d", ev->wheel.y > 0 ? 10 : -10); |
@@ -1642,7 +1663,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
1642 | } | 1663 | } |
1643 | smoothScroll_DocumentWidget_( | 1664 | smoothScroll_DocumentWidget_( |
1644 | d, | 1665 | d, |
1645 | -3 * ev->wheel.y * lineHeight_Text(paragraph_FontId), | 1666 | -3 * ev->wheel.y * lineHeight_Text(paragraph_FontId) * acceleration, |
1646 | gap_Text * smoothSpeed_DocumentWidget_ + | 1667 | gap_Text * smoothSpeed_DocumentWidget_ + |
1647 | (isSmoothScrolling_DocumentWidget_(d) ? d->smoothSpeed : 0)); | 1668 | (isSmoothScrolling_DocumentWidget_(d) ? d->smoothSpeed : 0)); |
1648 | #endif | 1669 | #endif |
@@ -2069,6 +2090,24 @@ static int drawSideRect_(iPaint *p, iRect rect) { //}, int thickness) { | |||
2069 | return fg; | 2090 | return fg; |
2070 | } | 2091 | } |
2071 | 2092 | ||
2093 | static iRangecc currentHeading_DocumentWidget_(const iDocumentWidget *d) { | ||
2094 | iRangecc heading = iNullRange; | ||
2095 | if (d->firstVisibleRun) { | ||
2096 | iConstForEach(Array, i, headings_GmDocument(d->doc)) { | ||
2097 | const iGmHeading *head = i.value; | ||
2098 | if (head->level == 0) { | ||
2099 | if (head->text.start <= d->firstVisibleRun->text.start) { | ||
2100 | heading = head->text; | ||
2101 | } | ||
2102 | if (d->lastVisibleRun && head->text.start > d->lastVisibleRun->text.start) { | ||
2103 | break; | ||
2104 | } | ||
2105 | } | ||
2106 | } | ||
2107 | } | ||
2108 | return heading; | ||
2109 | } | ||
2110 | |||
2072 | static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { | 2111 | static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { |
2073 | const iWidget *w = constAs_Widget(d); | 2112 | const iWidget *w = constAs_Widget(d); |
2074 | const iRect bounds = bounds_Widget(w); | 2113 | const iRect bounds = bounds_Widget(w); |
@@ -2090,22 +2129,18 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { | |||
2090 | p.alpha = opacity * 255; | 2129 | p.alpha = opacity * 255; |
2091 | //int offset = iMax(0, bottom_Rect(banner->visBounds) - d->scrollY); | 2130 | //int offset = iMax(0, bottom_Rect(banner->visBounds) - d->scrollY); |
2092 | rect.pos.y += height_Rect(bounds) / 2 - rect.size.y / 2 - (banner ? banner->visBounds.size.y / 2 : 0); // offset; | 2131 | rect.pos.y += height_Rect(bounds) / 2 - rect.size.y / 2 - (banner ? banner->visBounds.size.y / 2 : 0); // offset; |
2132 | //rect.pos.y -= lineHeight_Text(heading3_FontId) / 2; /* the heading text underneath */ | ||
2093 | int fg = drawSideRect_(&p, rect); //, gap_UI / 2); | 2133 | int fg = drawSideRect_(&p, rect); //, gap_UI / 2); |
2094 | // if (equal_Color(get_Color(tmBannerBackground_ColorId), get_Color(tmBackground_ColorId))) { | ||
2095 | // drawRectThickness_Paint(&p, rect, gap_UI / 2, tmBannerIcon_ColorId); | ||
2096 | // } | ||
2097 | // else { | ||
2098 | // fillRect_Paint(&p, rect, tmBannerBackground_ColorId); | ||
2099 | // } | ||
2100 | iString str; | 2134 | iString str; |
2101 | initUnicodeN_String(&str, &icon, 1); | 2135 | initUnicodeN_String(&str, &icon, 1); |
2102 | drawCentered_Text(banner_FontId, rect, iTrue, fg, "%s", cstr_String(&str)); | 2136 | drawCentered_Text(banner_FontId, rect, iTrue, fg, "%s", cstr_String(&str)); |
2103 | #if 0 | 2137 | #if 1 |
2104 | if (avail >= minBannerSize * 2) { | 2138 | if (avail >= minBannerSize * 2.25f) { |
2105 | const char *endp; | 2139 | iRangecc text = currentHeading_DocumentWidget_(d);// bannerText_DocumentWidget_(d); |
2106 | iRangecc text = bannerText_DocumentWidget_(d); | ||
2107 | iInt2 pos = addY_I2(bottomLeft_Rect(rect), gap_Text); | 2140 | iInt2 pos = addY_I2(bottomLeft_Rect(rect), gap_Text); |
2108 | const int font = heading3_FontId; | 2141 | const int font = heading3_FontId; |
2142 | drawWrapRange_Text(font, pos, avail - margin, tmBannerSideTitle_ColorId, text); | ||
2143 | #if 0 | ||
2109 | while (!isEmpty_Range(&text)) { | 2144 | while (!isEmpty_Range(&text)) { |
2110 | tryAdvance_Text(font, text, avail - 2 * margin, &endp); | 2145 | tryAdvance_Text(font, text, avail - 2 * margin, &endp); |
2111 | drawRange_Text( | 2146 | drawRange_Text( |
@@ -2117,6 +2152,7 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { | |||
2117 | text.start = endp; | 2152 | text.start = endp; |
2118 | pos.y += lineHeight_Text(font); | 2153 | pos.y += lineHeight_Text(font); |
2119 | } | 2154 | } |
2155 | #endif | ||
2120 | } | 2156 | } |
2121 | #endif | 2157 | #endif |
2122 | setOpacity_Text(1.0f); | 2158 | setOpacity_Text(1.0f); |
@@ -2142,31 +2178,21 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { | |||
2142 | /* Outline on the right side. */ | 2178 | /* Outline on the right side. */ |
2143 | const float outlineOpacity = value_Anim(&d->outlineOpacity); | 2179 | const float outlineOpacity = value_Anim(&d->outlineOpacity); |
2144 | if (prefs_App()->hoverOutline && !isEmpty_Array(&d->outline) && outlineOpacity > 0.0f) { | 2180 | if (prefs_App()->hoverOutline && !isEmpty_Array(&d->outline) && outlineOpacity > 0.0f) { |
2145 | // const int font = uiLabel_FontId; | 2181 | const int innerWidth = outlineWidth_DocumentWidget_(d); |
2146 | //iRect outlineRect = initCorners_Rect(topRight_Rect(docBounds), bottomRight_Rect(bounds)); | 2182 | const int outWidth = innerWidth + 2 * outlinePadding_DocumentWidget_ * gap_UI; |
2147 | //const int excess = width_Rect(outlineRect) - 75 * gap_UI; | 2183 | const int topMargin = 0; |
2148 | // if (excess > 0) { | 2184 | const int bottomMargin = 3 * gap_UI; |
2149 | // adjustEdges_Rect(&outlineRect, 0, 0, 0, excess); | 2185 | const int scrollMax = scrollMax_DocumentWidget_(d); |
2150 | // } | 2186 | const int outHeight = outlineHeight_DocumentWidget_(d); |
2151 | // const int margin = gap_UI * d->pageMargin; | 2187 | const int oversize = outHeight - height_Rect(bounds) + topMargin + bottomMargin; |
2152 | const int innerWidth = outlineWidth_DocumentWidget_(d); | ||
2153 | const int outWidth = innerWidth + 2 * outlinePadding_DocumentWidget_ * gap_UI; | ||
2154 | const int topMargin = 0;//d->pageMargin * gap_UI; // + (banner ? banner->visBounds.size.y : 0); | ||
2155 | const int bottomMargin = 3 * gap_UI; //d->pageMargin * gap_UI; | ||
2156 | iInt2 pos = add_I2(topRight_Rect(bounds), init_I2(-outWidth - width_Widget(d->scroll), topMargin)); | ||
2157 | // const int lineWidth = avail - margin; | ||
2158 | // pos.y = drawRangeWrap_Text(uiContent_FontId, pos, lineWidth, tmBannerIcon_ColorId, | ||
2159 | // bannerText_DocumentWidget_(d)); | ||
2160 | // pos.y += gap_UI; | ||
2161 | const int scrollMax = scrollMax_DocumentWidget_(d); | ||
2162 | const int outHeight = bottom_Rect(((const iOutlineItem *) constBack_Array(&d->outline))->rect); | ||
2163 | const int oversize = outHeight - height_Rect(bounds) + topMargin + bottomMargin; | ||
2164 | const int scroll = | 2188 | const int scroll = |
2165 | (oversize > 0 && scrollMax > 0 ? oversize * d->scrollY / scrollMax_DocumentWidget_(d) | 2189 | (oversize > 0 && scrollMax > 0 ? oversize * d->scrollY / scrollMax_DocumentWidget_(d) |
2166 | : 0); | 2190 | : 0); |
2191 | iInt2 pos = | ||
2192 | add_I2(topRight_Rect(bounds), init_I2(-outWidth - width_Widget(d->scroll), topMargin)); | ||
2167 | /* Center short outlines vertically. */ | 2193 | /* Center short outlines vertically. */ |
2168 | if (oversize < 0) { | 2194 | if (oversize < 0) { |
2169 | pos.y -= oversize / 2;// + (banner ? banner->visBounds.size.y / 2 : 0); | 2195 | pos.y -= oversize / 2; |
2170 | } | 2196 | } |
2171 | pos.y -= scroll; | 2197 | pos.y -= scroll; |
2172 | setOpacity_Text(outlineOpacity); | 2198 | setOpacity_Text(outlineOpacity); |