[gimp/wip/gradient-edit: 4/42] app: add persistent handle selection to GimpToolLine
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/gradient-edit: 4/42] app: add persistent handle selection to GimpToolLine
- Date: Fri, 6 Oct 2017 19:40:50 +0000 (UTC)
commit eb18e3ee7caa5395adf71c44c9104a17b6ba0ae5
Author: Ell <ell_se yahoo com>
Date: Wed Jul 19 14:48:09 2017 -0400
app: add persistent handle selection to GimpToolLine
En route to on-canvas gradient editing, add support for persistent
handle selection to GimpToolLine (a handle being either an endpoint
or a slider). Handles are selected through clicking, however,
unlike before, the selection persists after the mouse is released.
A new "selection" property specifies the currently-selected handle
(who knows, maybe in the future we'll add multi-selection), and a
new "selection-changed" signal is emitted when the selection changes.
The visual feedback has been changed to better suit the new behavior,
and the behaviors yet to be added: The selected handle is marked
using highlighting; the highlighting doesn't change while hovering
over other handles. Only the hit-test circle is used as hover
indication, however, we use a fixed-size circle, and only show the
circle for the currently hovered-over handle -- no more trippy
expanding circles :)
A few minor changes along the way:
- The selected handle is now the (first) one that's closest to the
cursor, instead of the first one to pass hit-testing.
- We don't move the selectd handle upon button-press, only upon
motion, so that handles can be selected without moving them.
- Show a MOVE cursor modifier when hovering over a handle.
app/display/gimptoolline.c | 582 ++++++++++++++++++++++++++------------------
app/display/gimptoolline.h | 40 +++-
2 files changed, 370 insertions(+), 252 deletions(-)
---
diff --git a/app/display/gimptoolline.c b/app/display/gimptoolline.c
index 6f9ddaf..d37fd4e 100644
--- a/app/display/gimptoolline.c
+++ b/app/display/gimptoolline.c
@@ -35,6 +35,7 @@
#include "widgets/gimpwidgets-utils.h"
+#include "gimpcanvasgroup.h"
#include "gimpcanvashandle.h"
#include "gimpcanvasline.h"
#include "gimpdisplayshell.h"
@@ -43,22 +44,22 @@
#include "gimp-intl.h"
-#define SHOW_LINE TRUE
-#define ENDPOINT_GRIP_HANDLE_TYPE GIMP_HANDLE_CROSS
-#define ENDPOINT_GRIP_HANDLE_SIZE GIMP_CANVAS_HANDLE_SIZE_CROSS
-#define SLIDER_GRIP_HANDLE_TYPE GIMP_HANDLE_FILLED_DIAMOND
-#define SLIDER_GRIP_HANDLE_SIZE (ENDPOINT_GRIP_HANDLE_SIZE * 2 / 3)
+#define SHOW_LINE TRUE
+#define GRAB_LINE_MASK GDK_MOD1_MASK
+#define ENDPOINT_HANDLE_TYPE GIMP_HANDLE_CROSS
+#define ENDPOINT_HANDLE_SIZE GIMP_CANVAS_HANDLE_SIZE_CROSS
+#define SLIDER_HANDLE_TYPE GIMP_HANDLE_FILLED_DIAMOND
+#define SLIDER_HANDLE_SIZE (ENDPOINT_HANDLE_SIZE * 2 / 3)
+#define HANDLE_CIRCLE_SCALE 1.8
+#define LINE_VICINITY ((gint) (SLIDER_HANDLE_SIZE * HANDLE_CIRCLE_SCALE) / 2)
typedef enum
{
- /* POINT_NONE evaluates to FALSE */
- POINT_NONE = 0,
- POINT_START,
- POINT_END,
- POINT_BOTH,
- POINT_SLIDER
-} GimpToolLinePoint;
+ GRAB_NONE,
+ GRAB_SELECTION,
+ GRAB_LINE
+} GimpToolLineGrab;
enum
{
@@ -68,9 +69,16 @@ enum
PROP_X2,
PROP_Y2,
PROP_SLIDERS,
+ PROP_SELECTION,
PROP_STATUS_TITLE,
};
+enum
+{
+ SELECTION_CHANGED,
+ LAST_SIGNAL
+};
+
struct _GimpToolLinePrivate
{
gdouble x1;
@@ -78,6 +86,7 @@ struct _GimpToolLinePrivate
gdouble x2;
gdouble y2;
GArray *sliders;
+ gint selection;
gchar *status_title;
gdouble saved_x1;
@@ -88,17 +97,15 @@ struct _GimpToolLinePrivate
gdouble mouse_x;
gdouble mouse_y;
- GimpToolLinePoint point;
- gint slider_index;
- gboolean point_grabbed;
+ gint hover;
+ GimpToolLineGrab grab;
GimpCanvasItem *line;
- GimpCanvasItem *start_handle_circle;
- GimpCanvasItem *start_handle_grip;
- GimpCanvasItem *end_handle_circle;
- GimpCanvasItem *end_handle_grip;
- GArray *slider_handle_circles;
- GArray *slider_handle_grips;
+ GimpCanvasItem *start_handle;
+ GimpCanvasItem *end_handle;
+ GimpCanvasItem *slider_group;
+ GArray *slider_handles;
+ GimpCanvasItem *handle_circle;
};
@@ -148,7 +155,12 @@ static gboolean gimp_tool_line_get_cursor (GimpToolWidget *widget,
static GimpControllerSlider *
gimp_tool_line_get_slider (GimpToolLine *line,
gint slider);
-static gboolean gimp_tool_line_point_motion (GimpToolLine *line,
+static GimpCanvasItem *
+ gimp_tool_line_get_handle (GimpToolLine *line,
+ gint handle);
+
+static gboolean
+ gimp_tool_line_selection_motion (GimpToolLine *line,
gboolean constrain);
static void gimp_tool_line_update_handles (GimpToolLine *line);
@@ -157,11 +169,18 @@ static void gimp_tool_line_update_status (GimpToolLine *line,
GdkModifierType state,
gboolean proximity);
+static gboolean gimp_tool_line_handle_hit (GimpCanvasItem *handle,
+ gdouble x,
+ gdouble y,
+ gdouble *min_dist);
+
G_DEFINE_TYPE (GimpToolLine, gimp_tool_line, GIMP_TYPE_TOOL_WIDGET)
#define parent_class gimp_tool_line_parent_class
+static guint line_signals[LAST_SIGNAL] = { 0, };
+
static void
gimp_tool_line_class_init (GimpToolLineClass *klass)
@@ -182,6 +201,15 @@ gimp_tool_line_class_init (GimpToolLineClass *klass)
widget_class->motion_modifier = gimp_tool_line_motion_modifier;
widget_class->get_cursor = gimp_tool_line_get_cursor;
+ line_signals[SELECTION_CHANGED] =
+ g_signal_new ("selection-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GimpToolLineClass, selection_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
g_object_class_install_property (object_class, PROP_X1,
g_param_spec_double ("x1", NULL, NULL,
-GIMP_MAX_IMAGE_SIZE,
@@ -215,6 +243,14 @@ gimp_tool_line_class_init (GimpToolLineClass *klass)
G_TYPE_ARRAY,
GIMP_PARAM_READWRITE));
+ g_object_class_install_property (object_class, PROP_SELECTION,
+ g_param_spec_int ("selection", NULL, NULL,
+ GIMP_TOOL_LINE_HANDLE_NONE,
+ G_MAXINT,
+ GIMP_TOOL_LINE_HANDLE_NONE,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
g_object_class_install_property (object_class, PROP_STATUS_TITLE,
g_param_spec_string ("status-title",
NULL, NULL,
@@ -236,10 +272,12 @@ gimp_tool_line_init (GimpToolLine *line)
private->sliders = g_array_new (FALSE, FALSE, sizeof (GimpControllerSlider));
- private->slider_handle_circles = g_array_new (FALSE, TRUE,
- sizeof (GimpCanvasItem *));
- private->slider_handle_grips = g_array_new (FALSE, TRUE,
- sizeof (GimpCanvasItem *));
+ private->selection = GIMP_TOOL_LINE_HANDLE_NONE;
+ private->hover = GIMP_TOOL_LINE_HANDLE_NONE;
+ private->grab = GRAB_NONE;
+
+ private->slider_handles = g_array_new (FALSE, TRUE,
+ sizeof (GimpCanvasItem *));
}
static void
@@ -259,40 +297,36 @@ gimp_tool_line_constructed (GObject *object)
gimp_canvas_item_set_visible (private->line, SHOW_LINE);
- private->start_handle_circle =
- gimp_tool_widget_add_handle (widget,
- GIMP_HANDLE_CIRCLE,
- private->x1,
- private->y1,
- 2 * ENDPOINT_GRIP_HANDLE_SIZE,
- 2 * ENDPOINT_GRIP_HANDLE_SIZE,
- GIMP_HANDLE_ANCHOR_CENTER);
-
- private->start_handle_grip =
+ private->start_handle =
gimp_tool_widget_add_handle (widget,
- ENDPOINT_GRIP_HANDLE_TYPE,
+ ENDPOINT_HANDLE_TYPE,
private->x1,
private->y1,
- ENDPOINT_GRIP_HANDLE_SIZE,
- ENDPOINT_GRIP_HANDLE_SIZE,
+ ENDPOINT_HANDLE_SIZE,
+ ENDPOINT_HANDLE_SIZE,
GIMP_HANDLE_ANCHOR_CENTER);
- private->end_handle_circle =
+ private->end_handle =
gimp_tool_widget_add_handle (widget,
- GIMP_HANDLE_CIRCLE,
+ ENDPOINT_HANDLE_TYPE,
private->x2,
private->y2,
- 2 * ENDPOINT_GRIP_HANDLE_SIZE,
- 2 * ENDPOINT_GRIP_HANDLE_SIZE,
+ ENDPOINT_HANDLE_SIZE,
+ ENDPOINT_HANDLE_SIZE,
GIMP_HANDLE_ANCHOR_CENTER);
- private->end_handle_grip =
+ private->slider_group =
+ gimp_canvas_group_new (gimp_tool_widget_get_shell (widget));
+ gimp_tool_widget_add_item (widget, private->slider_group);
+ g_object_unref (private->slider_group);
+
+ private->handle_circle =
gimp_tool_widget_add_handle (widget,
- ENDPOINT_GRIP_HANDLE_TYPE,
- private->x2,
- private->y2,
- ENDPOINT_GRIP_HANDLE_SIZE,
- ENDPOINT_GRIP_HANDLE_SIZE,
+ GIMP_HANDLE_CIRCLE,
+ private->x1,
+ private->y1,
+ ENDPOINT_HANDLE_SIZE * HANDLE_CIRCLE_SCALE,
+ ENDPOINT_HANDLE_SIZE * HANDLE_CIRCLE_SCALE,
GIMP_HANDLE_ANCHOR_CENTER);
gimp_tool_line_changed (widget);
@@ -306,8 +340,7 @@ gimp_tool_line_finalize (GObject *object)
g_clear_pointer (&private->sliders, g_array_unref);
g_clear_pointer (&private->status_title, g_free);
- g_clear_pointer (&private->slider_handle_circles, g_array_unref);
- g_clear_pointer (&private->slider_handle_grips, g_array_unref);
+ g_clear_pointer (&private->slider_handles, g_array_unref);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -337,10 +370,41 @@ gimp_tool_line_set_property (GObject *object,
break;
case PROP_SLIDERS:
- g_return_if_fail (g_value_get_boxed (value) != NULL);
+ {
+ GArray *sliders = g_value_dup_boxed (value);
+
+ g_return_if_fail (sliders != NULL);
+
+ if (GIMP_TOOL_LINE_HANDLE_IS_SLIDER (private->selection) &&
+ sliders->len != private->sliders->len)
+ {
+ gimp_tool_line_set_selection (line, GIMP_TOOL_LINE_HANDLE_NONE);
+ }
+
+ if (GIMP_TOOL_LINE_HANDLE_IS_SLIDER (private->hover))
+ private->hover = GIMP_TOOL_LINE_HANDLE_NONE;
- g_array_unref (private->sliders);
- private->sliders = g_value_dup_boxed (value);
+ g_array_unref (private->sliders);
+ private->sliders = sliders;
+ }
+ break;
+
+ case PROP_SELECTION:
+ {
+ gint selection = g_value_get_int (value);
+
+ g_return_if_fail (selection < (gint) private->sliders->len);
+
+ if (selection != private->selection)
+ {
+ private->selection = selection;
+
+ if (private->grab == GRAB_SELECTION)
+ private->grab = GRAB_NONE;
+
+ g_signal_emit (line, line_signals[SELECTION_CHANGED], 0);
+ }
+ }
break;
case PROP_STATUS_TITLE:
@@ -384,6 +448,10 @@ gimp_tool_line_get_property (GObject *object,
g_value_set_boxed (value, private->sliders);
break;
+ case PROP_SELECTION:
+ g_value_set_int (value, private->selection);
+ break;
+
case PROP_STATUS_TITLE:
g_value_set_string (value, private->status_title);
break;
@@ -407,73 +475,54 @@ gimp_tool_line_changed (GimpToolWidget *widget)
private->x2,
private->y2);
- gimp_canvas_handle_set_position (private->start_handle_circle,
- private->x1,
- private->y1);
- gimp_canvas_handle_set_position (private->start_handle_grip,
+ gimp_canvas_handle_set_position (private->start_handle,
private->x1,
private->y1);
- gimp_canvas_handle_set_position (private->end_handle_circle,
- private->x2,
- private->y2);
- gimp_canvas_handle_set_position (private->end_handle_grip,
+ gimp_canvas_handle_set_position (private->end_handle,
private->x2,
private->y2);
/* remove excessive slider handles */
- for (i = private->sliders->len; i < private->slider_handle_circles->len; i++)
+ for (i = private->sliders->len; i < private->slider_handles->len; i++)
{
- gimp_tool_widget_remove_item (widget,
- g_array_index (private->slider_handle_circles,
- GimpCanvasItem *, i));
- gimp_tool_widget_remove_item (widget,
- g_array_index (private->slider_handle_grips,
- GimpCanvasItem *, i));
+ gimp_canvas_group_remove_item (GIMP_CANVAS_GROUP (private->slider_group),
+ gimp_tool_line_get_handle (line, i));
}
- g_array_set_size (private->slider_handle_circles, private->sliders->len);
- g_array_set_size (private->slider_handle_grips, private->sliders->len);
+ g_array_set_size (private->slider_handles, private->sliders->len);
for (i = 0; i < private->sliders->len; i++)
{
gdouble value;
gdouble x;
gdouble y;
- GimpCanvasItem **circle;
- GimpCanvasItem **grip;
+ GimpCanvasItem **handle;
value = gimp_tool_line_get_slider (line, i)->value;
x = private->x1 + (private->x2 - private->x1) * value;
y = private->y1 + (private->y2 - private->y1) * value;
- circle = &g_array_index (private->slider_handle_circles,
- GimpCanvasItem *, i);
- grip = &g_array_index (private->slider_handle_grips,
- GimpCanvasItem *, i);
+ handle = &g_array_index (private->slider_handles, GimpCanvasItem *, i);
- if (*circle)
+ if (*handle)
{
- gimp_canvas_handle_set_position (*circle, x, y);
- gimp_canvas_handle_set_position (*grip, x, y);
+ gimp_canvas_handle_set_position (*handle, x, y);
}
else
{
- *circle = gimp_tool_widget_add_handle (widget,
- GIMP_HANDLE_CIRCLE,
- x,
- y,
- 2 * SLIDER_GRIP_HANDLE_SIZE,
- 2 * SLIDER_GRIP_HANDLE_SIZE,
- GIMP_HANDLE_ANCHOR_CENTER);
- *grip = gimp_tool_widget_add_handle (widget,
- SLIDER_GRIP_HANDLE_TYPE,
- x,
- y,
- SLIDER_GRIP_HANDLE_SIZE,
- SLIDER_GRIP_HANDLE_SIZE,
- GIMP_HANDLE_ANCHOR_CENTER);
+ *handle = gimp_canvas_handle_new (gimp_tool_widget_get_shell (widget),
+ SLIDER_HANDLE_TYPE,
+ GIMP_HANDLE_ANCHOR_CENTER,
+ x,
+ y,
+ SLIDER_HANDLE_SIZE,
+ SLIDER_HANDLE_SIZE);
+
+ gimp_canvas_group_add_item (GIMP_CANVAS_GROUP (private->slider_group),
+ *handle);
+ g_object_unref (*handle);
}
}
@@ -491,30 +540,41 @@ gimp_tool_line_button_press (GimpToolWidget *widget,
GimpToolLine *line = GIMP_TOOL_LINE (widget);
GimpToolLinePrivate *private = line->private;
- if (private->point != POINT_NONE)
+ private->grab = GRAB_NONE;
+
+ private->saved_x1 = private->x1;
+ private->saved_y1 = private->y1;
+ private->saved_x2 = private->x2;
+ private->saved_y2 = private->y2;
+
+ if (GIMP_TOOL_LINE_HANDLE_IS_SLIDER (private->hover))
{
- private->saved_x1 = private->x1;
- private->saved_y1 = private->y1;
- private->saved_x2 = private->x2;
- private->saved_y2 = private->y2;
+ private->saved_slider_value =
+ gimp_tool_line_get_slider (line, private->hover)->value;
+ }
- if (private->point == POINT_SLIDER)
- {
- private->saved_slider_value =
- gimp_tool_line_get_slider (line, private->slider_index)->value;
- }
+ if (private->hover != GIMP_TOOL_LINE_HANDLE_NONE)
+ {
+ gimp_tool_line_set_selection (line, private->hover);
- private->point_grabbed = TRUE;
+ private->grab = GRAB_SELECTION;
+ }
+ else if (state & GRAB_LINE_MASK)
+ {
+ private->grab = GRAB_LINE;
+ }
- gimp_tool_line_point_motion (line,
- state & gimp_get_constrain_behavior_mask ());
+ if (grab == GRAB_NONE)
+ {
+ private->hover = GIMP_TOOL_LINE_HANDLE_NONE;
- return private->point;
+ gimp_tool_line_set_selection (line, GIMP_TOOL_LINE_HANDLE_NONE);
}
+ gimp_tool_line_update_handles (line);
gimp_tool_line_update_status (line, state, TRUE);
- return 0;
+ return private->grab != GRAB_NONE;
}
void
@@ -527,11 +587,13 @@ gimp_tool_line_button_release (GimpToolWidget *widget,
GimpToolLine *line = GIMP_TOOL_LINE (widget);
GimpToolLinePrivate *private = line->private;
- if (release_type == GIMP_BUTTON_RELEASE_CANCEL)
+ if (release_type == GIMP_BUTTON_RELEASE_CANCEL &&
+ private->grab != GRAB_NONE)
{
- if (private->point == POINT_SLIDER)
+ if (private->grab == GRAB_SELECTION &&
+ GIMP_TOOL_LINE_HANDLE_IS_SLIDER (private->selection))
{
- gimp_tool_line_get_slider (line, private->slider_index)->value =
+ gimp_tool_line_get_slider (line, private->selection)->value =
private->saved_slider_value;
}
@@ -543,7 +605,7 @@ gimp_tool_line_button_release (GimpToolWidget *widget,
NULL);
}
- private->point_grabbed = FALSE;
+ private->grab = GRAB_NONE;
}
void
@@ -560,7 +622,7 @@ gimp_tool_line_motion (GimpToolWidget *widget,
private->mouse_x = coords->x;
private->mouse_y = coords->y;
- if (private->point == POINT_BOTH)
+ if (private->grab == GRAB_LINE)
{
g_object_set (line,
"x1", private->x1 + diff_x,
@@ -573,7 +635,7 @@ gimp_tool_line_motion (GimpToolWidget *widget,
{
gboolean constrain = (state & gimp_get_constrain_behavior_mask ()) != 0;
- gimp_tool_line_point_motion (line, constrain);
+ gimp_tool_line_selection_motion (line, constrain);
}
gimp_tool_line_update_status (line, state, TRUE);
@@ -592,51 +654,38 @@ gimp_tool_line_hover (GimpToolWidget *widget,
private->mouse_x = coords->x;
private->mouse_y = coords->y;
- gimp_tool_line_update_handles (line);
-
- private->point = POINT_NONE;
+ private->hover = GIMP_TOOL_LINE_HANDLE_NONE;
- if (state & GDK_MOD1_MASK)
- {
- private->point = POINT_BOTH;
- }
- else
+ if (! (state & GRAB_LINE_MASK))
{
- /* give sliders precedence over the endpoints, since they're smaller */
- for (i = private->sliders->len - 1; i >= 0; i--)
+ /* find the closest handle to the cursor */
+ gdouble min_dist = G_MAXDOUBLE;
+ gint first_handle = private->sliders->len - 1;
+
+ /* skip the sliders if the two endpoints are the same, in particular so
+ * that if the line is created during a button-press event (as in the
+ * blend tool), the end endpoint is dragged, instead of a slider.
+ */
+ if (private->x1 == private->x2 && private->y1 == private->y2)
+ first_handle = -1;
+
+ for (i = first_handle; i > GIMP_TOOL_LINE_HANDLE_NONE; i--)
{
- GimpCanvasItem *circle;
+ GimpCanvasItem *handle;
- circle = g_array_index (private->slider_handle_circles,
- GimpCanvasItem *, i);
-
- if (gimp_canvas_item_hit (circle, private->mouse_x, private->mouse_y))
- {
- private->point = POINT_SLIDER;
- private->slider_index = i;
-
- break;
- }
- }
+ handle = gimp_tool_line_get_handle (line, i);
- if (private->point == POINT_NONE)
- {
- if (gimp_canvas_item_hit (private->end_handle_circle,
- private->mouse_x,
- private->mouse_y))
- {
- private->point = POINT_END;
- }
- else if (gimp_canvas_item_hit (private->start_handle_circle,
+ if (gimp_tool_line_handle_hit (handle,
private->mouse_x,
- private->mouse_y))
+ private->mouse_y,
+ &min_dist))
{
- private->point = POINT_START;
+ private->hover = i;
}
}
}
- gimp_tool_line_update_hilight (line);
+ gimp_tool_line_update_handles (line);
gimp_tool_line_update_status (line, state, proximity);
}
@@ -650,7 +699,7 @@ gimp_tool_line_motion_modifier (GimpToolWidget *widget,
if (key == gimp_get_constrain_behavior_mask ())
{
- gimp_tool_line_point_motion (line, press);
+ gimp_tool_line_selection_motion (line, press);
gimp_tool_line_update_status (line, state, TRUE);
}
@@ -667,7 +716,14 @@ gimp_tool_line_get_cursor (GimpToolWidget *widget,
GimpToolLine *line = GIMP_TOOL_LINE (widget);
GimpToolLinePrivate *private = line->private;
- if (private->point == POINT_BOTH)
+ if (private->grab ==GRAB_LINE || (state & GRAB_LINE_MASK))
+ {
+ *modifier = GIMP_CURSOR_MODIFIER_MOVE;
+
+ return TRUE;
+ }
+ else if (private->grab == GRAB_SELECTION ||
+ private->hover > GIMP_TOOL_LINE_HANDLE_NONE)
{
*modifier = GIMP_CURSOR_MODIFIER_MOVE;
@@ -688,17 +744,49 @@ gimp_tool_line_get_slider (GimpToolLine *line,
return &g_array_index (private->sliders, GimpControllerSlider, slider);
}
+static GimpCanvasItem *
+gimp_tool_line_get_handle (GimpToolLine *line,
+ gint handle)
+{
+ GimpToolLinePrivate *private = line->private;
+
+ switch (handle)
+ {
+ case GIMP_TOOL_LINE_HANDLE_NONE:
+ return NULL;
+
+ case GIMP_TOOL_LINE_HANDLE_START:
+ return private->start_handle;
+
+ case GIMP_TOOL_LINE_HANDLE_END:
+ return private->end_handle;
+
+ default:
+ g_assert (handle >= 0 &&
+ handle < (gint) private->slider_handles->len);
+
+ return g_array_index (private->slider_handles,
+ GimpCanvasItem *, handle);
+ }
+}
+
static gboolean
-gimp_tool_line_point_motion (GimpToolLine *line,
- gboolean constrain)
+gimp_tool_line_selection_motion (GimpToolLine *line,
+ gboolean constrain)
{
GimpToolLinePrivate *private = line->private;
gdouble x = private->mouse_x;
gdouble y = private->mouse_y;
- switch (private->point)
+ if (private->grab != GRAB_SELECTION)
+ return FALSE;
+
+ switch (private->selection)
{
- case POINT_START:
+ case GIMP_TOOL_LINE_HANDLE_NONE:
+ g_assert_not_reached ();
+
+ case GIMP_TOOL_LINE_HANDLE_START:
if (constrain)
gimp_constrain_line (private->x2, private->y2,
&x, &y,
@@ -710,7 +798,7 @@ gimp_tool_line_point_motion (GimpToolLine *line,
NULL);
return TRUE;
- case POINT_END:
+ case GIMP_TOOL_LINE_HANDLE_END:
if (constrain)
gimp_constrain_line (private->x1, private->y1,
&x, &y,
@@ -722,7 +810,7 @@ gimp_tool_line_point_motion (GimpToolLine *line,
NULL);
return TRUE;
- case POINT_SLIDER:
+ default:
{
gdouble length_sqr;
@@ -737,7 +825,7 @@ gimp_tool_line_point_motion (GimpToolLine *line,
GimpControllerSlider *slider;
gdouble value;
- slider = gimp_tool_line_get_slider (line, private->slider_index);
+ slider = gimp_tool_line_get_slider (line, private->selection);
/* project the cursor position onto the line */
value = (private->x2 - private->x1) * (x - private->x1) +
@@ -761,82 +849,41 @@ gimp_tool_line_point_motion (GimpToolLine *line,
return TRUE;
}
-
- default:
- break;
}
-
- return FALSE;
}
static void
gimp_tool_line_update_handles (GimpToolLine *line)
{
GimpToolLinePrivate *private = line->private;
- gboolean start_visible, end_visible;
- gint start_diameter, end_diameter;
- gint i;
-
- /* Calculate handle visibility */
- if (private->point_grabbed)
- {
- start_visible = FALSE;
- end_visible = FALSE;
- }
- else
- {
- start_diameter = gimp_canvas_handle_calc_size (private->start_handle_circle,
- private->mouse_x,
- private->mouse_y,
- 0,
- 2 * ENDPOINT_GRIP_HANDLE_SIZE);
- start_visible = start_diameter > 2;
-
- end_diameter = gimp_canvas_handle_calc_size (private->end_handle_circle,
- private->mouse_x,
- private->mouse_y,
- 0,
- 2 * ENDPOINT_GRIP_HANDLE_SIZE);
- end_visible = end_diameter > 2;
- }
+ GimpCanvasItem *handle;
+ gboolean visible;
- gimp_canvas_item_set_visible (private->start_handle_circle, start_visible);
- gimp_canvas_item_set_visible (private->end_handle_circle, end_visible);
+ handle = gimp_tool_line_get_handle (line, private->hover);
- if (start_visible)
- gimp_canvas_handle_set_size (private->start_handle_circle,
- start_diameter, start_diameter);
+ visible = handle && private->grab == GRAB_NONE;
- if (end_visible)
- gimp_canvas_handle_set_size (private->end_handle_circle,
- end_diameter, end_diameter);
-
- for (i = 0; i < private->sliders->len; i++)
+ if (visible)
{
- GimpCanvasItem *circle;
- gboolean visible;
- gint diameter;
+ gdouble x;
+ gdouble y;
+ gint width;
+ gint height;
- circle = g_array_index (private->slider_handle_circles,
- GimpCanvasItem *, i);
+ gimp_canvas_handle_get_position (handle, &x, &y);
+ gimp_canvas_handle_get_size (handle, &width, &height);
- if (private->point_grabbed)
- visible = FALSE;
- else
- {
- diameter = gimp_canvas_handle_calc_size (circle,
- private->mouse_x,
- private->mouse_y,
- 0,
- 2 * SLIDER_GRIP_HANDLE_SIZE);
- visible = diameter > 2;
- }
+ width = MAX (width, SLIDER_HANDLE_SIZE);
+ height = MAX (height, SLIDER_HANDLE_SIZE);
- gimp_canvas_item_set_visible (circle, visible);
+ width *= HANDLE_CIRCLE_SCALE;
+ height *= HANDLE_CIRCLE_SCALE;
- if (visible)
- gimp_canvas_handle_set_size (circle, diameter, diameter);
+ gimp_canvas_handle_set_position (private->handle_circle, x, y);
+ gimp_canvas_handle_set_size (private->handle_circle, width, height);
}
+
+ gimp_canvas_item_set_visible (private->handle_circle, visible);
}
static void
@@ -845,32 +892,15 @@ gimp_tool_line_update_hilight (GimpToolLine *line)
GimpToolLinePrivate *private = line->private;
gint i;
- gimp_canvas_item_set_highlight (private->start_handle_circle,
- private->point == POINT_START);
- gimp_canvas_item_set_highlight (private->start_handle_grip,
- private->point == POINT_START);
-
- gimp_canvas_item_set_highlight (private->end_handle_circle,
- private->point == POINT_END);
- gimp_canvas_item_set_highlight (private->end_handle_grip,
- private->point == POINT_END);
-
- for (i = 0; i < private->sliders->len; i++)
+ for (i = GIMP_TOOL_LINE_HANDLE_NONE + 1;
+ i < (gint) private->sliders->len;
+ i++)
{
- GimpCanvasItem *circle;
- GimpCanvasItem *grip;
- gboolean highlight;
+ GimpCanvasItem *handle;
- circle = g_array_index (private->slider_handle_circles,
- GimpCanvasItem *, i);
- grip = g_array_index (private->slider_handle_grips,
- GimpCanvasItem *, i);
+ handle = gimp_tool_line_get_handle (line, i);
- highlight =
- (private->point == POINT_SLIDER && private->slider_index == i);
-
- gimp_canvas_item_set_highlight (circle, highlight);
- gimp_canvas_item_set_highlight (grip, highlight);
+ gimp_canvas_item_set_highlight (handle, i == private->selection);
}
}
@@ -907,6 +937,40 @@ gimp_tool_line_update_status (GimpToolLine *line,
}
}
+static gboolean
+gimp_tool_line_handle_hit (GimpCanvasItem *handle,
+ gdouble x,
+ gdouble y,
+ gdouble *min_dist)
+{
+ gdouble handle_x;
+ gdouble handle_y;
+ gint handle_width;
+ gint handle_height;
+ gint radius;
+ gdouble dist;
+
+ gimp_canvas_handle_get_position (handle, &handle_x, &handle_y);
+ gimp_canvas_handle_get_size (handle, &handle_width, &handle_height);
+
+ radius = ((gint) (handle_width * HANDLE_CIRCLE_SCALE)) / 2;
+ radius = MAX (radius, LINE_VICINITY);
+
+ dist = gimp_canvas_item_transform_distance (handle,
+ x, y, handle_x, handle_y);
+
+ if (dist <= radius && dist < *min_dist)
+ {
+ *min_dist = dist;
+
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
/* public functions */
@@ -940,6 +1004,12 @@ gimp_tool_line_set_sliders (GimpToolLine *line,
private = line->private;
+ if (GIMP_TOOL_LINE_HANDLE_IS_SLIDER (private->selection) &&
+ private->sliders->len != n_sliders)
+ {
+ gimp_tool_line_set_selection (line, GIMP_TOOL_LINE_HANDLE_NONE);
+ }
+
g_array_set_size (private->sliders, n_sliders);
memcpy (private->sliders->data, sliders,
@@ -964,3 +1034,33 @@ gimp_tool_line_get_sliders (GimpToolLine *line,
return (const GimpControllerSlider *) private->sliders->data;
}
+
+void
+gimp_tool_line_set_selection (GimpToolLine *line,
+ gint handle)
+{
+ GimpToolLinePrivate *private;
+
+ g_return_if_fail (GIMP_IS_TOOL_LINE (line));
+
+ private = line->private;
+
+ g_return_if_fail (handle >= GIMP_TOOL_LINE_HANDLE_NONE &&
+ handle < (gint) private->sliders->len);
+
+ g_object_set (line,
+ "selection", handle,
+ NULL);
+}
+
+gint
+gimp_tool_line_get_selection (GimpToolLine *line)
+{
+ GimpToolLinePrivate *private;
+
+ g_return_val_if_fail (GIMP_IS_TOOL_LINE (line), GIMP_TOOL_LINE_HANDLE_NONE);
+
+ private = line->private;
+
+ return private->selection;
+}
diff --git a/app/display/gimptoolline.h b/app/display/gimptoolline.h
index 2398d03..e4f21a4 100644
--- a/app/display/gimptoolline.h
+++ b/app/display/gimptoolline.h
@@ -25,6 +25,17 @@
#include "gimptoolwidget.h"
+/* in the context of GimpToolLine, "handle" is a collective term for either an
+ * endpoint or a slider. a handle value may be either a (nonnegative) slider
+ * index, or one of the values below:
+ */
+#define GIMP_TOOL_LINE_HANDLE_NONE (-3)
+#define GIMP_TOOL_LINE_HANDLE_START (-2)
+#define GIMP_TOOL_LINE_HANDLE_END (-1)
+
+#define GIMP_TOOL_LINE_HANDLE_IS_SLIDER(handle) ((handle) >= 0)
+
+
#define GIMP_TYPE_TOOL_LINE (gimp_tool_line_get_type ())
#define GIMP_TOOL_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TOOL_LINE,
GimpToolLine))
#define GIMP_TOOL_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_TOOL_LINE,
GimpToolLineClass))
@@ -47,22 +58,29 @@ struct _GimpToolLine
struct _GimpToolLineClass
{
GimpToolWidgetClass parent_class;
+
+ /* signals */
+ void (* selection_changed) (GimpToolLine *line);
};
-GType gimp_tool_line_get_type (void) G_GNUC_CONST;
+GType gimp_tool_line_get_type (void) G_GNUC_CONST;
+
+GimpToolWidget * gimp_tool_line_new (GimpDisplayShell *shell,
+ gdouble x1,
+ gdouble y1,
+ gdouble x2,
+ gdouble y2);
-GimpToolWidget * gimp_tool_line_new (GimpDisplayShell *shell,
- gdouble x1,
- gdouble y1,
- gdouble x2,
- gdouble y2);
+void gimp_tool_line_set_sliders (GimpToolLine *line,
+ const GimpControllerSlider *sliders,
+ gint n_sliders);
+const GimpControllerSlider * gimp_tool_line_get_sliders (GimpToolLine *line,
+ gint *n_sliders);
-void gimp_tool_line_set_sliders (GimpToolLine *line,
- const GimpControllerSlider *sliders,
- gint n_sliders);
-const GimpControllerSlider * gimp_tool_line_get_sliders (GimpToolLine *line,
- gint *n_sliders);
+void gimp_tool_line_set_selection (GimpToolLine *line,
+ gint handle);
+gint gimp_tool_line_get_selection (GimpToolLine *line);
#endif /* __GIMP_TOOL_LINE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]