summaryrefslogtreecommitdiff
path: root/src/ui/sidebarwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/sidebarwidget.c')
-rw-r--r--src/ui/sidebarwidget.c170
1 files changed, 108 insertions, 62 deletions
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c
index de576f72..71b641d4 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) {
@@ -166,8 +173,8 @@ void setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) {
166 for (enum iSidebarMode i = 0; i < max_SidebarMode; i++) { 173 for (enum iSidebarMode i = 0; i < max_SidebarMode; i++) {
167 setFlags_Widget(as_Widget(d->modeButtons[i]), selected_WidgetFlag, i == d->mode); 174 setFlags_Widget(as_Widget(d->modeButtons[i]), selected_WidgetFlag, i == d->mode);
168 } 175 }
169 const float heights[max_SidebarMode] = { 1.5f, 3, 3, 1.2f }; 176 const float heights[max_SidebarMode] = { 1.333f, 3, 3, 1.2f };
170 d->itemHeight = heights[mode] * lineHeight_Text(default_FontId); 177 d->itemHeight = heights[mode] * lineHeight_Text(uiContent_FontId);
171} 178}
172 179
173enum iSidebarMode mode_SidebarWidget(const iSidebarWidget *d) { 180enum iSidebarMode mode_SidebarWidget(const iSidebarWidget *d) {
@@ -217,7 +224,7 @@ void init_SidebarWidget(iSidebarWidget *d) {
217 frameless_WidgetFlag | expand_WidgetFlag); 224 frameless_WidgetFlag | expand_WidgetFlag);
218 d->maxButtonLabelWidth = 225 d->maxButtonLabelWidth =
219 iMaxi(d->maxButtonLabelWidth, 226 iMaxi(d->maxButtonLabelWidth,
220 3 * gap_UI + measure_Text(default_FontId, normalModeLabels_[i]).x); 227 3 * gap_UI + measure_Text(uiLabel_FontId, normalModeLabels_[i]).x);
221 } 228 }
222 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); 229 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget()));
223 setThumb_ScrollWidget(d->scroll, 0, 0); 230 setThumb_ScrollWidget(d->scroll, 0, 0);
@@ -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,13 +417,16 @@ 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")) {
408 d->scrollY = 0; 424 d->scrollY = 0;
409 updateItems_SidebarWidget_(d); 425 updateItems_SidebarWidget_(d);
410 } 426 }
427 else if (equal_Command(cmd, "theme.changed")) {
428 invalidate_SidebarWidget_(d);
429 }
411 else if (equal_Command(cmd, "bookmark.copy")) { 430 else if (equal_Command(cmd, "bookmark.copy")) {
412 const iSidebarItem *item = hoverItem_SidebarWidget_(d); 431 const iSidebarItem *item = hoverItem_SidebarWidget_(d);
413 if (d->mode == bookmarks_SidebarMode && item) { 432 if (d->mode == bookmarks_SidebarMode && item) {
@@ -454,7 +473,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
454 } 473 }
455 if (hover != d->hoverItem) { 474 if (hover != d->hoverItem) {
456 d->hoverItem = hover; 475 d->hoverItem = hover;
457 refresh_Widget(w); 476 invalidate_SidebarWidget_(d);
458 } 477 }
459 } 478 }
460 if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { 479 if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) {
@@ -464,8 +483,6 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
464#else 483#else
465 scroll_SidebarWidget_(d, -ev->wheel.y * 3 * d->itemHeight); 484 scroll_SidebarWidget_(d, -ev->wheel.y * 3 * d->itemHeight);
466#endif 485#endif
467 d->hoverItem = iInvalidPos;
468 refresh_Widget(w);
469 return iTrue; 486 return iTrue;
470 } 487 }
471 if (d->menu && ev->type == SDL_MOUSEBUTTONDOWN) { 488 if (d->menu && ev->type == SDL_MOUSEBUTTONDOWN) {
@@ -475,14 +492,14 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
475 } 492 }
476 switch (processEvent_Click(&d->click, ev)) { 493 switch (processEvent_Click(&d->click, ev)) {
477 case started_ClickResult: 494 case started_ClickResult:
478 refresh_Widget(w); 495 invalidate_SidebarWidget_(d);
479 break; 496 break;
480 case finished_ClickResult: 497 case finished_ClickResult:
481 if (contains_Rect(contentBounds_SidebarWidget_(d), pos_Click(&d->click)) && 498 if (contains_Rect(contentBounds_SidebarWidget_(d), pos_Click(&d->click)) &&
482 d->hoverItem != iInvalidSize) { 499 d->hoverItem != iInvalidSize) {
483 itemClicked_SidebarWidget_(d, d->hoverItem); 500 itemClicked_SidebarWidget_(d, d->hoverItem);
484 } 501 }
485 refresh_Widget(w); 502 invalidate_SidebarWidget_(d);
486 break; 503 break;
487 default: 504 default:
488 break; 505 break;
@@ -490,64 +507,93 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
490 return processEvent_Widget(w, ev); 507 return processEvent_Widget(w, ev);
491} 508}
492 509
510static void allocVisBuffer_SidebarWidget_(iSidebarWidget *d) {
511 const iInt2 size = contentBounds_SidebarWidget_(d).size;
512 if (!d->visBuffer || !isEqual_I2(size_SDLTexture(d->visBuffer), size)) {
513 if (d->visBuffer) {
514 SDL_DestroyTexture(d->visBuffer);
515 }
516 d->visBuffer = SDL_CreateTexture(renderer_Window(get_Window()),
517 SDL_PIXELFORMAT_RGBA8888,
518 SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET,
519 size.x,
520 size.y);
521 SDL_SetTextureBlendMode(d->visBuffer, SDL_BLENDMODE_NONE);
522 d->visBufferValid = iFalse;
523 }
524}
525
493static void draw_SidebarWidget_(const iSidebarWidget *d) { 526static void draw_SidebarWidget_(const iSidebarWidget *d) {
494 const iWidget *w = constAs_Widget(d); 527 const iWidget *w = constAs_Widget(d);
495 const iRect bounds = contentBounds_SidebarWidget_(d); 528 const iRect bounds = contentBounds_SidebarWidget_(d);
496 const iBool isPressing = d->click.isActive && contains_Rect(bounds, pos_Click(&d->click)); 529 const iBool isPressing = d->click.isActive && contains_Rect(bounds, pos_Click(&d->click));
497 iPaint p; 530 iPaint p;
498 init_Paint(&p); 531 init_Paint(&p);
499 fillRect_Paint(&p, 532 const int bg =
500 bounds_Widget(w), 533 d->mode == documentOutline_SidebarMode ? tmBackground_ColorId : uiBackground_ColorId;
501 d->mode == documentOutline_SidebarMode ? tmBackground_ColorId 534 fillRect_Paint(&p, bounds_Widget(w), bg); /* TODO: should do only the mode buttons area */
502 : uiBackground_ColorId); 535 if (!d->visBufferValid) {
503 /* Draw the items. */ { 536 allocVisBuffer_SidebarWidget_(iConstCast(iSidebarWidget *, d));
504 const int font = default_FontId; 537 iRect bufBounds = bounds;
505 const iRanges visRange = visRange_SidebarWidget_(d); 538 bufBounds.pos = zero_I2();
506 iInt2 pos = addY_I2(topLeft_Rect(bounds), -(d->scrollY % d->itemHeight)); 539 beginTarget_Paint(&p, d->visBuffer);
507 for (size_t i = visRange.start; i < visRange.end; i++) { 540 fillRect_Paint(&p, bufBounds, bg);
508 const iSidebarItem *item = constAt_Array(&d->items, i); 541 /* Draw the items. */ {
509 const iRect itemRect = { pos, init_I2(width_Rect(bounds), d->itemHeight) }; 542 const int font = uiContent_FontId;
510 const iBool isHover = (d->hoverItem == i); 543 const iRanges visRange = visRange_SidebarWidget_(d);
511 setClip_Paint(&p, intersect_Rect(itemRect, bounds)); 544 iInt2 pos = addY_I2(topLeft_Rect(bufBounds), -(d->scrollY % d->itemHeight));
512 if (isHover) { 545 for (size_t i = visRange.start; i < visRange.end; i++) {
513 fillRect_Paint(&p, 546 const iSidebarItem *item = constAt_Array(&d->items, i);
514 itemRect, 547 const iRect itemRect = { pos, init_I2(width_Rect(bufBounds), d->itemHeight) };
515 isPressing ? uiBackgroundPressed_ColorId 548 const iBool isHover = (d->hoverItem == i);
516 : uiBackgroundFramelessHover_ColorId); 549 setClip_Paint(&p, intersect_Rect(itemRect, bufBounds));
517 } 550 if (isHover) {
518 if (d->mode == documentOutline_SidebarMode) { 551 fillRect_Paint(&p,
519 const int fg = 552 itemRect,
520 isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId) 553 isPressing ? uiBackgroundPressed_ColorId
521 : (tmHeading1_ColorId + item->indent / (4 * gap_UI)); 554 : uiBackgroundFramelessHover_ColorId);
522 drawRange_Text(font, init_I2(pos.x + 3 * gap_UI + item->indent, 555 }
523 mid_Rect(itemRect).y - lineHeight_Text(font) / 2), 556 if (d->mode == documentOutline_SidebarMode) {
524 fg, range_String(&item->label)); 557 const int fg = isHover ? (isPressing ? uiTextPressed_ColorId
525 } 558 : uiTextFramelessHover_ColorId)
526 else if (d->mode == bookmarks_SidebarMode) { 559 : (tmHeading1_ColorId + item->indent / (4 * gap_UI));
527 const int fg = 560 drawRange_Text(font,
528 isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId) 561 init_I2(pos.x + 3 * gap_UI + item->indent,
529 : uiText_ColorId; 562 mid_Rect(itemRect).y - lineHeight_Text(font) / 2),
530 iString str; 563 fg,
531 init_String(&str); 564 range_String(&item->label));
532 appendChar_String(&str, item->icon ? item->icon : 0x1f588); 565 }
533 const iRect iconArea = { addX_I2(pos, gap_UI), init_I2(7 * gap_UI, d->itemHeight) }; 566 else if (d->mode == bookmarks_SidebarMode) {
534 drawCentered_Text(font, 567 const int fg = isHover ? (isPressing ? uiTextPressed_ColorId
535 iconArea, 568 : uiTextFramelessHover_ColorId)
536 iTrue, 569 : uiText_ColorId;
537 isHover 570 iString str;
538 ? (isPressing ? uiTextPressed_ColorId : uiIconHover_ColorId) 571 init_String(&str);
539 : uiIcon_ColorId, 572 appendChar_String(&str, item->icon ? item->icon : 0x1f588);
540 "%s", 573 const iRect iconArea = { addX_I2(pos, gap_UI),
541 cstr_String(&str)); 574 init_I2(7 * gap_UI, d->itemHeight) };
542 deinit_String(&str); 575 drawCentered_Text(
543 iInt2 textPos = 576 font,
544 addY_I2(topRight_Rect(iconArea), (d->itemHeight - lineHeight_Text(font)) / 2); 577 iconArea,
545 drawRange_Text(font, textPos, fg, range_String(&item->label)); 578 iTrue,
579 isHover ? (isPressing ? uiTextPressed_ColorId : uiIconHover_ColorId)
580 : uiIcon_ColorId,
581 "%s",
582 cstr_String(&str));
583 deinit_String(&str);
584 iInt2 textPos = addY_I2(topRight_Rect(iconArea),
585 (d->itemHeight - lineHeight_Text(font)) / 2);
586 drawRange_Text(font, textPos, fg, range_String(&item->label));
587 }
588 unsetClip_Paint(&p);
589 pos.y += d->itemHeight;
546 } 590 }
547 unsetClip_Paint(&p);
548 pos.y += d->itemHeight;
549 } 591 }
592 endTarget_Paint(&p);
593 iConstCast(iSidebarWidget *, d)->visBufferValid = iTrue;
550 } 594 }
595 SDL_RenderCopy(
596 renderer_Window(get_Window()), d->visBuffer, NULL, (const SDL_Rect *) &bounds);
551 draw_Widget(w); 597 draw_Widget(w);
552 drawVLine_Paint(&p, 598 drawVLine_Paint(&p,
553 addX_I2(topRight_Rect(bounds_Widget(w)), -1), 599 addX_I2(topRight_Rect(bounds_Widget(w)), -1),