(#788) Make ColorPicker work across all of the layers

master
rexim 2019-07-01 22:49:11 +07:00
parent 2eee928605
commit 6c48bc6475
15 changed files with 136 additions and 109 deletions

View File

@ -127,3 +127,29 @@ int color_hex_to_stream(Color color, FILE *stream)
SDL_Color sdl = color_for_sdl(color);
return fprintf(stream, "%02x%02x%02x", sdl.r, sdl.g, sdl.b);
}
Color rgba_to_hsla(Color color)
{
const float max = fmaxf(color.r, fmaxf(color.g, color.b));
const float min = fminf(color.r, fminf(color.g, color.b));
const float c = max - min;
float hue = 0.0f;
float saturation = 0.0f;
const float lightness = (max + min) * 0.5f;
if (fabsf(c) > 1e-6) {
if (fabs(max - color.r) <= 1e-6) {
hue = 60.0f * fmodf((color.g - color.b) / c, 6.0f);
} else if (fabs(max - color.g) <= 1e-6) {
hue = 60.0f * ((color.b - color.r) / c + 2.0f);
} else {
hue = 60.0f * ((color.r - color.g) / c + 4.0f);
}
saturation = c / (1.0f - fabsf(2.0f * lightness - 1.0f));
}
// TODO: Color struct is used not only for RGBA
// But also for HSLA. We should make another similar struct but for HSLA
return rgba(hue, saturation, lightness, color.a);
}

View File

