#include <stdbool.h>
+#include <string.h>
#include "game/level/boxes.h"
#include "system/stacktrace.h"
#include "system/line_stream.h"
#include "system/log.h"
#include "game/camera.h"
-#include "proto_rect.h"
#include "color_picker.h"
#include "color.h"
+#include "undo_history.h"
-#define COLOR_CELL_WIDTH 50.0f
-#define COLOR_CELL_HEIGHT 50.0f
+// TODO(#1021): ColorPicker doesn't have any padding between the sliders
+#define COLOR_SLIDER_HEIGHT 60.0f
+#define COLOR_PICKER_WIDTH 300.0f
+#define COLOR_PICKER_HEIGHT (COLOR_SLIDER_HEIGHT * COLOR_SLIDER_N)
+#define COLOR_PICKER_REFERENCE 1920.0f
+#define COLOR_PICKER_HW_RATIO (COLOR_PICKER_HEIGHT/ COLOR_PICKER_WIDTH)
+#define COLOR_PICKER_WR_RATIO (COLOR_PICKER_WIDTH / COLOR_PICKER_REFERENCE)
-// TODO(#788): Colors of ColorPicker are poor
-static Color colors[] = {
- {1.0f, 0.0f, 0.0f, 1.0f},
- {0.0f, 1.0f, 0.0f, 1.0f},
- {0.0f, 0.0f, 1.0f, 1.0f}
+const char *slider_labels[COLOR_SLIDER_N] = {
+ "Hue",
+ "Saturation",
+ "Lightness"
};
-static const size_t colors_count = sizeof(colors) / sizeof(Color);
-LayerPtr color_picker_as_layer(ColorPicker *color_picker)
+ColorPicker create_color_picker_from_rgba(Color color)
{
- LayerPtr layer = {
- .ptr = color_picker,
- .type = LAYER_COLOR_PICKER
+ Color color_hsla = rgba_to_hsla(color);
+ ColorPicker color_picker = {
+ .sliders = {
+ {0, color_hsla.r, 360.0f},
+ {0, color_hsla.g, 1.0f},
+ {0, color_hsla.b, 1.0f}
+ }
};
- return layer;
+ return color_picker;
}
int color_picker_read_from_line_stream(ColorPicker *color_picker,
log_fail("Could not read color\n");
}
- color_picker->color = hexstr(color);
+ *color_picker = create_color_picker_from_rgba(hexstr(color));
return 0;
}
trace_assert(color_picker);
trace_assert(camera);
- for (size_t i = 0; i < colors_count; ++i) {
- if (camera_fill_rect_screen(
+ const Rect viewport = camera_view_port_screen(camera);
+ const Rect boundary = rect(
+ 0.0f, 0.0f,
+ viewport.w * COLOR_PICKER_WR_RATIO,
+ viewport.w * COLOR_PICKER_WR_RATIO * COLOR_PICKER_HW_RATIO);
+
+ const float color_slider_height =
+ boundary.h / (COLOR_SLIDER_N + 1.0f);
+
+ if (camera_fill_rect_screen(
+ camera,
+ rect(boundary.x, boundary.y,
+ boundary.w, color_slider_height),
+ color_picker_rgba(color_picker)) < 0) {
+ return -1;
+ }
+
+ for (ColorPickerSlider index = 0; index < COLOR_SLIDER_N; ++index) {
+ const Rect slider_rect =
+ rect(boundary.x,
+ boundary.y + color_slider_height * (float) (index + 1),
+ boundary.w, color_slider_height);
+ const float font_scale = boundary.w / COLOR_PICKER_WIDTH;
+ const Point label_size = vec(2.5f * font_scale, 2.5f * font_scale);
+
+ if (slider_render(
+ &color_picker->sliders[index],
+ camera,
+ slider_rect) < 0) {
+ return -1;
+ }
+
+ if (camera_render_text_screen(
camera,
- rect(COLOR_CELL_WIDTH * (float) i, 0,
- COLOR_CELL_WIDTH,
- COLOR_CELL_HEIGHT),
- colors[i]) < 0) {
+ slider_labels[index],
+ label_size,
+ COLOR_BLACK,
+ vec(slider_rect.x + boundary.w,
+ slider_rect.y + color_slider_height * 0.5f - label_size.y * (float) FONT_CHAR_HEIGHT * 0.5f)) < 0) {
return -1;
}
}
return 0;
}
-int color_picker_mouse_button(ColorPicker *color_picker,
- const SDL_MouseButtonEvent *event,
- bool *selected)
+// TODO(#932): the `selected` event propagation control is cumbersome
+int color_picker_event(ColorPicker *color_picker,
+ const SDL_Event *event,
+ const Camera *camera,
+ int *selected_out)
{
trace_assert(color_picker);
trace_assert(event);
+ trace_assert(camera);
+
+ int selected = 0;
+
+ const Rect viewport = camera_view_port_screen(camera);
+ const Rect boundary = rect(
+ 0.0f, 0.0f,
+ viewport.w * COLOR_PICKER_WR_RATIO,
+ viewport.w * COLOR_PICKER_WR_RATIO * COLOR_PICKER_HW_RATIO);
- if (event->type == SDL_MOUSEBUTTONDOWN) {
- switch (event->button) {
- case SDL_BUTTON_LEFT: {
- for (size_t i = 0; i < colors_count; ++i) {
- const Vec mouse_position = vec((float) event->x, (float) event->y);
- const Rect color_cell =
- rect(COLOR_CELL_WIDTH * (float) i, 0,
- COLOR_CELL_WIDTH,
- COLOR_CELL_HEIGHT);
- if (rect_contains_point(color_cell, mouse_position)) {
- color_picker->color = colors[i];
- if (selected) {
- *selected = true;
- }
- return 0;
- }
- }
- } break;
+ const float color_slider_height =
+ boundary.h / (COLOR_SLIDER_N + 1.0f);
+
+ for (ColorPickerSlider index = 0;
+ !selected && index < COLOR_SLIDER_N;
+ ++index) {
+ if (slider_event(
+ &color_picker->sliders[index],
+ event,
+ rect(boundary.x,
+ boundary.y + color_slider_height * (float) (index + 1),
+ boundary.w, color_slider_height),
+ &selected) < 0) {
+ return -1;
}
}
+ if (selected_out) {
+ *selected_out = selected;
+ }
+
return 0;
}
+
+Color color_picker_rgba(const ColorPicker *color_picker)
+{
+ return hsla(
+ color_picker->sliders[COLOR_SLIDER_HUE].value,
+ color_picker->sliders[COLOR_SLIDER_SAT].value,
+ color_picker->sliders[COLOR_SLIDER_LIT].value,
+ 1.0f);
+}