diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-03 23:26:50 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-03 23:26:50 +0100 |
| commit | a1a8281a6f72ee7f1bcedf442f6ade48da8ffef4 (patch) | |
| tree | 07a55046e125b752047da22abe65258feeada5e8 /src/gui.cpp | |
| parent | World: add world/sky material colour modulation (diff) | |
| download | hl2h-a1a8281a6f72ee7f1bcedf442f6ade48da8ffef4.tar.gz hl2h-a1a8281a6f72ee7f1bcedf442f6ade48da8ffef4.zip | |
GUI: add inline colour picker control
Replace the six RGB sliders on the World tint card with a CK_COLOR control:
each row shows a live swatch and expands an inline picker with a
saturation/value square, a hue bar, and hex/RGB preview. The picker grows the
card in place so it scrolls/clips like any other row, keeps HSV state while
open (grey does not lose its hue), writes the shared 0-255 RGB triple used by
the config, and saves on mouse release.
Costs ~1.2k small rects per frame only while a picker is open; no texture
interface needed.
Diffstat (limited to 'src/gui.cpp')
| -rw-r--r-- | src/gui.cpp | 326 |
1 files changed, 312 insertions, 14 deletions
diff --git a/src/gui.cpp b/src/gui.cpp index 9d27a09..9981f25 100644 --- a/src/gui.cpp +++ b/src/gui.cpp | |||
| @@ -182,7 +182,8 @@ enum CtrlKind { | |||
| 182 | CK_BIND, | 182 | CK_BIND, |
| 183 | CK_SECTION, | 183 | CK_SECTION, |
| 184 | CK_INFO, | 184 | CK_INFO, |
| 185 | CK_BUTTON | 185 | CK_BUTTON, |
| 186 | CK_COLOR | ||
| 186 | }; | 187 | }; |
| 187 | 188 | ||
| 188 | enum CtrlAction { ACT_NONE = 0, ACT_RELOAD, ACT_RESET }; | 189 | enum CtrlAction { ACT_NONE = 0, ACT_RELOAD, ACT_RESET }; |
| @@ -193,9 +194,13 @@ struct Ctrl { | |||
| 193 | const char *desc; | 194 | const char *desc; |
| 194 | bool *bval; // CK_TOGGLE | 195 | bool *bval; // CK_TOGGLE |
| 195 | int *ival; // CK_SLIDER | 196 | int *ival; // CK_SLIDER |
| 197 | int *rgb; // CK_COLOR: three ints, 0..255 | ||
| 196 | int min, max; | 198 | int min, max; |
| 197 | int action; // CK_BUTTON | 199 | int action; // CK_BUTTON |
| 198 | bool zero_unlimited; // slider: value 0 displays as "All" | 200 | bool zero_unlimited; // slider: value 0 displays as "All" |
| 201 | // CK_COLOR picker state, kept while the picker is open so grey colours do | ||
| 202 | // not lose their hue when the user drags value/saturation. | ||
| 203 | float hue, sat, val; | ||
| 199 | }; | 204 | }; |
| 200 | 205 | ||
| 201 | struct Card { | 206 | struct Card { |
| @@ -247,6 +252,10 @@ static void add_ctrl(int card, int kind, const char *label, const char *desc, | |||
| 247 | c.max = max; | 252 | c.max = max; |
| 248 | c.action = action; | 253 | c.action = action; |
| 249 | c.zero_unlimited = false; | 254 | c.zero_unlimited = false; |
| 255 | c.rgb = nullptr; | ||
| 256 | c.hue = 0.0f; | ||
| 257 | c.sat = 0.0f; | ||
| 258 | c.val = 1.0f; | ||
| 250 | g_cards[card].n++; | 259 | g_cards[card].n++; |
| 251 | } | 260 | } |
| 252 | static void add_toggle(int card, const char *label, const char *desc, | 261 | static void add_toggle(int card, const char *label, const char *desc, |
| @@ -267,6 +276,12 @@ static void add_button(int card, const char *label, const char *desc, | |||
| 267 | int action) { | 276 | int action) { |
| 268 | add_ctrl(card, CK_BUTTON, label, desc, 0, 0, nullptr, nullptr, action); | 277 | add_ctrl(card, CK_BUTTON, label, desc, 0, 0, nullptr, nullptr, action); |
| 269 | } | 278 | } |
| 279 | static void add_color(int card, const char *label, const char *desc, | ||
| 280 | int *rgb) { | ||
| 281 | int i = g_nctrl; | ||
| 282 | add_ctrl(card, CK_COLOR, label, desc, 0, 255, nullptr, nullptr, ACT_NONE); | ||
| 283 | g_ctrls[i].rgb = rgb; | ||
| 284 | } | ||
| 270 | 285 | ||
| 271 | static int ctrl_val(const Ctrl &c) { | 286 | static int ctrl_val(const Ctrl &c) { |
| 272 | if (c.kind == CK_TOGGLE && c.bval) | 287 | if (c.kind == CK_TOGGLE && c.bval) |
| @@ -381,19 +396,11 @@ static void build_cards() { | |||
| 381 | add_toggle(tint, "World brushes", | 396 | add_toggle(tint, "World brushes", |
| 382 | "Tint world textures (sky and water excluded from this part).", | 397 | "Tint world textures (sky and water excluded from this part).", |
| 383 | &g_tint_world_on); | 398 | &g_tint_world_on); |
| 384 | add_slider(tint, "World red", "Red channel of the world tint (0-255).", 0, | 399 | add_color(tint, "World colour", "Click the swatch to open the picker.", |
| 385 | 255, &g_tint_world_rgb[0]); | 400 | g_tint_world_rgb); |
| 386 | add_slider(tint, "World green", "Green channel of the world tint (0-255).", 0, | ||
| 387 | 255, &g_tint_world_rgb[1]); | ||
| 388 | add_slider(tint, "World blue", "Blue channel of the world tint (0-255).", 0, | ||
| 389 | 255, &g_tint_world_rgb[2]); | ||
| 390 | add_toggle(tint, "Skybox", "Tint the skybox textures.", &g_tint_sky_on); | 401 | add_toggle(tint, "Skybox", "Tint the skybox textures.", &g_tint_sky_on); |
| 391 | add_slider(tint, "Sky red", "Red channel of the sky tint (0-255).", 0, 255, | 402 | add_color(tint, "Sky colour", "Click the swatch to open the picker.", |
| 392 | &g_tint_sky_rgb[0]); | 403 | g_tint_sky_rgb); |
| 393 | add_slider(tint, "Sky green", "Green channel of the sky tint (0-255).", 0, | ||
| 394 | 255, &g_tint_sky_rgb[1]); | ||
| 395 | add_slider(tint, "Sky blue", "Blue channel of the sky tint (0-255).", 0, 255, | ||
| 396 | &g_tint_sky_rgb[2]); | ||
| 397 | 404 | ||
| 398 | int spread = add_card(3, &g_spread, "Spread control", | 405 | int spread = add_card(3, &g_spread, "Spread control", |
| 399 | "Choose a server shot seed that tightens the cone.", | 406 | "Choose a server shot seed that tightens the cone.", |
| @@ -436,6 +443,8 @@ static int g_scroll_drag_dy = 0; | |||
| 436 | static float g_scroll_drag_start = 0.0f; | 443 | static float g_scroll_drag_start = 0.0f; |
| 437 | static int g_hover_slider = -1; | 444 | static int g_hover_slider = -1; |
| 438 | static int g_slider_drag = -1; | 445 | static int g_slider_drag = -1; |
| 446 | static int g_picker_ctrl = -1; // CK_COLOR control with its picker expanded | ||
| 447 | static int g_picker_drag = 0; // 1 = SV square, 2 = hue bar | ||
| 439 | static int g_capture_card = -1; | 448 | static int g_capture_card = -1; |
| 440 | static QAngle g_frozen{0, 0, 0}; | 449 | static QAngle g_frozen{0, 0, 0}; |
| 441 | static int g_mouse_x = 0, g_mouse_y = 0; | 450 | static int g_mouse_x = 0, g_mouse_y = 0; |
| @@ -821,7 +830,40 @@ static int button_w(const char *label) { | |||
| 821 | return bw; | 830 | return bw; |
| 822 | } | 831 | } |
| 823 | 832 | ||
| 833 | static int label_row_h(const Ctrl &c); | ||
| 834 | static bool picker_open_for(const Ctrl &c); | ||
| 835 | static int picker_panel_h(); | ||
| 836 | static bool card_in_category(int i); | ||
| 837 | static Rect card_rect(int index, int y); | ||
| 838 | static int card_h(const Card &c); | ||
| 839 | |||
| 824 | static int row_h(const Ctrl &c) { | 840 | static int row_h(const Ctrl &c) { |
| 841 | int h = label_row_h(c); | ||
| 842 | if (picker_open_for(c)) | ||
| 843 | h += picker_panel_h(); | ||
| 844 | return h; | ||
| 845 | } | ||
| 846 | |||
| 847 | // --------------------------------------------------------------------------- | ||
| 848 | // Colour picker (CK_COLOR) | ||
| 849 | // --------------------------------------------------------------------------- | ||
| 850 | |||
| 851 | static constexpr int PICKER_SV_W = 180; | ||
| 852 | static constexpr int PICKER_SV_H = 110; | ||
| 853 | static constexpr int PICKER_HUE_H = 12; | ||
| 854 | static constexpr int PICKER_GAP = 8; | ||
| 855 | |||
| 856 | static bool picker_open_for(const Ctrl &c) { | ||
| 857 | return c.kind == CK_COLOR && g_picker_ctrl >= 0 && | ||
| 858 | &c == &g_ctrls[g_picker_ctrl]; | ||
| 859 | } | ||
| 860 | |||
| 861 | static int picker_panel_h() { | ||
| 862 | return S((float)(PICKER_GAP + PICKER_SV_H + PICKER_GAP + PICKER_HUE_H + | ||
| 863 | PICKER_GAP)); | ||
| 864 | } | ||
| 865 | |||
| 866 | static int label_row_h(const Ctrl &c) { | ||
| 825 | if (c.kind == CK_BUTTON) | 867 | if (c.kind == CK_BUTTON) |
| 826 | return S(32.0f); | 868 | return S(32.0f); |
| 827 | int maxw = (c.kind == CK_INFO || c.kind == CK_SECTION) | 869 | int maxw = (c.kind == CK_INFO || c.kind == CK_SECTION) |
| @@ -837,6 +879,207 @@ static int row_h(const Ctrl &c) { | |||
| 837 | return h < minh ? minh : h; | 879 | return h < minh ? minh : h; |
| 838 | } | 880 | } |
| 839 | 881 | ||
| 882 | static void hsv_to_rgb(float h, float s, float v, int &r, int &g, int &b) { | ||
| 883 | if (h < 0.0f) h = 0.0f; | ||
| 884 | h = fmodf(h, 360.0f); | ||
| 885 | if (h < 0.0f) h += 360.0f; | ||
| 886 | if (s < 0.0f) s = 0.0f; | ||
| 887 | if (s > 1.0f) s = 1.0f; | ||
| 888 | if (v < 0.0f) v = 0.0f; | ||
| 889 | if (v > 1.0f) v = 1.0f; | ||
| 890 | float c = v * s; | ||
| 891 | float x = c * (1.0f - fabsf(fmodf(h / 60.0f, 2.0f) - 1.0f)); | ||
| 892 | float m = v - c; | ||
| 893 | float rr = 0.0f, gg = 0.0f, bb = 0.0f; | ||
| 894 | if (h < 60.0f) { | ||
| 895 | rr = c; gg = x; | ||
| 896 | } else if (h < 120.0f) { | ||
| 897 | rr = x; gg = c; | ||
| 898 | } else if (h < 180.0f) { | ||
| 899 | gg = c; bb = x; | ||
| 900 | } else if (h < 240.0f) { | ||
| 901 | gg = x; bb = c; | ||
| 902 | } else if (h < 300.0f) { | ||
| 903 | rr = x; bb = c; | ||
| 904 | } else { | ||
| 905 | rr = c; bb = x; | ||
| 906 | } | ||
| 907 | r = (int)((rr + m) * 255.0f + 0.5f); | ||
| 908 | g = (int)((gg + m) * 255.0f + 0.5f); | ||
| 909 | b = (int)((bb + m) * 255.0f + 0.5f); | ||
| 910 | } | ||
| 911 | |||
| 912 | static void rgb_to_hsv(int r, int g, int b, float &h, float &s, float &v) { | ||
| 913 | float rf = r / 255.0f, gf = g / 255.0f, bf = b / 255.0f; | ||
| 914 | float mx = fmaxf(rf, fmaxf(gf, bf)); | ||
| 915 | float mn = fminf(rf, fminf(gf, bf)); | ||
| 916 | float d = mx - mn; | ||
| 917 | v = mx; | ||
| 918 | s = mx > 0.0f ? d / mx : 0.0f; | ||
| 919 | if (d <= 0.0f) { | ||
| 920 | h = 0.0f; | ||
| 921 | return; | ||
| 922 | } | ||
| 923 | if (mx == rf) | ||
| 924 | h = 60.0f * fmodf((gf - bf) / d, 6.0f); | ||
| 925 | else if (mx == gf) | ||
| 926 | h = 60.0f * ((bf - rf) / d + 2.0f); | ||
| 927 | else | ||
| 928 | h = 60.0f * ((rf - gf) / d + 4.0f); | ||
| 929 | if (h < 0.0f) | ||
| 930 | h += 360.0f; | ||
| 931 | } | ||
| 932 | |||
| 933 | struct PickerRects { | ||
| 934 | Rect panel, sv, hue, preview; | ||
| 935 | }; | ||
| 936 | |||
| 937 | static PickerRects picker_rects(const Rect &cr, int row_y, int base_h) { | ||
| 938 | PickerRects p{}; | ||
| 939 | int px = cr.x + S(16.0f); | ||
| 940 | int py = row_y + base_h; | ||
| 941 | int pw = card_content_w() - S(32.0f); | ||
| 942 | if (pw > S(340.0f)) pw = S(340.0f); | ||
| 943 | p.panel = Rect{px, py, pw, picker_panel_h()}; | ||
| 944 | int preview_w = S(84.0f); | ||
| 945 | int svw = S((float)PICKER_SV_W); | ||
| 946 | if (svw + preview_w + S(16.0f) > pw) | ||
| 947 | svw = pw - preview_w - S(16.0f); | ||
| 948 | if (svw < S(60.0f)) | ||
| 949 | svw = S(60.0f); | ||
| 950 | p.sv = Rect{px + S(PICKER_GAP), py + S(PICKER_GAP), svw, | ||
| 951 | S((float)PICKER_SV_H)}; | ||
| 952 | p.hue = Rect{p.sv.x, p.sv.y + p.sv.h + S(PICKER_GAP), svw, | ||
| 953 | S((float)PICKER_HUE_H)}; | ||
| 954 | p.preview = Rect{p.sv.x + p.sv.w + S(12.0f), p.sv.y, preview_w, S(52.0f)}; | ||
| 955 | return p; | ||
| 956 | } | ||
| 957 | |||
| 958 | // Widget row/card used to map a control index back to screen space. Needed by | ||
| 959 | // the drag handler, which runs outside click/layout context. | ||
| 960 | static bool control_rect(int ctrl_index, Rect &out_card, Rect &out_row) { | ||
| 961 | Rect content{g_win_x + S(190.0f), g_win_y + S(38.0f), | ||
| 962 | g_win_w - S(190.0f), g_win_h - S(38.0f) - S(30.0f)}; | ||
| 963 | int y = content.y - (int)g_scroll + S(8.0f); | ||
| 964 | for (int i = 0; i < g_ncards; i++) { | ||
| 965 | if (!card_in_category(i)) | ||
| 966 | continue; | ||
| 967 | Card &c = g_cards[i]; | ||
| 968 | Rect cr = card_rect(i, y); | ||
| 969 | if (c.expanded) { | ||
| 970 | int by = cr.y + header_h(c) + S(6.0f); | ||
| 971 | for (int j = 0; j < c.n; j++) { | ||
| 972 | Ctrl &ct = g_ctrls[c.c0 + j]; | ||
| 973 | int rh = row_h(ct); | ||
| 974 | if (c.c0 + j == ctrl_index) { | ||
| 975 | out_card = cr; | ||
| 976 | out_row = Rect{cr.x, by, cr.w, rh}; | ||
| 977 | return true; | ||
| 978 | } | ||
| 979 | by += rh; | ||
| 980 | } | ||
| 981 | } | ||
| 982 | y += card_h(c); | ||
| 983 | } | ||
| 984 | return false; | ||
| 985 | } | ||
| 986 | |||
| 987 | static bool picker_rects_for(int ctrl_index, PickerRects &out) { | ||
| 988 | if (ctrl_index < 0 || ctrl_index >= g_nctrl) | ||
| 989 | return false; | ||
| 990 | Rect card, row; | ||
| 991 | if (!control_rect(ctrl_index, card, row)) | ||
| 992 | return false; | ||
| 993 | Ctrl &ct = g_ctrls[ctrl_index]; | ||
| 994 | out = picker_rects(card, row.y, label_row_h(ct)); | ||
| 995 | return true; | ||
| 996 | } | ||
| 997 | |||
| 998 | static void picker_apply(Ctrl &ct, const PickerRects &p) { | ||
| 999 | if (!ct.rgb || p.sv.w <= 0 || p.hue.w <= 0) | ||
| 1000 | return; | ||
| 1001 | if (g_picker_drag == 1) { | ||
| 1002 | float s = (float)(g_mouse_x - p.sv.x) / (float)p.sv.w; | ||
| 1003 | float v = 1.0f - (float)(g_mouse_y - p.sv.y) / (float)p.sv.h; | ||
| 1004 | if (s < 0.0f) s = 0.0f; | ||
| 1005 | if (s > 1.0f) s = 1.0f; | ||
| 1006 | if (v < 0.0f) v = 0.0f; | ||
| 1007 | if (v > 1.0f) v = 1.0f; | ||
| 1008 | ct.sat = s; | ||
| 1009 | ct.val = v; | ||
| 1010 | } else if (g_picker_drag == 2) { | ||
| 1011 | float h = 360.0f * (float)(g_mouse_x - p.hue.x) / (float)p.hue.w; | ||
| 1012 | if (h < 0.0f) h = 0.0f; | ||
| 1013 | if (h >= 360.0f) h = 359.9f; | ||
| 1014 | ct.hue = h; | ||
| 1015 | } | ||
| 1016 | hsv_to_rgb(ct.hue, ct.sat, ct.val, ct.rgb[0], ct.rgb[1], ct.rgb[2]); | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | static void draw_picker(const Rect &clip, const Rect &cr, const Ctrl &ct, | ||
| 1020 | int row_y) { | ||
| 1021 | PickerRects p = picker_rects(cr, row_y, label_row_h(ct)); | ||
| 1022 | fill(p.panel, Col{20, 23, 29, 250}, &clip); | ||
| 1023 | outline(p.panel, C_BORDER, &clip); | ||
| 1024 | |||
| 1025 | // Saturation/value field: solid rows of a white->hue gradient scaled by V. | ||
| 1026 | int sx = S(4.0f); | ||
| 1027 | int sy = S(4.0f); | ||
| 1028 | if (sx < 2) sx = 2; | ||
| 1029 | if (sy < 2) sy = 2; | ||
| 1030 | for (int yy = 0; yy < p.sv.h; yy += sy) { | ||
| 1031 | float v = 1.0f - ((float)yy + (float)sy * 0.5f) / (float)p.sv.h; | ||
| 1032 | int rh = sy < p.sv.h - yy ? sy : p.sv.h - yy; | ||
| 1033 | for (int xx = 0; xx < p.sv.w; xx += sx) { | ||
| 1034 | float s = ((float)xx + (float)sx * 0.5f) / (float)p.sv.w; | ||
| 1035 | int r, g, b; | ||
| 1036 | hsv_to_rgb(ct.hue, s, v, r, g, b); | ||
| 1037 | int rw = sx < p.sv.w - xx ? sx : p.sv.w - xx; | ||
| 1038 | fill(Rect{p.sv.x + xx, p.sv.y + yy, rw, rh}, Col{r, g, b, 255}, &clip); | ||
| 1039 | } | ||
| 1040 | } | ||
| 1041 | outline(p.sv, Col{0, 0, 0, 255}, &clip); | ||
| 1042 | |||
| 1043 | // Hue bar. | ||
| 1044 | int hx = S(4.0f); | ||
| 1045 | if (hx < 2) hx = 2; | ||
| 1046 | for (int xx = 0; xx < p.hue.w; xx += hx) { | ||
| 1047 | float h = 360.0f * ((float)xx + (float)hx * 0.5f) / (float)p.hue.w; | ||
| 1048 | int r, g, b; | ||
| 1049 | hsv_to_rgb(h, 1.0f, 1.0f, r, g, b); | ||
| 1050 | int rw = hx < p.hue.w - xx ? hx : p.hue.w - xx; | ||
| 1051 | fill(Rect{p.hue.x + xx, p.hue.y, rw, p.hue.h}, Col{r, g, b, 255}, &clip); | ||
| 1052 | } | ||
| 1053 | outline(p.hue, Col{0, 0, 0, 255}, &clip); | ||
| 1054 | |||
| 1055 | // Selection markers. | ||
| 1056 | int mx = p.sv.x + (int)(ct.sat * (float)p.sv.w); | ||
| 1057 | int my = p.sv.y + (int)((1.0f - ct.val) * (float)p.sv.h); | ||
| 1058 | Rect svm{mx - S(4.0f), my - S(4.0f), S(8.0f), S(8.0f)}; | ||
| 1059 | outline(svm, Col{0, 0, 0, 255}, &clip); | ||
| 1060 | Rect svm2{mx - S(3.0f), my - S(3.0f), S(6.0f), S(6.0f)}; | ||
| 1061 | outline(svm2, Col{255, 255, 255, 255}, &clip); | ||
| 1062 | |||
| 1063 | int hxm = p.hue.x + (int)((ct.hue / 360.0f) * (float)p.hue.w); | ||
| 1064 | line(hxm, p.hue.y - S(2.0f), hxm, p.hue.y + p.hue.h + S(2.0f), | ||
| 1065 | Col{255, 255, 255, 255}); | ||
| 1066 | |||
| 1067 | // Preview swatch and hex value. | ||
| 1068 | int pr = ct.rgb ? ct.rgb[0] : 255; | ||
| 1069 | int pg = ct.rgb ? ct.rgb[1] : 255; | ||
| 1070 | int pb = ct.rgb ? ct.rgb[2] : 255; | ||
| 1071 | fill(p.preview, Col{pr, pg, pb, 255}, &clip); | ||
| 1072 | outline(p.preview, C_BORDER, &clip); | ||
| 1073 | char hex[16]; | ||
| 1074 | snprintf(hex, sizeof(hex), "#%02X%02X%02X", pr, pg, pb); | ||
| 1075 | text_in(clip, p.preview.x, p.preview.y + p.preview.h + S(8.0f), hex, | ||
| 1076 | g_font_body, g_body_h, p.preview.w, C_TEXT); | ||
| 1077 | char rgb[48]; | ||
| 1078 | snprintf(rgb, sizeof(rgb), "%d %d %d", pr, pg, pb); | ||
| 1079 | text_in(clip, p.preview.x, p.preview.y + p.preview.h + S(8.0f) + g_body_h, | ||
| 1080 | rgb, g_font_body, g_body_h, p.preview.w, C_DIM); | ||
| 1081 | } | ||
| 1082 | |||
| 840 | static int body_h(const Card &c) { | 1083 | static int body_h(const Card &c) { |
| 841 | if (!c.expanded) | 1084 | if (!c.expanded) |
| 842 | return 0; | 1085 | return 0; |
| @@ -877,6 +1120,8 @@ static void close_gui() { | |||
| 877 | g_dragging = false; | 1120 | g_dragging = false; |
| 878 | g_scroll_drag = false; | 1121 | g_scroll_drag = false; |
| 879 | g_slider_drag = -1; | 1122 | g_slider_drag = -1; |
| 1123 | g_picker_ctrl = -1; | ||
| 1124 | g_picker_drag = 0; | ||
| 880 | g_reset_armed = false; | 1125 | g_reset_armed = false; |
| 881 | input_clear_mouse_states(); | 1126 | input_clear_mouse_states(); |
| 882 | if (g_sdl_ready) { | 1127 | if (g_sdl_ready) { |
| @@ -1115,6 +1360,37 @@ static void handle_mouse_click() { | |||
| 1115 | } | 1360 | } |
| 1116 | return; | 1361 | return; |
| 1117 | } | 1362 | } |
| 1363 | if (ct.kind == CK_COLOR) { | ||
| 1364 | int idx = c.c0 + j; | ||
| 1365 | int base = label_row_h(ct); | ||
| 1366 | bool is_open = (g_picker_ctrl == idx); | ||
| 1367 | if (is_open) { | ||
| 1368 | PickerRects p = picker_rects(cr, by, base); | ||
| 1369 | if (p.sv.has(mx, my)) { | ||
| 1370 | g_picker_drag = 1; | ||
| 1371 | picker_apply(g_ctrls[idx], p); | ||
| 1372 | return; | ||
| 1373 | } | ||
| 1374 | if (p.hue.has(mx, my)) { | ||
| 1375 | g_picker_drag = 2; | ||
| 1376 | picker_apply(g_ctrls[idx], p); | ||
| 1377 | return; | ||
| 1378 | } | ||
| 1379 | } | ||
| 1380 | Rect sw{cr.x + cr.w - S(96.0f), by + (base - S(20.0f)) / 2, | ||
| 1381 | S(72.0f), S(20.0f)}; | ||
| 1382 | if (my < by + base || sw.has(mx, my)) { | ||
| 1383 | if (is_open) { | ||
| 1384 | g_picker_ctrl = -1; | ||
| 1385 | } else { | ||
| 1386 | g_picker_ctrl = idx; | ||
| 1387 | if (ct.rgb) | ||
| 1388 | rgb_to_hsv(ct.rgb[0], ct.rgb[1], ct.rgb[2], ct.hue, ct.sat, | ||
| 1389 | ct.val); | ||
| 1390 | } | ||
| 1391 | } | ||
| 1392 | return; | ||
| 1393 | } | ||
| 1118 | if (ct.kind == CK_BUTTON) { | 1394 | if (ct.kind == CK_BUTTON) { |
| 1119 | int bw = button_w(ct.label); | 1395 | int bw = button_w(ct.label); |
| 1120 | Rect b{cr.x + cr.w - S(16.0f) - bw, | 1396 | Rect b{cr.x + cr.w - S(16.0f) - bw, |
| @@ -1291,6 +1567,17 @@ void gui_handle_input() { | |||
| 1291 | } | 1567 | } |
| 1292 | } | 1568 | } |
| 1293 | 1569 | ||
| 1570 | if (g_picker_drag) { | ||
| 1571 | if (!g_mouse_down) { | ||
| 1572 | g_picker_drag = 0; | ||
| 1573 | config_save(); | ||
| 1574 | } else if (g_picker_ctrl >= 0) { | ||
| 1575 | PickerRects p; | ||
| 1576 | if (picker_rects_for(g_picker_ctrl, p)) | ||
| 1577 | picker_apply(g_ctrls[g_picker_ctrl], p); | ||
| 1578 | } | ||
| 1579 | } | ||
| 1580 | |||
| 1294 | if (g_scroll_drag) { | 1581 | if (g_scroll_drag) { |
| 1295 | if (!g_mouse_down) { | 1582 | if (!g_mouse_down) { |
| 1296 | g_scroll_drag = false; | 1583 | g_scroll_drag = false; |
| @@ -1472,7 +1759,8 @@ static void draw_card(const Rect &clip, int index, int y) { | |||
| 1472 | wrap_text(ct.label, maxw, g_body_h, lines); | 1759 | wrap_text(ct.label, maxw, g_body_h, lines); |
| 1473 | int lh = g_body_h + S(2.0f); | 1760 | int lh = g_body_h + S(2.0f); |
| 1474 | int text_h = (int)lines.size() * lh - S(2.0f); | 1761 | int text_h = (int)lines.size() * lh - S(2.0f); |
| 1475 | int ly = by + (rh - text_h) / 2; | 1762 | int base_h = label_row_h(ct); |
| 1763 | int ly = by + (base_h - text_h) / 2; | ||
| 1476 | draw_wrapped(clip, cr.x + S(16.0f), ly, ct.label, g_font_body, g_body_h, | 1764 | draw_wrapped(clip, cr.x + S(16.0f), ly, ct.label, g_font_body, g_body_h, |
| 1477 | maxw, C_TEXT, S(2.0f)); | 1765 | maxw, C_TEXT, S(2.0f)); |
| 1478 | if (ct.kind == CK_TOGGLE) { | 1766 | if (ct.kind == CK_TOGGLE) { |
| @@ -1483,6 +1771,16 @@ static void draw_card(const Rect &clip, int index, int y) { | |||
| 1483 | on ? C_GOOD : C_DIM); | 1771 | on ? C_GOOD : C_DIM); |
| 1484 | } else if (ct.kind == CK_SLIDER) { | 1772 | } else if (ct.kind == CK_SLIDER) { |
| 1485 | draw_slider(clip, cr, by, rh, ct); | 1773 | draw_slider(clip, cr, by, rh, ct); |
| 1774 | } else if (ct.kind == CK_COLOR) { | ||
| 1775 | int pr = ct.rgb ? ct.rgb[0] : 255; | ||
| 1776 | int pg = ct.rgb ? ct.rgb[1] : 255; | ||
| 1777 | int pb = ct.rgb ? ct.rgb[2] : 255; | ||
| 1778 | Rect sw{cr.x + cr.w - S(96.0f), | ||
| 1779 | by + (base_h - S(20.0f)) / 2, S(72.0f), S(20.0f)}; | ||
| 1780 | fill(sw, Col{pr, pg, pb, 255}, &clip); | ||
| 1781 | outline(sw, picker_open_for(ct) ? C_ACCENT : C_BORDER, &clip); | ||
| 1782 | if (picker_open_for(ct)) | ||
| 1783 | draw_picker(clip, cr, ct, by); | ||
| 1486 | } | 1784 | } |
| 1487 | } | 1785 | } |
| 1488 | by += rh; | 1786 | by += rh; |