@ -14,6 +14,7 @@ typedef struct Color {
Color rgba(float r, float g, float b, float a);
Color hsla(float h, float s, float l, float a);
Color rgba_to_hsla(Color color);
Color hexstr(const char *hexstr);
SDL_Color color_for_sdl(Color color);

View File

@ -70,7 +70,7 @@ Level *create_level_from_level_editor(const LevelEditor *level_editor,
level->background = PUSH_LT(
lt,
create_background(level_editor->background_layer.color),
create_background(color_picker_rgba(&level_editor->background_layer)),
destroy_background);
if (level->background == NULL) {
RETURN_LT(lt, NULL);

View File

@ -54,7 +54,7 @@ LevelEditor *create_level_editor(void)
RETURN_LT(lt, NULL);
}
level_editor->background_layer.color = hexstr("fffda5");
level_editor->background_layer = create_color_picker_from_rgba(hexstr("fffda5"));
level_editor->player_layer = PUSH_LT(
lt,
@ -300,7 +300,7 @@ int level_editor_render(const LevelEditor *level_editor,
trace_assert(level_editor);
trace_assert(camera);
if (camera_clear_background(camera, level_editor->background_layer.color) < 0) {
if (camera_clear_background(camera, color_picker_rgba(&level_editor->background_layer)) < 0) {
return -1;
}

View File

@ -9,16 +9,8 @@
#include "color_picker.h"
#include "color.h"
#define COLOR_CELL_WIDTH 50.0f
#define COLOR_CELL_HEIGHT 50.0f
// 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}
};
static const size_t colors_count = sizeof(colors) / sizeof(Color);
#define COLOR_SLIDER_HEIGHT 50.0f
#define COLOR_SLIDER_WIDTH 300.0f
LayerPtr color_picker_as_layer(ColorPicker *color_picker)
{
@ -29,6 +21,17 @@ LayerPtr color_picker_as_layer(ColorPicker *color_picker)
return layer;
}
ColorPicker create_color_picker_from_rgba(Color color)
{
Color color_hsla = rgba_to_hsla(color);
ColorPicker color_picker = {
.hue = {0, color_hsla.r, 360.0f},
.saturation = {0, color_hsla.g, 1.0f},
.lightness = {0, color_hsla.b, 1.0f}
};
return color_picker;
}
int color_picker_read_from_line_stream(ColorPicker *color_picker,
LineStream *line_stream)
{
@ -42,14 +45,7 @@ int color_picker_read_from_line_stream(ColorPicker *color_picker,
log_fail("Could not read color\n");
}
color_picker->color = hexstr(color);
color_picker->hue.value = 0.0f;
color_picker->hue.max_value = 360.0f;
color_picker->saturation.value = 0.0f;
color_picker->saturation.max_value = 1.0f;
color_picker->lightness.value = 0.0f;
color_picker->lightness.max_value = 1.0f;
*color_picker = create_color_picker_from_rgba(hexstr(color));
return 0;
}
@ -60,40 +56,29 @@ int color_picker_render(const ColorPicker *color_picker,
trace_assert(color_picker);
trace_assert(camera);
for (size_t i = 0; i < colors_count; ++i) {
if (camera_fill_rect_screen(
camera,
rect(COLOR_CELL_WIDTH * (float) i, 0,
COLOR_CELL_WIDTH,
COLOR_CELL_HEIGHT),
colors[i]) < 0) {
return -1;
}
}
/* TODO: Color Picker sliders don't have any labels */
if (slider_render(
&color_picker->hue,
camera,
rect(0.0f, COLOR_CELL_HEIGHT,
300.0f, COLOR_CELL_HEIGHT)) < 0) {
rect(0.0f, COLOR_SLIDER_HEIGHT,
COLOR_SLIDER_WIDTH, COLOR_SLIDER_HEIGHT)) < 0) {
return -1;
}
if (slider_render(
&color_picker->saturation,
camera,
rect(0.0f, COLOR_CELL_HEIGHT * 2.0f,
300.0f, COLOR_CELL_HEIGHT)) < 0) {
rect(0.0f, COLOR_SLIDER_HEIGHT * 2.0f,
COLOR_SLIDER_WIDTH, COLOR_SLIDER_HEIGHT)) < 0) {
return -1;
}
if (slider_render(
&color_picker->lightness,
camera,
rect(0.0f, COLOR_CELL_HEIGHT * 3.0f,
300.0f, COLOR_CELL_HEIGHT)) < 0) {
rect(0.0f, COLOR_SLIDER_HEIGHT * 3.0f,
COLOR_SLIDER_WIDTH, COLOR_SLIDER_HEIGHT)) < 0) {
return -1;
}
@ -101,60 +86,54 @@ int color_picker_render(const ColorPicker *color_picker,
return 0;
}
int color_picker_event(ColorPicker *color_picker, const SDL_Event *event, int *selected)
// TODO: the `selected` event propagation control is cumbersome
int color_picker_event(ColorPicker *color_picker, const SDL_Event *event, int *selected_out)
{
trace_assert(color_picker);
trace_assert(event);
int selected = 0;
if (slider_event(&color_picker->hue,
event,
rect(0.0f, COLOR_CELL_HEIGHT,
300.0f, COLOR_CELL_HEIGHT)) < 0) {
rect(0.0f, COLOR_SLIDER_HEIGHT,
COLOR_SLIDER_WIDTH, COLOR_SLIDER_HEIGHT),
&selected) < 0) {
return -1;
}
if (slider_event(&color_picker->saturation,
event,
rect(0.0f, COLOR_CELL_HEIGHT * 2.0f,
300.0f, COLOR_CELL_HEIGHT)) < 0) {
return -1;
}
if (slider_event(&color_picker->lightness,
event,
rect(0.0f, COLOR_CELL_HEIGHT * 3.0f,
300.0f, COLOR_CELL_HEIGHT)) < 0) {
return -1;
}
color_picker->color = hsla(
color_picker->hue.value,
color_picker->saturation.value,
color_picker->lightness.value,
1.0f);
switch (event->type) {
case SDL_MOUSEBUTTONDOWN: {
switch (event->button.button) {
case SDL_BUTTON_LEFT: {
for (size_t i = 0; i < colors_count; ++i) {
const Vec mouse_position = vec((float) event->button.x, (float) event->button.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;
if (!selected) {
if (slider_event(&color_picker->saturation,
event,
rect(0.0f, COLOR_SLIDER_HEIGHT * 2.0f,
COLOR_SLIDER_WIDTH, COLOR_SLIDER_HEIGHT),
&selected) < 0) {
return -1;
}
} break;
}
if (!selected) {
if (slider_event(&color_picker->lightness,
event,
rect(0.0f, COLOR_SLIDER_HEIGHT * 3.0f,
COLOR_SLIDER_WIDTH, 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->hue.value,
color_picker->saturation.value,
color_picker->lightness.value,
1.0f);
}

View File

@ -6,7 +6,6 @@
#include "ui/slider.h"
typedef struct {
Color color;
// TODO: ColorPicker should use array of sliders
Slider hue;
Slider saturation;
@ -15,6 +14,8 @@ typedef struct {
typedef struct LineStream LineStream;
ColorPicker create_color_picker_from_rgba(Color color);
int color_picker_read_from_line_stream(ColorPicker *color_picker,
LineStream *line_stream);
@ -24,4 +25,6 @@ int color_picker_render(const ColorPicker *color_picker,
Camera *camera);
int color_picker_event(ColorPicker *color_picker, const SDL_Event *event, int *selected);
Color color_picker_rgba(const ColorPicker *color_picker);
#endif // COLOR_PICKER_H_

View File

@ -65,7 +65,7 @@ int layer_dump_stream(LayerPtr layer,
return player_layer_dump_stream(layer.ptr, stream);
case LAYER_COLOR_PICKER: {
color_hex_to_stream(((ColorPicker*)layer.ptr)->color, stream);
color_hex_to_stream(color_picker_rgba(layer.ptr), stream);
return fprintf(stream, "\n");
}

View File

@ -16,7 +16,7 @@ PlayerLayer *create_player_layer(Vec position, Color color)
player_layer->lt = lt;
player_layer->position = position;
player_layer->color_picker.color = color;
player_layer->color_picker = create_color_picker_from_rgba(color);
return player_layer;
}
@ -76,7 +76,7 @@ int player_layer_render(const PlayerLayer *player_layer,
player_layer->position,
vec(25.0f, 25.0f)),
color_scale(
player_layer->color_picker.color,
color_picker_rgba(&player_layer->color_picker),
rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.0f))) < 0) {
return -1;
}
@ -125,7 +125,7 @@ int player_layer_dump_stream(const PlayerLayer *player_layer,
trace_assert(filedump);
fprintf(filedump, "%f %f ", player_layer->position.x, player_layer->position.y);
color_hex_to_stream(player_layer->color_picker.color, filedump);
color_hex_to_stream(color_picker_rgba(&player_layer->color_picker), filedump);
fprintf(filedump, "\n");
return 0;

View File

@ -119,7 +119,7 @@ PointLayer *create_point_layer_from_line_stream(LineStream *line_stream)
point_layer->selected = -1;
point_layer->color_picker.color = rgba(1.0f, 0.0f, 0.0f, 1.0f);
point_layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
return point_layer;
}
@ -203,6 +203,7 @@ static int point_layer_mouse_button(PointLayer *point_layer,
const int n = (int) dynarray_count(point_layer->points);
const Point *points = dynarray_data(point_layer->points);
const Point point = camera_map_screen(camera, event->x, event->y);
const Color color = color_picker_rgba(&point_layer->color_picker);
for (int i = 0; i < n; ++i) {
if (vec_length(vec_sub(points[i], point)) < POINT_LAYER_ELEMENT_RADIUS) {
@ -219,7 +220,7 @@ static int point_layer_mouse_button(PointLayer *point_layer,
id[ID_MAX_SIZE - 1] = '\0';
dynarray_push(point_layer->points, &point);
dynarray_push(point_layer->colors, &point_layer->color_picker.color);
dynarray_push(point_layer->colors, &color);
dynarray_push(point_layer->ids, id);
}

View File

@ -12,10 +12,10 @@
#define PROTO_AREA_THRESHOLD 10.0
int proto_rect_render(const ProtoRect *proto_rect,
Camera *camera)
Camera *camera,
Color color)
{
trace_assert(proto_rect);
trace_assert(proto_rect->color_current);
trace_assert(camera);
if (proto_rect->active) {
@ -24,7 +24,7 @@ int proto_rect_render(const ProtoRect *proto_rect,
rect_from_points(
proto_rect->begin,
proto_rect->end),
*proto_rect->color_current) < 0) {
color) < 0) {
return -1;
}
}
@ -34,13 +34,14 @@ int proto_rect_render(const ProtoRect *proto_rect,
int proto_rect_event(ProtoRect *proto_rect,
const SDL_Event *event,
const Camera *camera)
const Camera *camera,
Color color,
RectLayer *layer)
{
trace_assert(proto_rect);
trace_assert(proto_rect->color_current);
trace_assert(proto_rect->layer_current);
trace_assert(event);
trace_assert(camera);
trace_assert(layer);
if (proto_rect->active) {
// Active
@ -55,7 +56,7 @@ int proto_rect_event(ProtoRect *proto_rect,
const float area = real_rect.w * real_rect.h;
if (area >= PROTO_AREA_THRESHOLD) {
rect_layer_add_rect(proto_rect->layer_current, real_rect, *proto_rect->color_current);
rect_layer_add_rect(layer, real_rect, color);
} else {
log_info("The area is too small %f. Such small box won't be created.\n", area);
}

View File

@ -7,15 +7,15 @@ typedef struct {
bool active;
Sint32 x, y;
Vec begin, end;
Color *color_current;
RectLayer *layer_current;
} ProtoRect;
int proto_rect_render(const ProtoRect *proto_rect,
Camera *camera);
Camera *camera,
Color color);
int proto_rect_event(ProtoRect *proto_rect,
const SDL_Event *event,
const Camera *camera);
const Camera *camera,
Color color,
RectLayer *layer);
#endif // PROTO_RECT_H_

View File

@ -67,9 +67,7 @@ RectLayer *create_rect_layer(void)
RETURN_LT(lt, NULL);
}
layer->color_picker.color = rgba(1.0f, 0.0f, 0.0f, 1.0f);
layer->proto_rect.color_current = &layer->color_picker.color;
layer->proto_rect.layer_current = layer;
layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
return layer;
}
@ -148,7 +146,10 @@ int rect_layer_render(const RectLayer *layer, Camera *camera, int active)
}
}
if (proto_rect_render(&layer->proto_rect, camera) < 0) {
if (proto_rect_render(
&layer->proto_rect,
camera,
color_picker_rgba(&layer->color_picker)) < 0) {
return -1;
}
@ -169,7 +170,13 @@ int rect_layer_event(RectLayer *layer, const SDL_Event *event, const Camera *cam
return -1;
}
if (!selected && proto_rect_event(&layer->proto_rect, event, camera) < 0) {
if (!selected &&
proto_rect_event(
&layer->proto_rect,
event,
camera,
color_picker_rgba(&layer->color_picker),
layer) < 0) {
return -1;
}

View File

@ -75,7 +75,7 @@ Player *create_player_from_player_layer(const PlayerLayer *player_layer,
player->dying_body = PUSH_LT(
lt,
create_explosion(
player_layer->color_picker.color,
color_picker_rgba(&player_layer->color_picker),
PLAYER_DEATH_DURATION),
destroy_explosion);
if (player->dying_body == NULL) {
@ -83,7 +83,7 @@ Player *create_player_from_player_layer(const PlayerLayer *player_layer,
}
player->jump_threshold = 0;
player->color = player_layer->color_picker.color;
player->color = color_picker_rgba(&player_layer->color_picker);
player->checkpoint = player_layer->position;
player->play_die_cue = 0;
player->state = PLAYER_STATE_ALIVE;

View File

@ -34,7 +34,7 @@ int slider_render(const Slider *slider, Camera *camera, Rect boundary)
return 0;
}
int slider_event(Slider *slider, const SDL_Event *event, Rect boundary)
int slider_event(Slider *slider, const SDL_Event *event, Rect boundary, int *selected)
{
trace_assert(slider);
trace_assert(event);
@ -44,11 +44,17 @@ int slider_event(Slider *slider, const SDL_Event *event, Rect boundary)
Point position = vec((float) event->button.x, (float) event->button.y);
if (rect_contains_point(boundary, position)) {
slider->drag = 1;
if (selected) {
*selected = 1;
}
}
} break;
case SDL_MOUSEBUTTONUP: {
slider->drag = 0;
if (selected) {
*selected = 1;
}
} break;
case SDL_MOUSEMOTION: {
@ -56,6 +62,9 @@ int slider_event(Slider *slider, const SDL_Event *event, Rect boundary)
const float x = fminf(fmaxf((float) event->button.x - boundary.x, 0.0f), (float) boundary.w);
const float ratio = x / (float) boundary.w;
slider->value = ratio * slider->max_value;
if (selected) {
*selected = 1;
}
}
} break;
}

View File

@ -11,6 +11,6 @@ typedef struct Camera Camera;
typedef union SDL_Event SDL_Event;
int slider_render(const Slider *slider, Camera *camera, Rect boundary);
int slider_event(Slider *slider, const SDL_Event *event, Rect boundary);
int slider_event(Slider *slider, const SDL_Event *event, Rect boundary, int *selected);
#endif // SLIDER_H_