app: allow adding and removing sliders to/from a GimpToolLine
Add support for adding and removing sliders to/from a GimpToolLine, using three new signals: - can-add-slider: Takes a double argument in the range [0,1], indicating a location along the line, and returns a boolean value, indicating whether a slider can be added at that location. - add-slider: Takes a double argument in the range [0,1], indicating a location along the line, for which can-add-slider returned TRUE. In response, should add a new slider at that location, and return its index, or a negative value if no slider was added. - remove-slider: Takes a slider index. In response, may remove the slider. On the UI side, when the cursor is close enough to the line, but not within the hit area of an existing handle, GimpToolLine checks if a slider can be added at the cursor position, using can-add- slider. If a slider can be added, a dashed circle appears at the cursor position along the line, indicating where a slider will be added. The cursor is added by clicking, which emits an add-slider signal; if the signal returns a slider index, the new slider is selected, and can be subsequently dragged. Removing a slider is done by either selecting the slider and pressing backspace (or delete, although we don't actually forward it to the tool atm,) or by "tearing" the slider: when dragging the slider, if the cursor is far enough from the liner, a dashed circle appears around the slider, and releasing the mouse removes the slider.
This commit is contained in:
@ -23,6 +23,7 @@
|
||||
# BOOL deprecated alias for BOOLEAN
|
||||
|
||||
BOOLEAN: BOOLEAN
|
||||
BOOLEAN: DOUBLE
|
||||
BOOLEAN: ENUM, INT
|
||||
BOOLEAN: OBJECT
|
||||
BOOLEAN: OBJECT, POINTER
|
||||
@ -30,6 +31,8 @@ BOOLEAN: OBJECT, POINTER, STRING
|
||||
BOOLEAN: STRING
|
||||
BOOLEAN: STRING, FLAGS
|
||||
|
||||
INT: DOUBLE
|
||||
|
||||
VOID: BOOLEAN
|
||||
VOID: BOOLEAN, INT, INT, INT, INT
|
||||
VOID: BOXED
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/gimp-utils.h"
|
||||
#include "core/gimpmarshal.h"
|
||||
|
||||
#include "widgets/gimpwidgets-utils.h"
|
||||
|
||||
@ -40,6 +41,7 @@
|
||||
#include "gimpcanvashandle.h"
|
||||
#include "gimpcanvasline.h"
|
||||
#include "gimpdisplayshell.h"
|
||||
#include "gimpdisplayshell-cursor.h"
|
||||
#include "gimptoolline.h"
|
||||
|
||||
#include "gimp-intl.h"
|
||||
@ -53,6 +55,11 @@
|
||||
#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)
|
||||
#define SLIDER_TEAR_DISTANCE (5 * LINE_VICINITY)
|
||||
|
||||
|
||||
/* hover-only "handles" */
|
||||
#define HOVER_NEW_SLIDER (GIMP_TOOL_LINE_HANDLE_NONE - 1)
|
||||
|
||||
|
||||
typedef enum
|
||||
@ -76,6 +83,9 @@ enum
|
||||
|
||||
enum
|
||||
{
|
||||
CAN_ADD_SLIDER,
|
||||
ADD_SLIDER,
|
||||
REMOVE_SLIDER,
|
||||
SELECTION_CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
@ -99,6 +109,8 @@ struct _GimpToolLinePrivate
|
||||
gdouble mouse_x;
|
||||
gdouble mouse_y;
|
||||
gint hover;
|
||||
gdouble new_slider_value;
|
||||
gboolean remove_slider;
|
||||
GimpToolLineGrab grab;
|
||||
|
||||
GimpCanvasItem *line;
|
||||
@ -161,6 +173,11 @@ static GimpControllerSlider *
|
||||
static GimpCanvasItem *
|
||||
gimp_tool_line_get_handle (GimpToolLine *line,
|
||||
gint handle);
|
||||
static gdouble gimp_tool_line_project_point (GimpToolLine *line,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gboolean constrain,
|
||||
gdouble *dist);
|
||||
|
||||
static gboolean
|
||||
gimp_tool_line_selection_motion (GimpToolLine *line,
|
||||
@ -205,6 +222,36 @@ 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[CAN_ADD_SLIDER] =
|
||||
g_signal_new ("can-add-slider",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GimpToolLineClass, can_add_slider),
|
||||
NULL, NULL,
|
||||
gimp_marshal_BOOLEAN__DOUBLE,
|
||||
G_TYPE_BOOLEAN, 1,
|
||||
G_TYPE_DOUBLE);
|
||||
|
||||
line_signals[ADD_SLIDER] =
|
||||
g_signal_new ("add-slider",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GimpToolLineClass, add_slider),
|
||||
NULL, NULL,
|
||||
gimp_marshal_INT__DOUBLE,
|
||||
G_TYPE_INT, 1,
|
||||
G_TYPE_DOUBLE);
|
||||
|
||||
line_signals[REMOVE_SLIDER] =
|
||||
g_signal_new ("remove-slider",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (GimpToolLineClass, remove_slider),
|
||||
NULL, NULL,
|
||||
gimp_marshal_VOID__INT,
|
||||
G_TYPE_NONE, 1,
|
||||
G_TYPE_INT);
|
||||
|
||||
line_signals[SELECTION_CHANGED] =
|
||||
g_signal_new ("selection-changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
@ -544,7 +591,8 @@ gimp_tool_line_button_press (GimpToolWidget *widget,
|
||||
GimpToolLine *line = GIMP_TOOL_LINE (widget);
|
||||
GimpToolLinePrivate *private = line->private;
|
||||
|
||||
private->grab = GRAB_NONE;
|
||||
private->grab = GRAB_NONE;
|
||||
private->remove_slider = FALSE;
|
||||
|
||||
private->saved_x1 = private->x1;
|
||||
private->saved_y1 = private->y1;
|
||||
@ -557,12 +605,31 @@ gimp_tool_line_button_press (GimpToolWidget *widget,
|
||||
gimp_tool_line_get_slider (line, private->hover)->value;
|
||||
}
|
||||
|
||||
if (private->hover != GIMP_TOOL_LINE_HANDLE_NONE)
|
||||
if (private->hover > GIMP_TOOL_LINE_HANDLE_NONE)
|
||||
{
|
||||
gimp_tool_line_set_selection (line, private->hover);
|
||||
|
||||
private->grab = GRAB_SELECTION;
|
||||
}
|
||||
else if (private->hover == HOVER_NEW_SLIDER)
|
||||
{
|
||||
gint slider;
|
||||
|
||||
g_signal_emit (line, line_signals[ADD_SLIDER], 0,
|
||||
private->new_slider_value, &slider);
|
||||
|
||||
g_return_val_if_fail (slider < (gint) private->sliders->len, FALSE);
|
||||
|
||||
if (slider >= 0)
|
||||
{
|
||||
gimp_tool_line_set_selection (line, slider);
|
||||
|
||||
private->saved_slider_value =
|
||||
gimp_tool_line_get_slider (line, private->selection)->value;
|
||||
|
||||
private->grab = GRAB_SELECTION;
|
||||
}
|
||||
}
|
||||
else if (state & GRAB_LINE_MASK)
|
||||
{
|
||||
private->grab = GRAB_LINE;
|
||||
@ -590,26 +657,34 @@ gimp_tool_line_button_release (GimpToolWidget *widget,
|
||||
{
|
||||
GimpToolLine *line = GIMP_TOOL_LINE (widget);
|
||||
GimpToolLinePrivate *private = line->private;
|
||||
|
||||
if (release_type == GIMP_BUTTON_RELEASE_CANCEL &&
|
||||
private->grab != GRAB_NONE)
|
||||
{
|
||||
if (private->grab == GRAB_SELECTION &&
|
||||
GIMP_TOOL_LINE_HANDLE_IS_SLIDER (private->selection))
|
||||
{
|
||||
gimp_tool_line_get_slider (line, private->selection)->value =
|
||||
private->saved_slider_value;
|
||||
}
|
||||
|
||||
g_object_set (line,
|
||||
"x1", private->saved_x1,
|
||||
"y1", private->saved_y1,
|
||||
"x2", private->saved_x2,
|
||||
"y2", private->saved_y2,
|
||||
NULL);
|
||||
}
|
||||
GimpToolLineGrab grab = private->grab;
|
||||
|
||||
private->grab = GRAB_NONE;
|
||||
|
||||
if (release_type == GIMP_BUTTON_RELEASE_CANCEL)
|
||||
{
|
||||
if (grab != GRAB_NONE)
|
||||
{
|
||||
if (grab == GRAB_SELECTION &&
|
||||
GIMP_TOOL_LINE_HANDLE_IS_SLIDER (private->selection))
|
||||
{
|
||||
gimp_tool_line_get_slider (line, private->selection)->value =
|
||||
private->saved_slider_value;
|
||||
}
|
||||
|
||||
g_object_set (line,
|
||||
"x1", private->saved_x1,
|
||||
"y1", private->saved_y1,
|
||||
"x2", private->saved_x2,
|
||||
"y2", private->saved_y2,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
else if (grab == GRAB_SELECTION && private->remove_slider)
|
||||
{
|
||||
g_signal_emit (line, line_signals[REMOVE_SLIDER], 0,
|
||||
private->selection);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -687,6 +762,35 @@ gimp_tool_line_hover (GimpToolWidget *widget,
|
||||
private->hover = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (private->hover == GIMP_TOOL_LINE_HANDLE_NONE)
|
||||
{
|
||||
gboolean constrain;
|
||||
gdouble value;
|
||||
gdouble dist;
|
||||
|
||||
constrain = (state & gimp_get_constrain_behavior_mask ()) != 0;
|
||||
|
||||
value = gimp_tool_line_project_point (line,
|
||||
private->mouse_x,
|
||||
private->mouse_y,
|
||||
constrain,
|
||||
&dist);
|
||||
|
||||
if (value >= 0.0 && value <= 1.0 && dist <= LINE_VICINITY)
|
||||
{
|
||||
gboolean can_add;
|
||||
|
||||
g_signal_emit (line, line_signals[CAN_ADD_SLIDER], 0,
|
||||
value, &can_add);
|
||||
|
||||
if (can_add)
|
||||
{
|
||||
private->hover = HOVER_NEW_SLIDER;
|
||||
private->new_slider_value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gimp_tool_line_update_handles (line);
|
||||
@ -812,6 +916,15 @@ gimp_tool_line_key_press (GimpToolWidget *widget,
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case GDK_KEY_BackSpace:
|
||||
case GDK_KEY_Delete:
|
||||
if (GIMP_TOOL_LINE_HANDLE_IS_SLIDER (private->selection))
|
||||
{
|
||||
g_signal_emit (line, line_signals[REMOVE_SLIDER], 0,
|
||||
private->selection);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return GIMP_TOOL_WIDGET_CLASS (parent_class)->key_press (widget, kevent);
|
||||
@ -853,7 +966,22 @@ gimp_tool_line_get_cursor (GimpToolWidget *widget,
|
||||
else if (private->grab == GRAB_SELECTION ||
|
||||
private->hover > GIMP_TOOL_LINE_HANDLE_NONE)
|
||||
{
|
||||
*modifier = GIMP_CURSOR_MODIFIER_MOVE;
|
||||
if (private->grab == GRAB_SELECTION &&
|
||||
GIMP_TOOL_LINE_HANDLE_IS_SLIDER (private->selection) &&
|
||||
private->remove_slider)
|
||||
{
|
||||
*modifier = GIMP_CURSOR_MODIFIER_MINUS;
|
||||
}
|
||||
else
|
||||
{
|
||||
*modifier = GIMP_CURSOR_MODIFIER_MOVE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (private->hover == HOVER_NEW_SLIDER)
|
||||
{
|
||||
*modifier = GIMP_CURSOR_MODIFIER_PLUS;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -898,6 +1026,58 @@ gimp_tool_line_get_handle (GimpToolLine *line,
|
||||
}
|
||||
}
|
||||
|
||||
static gdouble
|
||||
gimp_tool_line_project_point (GimpToolLine *line,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gboolean constrain,
|
||||
gdouble *dist)
|
||||
{
|
||||
GimpToolLinePrivate *private = line->private;
|
||||
gdouble length_sqr;
|
||||
gdouble value = 0.0;
|
||||
|
||||
length_sqr = SQR (private->x2 - private->x1) +
|
||||
SQR (private->y2 - private->y1);
|
||||
|
||||
/* don't calculate the projection for 0-length lines, since we'll just get
|
||||
* NaN.
|
||||
*/
|
||||
if (length_sqr > 0.0)
|
||||
{
|
||||
value = (private->x2 - private->x1) * (x - private->x1) +
|
||||
(private->y2 - private->y1) * (y - private->y1);
|
||||
value /= length_sqr;
|
||||
|
||||
if (dist)
|
||||
{
|
||||
gdouble px;
|
||||
gdouble py;
|
||||
|
||||
px = private->x1 + (private->x2 - private->x1) * value;
|
||||
py = private->y1 + (private->y2 - private->y1) * value;
|
||||
|
||||
*dist = gimp_canvas_item_transform_distance (private->line,
|
||||
x, y,
|
||||
px, py);
|
||||
}
|
||||
|
||||
if (constrain)
|
||||
value = RINT (12.0 * value) / 12.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dist)
|
||||
{
|
||||
*dist = gimp_canvas_item_transform_distance (private->line,
|
||||
x, y,
|
||||
private->x1, private->y1);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gimp_tool_line_selection_motion (GimpToolLine *line,
|
||||
gboolean constrain)
|
||||
@ -940,40 +1120,49 @@ gimp_tool_line_selection_motion (GimpToolLine *line,
|
||||
|
||||
default:
|
||||
{
|
||||
gdouble length_sqr;
|
||||
GimpDisplayShell *shell;
|
||||
GimpControllerSlider *slider;
|
||||
gdouble value;
|
||||
gdouble dist;
|
||||
|
||||
length_sqr = SQR (private->x2 - private->x1) +
|
||||
SQR (private->y2 - private->y1);
|
||||
shell = gimp_tool_widget_get_shell (GIMP_TOOL_WIDGET (line));
|
||||
|
||||
/* don't change slider values of 0-length lines, since we'll just get
|
||||
* NaN.
|
||||
*/
|
||||
if (length_sqr > 0.0)
|
||||
{
|
||||
GimpControllerSlider *slider;
|
||||
gdouble value;
|
||||
slider = gimp_tool_line_get_slider (line, private->selection);
|
||||
|
||||
slider = gimp_tool_line_get_slider (line, private->selection);
|
||||
/* project the cursor position onto the line */
|
||||
value = gimp_tool_line_project_point (line, x, y, constrain, &dist);
|
||||
|
||||
/* project the cursor position onto the line */
|
||||
value = (private->x2 - private->x1) * (x - private->x1) +
|
||||
(private->y2 - private->y1) * (y - private->y1);
|
||||
value /= length_sqr;
|
||||
value = CLAMP (value, slider->min, slider->max);
|
||||
value = CLAMP (value, 0.0, 1.0);
|
||||
|
||||
if (constrain)
|
||||
value = RINT (12.0 * value) / 12.0;
|
||||
value = fabs (value); /* avoid negative zero */
|
||||
|
||||
value = CLAMP (value, slider->min, slider->max);
|
||||
value = CLAMP (value, 0.0, 1.0);
|
||||
slider->value = value;
|
||||
|
||||
value = fabs (value); /* avoid negative zero */
|
||||
g_object_set (line,
|
||||
"sliders", private->sliders,
|
||||
NULL);
|
||||
|
||||
slider->value = value;
|
||||
/* slider tearing */
|
||||
private->remove_slider = dist > SLIDER_TEAR_DISTANCE;
|
||||
|
||||
g_object_set (line,
|
||||
"sliders", private->sliders,
|
||||
NULL);
|
||||
}
|
||||
/* eek! */
|
||||
{
|
||||
GimpCursorType cursor;
|
||||
GimpToolCursorType tool_cursor;
|
||||
GimpCursorModifier modifier;
|
||||
|
||||
cursor = shell->current_cursor;
|
||||
tool_cursor = shell->tool_cursor;
|
||||
modifier = GIMP_CURSOR_MODIFIER_NONE;
|
||||
|
||||
gimp_tool_line_get_cursor (GIMP_TOOL_WIDGET (line), NULL, 0,
|
||||
&cursor, &tool_cursor, &modifier);
|
||||
|
||||
gimp_display_shell_set_cursor (shell, cursor, tool_cursor, modifier);
|
||||
}
|
||||
|
||||
gimp_tool_line_update_handles (line);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -984,22 +1173,53 @@ static void
|
||||
gimp_tool_line_update_handles (GimpToolLine *line)
|
||||
{
|
||||
GimpToolLinePrivate *private = line->private;
|
||||
GimpCanvasItem *handle;
|
||||
gboolean visible;
|
||||
|
||||
handle = gimp_tool_line_get_handle (line, private->hover);
|
||||
|
||||
visible = handle && private->grab == GRAB_NONE;
|
||||
visible = (private->grab == GRAB_NONE &&
|
||||
private->hover != GIMP_TOOL_LINE_HANDLE_NONE) ||
|
||||
(private->grab == GRAB_SELECTION &&
|
||||
private->remove_slider);
|
||||
|
||||
if (visible)
|
||||
{
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
gint width;
|
||||
gint height;
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
gint width;
|
||||
gint height;
|
||||
gboolean dashed;
|
||||
|
||||
gimp_canvas_handle_get_position (handle, &x, &y);
|
||||
gimp_canvas_handle_get_size (handle, &width, &height);
|
||||
if (private->grab == GRAB_NONE && private->hover == HOVER_NEW_SLIDER)
|
||||
{
|
||||
/* new slider */
|
||||
x = private->x1 +
|
||||
(private->x2 - private->x1) * private->new_slider_value;
|
||||
y = private->y1 +
|
||||
(private->y2 - private->y1) * private->new_slider_value;
|
||||
|
||||
width = height = SLIDER_HANDLE_SIZE;
|
||||
|
||||
dashed = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
GimpCanvasItem *handle;
|
||||
|
||||
if (private->grab == GRAB_SELECTION)
|
||||
{
|
||||
/* tear slider */
|
||||
handle = gimp_tool_line_get_handle (line, private->selection);
|
||||
dashed = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* hover over handle */
|
||||
handle = gimp_tool_line_get_handle (line, private->hover);
|
||||
dashed = FALSE;
|
||||
}
|
||||
|
||||
gimp_canvas_handle_get_position (handle, &x, &y);
|
||||
gimp_canvas_handle_get_size (handle, &width, &height);
|
||||
}
|
||||
|
||||
width = MAX (width, SLIDER_HANDLE_SIZE);
|
||||
height = MAX (height, SLIDER_HANDLE_SIZE);
|
||||
@ -1009,6 +1229,11 @@ gimp_tool_line_update_handles (GimpToolLine *line)
|
||||
|
||||
gimp_canvas_handle_set_position (private->handle_circle, x, y);
|
||||
gimp_canvas_handle_set_size (private->handle_circle, width, height);
|
||||
|
||||
g_object_set (private->handle_circle,
|
||||
"type", dashed ? GIMP_HANDLE_DASHED_CIRCLE :
|
||||
GIMP_HANDLE_CIRCLE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
gimp_canvas_item_set_visible (private->handle_circle, visible);
|
||||
|
@ -60,7 +60,13 @@ struct _GimpToolLineClass
|
||||
GimpToolWidgetClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (* selection_changed) (GimpToolLine *line);
|
||||
gboolean (* can_add_slider) (GimpToolLine *line,
|
||||
gdouble value);
|
||||
gint (* add_slider) (GimpToolLine *line,
|
||||
gdouble value);
|
||||
void (* remove_slider) (GimpToolLine *line,
|
||||
gint slider);
|
||||
void (* selection_changed) (GimpToolLine *line);
|
||||
};
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user