diff --git a/src/application/applicationstate.c b/src/application/applicationstate.c index 0fdf3e5..28b5735 100644 --- a/src/application/applicationstate.c +++ b/src/application/applicationstate.c @@ -1,3 +1,6 @@ +#include "src/ui/uicontroller.h" +#include "stdlib.h" + #include "./applicationstate.h" #include "glib.h" #include "gtk/gtk.h" @@ -39,10 +42,32 @@ static void appstate_on_color_change(VektorColorWheel* wheel, gpointer user_data if(appstate->selectedShape != NULL) { appstate->selectedShape->style.stroke_color = c; } + + // set entry fields under the color selector + char *str_r, *str_g, *str_b; + str_r = g_strdup_printf("%d", c.r); + str_g = g_strdup_printf("%d", c.g); + str_b = g_strdup_printf("%d", c.b); + gtk_editable_set_text(GTK_EDITABLE(appstate->widgetState->sidepanelEntryR), str_r); + gtk_editable_set_text(GTK_EDITABLE(appstate->widgetState->sidepanelEntryG), str_g); + gtk_editable_set_text(GTK_EDITABLE(appstate->widgetState->sidepanelEntryB), str_b); gtk_gl_area_queue_render(GTK_GL_AREA(appstate->widgetState->workspaceCanvas)); } +static void appstate_on_entry_update(GtkEntry* entry, gpointer user_data) { + VektorWidgetState* widgetState = (VektorWidgetState*)user_data; + unsigned char r = (unsigned char)atoi(gtk_editable_get_text(GTK_EDITABLE(widgetState->sidepanelEntryR))); + unsigned char g = (unsigned char)atoi(gtk_editable_get_text(GTK_EDITABLE(widgetState->sidepanelEntryG))); + unsigned char b = (unsigned char)atoi(gtk_editable_get_text(GTK_EDITABLE(widgetState->sidepanelEntryB))); + + g_print("%d", r); + vektor_color_wheel_set_color( + VEKTOR_COLOR_WHEEL(widgetState->workspaceColorPicker), + (VektorColor){.r = r, .g = g, .b = b} + ); +} + static void canvas_onclick(GtkGestureClick* gesture, int n_press, double x, double y, gpointer user_data) { @@ -139,6 +164,15 @@ void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) { g_signal_connect(G_OBJECT(wstate->workspaceColorPicker), "color-changed", G_CALLBACK(appstate_on_color_change), stateOut); + // hook rgb entries change + g_signal_connect(G_OBJECT(wstate->sidepanelEntryR), "activate", + G_CALLBACK(appstate_on_entry_update), stateOut->widgetState); + g_signal_connect(G_OBJECT(wstate->sidepanelEntryG), "activate", + G_CALLBACK(appstate_on_entry_update), stateOut->widgetState); + g_signal_connect(G_OBJECT(wstate->sidepanelEntryB), "activate", + G_CALLBACK(appstate_on_entry_update), stateOut->widgetState); + + // Add click gesture to canvas GtkGesture* canvasClickGesture = gtk_gesture_click_new(); g_signal_connect(G_OBJECT(canvasClickGesture), "pressed", diff --git a/src/ui/uicontroller.c b/src/ui/uicontroller.c index f211339..461ba46 100644 --- a/src/ui/uicontroller.c +++ b/src/ui/uicontroller.c @@ -41,6 +41,8 @@ void vektor_uictrl_init(GtkApplication* app, VektorWidgetState* stateOut) { GTK_WINDOW(gtk_builder_get_object(builder, "main_window")); stateOut->workspacePaned = GTK_PANED(gtk_builder_get_object(builder, "workspace_paned")); + stateOut->sidepanelPaned = + GTK_PANED(gtk_builder_get_object(builder, "sidepanel")); stateOut->workspaceCanvas = GTK_GL_AREA(gtk_builder_get_object(builder, "workspace")); @@ -57,6 +59,13 @@ void vektor_uictrl_init(GtkApplication* app, VektorWidgetState* stateOut) { stateOut->workspaceColorPicker = VEKTOR_COLOR_WHEEL(gtk_builder_get_object(builder, "color_picker")); + stateOut->sidepanelEntryR = + GTK_ENTRY(gtk_builder_get_object(builder, "spin_color_r")); + stateOut->sidepanelEntryG = + GTK_ENTRY(gtk_builder_get_object(builder, "spin_color_g")); + stateOut->sidepanelEntryB = + GTK_ENTRY(gtk_builder_get_object(builder, "spin_color_b")); + // Set window properties gtk_window_set_application(stateOut->window, app); gtk_window_set_title(stateOut->window, "Vektor"); @@ -67,4 +76,5 @@ void vektor_uictrl_init(GtkApplication* app, VektorWidgetState* stateOut) { void vektor_uictrl_map(VektorWidgetState* state) { gtk_paned_set_position(state->workspacePaned, 800 * .7); + gtk_paned_set_position(state->sidepanelPaned, 250); } diff --git a/src/ui/uicontroller.h b/src/ui/uicontroller.h index fa600e4..dc443e3 100644 --- a/src/ui/uicontroller.h +++ b/src/ui/uicontroller.h @@ -12,6 +12,7 @@ all the widgets used in internal logic of the program typedef struct VektorWidgetState { GtkWindow* window; GtkPaned* workspacePaned; + GtkPaned* sidepanelPaned; GtkGLArea* workspaceCanvas; GtkButton* workspaceButtonMasterShapes; @@ -22,6 +23,10 @@ typedef struct VektorWidgetState { VektorColorWheel* workspaceColorPicker; + GtkEntry* sidepanelEntryR; + GtkEntry* sidepanelEntryG; + GtkEntry* sidepanelEntryB; + // GtkWidget* Workspace } VektorWidgetState; diff --git a/src/ui/widgets/colorwheel.c b/src/ui/widgets/colorwheel.c index 2f8693c..baa27ad 100644 --- a/src/ui/widgets/colorwheel.c +++ b/src/ui/widgets/colorwheel.c @@ -45,6 +45,51 @@ static gboolean point_in_triangle( return (*u >= 0 && *v >= 0 && *w >= 0); } +static void closest_point_on_segment( + double px, double py, + double ax, double ay, + double bx, double by, + double *rx, double *ry) +{ + double abx = bx - ax; + double aby = by - ay; + + double apx = px - ax; + double apy = py - ay; + + double t = (apx*abx + apy*aby) / (abx*abx + aby*aby); + + if (t < 0) t = 0; + if (t > 1) t = 1; + + *rx = ax + abx * t; + *ry = ay + aby * t; +} + +static void closest_point_on_triangle( + double px, double py, + double ax, double ay, + double bx, double by, + double cx, double cy, + double *rx, double *ry) +{ + double p1x,p1y; + double p2x,p2y; + double p3x,p3y; + + closest_point_on_segment(px,py, ax,ay, bx,by, &p1x,&p1y); + closest_point_on_segment(px,py, bx,by, cx,cy, &p2x,&p2y); + closest_point_on_segment(px,py, cx,cy, ax,ay, &p3x,&p3y); + + double d1 = (px-p1x)*(px-p1x) + (py-p1y)*(py-p1y); + double d2 = (px-p2x)*(px-p2x) + (py-p2y)*(py-p2y); + double d3 = (px-p3x)*(px-p3x) + (py-p3y)*(py-p3y); + + if (d1 <= d2 && d1 <= d3) { *rx = p1x; *ry = p1y; } + else if (d2 <= d3) { *rx = p2x; *ry = p2y; } + else { *rx = p3x; *ry = p3y; } +} + static void vektor_color_wheel_snapshot(GtkWidget* widget, GtkSnapshot* snapshot) { VektorColorWheel* self = VEKTOR_COLOR_WHEEL(widget); @@ -147,7 +192,7 @@ static void vektor_color_wheel_snapshot(GtkWidget* widget, GtkSnapshot* snapshot cairo_arc(cr, px, py, 5, 0, 2*M_PI); float fr, fg, fb; - vektor_colorout_wheel_get_color(self, &fr, &fg, &fb); + vektor_color_wheel_get_colorout(self, &fr, &fg, &fb); cairo_set_source_rgb(cr, fr, fg, fb); cairo_fill_preserve(cr); cairo_set_source_rgb(cr, 0.1, 0.1, 0.1); @@ -206,7 +251,8 @@ static void on_click(GtkGestureClick* gesture, int n_press, double x, double y, double cy2 = cy - 0.866 * triangle_radius; double u,v,w; - if(point_in_triangle(x,y, ax,ay, bx,by, cx2,cy2, &u,&v,&w)) { + gboolean inside = point_in_triangle(x,y, ax,ay, bx,by, cx2,cy2, &u,&v,&w); + if(inside) { // pick point in the triangle double denom = u + v; if (denom > 0.0001) { // avoid div-by-zero at black vertex @@ -222,14 +268,41 @@ static void on_click(GtkGestureClick* gesture, int n_press, double x, double y, double dy = y - cy; double dist = sqrt(dx*dx+dy*dy); - if(dist > inner_radius && dist < outer_radius) { + if(dist > inner_radius && dist < outer_radius) { // pick point on color wheel double angle = atan2(dy, dx); if(angle < 0) { angle += 2 * M_PI; } wheel->hue = angle / (2*M_PI); g_signal_emit(wheel, signals[COLOR_CHANGED], 0); + + } else if (dist < inner_radius) { // snap to triangle edge + double sx,sy; + + closest_point_on_triangle( + x,y, + ax,ay, + bx,by, + cx2,cy2, + &sx,&sy + ); + + x = sx; + y = sy; + + point_in_triangle(x,y, ax,ay, bx,by, cx2,cy2, &u,&v,&w); + + // calculate triangle point + double denom = u + v; + if (denom > 0.0001) { + wheel->saturation = u / denom; + } else { + wheel->saturation = 0.0; + } + wheel->lightness = denom; + g_signal_emit(wheel, signals[COLOR_CHANGED], 0); } + } gtk_widget_queue_draw(widget); @@ -293,9 +366,20 @@ VektorColor vektor_color_wheel_get_color(VektorColorWheel* wheel) { }; } -void vektor_colorout_wheel_get_color(VektorColorWheel* wheel, float* r, float* g, float* b) { +void vektor_color_wheel_get_colorout(VektorColorWheel* wheel, float* r, float* g, float* b) { gtk_hsv_to_rgb(wheel->hue, wheel->saturation, wheel->lightness, r, g, b); +} + +void vektor_color_wheel_set_color(VektorColorWheel* wheel, VektorColor c) { + float h,s,v; + gtk_rgb_to_hsv(c.r/255.0, c.g/255.0, c.b/255.0, &h, &s, &v); + wheel->hue = (float)h; + wheel->saturation = (float)s; + wheel->lightness = (float)v; + + gtk_widget_queue_draw(GTK_WIDGET(wheel)); + g_signal_emit(wheel, signals[COLOR_CHANGED], 0); } \ No newline at end of file diff --git a/src/ui/widgets/colorwheel.h b/src/ui/widgets/colorwheel.h index 3ddc952..0259d7c 100644 --- a/src/ui/widgets/colorwheel.h +++ b/src/ui/widgets/colorwheel.h @@ -9,6 +9,7 @@ G_DECLARE_FINAL_TYPE(VektorColorWheel, vektor_color_wheel, VEKTOR, COLOR_WHEEL, GtkWidget* vektor_color_wheel_new(void); VektorColor vektor_color_wheel_get_color(VektorColorWheel* wheel); -void vektor_colorout_wheel_get_color(VektorColorWheel* wheel, float* r, float* g, float* b); +void vektor_color_wheel_get_colorout(VektorColorWheel* wheel, float* r, float* g, float* b); +void vektor_color_wheel_set_color(VektorColorWheel* wheel, VektorColor c); #endif \ No newline at end of file diff --git a/ui/main.ui b/ui/main.ui index d2028d1..829ad38 100644 --- a/ui/main.ui +++ b/ui/main.ui @@ -148,10 +148,68 @@ 6 - - true - true + + vertical + + + + true + true + + + + + + horizontal + center + + + + R + 6 + 6 + + + + + + 0 + + + + + + G + 6 + 6 + + + + + + 0 + + + + + + B + 6 + 6 + + + + + + 0 + + + + + + +