From ef297dafa84154d8f28f014410ab742f7994c557 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Tue, 18 Aug 2020 10:53:01 +0300 Subject: Render target switching --- src/ui/paint.c | 18 ++++++++++++++++++ src/ui/paint.h | 10 +++++++--- src/ui/text.c | 6 ++++-- 3 files changed, 29 insertions(+), 5 deletions(-) (limited to 'src/ui') diff --git a/src/ui/paint.c b/src/ui/paint.c index 85e75f15..a55670e9 100644 --- a/src/ui/paint.c +++ b/src/ui/paint.c @@ -1,5 +1,7 @@ #include "paint.h" +#include + iLocalDef SDL_Renderer *renderer_Paint_(const iPaint *d) { iAssert(d->dst); return d->dst->render; @@ -12,6 +14,18 @@ static void setColor_Paint_(const iPaint *d, int color) { void init_Paint(iPaint *d) { d->dst = get_Window(); + d->oldTarget = NULL; +} + +void beginTarget_Paint(iPaint *d, SDL_Texture *target) { + SDL_Renderer *rend = renderer_Paint_(d); + d->oldTarget = SDL_GetRenderTarget(rend); + SDL_SetRenderTarget(rend, target); +} + +void endTarget_Paint(iPaint *d) { + SDL_SetRenderTarget(renderer_Paint_(d), d->oldTarget); + d->oldTarget = NULL; } void setClip_Paint(iPaint *d, iRect rect) { @@ -19,8 +33,12 @@ void setClip_Paint(iPaint *d, iRect rect) { } void unsetClip_Paint(iPaint *d) { +#if SDL_VERSION_ATLEAST(2, 0, 12) + SDL_RenderSetClipRect(renderer_Paint_(d), NULL); +#else const SDL_Rect winRect = { 0, 0, d->dst->root->rect.size.x, d->dst->root->rect.size.y }; SDL_RenderSetClipRect(renderer_Paint_(d), &winRect); +#endif } void drawRect_Paint(const iPaint *d, iRect rect, int color) { diff --git a/src/ui/paint.h b/src/ui/paint.h index 90c5f504..aafc7496 100644 --- a/src/ui/paint.h +++ b/src/ui/paint.h @@ -9,12 +9,16 @@ iDeclareType(Paint) struct Impl_Paint { iWindow *dst; + SDL_Texture *oldTarget; }; -void init_Paint (iPaint *); +void init_Paint (iPaint *); -void setClip_Paint (iPaint *, iRect rect); -void unsetClip_Paint (iPaint *); +void beginTarget_Paint (iPaint *, SDL_Texture *target); +void endTarget_Paint (iPaint *); + +void setClip_Paint (iPaint *, iRect rect); +void unsetClip_Paint (iPaint *); void drawRect_Paint (const iPaint *, iRect rect, int color); void drawRectThickness_Paint (const iPaint *, iRect rect, int thickness, int color); diff --git a/src/ui/text.c b/src/ui/text.c index f947c4df..52af34bb 100644 --- a/src/ui/text.c +++ b/src/ui/text.c @@ -306,10 +306,11 @@ static void cache_Font_(iFont *d, iGlyph *glyph, int hoff) { } /* Determine placement in the glyph cache texture, advancing in rows. */ glRect->pos = assignCachePos_Text_(txt, glRect->size); + SDL_Texture *oldTarget = SDL_GetRenderTarget(render); SDL_SetRenderTarget(render, txt->cache); const SDL_Rect dstRect = sdlRect_(*glRect); SDL_RenderCopy(render, tex, &(SDL_Rect){ 0, 0, dstRect.w, dstRect.h }, &dstRect); - SDL_SetRenderTarget(render, NULL); + SDL_SetRenderTarget(render, oldTarget); if (tex) { SDL_DestroyTexture(tex); iAssert(surface); @@ -670,9 +671,10 @@ void init_TextBuf(iTextBuf *d, int font, const char *text) { d->size.x, d->size.y); SDL_SetTextureBlendMode(d->texture, SDL_BLENDMODE_BLEND); + SDL_Texture *oldTarget = SDL_GetRenderTarget(render); SDL_SetRenderTarget(render, d->texture); draw_Text_(font, zero_I2(), white_ColorId, range_CStr(text)); - SDL_SetRenderTarget(render, NULL); + SDL_SetRenderTarget(render, oldTarget); } void deinit_TextBuf(iTextBuf *d) { -- cgit v1.2.3 From 115bbb5f85fd964029aa7d9076dc124bd4034065 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Tue, 18 Aug 2020 10:53:49 +0300 Subject: DocumentWidget: Faster redraw of the document Keep static content in a buffer. The marked ranges still need to be drawn in a better way. --- src/ui/documentwidget.c | 339 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 239 insertions(+), 100 deletions(-) (limited to 'src/ui') diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 47d7f755..b5fdde93 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -19,6 +19,7 @@ #include #include #include +#include #include iDeclareClass(MediaRequest) @@ -112,33 +113,37 @@ enum iRequestState { }; struct Impl_DocumentWidget { - iWidget widget; + iWidget widget; enum iRequestState state; - iModel mod; - iString *titleUser; - iGmRequest *request; - iAtomicInt isRequestUpdated; /* request has new content, need to parse it */ - iObjectList *media; - iGmDocument *doc; - int certFlags; - iDate certExpiry; - iString * certSubject; - iBool selecting; - iRangecc selectMark; - iRangecc foundMark; - int pageMargin; - iPtrArray visibleLinks; - const iGmRun *hoverLink; - iBool noHoverWhileScrolling; - iBool showLinkNumbers; - iClick click; - float initialNormScrollY; - int scrollY; + iModel mod; + iString * titleUser; + iGmRequest * request; + iAtomicInt isRequestUpdated; /* request has new content, need to parse it */ + iObjectList * media; + iGmDocument * doc; + int certFlags; + iDate certExpiry; + iString * certSubject; + iBool selecting; + iRangecc selectMark; + iRangecc foundMark; + int pageMargin; + iPtrArray visibleLinks; + const iGmRun * hoverLink; + iBool noHoverWhileScrolling; + iBool showLinkNumbers; + iClick click; + float initNormScrollY; + int scrollY; iScrollWidget *scroll; - iWidget *menu; - SDL_Cursor *arrowCursor; /* TODO: cursors belong in Window */ - SDL_Cursor *beamCursor; - SDL_Cursor *handCursor; + iWidget * menu; + SDL_Cursor * arrowCursor; /* TODO: cursors belong in Window */ + SDL_Cursor * beamCursor; + SDL_Cursor * handCursor; + SDL_Texture * visBuffer[2]; + int visBufferIndex; + iInt2 visBufferSize; + iRangei visBufferValidRange; }; iDefineObjectConstruction(DocumentWidget) @@ -158,7 +163,7 @@ void init_DocumentWidget(iDocumentWidget *d) { d->isRequestUpdated = iFalse; d->media = new_ObjectList(); d->doc = new_GmDocument(); - d->initialNormScrollY = 0; + d->initNormScrollY = 0; d->scrollY = 0; d->selecting = iFalse; d->selectMark = iNullRange; @@ -167,9 +172,13 @@ void init_DocumentWidget(iDocumentWidget *d) { d->hoverLink = NULL; d->noHoverWhileScrolling = iFalse; d->showLinkNumbers = iFalse; - d->arrowCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); - d->beamCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); - d->handCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); + iZap(d->visBuffer); + d->visBufferIndex = 0; + d->visBufferSize = zero_I2(); + iZap(d->visBufferValidRange); + d->arrowCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); + d->beamCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); + d->handCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); init_PtrArray(&d->visibleLinks); init_Click(&d->click, d, SDL_BUTTON_LEFT); addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); @@ -219,7 +228,7 @@ static iRect documentBounds_DocumentWidget_(const iDocumentWidget *d) { rect.pos.y += margin; rect.size.y -= margin; } - iInt2 docSize = addY_I2(size_GmDocument(d->doc), 0 /*-lineHeight_Text(banner_FontId) * 2*/); + const iInt2 docSize = size_GmDocument(d->doc); if (docSize.y < rect.size.y) { /* Center vertically if short. */ int offset = (rect.size.y - docSize.y) / 2; @@ -229,6 +238,14 @@ static iRect documentBounds_DocumentWidget_(const iDocumentWidget *d) { return rect; } +iLocalDef int documentToWindowY_DocumentWidget_(const iDocumentWidget *d, int docY) { + return docY - d->scrollY + documentBounds_DocumentWidget_(d).pos.y; +} + +iLocalDef int windowToDocumentY_DocumentWidget_(const iDocumentWidget *d, int localY) { + return localY + d->scrollY - documentBounds_DocumentWidget_(d).pos.y; +} + static iInt2 documentPos_DocumentWidget_(const iDocumentWidget *d, iInt2 pos) { return addY_I2(sub_I2(pos, topLeft_Rect(documentBounds_DocumentWidget_(d))), d->scrollY); } @@ -252,9 +269,9 @@ static void requestFinished_DocumentWidget_(iAnyObject *obj) { } static iRangei visibleRange_DocumentWidget_(const iDocumentWidget *d) { - const int margin = gap_UI * d->pageMargin; + const int margin = !hasSiteBanner_GmDocument(d->doc) ? gap_UI * d->pageMargin : 0; return (iRangei){ d->scrollY - margin, - d->scrollY + height_Rect(bounds_Widget(constAs_Widget(d))) }; + d->scrollY + height_Rect(bounds_Widget(constAs_Widget(d))) - margin }; } static void addVisibleLink_DocumentWidget_(void *context, const iGmRun *run) { @@ -453,6 +470,10 @@ static void updateTheme_DocumentWidget_(iDocumentWidget *d) { } } +static void invalidate_DocumentWidget_(iDocumentWidget *d) { + iZap(d->visBufferValidRange); +} + static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse *response) { if (d->state == ready_RequestState) { return; @@ -462,6 +483,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse const enum iGmStatusCode statusCode = response->statusCode; if (category_GmStatusCode(statusCode) != categoryInput_GmStatusCode) { iString str; + invalidate_DocumentWidget_(d); updateTheme_DocumentWidget_(d); initBlock_String(&str, &response->body); if (category_GmStatusCode(statusCode) == categorySuccess_GmStatusCode) { @@ -600,11 +622,11 @@ static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { if (recent && recent->cachedResponse) { const iGmResponse *resp = recent->cachedResponse; d->state = fetching_RequestState; - d->initialNormScrollY = recent->normScrollY; + d->initNormScrollY = recent->normScrollY; /* Use the cached response data. */ updateTrust_DocumentWidget_(d, resp); updateDocument_DocumentWidget_(d, resp); - d->scrollY = d->initialNormScrollY * size_GmDocument(d->doc).y; + d->scrollY = d->initNormScrollY * size_GmDocument(d->doc).y; d->state = ready_RequestState; updateVisible_DocumentWidget_(d); postCommandf_App("document.changed doc:%p url:%s", d, cstr_String(d->mod.url)); @@ -640,7 +662,7 @@ void setUrlFromCache_DocumentWidget(iDocumentWidget *d, const iString *url, iBoo iDocumentWidget *duplicate_DocumentWidget(const iDocumentWidget *orig) { iDocumentWidget *d = new_DocumentWidget(); delete_History(d->mod.history); - d->initialNormScrollY = normScrollPos_DocumentWidget_(d); + d->initNormScrollY = normScrollPos_DocumentWidget_(d); d->mod.history = copy_History(orig->mod.history); setUrlFromCache_DocumentWidget(d, orig->mod.url, iTrue); return d; @@ -651,7 +673,7 @@ void setUrl_DocumentWidget(iDocumentWidget *d, const iString *url) { } void setInitialScroll_DocumentWidget(iDocumentWidget *d, float normScrollY) { - d->initialNormScrollY = normScrollY; + d->initNormScrollY = normScrollY; } iBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) { @@ -695,7 +717,7 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) { case categoryInput_GmStatusCode: { iUrl parts; init_Url(&parts, d->mod.url); - printf("%s\n", cstr_String(meta_GmRequest(d->request))); +// printf("%s\n", cstr_String(meta_GmRequest(d->request))); iWidget *dlg = makeValueInput_Widget( as_Widget(d), NULL, @@ -809,6 +831,7 @@ static iBool requestMedia_DocumentWidget_(iDocumentWidget *d, iGmLinkId linkId) d->media, iClob(new_MediaRequest( d, linkId, absoluteUrl_String(d->mod.url, linkUrl_GmDocument(d->doc, linkId))))); + invalidate_DocumentWidget_(d); return iTrue; } return iFalse; @@ -835,6 +858,7 @@ static iBool handleMediaCommand_DocumentWidget_(iDocumentWidget *d, const char * setImage_GmDocument(d->doc, req->linkId, meta_GmRequest(req->req), body_GmRequest(req->req)); updateVisible_DocumentWidget_(d); + invalidate_DocumentWidget_(d); refresh_Widget(as_Widget(d)); } } @@ -848,6 +872,36 @@ static iBool handleMediaCommand_DocumentWidget_(iDocumentWidget *d, const char * return iFalse; } +static void deallocVisBuffer_DocumentWidget_(iDocumentWidget *d) { + d->visBufferSize = zero_I2(); + iZap(d->visBufferValidRange); + iForIndices(i, d->visBuffer) { + SDL_DestroyTexture(d->visBuffer[i]); + d->visBuffer[i] = NULL; + } +} + +static void allocVisBuffer_DocumentWidget_(iDocumentWidget *d) { + iWidget *w = as_Widget(d); + const iBool isVisible = isVisible_Widget(w); + const iInt2 size = bounds_Widget(w).size; + if (!isEqual_I2(size, d->visBufferSize) || !isVisible) { + deallocVisBuffer_DocumentWidget_(d); + } + if (isVisible && !d->visBuffer[0]) { + iZap(d->visBufferValidRange); + d->visBufferSize = size; + iForIndices(i, d->visBuffer) { + d->visBuffer[i] = SDL_CreateTexture(renderer_Window(get_Window()), + SDL_PIXELFORMAT_RGBA8888, + SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, + size.x, + size.y); + SDL_SetTextureBlendMode(d->visBuffer[i], SDL_BLENDMODE_NONE); + } + } +} + void updateSize_DocumentWidget(iDocumentWidget *d) { setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d)); updateVisible_DocumentWidget_(d); @@ -867,11 +921,14 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) scrollTo_DocumentWidget_(d, mid_Rect(mid->bounds).y, iTrue); } } + invalidate_DocumentWidget_(d); + allocVisBuffer_DocumentWidget_(d); refresh_Widget(w); updateWindowTitle_DocumentWidget_(d); } else if (equal_Command(cmd, "theme.changed") && document_App() == d) { updateTheme_DocumentWidget_(d); + invalidate_DocumentWidget_(d); refresh_Widget(w); } else if (equal_Command(cmd, "tabs.changed")) { @@ -884,6 +941,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) updateVisible_DocumentWidget_(d); } updateWindowTitle_DocumentWidget_(d); + allocVisBuffer_DocumentWidget_(d); return iFalse; } else if (equal_Command(cmd, "server.showcert") && d == document_App()) { @@ -968,7 +1026,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) else if (equalWidget_Command(cmd, w, "document.request.finished") && pointerLabel_Command(cmd, "request") == d->request) { checkResponse_DocumentWidget_(d); - d->scrollY = d->initialNormScrollY * size_GmDocument(d->doc).y; + d->scrollY = d->initNormScrollY * size_GmDocument(d->doc).y; d->state = ready_RequestState; /* The response may be cached. */ { const iRangecc proto = urlProtocol_String(d->mod.url); @@ -1002,7 +1060,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) return handleMediaCommand_DocumentWidget_(d, cmd); } else if (equal_Command(cmd, "document.reload") && document_App() == d) { - d->initialNormScrollY = normScrollPos_DocumentWidget_(d); + d->initNormScrollY = normScrollPos_DocumentWidget_(d); fetch_DocumentWidget_(d); return iTrue; } @@ -1100,6 +1158,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e case SDLK_RALT: if (document_App() == d) { d->showLinkNumbers = iFalse; + invalidate_DocumentWidget_(d); refresh_Widget(w); } break; @@ -1127,21 +1186,10 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e case SDLK_RALT: if (document_App() == d) { d->showLinkNumbers = iTrue; + invalidate_DocumentWidget_(d); refresh_Widget(w); } break; - case SDLK_1: - case SDLK_2: - case SDLK_3: - case SDLK_4: - case SDLK_5: - case SDLK_6: - case SDLK_7: - case SDLK_8: - case SDLK_9: - if (mods == KMOD_ALT || mods == (KMOD_ALT | KMOD_PRIMARY)) { - } - break; case SDLK_HOME: d->scrollY = 0; scroll_DocumentWidget_(d, 0); @@ -1264,6 +1312,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e d->hoverLink = NULL; scroll_DocumentWidget_(d, 0); updateVisible_DocumentWidget_(d); + invalidate_DocumentWidget_(d); refresh_Widget(w); return iTrue; } @@ -1274,6 +1323,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e setImage_GmDocument(d->doc, linkId, meta_GmRequest(req->req), body_GmRequest(req->req)); updateVisible_DocumentWidget_(d); + invalidate_DocumentWidget_(d); refresh_Widget(w); return iTrue; } @@ -1305,7 +1355,13 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e iDeclareType(DrawContext) +enum iDrawRunPass { + static_DrawRunPass, + dynamic_DrawRunPass, +}; + struct Impl_DrawContext { + enum iDrawRunPass pass; const iDocumentWidget *widget; iRect widgetBounds; iRect bounds; /* document area */ @@ -1348,57 +1404,67 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { iDrawContext *d = context; const iInt2 origin = addY_I2(d->bounds.pos, -d->widget->scrollY); if (run->imageId) { - SDL_Texture *tex = imageTexture_GmDocument(d->widget->doc, run->imageId); - if (tex) { - const iRect dst = moved_Rect(run->visBounds, origin); - SDL_RenderCopy(d->paint.dst->render, tex, NULL, - &(SDL_Rect){ dst.pos.x, dst.pos.y, dst.size.x, dst.size.y }); + if (d->pass == static_DrawRunPass) { + SDL_Texture *tex = imageTexture_GmDocument(d->widget->doc, run->imageId); + if (tex) { + const iRect dst = moved_Rect(run->visBounds, origin); + SDL_RenderCopy(d->paint.dst->render, tex, NULL, + &(SDL_Rect){ dst.pos.x, dst.pos.y, dst.size.x, dst.size.y }); + } } return; } + /* Text markers. */ + if (d->pass == dynamic_DrawRunPass) { + fillRange_DrawContext_(d, run, uiMatching_ColorId, d->widget->foundMark, &d->inFoundMark); + fillRange_DrawContext_(d, run, uiMarked_ColorId, d->widget->selectMark, &d->inSelectMark); + } enum iColorId fg = run->color; const iGmDocument *doc = d->widget->doc; + /* Matches the current drawing pass? */ + const iBool isDynamic = (run->linkId && ~run->flags & decoration_GmRunFlag); + if (isDynamic ^ (d->pass == dynamic_DrawRunPass)) { + return; + } const iBool isHover = - (run->linkId != 0 && d->widget->hoverLink && run->linkId == d->widget->hoverLink->linkId && - !isEmpty_Rect(run->bounds)); + (run->linkId && d->widget->hoverLink && run->linkId == d->widget->hoverLink->linkId && + ~run->flags & decoration_GmRunFlag); const iInt2 visPos = add_I2(run->visBounds.pos, origin); - /* Text markers. */ - /* TODO: Add themed palette entries */ - fillRange_DrawContext_(d, run, uiMatching_ColorId, d->widget->foundMark, &d->inFoundMark); - fillRange_DrawContext_(d, run, uiMarked_ColorId, d->widget->selectMark, &d->inSelectMark); - if (run->linkId && !isEmpty_Rect(run->bounds)) { + if (run->linkId && ~run->flags & decoration_GmRunFlag) { fg = linkColor_GmDocument(doc, run->linkId, isHover ? textHover_GmLinkPart : text_GmLinkPart); if (linkFlags_GmDocument(doc, run->linkId) & content_GmLinkFlag) { fg = linkColor_GmDocument(doc, run->linkId, textHover_GmLinkPart); /* link is inactive */ } } if (run->flags & siteBanner_GmRunFlag) { - /* Draw the site banner. */ - fillRect_Paint( - &d->paint, - initCorners_Rect(topLeft_Rect(d->widgetBounds), - init_I2(right_Rect(bounds_Widget(constAs_Widget(d->widget))), - visPos.y + height_Rect(run->visBounds))), - tmBannerBackground_ColorId); - const iChar icon = siteIcon_GmDocument(doc); - iString bannerText; - init_String(&bannerText); - iInt2 bpos = add_I2(visPos, init_I2(0, lineHeight_Text(banner_FontId) / 2)); - if (icon) { - appendChar_String(&bannerText, icon); - const iRect iconRect = visualBounds_Text(banner_FontId, range_String(&bannerText)); + if (d->pass == static_DrawRunPass) { + /* Draw the site banner. */ + fillRect_Paint( + &d->paint, + initCorners_Rect(topLeft_Rect(d->widgetBounds), + init_I2(right_Rect(bounds_Widget(constAs_Widget(d->widget))), + visPos.y + height_Rect(run->visBounds))), + tmBannerBackground_ColorId); + const iChar icon = siteIcon_GmDocument(doc); + iString bannerText; + init_String(&bannerText); + iInt2 bpos = add_I2(visPos, init_I2(0, lineHeight_Text(banner_FontId) / 2)); + if (icon) { + appendChar_String(&bannerText, icon); + const iRect iconRect = visualBounds_Text(banner_FontId, range_String(&bannerText)); + drawRange_Text(run->font, + addY_I2(bpos, -mid_Rect(iconRect).y + lineHeight_Text(run->font) / 2), + tmBannerIcon_ColorId, + range_String(&bannerText)); + bpos.x += right_Rect(iconRect) + 3 * gap_Text; + } drawRange_Text(run->font, - addY_I2(bpos, -mid_Rect(iconRect).y + lineHeight_Text(run->font) / 2), - tmBannerIcon_ColorId, - range_String(&bannerText)); - bpos.x += right_Rect(iconRect) + 3 * gap_Text; + bpos, + tmBannerTitle_ColorId, + isEmpty_String(d->widget->titleUser) ? run->text + : range_String(d->widget->titleUser)); + deinit_String(&bannerText); } - drawRange_Text(run->font, - bpos, - tmBannerTitle_ColorId, - isEmpty_String(d->widget->titleUser) ? run->text - : range_String(d->widget->titleUser)); - deinit_String(&bannerText); } else { if (d->showLinkNumbers && run->linkId && run->flags & decoration_GmRunFlag) { @@ -1413,10 +1479,11 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { } } drawRange_Text(run->font, visPos, fg, run->text); +// printf("{%s}\n", cstr_Rangecc(run->text)); runDrawn:; } /* Presentation of links. */ - if (run->linkId && ~run->flags & decoration_GmRunFlag) { + if (run->linkId && ~run->flags & decoration_GmRunFlag && d->pass == dynamic_DrawRunPass) { const int metaFont = paragraph_FontId; /* TODO: Show status of an ongoing media request. */ const int flags = linkFlags_GmDocument(doc, run->linkId); @@ -1515,22 +1582,94 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { // drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, red_ColorId); } +static iRangei intersect_Rangei_(iRangei a, iRangei b) { + if (a.end < b.start || a.start > b.end) { + return (iRangei){ 0, 0 }; + } + return (iRangei){ iMax(a.start, b.start), iMin(a.end, b.end) }; +} + +iLocalDef iBool isEmpty_Rangei_(iRangei d) { + return size_Range(&d) == 0; +} + 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 iInt2 origin = topLeft_Rect(bounds); + const iRangei visRange = visibleRange_DocumentWidget_(d); draw_Widget(w); - iDrawContext ctx = { - .widget = d, - .widgetBounds = /* omit scrollbar width */ - adjusted_Rect(bounds, zero_I2(), init_I2(-constAs_Widget(d->scroll)->rect.size.x, 0)), - .bounds = documentBounds_DocumentWidget_(d), + allocVisBuffer_DocumentWidget_(iConstCast(iDocumentWidget *, d)); + iDrawContext ctxDynamic = { + .pass = dynamic_DrawRunPass, + .widget = d, + .widgetBounds = adjusted_Rect(bounds, + zero_I2(), + init_I2(-constAs_Widget(d->scroll)->rect.size.x, 0)), /* omit scrollbar width */ + .bounds = documentBounds_DocumentWidget_(d), .showLinkNumbers = d->showLinkNumbers, }; - init_Paint(&ctx.paint); - fillRect_Paint(&ctx.paint, bounds, tmBackground_ColorId); - setClip_Paint(&ctx.paint, bounds); - render_GmDocument(d->doc, visibleRange_DocumentWidget_(d), drawRun_DrawContext_, &ctx); - unsetClip_Paint(&ctx.paint); + iDrawContext ctxStatic = ctxDynamic; + ctxStatic.pass = static_DrawRunPass; + subv_I2(&ctxStatic.widgetBounds.pos, origin); + subv_I2(&ctxStatic.bounds.pos, origin); + SDL_Renderer *render = get_Window()->render; + /* Static content. */ { + iPaint *p = &ctxStatic.paint; + init_Paint(p); + const int vbSrc = d->visBufferIndex; + const int vbDst = d->visBufferIndex ^ 1; + iRangei drawRange = visRange; + iAssert(d->visBuffer[vbDst]); + beginTarget_Paint(p, d->visBuffer[vbDst]); + const iRect visBufferRect = { zero_I2(), d->visBufferSize }; + iRect drawRect = visBufferRect; + if (!isEmpty_Rangei_(intersect_Rangei_(visRange, d->visBufferValidRange))) { + const iRangei isct = intersect_Rangei_(visRange, d->visBufferValidRange); + if (visRange.start < d->visBufferValidRange.start) { + drawRange = (iRangei){ visRange.start, d->visBufferValidRange.start }; + } + else { + drawRange = (iRangei){ d->visBufferValidRange.end, visRange.end }; + } + if (isEmpty_Range(&drawRange)) { + SDL_RenderCopy(render, d->visBuffer[vbSrc], NULL, NULL); + } + else { + SDL_RenderCopy( + render, + d->visBuffer[vbSrc], + NULL, + &(SDL_Rect){ 0, + documentToWindowY_DocumentWidget_(d, d->visBufferValidRange.start) - origin.y, + d->visBufferSize.x, + d->visBufferSize.y }); + drawRect = init_Rect(0, + documentToWindowY_DocumentWidget_(d, drawRange.start) - origin.y, + d->visBufferSize.x, + size_Range(&drawRange)); + } + } + if (!isEmpty_Range(&drawRange)) { + setClip_Paint(p, drawRect); + fillRect_Paint(p, drawRect, vbDst == 1 ? blue_ColorId : red_ColorId); //tmBackground_ColorId); + render_GmDocument(d->doc, drawRange, drawRun_DrawContext_, &ctxStatic); + unsetClip_Paint(p); + } + endTarget_Paint(p); + SDL_RenderCopy(render, d->visBuffer[vbDst], NULL, + &(SDL_Rect){ origin.x, origin.y, bounds.size.x, bounds.size.y } ); + iConstCast(iDocumentWidget *, d)->visBufferValidRange = visRange; + iConstCast(iDocumentWidget *, d)->visBufferIndex = vbDst; + } + /* Dynamic content. */ { + iPaint *p = &ctxDynamic.paint; + init_Paint(p); + setClip_Paint(p, bounds); + render_GmDocument(d->doc, visRange, drawRun_DrawContext_, &ctxDynamic); + unsetClip_Paint(p); + } + // drawRect_Paint(&ctx.paint, // moved_Rect((iRect){ zero_I2(), size_GmDocument(d->doc) }, // add_I2(topLeft_Rect(ctx.bounds), init_I2(0, -d->scrollY))), -- cgit v1.2.3 From 0bbfd5a2e25e2a843fcee757469193533da98948 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Tue, 18 Aug 2020 11:23:54 +0300 Subject: Added a larger content-friendly UI font Mostly for sidebar contents. --- src/ui/sidebarwidget.c | 6 +++--- src/ui/text.c | 6 +++--- src/ui/text.h | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src/ui') diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index de576f72..3fbcccd3 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -167,7 +167,7 @@ void setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) { setFlags_Widget(as_Widget(d->modeButtons[i]), selected_WidgetFlag, i == d->mode); } const float heights[max_SidebarMode] = { 1.5f, 3, 3, 1.2f }; - d->itemHeight = heights[mode] * lineHeight_Text(default_FontId); + d->itemHeight = heights[mode] * lineHeight_Text(uiContent_FontId); } enum iSidebarMode mode_SidebarWidget(const iSidebarWidget *d) { @@ -217,7 +217,7 @@ void init_SidebarWidget(iSidebarWidget *d) { frameless_WidgetFlag | expand_WidgetFlag); d->maxButtonLabelWidth = iMaxi(d->maxButtonLabelWidth, - 3 * gap_UI + measure_Text(default_FontId, normalModeLabels_[i]).x); + 3 * gap_UI + measure_Text(uiLabel_FontId, normalModeLabels_[i]).x); } addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); setThumb_ScrollWidget(d->scroll, 0, 0); @@ -501,7 +501,7 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) { d->mode == documentOutline_SidebarMode ? tmBackground_ColorId : uiBackground_ColorId); /* Draw the items. */ { - const int font = default_FontId; + const int font = uiContent_FontId; const iRanges visRange = visRange_SidebarWidget_(d); iInt2 pos = addY_I2(topLeft_Rect(bounds), -(d->scrollY % d->itemHeight)); for (size_t i = visRange.start; i < visRange.end; i++) { diff --git a/src/ui/text.c b/src/ui/text.c index 52af34bb..1e702eee 100644 --- a/src/ui/text.c +++ b/src/ui/text.c @@ -120,7 +120,7 @@ static void initFonts_Text_(iText *d) { int symbolsFont; } fontData[max_FontId] = { { &fontSourceSansProRegular_Embedded, fontSize_UI, defaultSymbols_FontId }, - { &fontSourceSansProRegular_Embedded, fontSize_UI * 1.666f, defaultLargeSymbols_FontId }, + { &fontSourceSansProRegular_Embedded, fontSize_UI * 1.150f, defaultMediumSymbols_FontId }, { &fontFiraMonoRegular_Embedded, fontSize_UI * 0.866f, defaultSymbols_FontId }, { &fontFiraSansRegular_Embedded, textSize, symbols_FontId }, { &fontFiraMonoRegular_Embedded, textSize * 0.866f, smallSymbols_FontId }, @@ -133,14 +133,14 @@ static void initFonts_Text_(iText *d) { { &fontFiraSansBold_Embedded, textSize * 2.000f, hugeSymbols_FontId }, { &fontFiraSansLight_Embedded, textSize * 1.666f, largeSymbols_FontId }, { &fontSymbola_Embedded, fontSize_UI, defaultSymbols_FontId }, - { &fontSymbola_Embedded, fontSize_UI * 1.666f, defaultLargeSymbols_FontId }, + { &fontSymbola_Embedded, fontSize_UI * 1.150f, defaultMediumSymbols_FontId }, { &fontSymbola_Embedded, textSize, symbols_FontId }, { &fontSymbola_Embedded, textSize * 1.333f, mediumSymbols_FontId }, { &fontSymbola_Embedded, textSize * 1.666f, largeSymbols_FontId }, { &fontSymbola_Embedded, textSize * 2.000f, hugeSymbols_FontId }, { &fontSymbola_Embedded, textSize * 0.866f, smallSymbols_FontId }, { &fontNotoEmojiRegular_Embedded, fontSize_UI, defaultSymbols_FontId }, - { &fontNotoEmojiRegular_Embedded, fontSize_UI * 1.666f, defaultLargeSymbols_FontId }, + { &fontNotoEmojiRegular_Embedded, fontSize_UI * 1.150f, defaultMediumSymbols_FontId }, { &fontNotoEmojiRegular_Embedded, textSize, symbols_FontId }, { &fontNotoEmojiRegular_Embedded, textSize * 1.333f, mediumSymbols_FontId }, { &fontNotoEmojiRegular_Embedded, textSize * 1.666f, largeSymbols_FontId }, diff --git a/src/ui/text.h b/src/ui/text.h index 85ab44e2..2d49a1a6 100644 --- a/src/ui/text.h +++ b/src/ui/text.h @@ -7,7 +7,7 @@ enum iFontId { default_FontId, - defaultLarge_FontId, + defaultMedium_FontId, defaultMonospace_FontId, regular_FontId, monospace_FontId, @@ -21,7 +21,7 @@ enum iFontId { largeLight_FontId, /* symbol fonts */ defaultSymbols_FontId, - defaultLargeSymbols_FontId, + defaultMediumSymbols_FontId, symbols_FontId, mediumSymbols_FontId, largeSymbols_FontId, @@ -29,7 +29,7 @@ enum iFontId { smallSymbols_FontId, /* emoji fonts */ defaultEmoji_FontId, - defaultLargeEmoji_FontId, + defaultMediumEmoji_FontId, emoji_FontId, mediumEmoji_FontId, largeEmoji_FontId, @@ -42,7 +42,7 @@ enum iFontId { uiLabel_FontId = default_FontId, uiShortcuts_FontId = default_FontId, uiInput_FontId = defaultMonospace_FontId, - uiBookmarkIcon_FontId = defaultLarge_FontId, + uiContent_FontId = defaultMedium_FontId, /* Document fonts: */ paragraph_FontId = regular_FontId, firstParagraph_FontId = medium_FontId, -- cgit v1.2.3 From 701f93645b7bb1f2e07e975f97b796910516256d Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Tue, 18 Aug 2020 11:24:01 +0300 Subject: Minor tweaks --- src/gmdocument.c | 5 +++-- src/gmrequest.c | 2 +- src/ui/documentwidget.c | 24 ++++++++++++------------ 3 files changed, 16 insertions(+), 15 deletions(-) (limited to 'src/ui') diff --git a/src/gmdocument.c b/src/gmdocument.c index 535a873e..a6fc39c5 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c @@ -413,8 +413,9 @@ static void doLayout_GmDocument_(iGmDocument *d) { pos.y += required - delta; } } - /* Save the document title. */ - if (type == heading1_GmLineType && isEmpty_String(&d->title)) { + /* Save the document title (first high-level heading). */ + if ((type == heading1_GmLineType || type == heading2_GmLineType) && + isEmpty_String(&d->title)) { setRange_String(&d->title, line); } /* List bullet. */ diff --git a/src/gmrequest.c b/src/gmrequest.c index 2b6ee9f9..0d69861d 100644 --- a/src/gmrequest.c +++ b/src/gmrequest.c @@ -330,7 +330,7 @@ void submit_GmRequest(iGmRequest *d) { /* TODO: Check supported file types: images, audio */ /* TODO: Detect text files based on contents? E.g., is the content valid UTF-8. */ d->resp.statusCode = success_GmStatusCode; - if (endsWithCase_String(path, ".gmi")) { + if (endsWithCase_String(path, ".gmi") || endsWithCase_String(path, ".gemini")) { setCStr_String(&d->resp.meta, "text/gemini; charset=utf-8"); } else if (endsWithCase_String(path, ".txt")) { diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index b5fdde93..29803252 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -1001,16 +1001,18 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) return iTrue; } else if (equal_Command(cmd, "document.input.submit")) { - iString *value = collect_String(suffix_Command(cmd, "value")); - urlEncode_String(value); - iString *url = collect_String(copy_String(d->mod.url)); - const size_t qPos = indexOfCStr_String(url, "?"); - if (qPos != iInvalidPos) { - remove_Block(&url->chars, qPos, iInvalidSize); + if (arg_Command(cmd)) { + iString *value = collect_String(suffix_Command(cmd, "value")); + urlEncode_String(value); + iString *url = collect_String(copy_String(d->mod.url)); + const size_t qPos = indexOfCStr_String(url, "?"); + if (qPos != iInvalidPos) { + remove_Block(&url->chars, qPos, iInvalidSize); + } + appendCStr_String(url, "?"); + append_String(url, value); + postCommandf_App("open url:%s", cstr_String(url)); } - appendCStr_String(url, "?"); - append_String(url, value); - postCommandf_App("open url:%s", cstr_String(url)); return iTrue; } else if (equal_Command(cmd, "valueinput.cancelled") && @@ -1577,7 +1579,6 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { } } } - // drawRect_Paint(&d->paint, (iRect){ visPos, run->bounds.size }, green_ColorId); // drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, red_ColorId); } @@ -1625,7 +1626,6 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { const iRect visBufferRect = { zero_I2(), d->visBufferSize }; iRect drawRect = visBufferRect; if (!isEmpty_Rangei_(intersect_Rangei_(visRange, d->visBufferValidRange))) { - const iRangei isct = intersect_Rangei_(visRange, d->visBufferValidRange); if (visRange.start < d->visBufferValidRange.start) { drawRange = (iRangei){ visRange.start, d->visBufferValidRange.start }; } @@ -1652,7 +1652,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { } if (!isEmpty_Range(&drawRange)) { setClip_Paint(p, drawRect); - fillRect_Paint(p, drawRect, vbDst == 1 ? blue_ColorId : red_ColorId); //tmBackground_ColorId); + fillRect_Paint(p, drawRect, tmBackground_ColorId); // vbDst == 1 ? blue_ColorId : red_ColorId render_GmDocument(d->doc, drawRange, drawRun_DrawContext_, &ctxStatic); unsetClip_Paint(p); } -- cgit v1.2.3 From a87d5af936c168ed6edbc66547a2c8fddf81f41f Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Tue, 18 Aug 2020 11:48:46 +0300 Subject: SidebarWidget: Faster redraws Reuse previous contents if they are still valid. --- src/ui/paint.c | 6 ++ src/ui/paint.h | 2 + src/ui/sidebarwidget.c | 161 +++++++++++++++++++++++++++++++------------------ 3 files changed, 110 insertions(+), 59 deletions(-) (limited to 'src/ui') diff --git a/src/ui/paint.c b/src/ui/paint.c index a55670e9..264ca0d8 100644 --- a/src/ui/paint.c +++ b/src/ui/paint.c @@ -74,3 +74,9 @@ void drawLines_Paint(const iPaint *d, const iInt2 *points, size_t count, int col setColor_Paint_(d, color); SDL_RenderDrawLines(renderer_Paint_(d), (const SDL_Point *) points, count); } + +iInt2 size_SDLTexture(SDL_Texture *d) { + iInt2 size; + SDL_QueryTexture(d, NULL, NULL, &size.x, &size.y); + return size; +} diff --git a/src/ui/paint.h b/src/ui/paint.h index aafc7496..5b29b176 100644 --- a/src/ui/paint.h +++ b/src/ui/paint.h @@ -35,3 +35,5 @@ iLocalDef void drawHLine_Paint(const iPaint *d, iInt2 pos, int len, int color) { iLocalDef void drawVLine_Paint(const iPaint *d, iInt2 pos, int len, int color) { drawLine_Paint(d, pos, addY_I2(pos, len), color); } + +iInt2 size_SDLTexture (SDL_Texture *); diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 3fbcccd3..a8c2cd91 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -59,10 +59,17 @@ struct Impl_SidebarWidget { iWidget *resizer; SDL_Cursor *resizeCursor; iWidget *menu; + SDL_Texture *visBuffer; + iBool visBufferValid; }; iDefineObjectConstruction(SidebarWidget) +static void invalidate_SidebarWidget_(iSidebarWidget *d) { + d->visBufferValid = iFalse; + refresh_Widget(as_Widget(d)); +} + static iBool isResizing_SidebarWidget_(const iSidebarWidget *d) { return (flags_Widget(d->resizer) & pressed_WidgetFlag) != 0; } @@ -157,7 +164,7 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { break; } updateVisible_SidebarWidget_(d); - refresh_Widget(as_Widget(d)); + invalidate_SidebarWidget_(d); } void setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) { @@ -232,12 +239,15 @@ void init_SidebarWidget(iSidebarWidget *d) { setBackgroundColor_Widget(d->resizer, none_ColorId); d->resizeCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); d->menu = NULL; + d->visBuffer = NULL; + d->visBufferValid = iFalse; } void deinit_SidebarWidget(iSidebarWidget *d) { SDL_FreeCursor(d->resizeCursor); clearItems_SidebarWidget_(d); deinit_Array(&d->items); + SDL_DestroyTexture(d->visBuffer); } static int visCount_SidebarWidget_(const iSidebarWidget *d) { @@ -277,14 +287,18 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, size_t index) { } static void scroll_SidebarWidget_(iSidebarWidget *d, int offset) { + const int oldScroll = d->scrollY; d->scrollY += offset; if (d->scrollY < 0) { d->scrollY = 0; } const int scrollMax = scrollMax_SidebarWidget_(d); d->scrollY = iMin(d->scrollY, scrollMax); - updateVisible_SidebarWidget_(d); - refresh_Widget(as_Widget(d)); + if (oldScroll != d->scrollY) { + d->hoverItem = iInvalidPos; + updateVisible_SidebarWidget_(d); + invalidate_SidebarWidget_(d); + } } static void checkModeButtonLayout_SidebarWidget_(iSidebarWidget *d) { @@ -320,7 +334,7 @@ void setWidth_SidebarWidget(iSidebarWidget *d, int width) { checkModeButtonLayout_SidebarWidget_(d); if (!isRefreshPending_App()) { updateSize_DocumentWidget(document_App()); - refresh_Widget(w); + invalidate_SidebarWidget_(d); } } @@ -349,6 +363,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) if (isResize_UserEvent(ev)) { updateVisible_SidebarWidget_(d); checkModeButtonLayout_SidebarWidget_(d); + invalidate_SidebarWidget_(d); } else if (ev->type == SDL_USEREVENT && ev->user.code == command_UserEventCode) { const char *cmd = command_UserEvent(ev); @@ -392,6 +407,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) setFlags_Widget(w, hidden_WidgetFlag, isVisible_Widget(w)); if (isVisible_Widget(w)) { w->rect.size.x = d->width; + invalidate_SidebarWidget_(d); } arrange_Widget(w->parent); updateSize_DocumentWidget(document_App()); @@ -401,7 +417,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) else if (equal_Command(cmd, "scroll.moved")) { d->scrollY = arg_Command(command_UserEvent(ev)); d->hoverItem = iInvalidPos; - refresh_Widget(w); + invalidate_SidebarWidget_(d); return iTrue; } else if (equal_Command(cmd, "tabs.changed") || equal_Command(cmd, "document.changed")) { @@ -454,7 +470,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) } if (hover != d->hoverItem) { d->hoverItem = hover; - refresh_Widget(w); + invalidate_SidebarWidget_(d); } } if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { @@ -464,8 +480,6 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) #else scroll_SidebarWidget_(d, -ev->wheel.y * 3 * d->itemHeight); #endif - d->hoverItem = iInvalidPos; - refresh_Widget(w); return iTrue; } if (d->menu && ev->type == SDL_MOUSEBUTTONDOWN) { @@ -475,14 +489,14 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) } switch (processEvent_Click(&d->click, ev)) { case started_ClickResult: - refresh_Widget(w); + invalidate_SidebarWidget_(d); break; case finished_ClickResult: if (contains_Rect(contentBounds_SidebarWidget_(d), pos_Click(&d->click)) && d->hoverItem != iInvalidSize) { itemClicked_SidebarWidget_(d, d->hoverItem); } - refresh_Widget(w); + invalidate_SidebarWidget_(d); break; default: break; @@ -490,64 +504,93 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) return processEvent_Widget(w, ev); } +static void allocVisBuffer_SidebarWidget_(iSidebarWidget *d) { + const iInt2 size = contentBounds_SidebarWidget_(d).size; + if (!d->visBuffer || !isEqual_I2(size_SDLTexture(d->visBuffer), size)) { + if (d->visBuffer) { + SDL_DestroyTexture(d->visBuffer); + } + d->visBuffer = SDL_CreateTexture(renderer_Window(get_Window()), + SDL_PIXELFORMAT_RGBA8888, + SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, + size.x, + size.y); + SDL_SetTextureBlendMode(d->visBuffer, SDL_BLENDMODE_NONE); + d->visBufferValid = iFalse; + } +} + static void draw_SidebarWidget_(const iSidebarWidget *d) { const iWidget *w = constAs_Widget(d); const iRect bounds = contentBounds_SidebarWidget_(d); const iBool isPressing = d->click.isActive && contains_Rect(bounds, pos_Click(&d->click)); iPaint p; init_Paint(&p); - fillRect_Paint(&p, - bounds_Widget(w), - d->mode == documentOutline_SidebarMode ? tmBackground_ColorId - : uiBackground_ColorId); - /* Draw the items. */ { - const int font = uiContent_FontId; - const iRanges visRange = visRange_SidebarWidget_(d); - iInt2 pos = addY_I2(topLeft_Rect(bounds), -(d->scrollY % d->itemHeight)); - for (size_t i = visRange.start; i < visRange.end; i++) { - const iSidebarItem *item = constAt_Array(&d->items, i); - const iRect itemRect = { pos, init_I2(width_Rect(bounds), d->itemHeight) }; - const iBool isHover = (d->hoverItem == i); - setClip_Paint(&p, intersect_Rect(itemRect, bounds)); - if (isHover) { - fillRect_Paint(&p, - itemRect, - isPressing ? uiBackgroundPressed_ColorId - : uiBackgroundFramelessHover_ColorId); - } - if (d->mode == documentOutline_SidebarMode) { - const int fg = - isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId) - : (tmHeading1_ColorId + item->indent / (4 * gap_UI)); - drawRange_Text(font, init_I2(pos.x + 3 * gap_UI + item->indent, - mid_Rect(itemRect).y - lineHeight_Text(font) / 2), - fg, range_String(&item->label)); - } - else if (d->mode == bookmarks_SidebarMode) { - const int fg = - isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId) - : uiText_ColorId; - iString str; - init_String(&str); - appendChar_String(&str, item->icon ? item->icon : 0x1f588); - const iRect iconArea = { addX_I2(pos, gap_UI), init_I2(7 * gap_UI, d->itemHeight) }; - drawCentered_Text(font, - iconArea, - iTrue, - isHover - ? (isPressing ? uiTextPressed_ColorId : uiIconHover_ColorId) - : uiIcon_ColorId, - "%s", - cstr_String(&str)); - deinit_String(&str); - iInt2 textPos = - addY_I2(topRight_Rect(iconArea), (d->itemHeight - lineHeight_Text(font)) / 2); - drawRange_Text(font, textPos, fg, range_String(&item->label)); + const int bg = + d->mode == documentOutline_SidebarMode ? tmBackground_ColorId : uiBackground_ColorId; + fillRect_Paint(&p, bounds_Widget(w), bg); /* TODO: should do only the mode buttons area */ + if (!d->visBufferValid) { + allocVisBuffer_SidebarWidget_(iConstCast(iSidebarWidget *, d)); + iRect bufBounds = bounds; + bufBounds.pos = zero_I2(); + beginTarget_Paint(&p, d->visBuffer); + fillRect_Paint(&p, bufBounds, bg); + /* Draw the items. */ { + const int font = uiContent_FontId; + const iRanges visRange = visRange_SidebarWidget_(d); + iInt2 pos = addY_I2(topLeft_Rect(bufBounds), -(d->scrollY % d->itemHeight)); + for (size_t i = visRange.start; i < visRange.end; i++) { + const iSidebarItem *item = constAt_Array(&d->items, i); + const iRect itemRect = { pos, init_I2(width_Rect(bufBounds), d->itemHeight) }; + const iBool isHover = (d->hoverItem == i); + setClip_Paint(&p, intersect_Rect(itemRect, bufBounds)); + if (isHover) { + fillRect_Paint(&p, + itemRect, + isPressing ? uiBackgroundPressed_ColorId + : uiBackgroundFramelessHover_ColorId); + } + if (d->mode == documentOutline_SidebarMode) { + const int fg = isHover ? (isPressing ? uiTextPressed_ColorId + : uiTextFramelessHover_ColorId) + : (tmHeading1_ColorId + item->indent / (4 * gap_UI)); + drawRange_Text(font, + init_I2(pos.x + 3 * gap_UI + item->indent, + mid_Rect(itemRect).y - lineHeight_Text(font) / 2), + fg, + range_String(&item->label)); + } + else if (d->mode == bookmarks_SidebarMode) { + const int fg = isHover ? (isPressing ? uiTextPressed_ColorId + : uiTextFramelessHover_ColorId) + : uiText_ColorId; + iString str; + init_String(&str); + appendChar_String(&str, item->icon ? item->icon : 0x1f588); + const iRect iconArea = { addX_I2(pos, gap_UI), + init_I2(7 * gap_UI, d->itemHeight) }; + drawCentered_Text( + font, + iconArea, + iTrue, + isHover ? (isPressing ? uiTextPressed_ColorId : uiIconHover_ColorId) + : uiIcon_ColorId, + "%s", + cstr_String(&str)); + deinit_String(&str); + iInt2 textPos = addY_I2(topRight_Rect(iconArea), + (d->itemHeight - lineHeight_Text(font)) / 2); + drawRange_Text(font, textPos, fg, range_String(&item->label)); + } + unsetClip_Paint(&p); + pos.y += d->itemHeight; } - unsetClip_Paint(&p); - pos.y += d->itemHeight; } + endTarget_Paint(&p); + iConstCast(iSidebarWidget *, d)->visBufferValid = iTrue; } + SDL_RenderCopy( + renderer_Window(get_Window()), d->visBuffer, NULL, (const SDL_Rect *) &bounds); draw_Widget(w); drawVLine_Paint(&p, addX_I2(topRight_Rect(bounds_Widget(w)), -1), -- cgit v1.2.3 From 2d6d6cd513b8de36971545834212f927fa4e27dc Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Tue, 18 Aug 2020 14:14:29 +0300 Subject: SidebarWidget: Bookmark heights; theme changes --- src/ui/sidebarwidget.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/ui') diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index a8c2cd91..71b641d4 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -173,7 +173,7 @@ void setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) { for (enum iSidebarMode i = 0; i < max_SidebarMode; i++) { setFlags_Widget(as_Widget(d->modeButtons[i]), selected_WidgetFlag, i == d->mode); } - const float heights[max_SidebarMode] = { 1.5f, 3, 3, 1.2f }; + const float heights[max_SidebarMode] = { 1.333f, 3, 3, 1.2f }; d->itemHeight = heights[mode] * lineHeight_Text(uiContent_FontId); } @@ -424,6 +424,9 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) d->scrollY = 0; updateItems_SidebarWidget_(d); } + else if (equal_Command(cmd, "theme.changed")) { + invalidate_SidebarWidget_(d); + } else if (equal_Command(cmd, "bookmark.copy")) { const iSidebarItem *item = hoverItem_SidebarWidget_(d); if (d->mode == bookmarks_SidebarMode && item) { -- cgit v1.2.3