diff options
| author | salmonik <salmonik@tuta.io> | 2026-10-27 20:30:15 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-10-27 20:30:15 +0100 |
| commit | 5ee13d8cee52505056a14c3ba3793d0e56afa202 (patch) | |
| tree | 856c32e86382d1a4a0161271fdc7cc714560cee2 | |
| parent | Stucklaunch: alternate attack/use and expose spam rate (diff) | |
| download | hl2h-5ee13d8cee52505056a14c3ba3793d0e56afa202.tar.gz hl2h-5ee13d8cee52505056a14c3ba3793d0e56afa202.zip | |
GUI: wrap all text instead of truncating
- Remove ellipsis truncation from text_in; text is never cut to fit.
- Add a wrapping helper that breaks at spaces and, for long words such as
paths, at character boundaries. Card titles, control labels, info rows,
sections, tooltips and toasts now wrap and their rows/panels grow.
- Use ISurface::GetTextSize (slot 75) for real glyph widths, with the old
estimate only as a fallback before the surface/fonts exist.
- Dynamic card header height for wrapped titles; Active/Bind controls stay
vertically centered. Slider controls are vertically centered in taller
wrapped rows.
- Auto-size System buttons to their labels.
- Tooltips wrap to a panel sized by the widest line.
- Drop the duplicate config path from the footer; the System page shows it
wrapped, so the footer hint fits without clipping.
| -rw-r--r-- | CONTEXT.md | 4 | ||||
| -rw-r--r-- | src/ISURFACE_STATUS.md | 1 | ||||
| -rw-r--r-- | src/gui.cpp | 419 |
3 files changed, 250 insertions, 174 deletions
| @@ -108,6 +108,10 @@ vocabulary / decisions. | |||
| 108 | - **Category**: sidebar group. Movement, Combat, Visuals, Weapons, System. | 108 | - **Category**: sidebar group. Movement, Combat, Visuals, Weapons, System. |
| 109 | - **Card**: per-feature panel. Header always shows Active + Bind; body is a | 109 | - **Card**: per-feature panel. Header always shows Active + Bind; body is a |
| 110 | collapsible set of settings. | 110 | collapsible set of settings. |
| 111 | - **Text layout**: measured with `ISurface::GetTextSize` and wrapped to the | ||
| 112 | available width. Card headers, control rows, info rows, tooltips and toasts | ||
| 113 | grow/wrap instead of truncating; there is no ellipsis truncation. The config | ||
| 114 | path is shown on the System page (not duplicated in the footer). | ||
| 111 | - **Freeze**: while the GUI is open, look/attack/use/impulse/weapon selection | 115 | - **Freeze**: while the GUI is open, look/attack/use/impulse/weapon selection |
| 112 | are blocked and combat features are skipped, but normal WASD/jump/duck/walk | 116 | are blocked and combat features are skipped, but normal WASD/jump/duck/walk |
| 113 | movement is allowed. Mouse deltas are discarded before `CInput::CreateMove` | 117 | movement is allowed. Mouse deltas are discarded before `CInput::CreateMove` |
diff --git a/src/ISURFACE_STATUS.md b/src/ISURFACE_STATUS.md index d553af0..53be3b0 100644 --- a/src/ISURFACE_STATUS.md +++ b/src/ISURFACE_STATUS.md | |||
| @@ -26,6 +26,7 @@ slots 6/10/12/15/17/18/20/22/66/67. | |||
| 26 | | 22 | `DrawPrintText(wchar_t*, int, drawType)` | reads font `0x290`, pos `0x2c/0x30` | | 26 | | 22 | `DrawPrintText(wchar_t*, int, drawType)` | reads font `0x290`, pos `0x2c/0x30` | |
| 27 | | 66 | `CreateFont()` | SDK header 62; empirical (379) | | 27 | | 66 | `CreateFont()` | SDK header 62; empirical (379) | |
| 28 | | 67 | `AddGlyphSetToFont(font,name,tall,weight,blur,scanlines,flags,rangeMin,rangeMax)` | SDK header 62+4; disassembly (slot 67 = 0x6a300, passes 9 args to FontManager) | | 28 | | 67 | `AddGlyphSetToFont(font,name,tall,weight,blur,scanlines,flags,rangeMin,rangeMax)` | SDK header 62+4; disassembly (slot 67 = 0x6a300, passes 9 args to FontManager) | |
| 29 | | 75 | `GetTextSize(HFont, const wchar_t*, int& wide, int& tall)` | SDK header 71+4; used for accurate GUI wrapping | | ||
| 29 | | 87 | `SolveTraverse` | InternalSchemeSettingsTraverse profiling strings @ 0x73240 | | 30 | | 87 | `SolveTraverse` | InternalSchemeSettingsTraverse profiling strings @ 0x73240 | |
| 30 | | 88 | `PaintTraverse(VPANEL)` | tail-calls `ipanel->vt+0x1c8(panel,false)` @ 0x697e0 | | 31 | | 88 | `PaintTraverse(VPANEL)` | tail-calls `ipanel->vt+0x1c8(panel,false)` @ 0x697e0 | |
| 31 | | 114 | `PaintTraverseEx(VPANEL, bool paintPopups)` | IsVisible check `ipanel+0x40`, popup array `this+0x250/0x25c`, "Too many popups!" assert @ 0x6dd46 | | 32 | | 114 | `PaintTraverseEx(VPANEL, bool paintPopups)` | IsVisible check `ipanel+0x40`, popup array `this+0x250/0x25c`, "Too many popups!" assert @ 0x6dd46 | |
diff --git a/src/gui.cpp b/src/gui.cpp index fc95d1f..f4ba009 100644 --- a/src/gui.cpp +++ b/src/gui.cpp | |||
| @@ -30,7 +30,8 @@ enum { | |||
| 30 | GS_DrawPrintText = 22, | 30 | GS_DrawPrintText = 22, |
| 31 | GS_GetScreenSize = 38, | 31 | GS_GetScreenSize = 38, |
| 32 | GS_CreateFont = 66, | 32 | GS_CreateFont = 66, |
| 33 | GS_AddGlyphSet = 67 | 33 | GS_AddGlyphSet = 67, |
| 34 | GS_GetTextSize = 75 | ||
| 34 | }; | 35 | }; |
| 35 | 36 | ||
| 36 | static unsigned long g_font_body = 0; | 37 | static unsigned long g_font_body = 0; |
| @@ -87,6 +88,11 @@ static void s_screen(int &w, int &h) { | |||
| 87 | using Fn = void (*)(void *, int &, int &); | 88 | using Fn = void (*)(void *, int &, int &); |
| 88 | vfunc<Fn>(g_surface, GS_GetScreenSize)(g_surface, w, h); | 89 | vfunc<Fn>(g_surface, GS_GetScreenSize)(g_surface, w, h); |
| 89 | } | 90 | } |
| 91 | static void s_text_size(unsigned long font, const wchar_t *text, int &w, | ||
| 92 | int &h) { | ||
| 93 | using Fn = void (*)(void *, unsigned long, const wchar_t *, int &, int &); | ||
| 94 | vfunc<Fn>(g_surface, GS_GetTextSize)(g_surface, font, text, w, h); | ||
| 95 | } | ||
| 90 | 96 | ||
| 91 | // --------------------------------------------------------------------------- | 97 | // --------------------------------------------------------------------------- |
| 92 | // SDL polling | 98 | // SDL polling |
| @@ -511,17 +517,98 @@ static void ensure_fonts() { | |||
| 511 | } | 517 | } |
| 512 | 518 | ||
| 513 | static int text_w(const char *s, int tall) { | 519 | static int text_w(const char *s, int tall) { |
| 514 | if (!s) return 0; | 520 | if (!s) |
| 521 | return 0; | ||
| 522 | unsigned long font = | ||
| 523 | (g_font_title && tall == g_title_h) ? g_font_title : g_font_body; | ||
| 524 | if (g_surface && font) { | ||
| 525 | wchar_t wbuf[1024]; | ||
| 526 | size_t n = mbstowcs(wbuf, s, 1023); | ||
| 527 | if (n != (size_t)-1) { | ||
| 528 | wbuf[n] = 0; | ||
| 529 | int w = 0, h = 0; | ||
| 530 | s_text_size(font, wbuf, w, h); | ||
| 531 | if (w > 0) | ||
| 532 | return w; | ||
| 533 | } | ||
| 534 | } | ||
| 535 | // Fallback when the surface/font is not ready yet. | ||
| 515 | return (int)(strlen(s) * tall * 0.52f + 0.5f); | 536 | return (int)(strlen(s) * tall * 0.52f + 0.5f); |
| 516 | } | 537 | } |
| 517 | 538 | ||
| 518 | static void draw_text_raw(int x, int y, const char *s, unsigned long font, | 539 | static void draw_text_raw(int x, int y, const char *s, unsigned long font, |
| 540 | int tall); | ||
| 541 | |||
| 542 | // Break text into lines that fit max_w. Words that are too wide (paths, long | ||
| 543 | // identifiers) are split by character so nothing is ever truncated. | ||
| 544 | static void wrap_text(const char *text, int max_w, int tall, | ||
| 545 | std::vector<std::string> &out) { | ||
| 546 | out.clear(); | ||
| 547 | if (!text || !*text || max_w <= 0) | ||
| 548 | return; | ||
| 549 | const char *p = text; | ||
| 550 | std::string line; | ||
| 551 | while (*p) { | ||
| 552 | while (*p == ' ') | ||
| 553 | p++; | ||
| 554 | if (!*p) | ||
| 555 | break; | ||
| 556 | const char *start = p; | ||
| 557 | while (*p && *p != ' ') | ||
| 558 | p++; | ||
| 559 | std::string word(start, (size_t)(p - start)); | ||
| 560 | if (!line.empty()) { | ||
| 561 | std::string cand = line + " " + word; | ||
| 562 | if (text_w(cand.c_str(), tall) <= max_w) { | ||
| 563 | line = cand; | ||
| 564 | continue; | ||
| 565 | } | ||
| 566 | out.push_back(line); | ||
| 567 | line.clear(); | ||
| 568 | } | ||
| 569 | while (text_w(word.c_str(), tall) > max_w && word.size() > 1) { | ||
| 570 | size_t n = word.size(); | ||
| 571 | while (n > 1 && text_w(word.substr(0, n).c_str(), tall) > max_w) | ||
| 572 | n--; | ||
| 573 | out.push_back(word.substr(0, n)); | ||
| 574 | word = word.substr(n); | ||
| 575 | } | ||
| 576 | line = word; | ||
| 577 | } | ||
| 578 | if (!line.empty()) | ||
| 579 | out.push_back(line); | ||
| 580 | } | ||
| 581 | |||
| 582 | static int wrap_count(const char *text, int max_w, int tall) { | ||
| 583 | std::vector<std::string> lines; | ||
| 584 | wrap_text(text, max_w, tall, lines); | ||
| 585 | return (int)lines.size(); | ||
| 586 | } | ||
| 587 | |||
| 588 | static void draw_wrapped(const Rect &clip, int x, int y, const char *text, | ||
| 589 | unsigned long font, int tall, int max_w, | ||
| 590 | const Col &c, int line_gap = 2) { | ||
| 591 | if (!text || !font) | ||
| 592 | return; | ||
| 593 | std::vector<std::string> lines; | ||
| 594 | wrap_text(text, max_w, tall, lines); | ||
| 595 | s_text_color(c.r, c.g, c.b, c.a); | ||
| 596 | int lh = tall + line_gap; | ||
| 597 | for (size_t i = 0; i < lines.size(); i++) { | ||
| 598 | int ly = y + (int)i * lh; | ||
| 599 | if (ly < clip.y || ly + tall > clip.y + clip.h) | ||
| 600 | continue; | ||
| 601 | draw_text_raw(x, ly, lines[i].c_str(), font, tall); | ||
| 602 | } | ||
| 603 | } | ||
| 604 | |||
| 605 | static void draw_text_raw(int x, int y, const char *s, unsigned long font, | ||
| 519 | int tall) { | 606 | int tall) { |
| 520 | (void)tall; | 607 | (void)tall; |
| 521 | if (!s || !font) | 608 | if (!s || !font) |
| 522 | return; | 609 | return; |
| 523 | wchar_t w[256]; | 610 | wchar_t w[1024]; |
| 524 | size_t n = mbstowcs(w, s, 255); | 611 | size_t n = mbstowcs(w, s, 1023); |
| 525 | if (n == (size_t)-1) | 612 | if (n == (size_t)-1) |
| 526 | return; | 613 | return; |
| 527 | w[n] = 0; | 614 | w[n] = 0; |
| @@ -532,46 +619,20 @@ static void draw_text_raw(int x, int y, const char *s, unsigned long font, | |||
| 532 | 619 | ||
| 533 | static void text_in(const Rect &clip, int x, int y, const char *s, | 620 | static void text_in(const Rect &clip, int x, int y, const char *s, |
| 534 | unsigned long font, int tall, int max_w, const Col &c) { | 621 | unsigned long font, int tall, int max_w, const Col &c) { |
| 622 | (void)max_w; // callers must size the layout; text is never truncated | ||
| 535 | if (!s || !font) | 623 | if (!s || !font) |
| 536 | return; | 624 | return; |
| 537 | if (y < clip.y || y + tall > clip.y + clip.h) | 625 | if (y < clip.y || y + tall > clip.y + clip.h) |
| 538 | return; | 626 | return; |
| 539 | if (x >= clip.x + clip.w) | 627 | if (x >= clip.x + clip.w) |
| 540 | return; | 628 | return; |
| 541 | |||
| 542 | // Available space from x to the clip edge, optionally capped by max_w. | ||
| 543 | // Truncate first, then clamp: shifting before truncating used to draw the | ||
| 544 | // text outside the tooltip/button box. | ||
| 545 | int avail = clip.x + clip.w - x; | ||
| 546 | if (max_w > 0 && max_w < avail) | ||
| 547 | avail = max_w; | ||
| 548 | if (avail <= 0) | ||
| 549 | return; | ||
| 550 | |||
| 551 | char buf[256]; | ||
| 552 | const char *draw = s; | ||
| 553 | int w = text_w(s, tall); | 629 | int w = text_w(s, tall); |
| 554 | if (w > avail) { | ||
| 555 | snprintf(buf, sizeof(buf), "%s", s); | ||
| 556 | int n = (int)strlen(buf); | ||
| 557 | int dots = text_w("...", tall); | ||
| 558 | while (n > 0 && text_w(buf, tall) + dots > avail) | ||
| 559 | buf[--n] = 0; | ||
| 560 | if (n > 0 && n + 3 < (int)sizeof(buf)) { | ||
| 561 | buf[n++] = '.'; | ||
| 562 | buf[n++] = '.'; | ||
| 563 | buf[n++] = '.'; | ||
| 564 | buf[n] = 0; | ||
| 565 | } | ||
| 566 | draw = buf; | ||
| 567 | w = text_w(draw, tall); | ||
| 568 | } | ||
| 569 | if (x + w > clip.x + clip.w) | 630 | if (x + w > clip.x + clip.w) |
| 570 | x = clip.x + clip.w - w; | 631 | x = clip.x + clip.w - w; |
| 571 | if (x < clip.x) | 632 | if (x < clip.x) |
| 572 | x = clip.x; | 633 | x = clip.x; |
| 573 | s_text_color(c.r, c.g, c.b, c.a); | 634 | s_text_color(c.r, c.g, c.b, c.a); |
| 574 | draw_text_raw(x, y, draw, font, tall); | 635 | draw_text_raw(x, y, s, font, tall); |
| 575 | } | 636 | } |
| 576 | 637 | ||
| 577 | static Rect clip_rect(const Rect &r, const Rect &clip) { | 638 | static Rect clip_rect(const Rect &r, const Rect &clip) { |
| @@ -640,13 +701,48 @@ static void layout() { | |||
| 640 | if (g_win_y + g_win_h > h) g_win_y = h - g_win_h; | 701 | if (g_win_y + g_win_h > h) g_win_y = h - g_win_h; |
| 641 | } | 702 | } |
| 642 | 703 | ||
| 704 | static int card_content_w() { return g_win_w - S(190.0f) - S(28.0f); } | ||
| 705 | |||
| 706 | static int title_max_w() { return card_content_w() - S(210.0f); } | ||
| 707 | |||
| 708 | static int header_h(const Card &c) { | ||
| 709 | int n = wrap_count(c.title, title_max_w(), g_title_h); | ||
| 710 | if (n < 1) | ||
| 711 | n = 1; | ||
| 712 | int h = n * (g_title_h + S(2.0f)) + S(12.0f); | ||
| 713 | return h < S(36.0f) ? S(36.0f) : h; | ||
| 714 | } | ||
| 715 | |||
| 716 | static int label_max_w(const Ctrl &c) { | ||
| 717 | if (c.kind == CK_SLIDER) | ||
| 718 | return S(214.0f); | ||
| 719 | return card_content_w() - S(16.0f) - S(110.0f); | ||
| 720 | } | ||
| 721 | |||
| 722 | static int button_w(const char *label) { | ||
| 723 | int bw = text_w(label, g_body_h) + S(20.0f); | ||
| 724 | if (bw < S(160.0f)) | ||
| 725 | bw = S(160.0f); | ||
| 726 | int maxw = card_content_w() - S(24.0f); | ||
| 727 | if (bw > maxw) | ||
| 728 | bw = maxw; | ||
| 729 | return bw; | ||
| 730 | } | ||
| 731 | |||
| 643 | static int row_h(const Ctrl &c) { | 732 | static int row_h(const Ctrl &c) { |
| 644 | switch (c.kind) { | 733 | if (c.kind == CK_BUTTON) |
| 645 | case CK_SECTION: return S(24.0f); | 734 | return S(32.0f); |
| 646 | case CK_INFO: return S(20.0f); | 735 | int maxw = (c.kind == CK_INFO || c.kind == CK_SECTION) |
| 647 | case CK_BUTTON: return S(32.0f); | 736 | ? card_content_w() - S(24.0f) |
| 648 | default: return S(27.0f); | 737 | : label_max_w(c); |
| 649 | } | 738 | int n = wrap_count(c.label, maxw, g_body_h); |
| 739 | if (n < 1) | ||
| 740 | n = 1; | ||
| 741 | int h = n * (g_body_h + S(2.0f)) + S(8.0f); | ||
| 742 | int minh = (c.kind == CK_INFO) ? S(20.0f) | ||
| 743 | : (c.kind == CK_SECTION) ? S(24.0f) | ||
| 744 | : S(27.0f); | ||
| 745 | return h < minh ? minh : h; | ||
| 650 | } | 746 | } |
| 651 | 747 | ||
| 652 | static int body_h(const Card &c) { | 748 | static int body_h(const Card &c) { |
| @@ -658,7 +754,7 @@ static int body_h(const Card &c) { | |||
| 658 | return h + S(6.0f); | 754 | return h + S(6.0f); |
| 659 | } | 755 | } |
| 660 | 756 | ||
| 661 | static int card_h(const Card &c) { return S(36.0f) + body_h(c) + S(8.0f); } | 757 | static int card_h(const Card &c) { return header_h(c) + body_h(c) + S(8.0f); } |
| 662 | 758 | ||
| 663 | static Rect card_rect(int index, int y) { | 759 | static Rect card_rect(int index, int y) { |
| 664 | Card &c = g_cards[index]; | 760 | Card &c = g_cards[index]; |
| @@ -866,14 +962,15 @@ static void handle_mouse_click() { | |||
| 866 | Card &c = g_cards[i]; | 962 | Card &c = g_cards[i]; |
| 867 | Rect cr = card_rect(i, y); | 963 | Rect cr = card_rect(i, y); |
| 868 | int ch = card_h(c); | 964 | int ch = card_h(c); |
| 965 | int hh = header_h(c); | ||
| 869 | if (my >= cr.y && my < cr.y + ch) { | 966 | if (my >= cr.y && my < cr.y + ch) { |
| 870 | // header | 967 | // header |
| 871 | if (my < cr.y + S(36.0f)) { | 968 | if (my < cr.y + hh) { |
| 872 | if (c.feat) { | 969 | if (c.feat) { |
| 873 | Rect active{cr.x + cr.w - S(170.0f), cr.y + S(9.0f), S(18.0f), | 970 | Rect active{cr.x + cr.w - S(170.0f), |
| 874 | S(18.0f)}; | 971 | cr.y + (hh - S(18.0f)) / 2, S(18.0f), S(18.0f)}; |
| 875 | Rect bind{cr.x + cr.w - S(112.0f), cr.y + S(7.0f), S(100.0f), | 972 | Rect bind{cr.x + cr.w - S(112.0f), |
| 876 | S(22.0f)}; | 973 | cr.y + (hh - S(22.0f)) / 2, S(100.0f), S(22.0f)}; |
| 877 | if (active.has(mx, my)) { | 974 | if (active.has(mx, my)) { |
| 878 | c.feat->active = !c.feat->active; | 975 | c.feat->active = !c.feat->active; |
| 879 | config_save(); | 976 | config_save(); |
| @@ -895,7 +992,7 @@ static void handle_mouse_click() { | |||
| 895 | return; | 992 | return; |
| 896 | } | 993 | } |
| 897 | // body | 994 | // body |
| 898 | int by = cr.y + S(36.0f) + S(6.0f); | 995 | int by = cr.y + hh + S(6.0f); |
| 899 | for (int j = 0; j < c.n; j++) { | 996 | for (int j = 0; j < c.n; j++) { |
| 900 | Ctrl &ct = g_ctrls[c.c0 + j]; | 997 | Ctrl &ct = g_ctrls[c.c0 + j]; |
| 901 | int rh = row_h(ct); | 998 | int rh = row_h(ct); |
| @@ -908,7 +1005,8 @@ static void handle_mouse_click() { | |||
| 908 | return; | 1005 | return; |
| 909 | } | 1006 | } |
| 910 | if (ct.kind == CK_SLIDER) { | 1007 | if (ct.kind == CK_SLIDER) { |
| 911 | Rect track{cr.x + S(16.0f) + S(230.0f), by + S(9.0f), | 1008 | Rect track{cr.x + S(16.0f) + S(230.0f), |
| 1009 | by + (rh - S(8.0f)) / 2, | ||
| 912 | cr.w - S(16.0f) - S(230.0f) - S(64.0f), S(8.0f)}; | 1010 | cr.w - S(16.0f) - S(230.0f) - S(64.0f), S(8.0f)}; |
| 913 | if (mx >= track.x && mx < track.x + track.w) { | 1011 | if (mx >= track.x && mx < track.x + track.w) { |
| 914 | float t = (float)(mx - track.x) / (float)track.w; | 1012 | float t = (float)(mx - track.x) / (float)track.w; |
| @@ -921,8 +1019,9 @@ static void handle_mouse_click() { | |||
| 921 | return; | 1019 | return; |
| 922 | } | 1020 | } |
| 923 | if (ct.kind == CK_BUTTON) { | 1021 | if (ct.kind == CK_BUTTON) { |
| 924 | Rect b{cr.x + cr.w - S(176.0f), by + S(3.0f), S(160.0f), | 1022 | int bw = button_w(ct.label); |
| 925 | S(26.0f)}; | 1023 | Rect b{cr.x + cr.w - S(16.0f) - bw, |
| 1024 | by + (rh - S(26.0f)) / 2, bw, S(26.0f)}; | ||
| 926 | if (b.has(mx, my)) { | 1025 | if (b.has(mx, my)) { |
| 927 | if (ct.action == ACT_RELOAD) { | 1026 | if (ct.action == ACT_RELOAD) { |
| 928 | config_reload(); | 1027 | config_reload(); |
| @@ -964,13 +1063,14 @@ static void handle_hover() { | |||
| 964 | Card &c = g_cards[i]; | 1063 | Card &c = g_cards[i]; |
| 965 | Rect cr = card_rect(i, y); | 1064 | Rect cr = card_rect(i, y); |
| 966 | int ch = card_h(c); | 1065 | int ch = card_h(c); |
| 1066 | int hh = header_h(c); | ||
| 967 | if (my >= cr.y && my < cr.y + ch) { | 1067 | if (my >= cr.y && my < cr.y + ch) { |
| 968 | if (my < cr.y + S(36.0f)) { | 1068 | if (my < cr.y + hh) { |
| 969 | if (c.feat) { | 1069 | if (c.feat) { |
| 970 | Rect active{cr.x + cr.w - S(170.0f), cr.y + S(9.0f), S(18.0f), | 1070 | Rect active{cr.x + cr.w - S(170.0f), |
| 971 | S(18.0f)}; | 1071 | cr.y + (hh - S(18.0f)) / 2, S(18.0f), S(18.0f)}; |
| 972 | Rect bind{cr.x + cr.w - S(112.0f), cr.y + S(7.0f), S(100.0f), | 1072 | Rect bind{cr.x + cr.w - S(112.0f), |
| 973 | S(22.0f)}; | 1073 | cr.y + (hh - S(22.0f)) / 2, S(100.0f), S(22.0f)}; |
| 974 | if (active.has(mx, my)) | 1074 | if (active.has(mx, my)) |
| 975 | g_hover_desc = "Enable this feature. A bind, when set, must be " | 1075 | g_hover_desc = "Enable this feature. A bind, when set, must be " |
| 976 | "held for it to run."; | 1076 | "held for it to run."; |
| @@ -987,7 +1087,7 @@ static void handle_hover() { | |||
| 987 | } | 1087 | } |
| 988 | return; | 1088 | return; |
| 989 | } | 1089 | } |
| 990 | int by = cr.y + S(36.0f) + S(6.0f); | 1090 | int by = cr.y + hh + S(6.0f); |
| 991 | for (int j = 0; j < c.n; j++) { | 1091 | for (int j = 0; j < c.n; j++) { |
| 992 | Ctrl &ct = g_ctrls[c.c0 + j]; | 1092 | Ctrl &ct = g_ctrls[c.c0 + j]; |
| 993 | int rh = row_h(ct); | 1093 | int rh = row_h(ct); |
| @@ -1165,11 +1265,13 @@ static void draw_checkbox(int x, int y, bool on) { | |||
| 1165 | } | 1265 | } |
| 1166 | } | 1266 | } |
| 1167 | 1267 | ||
| 1168 | static void draw_slider(const Rect &clip, const Rect &cr, int y, const Ctrl &ct) { | 1268 | static void draw_slider(const Rect &clip, const Rect &cr, int y, int rh, |
| 1269 | const Ctrl &ct) { | ||
| 1169 | int track_x = cr.x + S(16.0f) + S(230.0f); | 1270 | int track_x = cr.x + S(16.0f) + S(230.0f); |
| 1170 | int track_w = cr.w - S(16.0f) - S(230.0f) - S(64.0f); | 1271 | int track_w = cr.w - S(16.0f) - S(230.0f) - S(64.0f); |
| 1171 | if (track_w < S(30.0f)) track_w = S(30.0f); | 1272 | if (track_w < S(30.0f)) track_w = S(30.0f); |
| 1172 | Rect track{track_x, y + S(9.0f), track_w, S(8.0f)}; | 1273 | int track_y = y + (rh - S(8.0f)) / 2; |
| 1274 | Rect track{track_x, track_y, track_w, S(8.0f)}; | ||
| 1173 | fill(track, Col{38, 42, 50, 255}, &clip); | 1275 | fill(track, Col{38, 42, 50, 255}, &clip); |
| 1174 | int value = ctrl_val(ct); | 1276 | int value = ctrl_val(ct); |
| 1175 | float t = (ct.max > ct.min) | 1277 | float t = (ct.max > ct.min) |
| @@ -1181,8 +1283,8 @@ static void draw_slider(const Rect &clip, const Rect &cr, int y, const Ctrl &ct) | |||
| 1181 | fill(Rect{kx, track.y - S(4.0f), S(8.0f), S(16.0f)}, C_ACCENT, &clip); | 1283 | fill(Rect{kx, track.y - S(4.0f), S(8.0f), S(16.0f)}, C_ACCENT, &clip); |
| 1182 | char val[32]; | 1284 | char val[32]; |
| 1183 | snprintf(val, sizeof(val), "%d", value); | 1285 | snprintf(val, sizeof(val), "%d", value); |
| 1184 | text_in(clip, cr.x + cr.w - S(52.0f), y + S(4.0f), val, g_font_body, g_body_h, | 1286 | text_in(clip, cr.x + cr.w - S(52.0f), y + (rh - g_body_h) / 2, val, |
| 1185 | S(44.0f), C_TEXT); | 1287 | g_font_body, g_body_h, 0, C_TEXT); |
| 1186 | } | 1288 | } |
| 1187 | 1289 | ||
| 1188 | static void draw_card(const Rect &clip, int index, int y) { | 1290 | static void draw_card(const Rect &clip, int index, int y) { |
| @@ -1193,10 +1295,12 @@ static void draw_card(const Rect &clip, int index, int y) { | |||
| 1193 | return; | 1295 | return; |
| 1194 | fill(cr, C_PANEL, &clip); | 1296 | fill(cr, C_PANEL, &clip); |
| 1195 | outline(cr, Col{52, 57, 67, 255}, &clip); | 1297 | outline(cr, Col{52, 57, 67, 255}, &clip); |
| 1196 | Rect head{cr.x, cr.y, cr.w, S(36.0f)}; | 1298 | int hh = header_h(c); |
| 1299 | Rect head{cr.x, cr.y, cr.w, hh}; | ||
| 1197 | fill(head, C_HEADER, &clip); | 1300 | fill(head, C_HEADER, &clip); |
| 1301 | |||
| 1198 | // expand arrow | 1302 | // expand arrow |
| 1199 | int ax = cr.x + S(10.0f), ay = cr.y + S(13.0f); | 1303 | int ax = cr.x + S(10.0f), ay = cr.y + (hh - S(8.0f)) / 2; |
| 1200 | if (c.expanded) { | 1304 | if (c.expanded) { |
| 1201 | line(ax, ay, ax + S(4.0f), ay + S(5.0f), C_DIM); | 1305 | line(ax, ay, ax + S(4.0f), ay + S(5.0f), C_DIM); |
| 1202 | line(ax + S(4.0f), ay + S(5.0f), ax + S(8.0f), ay, C_DIM); | 1306 | line(ax + S(4.0f), ay + S(5.0f), ax + S(8.0f), ay, C_DIM); |
| @@ -1204,40 +1308,53 @@ static void draw_card(const Rect &clip, int index, int y) { | |||
| 1204 | line(ax, ay, ax + S(5.0f), ay + S(4.0f), C_DIM); | 1308 | line(ax, ay, ax + S(5.0f), ay + S(4.0f), C_DIM); |
| 1205 | line(ax + S(5.0f), ay + S(4.0f), ax, ay + S(8.0f), C_DIM); | 1309 | line(ax + S(5.0f), ay + S(4.0f), ax, ay + S(8.0f), C_DIM); |
| 1206 | } | 1310 | } |
| 1207 | text_in(clip, cr.x + S(24.0f), cr.y + S(8.0f), c.title, g_font_title, | 1311 | |
| 1208 | g_title_h, cr.w - S(180.0f), C_TEXT); | 1312 | // title (wraps instead of truncating) |
| 1313 | std::vector<std::string> title_lines; | ||
| 1314 | wrap_text(c.title, title_max_w(), g_title_h, title_lines); | ||
| 1315 | int tlh = g_title_h + S(2.0f); | ||
| 1316 | int title_h = (int)title_lines.size() * tlh - S(2.0f); | ||
| 1317 | int ty = cr.y + (hh - title_h) / 2; | ||
| 1318 | draw_wrapped(clip, cr.x + S(24.0f), ty, c.title, g_font_title, g_title_h, | ||
| 1319 | title_max_w(), C_TEXT, S(2.0f)); | ||
| 1320 | |||
| 1209 | if (c.feat) { | 1321 | if (c.feat) { |
| 1210 | bool active = c.feat->active; | 1322 | bool active = c.feat->active; |
| 1211 | draw_checkbox(cr.x + cr.w - S(170.0f), cr.y + S(10.0f), active); | 1323 | int active_y = cr.y + (hh - S(18.0f)) / 2; |
| 1212 | text_in(clip, cr.x + cr.w - S(148.0f), cr.y + S(9.0f), | 1324 | draw_checkbox(cr.x + cr.w - S(170.0f), active_y, active); |
| 1213 | active ? "On" : "Off", g_font_body, g_body_h, S(32.0f), | 1325 | text_in(clip, cr.x + cr.w - S(148.0f), |
| 1214 | active ? C_GOOD : C_DIM); | 1326 | active_y + (S(18.0f) - g_body_h) / 2, active ? "On" : "Off", |
| 1215 | Rect bind{cr.x + cr.w - S(112.0f), cr.y + S(7.0f), S(100.0f), S(22.0f)}; | 1327 | g_font_body, g_body_h, 0, active ? C_GOOD : C_DIM); |
| 1328 | Rect bind{cr.x + cr.w - S(112.0f), cr.y + (hh - S(22.0f)) / 2, S(100.0f), | ||
| 1329 | S(22.0f)}; | ||
| 1216 | fill(bind, Col{45, 50, 60, 255}, &clip); | 1330 | fill(bind, Col{45, 50, 60, 255}, &clip); |
| 1217 | outline(bind, C_BORDER, &clip); | 1331 | outline(bind, C_BORDER, &clip); |
| 1218 | const char *bl = (g_capture_card == index) | 1332 | const char *bl = (g_capture_card == index) |
| 1219 | ? "Press..." | 1333 | ? "Press..." |
| 1220 | : scancode_name(c.feat->bind); | 1334 | : scancode_name(c.feat->bind); |
| 1221 | text_in(clip, bind.x + S(7.0f), bind.y + S(3.0f), bl, g_font_body, g_body_h, | 1335 | text_in(clip, bind.x + S(7.0f), bind.y + (bind.h - g_body_h) / 2, bl, |
| 1222 | bind.w - S(22.0f), C_TEXT); | 1336 | g_font_body, g_body_h, 0, C_TEXT); |
| 1223 | text_in(clip, bind.x + bind.w - S(16.0f), bind.y + S(3.0f), "x", | 1337 | text_in(clip, bind.x + bind.w - S(16.0f), |
| 1224 | g_font_body, g_body_h, S(10.0f), C_DIM); | 1338 | bind.y + (bind.h - g_body_h) / 2, "x", g_font_body, g_body_h, 0, |
| 1339 | C_DIM); | ||
| 1225 | } | 1340 | } |
| 1226 | if (!c.expanded) | 1341 | if (!c.expanded) |
| 1227 | return; | 1342 | return; |
| 1228 | 1343 | ||
| 1229 | int by = cr.y + S(36.0f) + S(6.0f); | 1344 | int by = cr.y + hh + S(6.0f); |
| 1230 | for (int j = 0; j < c.n; j++) { | 1345 | for (int j = 0; j < c.n; j++) { |
| 1231 | Ctrl &ct = g_ctrls[c.c0 + j]; | 1346 | Ctrl &ct = g_ctrls[c.c0 + j]; |
| 1232 | int rh = row_h(ct); | 1347 | int rh = row_h(ct); |
| 1233 | if (ct.kind == CK_SECTION) { | 1348 | if (ct.kind == CK_SECTION) { |
| 1234 | text_in(clip, cr.x + S(16.0f), by + S(3.0f), ct.label, g_font_body, | 1349 | draw_wrapped(clip, cr.x + S(16.0f), by + S(3.0f), ct.label, g_font_body, |
| 1235 | g_body_h, cr.w - S(24.0f), C_ACCENT); | 1350 | g_body_h, card_content_w() - S(24.0f), C_ACCENT, S(2.0f)); |
| 1236 | } else if (ct.kind == CK_INFO) { | 1351 | } else if (ct.kind == CK_INFO) { |
| 1237 | text_in(clip, cr.x + S(16.0f), by + S(1.0f), ct.label, g_font_body, | 1352 | draw_wrapped(clip, cr.x + S(16.0f), by + S(3.0f), ct.label, g_font_body, |
| 1238 | g_body_h, cr.w - S(24.0f), C_DIM); | 1353 | g_body_h, card_content_w() - S(24.0f), C_DIM, S(2.0f)); |
| 1239 | } else if (ct.kind == CK_BUTTON) { | 1354 | } else if (ct.kind == CK_BUTTON) { |
| 1240 | Rect b{cr.x + cr.w - S(176.0f), by + S(3.0f), S(160.0f), S(26.0f)}; | 1355 | int bw = button_w(ct.label); |
| 1356 | Rect b{cr.x + cr.w - S(16.0f) - bw, by + (rh - S(26.0f)) / 2, bw, | ||
| 1357 | S(26.0f)}; | ||
| 1241 | fill(b, Col{45, 50, 60, 255}, &clip); | 1358 | fill(b, Col{45, 50, 60, 255}, &clip); |
| 1242 | outline(b, C_BORDER, &clip); | 1359 | outline(b, C_BORDER, &clip); |
| 1243 | const char *label = ct.label; | 1360 | const char *label = ct.label; |
| @@ -1247,19 +1364,25 @@ static void draw_card(const Rect &clip, int index, int y) { | |||
| 1247 | else | 1364 | else |
| 1248 | label = "Confirm reset"; | 1365 | label = "Confirm reset"; |
| 1249 | } | 1366 | } |
| 1250 | text_in(clip, b.x + S(10.0f), b.y + S(4.0f), label, g_font_body, | 1367 | text_in(clip, b.x + S(10.0f), b.y + (b.h - g_body_h) / 2, label, |
| 1251 | g_body_h, b.w - S(16.0f), C_TEXT); | 1368 | g_font_body, g_body_h, 0, C_TEXT); |
| 1252 | } else { | 1369 | } else { |
| 1253 | text_in(clip, cr.x + S(16.0f), by + S(4.0f), ct.label, g_font_body, | 1370 | int maxw = label_max_w(ct); |
| 1254 | g_body_h, S(220.0f), C_TEXT); | 1371 | std::vector<std::string> lines; |
| 1372 | wrap_text(ct.label, maxw, g_body_h, lines); | ||
| 1373 | int lh = g_body_h + S(2.0f); | ||
| 1374 | int text_h = (int)lines.size() * lh - S(2.0f); | ||
| 1375 | int ly = by + (rh - text_h) / 2; | ||
| 1376 | draw_wrapped(clip, cr.x + S(16.0f), ly, ct.label, g_font_body, g_body_h, | ||
| 1377 | maxw, C_TEXT, S(2.0f)); | ||
| 1255 | if (ct.kind == CK_TOGGLE) { | 1378 | if (ct.kind == CK_TOGGLE) { |
| 1256 | bool on = ctrl_val(ct) != 0; | 1379 | bool on = ctrl_val(ct) != 0; |
| 1257 | draw_checkbox(cr.x + cr.w - S(31.0f), by + S(5.0f), on); | 1380 | draw_checkbox(cr.x + cr.w - S(31.0f), by + (rh - S(15.0f)) / 2, on); |
| 1258 | text_in(clip, cr.x + cr.w - S(58.0f), by + S(3.0f), | 1381 | text_in(clip, cr.x + cr.w - S(58.0f), by + (rh - g_body_h) / 2, |
| 1259 | on ? "On" : "Off", g_font_body, g_body_h, S(26.0f), | 1382 | on ? "On" : "Off", g_font_body, g_body_h, 0, |
| 1260 | on ? C_GOOD : C_DIM); | 1383 | on ? C_GOOD : C_DIM); |
| 1261 | } else if (ct.kind == CK_SLIDER) { | 1384 | } else if (ct.kind == CK_SLIDER) { |
| 1262 | draw_slider(clip, cr, by, ct); | 1385 | draw_slider(clip, cr, by, rh, ct); |
| 1263 | } | 1386 | } |
| 1264 | } | 1387 | } |
| 1265 | by += rh; | 1388 | by += rh; |
| @@ -1272,94 +1395,46 @@ static void draw_tooltip() { | |||
| 1272 | float d = now_sec() - (float)g_hover_since; | 1395 | float d = now_sec() - (float)g_hover_since; |
| 1273 | if (d < 0.4f) | 1396 | if (d < 0.4f) |
| 1274 | return; | 1397 | return; |
| 1275 | int tw = text_w(g_hover_desc, g_body_h) + S(16.0f); | ||
| 1276 | int maxw = S(380.0f); | 1398 | int maxw = S(380.0f); |
| 1277 | if (tw > maxw) tw = maxw; | 1399 | if (maxw > g_scr_w - S(32.0f)) |
| 1278 | int th = g_body_h + S(14.0f); | 1400 | maxw = g_scr_w - S(32.0f); |
| 1401 | std::vector<std::string> lines; | ||
| 1402 | wrap_text(g_hover_desc, maxw, g_body_h, lines); | ||
| 1403 | if (lines.empty()) | ||
| 1404 | return; | ||
| 1405 | int line_w = 0; | ||
| 1406 | for (auto &line : lines) { | ||
| 1407 | int w = text_w(line.c_str(), g_body_h); | ||
| 1408 | if (w > line_w) | ||
| 1409 | line_w = w; | ||
| 1410 | } | ||
| 1411 | int line_h = g_body_h + S(3.0f); | ||
| 1412 | int tw = line_w + S(16.0f); | ||
| 1413 | int th = (int)lines.size() * line_h + S(12.0f) - S(3.0f); | ||
| 1279 | int x = g_hover_x + S(14.0f); | 1414 | int x = g_hover_x + S(14.0f); |
| 1280 | int y = g_hover_y + S(16.0f); | 1415 | int y = g_hover_y + S(16.0f); |
| 1281 | if (x + tw > g_scr_w - S(4.0f)) x = g_hover_x - tw - S(10.0f); | 1416 | if (x + tw > g_scr_w - S(4.0f)) |
| 1282 | if (y + th > g_scr_h - S(4.0f)) y = g_hover_y - th - S(10.0f); | 1417 | x = g_hover_x - tw - S(10.0f); |
| 1418 | if (y + th > g_scr_h - S(4.0f)) | ||
| 1419 | y = g_hover_y - th - S(10.0f); | ||
| 1420 | if (x < S(4.0f)) | ||
| 1421 | x = S(4.0f); | ||
| 1422 | if (y < S(4.0f)) | ||
| 1423 | y = S(4.0f); | ||
| 1283 | Rect r{x, y, tw, th}; | 1424 | Rect r{x, y, tw, th}; |
| 1284 | fill(r, Col{12, 14, 18, 248}); | 1425 | fill(r, Col{12, 14, 18, 248}); |
| 1285 | outline(r, C_ACCENT_DIM); | 1426 | outline(r, C_ACCENT_DIM); |
| 1286 | Rect inner{x + S(7.0f), y + S(6.0f), tw - S(14.0f), g_body_h}; | 1427 | s_text_font(g_font_body); |
| 1287 | text_in(inner, inner.x, inner.y, g_hover_desc, g_font_body, g_body_h, | 1428 | s_text_color(C_TEXT.r, C_TEXT.g, C_TEXT.b, C_TEXT.a); |
| 1288 | inner.w, C_TEXT); | 1429 | for (size_t i = 0; i < lines.size(); i++) |
| 1430 | draw_text_raw(x + S(7.0f), y + S(6.0f) + (int)i * line_h, | ||
| 1431 | lines[i].c_str(), g_font_body, g_body_h); | ||
| 1289 | } | 1432 | } |
| 1290 | 1433 | ||
| 1291 | // --------------------------------------------------------------------------- | 1434 | // --------------------------------------------------------------------------- |
| 1292 | // Toast drawing | 1435 | // Toast drawing |
| 1293 | // --------------------------------------------------------------------------- | 1436 | // --------------------------------------------------------------------------- |
| 1294 | 1437 | ||
| 1295 | static int wrap_toast(const char *text, int max_w, int tall, | ||
| 1296 | char lines[][256], int max_lines) { | ||
| 1297 | int n = 0; | ||
| 1298 | char cur[256] = {}; | ||
| 1299 | bool truncated = false; | ||
| 1300 | const char *p = text; | ||
| 1301 | while (*p) { | ||
| 1302 | while (*p == ' ') | ||
| 1303 | p++; | ||
| 1304 | if (!*p) | ||
| 1305 | break; | ||
| 1306 | const char *start = p; | ||
| 1307 | while (*p && *p != ' ') | ||
| 1308 | p++; | ||
| 1309 | size_t wl = (size_t)(p - start); | ||
| 1310 | if (wl > 120) | ||
| 1311 | wl = 120; | ||
| 1312 | char word[128]; | ||
| 1313 | memcpy(word, start, wl); | ||
| 1314 | word[wl] = 0; | ||
| 1315 | |||
| 1316 | char cand[256]; | ||
| 1317 | if (cur[0]) | ||
| 1318 | snprintf(cand, sizeof(cand), "%s %s", cur, word); | ||
| 1319 | else | ||
| 1320 | snprintf(cand, sizeof(cand), "%s", word); | ||
| 1321 | |||
| 1322 | if (text_w(cand, tall) <= max_w || !cur[0]) { | ||
| 1323 | snprintf(cur, sizeof(cur), "%s", cand); | ||
| 1324 | if (text_w(cur, tall) > max_w) { | ||
| 1325 | // A single word longer than the panel: hard-truncate it. | ||
| 1326 | int len = (int)strlen(cur); | ||
| 1327 | while (len > 3 && text_w(cur, tall) > max_w) | ||
| 1328 | cur[--len] = 0; | ||
| 1329 | if (len > 3) { | ||
| 1330 | cur[len - 3] = '.'; | ||
| 1331 | cur[len - 2] = '.'; | ||
| 1332 | cur[len - 1] = '.'; | ||
| 1333 | } | ||
| 1334 | truncated = true; | ||
| 1335 | } | ||
| 1336 | } else { | ||
| 1337 | if (n < max_lines) | ||
| 1338 | snprintf(lines[n++], 256, "%s", cur); | ||
| 1339 | else | ||
| 1340 | truncated = true; | ||
| 1341 | snprintf(cur, sizeof(cur), "%s", word); | ||
| 1342 | } | ||
| 1343 | } | ||
| 1344 | if (cur[0]) { | ||
| 1345 | if (n < max_lines) | ||
| 1346 | snprintf(lines[n++], 256, "%s", cur); | ||
| 1347 | else | ||
| 1348 | truncated = true; | ||
| 1349 | } | ||
| 1350 | if (truncated && n > 0) { | ||
| 1351 | char *last = lines[n - 1]; | ||
| 1352 | int len = (int)strlen(last); | ||
| 1353 | if (len + 3 < 256) { | ||
| 1354 | last[len++] = '.'; | ||
| 1355 | last[len++] = '.'; | ||
| 1356 | last[len++] = '.'; | ||
| 1357 | last[len] = 0; | ||
| 1358 | } | ||
| 1359 | } | ||
| 1360 | return n; | ||
| 1361 | } | ||
| 1362 | |||
| 1363 | void gui_draw_toasts() { | 1438 | void gui_draw_toasts() { |
| 1364 | if (!g_surface) | 1439 | if (!g_surface) |
| 1365 | return; | 1440 | return; |
| @@ -1401,13 +1476,14 @@ void gui_draw_toasts() { | |||
| 1401 | if (a > 1.0f) a = 1.0f; | 1476 | if (a > 1.0f) a = 1.0f; |
| 1402 | int alpha = (int)(a * 255.0f); | 1477 | int alpha = (int)(a * 255.0f); |
| 1403 | 1478 | ||
| 1404 | char lines[4][256]; | 1479 | std::vector<std::string> lines; |
| 1405 | int nl = wrap_toast(t.text, max_w, g_body_h, lines, 4); | 1480 | wrap_text(t.text, max_w, g_body_h, lines); |
| 1481 | int nl = (int)lines.size(); | ||
| 1406 | if (nl == 0) | 1482 | if (nl == 0) |
| 1407 | continue; | 1483 | continue; |
| 1408 | int line_w = 0; | 1484 | int line_w = 0; |
| 1409 | for (int j = 0; j < nl; j++) { | 1485 | for (int j = 0; j < nl; j++) { |
| 1410 | int w = text_w(lines[j], g_body_h); | 1486 | int w = text_w(lines[j].c_str(), g_body_h); |
| 1411 | if (w > line_w) | 1487 | if (w > line_w) |
| 1412 | line_w = w; | 1488 | line_w = w; |
| 1413 | } | 1489 | } |
| @@ -1432,7 +1508,7 @@ void gui_draw_toasts() { | |||
| 1432 | for (int j = 0; j < nl; j++) { | 1508 | for (int j = 0; j < nl; j++) { |
| 1433 | s_text_pos(x + pad + S(6.0f), y + pad + j * line_h); | 1509 | s_text_pos(x + pad + S(6.0f), y + pad + j * line_h); |
| 1434 | wchar_t w[256]; | 1510 | wchar_t w[256]; |
| 1435 | size_t wn = mbstowcs(w, lines[j], 255); | 1511 | size_t wn = mbstowcs(w, lines[j].c_str(), 255); |
| 1436 | if (wn == (size_t)-1) | 1512 | if (wn == (size_t)-1) |
| 1437 | continue; | 1513 | continue; |
| 1438 | w[wn] = 0; | 1514 | w[wn] = 0; |
| @@ -1515,15 +1591,10 @@ void gui_draw() { | |||
| 1515 | g_capture_card >= 0 ? "press a key / Esc" : "INS close"; | 1591 | g_capture_card >= 0 ? "press a key / Esc" : "INS close"; |
| 1516 | int hint_w = text_w(hint, g_body_h); | 1592 | int hint_w = text_w(hint, g_body_h); |
| 1517 | int hint_x = foot.x + foot.w - hint_w - S(12.0f); | 1593 | int hint_x = foot.x + foot.w - hint_w - S(12.0f); |
| 1518 | int left_x = foot.x + S(12.0f); | 1594 | if (hint_x < foot.x + S(12.0f)) |
| 1519 | if (hint_x < left_x) | 1595 | hint_x = foot.x + S(12.0f); |
| 1520 | hint_x = left_x; | 1596 | text_in(foot, hint_x, foot.y + S(6.0f), hint, g_font_body, g_body_h, 0, |
| 1521 | int left_max = hint_x - left_x - S(12.0f); | 1597 | C_DIM); |
| 1522 | if (left_max > 0) | ||
| 1523 | text_in(foot, left_x, foot.y + S(6.0f), g_config_label, g_font_body, | ||
| 1524 | g_body_h, left_max, C_DIM); | ||
| 1525 | text_in(foot, hint_x, foot.y + S(6.0f), hint, g_font_body, g_body_h, | ||
| 1526 | hint_w + S(4.0f), C_DIM); | ||
| 1527 | 1598 | ||
| 1528 | draw_tooltip(); | 1599 | draw_tooltip(); |
| 1529 | } | 1600 | } |
