diff options
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/paint.c | 6 | ||||
-rw-r--r-- | src/ui/paint.h | 2 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 161 |
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 | |||
78 | iInt2 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) { | |||
35 | iLocalDef void drawVLine_Paint(const iPaint *d, iInt2 pos, int len, int color) { | 35 | iLocalDef 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 | |||
39 | 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 { | |||
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 | ||
64 | iDefineObjectConstruction(SidebarWidget) | 66 | iDefineObjectConstruction(SidebarWidget) |
65 | 67 | ||
68 | static void invalidate_SidebarWidget_(iSidebarWidget *d) { | ||
69 | d->visBufferValid = iFalse; | ||
70 | refresh_Widget(as_Widget(d)); | ||
71 | } | ||
72 | |||
66 | static iBool isResizing_SidebarWidget_(const iSidebarWidget *d) { | 73 | static 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 | ||
163 | void setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) { | 170 | void 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 | ||
237 | void deinit_SidebarWidget(iSidebarWidget *d) { | 246 | void 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 | ||
243 | static int visCount_SidebarWidget_(const iSidebarWidget *d) { | 253 | static int visCount_SidebarWidget_(const iSidebarWidget *d) { |
@@ -277,14 +287,18 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, size_t index) { | |||
277 | } | 287 | } |
278 | 288 | ||
279 | static void scroll_SidebarWidget_(iSidebarWidget *d, int offset) { | 289 | static 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 | ||
290 | static void checkModeButtonLayout_SidebarWidget_(iSidebarWidget *d) { | 304 | static 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 | ||
507 | static 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 | |||
493 | static void draw_SidebarWidget_(const iSidebarWidget *d) { | 523 | static 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), |