feat(untested): add handle dragging
This commit is contained in:
@@ -124,7 +124,7 @@ begin_click_dispatch:
|
|||||||
// selecting a tool resets the selection, so this condition
|
// selecting a tool resets the selection, so this condition
|
||||||
// should not happen
|
// should not happen
|
||||||
g_warning("Invalid selected primitive; polyline expected");
|
g_warning("Invalid selected primitive; polyline expected");
|
||||||
state->selectedShape = NULL;
|
vektor_appstate_deselect_shape(state);
|
||||||
goto begin_click_dispatch; // retry
|
goto begin_click_dispatch; // retry
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ begin_click_dispatch:
|
|||||||
|
|
||||||
} else if (state->selectedShape->primitive.kind != VEKTOR_POLYGON) {
|
} else if (state->selectedShape->primitive.kind != VEKTOR_POLYGON) {
|
||||||
g_warning("Invalid selected primitive; polygon expected");
|
g_warning("Invalid selected primitive; polygon expected");
|
||||||
state->selectedShape = NULL;
|
vektor_appstate_deselect_shape(state);
|
||||||
goto begin_click_dispatch; // retry
|
goto begin_click_dispatch; // retry
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,17 +215,19 @@ begin_click_dispatch:
|
|||||||
for (size_t i = 0; i < state->shapeBuffer->count; i++) {
|
for (size_t i = 0; i < state->shapeBuffer->count; i++) {
|
||||||
VektorBBox bbox = vektor_primitive_get_bbox(
|
VektorBBox bbox = vektor_primitive_get_bbox(
|
||||||
state->shapeBuffer->shapes[i].primitive);
|
state->shapeBuffer->shapes[i].primitive);
|
||||||
|
|
||||||
|
// expand the bbox a little so its not painful to
|
||||||
|
// try to grab handles located on the border of said bbox
|
||||||
|
bbox = vektor_bbox_expand(bbox, 0.02);
|
||||||
|
|
||||||
if (vektor_bbox_isinside(bbox, pos)) {
|
if (vektor_bbox_isinside(bbox, pos)) {
|
||||||
state->selectedShape = &(state->shapeBuffer->shapes[i]);
|
state->selectedShape = &(state->shapeBuffer->shapes[i]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// was clicked outside any shapes - reset selection
|
// was clicked outside any shapes - reset selection
|
||||||
state->selectedShape = NULL;
|
vektor_appstate_deselect_shape(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->selectedShape != NULL)
|
|
||||||
g_print("%zu\n", state->selectedShape->handleCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_appstate_canvas_drag_begin(GtkGestureDrag* gesture, gdouble x,
|
void vektor_appstate_canvas_drag_begin(GtkGestureDrag* gesture, gdouble x,
|
||||||
@@ -233,26 +235,65 @@ void vektor_appstate_canvas_drag_begin(GtkGestureDrag* gesture, gdouble x,
|
|||||||
GtkWidget* widget =
|
GtkWidget* widget =
|
||||||
gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture));
|
gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture));
|
||||||
|
|
||||||
|
VektorAppState* state = (VektorAppState*)user_data;
|
||||||
|
|
||||||
int widget_w = gtk_widget_get_width(widget);
|
int widget_w = gtk_widget_get_width(widget);
|
||||||
int widget_h = gtk_widget_get_height(widget);
|
int widget_h = gtk_widget_get_height(widget);
|
||||||
|
|
||||||
V2 normalized_coords =
|
V2 position =
|
||||||
(V2){(2 * (x / widget_w)) - 1, 1 - (2 * (y / widget_h))};
|
(V2){(2 * (x / widget_w)) - 1, 1 - (2 * (y / widget_h))};
|
||||||
|
|
||||||
|
if(state->selectedShape != NULL) {
|
||||||
|
VektorShape* selectedShape = state->selectedShape;
|
||||||
|
|
||||||
|
// get selected shape's handles and check
|
||||||
|
// if we click any of them
|
||||||
|
for(size_t i = 0; i < selectedShape->handleCount; i++) {
|
||||||
|
VektorBBox bbox = vektor_shape_get_handle_bbox(selectedShape->handles[i]);
|
||||||
|
if(vektor_bbox_isinside(bbox, position)) {
|
||||||
|
// clicked inside handle
|
||||||
|
state->heldHandleIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_appstate_canvas_drag_update(GtkGestureDrag* gesture, gdouble x,
|
void vektor_appstate_canvas_drag_update(GtkGestureDrag* gesture, gdouble x,
|
||||||
gdouble y, gpointer user_data) {
|
gdouble y, gpointer user_data) {
|
||||||
|
|
||||||
|
// ---- setup normalized coordinates (boilerplate) ----
|
||||||
gdouble start_x, start_y;
|
gdouble start_x, start_y;
|
||||||
gtk_gesture_drag_get_start_point(gesture, &start_x, &start_y);
|
gtk_gesture_drag_get_start_point(gesture, &start_x, &start_y);
|
||||||
|
|
||||||
GtkWidget* widget =
|
GtkWidget* widget =
|
||||||
gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture));
|
gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture));
|
||||||
|
|
||||||
|
VektorAppState* state = (VektorAppState*)user_data;
|
||||||
|
|
||||||
int widget_w = gtk_widget_get_width(widget);
|
int widget_w = gtk_widget_get_width(widget);
|
||||||
int widget_h = gtk_widget_get_height(widget);
|
int widget_h = gtk_widget_get_height(widget);
|
||||||
|
|
||||||
V2 norm = (V2){(2 * ((x + start_x) / widget_w)) - 1,
|
V2 position = (V2){(2 * ((x + start_x) / widget_w)) - 1,
|
||||||
1 - (2 * ((y + start_y) / widget_h))};
|
1 - (2 * ((y + start_y) / widget_h))};
|
||||||
|
|
||||||
|
// drag handle if selected
|
||||||
|
if(state->selectedShape != NULL && state->heldHandleIndex != -1) {
|
||||||
|
state->selectedShape->handles[state->heldHandleIndex] = position;
|
||||||
|
vektor_shape_handles_updated(state->selectedShape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vektor_appstate_canvas_drag_end(GtkGestureDrag* gesture, gdouble x,
|
||||||
|
gdouble y, gpointer user_data) {
|
||||||
|
|
||||||
|
VektorAppState* state = (VektorAppState*)user_data;
|
||||||
|
|
||||||
|
// if we were dragging a handle
|
||||||
|
if(state->selectedShape != NULL && state->heldHandleIndex != -1) {
|
||||||
|
state->heldHandleIndex = -1; // ...then remove handle drag flag
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) {
|
void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) {
|
||||||
@@ -292,6 +333,7 @@ void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) {
|
|||||||
stateOut->widgetState = wstate;
|
stateOut->widgetState = wstate;
|
||||||
stateOut->currentColor = vektor_color_solid(0, 0, 0);
|
stateOut->currentColor = vektor_color_solid(0, 0, 0);
|
||||||
stateOut->selectedShape = NULL;
|
stateOut->selectedShape = NULL;
|
||||||
|
stateOut->heldHandleIndex = -1;
|
||||||
|
|
||||||
VektorCanvasRenderInfo* renderInfo = malloc(sizeof(VektorCanvasRenderInfo));
|
VektorCanvasRenderInfo* renderInfo = malloc(sizeof(VektorCanvasRenderInfo));
|
||||||
renderInfo->zoom = 1;
|
renderInfo->zoom = 1;
|
||||||
@@ -351,7 +393,14 @@ void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) {
|
|||||||
G_CALLBACK(vektor_appstate_canvas_drag_update), stateOut);
|
G_CALLBACK(vektor_appstate_canvas_drag_update), stateOut);
|
||||||
g_signal_connect(G_OBJECT(canvasDragGesture), "drag-begin",
|
g_signal_connect(G_OBJECT(canvasDragGesture), "drag-begin",
|
||||||
G_CALLBACK(vektor_appstate_canvas_drag_begin), stateOut);
|
G_CALLBACK(vektor_appstate_canvas_drag_begin), stateOut);
|
||||||
|
g_signal_connect(G_OBJECT(canvasDragGesture), "drag-end",
|
||||||
|
G_CALLBACK(vektor_appstate_canvas_drag_end), stateOut);
|
||||||
|
|
||||||
gtk_widget_add_controller(GTK_WIDGET(wstate->workspaceCanvas),
|
gtk_widget_add_controller(GTK_WIDGET(wstate->workspaceCanvas),
|
||||||
GTK_EVENT_CONTROLLER(canvasDragGesture));
|
GTK_EVENT_CONTROLLER(canvasDragGesture));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vektor_appstate_deselect_shape(VektorAppState* state) {
|
||||||
|
state->heldHandleIndex = -1;
|
||||||
|
state->selectedShape = NULL;
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ typedef struct VektorAppState {
|
|||||||
|
|
||||||
VektorAppTool selectedTool;
|
VektorAppTool selectedTool;
|
||||||
VektorShape* selectedShape;
|
VektorShape* selectedShape;
|
||||||
|
int heldHandleIndex;
|
||||||
|
|
||||||
VektorColor currentColor;
|
VektorColor currentColor;
|
||||||
|
|
||||||
@@ -33,5 +34,6 @@ typedef struct VektorAppState {
|
|||||||
|
|
||||||
void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut);
|
void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut);
|
||||||
void vektor_appstate_canvas_click(VektorAppState* state, double x, double y);
|
void vektor_appstate_canvas_click(VektorAppState* state, double x, double y);
|
||||||
|
void vektor_appstate_deselect_shape(VektorAppState* state);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -207,8 +207,6 @@ void vektor_rectangle_create_handles(VektorRectangle* rectangle, V2** handleArr,
|
|||||||
|
|
||||||
V2 halfdist = vec2_scale(vec2_sub(rectangle->end, rectangle->start), 0.5f);
|
V2 halfdist = vec2_scale(vec2_sub(rectangle->end, rectangle->start), 0.5f);
|
||||||
V2 center = vec2_add(rectangle->start, halfdist);
|
V2 center = vec2_add(rectangle->start, halfdist);
|
||||||
g_print("boobs: %f %f\n", rectangle->start.x, rectangle->start.y);
|
|
||||||
g_print("pussy: %f %f\n", rectangle->end.x, rectangle->end.y);
|
|
||||||
|
|
||||||
(*handleArr)[0] = center;
|
(*handleArr)[0] = center;
|
||||||
(*handleArr)[1] = vec2_add(center, vec2_mul(halfdist, (V2){-1.0f, 1.0f}));
|
(*handleArr)[1] = vec2_add(center, vec2_mul(halfdist, (V2){-1.0f, 1.0f}));
|
||||||
@@ -238,6 +236,23 @@ void vektor_shape_create_handles(VektorShape* shape) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------ AUXILIARY HANDLE METHODS ------
|
||||||
|
|
||||||
|
|
||||||
|
void vektor_shape_add_handle(VektorShape* shape, V2 handle) {
|
||||||
|
// could be optimised with capacity property
|
||||||
|
// but this function is only called when adding new
|
||||||
|
// points to polyline and polygon, so it should
|
||||||
|
// not be that much of an overhead
|
||||||
|
shape->handles =
|
||||||
|
realloc(shape->handles, sizeof(V2) * shape->handleCount + 1);
|
||||||
|
shape->handles[shape->handleCount++] = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
VektorBBox vektor_shape_get_handle_bbox(V2 handle) {
|
||||||
|
return vektor_bbox_fromcenter(handle, 0.02);
|
||||||
|
}
|
||||||
|
|
||||||
// ------ PRIMITIVE HANDLES UPDATING ------
|
// ------ PRIMITIVE HANDLES UPDATING ------
|
||||||
|
|
||||||
void vektor_polyline_handles_updated(VektorPolyline* polyline, V2** handles,
|
void vektor_polyline_handles_updated(VektorPolyline* polyline, V2** handles,
|
||||||
@@ -335,16 +350,6 @@ void vektor_shape_handles_updated(VektorShape* shape) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_shape_add_handle(VektorShape* shape, V2 handle) {
|
|
||||||
// could be optimised with capacity property
|
|
||||||
// but this function is only called when adding new
|
|
||||||
// points to polyline and polygon, so it should
|
|
||||||
// not be that much of an overhead
|
|
||||||
shape->handles =
|
|
||||||
realloc(shape->handles, sizeof(V2) * shape->handleCount + 1);
|
|
||||||
shape->handles[shape->handleCount++] = handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------ BBOX METHODS ------
|
// ------ BBOX METHODS ------
|
||||||
|
|
||||||
bool vektor_bbox_isinside(VektorBBox bbox, V2 point) {
|
bool vektor_bbox_isinside(VektorBBox bbox, V2 point) {
|
||||||
|
|||||||
@@ -108,7 +108,10 @@ void vektor_circle_create_handles(VektorCircle* circle, V2** handleArr,
|
|||||||
void vektor_rectangle_create_handles(VektorRectangle* rectangle, V2** handleArr,
|
void vektor_rectangle_create_handles(VektorRectangle* rectangle, V2** handleArr,
|
||||||
size_t* count);
|
size_t* count);
|
||||||
void vektor_shape_create_handles(VektorShape* shape);
|
void vektor_shape_create_handles(VektorShape* shape);
|
||||||
|
|
||||||
|
|
||||||
void vektor_shape_add_handle(VektorShape* shape, V2 handle);
|
void vektor_shape_add_handle(VektorShape* shape, V2 handle);
|
||||||
|
VektorBBox vektor_shape_get_handle_bbox(V2 handle);
|
||||||
|
|
||||||
/* reconstructs the shape based on handles alone */
|
/* reconstructs the shape based on handles alone */
|
||||||
void vektor_polyline_handles_updated(VektorPolyline* polyline, V2** handles,
|
void vektor_polyline_handles_updated(VektorPolyline* polyline, V2** handles,
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ static gboolean render(GtkGLArea* a, GdkGLContext* ctx,
|
|||||||
// create handle quads if a shape is selected
|
// create handle quads if a shape is selected
|
||||||
for (size_t i = 0; i < selectedShape->handleCount; i++) {
|
for (size_t i = 0; i < selectedShape->handleCount; i++) {
|
||||||
V2 handle = selectedShape->handles[i];
|
V2 handle = selectedShape->handles[i];
|
||||||
VektorBBox handleBbox = vektor_bbox_fromcenter(handle, 0.01f);
|
VektorBBox handleBbox = vektor_shape_get_handle_bbox(handle);
|
||||||
vektor_vb_add_quad(&vb, handleBbox.min, handleBbox.max,
|
vektor_vb_add_quad(&vb, handleBbox.min, handleBbox.max,
|
||||||
vektor_color_new(255, 255, 255, 255));
|
vektor_color_new(255, 255, 255, 255));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user