colourpicker

Simple Colour Picker written in C
git clone anongit@rnpnr.xyz:colourpicker.git
Log | Files | Refs | Feed | Submodules | README | LICENSE

Commit: 4c2545a25a1029b986dc7165db81ddff0ec516aa
Parent: 8e4d0f1457ef72ba9568d858e8c0ea65fefb2d08
Author: Randy Palamar
Date:   Sat,  8 Jun 2024 11:35:30 -0600

draw modifiable sliders

Diffstat:
Mcolourpicker.c | 152+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Mmain.c | 9++++++++-
Mutil.c | 25+++++++++++++++++++++++++
3 files changed, 170 insertions(+), 16 deletions(-)

diff --git a/colourpicker.c b/colourpicker.c @@ -2,6 +2,124 @@ #include <raylib.h> #include "util.c" +static v2 +center_text_in_rect(Rect r, const char *text, Font font, f32 fontsize) +{ + v2 ts = { .rv = MeasureTextEx(font, text, fontsize, 0) }; + v2 delta = { .w = r.size.w - ts.w, .h = r.size.h - ts.h }; + return (v2) { + .x = r.pos.x + 0.5 * delta.w, + .y = r.pos.y + 0.5 * delta.h, + }; +} + +static Rect +cut_rect_middle(Rect r, f32 left, f32 right) +{ + ASSERT(left <= right); + r.pos.x += r.size.w * left; + r.size.w = r.size.w * (right - left); + return r; +} + +static Rect +cut_rect_left(Rect r, f32 fraction) +{ + r.size.w *= fraction; + return r; +} + +static Rect +cut_rect_right(Rect r, f32 fraction) +{ + r.pos.x += fraction * r.size.w; + r.size.w *= (1 - fraction); + return r; +} + +static f32 +do_slider(Rect r, char *label, f32 current, Font font) +{ + Rect lr = cut_rect_left(r, 0.1); + Rect vr = cut_rect_right(r, 0.85); + + Rect sr = cut_rect_middle(r, 0.1, 0.85); + sr.size.h *= 0.75; + sr.pos.y += r.size.h * 0.125; + + v2 fpos = center_text_in_rect(lr, label, font, 48); + DrawTextEx(font, label, fpos.rv, 48, 0, LIGHTGRAY); + + v2 mouse = { .rv = GetMousePosition() }; + if (CheckCollisionPointRec(mouse.rv, sr.rr)) { + f32 wheel = GetMouseWheelMove(); + if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) + current = (mouse.x - sr.pos.x) / sr.size.w; + current += 4 * wheel / sr.size.w; + CLAMP(current, 0.0, 1.0); + } + + DrawRectangleRounded(sr.rr, 1.0, 0, PURPLE); + v2 start = { + .x = sr.pos.x + current * sr.size.w, + .y = sr.pos.y + sr.size.h, + }; + v2 end = start; + end.y -= sr.size.h; + DrawLineEx(start.rv, end.rv, 8, BLACK); + + const char *value = TextFormat("%0.02f", current); + fpos = center_text_in_rect(vr, value, font, 36); + DrawTextEx(font, value, fpos.rv, 36, 0, LIGHTGRAY); + + return current; +} + +static enum colour_picker_mode +do_status_bar(Rect r, enum colour_picker_mode mode, Color colour, Font font) +{ + Rect hr = cut_rect_left(r, 0.5); + Rect sr = cut_rect_right(r, 0.7); + + const char *hex = TextFormat("%02x%02x%02x%02x", + colour.r, colour.b, colour.g, + colour.a); + v2 fpos = center_text_in_rect(hr, hex, font, 48); + DrawTextEx(font, hex, fpos.rv, 48, 0, LIGHTGRAY); + + v2 mouse = { .rv = GetMousePosition() }; + + if (CheckCollisionPointRec(mouse.rv, hr.rr)) { + if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) + SetClipboardText(hex); + } + + if (CheckCollisionPointRec(mouse.rv, sr.rr)) { + if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { + if (mode == HSV) + mode = RGB; + else + mode++; + } + if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) { + if (mode == RGB) + mode = HSV; + else + mode--; + } + } + + char *mtext; + switch (mode) { + case RGB: mtext = "RGB"; break; + case HSV: mtext = "HSV"; break; + } + fpos = center_text_in_rect(sr, mtext, font, 48); + DrawTextEx(font, mtext, fpos.rv, 48, 0, LIGHTGRAY); + + return mode; +} + void do_colour_picker(ColourPickerCtx *ctx) { @@ -9,12 +127,12 @@ do_colour_picker(ColourPickerCtx *ctx) DrawFPS(20, 20); uv2 ws = ctx->window_size; + Color colour = ColorFromNormalized(ctx->colour.rv); { v2 cc = { .x = (f32)ws.w / 2, .y = (f32)ws.h / 4 }; DrawCircleSector(cc.rv, 0.6 * cc.x, 0, 360, 69, RED); - DrawCircleSector(cc.rv, 0.58 * cc.x, 0, 360, 69, BLACK); - DrawText("Hello World!", ws.w * 0.3, ws.h / 4, 48, BLUE); + DrawCircleSector(cc.rv, 0.58 * cc.x, 0, 360, 69, colour); } { @@ -24,24 +142,28 @@ do_colour_picker(ColourPickerCtx *ctx) } { - v2 subregion = { - .x = (f32)ws.w * 0.9, - .y = (f32)ws.h / 2 * 0.9, + Rect subregion = { + .pos = { .x = 0.05 * (f32)ws.w, .y = (f32)ws.h / 2, }, + .size = { .w = (f32)ws.w * 0.9, .h = (f32)ws.h / 2 * 0.9 }, }; - v2 starting_pos = { - .x = 0.05 * (f32)ws.w, - .y = (f32)ws.h / 2 + 0.25 * ((f32)ws.h / 2), - }; + Rect sb = subregion; + sb.size.h *= 0.25; + ctx->mode = do_status_bar(sb, ctx->mode, colour, ctx->font); + + Rect r = subregion; + r.pos.y += 0.25 * ((f32)ws.h / 2); + r.size.h *= 0.15; - v2 size = { .x = subregion.x, .y = 0.15 * subregion.y }; + ctx->colour.r = do_slider(r, "R:", ctx->colour.r, ctx->font); - DrawRectangleV(starting_pos.rv, size.rv, DARKGREEN); + r.pos.y += r.size.h + 0.03 * ((f32)ws.h / 2); + ctx->colour.g = do_slider(r, "G:", ctx->colour.g, ctx->font); - starting_pos.y += size.y + 0.1 * ((f32)ws.h / 2); - DrawRectangleV(starting_pos.rv, size.rv, DARKGREEN); + r.pos.y += r.size.h + 0.03 * ((f32)ws.h / 2); + ctx->colour.b = do_slider(r, "B:", ctx->colour.b, ctx->font); - starting_pos.y += size.y + 0.1 * ((f32)ws.h / 2); - DrawRectangleV(starting_pos.rv, size.rv, DARKGREEN); + r.pos.y += r.size.h + 0.03 * ((f32)ws.h / 2); + ctx->colour.a = do_slider(r, "A:", ctx->colour.a, ctx->font); } } diff --git a/main.c b/main.c @@ -2,6 +2,7 @@ #include <dlfcn.h> #include <fcntl.h> #include <raylib.h> +#include <stdio.h> #include <sys/stat.h> #include "util.c" @@ -11,6 +12,8 @@ typedef struct timespec Filetime; static const char *libname = "./libcolourpicker.so"; static void *libhandle; +static const char *fontpath = "/home/rnp/.local/share/fonts/Aozora Mincho Medium.ttf"; + typedef void (do_colour_picker_fn)(ColourPickerCtx *); static do_colour_picker_fn *do_colour_picker; @@ -35,18 +38,22 @@ load_library(const char *lib) dlclose(libhandle); libhandle = dlopen(lib, RTLD_NOW|RTLD_LOCAL); do_colour_picker = dlsym(libhandle, "do_colour_picker"); + if (!libhandle || !do_colour_picker) + fprintf(stderr, "Couldn't Hot Reload ColourPicker\n"); } int main(void) { - ColourPickerCtx ctx; + ColourPickerCtx ctx = {0}; ctx.window_size = (uv2){.w = 720, .h = 960}; SetConfigFlags(FLAG_VSYNC_HINT); InitWindow(ctx.window_size.w, ctx.window_size.h, "Colour Picker"); load_library(libname); + ctx.font = LoadFontEx(fontpath, 128, 0, 0); + Filetime updated_time = get_filetime(libname); while(!WindowShouldClose()) { BeginDrawing(); diff --git a/util.c b/util.c @@ -2,6 +2,8 @@ #include <stddef.h> #include <stdint.h> +#define ASSERT(c) do { if (!(c)) __builtin_debugtrap(); } while (0); + typedef int32_t i32; typedef uint32_t u32; typedef float f32; @@ -16,10 +18,33 @@ typedef union { typedef union { struct { f32 x, y; }; + struct { f32 w, h; }; Vector2 rv; f32 E[2]; } v2; +typedef union { + struct { f32 x, y, z, w; }; + struct { f32 r, g, b, a; }; + Vector4 rv; + f32 E[4]; +} v4; + +typedef union { + struct { v2 pos, size; }; + Rectangle rr; +} Rect; + +enum colour_picker_mode { + RGB, + HSV, +}; + typedef struct { uv2 window_size; + Font font; + v4 colour; + enum colour_picker_mode mode; } ColourPickerCtx; + +#define CLAMP(x, a, b) ((x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x))