]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor/color_picker.c
6cacb7eb1f2e4ea063ae50e652a0c3c4fa728a54
[nothing.git] / src / game / level / level_editor / color_picker.c
1 #include <stdbool.h>
2 #include <string.h>
3
4 #include "game/level/boxes.h"
5 #include "system/stacktrace.h"
6 #include "system/line_stream.h"
7 #include "system/log.h"
8 #include "game/camera.h"
9 #include "color_picker.h"
10 #include "color.h"
11 #include "undo_history.h"
12
13 #define COLOR_SLIDER_HEIGHT 60.0f
14 #define COLOR_PICKER_WIDTH 300.0f
15 #define COLOR_PICKER_HEIGHT (COLOR_SLIDER_HEIGHT * COLOR_SLIDER_N)
16 #define COLOR_PICKER_REFERENCE 1920.0f
17 #define COLOR_PICKER_HW_RATIO (COLOR_PICKER_HEIGHT/ COLOR_PICKER_WIDTH)
18 #define COLOR_PICKER_WR_RATIO (COLOR_PICKER_WIDTH / COLOR_PICKER_REFERENCE)
19
20 const char *slider_labels[COLOR_SLIDER_N] = {
21     "Hue",
22     "Saturation",
23     "Lightness"
24 };
25
26 ColorPicker create_color_picker_from_rgba(Color color)
27 {
28     Color color_hsla = rgba_to_hsla(color);
29     ColorPicker color_picker = {
30         .sliders = {
31             {0, color_hsla.r, 360.0f},
32             {0, color_hsla.g, 1.0f},
33             {0, color_hsla.b, 1.0f}
34         }
35     };
36     return color_picker;
37 }
38
39 int color_picker_read_from_line_stream(ColorPicker *color_picker,
40                                        LineStream *line_stream)
41 {
42     char color[7];
43     const char *line = line_stream_next(line_stream);
44     if (line == NULL) {
45         return -1;
46     }
47
48     if (sscanf(line, "%6s", color) == EOF) {
49         log_fail("Could not read color\n");
50     }
51
52     *color_picker = create_color_picker_from_rgba(hexstr(color));
53
54     return 0;
55 }
56
57 int color_picker_render(const ColorPicker *color_picker,
58                         const Camera *camera)
59 {
60     trace_assert(color_picker);
61     trace_assert(camera);
62
63     const Rect viewport = camera_view_port_screen(camera);
64     const Rect boundary = rect(
65         0.0f, 0.0f,
66         viewport.w * COLOR_PICKER_WR_RATIO,
67         viewport.w * COLOR_PICKER_WR_RATIO * COLOR_PICKER_HW_RATIO);
68
69     const float color_slider_height =
70         boundary.h / (COLOR_SLIDER_N + 1.0f);
71
72     if (camera_fill_rect_screen(
73             camera,
74             rect(boundary.x, boundary.y,
75                  boundary.w, color_slider_height),
76             color_picker_rgba(color_picker)) < 0) {
77         return -1;
78     }
79
80     for (ColorPickerSlider index = 0; index < COLOR_SLIDER_N; ++index) {
81         const Rect slider_rect =
82             rect(boundary.x,
83                  boundary.y + color_slider_height * (float) (index + 1),
84                  boundary.w, color_slider_height);
85         const float font_scale = boundary.w / COLOR_PICKER_WIDTH;
86         const Vec2f label_size = vec(2.5f * font_scale, 2.5f * font_scale);
87
88         if (slider_render(
89                 &color_picker->sliders[index],
90                 camera,
91                 slider_rect) < 0) {
92             return -1;
93         }
94
95         camera_render_text_screen(
96             camera,
97             slider_labels[index],
98             label_size,
99             COLOR_BLACK,
100             vec(slider_rect.x + boundary.w,
101                 slider_rect.y + color_slider_height * 0.5f - label_size.y * (float) FONT_CHAR_HEIGHT * 0.5f));
102     }
103
104     return 0;
105 }
106
107 // TODO(#932): the `selected` event propagation control is cumbersome
108 int color_picker_event(ColorPicker *color_picker,
109                        const SDL_Event *event,
110                        const Camera *camera,
111                        int *selected_out)
112 {
113     trace_assert(color_picker);
114     trace_assert(event);
115     trace_assert(camera);
116
117     int selected = 0;
118
119     const Rect viewport = camera_view_port_screen(camera);
120     const Rect boundary = rect(
121         0.0f, 0.0f,
122         viewport.w * COLOR_PICKER_WR_RATIO,
123         viewport.w * COLOR_PICKER_WR_RATIO * COLOR_PICKER_HW_RATIO);
124
125     const float color_slider_height =
126         boundary.h / (COLOR_SLIDER_N + 1.0f);
127
128     for (ColorPickerSlider index = 0;
129          !selected && index < COLOR_SLIDER_N;
130          ++index) {
131         if (slider_event(
132                 &color_picker->sliders[index],
133                 event,
134                 rect(boundary.x,
135                      boundary.y + color_slider_height * (float) (index + 1),
136                      boundary.w, color_slider_height),
137                 &selected) < 0) {
138             return -1;
139         }
140     }
141
142     if (selected_out) {
143         *selected_out = selected;
144     }
145
146     return 0;
147 }
148
149 Color color_picker_rgba(const ColorPicker *color_picker)
150 {
151     return hsla(
152         color_picker->sliders[COLOR_SLIDER_HUE].value,
153         color_picker->sliders[COLOR_SLIDER_SAT].value,
154         color_picker->sliders[COLOR_SLIDER_LIT].value,
155         1.0f);
156 }