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