app: make painting possibly multi-drawable aware.

- Make the various virtual methods of GimpPaintCore use a list of
  drawables as argument instead of a single drawable.
- gimp_brush_core_eval_transform_dynamics() can work with an image as
  argument rather than a drawable as it doesn't actually depends on
  specific drawable data.
- New function gimp_paint_tool_enable_multi_paint() to be used in init()
  method of paint tools to announce that this tool can work with
  multiple layers selected.
- Use gimp_paint_tool_enable_multi_paint() in the GimpSourceTool base
  class only for now.

This is a first step for multi-layer drawing, but we don't want it to be
possible in just any random cases, which is why I add a special function
to advertize this capability. We will use it for special-casing the
clone (as well as heal and perspective tools most likely) tool to work
on several layers at once. At this step, it is still very bugged and not
really working properly. In particular, since we don't process the
drawable offset early anymore (because it makes no sense when we pass a
list of drawables with different offsets), I suspect that all the
offset-related code will be very broken.
This commit is contained in:
Jehan 2021-08-16 23:46:32 +02:00
parent e0ac71bfcc
commit 8934d43975
21 changed files with 545 additions and 445 deletions

View File

@ -49,7 +49,7 @@ enum
static void gimp_airbrush_finalize (GObject *object);
static void gimp_airbrush_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -123,7 +123,7 @@ gimp_airbrush_finalize (GObject *object)
static void
gimp_airbrush_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -133,6 +133,8 @@ gimp_airbrush_paint (GimpPaintCore *paint_core,
GimpAirbrushOptions *options = GIMP_AIRBRUSH_OPTIONS (paint_options);
GimpDynamics *dynamics = GIMP_BRUSH_CORE (paint_core)->dynamics;
g_return_if_fail (g_list_length (drawables) == 1);
if (airbrush->timeout_id)
{
g_source_remove (airbrush->timeout_id);
@ -142,18 +144,18 @@ gimp_airbrush_paint (GimpPaintCore *paint_core,
switch (paint_state)
{
case GIMP_PAINT_STATE_INIT:
GIMP_PAINT_CORE_CLASS (parent_class)->paint (paint_core, drawable,
GIMP_PAINT_CORE_CLASS (parent_class)->paint (paint_core, drawables,
paint_options,
sym,
paint_state, time);
break;
case GIMP_PAINT_STATE_MOTION:
gimp_airbrush_motion (paint_core, drawable, paint_options, sym);
gimp_airbrush_motion (paint_core, drawables->data, paint_options, sym);
if ((options->rate != 0.0) && ! options->motion_only)
{
GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawables->data));
gdouble fade_point;
gdouble dynamic_rate;
gint timeout;
@ -162,7 +164,7 @@ gimp_airbrush_paint (GimpPaintCore *paint_core,
fade_point = gimp_paint_options_get_fade (paint_options, image,
paint_core->pixel_dist);
airbrush->drawable = drawable;
airbrush->drawable = drawables->data;
airbrush->paint_options = paint_options;
if (airbrush->sym)
@ -191,7 +193,7 @@ gimp_airbrush_paint (GimpPaintCore *paint_core,
break;
case GIMP_PAINT_STATE_FINISH:
GIMP_PAINT_CORE_CLASS (parent_class)->paint (paint_core, drawable,
GIMP_PAINT_CORE_CLASS (parent_class)->paint (paint_core, drawables,
paint_options,
sym,
paint_state, time);
@ -250,16 +252,20 @@ gimp_airbrush_timeout (gpointer data)
void
gimp_airbrush_stamp (GimpAirbrush *airbrush)
{
GList *drawables;
g_return_if_fail (GIMP_IS_AIRBRUSH (airbrush));
gimp_symmetry_set_origin (airbrush->sym,
airbrush->drawable, &airbrush->coords);
drawables = g_list_prepend (NULL, airbrush->drawable),
gimp_airbrush_paint (GIMP_PAINT_CORE (airbrush),
airbrush->drawable,
drawables,
airbrush->paint_options,
airbrush->sym,
GIMP_PAINT_STATE_MOTION, 0);
g_list_free (drawables);
gimp_symmetry_clear_origin (airbrush->sym);
}

View File

@ -65,22 +65,22 @@ enum
static void gimp_brush_core_finalize (GObject *object);
static gboolean gimp_brush_core_start (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
GError **error);
static gboolean gimp_brush_core_pre_paint (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpPaintState paint_state,
guint32 time);
static void gimp_brush_core_post_paint (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpPaintState paint_state,
guint32 time);
static void gimp_brush_core_interpolate (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
guint32 time);
@ -249,7 +249,7 @@ gimp_brush_core_finalize (GObject *object)
static gboolean
gimp_brush_core_pre_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpPaintState paint_state,
guint32 time)
@ -281,7 +281,7 @@ gimp_brush_core_pre_paint (GimpPaintCore *paint_core,
/*No drawing anything if the scale is too small*/
if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_transforming_brush)
{
GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawables->data));
gdouble fade_point;
if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_dynamic_transforming_brush)
@ -337,7 +337,7 @@ gimp_brush_core_pre_paint (GimpPaintCore *paint_core,
static void
gimp_brush_core_post_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpPaintState paint_state,
guint32 time)
@ -352,13 +352,16 @@ gimp_brush_core_post_paint (GimpPaintCore *paint_core,
static gboolean
gimp_brush_core_start (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
GError **error)
{
GimpBrushCore *core = GIMP_BRUSH_CORE (paint_core);
GimpContext *context = GIMP_CONTEXT (paint_options);
GimpImage *image = NULL;
g_return_val_if_fail (drawables != NULL, FALSE);
gimp_brush_core_set_brush (core, gimp_context_get_brush (context));
@ -378,10 +381,17 @@ gimp_brush_core_start (GimpPaintCore *paint_core,
return FALSE;
}
for (GList *iter = drawables; iter; iter = iter->next)
if (image == NULL)
image = gimp_item_get_image (GIMP_ITEM (iter->data));
else
g_return_val_if_fail (image == gimp_item_get_image (GIMP_ITEM (iter->data)),
FALSE);
if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_transforming_brush)
{
gimp_brush_core_eval_transform_dynamics (core,
drawable,
image,
paint_options,
coords);
@ -393,8 +403,7 @@ gimp_brush_core_start (GimpPaintCore *paint_core,
core->brush = core->main_brush;
core->jitter =
gimp_paint_options_get_jitter (paint_options,
gimp_item_get_image (GIMP_ITEM (drawable)));
gimp_paint_options_get_jitter (paint_options, image);
return TRUE;
}
@ -427,12 +436,12 @@ gimp_avoid_exact_integer (gdouble *x)
static void
gimp_brush_core_interpolate (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
guint32 time)
{
GimpBrushCore *core = GIMP_BRUSH_CORE (paint_core);
GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawables->data));
GimpDynamicsOutput *spacing_output;
GimpCoords last_coords;
GimpCoords current_coords;
@ -496,7 +505,7 @@ gimp_brush_core_interpolate (GimpPaintCore *paint_core,
{
gimp_paint_core_set_last_coords (paint_core, &current_coords);
gimp_paint_core_paint (paint_core, drawable, paint_options,
gimp_paint_core_paint (paint_core, drawables, paint_options,
GIMP_PAINT_STATE_MOTION, time);
paint_core->pixel_dist = pixel_initial + pixel_dist; /* Don't forget to update pixel distance*/
@ -757,7 +766,7 @@ gimp_brush_core_interpolate (GimpPaintCore *paint_core,
paint_core->distance = initial + t * dist;
paint_core->pixel_dist = pixel_initial + t * pixel_dist;
gimp_paint_core_paint (paint_core, drawable, paint_options,
gimp_paint_core_paint (paint_core, drawables, paint_options,
GIMP_PAINT_STATE_MOTION, time);
}
@ -1140,7 +1149,7 @@ gimp_brush_core_get_brush_pixmap (GimpBrushCore *core)
void
gimp_brush_core_eval_transform_dynamics (GimpBrushCore *core,
GimpDrawable *drawable,
GimpImage *image,
GimpPaintOptions *paint_options,
const GimpCoords *coords)
{
@ -1186,9 +1195,8 @@ gimp_brush_core_eval_transform_dynamics (GimpBrushCore *core,
{
gdouble fade_point = 1.0;
if (drawable)
if (image)
{
GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
GimpPaintCore *paint_core = GIMP_PAINT_CORE (core);
fade_point = gimp_paint_options_get_fade (paint_options, image,

View File

@ -140,7 +140,7 @@ const GimpTempBuf * gimp_brush_core_get_brush_pixmap
void gimp_brush_core_eval_transform_dynamics
(GimpBrushCore *core,
GimpDrawable *drawable,
GimpImage *image,
GimpPaintOptions *paint_options,
const GimpCoords *coords);
void gimp_brush_core_eval_transform_symmetry

View File

@ -46,7 +46,7 @@
static gboolean gimp_clone_start (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
GError **error);
@ -110,14 +110,14 @@ gimp_clone_init (GimpClone *clone)
static gboolean
gimp_clone_start (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
GError **error)
{
GimpCloneOptions *options = GIMP_CLONE_OPTIONS (paint_options);
if (! GIMP_PAINT_CORE_CLASS (parent_class)->start (paint_core, drawable,
if (! GIMP_PAINT_CORE_CLASS (parent_class)->start (paint_core, drawables,
paint_options, coords,
error))
{

View File

@ -47,7 +47,7 @@
static void gimp_convolve_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -101,16 +101,19 @@ gimp_convolve_init (GimpConvolve *convolve)
static void
gimp_convolve_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
guint32 time)
{
g_return_if_fail (g_list_length (drawables) == 1);
switch (paint_state)
{
case GIMP_PAINT_STATE_MOTION:
gimp_convolve_motion (paint_core, drawable, paint_options, sym);
for (GList *iter = drawables; iter; iter = iter->next)
gimp_convolve_motion (paint_core, iter->data, paint_options, sym);
break;
default:
@ -156,7 +159,7 @@ gimp_convolve_motion (GimpPaintCore *paint_core,
return;
gimp_brush_core_eval_transform_dynamics (GIMP_BRUSH_CORE (paint_core),
drawable,
image,
paint_options,
coords);
n_strokes = gimp_symmetry_get_size (sym);

View File

@ -40,7 +40,7 @@
static void gimp_dodge_burn_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -86,19 +86,22 @@ gimp_dodge_burn_init (GimpDodgeBurn *dodgeburn)
static void
gimp_dodge_burn_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
guint32 time)
{
g_return_if_fail (g_list_length (drawables) == 1);
switch (paint_state)
{
case GIMP_PAINT_STATE_INIT:
break;
case GIMP_PAINT_STATE_MOTION:
gimp_dodge_burn_motion (paint_core, drawable, paint_options, sym);
for (GList *iter = drawables; iter; iter = iter->next)
gimp_dodge_burn_motion (paint_core, iter->data, paint_options, sym);
break;
case GIMP_PAINT_STATE_FINISH:
@ -142,12 +145,12 @@ gimp_dodge_burn_motion (GimpPaintCore *paint_core,
return;
if (paint_options->application_mode == GIMP_PAINT_CONSTANT)
src_buffer = gimp_paint_core_get_orig_image (paint_core);
src_buffer = gimp_paint_core_get_orig_image (paint_core, drawable);
else
src_buffer = gimp_drawable_get_buffer (drawable);
gimp_brush_core_eval_transform_dynamics (brush_core,
drawable,
image,
paint_options,
coords);
n_strokes = gimp_symmetry_get_size (sym);

View File

@ -68,7 +68,7 @@
*/
static gboolean gimp_heal_start (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
GError **error);
@ -138,21 +138,21 @@ gimp_heal_init (GimpHeal *heal)
static gboolean
gimp_heal_start (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
GError **error)
{
GimpSourceCore *source_core = GIMP_SOURCE_CORE (paint_core);
if (! GIMP_PAINT_CORE_CLASS (parent_class)->start (paint_core, drawable,
if (! GIMP_PAINT_CORE_CLASS (parent_class)->start (paint_core, drawables,
paint_options, coords,
error))
{
return FALSE;
}
if (! source_core->set_source && gimp_drawable_is_indexed (drawable))
if (! source_core->set_source && gimp_drawable_is_indexed (drawables->data))
{
g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
_("Healing does not operate on indexed layers."));

View File

@ -54,7 +54,7 @@
static void gimp_ink_finalize (GObject *object);
static void gimp_ink_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -149,7 +149,7 @@ gimp_ink_finalize (GObject *object)
static void
gimp_ink_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -159,6 +159,8 @@ gimp_ink_paint (GimpPaintCore *paint_core,
GimpCoords *cur_coords;
GimpCoords last_coords;
g_return_if_fail (g_list_length (drawables) == 1);
gimp_paint_core_get_last_coords (paint_core, &last_coords);
cur_coords = gimp_symmetry_get_origin (sym);
@ -215,7 +217,8 @@ gimp_ink_paint (GimpPaintCore *paint_core,
break;
case GIMP_PAINT_STATE_MOTION:
gimp_ink_motion (paint_core, drawable, paint_options, sym, time);
for (GList *iter = drawables; iter; iter = iter->next)
gimp_ink_motion (paint_core, iter->data, paint_options, sym, time);
break;
case GIMP_PAINT_STATE_FINISH:

View File

@ -62,16 +62,16 @@ struct _GimpMybrushCorePrivate
static void gimp_mybrush_core_finalize (GObject *object);
static gboolean gimp_mybrush_core_start (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
GError **error);
static void gimp_mybrush_core_interpolate (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
guint32 time);
static void gimp_mybrush_core_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -141,7 +141,7 @@ gimp_mybrush_core_finalize (GObject *object)
static gboolean
gimp_mybrush_core_start (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
GError **error)
@ -163,7 +163,7 @@ gimp_mybrush_core_start (GimpPaintCore *paint_core,
static void
gimp_mybrush_core_interpolate (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
guint32 time)
{
@ -180,13 +180,13 @@ gimp_mybrush_core_interpolate (GimpPaintCore *paint_core,
mybrush->private->synthetic = TRUE;
gimp_paint_core_paint (paint_core, drawable, paint_options,
gimp_paint_core_paint (paint_core, drawables, paint_options,
GIMP_PAINT_STATE_MOTION, time);
paint_core->cur_coords = saved_coords;
}
gimp_paint_core_paint (paint_core, drawable, paint_options,
gimp_paint_core_paint (paint_core, drawables, paint_options,
GIMP_PAINT_STATE_MOTION, time);
paint_core->last_coords = paint_core->cur_coords;
@ -194,7 +194,7 @@ gimp_mybrush_core_interpolate (GimpPaintCore *paint_core,
static void
gimp_mybrush_core_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -204,6 +204,8 @@ gimp_mybrush_core_paint (GimpPaintCore *paint_core,
GimpContext *context = GIMP_CONTEXT (paint_options);
GimpRGB fg;
g_return_if_fail (g_list_length (drawables) == 1);
switch (paint_state)
{
case GIMP_PAINT_STATE_INIT:
@ -212,21 +214,21 @@ gimp_mybrush_core_paint (GimpPaintCore *paint_core,
gimp_symmetry_set_stateful (sym, TRUE);
mybrush->private->surface =
gimp_mypaint_surface_new (gimp_drawable_get_buffer (drawable),
gimp_drawable_get_active_mask (drawable),
gimp_mypaint_surface_new (gimp_drawable_get_buffer (drawables->data),
gimp_drawable_get_active_mask (drawables->data),
paint_core->mask_buffer,
paint_core->mask_x_offset,
paint_core->mask_y_offset,
GIMP_MYBRUSH_OPTIONS (paint_options));
gimp_mybrush_core_create_brushes (mybrush, drawable, paint_options, sym);
gimp_mybrush_core_create_brushes (mybrush, drawables->data, paint_options, sym);
mybrush->private->last_time = -1;
mybrush->private->synthetic = FALSE;
break;
case GIMP_PAINT_STATE_MOTION:
gimp_mybrush_core_motion (paint_core, drawable, paint_options,
gimp_mybrush_core_motion (paint_core, drawables->data, paint_options,
sym, time);
break;

View File

@ -47,7 +47,7 @@
static void gimp_paintbrush_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -104,7 +104,7 @@ gimp_paintbrush_init (GimpPaintbrush *paintbrush)
static void
gimp_paintbrush_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -112,26 +112,32 @@ gimp_paintbrush_paint (GimpPaintCore *paint_core,
{
GimpPaintbrush *paintbrush = GIMP_PAINTBRUSH (paint_core);
g_return_if_fail (g_list_length (drawables) == 1);
switch (paint_state)
{
case GIMP_PAINT_STATE_INIT:
{
GimpRGB color;
if (GIMP_PAINTBRUSH_GET_CLASS (paintbrush)->get_color_history_color &&
GIMP_PAINTBRUSH_GET_CLASS (paintbrush)->get_color_history_color (
paintbrush, drawable, paint_options, &color))
{
GimpContext *context = GIMP_CONTEXT (paint_options);
for (GList *iter = drawables; iter; iter = iter->next)
if (GIMP_PAINTBRUSH_GET_CLASS (paintbrush)->get_color_history_color &&
GIMP_PAINTBRUSH_GET_CLASS (paintbrush)->get_color_history_color (paintbrush,
iter->data,
paint_options,
&color))
{
GimpContext *context = GIMP_CONTEXT (paint_options);
gimp_palettes_add_color_history (context->gimp, &color);
}
gimp_palettes_add_color_history (context->gimp, &color);
}
}
break;
case GIMP_PAINT_STATE_MOTION:
_gimp_paintbrush_motion (paint_core, drawable, paint_options,
sym, GIMP_OPACITY_OPAQUE);
for (GList *iter = drawables; iter; iter = iter->next)
_gimp_paintbrush_motion (paint_core, iter->data, paint_options,
sym, GIMP_OPACITY_OPAQUE);
break;
case GIMP_PAINT_STATE_FINISH:
@ -258,7 +264,7 @@ _gimp_paintbrush_motion (GimpPaintCore *paint_core,
if (GIMP_BRUSH_CORE_GET_CLASS (brush_core)->handles_transforming_brush)
{
gimp_brush_core_eval_transform_dynamics (brush_core,
drawable,
image,
paint_options,
coords);
}

View File

@ -55,6 +55,9 @@ gimp_paint_core_stroke (GimpPaintCore *core,
gboolean push_undo,
GError **error)
{
GList *drawables;
gboolean success = FALSE;
g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), FALSE);
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE);
@ -63,36 +66,40 @@ gimp_paint_core_stroke (GimpPaintCore *core,
g_return_val_if_fail (n_strokes > 0, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (gimp_paint_core_start (core, drawable, paint_options, &strokes[0],
drawables = g_list_prepend (NULL, drawable);
if (gimp_paint_core_start (core, drawables, paint_options, &strokes[0],
error))
{
gint i;
core->last_coords = strokes[0];
gimp_paint_core_paint (core, drawable, paint_options,
gimp_paint_core_paint (core, drawables, paint_options,
GIMP_PAINT_STATE_INIT, 0);
gimp_paint_core_paint (core, drawable, paint_options,
gimp_paint_core_paint (core, drawables, paint_options,
GIMP_PAINT_STATE_MOTION, 0);
for (i = 1; i < n_strokes; i++)
{
gimp_paint_core_interpolate (core, drawable, paint_options,
gimp_paint_core_interpolate (core, drawables, paint_options,
&strokes[i], 0);
}
gimp_paint_core_paint (core, drawable, paint_options,
gimp_paint_core_paint (core, drawables, paint_options,
GIMP_PAINT_STATE_FINISH, 0);
gimp_paint_core_finish (core, drawable, push_undo);
gimp_paint_core_finish (core, drawables, push_undo);
gimp_paint_core_cleanup (core);
return TRUE;
success = TRUE;
}
return FALSE;
g_list_free (drawables);
return success;
}
gboolean
@ -107,6 +114,7 @@ gimp_paint_core_stroke_boundary (GimpPaintCore *core,
gboolean push_undo,
GError **error)
{
GList *drawables;
GimpBoundSeg *stroke_segs;
gint n_stroke_segs;
gint off_x;
@ -148,6 +156,8 @@ gimp_paint_core_stroke_boundary (GimpPaintCore *core,
n_coords++;
drawables = g_list_prepend (NULL, drawable);
for (s = 0; s < n_stroke_segs; s++)
{
while (stroke_segs[seg].x1 != -1 ||
@ -172,7 +182,7 @@ gimp_paint_core_stroke_boundary (GimpPaintCore *core,
gimp_paint_core_stroke_emulate_dynamics (coords, n_coords);
if (initialized ||
gimp_paint_core_start (core, drawable, paint_options, &coords[0],
gimp_paint_core_start (core, drawables, paint_options, &coords[0],
error))
{
gint i;
@ -182,19 +192,19 @@ gimp_paint_core_stroke_boundary (GimpPaintCore *core,
core->cur_coords = coords[0];
core->last_coords = coords[0];
gimp_paint_core_paint (core, drawable, paint_options,
gimp_paint_core_paint (core, drawables, paint_options,
GIMP_PAINT_STATE_INIT, 0);
gimp_paint_core_paint (core, drawable, paint_options,
gimp_paint_core_paint (core, drawables, paint_options,
GIMP_PAINT_STATE_MOTION, 0);
for (i = 1; i < n_coords; i++)
{
gimp_paint_core_interpolate (core, drawable, paint_options,
gimp_paint_core_interpolate (core, drawables, paint_options,
&coords[i], 0);
}
gimp_paint_core_paint (core, drawable, paint_options,
gimp_paint_core_paint (core, drawables, paint_options,
GIMP_PAINT_STATE_FINISH, 0);
}
else
@ -214,11 +224,12 @@ gimp_paint_core_stroke_boundary (GimpPaintCore *core,
if (initialized)
{
gimp_paint_core_finish (core, drawable, push_undo);
gimp_paint_core_finish (core, drawables, push_undo);
gimp_paint_core_cleanup (core);
}
g_list_free (drawables);
g_free (coords);
g_free (stroke_segs);
@ -234,6 +245,7 @@ gimp_paint_core_stroke_vectors (GimpPaintCore *core,
gboolean push_undo,
GError **error)
{
GList *drawables;
GList *stroke;
gboolean initialized = FALSE;
gboolean due_to_lack_of_points = FALSE;
@ -253,6 +265,8 @@ gimp_paint_core_stroke_vectors (GimpPaintCore *core,
off_x -= vectors_off_x;
off_y -= vectors_off_y;
drawables = g_list_prepend (NULL, drawable);
for (stroke = vectors->strokes->head;
stroke;
stroke = stroke->next)
@ -278,7 +292,7 @@ gimp_paint_core_stroke_vectors (GimpPaintCore *core,
coords->len);
if (initialized ||
gimp_paint_core_start (core, drawable, paint_options,
gimp_paint_core_start (core, drawables, paint_options,
&g_array_index (coords, GimpCoords, 0),
error))
{
@ -287,20 +301,20 @@ gimp_paint_core_stroke_vectors (GimpPaintCore *core,
core->cur_coords = g_array_index (coords, GimpCoords, 0);
core->last_coords = g_array_index (coords, GimpCoords, 0);
gimp_paint_core_paint (core, drawable, paint_options,
gimp_paint_core_paint (core, drawables, paint_options,
GIMP_PAINT_STATE_INIT, 0);
gimp_paint_core_paint (core, drawable, paint_options,
gimp_paint_core_paint (core, drawables, paint_options,
GIMP_PAINT_STATE_MOTION, 0);
for (i = 1; i < coords->len; i++)
{
gimp_paint_core_interpolate (core, drawable, paint_options,
gimp_paint_core_interpolate (core, drawables, paint_options,
&g_array_index (coords, GimpCoords, i),
0);
}
gimp_paint_core_paint (core, drawable, paint_options,
gimp_paint_core_paint (core, drawables, paint_options,
GIMP_PAINT_STATE_FINISH, 0);
}
else
@ -322,7 +336,7 @@ gimp_paint_core_stroke_vectors (GimpPaintCore *core,
if (initialized)
{
gimp_paint_core_finish (core, drawable, push_undo);
gimp_paint_core_finish (core, drawables, push_undo);
gimp_paint_core_cleanup (core);
}
@ -333,6 +347,8 @@ gimp_paint_core_stroke_vectors (GimpPaintCore *core,
_("Not enough points to stroke"));
}
g_list_free (drawables);
return initialized;
}

View File

@ -80,28 +80,28 @@ static void gimp_paint_core_get_property (GObject *object,
GParamSpec *pspec);
static gboolean gimp_paint_core_real_start (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
GError **error);
static gboolean gimp_paint_core_real_pre_paint (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *options,
GimpPaintState paint_state,
guint32 time);
static void gimp_paint_core_real_paint (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *options,
GimpSymmetry *sym,
GimpPaintState paint_state,
guint32 time);
static void gimp_paint_core_real_post_paint (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *options,
GimpPaintState paint_state,
guint32 time);
static void gimp_paint_core_real_interpolate (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *options,
guint32 time);
static GeglBuffer *
@ -154,6 +154,7 @@ static void
gimp_paint_core_init (GimpPaintCore *core)
{
core->ID = global_core_ID++;
core->undo_buffers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
}
static void
@ -164,6 +165,7 @@ gimp_paint_core_finalize (GObject *object)
gimp_paint_core_cleanup (core);
g_clear_pointer (&core->undo_desc, g_free);
g_hash_table_unref (core->undo_buffers);
if (core->stroke_buffer)
{
@ -217,7 +219,7 @@ gimp_paint_core_get_property (GObject *object,
static gboolean
gimp_paint_core_real_start (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
GError **error)
@ -227,7 +229,7 @@ gimp_paint_core_real_start (GimpPaintCore *core,
static gboolean
gimp_paint_core_real_pre_paint (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpPaintState paint_state,
guint32 time)
@ -237,7 +239,7 @@ gimp_paint_core_real_pre_paint (GimpPaintCore *core,
static void
gimp_paint_core_real_paint (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -247,7 +249,7 @@ gimp_paint_core_real_paint (GimpPaintCore *core,
static void
gimp_paint_core_real_post_paint (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpPaintState paint_state,
guint32 time)
@ -256,11 +258,11 @@ gimp_paint_core_real_post_paint (GimpPaintCore *core,
static void
gimp_paint_core_real_interpolate (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
guint32 time)
{
gimp_paint_core_paint (core, drawable, paint_options,
gimp_paint_core_paint (core, drawables, paint_options,
GIMP_PAINT_STATE_MOTION, time);
core->last_coords = core->cur_coords;
@ -297,7 +299,7 @@ gimp_paint_core_real_push_undo (GimpPaintCore *core,
void
gimp_paint_core_paint (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpPaintState paint_state,
guint32 time)
@ -305,22 +307,19 @@ gimp_paint_core_paint (GimpPaintCore *core,
GimpPaintCoreClass *core_class;
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
g_return_if_fail (drawables != NULL);
g_return_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options));
core_class = GIMP_PAINT_CORE_GET_CLASS (core);
if (core_class->pre_paint (core, drawable,
if (core_class->pre_paint (core, drawables,
paint_options,
paint_state, time))
{
GimpSymmetry *sym;
GimpImage *image;
GimpItem *item;
item = GIMP_ITEM (drawable);
image = gimp_item_get_image (item);
image = gimp_item_get_image (GIMP_ITEM (drawables->data));
if (paint_state == GIMP_PAINT_STATE_MOTION)
{
@ -330,16 +329,16 @@ gimp_paint_core_paint (GimpPaintCore *core,
}
sym = g_object_ref (gimp_image_get_active_symmetry (image));
gimp_symmetry_set_origin (sym, drawable, &core->cur_coords);
gimp_symmetry_set_origin (sym, drawables->data, &core->cur_coords);
core_class->paint (core, drawable,
core_class->paint (core, drawables,
paint_options,
sym, paint_state, time);
gimp_symmetry_clear_origin (sym);
g_object_unref (sym);
core_class->post_paint (core, drawable,
core_class->post_paint (core, drawables,
paint_options,
paint_state, time);
}
@ -347,24 +346,24 @@ gimp_paint_core_paint (GimpPaintCore *core,
gboolean
gimp_paint_core_start (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
GError **error)
{
GimpImage *image;
GimpItem *item;
GimpChannel *mask;
g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), FALSE);
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE);
g_return_val_if_fail (g_list_length (drawables) > 0, FALSE);
g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), FALSE);
g_return_val_if_fail (coords != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
item = GIMP_ITEM (drawable);
image = gimp_item_get_image (item);
for (GList *iter = drawables; iter; iter = iter->next)
g_return_val_if_fail (gimp_item_is_attached (iter->data), FALSE);
image = gimp_item_get_image (GIMP_ITEM (drawables->data));
if (core->stroke_buffer)
{
@ -378,22 +377,15 @@ gimp_paint_core_start (GimpPaintCore *core,
/* remember the last stroke's endpoint for later undo */
core->start_coords = core->last_coords;
core->cur_coords = *coords;
core->cur_coords = *coords;
if (! GIMP_PAINT_CORE_GET_CLASS (core)->start (core, drawable,
if (! GIMP_PAINT_CORE_GET_CLASS (core)->start (core, drawables,
paint_options,
coords, error))
{
return FALSE;
}
/* Allocate the undo structure */
if (core->undo_buffer)
g_object_unref (core->undo_buffer);
core->undo_buffer = gimp_gegl_buffer_dup (gimp_drawable_get_buffer (drawable));
/* Set the image pickable */
if (! core->show_all)
core->image_pickable = GIMP_PICKABLE (image);
@ -410,80 +402,86 @@ gimp_paint_core_start (GimpPaintCore *core,
core->saved_proj_buffer = gimp_gegl_buffer_dup (buffer);
}
/* Allocate the canvas blocks structure */
if (core->canvas_buffer)
g_object_unref (core->canvas_buffer);
core->canvas_buffer =
gegl_buffer_new (GEGL_RECTANGLE (0, 0,
gimp_item_get_width (item),
gimp_item_get_height (item)),
babl_format ("Y float"));
/* Get the initial undo extents */
core->x1 = core->x2 = core->cur_coords.x;
core->y1 = core->y2 = core->cur_coords.y;
core->last_paint.x = -1e6;
core->last_paint.y = -1e6;
mask = gimp_image_get_mask (image);
/* don't apply the mask to itself and don't apply an empty mask */
if (GIMP_DRAWABLE (mask) != drawable && ! gimp_channel_is_empty (mask))
for (GList *iter = drawables; iter; iter = iter->next)
{
GeglBuffer *mask_buffer;
gint offset_x;
gint offset_y;
/* Allocate the undo structures */
g_hash_table_insert (core->undo_buffers, iter->data,
gimp_gegl_buffer_dup (gimp_drawable_get_buffer (iter->data)));
mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
gimp_item_get_offset (item, &offset_x, &offset_y);
/* Allocate the canvas blocks structure */
if (core->canvas_buffer)
g_object_unref (core->canvas_buffer);
core->mask_buffer = g_object_ref (mask_buffer);
core->mask_x_offset = -offset_x;
core->mask_y_offset = -offset_y;
}
else
{
core->mask_buffer = NULL;
}
core->canvas_buffer =
gegl_buffer_new (GEGL_RECTANGLE (0, 0,
gimp_item_get_width (iter->data),
gimp_item_get_height (iter->data)),
babl_format ("Y float"));
if (paint_options->use_applicator)
{
core->applicator = gimp_applicator_new (NULL);
/* Get the initial undo extents */
if (core->mask_buffer)
core->x1 = core->x2 = core->cur_coords.x;
core->y1 = core->y2 = core->cur_coords.y;
core->last_paint.x = -1e6;
core->last_paint.y = -1e6;
mask = gimp_image_get_mask (image);
/* don't apply the mask to itself and don't apply an empty mask */
if (GIMP_DRAWABLE (mask) != iter->data && ! gimp_channel_is_empty (mask))
{
gimp_applicator_set_mask_buffer (core->applicator,
core->mask_buffer);
gimp_applicator_set_mask_offset (core->applicator,
core->mask_x_offset,
core->mask_y_offset);
GeglBuffer *mask_buffer;
gint offset_x;
gint offset_y;
mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
gimp_item_get_offset (iter->data, &offset_x, &offset_y);
core->mask_buffer = g_object_ref (mask_buffer);
core->mask_x_offset = -offset_x;
core->mask_y_offset = -offset_y;
}
else
{
core->mask_buffer = NULL;
}
gimp_applicator_set_affect (core->applicator,
gimp_drawable_get_active_mask (drawable));
gimp_applicator_set_dest_buffer (core->applicator,
gimp_drawable_get_buffer (drawable));
}
if (paint_options->use_applicator)
{
core->applicator = gimp_applicator_new (NULL);
/* Freeze the drawable preview so that it isn't constantly updated. */
gimp_viewable_preview_freeze (GIMP_VIEWABLE (drawable));
if (core->mask_buffer)
{
gimp_applicator_set_mask_buffer (core->applicator,
core->mask_buffer);
gimp_applicator_set_mask_offset (core->applicator,
core->mask_x_offset,
core->mask_y_offset);
}
gimp_applicator_set_affect (core->applicator,
gimp_drawable_get_active_mask (iter->data));
gimp_applicator_set_dest_buffer (core->applicator,
gimp_drawable_get_buffer (iter->data));
}
/* Freeze the drawable preview so that it isn't constantly updated. */
gimp_viewable_preview_freeze (GIMP_VIEWABLE (iter->data));
}
return TRUE;
}
void
gimp_paint_core_finish (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
gboolean push_undo)
{
GimpImage *image;
gboolean undo_group_started = FALSE;
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
g_clear_object (&core->applicator);
@ -495,72 +493,87 @@ gimp_paint_core_finish (GimpPaintCore *core,
g_clear_object (&core->mask_buffer);
image = gimp_item_get_image (GIMP_ITEM (drawable));
image = gimp_item_get_image (GIMP_ITEM (drawables->data));
/* Determine if any part of the image has been altered--
* if nothing has, then just return...
*/
if ((core->x2 == core->x1) || (core->y2 == core->y1))
for (GList *iter = drawables; iter; iter = iter->next)
{
gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable));
return;
}
/* Determine if any part of the image has been altered--
* if nothing has, then just go to the next drawable...
*/
if ((core->x2 == core->x1) || (core->y2 == core->y1))
{
gimp_viewable_preview_thaw (GIMP_VIEWABLE (iter->data));
continue;
}
if (push_undo)
{
GeglBuffer *buffer;
GeglRectangle rect;
if (push_undo)
{
GeglBuffer *undo_buffer;
GeglBuffer *buffer;
GeglRectangle rect;
gimp_rectangle_intersect (core->x1, core->y1,
core->x2 - core->x1, core->y2 - core->y1,
0, 0,
gimp_item_get_width (GIMP_ITEM (drawable)),
gimp_item_get_height (GIMP_ITEM (drawable)),
&rect.x, &rect.y, &rect.width, &rect.height);
if (! g_hash_table_steal_extended (core->undo_buffers, iter->data,
NULL, (gpointer*) &undo_buffer))
{
g_critical ("%s: missing undo buffer for '%s'.",
G_STRFUNC, gimp_object_get_name (iter->data));
continue;
}
gegl_rectangle_align_to_buffer (&rect, &rect, core->undo_buffer,
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
gimp_rectangle_intersect (core->x1, core->y1,
core->x2 - core->x1, core->y2 - core->y1,
0, 0,
gimp_item_get_width (GIMP_ITEM (iter->data)),
gimp_item_get_height (GIMP_ITEM (iter->data)),
&rect.x, &rect.y, &rect.width, &rect.height);
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_PAINT,
core->undo_desc);
gegl_rectangle_align_to_buffer (&rect, &rect, undo_buffer,
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
GIMP_PAINT_CORE_GET_CLASS (core)->push_undo (core, image, NULL);
if (! undo_group_started)
{
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_PAINT,
core->undo_desc);
undo_group_started = TRUE;
}
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, rect.width, rect.height),
gimp_drawable_get_format (drawable));
GIMP_PAINT_CORE_GET_CLASS (core)->push_undo (core, image, NULL);
gimp_gegl_buffer_copy (core->undo_buffer,
&rect,
GEGL_ABYSS_NONE,
buffer,
GEGL_RECTANGLE (0, 0, 0, 0));
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, rect.width, rect.height),
gimp_drawable_get_format (iter->data));
gimp_drawable_push_undo (drawable, NULL,
buffer, rect.x, rect.y, rect.width, rect.height);
gimp_gegl_buffer_copy (undo_buffer,
&rect,
GEGL_ABYSS_NONE,
buffer,
GEGL_RECTANGLE (0, 0, 0, 0));
g_object_unref (buffer);
gimp_drawable_push_undo (iter->data, NULL,
buffer, rect.x, rect.y, rect.width, rect.height);
gimp_image_undo_group_end (image);
g_object_unref (buffer);
g_object_unref (undo_buffer);
}
gimp_viewable_preview_thaw (GIMP_VIEWABLE (iter->data));
}
core->image_pickable = NULL;
g_clear_object (&core->undo_buffer);
g_clear_object (&core->saved_proj_buffer);
gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable));
if (undo_group_started)
gimp_image_undo_group_end (image);
}
void
gimp_paint_core_cancel (GimpPaintCore *core,
GimpDrawable *drawable)
GList *drawables)
{
gint x, y;
gint width, height;
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
/* Determine if any part of the image has been altered--
* if nothing has, then just return...
@ -568,34 +581,46 @@ gimp_paint_core_cancel (GimpPaintCore *core,
if ((core->x2 == core->x1) || (core->y2 == core->y1))
return;
if (gimp_rectangle_intersect (core->x1, core->y1,
core->x2 - core->x1,
core->y2 - core->y1,
0, 0,
gimp_item_get_width (GIMP_ITEM (drawable)),
gimp_item_get_height (GIMP_ITEM (drawable)),
&x, &y, &width, &height))
for (GList *iter = drawables; iter; iter = iter->next)
{
GeglRectangle rect;
if (gimp_rectangle_intersect (core->x1, core->y1,
core->x2 - core->x1,
core->y2 - core->y1,
0, 0,
gimp_item_get_width (GIMP_ITEM (iter->data)),
gimp_item_get_height (GIMP_ITEM (iter->data)),
&x, &y, &width, &height))
{
GeglBuffer *undo_buffer;
GeglRectangle rect;
gegl_rectangle_align_to_buffer (&rect,
GEGL_RECTANGLE (x, y, width, height),
gimp_drawable_get_buffer (drawable),
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
if (! g_hash_table_steal_extended (core->undo_buffers, iter->data,
NULL, (gpointer*) &undo_buffer))
{
g_critical ("%s: missing undo buffer for '%s'.",
G_STRFUNC, gimp_object_get_name (iter->data));
continue;
}
gimp_gegl_buffer_copy (core->undo_buffer,
&rect,
GEGL_ABYSS_NONE,
gimp_drawable_get_buffer (drawable),
&rect);
gegl_rectangle_align_to_buffer (&rect,
GEGL_RECTANGLE (x, y, width, height),
gimp_drawable_get_buffer (iter->data),
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
gimp_gegl_buffer_copy (undo_buffer,
&rect,
GEGL_ABYSS_NONE,
gimp_drawable_get_buffer (iter->data),
&rect);
g_object_unref (undo_buffer);
}
gimp_drawable_update (iter->data, x, y, width, height);
gimp_viewable_preview_thaw (GIMP_VIEWABLE (iter->data));
}
g_clear_object (&core->undo_buffer);
g_clear_object (&core->saved_proj_buffer);
gimp_drawable_update (drawable, x, y, width, height);
gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable));
}
void
@ -603,7 +628,8 @@ gimp_paint_core_cleanup (GimpPaintCore *core)
{
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
g_clear_object (&core->undo_buffer);
g_hash_table_remove_all (core->undo_buffers);
g_clear_object (&core->saved_proj_buffer);
g_clear_object (&core->canvas_buffer);
g_clear_object (&core->paint_buffer);
@ -611,20 +637,19 @@ gimp_paint_core_cleanup (GimpPaintCore *core)
void
gimp_paint_core_interpolate (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
guint32 time)
{
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
g_return_if_fail (drawables != NULL);
g_return_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options));
g_return_if_fail (coords != NULL);
core->cur_coords = *coords;
GIMP_PAINT_CORE_GET_CLASS (core)->interpolate (core, drawable,
GIMP_PAINT_CORE_GET_CLASS (core)->interpolate (core, drawables,
paint_options, time);
}
@ -779,12 +804,17 @@ gimp_paint_core_get_image_pickable (GimpPaintCore *core)
}
GeglBuffer *
gimp_paint_core_get_orig_image (GimpPaintCore *core)
gimp_paint_core_get_orig_image (GimpPaintCore *core,
GimpDrawable *drawable)
{
g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), NULL);
g_return_val_if_fail (core->undo_buffer != NULL, NULL);
GeglBuffer *undo_buffer;
return core->undo_buffer;
g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), NULL);
undo_buffer = g_hash_table_lookup (core->undo_buffers, drawable);
g_return_val_if_fail (undo_buffer != NULL, NULL);
return undo_buffer;
}
GeglBuffer *
@ -807,9 +837,12 @@ gimp_paint_core_paste (GimpPaintCore *core,
GimpLayerMode paint_mode,
GimpPaintApplicationMode mode)
{
gint width = gegl_buffer_get_width (core->paint_buffer);
gint height = gegl_buffer_get_height (core->paint_buffer);
GimpComponentMask affect = gimp_drawable_get_active_mask (drawable);
gint width = gegl_buffer_get_width (core->paint_buffer);
gint height = gegl_buffer_get_height (core->paint_buffer);
GimpComponentMask affect = gimp_drawable_get_active_mask (drawable);
GeglBuffer *undo_buffer;
undo_buffer = g_hash_table_lookup (core->undo_buffers, drawable);
if (! affect)
return;
@ -851,8 +884,7 @@ gimp_paint_core_paste (GimpPaintCore *core,
GEGL_RECTANGLE (0, 0, width, height),
1.0);
gimp_applicator_set_src_buffer (core->applicator,
core->undo_buffer);
gimp_applicator_set_src_buffer (core->applicator, undo_buffer);
}
/* Otherwise:
* combine the paint mask to the paint buffer directly
@ -931,7 +963,7 @@ gimp_paint_core_paste (GimpPaintCore *core,
algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK;
/* undo buf -> paint_buf -> dest_buffer */
params.src_buffer = core->undo_buffer;
params.src_buffer = undo_buffer;
}
else
{
@ -998,8 +1030,9 @@ gimp_paint_core_replace (GimpPaintCore *core,
gdouble image_opacity,
GimpPaintApplicationMode mode)
{
gint width, height;
GimpComponentMask affect;
GeglBuffer *undo_buffer;
gint width, height;
GimpComponentMask affect;
if (! gimp_drawable_has_alpha (drawable))
{
@ -1022,6 +1055,8 @@ gimp_paint_core_replace (GimpPaintCore *core,
if (! affect)
return;
undo_buffer = g_hash_table_lookup (core->undo_buffers, drawable);
if (core->applicator)
{
GeglRectangle mask_rect;
@ -1060,8 +1095,7 @@ gimp_paint_core_replace (GimpPaintCore *core,
core->paint_buffer_y,
width, height);
gimp_applicator_set_src_buffer (core->applicator,
core->undo_buffer);
gimp_applicator_set_src_buffer (core->applicator, undo_buffer);
}
/* Otherwise:
* use the paint mask as the mask buffer directly

View File

@ -59,7 +59,7 @@ struct _GimpPaintCore
GimpPickable *image_pickable; /* the image pickable */
GeglBuffer *undo_buffer; /* pixels which have been modified */
GHashTable *undo_buffers; /* pixels which have been modified */
GeglBuffer *saved_proj_buffer; /* proj tiles which have been modified */
GeglBuffer *canvas_buffer; /* the buffer to paint the mask to */
GeglBuffer *paint_buffer; /* the buffer to paint pixels to */
@ -81,30 +81,30 @@ struct _GimpPaintCoreClass
/* virtual functions */
gboolean (* start) (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
GError **error);
gboolean (* pre_paint) (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpPaintState paint_state,
guint32 time);
void (* paint) (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
guint32 time);
void (* post_paint) (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpPaintState paint_state,
guint32 time);
void (* interpolate) (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
guint32 time);
@ -127,25 +127,25 @@ struct _GimpPaintCoreClass
GType gimp_paint_core_get_type (void) G_GNUC_CONST;
void gimp_paint_core_paint (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpPaintState state,
guint32 time);
gboolean gimp_paint_core_start (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
GError **error);
void gimp_paint_core_finish (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
gboolean push_undo);
void gimp_paint_core_cancel (GimpPaintCore *core,
GimpDrawable *drawable);
GList *drawables);
void gimp_paint_core_cleanup (GimpPaintCore *core);
void gimp_paint_core_interpolate (GimpPaintCore *core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
guint32 time);
@ -186,7 +186,8 @@ GeglBuffer * gimp_paint_core_get_paint_buffer (GimpPaintCore *core,
GimpPickable * gimp_paint_core_get_image_pickable (GimpPaintCore *core);
GeglBuffer * gimp_paint_core_get_orig_image (GimpPaintCore *core);
GeglBuffer * gimp_paint_core_get_orig_image (GimpPaintCore *core,
GimpDrawable *drawable);
GeglBuffer * gimp_paint_core_get_orig_proj (GimpPaintCore *core);
void gimp_paint_core_paste (GimpPaintCore *core,

View File

@ -47,7 +47,7 @@
static void gimp_perspective_clone_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -119,7 +119,7 @@ gimp_perspective_clone_init (GimpPerspectiveClone *clone)
static void
gimp_perspective_clone_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -140,7 +140,7 @@ gimp_perspective_clone_paint (GimpPaintCore *paint_core,
case GIMP_PAINT_STATE_INIT:
if (source_core->set_source)
{
g_object_set (source_core, "src-drawable", drawable, NULL);
g_object_set (source_core, "src-drawable", drawables->data, NULL);
source_core->src_x = floor (coords->x);
source_core->src_y = floor (coords->y);
@ -194,12 +194,12 @@ gimp_perspective_clone_paint (GimpPaintCore *paint_core,
if (options->sample_merged)
src_pickable = GIMP_PICKABLE (src_image);
dest_image = gimp_item_get_image (GIMP_ITEM (drawable));
dest_image = gimp_item_get_image (GIMP_ITEM (drawables->data));
if ((options->sample_merged &&
(src_image != dest_image)) ||
(! options->sample_merged &&
(source_core->src_drawable != drawable)))
(source_core->src_drawable != drawables->data)))
{
orig_buffer = gimp_pickable_get_buffer (src_pickable);
}
@ -208,7 +208,7 @@ gimp_perspective_clone_paint (GimpPaintCore *paint_core,
if (options->sample_merged)
orig_buffer = gimp_paint_core_get_orig_proj (paint_core);
else
orig_buffer = gimp_paint_core_get_orig_image (paint_core);
orig_buffer = gimp_paint_core_get_orig_image (paint_core, drawables->data);
}
}
break;
@ -326,7 +326,8 @@ gimp_perspective_clone_paint (GimpPaintCore *paint_core,
}
}
gimp_source_core_motion (source_core, drawable, paint_options, sym);
for (GList *iter = drawables; iter; iter = iter->next)
gimp_source_core_motion (source_core, iter->data, paint_options, sym);
}
break;

View File

@ -46,7 +46,7 @@
static void gimp_smudge_finalize (GObject *object);
static void gimp_smudge_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -133,7 +133,7 @@ gimp_smudge_finalize (GObject *object)
static void
gimp_smudge_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -141,6 +141,8 @@ gimp_smudge_paint (GimpPaintCore *paint_core,
{
GimpSmudge *smudge = GIMP_SMUDGE (paint_core);
g_return_if_fail (g_list_length (drawables) == 1);
switch (paint_state)
{
case GIMP_PAINT_STATE_INIT:
@ -169,11 +171,11 @@ gimp_smudge_paint (GimpPaintCore *paint_core,
case GIMP_PAINT_STATE_MOTION:
/* initialization fails if the user starts outside the drawable */
if (! smudge->initialized)
smudge->initialized = gimp_smudge_start (paint_core, drawable,
smudge->initialized = gimp_smudge_start (paint_core, drawables->data,
paint_options, sym);
if (smudge->initialized)
gimp_smudge_motion (paint_core, drawable, paint_options, sym);
gimp_smudge_motion (paint_core, drawables->data, paint_options, sym);
break;
case GIMP_PAINT_STATE_FINISH:
@ -223,7 +225,7 @@ gimp_smudge_start (GimpPaintCore *paint_core,
coords = gimp_symmetry_get_origin (sym);
gimp_brush_core_eval_transform_dynamics (brush_core,
drawable,
gimp_item_get_image (GIMP_ITEM (drawable)),
paint_options,
coords);
@ -395,7 +397,7 @@ gimp_smudge_motion (GimpPaintCore *paint_core,
return;
gimp_brush_core_eval_transform_dynamics (brush_core,
drawable,
image,
paint_options,
coords);

View File

@ -60,12 +60,12 @@ static void gimp_source_core_get_property (GObject *object,
GParamSpec *pspec);
static gboolean gimp_source_core_start (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
GError **error);
static void gimp_source_core_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -213,7 +213,7 @@ gimp_source_core_get_property (GObject *object,
static gboolean
gimp_source_core_start (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
const GimpCoords *coords,
GError **error)
@ -221,7 +221,7 @@ gimp_source_core_start (GimpPaintCore *paint_core,
GimpSourceCore *source_core = GIMP_SOURCE_CORE (paint_core);
GimpSourceOptions *options = GIMP_SOURCE_OPTIONS (paint_options);
if (! GIMP_PAINT_CORE_CLASS (parent_class)->start (paint_core, drawable,
if (! GIMP_PAINT_CORE_CLASS (parent_class)->start (paint_core, drawables,
paint_options, coords,
error))
{
@ -242,7 +242,7 @@ gimp_source_core_start (GimpPaintCore *paint_core,
if (options->sample_merged &&
gimp_item_get_image (GIMP_ITEM (source_core->src_drawable)) ==
gimp_item_get_image (GIMP_ITEM (drawable)))
gimp_item_get_image (GIMP_ITEM (drawables->data)))
{
paint_core->use_saved_proj = TRUE;
}
@ -253,7 +253,7 @@ gimp_source_core_start (GimpPaintCore *paint_core,
static void
gimp_source_core_paint (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GList *drawables,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
GimpPaintState paint_state,
@ -271,7 +271,7 @@ gimp_source_core_paint (GimpPaintCore *paint_core,
case GIMP_PAINT_STATE_INIT:
if (source_core->set_source)
{
gimp_source_core_set_src_drawable (source_core, drawable);
gimp_source_core_set_src_drawable (source_core, drawables->data);
/* FIXME(?): subpixel source sampling */
source_core->src_x = floor (coords->x);
@ -329,8 +329,9 @@ gimp_source_core_paint (GimpPaintCore *paint_core,
source_core->src_x = dest_x + source_core->offset_x;
source_core->src_y = dest_y + source_core->offset_y;
gimp_source_core_motion (source_core, drawable, paint_options,
sym);
for (GList *iter = drawables; iter; iter = iter->next)
gimp_source_core_motion (source_core, iter->data,
paint_options, sym);
}
break;
@ -430,7 +431,7 @@ gimp_source_core_motion (GimpSourceCore *source_core,
}
gimp_brush_core_eval_transform_dynamics (brush_core,
drawable,
image,
paint_options,
origin);
@ -629,7 +630,8 @@ gimp_source_core_real_get_source (GimpSourceCore *source_core,
if (options->sample_merged)
dest_buffer = gimp_paint_core_get_orig_proj (GIMP_PAINT_CORE (source_core));
else
dest_buffer = gimp_paint_core_get_orig_image (GIMP_PAINT_CORE (source_core));
dest_buffer = gimp_paint_core_get_orig_image (GIMP_PAINT_CORE (source_core),
drawable);
}
*paint_area_offset_x = x - (paint_buffer_x + src_offset_x);

View File

@ -156,23 +156,15 @@ gimp_brush_tool_oper_update (GimpTool *tool,
GimpDisplay *display)
{
GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (tool);
GimpDrawable *drawable = NULL;
GList *drawables;
GimpImage *image = gimp_display_get_image (display);
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state,
proximity, display);
drawables = gimp_image_get_selected_drawables (gimp_display_get_image (display));
if (drawables)
drawable = drawables->data;
g_list_free (drawables);
if (! gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool)) &&
drawable && proximity)
image && proximity)
{
GimpContext *context = GIMP_CONTEXT (paint_options);
GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool);
@ -187,7 +179,7 @@ gimp_brush_tool_oper_update (GimpTool *tool,
if (GIMP_BRUSH_CORE_GET_CLASS (brush_core)->handles_transforming_brush)
{
gimp_brush_core_eval_transform_dynamics (brush_core,
drawable,
image,
paint_options,
coords);
}

View File

@ -58,8 +58,9 @@ typedef struct
typedef struct
{
GimpCoords coords;
guint32 time;
GList *drawables;
GimpCoords coords;
guint32 time;
} InterpolateData;
@ -159,9 +160,8 @@ gimp_paint_tool_paint_thread (gpointer data)
static gboolean
gimp_paint_tool_paint_timeout (GimpPaintTool *paint_tool)
{
GimpPaintCore *core = paint_tool->core;
GimpDrawable *drawable = paint_tool->drawable;
gboolean update;
GimpPaintCore *core = paint_tool->core;
gboolean update = FALSE;
paint_timeout_pending = TRUE;
@ -170,7 +170,12 @@ gimp_paint_tool_paint_timeout (GimpPaintTool *paint_tool)
paint_tool->paint_x = core->last_paint.x;
paint_tool->paint_y = core->last_paint.y;
update = gimp_drawable_flush_paint (drawable);
for (GList *iter = paint_tool->drawables; iter; iter = iter->next)
{
update |= gimp_drawable_flush_paint (iter->data);
if (update)
break;
}
if (update && GIMP_PAINT_TOOL_GET_CLASS (paint_tool)->paint_flush)
GIMP_PAINT_TOOL_GET_CLASS (paint_tool)->paint_flush (paint_tool);
@ -205,11 +210,11 @@ gimp_paint_tool_paint_interpolate (GimpPaintTool *paint_tool,
{
GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool);
GimpPaintCore *core = paint_tool->core;
GimpDrawable *drawable = paint_tool->drawable;
gimp_paint_core_interpolate (core, drawable, paint_options,
gimp_paint_core_interpolate (core, data->drawables, paint_options,
&data->coords, data->time);
g_list_free (data->drawables);
g_slice_free (InterpolateData, data);
}
@ -230,10 +235,9 @@ gimp_paint_tool_paint_start (GimpPaintTool *paint_tool,
GimpPaintCore *core;
GimpDisplayShell *shell;
GimpImage *image;
GimpDrawable *drawable;
GList *drawables;
GList *iter;
GimpCoords curr_coords;
gint off_x, off_y;
g_return_val_if_fail (GIMP_IS_PAINT_TOOL (paint_tool), FALSE);
g_return_val_if_fail (GIMP_IS_DISPLAY (display), FALSE);
@ -249,17 +253,12 @@ gimp_paint_tool_paint_start (GimpPaintTool *paint_tool,
image = gimp_display_get_image (display);
drawables = gimp_image_get_selected_drawables (image);
g_return_val_if_fail (g_list_length (drawables) == 1, FALSE);
g_return_val_if_fail (g_list_length (drawables) == 1 ||
(g_list_length (drawables) > 1 && paint_tool->can_multi_paint),
FALSE);
curr_coords = *coords;
drawable = drawables->data;
g_list_free (drawables);
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
curr_coords.x -= off_x;
curr_coords.y -= off_y;
paint_tool->paint_x = curr_coords.x;
paint_tool->paint_y = curr_coords.y;
@ -267,7 +266,8 @@ gimp_paint_tool_paint_start (GimpPaintTool *paint_tool,
* paint core
*/
if (gimp_paint_tool_paint_use_thread (paint_tool))
gimp_drawable_start_paint (drawable);
for (iter = drawables; iter; iter = iter->next)
gimp_drawable_start_paint (iter->data);
/* Prepare to start the paint core */
if (GIMP_PAINT_TOOL_GET_CLASS (paint_tool)->paint_prepare)
@ -275,16 +275,19 @@ gimp_paint_tool_paint_start (GimpPaintTool *paint_tool,
/* Start the paint core */
if (! gimp_paint_core_start (core,
drawable, paint_options, &curr_coords,
drawables, paint_options, &curr_coords,
error))
{
gimp_drawable_end_paint (drawable);
for (iter = drawables; iter; iter = iter->next)
gimp_drawable_end_paint (iter->data);
g_list_free (drawables);
return FALSE;
}
paint_tool->display = display;
paint_tool->drawable = drawable;
g_list_free (paint_tool->drawables);
paint_tool->drawables = drawables;
if ((display != tool->display) || ! paint_tool->draw_line)
{
@ -323,18 +326,18 @@ gimp_paint_tool_paint_start (GimpPaintTool *paint_tool,
}
/* Let the specific painting function initialize itself */
gimp_paint_core_paint (core, drawable, paint_options,
gimp_paint_core_paint (core, drawables, paint_options,
GIMP_PAINT_STATE_INIT, time);
/* Paint to the image */
if (paint_tool->draw_line)
{
gimp_paint_core_interpolate (core, drawable, paint_options,
gimp_paint_core_interpolate (core, drawables, paint_options,
&core->cur_coords, time);
}
else
{
gimp_paint_core_paint (core, drawable, paint_options,
gimp_paint_core_paint (core, drawables, paint_options,
GIMP_PAINT_STATE_MOTION, time);
}
@ -361,14 +364,14 @@ gimp_paint_tool_paint_end (GimpPaintTool *paint_tool,
{
GimpPaintOptions *paint_options;
GimpPaintCore *core;
GimpDrawable *drawable;
GList *drawables;
g_return_if_fail (GIMP_IS_PAINT_TOOL (paint_tool));
g_return_if_fail (paint_tool->display != NULL);
paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool);
core = paint_tool->core;
drawable = paint_tool->drawable;
drawables = paint_tool->drawables;
/* Process remaining paint items */
if (gimp_paint_tool_paint_use_thread (paint_tool))
@ -414,13 +417,13 @@ gimp_paint_tool_paint_end (GimpPaintTool *paint_tool,
}
/* Let the specific painting function finish up */
gimp_paint_core_paint (core, drawable, paint_options,
gimp_paint_core_paint (core, drawables, paint_options,
GIMP_PAINT_STATE_FINISH, time);
if (cancel)
gimp_paint_core_cancel (core, drawable);
gimp_paint_core_cancel (core, drawables);
else
gimp_paint_core_finish (core, drawable, TRUE);
gimp_paint_core_finish (core, drawables, TRUE);
/* Notify subclasses */
if (gimp_paint_tool_paint_use_thread (paint_tool) &&
@ -431,10 +434,11 @@ gimp_paint_tool_paint_end (GimpPaintTool *paint_tool,
/* Exit paint mode */
if (gimp_paint_tool_paint_use_thread (paint_tool))
gimp_drawable_end_paint (drawable);
for (GList *iter = drawables; iter; iter = iter->next)
gimp_drawable_end_paint (iter->data);
paint_tool->display = NULL;
paint_tool->drawable = NULL;
paint_tool->display = NULL;
g_clear_pointer (&paint_tool->drawables, g_list_free);
}
gboolean
@ -442,8 +446,13 @@ gimp_paint_tool_paint_is_active (GimpPaintTool *paint_tool)
{
g_return_val_if_fail (GIMP_IS_PAINT_TOOL (paint_tool), FALSE);
return paint_tool->drawable != NULL &&
gimp_drawable_is_painting (paint_tool->drawable);
for (GList *iter = paint_tool->drawables; iter; iter = iter->next)
{
if (gimp_drawable_is_painting (iter->data))
return TRUE;
}
return FALSE;
}
void
@ -501,9 +510,8 @@ gimp_paint_tool_paint_motion (GimpPaintTool *paint_tool,
{
GimpPaintOptions *paint_options;
GimpPaintCore *core;
GimpDrawable *drawable;
GList *drawables;
InterpolateData *data;
gint off_x, off_y;
g_return_if_fail (GIMP_IS_PAINT_TOOL (paint_tool));
g_return_if_fail (coords != NULL);
@ -511,17 +519,13 @@ gimp_paint_tool_paint_motion (GimpPaintTool *paint_tool,
paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool);
core = paint_tool->core;
drawable = paint_tool->drawable;
drawables = paint_tool->drawables;
data = g_slice_new (InterpolateData);
data->coords = *coords;
data->time = time;
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
data->coords.x -= off_x;
data->coords.y -= off_y;
data->drawables = g_list_copy (drawables);
data->coords = *coords;
data->time = time;
paint_tool->cursor_x = data->coords.x;
paint_tool->cursor_y = data->coords.y;
@ -532,14 +536,14 @@ gimp_paint_tool_paint_motion (GimpPaintTool *paint_tool,
if (paint_tool->draw_line)
{
gimp_paint_core_set_current_coords (core, &data->coords);
g_list_free (data->drawables);
g_slice_free (InterpolateData, data);
return;
}
gimp_paint_tool_paint_push (
paint_tool,
(GimpPaintToolPaintFunc) gimp_paint_tool_paint_interpolate,
data);
gimp_paint_tool_paint_push (paint_tool,
(GimpPaintToolPaintFunc) gimp_paint_tool_paint_interpolate,
data);
}

View File

@ -160,9 +160,10 @@ gimp_paint_tool_init (GimpPaintTool *paint_tool)
gimp_tool_control_set_action_opacity (tool->control,
"context/context-opacity-set");
paint_tool->active = TRUE;
paint_tool->pick_colors = FALSE;
paint_tool->draw_line = FALSE;
paint_tool->active = TRUE;
paint_tool->pick_colors = FALSE;
paint_tool->can_multi_paint = FALSE;
paint_tool->draw_line = FALSE;
paint_tool->show_cursor = TRUE;
paint_tool->draw_brush = TRUE;
@ -277,7 +278,7 @@ gimp_paint_tool_button_press (GimpTool *tool,
GimpDisplayShell *shell = gimp_display_get_shell (display);
GimpImage *image = gimp_display_get_image (display);
GList *drawables;
GimpDrawable *drawable;
GList *iter;
gboolean constrain;
GError *error = NULL;
@ -289,68 +290,76 @@ gimp_paint_tool_button_press (GimpTool *tool,
}
drawables = gimp_image_get_selected_drawables (image);
if (g_list_length (drawables) != 1)
{
if (g_list_length (drawables) > 1)
gimp_tool_message_literal (tool, display,
_("Cannot paint on multiple layers. Select only one layer."));
else
gimp_tool_message_literal (tool, display,
_("No selected drawables."));
g_list_free (drawables);
return;
}
drawable = drawables->data;
if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)))
if (drawables == NULL)
{
gimp_tool_message_literal (tool, display,
_("Cannot paint on layer groups."));
g_list_free (drawables);
_("No selected drawables."));
return;
}
if (gimp_item_is_content_locked (GIMP_ITEM (drawable)))
else if (! paint_tool->can_multi_paint)
{
gimp_tool_message_literal (tool, display,
_("The active layer's pixels are locked."));
gimp_tools_blink_lock_box (display->gimp, GIMP_ITEM (drawable));
g_list_free (drawables);
if (g_list_length (drawables) != 1)
{
gimp_tool_message_literal (tool, display,
_("Cannot paint on multiple layers. Select only one layer."));
return;
g_list_free (drawables);
return;
}
}
if (! gimp_paint_tool_check_alpha (paint_tool, drawable, display, &error))
for (iter = drawables; iter; iter = iter->next)
{
GtkWidget *options_gui;
GtkWidget *mode_box;
GimpDrawable *drawable = iter->data;
gimp_tool_message_literal (tool, display, error->message);
if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)))
{
gimp_tool_message_literal (tool, display,
_("Cannot paint on layer groups."));
g_list_free (drawables);
options_gui = gimp_tools_get_tool_options_gui (
GIMP_TOOL_OPTIONS (options));
mode_box = gimp_paint_options_gui_get_paint_mode_box (options_gui);
return;
}
if (gtk_widget_is_sensitive (mode_box))
gimp_widget_blink (mode_box);
if (gimp_item_is_content_locked (GIMP_ITEM (drawable)))
{
gimp_tool_message_literal (tool, display,
_("A selected layer's pixels are locked."));
gimp_tools_blink_lock_box (display->gimp, GIMP_ITEM (drawable));
g_list_free (drawables);
g_clear_error (&error);
g_list_free (drawables);
return;
}
return;
}
if (! gimp_paint_tool_check_alpha (paint_tool, drawable, display, &error))
{
GtkWidget *options_gui;
GtkWidget *mode_box;
if (! gimp_item_is_visible (GIMP_ITEM (drawable)) &&
! config->edit_non_visible)
{
gimp_tool_message_literal (tool, display,
_("The active layer is not visible."));
g_list_free (drawables);
gimp_tool_message_literal (tool, display, error->message);
return;
options_gui = gimp_tools_get_tool_options_gui (GIMP_TOOL_OPTIONS (options));
mode_box = gimp_paint_options_gui_get_paint_mode_box (options_gui);
if (gtk_widget_is_sensitive (mode_box))
gimp_widget_blink (mode_box);
g_clear_error (&error);
g_list_free (drawables);
return;
}
if (! gimp_item_is_visible (GIMP_ITEM (drawable)) &&
! config->edit_non_visible)
{
gimp_tool_message_literal (tool, display,
_("A selected layer is not visible."));
g_list_free (drawables);
return;
}
}
if (gimp_draw_tool_is_active (draw_tool))
@ -533,27 +542,29 @@ gimp_paint_tool_cursor_update (GimpTool *tool,
{
GimpImage *image = gimp_display_get_image (display);
GList *drawables = gimp_image_get_selected_drawables (image);
GimpDrawable *drawable = NULL;
GList *iter;
if (! drawables)
return;
if (g_list_length (drawables) == 1)
drawable = drawables->data;
for (iter = drawables; iter; iter = iter->next)
{
GimpDrawable *drawable = iter->data;
if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)) ||
gimp_item_is_content_locked (GIMP_ITEM (drawable)) ||
! gimp_paint_tool_check_alpha (paint_tool, drawable, display, NULL) ||
! (gimp_item_is_visible (GIMP_ITEM (drawable)) ||
config->edit_non_visible))
{
modifier = GIMP_CURSOR_MODIFIER_BAD;
toggle_modifier = GIMP_CURSOR_MODIFIER_BAD;
break;
}
}
g_list_free (drawables);
if (! drawable ||
gimp_viewable_get_children (GIMP_VIEWABLE (drawable)) ||
gimp_item_is_content_locked (GIMP_ITEM (drawable)) ||
! gimp_paint_tool_check_alpha (paint_tool, drawable, display, NULL) ||
! (gimp_item_is_visible (GIMP_ITEM (drawable)) ||
config->edit_non_visible))
{
modifier = GIMP_CURSOR_MODIFIER_BAD;
toggle_modifier = GIMP_CURSOR_MODIFIER_BAD;
}
if (! paint_tool->show_cursor &&
modifier != GIMP_CURSOR_MODIFIER_BAD)
{
@ -626,19 +637,16 @@ gimp_paint_tool_oper_update (GimpTool *tool,
}
drawables = gimp_image_get_selected_drawables (image);
if (g_list_length (drawables) == 1 && proximity)
if ((g_list_length (drawables) == 1 ||
(g_list_length (drawables) > 1 && paint_tool->can_multi_paint)) &&
proximity)
{
gchar *status;
gboolean constrain_mask = gimp_get_constrain_behavior_mask ();
gint off_x, off_y;
core->cur_coords = *coords;
gimp_item_get_offset (GIMP_ITEM (drawables->data), &off_x, &off_y);
core->cur_coords.x -= off_x;
core->cur_coords.y -= off_y;
if (display == tool->display && (state & GIMP_PAINT_TOOL_LINE_MASK))
{
/* If shift is down and this is not the first paint stroke,
@ -725,31 +733,20 @@ gimp_paint_tool_draw (GimpDrawTool *draw_tool)
! gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (draw_tool)))
{
GimpPaintCore *core = paint_tool->core;
GimpImage *image = gimp_display_get_image (draw_tool->display);
GimpCanvasItem *outline = NULL;
gboolean line_drawn = FALSE;
gdouble cur_x, cur_y;
gint off_x, off_y;
GList *drawables = gimp_image_get_selected_drawables (image);
GimpDrawable *drawable;
g_return_if_fail (g_list_length (drawables) == 1);
drawable = drawables->data;
g_list_free (drawables);
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
if (gimp_paint_tool_paint_is_active (paint_tool) &&
paint_tool->snap_brush)
{
cur_x = paint_tool->paint_x + off_x;
cur_y = paint_tool->paint_y + off_y;
cur_x = paint_tool->paint_x;
cur_y = paint_tool->paint_y;
}
else
{
cur_x = paint_tool->cursor_x + off_x;
cur_y = paint_tool->cursor_y + off_y;
cur_x = paint_tool->cursor_x;
cur_y = paint_tool->cursor_y;
if (paint_tool->draw_line &&
! gimp_tool_control_is_active (GIMP_TOOL (draw_tool)->control))
@ -757,8 +754,8 @@ gimp_paint_tool_draw (GimpDrawTool *draw_tool)
GimpCanvasGroup *group;
gdouble last_x, last_y;
last_x = core->last_coords.x + off_x;
last_y = core->last_coords.y + off_y;
last_x = core->last_coords.x;
last_y = core->last_coords.y;
group = gimp_draw_tool_add_stroke_group (draw_tool);
gimp_draw_tool_push_group (draw_tool, group);
@ -1009,6 +1006,21 @@ gimp_paint_tool_enable_color_picker (GimpPaintTool *tool,
GIMP_COLOR_TOOL (tool)->pick_target = target;
}
/**
* gimp_paint_tool_enable_multi_paint:
* @tool: a #GimpPaintTool
*
* This is a convenience function used from the init method of paint
* tools that want to allow painting with several drawables.
**/
void
gimp_paint_tool_enable_multi_paint (GimpPaintTool *tool)
{
g_return_if_fail (GIMP_IS_PAINT_TOOL (tool));
tool->can_multi_paint = TRUE;
}
void
gimp_paint_tool_set_draw_fallback (GimpPaintTool *tool,
gboolean draw_fallback,

View File

@ -42,7 +42,8 @@ struct _GimpPaintTool
GimpColorTool parent_instance;
gboolean active;
gboolean pick_colors; /* pick color if ctrl is pressed */
gboolean pick_colors; /* pick color if ctrl is pressed */
gboolean can_multi_paint; /* if paint works with multiple drawables */
gboolean draw_line;
gboolean show_cursor;
@ -60,7 +61,7 @@ struct _GimpPaintTool
GimpPaintCore *core;
GimpDisplay *display;
GimpDrawable *drawable;
GList *drawables;
gdouble cursor_x;
gdouble cursor_y;
@ -97,6 +98,8 @@ void gimp_paint_tool_set_active (GimpPaintTool *tool,
void gimp_paint_tool_enable_color_picker (GimpPaintTool *tool,
GimpColorPickTarget target);
void gimp_paint_tool_enable_multi_paint (GimpPaintTool *tool);
void gimp_paint_tool_set_draw_fallback (GimpPaintTool *tool,
gboolean draw_fallback,
gint fallback_size);

View File

@ -116,6 +116,8 @@ static void
gimp_source_tool_init (GimpSourceTool *source)
{
source->show_source_outline = TRUE;
gimp_paint_tool_enable_multi_paint (GIMP_PAINT_TOOL (source));
}
static gboolean