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