From 511bf724271b13f6bfc7ac25b8a1c3c8ae2120c3 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Mon, 12 Dec 2022 21:03:32 -0600 Subject: [PATCH] Color selection working! Palette is next. --- CMakeLists.txt | 21 ++++---- src/color.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++++ src/color.h | 41 +++++++++++++++ src/vector.c | 111 ++++++++++++++++++++------------------- 4 files changed, 244 insertions(+), 66 deletions(-) create mode 100644 src/color.c create mode 100644 src/color.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 40449b5..f7085f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,16 +26,17 @@ project(joeydev C) set(CMAKE_C_STANDARD 99) set(SOURCE_FILES - src/main.c - src/utils.c - src/joeydev.c - src/vector.c - src/array.c - src/draw.c - src/image.c - src/vecparse.c - ui/generated/resources.c - thirdparty/memwatch/memwatch.c + thirdparty/memwatch/memwatch.c + ui/generated/resources.c + src/main.c + src/utils.c + src/joeydev.c + src/vector.c + src/array.c + src/draw.c + src/image.c + src/vecparse.c + src/color.c ) add_executable(${CMAKE_PROJECT_NAME} ${SOURCE_FILES}) diff --git a/src/color.c b/src/color.c new file mode 100644 index 0000000..c266e3e --- /dev/null +++ b/src/color.c @@ -0,0 +1,137 @@ +/* + * JoeyDev + * Copyright (C) 2018-2023 Scott Duensing + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "common.h" +#include "color.h" + + +typedef struct ColorDialogDataS { + GtkWidget *buttons[16]; + int selected; +} ColorDialogDataT; + + +static void addCss(GtkWidget *widget, char *css); +EVENT void colorClicked(GtkButton *widget, gpointer userData); +EVENT gboolean colorDialogClose(GtkWidget *object, GdkEvent *event, gpointer userData); + + +static void addCss(GtkWidget *widget, char *css) { + GtkCssProvider *provider; + GtkStyleContext *context; + + provider = gtk_css_provider_new(); + gtk_css_provider_load_from_data(provider, css, -1,NULL); + context = gtk_widget_get_style_context(widget); + gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider),GTK_STYLE_PROVIDER_PRIORITY_USER); + g_object_unref(provider); +} + + +EVENT void colorClicked(GtkButton *widget, gpointer userData) { + ColorDialogDataT *self = (ColorDialogDataT *)userData; + int i; + char *borderOn = "* { border-width: 3px; border-color: white; }"; + char *borderOff = "* { border-width: 0px; }"; + + for (i=0; i<16; i++) { + if (widget == GTK_BUTTON(self->buttons[i])) { + if (self->selected >= 0) { + addCss(self->buttons[self->selected], borderOff); + } + self->selected = i; + addCss(self->buttons[self->selected], borderOn); + } + } +} + + +EVENT gboolean colorDialogClose(GtkWidget *object, GdkEvent *event, gpointer userData) { + ColorDialogDataT *self = g_object_get_data(G_OBJECT(object), "colorData"); + + (void)event; + (void)userData; + + DEL(self); + + return FALSE; +} + + +int color_dialog_get_selected(GtkWidget *colorDialog) { + ColorDialogDataT *self = g_object_get_data(G_OBJECT(colorDialog), "colorData"); + + return self->selected; +} + + +GtkWidget *color_dialog_new(GtkWidget *parent, ColorT colors[]) { + GtkWidget *dialog; + GtkWidget *contentArea; + GtkWidget *grid; + char temp[256]; + int x; + int y; + int i; + ColorDialogDataT *self; + + self = NEW(ColorDialogDataT); + self->selected = -1; + + grid = gtk_grid_new(); + gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE); + gtk_grid_set_row_homogeneous(GTK_GRID(grid), TRUE); + i = 0; + for (y=0; y<4; y++) { + for (x=0; x<4; x++) { + self->buttons[i] = gtk_button_new(); + gtk_widget_set_hexpand(self->buttons[i], TRUE); + gtk_widget_set_vexpand(self->buttons[i], TRUE); + g_signal_connect(G_OBJECT(self->buttons[i]), "clicked", G_CALLBACK(colorClicked), self); + snprintf(temp, 256, "* { background-image:none; background-color: #%02x%02x%02x; }", colors[i].red, colors[i].green, colors[i].blue); + addCss(self->buttons[i], temp); + gtk_grid_attach(GTK_GRID (grid), self->buttons[i], x, y, 1, 1); + + i++; + } + } + + dialog = gtk_dialog_new_with_buttons("Color", + GTK_WINDOW(parent), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + "_Cancel", + GTK_RESPONSE_CANCEL, + "_Select", + GTK_RESPONSE_OK, + NULL + ); + + g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(colorDialogClose), self); + g_object_set_data(G_OBJECT(dialog), "colorData", self); + gtk_widget_set_size_request(dialog, 320, 320); + contentArea = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + gtk_container_add(GTK_CONTAINER(contentArea), grid); + + gtk_widget_show_all(dialog); + + return dialog; +} diff --git a/src/color.h b/src/color.h new file mode 100644 index 0000000..3c0d526 --- /dev/null +++ b/src/color.h @@ -0,0 +1,41 @@ +/* + * JoeyDev + * Copyright (C) 2018-2023 Scott Duensing + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef COLOR_H +#define COLOR_H + + +#include "common.h" + + +typedef struct ColorS { + unsigned char red; + unsigned char green; + unsigned char blue; +} ColorT; + + +int color_dialog_get_selected(GtkWidget *colorDialog); +GtkWidget *color_dialog_new(GtkWidget *parent, ColorT colors[]); + + +#endif //COLOR_H diff --git a/src/vector.c b/src/vector.c index eb43f9b..37f4988 100644 --- a/src/vector.c +++ b/src/vector.c @@ -34,6 +34,7 @@ #include "draw.h" #include "image.h" #include "vecparse.h" +#include "color.h" #define VICTOR_VERSION "1.00" @@ -105,6 +106,7 @@ EVENT gboolean drawVectorImageDraw(GtkWidget *widget, cairo_t *cr, gpointer use EVENT gboolean drawVectorImageMotionEvent(GtkWidget *widget, GdkEventMotion *event, gpointer userData); EVENT void editorVectorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotification *notifyData, gpointer userData); EVENT void fileVectorTraceImageFileSet(GtkWidget *object, gpointer userData); +static int findClosestPoint(VectorDataT *self, int x, int y); static int getWord(VecByteCodeT *bytecode, int *index); static void insertCommand(VectorDataT *self, char *command); static void insertText(VectorDataT *self, char *text); @@ -181,7 +183,8 @@ EVENT void drawVectorImageClick(GtkWidget *object, GdkEventButton *event, gpoint switch (self->clickState) { case CLICK_NONE: - // Do nothing. + // Highlight the closest point in editor. + findClosestPoint(self, x, y); break; case CLICK_BOX_1: @@ -340,12 +343,9 @@ EVENT gboolean drawVectorImageDraw(GtkWidget *widget, cairo_t *cr, gpointer user EVENT gboolean drawVectorImageMotionEvent(GtkWidget *widget, GdkEventMotion *event, gpointer userData) { VectorDataT *self = (VectorDataT *)userData; - int closest = -1; - int distance = INT_MAX; int x = (int)(event->x * 0.5); int y = (int)(event->y * 0.5); int temp; - int i; char buffer[8]; // If we're in a drawing action, bail out of this. @@ -354,34 +354,16 @@ EVENT gboolean drawVectorImageMotionEvent(GtkWidget *widget, GdkEventMotion *eve // If they're holding the button down, update the point. if (event->state & GDK_BUTTON1_MASK) { - // Find closest point to mouse pointer. - for (i = 0; i < arrlen(self->pointList); i++) { - temp = sqrt(pow(x - self->pointList[i]->x, 2) + pow(y - self->pointList[i]->y, 2)); - if (temp < distance) { - closest = i; - distance = temp; - } - } - - // Did we find a point to edit? - if (closest >= 0) { - // Select first occurrence of it in the text editor. - snprintf(buffer, 8, "%d,%d", self->pointList[closest]->x, self->pointList[closest]->y); - SSM(SCI_TARGETWHOLEDOCUMENT, 0, 0); - SSM(SCI_SETSEARCHFLAGS, SCFIND_NONE, 0); - temp = SSM(SCI_SEARCHINTARGET, strlen(buffer), (sptr_t)buffer); - // Did we find it in the text? - if (temp >= 0) { - // Select the text. - SSM(SCI_SETSEL, temp, temp + strlen(buffer)); - // Are these values sane? - if (x < 0) x = 0; - if (x > 319) x = 319; - if (y < 0) y = 0; - if (y > 199) y = 199; - snprintf(buffer, 8, "%d,%d", x, y); - SSM(SCI_REPLACETARGET, -1, (sptr_t)buffer); - } + // Did we find it in the text? + temp = findClosestPoint(self, x, y); + if (temp >= 0) { + // Are these values sane? + if (x < 0) x = 0; + if (x > 319) x = 319; + if (y < 0) y = 0; + if (y > 199) y = 199; + snprintf(buffer, 8, "%d,%d", x, y); + SSM(SCI_REPLACETARGET, -1, (sptr_t)buffer); } } @@ -465,6 +447,37 @@ EVENT void fileVectorTraceImageFileSet(GtkWidget *object, gpointer userData) { } +static int findClosestPoint(VectorDataT *self, int x, int y) { + int closest = -1; + int distance = INT_MAX; + int temp; + int i; + char buffer[8]; + + // Find closest point to mouse pointer. + for (i = 0; i < arrlen(self->pointList); i++) { + temp = sqrt(pow(x - self->pointList[i]->x, 2) + pow(y - self->pointList[i]->y, 2)); + if (temp < distance) { + closest = i; + distance = temp; + } + } + + // Did we find a point to edit? + if (closest >= 0) { + // Find first occurrence of it in the text editor. + snprintf(buffer, 8, "%d,%d", self->pointList[closest]->x, self->pointList[closest]->y); + SSM(SCI_TARGETWHOLEDOCUMENT, 0, 0); + SSM(SCI_SETSEARCHFLAGS, SCFIND_NONE, 0); + temp = SSM(SCI_SEARCHINTARGET, strlen(buffer), (sptr_t)buffer); + // Select the text. + SSM(SCI_SETSEL, temp, temp + strlen(buffer)); + return temp; + } + + return -1; +} + static int getWord(VecByteCodeT *bytecode, int *index) { int word; @@ -1240,42 +1253,28 @@ EVENT void toolCircleClicked(GtkToolButton *object, gpointer userData) { EVENT void toolColorClicked(GtkToolButton *object, gpointer userData) { VectorDataT *self = (VectorDataT *)userData; GtkWidget *dialog; - GdkRGBA colors[16]; - GdkRGBA selected; + ColorT colors[16]; char temp[4]; int i; - unsigned char r; - unsigned char g; - unsigned char b; - double scale = 1.0/256.0; (void)object; // Load the current JoeyLib palette into the dialog. for (i=0; i<16; i++) { - jlPaletteGet(self->jlc, i, &r, &g, &b); - colors[i].alpha = 1.0; - colors[i].red = (double)r * scale; - colors[i].green = (double)g * scale; - colors[i].blue = (double)b * scale; + jlPaletteGet(self->jlc, i, &colors[i].red, &colors[i].green, &colors[i].blue); } // Build the dialog. - dialog = gtk_color_chooser_dialog_new("Color", GTK_WINDOW(self->windowData.window)); - g_object_set (dialog, "show-editor", FALSE, NULL); - gtk_color_chooser_add_palette(GTK_COLOR_CHOOSER(dialog), GTK_ORIENTATION_HORIZONTAL, 4, 16, colors); + dialog = color_dialog_new(self->windowData.window, colors); // Run the dialog. - if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL) { - // Figure out which color index they selected. - gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &selected); - for (i=0; i<16; i++) { - if (colors[i].red == selected.red && colors[i].green == selected.green && colors[i].blue == selected.blue) { - // Write our selected color into the editor. - snprintf(temp, 4, " %d", i); - insertCommand(self, "COLOR"); - insertText(self, temp); - } + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) { + i = color_dialog_get_selected(dialog); + if (i >= 0) { + // Write our selected color into the editor. + snprintf(temp, 4, " %d", i); + insertCommand(self, "color"); + insertText(self, temp); } }