summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-08-18 11:48:46 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-08-18 11:48:46 +0300
commita87d5af936c168ed6edbc66547a2c8fddf81f41f (patch)
tree9fdae936b69db152b6e498b48bade0c25ed21d0c /src/ui
parent701f93645b7bb1f2e07e975f97b796910516256d (diff)
SidebarWidget: Faster redraws
Reuse previous contents if they are still valid.
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/paint.c6
-rw-r--r--src/ui/paint.h2
-rw-r--r--src/ui/sidebarwidget.c161
3 files changed, 110 insertions, 59 deletions
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
74 setColor_Paint_(d, color); 74 setColor_Paint_(d, color);
75 SDL_RenderDrawLines(renderer_Paint_(d), (const SDL_Point *) points, count); 75 SDL_RenderDrawLines(renderer_Paint_(d), (const SDL_Point *) points, count);
76} 76}
77
78iInt2 size_SDLTexture(SDL_Texture *d) {
79 iInt2 size;
80 SDL_QueryTexture(d, NULL, NULL, &size.x, &size.y);
81 return size;
82}
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) {
35iLocalDef void drawVLine_Paint(const iPaint *d, iInt2 pos, int len, int color) { 35iLocalDef void drawVLine_Paint(const iPaint *d, iInt2 pos, int len, int color) {
36 drawLine_Paint(d, pos, addY_I2(pos, len), color); 36 drawLine_Paint(d, pos, addY_I2(pos, len), color);
37} 37}
38
39iInt2 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 {
59 iWidget *resizer; 59 iWidget *resizer;
60 SDL_Cursor *resizeCursor; 60 SDL_Cursor *resizeCursor;
61 iWidget *menu; 61 iWidget *menu;
62 SDL_Texture *visBuffer;
63 iBool visBufferValid;
62}; 64};
63 65
64iDefineObjectConstruction(SidebarWidget) 66iDefineObjectConstruction(SidebarWidget)
65 67
68static void invalidate_SidebarWidget_(iSidebarWidget *d) {
69 d->visBufferValid = iFalse;
70 refresh_Widget(as_Widget(d));
71}
72
66static iBool isResizing_SidebarWidget_(const iSidebarWidget *d) { 73static iBool isResizing_SidebarWidget_(const iSidebarWidget *d) {
67 return (flags_Widget(d->resizer) & pressed_WidgetFlag) != 0; 74 return (flags_Widget(d->resizer) & pressed_WidgetFlag) != 0;
68} 75}
@@ -157,7 +164,7 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
157 break; 164 break;
158 } 165 }
159 updateVisible_SidebarWidget_(d); 166 updateVisible_SidebarWidget_(d);
160 refresh_Widget(as_Widget(d)); 167 invalidate_SidebarWidget_(d);
161} 168}
162 169
163void setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) { 170void setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) {
@@ -232,12 +239,15 @@ void init_SidebarWidget(iSidebarWidget *d) {
232 setBackgroundColor_Widget(d->resizer, none_ColorId); 239 setBackgroundColor_Widget(d->resizer, none_ColorId);
233 d->resizeCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); 240 d->resizeCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
234 d->menu = NULL; 241 d->menu = NULL;
242 d->visBuffer = NULL;
243 d->visBufferValid = iFalse;
235} 244}
236 245
237void deinit_SidebarWidget(iSidebarWidget *d) { 246void deinit_SidebarWidget(iSidebarWidget *d) {
238 SDL_FreeCursor(d->resizeCursor); 247 SDL_FreeCursor(d->resizeCursor);
239 clearItems_SidebarWidget_(d); 248 clearItems_SidebarWidget_(d);
240 deinit_Array(&d->items); 249 deinit_Array(&d->items);
250 SDL_DestroyTexture(d->visBuffer);
241} 251}
242 252
243static int visCount_SidebarWidget_(const iSidebarWidget *d) { 253static int visCount_SidebarWidget_(const iSidebarWidget *d) {
@@ -277,14 +287,18 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, size_t index) {
277} 287}
278 288
279static void scroll_SidebarWidget_(iSidebarWidget *d, int offset) { 289static void scroll_SidebarWidget_(iSidebarWidget *d, int offset) {
290 const int oldScroll = d->scrollY;
280 d->scrollY += offset; 291 d->scrollY += offset;
281 if (d->scrollY < 0) { 292 if (d->scrollY < 0) {
282 d->scrollY = 0; 293 d->scrollY = 0;
283 } 294 }
284 const int scrollMax = scrollMax_SidebarWidget_(d); 295 const int scrollMax = scrollMax_SidebarWidget_(d);
285 d->scrollY = iMin(d->scrollY, scrollMax); 296 d->scrollY = iMin(d->scrollY, scrollMax);
286 updateVisible_SidebarWidget_(d); 297 if (oldScroll != d->scrollY) {
287 refresh_Widget(as_Widget(d)); 298 d->hoverItem = iInvalidPos;
299 updateVisible_SidebarWidget_(d);
300 invalidate_SidebarWidget_(d);
301 }
288} 302}
289 303
290static void checkModeButtonLayout_SidebarWidget_(iSidebarWidget *d) { 304static void checkModeButtonLayout_SidebarWidget_(iSidebarWidget *d) {
@@ -320,7 +334,7 @@ void setWidth_SidebarWidget(iSidebarWidget *d, int width) {
320 checkModeButtonLayout_SidebarWidget_(d); 334 checkModeButtonLayout_SidebarWidget_(d);
321 if (!isRefreshPending_App()) { 335 if (!isRefreshPending_App()) {
322 updateSize_DocumentWidget(document_App()); 336 updateSize_DocumentWidget(document_App());
323 refresh_Widget(w); 337 invalidate_SidebarWidget_(d);
324 } 338 }
325} 339}
326 340
@@ -349,6 +363,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
349 if (isResize_UserEvent(ev)) { 363 if (isResize_UserEvent(ev)) {
350 updateVisible_SidebarWidget_(d); 364 updateVisible_SidebarWidget_(d);
351 checkModeButtonLayout_SidebarWidget_(d); 365 checkModeButtonLayout_SidebarWidget_(d);
366 invalidate_SidebarWidget_(d);
352 } 367 }
353 else if (ev->type == SDL_USEREVENT && ev->user.code == command_UserEventCode) { 368 else if (ev->type == SDL_USEREVENT && ev->user.code == command_UserEventCode) {
354 const char *cmd = command_UserEvent(ev); 369 const char *cmd = command_UserEvent(ev);
@@ -392,6 +407,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
392 setFlags_Widget(w, hidden_WidgetFlag, isVisible_Widget(w)); 407 setFlags_Widget(w, hidden_WidgetFlag, isVisible_Widget(w));
393 if (isVisible_Widget(w)) { 408 if (isVisible_Widget(w)) {
394 w->rect.size.x = d->width; 409 w->rect.size.x = d->width;
410 invalidate_SidebarWidget_(d);
395 } 411 }
396 arrange_Widget(w->parent); 412 arrange_Widget(w->parent);
397 updateSize_DocumentWidget(document_App()); 413 updateSize_DocumentWidget(document_App());
@@ -401,7 +417,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
401 else if (equal_Command(cmd, "scroll.moved")) { 417 else if (equal_Command(cmd, "scroll.moved")) {
402 d->scrollY = arg_Command(command_UserEvent(ev)); 418 d->scrollY = arg_Command(command_UserEvent(ev));
403 d->hoverItem = iInvalidPos; 419 d->hoverItem = iInvalidPos;
404 refresh_Widget(w); 420 invalidate_SidebarWidget_(d);
405 return iTrue; 421 return iTrue;
406 } 422 }
407 else if (equal_Command(cmd, "tabs.changed") || equal_Command(cmd, "document.changed")) { 423 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)
454 } 470 }
455 if (hover != d->hoverItem) { 471 if (hover != d->hoverItem) {
456 d->hoverItem = hover; 472 d->hoverItem = hover;
457 refresh_Widget(w); 473 invalidate_SidebarWidget_(d);
458 } 474 }
459 } 475 }
460 if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { 476 if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) {
@@ -464,8 +480,6 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
464#else 480#else
465 scroll_SidebarWidget_(d, -ev->wheel.y * 3 * d->itemHeight); 481 scroll_SidebarWidget_(d, -ev->wheel.y * 3 * d->itemHeight);
466#endif 482#endif
467 d->hoverItem = iInvalidPos;
468 refresh_Widget(w);
469 return iTrue; 483 return iTrue;
470 } 484 }
471 if (d->menu && ev->type == SDL_MOUSEBUTTONDOWN) { 485 if (d->menu && ev->type == SDL_MOUSEBUTTONDOWN) {
@@ -475,14 +489,14 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
475 } 489 }
476 switch (processEvent_Click(&d->click, ev)) { 490 switch (processEvent_Click(&d->click, ev)) {
477 case started_ClickResult: 491 case started_ClickResult:
478 refresh_Widget(w); 492 invalidate_SidebarWidget_(d);
479 break; 493 break;
480 case finished_ClickResult: 494 case finished_ClickResult:
481 if (contains_Rect(contentBounds_SidebarWidget_(d), pos_Click(&d->click)) && 495 if (contains_Rect(contentBounds_SidebarWidget_(d), pos_Click(&d->click)) &&
482 d->hoverItem != iInvalidSize) { 496 d->hoverItem != iInvalidSize) {
483 itemClicked_SidebarWidget_(d, d->hoverItem); 497 itemClicked_SidebarWidget_(d, d->hoverItem);
484 } 498 }
485 refresh_Widget(w); 499 invalidate_SidebarWidget_(d);
486 break; 500 break;
487 default: 501 default:
488 break; 502 break;
@@ -490,64 +504,93 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
490 return processEvent_Widget(w, ev); 504 return processEvent_Widget(w, ev);
491} 505}
492 506
507static void allocVisBuffer_SidebarWidget_(iSidebarWidget *d) {
508 const iInt2 size = contentBounds_SidebarWidget_(d).size;
509 if (!d->visBuffer || !isEqual_I2(size_SDLTexture(d->visBuffer), size)) {
510 if (d->visBuffer) {
511 SDL_DestroyTexture(d->visBuffer);
512 }
513 d->visBuffer = SDL_CreateTexture(renderer_Window(get_Window()),
514 SDL_PIXELFORMAT_RGBA8888,
515 SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET,
516 size.x,
517 size.y);
518 SDL_SetTextureBlendMode(d->visBuffer, SDL_BLENDMODE_NONE);
519 d->visBufferValid = iFalse;
520 }
521}
522
493static void draw_SidebarWidget_(const iSidebarWidget *d) { 523static void draw_SidebarWidget_(const iSidebarWidget *d) {
494 const iWidget *w = constAs_Widget(d); 524 const iWidget *w = constAs_Widget(d);
495 const iRect bounds = contentBounds_SidebarWidget_(d); 525 const iRect bounds = contentBounds_SidebarWidget_(d);
496 const iBool isPressing = d->click.isActive && contains_Rect(bounds, pos_Click(&d->click)); 526 const iBool isPressing = d->click.isActive && contains_Rect(bounds, pos_Click(&d->click));
497 iPaint p; 527 iPaint p;
498 init_Paint(&p); 528 init_Paint(&p);
499 fillRect_Paint(&p, 529 const int bg =
500 bounds_Widget(w), 530 d->mode == documentOutline_SidebarMode ? tmBackground_ColorId : uiBackground_ColorId;
501 d->mode == documentOutline_SidebarMode ? tmBackground_ColorId 531 fillRect_Paint(&p, bounds_Widget(w), bg); /* TODO: should do only the mode buttons area */
502 : uiBackground_ColorId); 532 if (!d->visBufferValid) {
503 /* Draw the items. */ { 533 allocVisBuffer_SidebarWidget_(iConstCast(iSidebarWidget *, d));
504 const int font = uiContent_FontId; 534 iRect bufBounds = bounds;
505 const iRanges visRange = visRange_SidebarWidget_(d); 535 bufBounds.pos = zero_I2();
506 iInt2 pos = addY_I2(topLeft_Rect(bounds), -(d->scrollY % d->itemHeight)); 536 beginTarget_Paint(&p, d->visBuffer);
507 for (size_t i = visRange.start; i < visRange.end; i++) { 537 fillRect_Paint(&p, bufBounds, bg);
508 const iSidebarItem *item = constAt_Array(&d->items, i); 538 /* Draw the items. */ {
509 const iRect itemRect = { pos, init_I2(width_Rect(bounds), d->itemHeight) }; 539 const int font = uiContent_FontId;
510 const iBool isHover = (d->hoverItem == i); 540 const iRanges visRange = visRange_SidebarWidget_(d);
511 setClip_Paint(&p, intersect_Rect(itemRect, bounds)); 541 iInt2 pos = addY_I2(topLeft_Rect(bufBounds), -(d->scrollY % d->itemHeight));
512 if (isHover) { 542 for (size_t i = visRange.start; i < visRange.end; i++) {
513 fillRect_Paint(&p, 543 const iSidebarItem *item = constAt_Array(&d->items, i);
514 itemRect, 544 const iRect itemRect = { pos, init_I2(width_Rect(bufBounds), d->itemHeight) };
515 isPressing ? uiBackgroundPressed_ColorId 545 const iBool isHover = (d->hoverItem == i);
516 : uiBackgroundFramelessHover_ColorId); 546 setClip_Paint(&p, intersect_Rect(itemRect, bufBounds));
517 } 547 if (isHover) {
518 if (d->mode == documentOutline_SidebarMode) { 548 fillRect_Paint(&p,
519 const int fg = 549 itemRect,
520 isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId) 550 isPressing ? uiBackgroundPressed_ColorId
521 : (tmHeading1_ColorId + item->indent / (4 * gap_UI)); 551 : uiBackgroundFramelessHover_ColorId);
522 drawRange_Text(font, init_I2(pos.x + 3 * gap_UI + item->indent, 552 }
523 mid_Rect(itemRect).y - lineHeight_Text(font) / 2), 553 if (d->mode == documentOutline_SidebarMode) {
524 fg, range_String(&item->label)); 554 const int fg = isHover ? (isPressing ? uiTextPressed_ColorId
525 } 555 : uiTextFramelessHover_ColorId)
526 else if (d->mode == bookmarks_SidebarMode) { 556 : (tmHeading1_ColorId + item->indent / (4 * gap_UI));
527 const int fg = 557 drawRange_Text(font,
528 isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId) 558 init_I2(pos.x + 3 * gap_UI + item->indent,
529 : uiText_ColorId; 559 mid_Rect(itemRect).y - lineHeight_Text(font) / 2),
530 iString str; 560 fg,
531 init_String(&str); 561 range_String(&item->label));
532 appendChar_String(&str, item->icon ? item->icon : 0x1f588); 562 }
533 const iRect iconArea = { addX_I2(pos, gap_UI), init_I2(7 * gap_UI, d->itemHeight) }; 563 else if (d->mode == bookmarks_SidebarMode) {
534 drawCentered_Text(font, 564 const int fg = isHover ? (isPressing ? uiTextPressed_ColorId
535 iconArea, 565 : uiTextFramelessHover_ColorId)
536 iTrue, 566 : uiText_ColorId;
537 isHover 567 iString str;
538 ? (isPressing ? uiTextPressed_ColorId : uiIconHover_ColorId) 568 init_String(&str);
539 : uiIcon_ColorId, 569 appendChar_String(&str, item->icon ? item->icon : 0x1f588);
540 "%s", 570 const iRect iconArea = { addX_I2(pos, gap_UI),
541 cstr_String(&str)); 571 init_I2(7 * gap_UI, d->itemHeight) };
542 deinit_String(&str); 572 drawCentered_Text(
543 iInt2 textPos = 573 font,
544 addY_I2(topRight_Rect(iconArea), (d->itemHeight - lineHeight_Text(font)) / 2); 574 iconArea,
545 drawRange_Text(font, textPos, fg, range_String(&item->label)); 575 iTrue,
576 isHover ? (isPressing ? uiTextPressed_ColorId : uiIconHover_ColorId)
577 : uiIcon_ColorId,
578 "%s",
579 cstr_String(&str));
580 deinit_String(&str);
581 iInt2 textPos = addY_I2(topRight_Rect(iconArea),
582 (d->itemHeight - lineHeight_Text(font)) / 2);
583 drawRange_Text(font, textPos, fg, range_String(&item->label));
584 }
585 unsetClip_Paint(&p);
586 pos.y += d->itemHeight;
546 } 587 }
547 unsetClip_Paint(&p);
548 pos.y += d->itemHeight;
549 } 588 }
589 endTarget_Paint(&p);
590 iConstCast(iSidebarWidget *, d)->visBufferValid = iTrue;
550 } 591 }
592 SDL_RenderCopy(
593 renderer_Window(get_Window()), d->visBuffer, NULL, (const SDL_Rect *) &bounds);
551 draw_Widget(w); 594 draw_Widget(w);
552 drawVLine_Paint(&p, 595 drawVLine_Paint(&p,
553 addX_I2(topRight_Rect(bounds_Widget(w)), -1), 596 addX_I2(topRight_Rect(bounds_Widget(w)), -1),