Bug 789764 - Please add Paste In Place feature

Add "In Place" variants for all sorts of pasting:

- extend the GimpPasteType enum with IN_PLACE values
- add the needed actions and menu items
- merge the action callbacks into one, taking an enum value as parameter
- refactor the pasting code in gimp-edit.c into smaller functions

We probably have too menu items in the "Edit" menu now, needs to be
sorted out.
This commit is contained in:
Michael Natterer 2017-11-12 18:41:05 +01:00
parent 79836aea34
commit f12d0d8c29
14 changed files with 421 additions and 280 deletions

View File

@ -42,24 +42,6 @@ static const GimpActionEntry buffers_actions[] =
NC_("buffers-action", "Buffers Menu"), NULL, NULL, NULL,
GIMP_HELP_BUFFER_DIALOG },
{ "buffers-paste", GIMP_ICON_EDIT_PASTE,
NC_("buffers-action", "_Paste Buffer"), NULL,
NC_("buffers-action", "Paste the selected buffer"),
G_CALLBACK (buffers_paste_cmd_callback),
GIMP_HELP_BUFFER_PASTE },
{ "buffers-paste-into", GIMP_ICON_EDIT_PASTE_INTO,
NC_("buffers-action", "Paste Buffer _Into"), NULL,
NC_("buffers-action", "Paste the selected buffer into the selection"),
G_CALLBACK (buffers_paste_into_cmd_callback),
GIMP_HELP_BUFFER_PASTE_INTO },
{ "buffers-paste-as-new-layer", GIMP_ICON_EDIT_PASTE_AS_NEW,
NC_("buffers-action", "Paste Buffer as New _Layer"), NULL,
NC_("buffers-action", "Paste the selected buffer as a new layer"),
G_CALLBACK (buffers_paste_as_new_layer_cmd_callback),
GIMP_HELP_BUFFER_PASTE_AS_NEW_LAYER },
{ "buffers-paste-as-new-image", GIMP_ICON_EDIT_PASTE_AS_NEW,
NC_("buffers-action", "Paste Buffer as _New Image"), NULL,
NC_("buffers-action", "Paste the selected buffer as a new image"),
@ -73,6 +55,47 @@ static const GimpActionEntry buffers_actions[] =
GIMP_HELP_BUFFER_DELETE }
};
static const GimpEnumActionEntry buffers_paste_actions[] =
{
{ "buffers-paste", GIMP_ICON_EDIT_PASTE,
NC_("buffers-action", "_Paste Buffer"), NULL,
NC_("buffers-action", "Paste the selected buffer"),
GIMP_PASTE_TYPE_FLOATING, FALSE,
GIMP_HELP_BUFFER_PASTE },
{ "buffers-paste-in-place", GIMP_ICON_EDIT_PASTE,
NC_("buffers-action", "Paste Buffer In Pl_ace"), NULL,
NC_("buffers-action", "Paste the selected buffer at its original position"),
GIMP_PASTE_TYPE_FLOATING_IN_PLACE, FALSE,
GIMP_HELP_BUFFER_PASTE_IN_PLACE },
{ "buffers-paste-into", GIMP_ICON_EDIT_PASTE_INTO,
NC_("buffers-action", "Paste Buffer _Into"), NULL,
NC_("buffers-action", "Paste the selected buffer into the selection"),
GIMP_PASTE_TYPE_FLOATING_INTO, FALSE,
GIMP_HELP_BUFFER_PASTE_INTO },
{ "buffers-paste-into-in-place", GIMP_ICON_EDIT_PASTE_INTO,
NC_("buffers-action", "Paste Buffer Into In Place"), NULL,
NC_("buffers-action",
"Paste the selected buffer into the selection at its original position"),
GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE, FALSE,
GIMP_HELP_BUFFER_PASTE_INTO_IN_PLACE },
{ "buffers-paste-as-new-layer", GIMP_ICON_EDIT_PASTE_AS_NEW,
NC_("buffers-action", "Paste Buffer as New _Layer"), NULL,
NC_("buffers-action", "Paste the selected buffer as a new layer"),
GIMP_PASTE_TYPE_NEW_LAYER, FALSE,
GIMP_HELP_BUFFER_PASTE_AS_NEW_LAYER },
{ "buffers-paste-as-new-layer-in-place", GIMP_ICON_EDIT_PASTE_AS_NEW,
NC_("buffers-action", "Paste Buffer as New Layer in Place"), NULL,
NC_("buffers-action",
"Paste the selected buffer as a new layer at its original position"),
GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE, FALSE,
GIMP_HELP_BUFFER_PASTE_AS_NEW_LAYER_IN_PLACE },
};
void
buffers_actions_setup (GimpActionGroup *group)
@ -80,6 +103,11 @@ buffers_actions_setup (GimpActionGroup *group)
gimp_action_group_add_actions (group, "buffers-action",
buffers_actions,
G_N_ELEMENTS (buffers_actions));
gimp_action_group_add_enum_actions (group, "buffers-action",
buffers_paste_actions,
G_N_ELEMENTS (buffers_paste_actions),
G_CALLBACK (buffers_paste_cmd_callback));
}
void
@ -96,8 +124,11 @@ buffers_actions_update (GimpActionGroup *group,
gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
SET_SENSITIVE ("buffers-paste", buffer);
SET_SENSITIVE ("buffers-paste-in-place", buffer);
SET_SENSITIVE ("buffers-paste-into", buffer);
SET_SENSITIVE ("buffers-paste-into-in-place", buffer);
SET_SENSITIVE ("buffers-paste-as-new-layer", buffer);
SET_SENSITIVE ("buffers-paste-as-new-layer-in-place", buffer);
SET_SENSITIVE ("buffers-paste-as-new-image", buffer);
SET_SENSITIVE ("buffers-delete", buffer);

View File

@ -30,7 +30,7 @@
#include "core/gimpcontext.h"
#include "core/gimpimage.h"
#include "widgets/gimpbufferview.h"
#include "widgets/gimpcontainereditor.h"
#include "widgets/gimpcontainerview.h"
#include "widgets/gimpcontainerview-utils.h"
@ -43,84 +43,18 @@
#include "gimp-intl.h"
/* local function prototypes */
static void buffers_paste (GimpBufferView *view,
GimpPasteType paste_type);
/* public functionss */
void
buffers_paste_cmd_callback (GtkAction *action,
gpointer data)
{
buffers_paste (GIMP_BUFFER_VIEW (data), GIMP_PASTE_TYPE_FLOATING);
}
void
buffers_paste_into_cmd_callback (GtkAction *action,
gpointer data)
{
buffers_paste (GIMP_BUFFER_VIEW (data), GIMP_PASTE_TYPE_FLOATING_INTO);
}
void
buffers_paste_as_new_layer_cmd_callback (GtkAction *action,
gpointer data)
{
buffers_paste (GIMP_BUFFER_VIEW (data), GIMP_PASTE_TYPE_NEW_LAYER);
}
void
buffers_paste_as_new_image_cmd_callback (GtkAction *action,
gint value,
gpointer data)
{
GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (data);
GimpContainer *container;
GimpContext *context;
GimpBuffer *buffer;
container = gimp_container_view_get_container (editor->view);
context = gimp_container_view_get_context (editor->view);
buffer = gimp_context_get_buffer (context);
if (buffer && gimp_container_have (container, GIMP_OBJECT (buffer)))
{
GtkWidget *widget = GTK_WIDGET (editor);
GimpImage *new_image;
new_image = gimp_edit_paste_as_new_image (context->gimp,
GIMP_OBJECT (buffer));
gimp_create_display (context->gimp, new_image,
GIMP_UNIT_PIXEL, 1.0,
G_OBJECT (gtk_widget_get_screen (widget)),
gimp_widget_get_monitor (widget));
g_object_unref (new_image);
}
}
void
buffers_delete_cmd_callback (GtkAction *action,
gpointer data)
{
GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (data);
gimp_container_view_remove_active (editor->view);
}
/* private functions */
static void
buffers_paste (GimpBufferView *view,
GimpPasteType paste_type)
{
GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (view);
GimpContainer *container;
GimpContext *context;
GimpBuffer *buffer;
GimpPasteType paste_type = (GimpPasteType) value;
container = gimp_container_view_get_container (editor->view);
context = gimp_container_view_get_context (editor->view);
@ -160,3 +94,41 @@ buffers_paste (GimpBufferView *view,
}
}
}
void
buffers_paste_as_new_image_cmd_callback (GtkAction *action,
gpointer data)
{
GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (data);
GimpContainer *container;
GimpContext *context;
GimpBuffer *buffer;
container = gimp_container_view_get_container (editor->view);
context = gimp_container_view_get_context (editor->view);
buffer = gimp_context_get_buffer (context);
if (buffer && gimp_container_have (container, GIMP_OBJECT (buffer)))
{
GtkWidget *widget = GTK_WIDGET (editor);
GimpImage *new_image;
new_image = gimp_edit_paste_as_new_image (context->gimp,
GIMP_OBJECT (buffer));
gimp_create_display (context->gimp, new_image,
GIMP_UNIT_PIXEL, 1.0,
G_OBJECT (gtk_widget_get_screen (widget)),
gimp_widget_get_monitor (widget));
g_object_unref (new_image);
}
}
void
buffers_delete_cmd_callback (GtkAction *action,
gpointer data)
{
GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (data);
gimp_container_view_remove_active (editor->view);
}

View File

@ -20,10 +20,7 @@
void buffers_paste_cmd_callback (GtkAction *action,
gpointer data);
void buffers_paste_into_cmd_callback (GtkAction *action,
gpointer data);
void buffers_paste_as_new_layer_cmd_callback (GtkAction *action,
gint value,
gpointer data);
void buffers_paste_as_new_image_cmd_callback (GtkAction *action,
gpointer data);

View File

@ -126,25 +126,6 @@ static const GimpActionEntry edit_actions[] =
G_CALLBACK (edit_copy_visible_cmd_callback),
GIMP_HELP_EDIT_COPY_VISIBLE },
{ "edit-paste", GIMP_ICON_EDIT_PASTE,
NC_("edit-action", "_Paste"), "<primary>V",
NC_("edit-action", "Paste the content of the clipboard"),
G_CALLBACK (edit_paste_cmd_callback),
GIMP_HELP_EDIT_PASTE },
{ "edit-paste-into", GIMP_ICON_EDIT_PASTE_INTO,
NC_("edit-action", "Paste _Into"), NULL,
NC_("edit-action",
"Paste the content of the clipboard into the current selection"),
G_CALLBACK (edit_paste_into_cmd_callback),
GIMP_HELP_EDIT_PASTE_INTO },
{ "edit-paste-as-new-layer", NULL,
NC_("edit-action", "New _Layer"), NULL,
NC_("edit-action", "Create a new layer from the content of the clipboard"),
G_CALLBACK (edit_paste_as_new_layer_cmd_callback),
GIMP_HELP_EDIT_PASTE_AS_NEW_LAYER },
{ "edit-paste-as-new-image", GIMP_ICON_EDIT_PASTE_AS_NEW,
NC_("edit-action", "From _Clipboard"), "<primary><shift>V",
NC_("edit-action", "Create a new image from the content of the clipboard"),
@ -189,6 +170,51 @@ static const GimpActionEntry edit_actions[] =
GIMP_HELP_EDIT_CLEAR }
};
static const GimpEnumActionEntry edit_paste_actions[] =
{
{ "edit-paste", GIMP_ICON_EDIT_PASTE,
NC_("edit-action", "_Paste"), "<primary>V",
NC_("edit-action", "Paste the content of the clipboard"),
GIMP_PASTE_TYPE_FLOATING, FALSE,
GIMP_HELP_EDIT_PASTE },
{ "edit-paste-in-place", GIMP_ICON_EDIT_PASTE,
NC_("edit-action", "Paste In Place"), NULL,
NC_("edit-action",
"Paste the content of the clipboard at its original position"),
GIMP_PASTE_TYPE_FLOATING_IN_PLACE, FALSE,
GIMP_HELP_EDIT_PASTE_IN_PLACE },
{ "edit-paste-into", GIMP_ICON_EDIT_PASTE_INTO,
NC_("edit-action", "Paste _Into Selection"), NULL,
NC_("edit-action",
"Paste the content of the clipboard into the current selection"),
GIMP_PASTE_TYPE_FLOATING_INTO, FALSE,
GIMP_HELP_EDIT_PASTE_INTO },
{ "edit-paste-into-in-place", GIMP_ICON_EDIT_PASTE_INTO,
NC_("edit-action", "Paste Into Selection In Place"), NULL,
NC_("edit-action",
"Paste the content of the clipboard into the current selection "
"at its original position"),
GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE, FALSE,
GIMP_HELP_EDIT_PASTE_INTO_IN_PLACE },
{ "edit-paste-as-new-layer", GIMP_ICON_EDIT_PASTE_AS_NEW,
NC_("edit-action", "New _Layer"), NULL,
NC_("edit-action", "Create a new layer from the content of the clipboard"),
GIMP_PASTE_TYPE_NEW_LAYER, FALSE,
GIMP_HELP_EDIT_PASTE_AS_NEW_LAYER },
{ "edit-paste-as-new-layer-in-place", GIMP_ICON_EDIT_PASTE_AS_NEW,
NC_("edit-action", "New Layer In _Place"), NULL,
NC_("edit-action",
"Create a new layer from the content of the clipboard"
"and place it at its original position"),
GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE, FALSE,
GIMP_HELP_EDIT_PASTE_AS_NEW_LAYER_IN_PLACE }
};
static const GimpEnumActionEntry edit_fill_actions[] =
{
{ "edit-fill-fg", GIMP_ICON_TOOL_BUCKET_FILL,
@ -223,6 +249,11 @@ edit_actions_setup (GimpActionGroup *group)
edit_actions,
G_N_ELEMENTS (edit_actions));
gimp_action_group_add_enum_actions (group, "edit-action",
edit_paste_actions,
G_N_ELEMENTS (edit_paste_actions),
G_CALLBACK (edit_paste_cmd_callback));
gimp_action_group_add_enum_actions (group, "edit-action",
edit_fill_actions,
G_N_ELEMENTS (edit_fill_actions),
@ -363,8 +394,11 @@ edit_actions_update (GimpActionGroup *group,
SET_SENSITIVE ("edit-copy", drawable);
SET_SENSITIVE ("edit-copy-visible", image);
/* "edit-paste" is always active */
SET_SENSITIVE ("edit-paste-in-place", image);
SET_SENSITIVE ("edit-paste-into", image);
SET_SENSITIVE ("edit-paste-into-in-place", image);
SET_SENSITIVE ("edit-paste-as-new-layer", image);
SET_SENSITIVE ("edit-paste-as-new-layer-in-place", image);
SET_SENSITIVE ("edit-named-cut", writable && !children);
SET_SENSITIVE ("edit-named-copy", drawable);

View File

@ -65,7 +65,7 @@
/* local function prototypes */
static void edit_paste (GimpDisplay *display,
GimpPasteType paste_into,
GimpPasteType paste_type,
gboolean try_svg);
static void cut_named_buffer_callback (GtkWidget *widget,
const gchar *name,
@ -327,38 +327,38 @@ edit_copy_visible_cmd_callback (GtkAction *action,
void
edit_paste_cmd_callback (GtkAction *action,
gint value,
gpointer data)
{
GimpDisplay *display = action_data_get_display (data);
GimpPasteType paste_type = (GimpPasteType) value;
if (display && gimp_display_get_image (display))
if (paste_type == GIMP_PASTE_TYPE_FLOATING)
{
edit_paste (display, GIMP_PASTE_TYPE_FLOATING, TRUE);
}
else
if (! display || ! gimp_display_get_image (display))
{
edit_paste_as_new_image_cmd_callback (action, data);
return;
}
}
void
edit_paste_into_cmd_callback (GtkAction *action,
gpointer data)
if (! display)
return;
switch (paste_type)
{
GimpDisplay *display;
return_if_no_display (display, data);
case GIMP_PASTE_TYPE_FLOATING:
case GIMP_PASTE_TYPE_FLOATING_IN_PLACE:
case GIMP_PASTE_TYPE_FLOATING_INTO:
case GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE:
edit_paste (display, paste_type, TRUE);
break;
edit_paste (display, GIMP_PASTE_TYPE_FLOATING_INTO, TRUE);
case GIMP_PASTE_TYPE_NEW_LAYER:
case GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE:
edit_paste (display, paste_type, FALSE);
break;
}
void
edit_paste_as_new_layer_cmd_callback (GtkAction *action,
gpointer data)
{
GimpDisplay *display;
return_if_no_display (display, data);
edit_paste (display, GIMP_PASTE_TYPE_NEW_LAYER, FALSE);
}
void

View File

@ -41,10 +41,7 @@ void edit_copy_visible_cmd_callback (GtkAction *action,
gpointer data);
void edit_paste_cmd_callback (GtkAction *action,
gpointer data);
void edit_paste_into_cmd_callback (GtkAction *action,
gpointer data);
void edit_paste_as_new_layer_cmd_callback (GtkAction *action,
gint value,
gpointer data);
void edit_paste_as_new_image_cmd_callback (GtkAction *action,
gpointer data);

View File

@ -319,16 +319,22 @@ gimp_paste_type_get_type (void)
static const GEnumValue values[] =
{
{ GIMP_PASTE_TYPE_FLOATING, "GIMP_PASTE_TYPE_FLOATING", "floating" },
{ GIMP_PASTE_TYPE_FLOATING_IN_PLACE, "GIMP_PASTE_TYPE_FLOATING_IN_PLACE", "floating-in-place" },
{ GIMP_PASTE_TYPE_FLOATING_INTO, "GIMP_PASTE_TYPE_FLOATING_INTO", "floating-into" },
{ GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE, "GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE", "floating-into-in-place" },
{ GIMP_PASTE_TYPE_NEW_LAYER, "GIMP_PASTE_TYPE_NEW_LAYER", "new-layer" },
{ GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE, "GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE", "new-layer-in-place" },
{ 0, NULL, NULL }
};
static const GimpEnumDesc descs[] =
{
{ GIMP_PASTE_TYPE_FLOATING, "GIMP_PASTE_TYPE_FLOATING", NULL },
{ GIMP_PASTE_TYPE_FLOATING_IN_PLACE, "GIMP_PASTE_TYPE_FLOATING_IN_PLACE", NULL },
{ GIMP_PASTE_TYPE_FLOATING_INTO, "GIMP_PASTE_TYPE_FLOATING_INTO", NULL },
{ GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE, "GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE", NULL },
{ GIMP_PASTE_TYPE_NEW_LAYER, "GIMP_PASTE_TYPE_NEW_LAYER", NULL },
{ GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE, "GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE", NULL },
{ 0, NULL, NULL }
};

View File

@ -169,8 +169,11 @@ GType gimp_paste_type_get_type (void) G_GNUC_CONST;
typedef enum /*< pdb-skip >*/
{
GIMP_PASTE_TYPE_FLOATING,
GIMP_PASTE_TYPE_FLOATING_IN_PLACE,
GIMP_PASTE_TYPE_FLOATING_INTO,
GIMP_PASTE_TYPE_NEW_LAYER
GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE,
GIMP_PASTE_TYPE_NEW_LAYER,
GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE
} GimpPasteType;

View File

@ -80,8 +80,15 @@ gimp_edit_cut (GimpImage *image,
gimp_channel_is_empty (gimp_image_get_mask (image)))
{
GimpImage *clip_image;
gint off_x, off_y;
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
clip_image = gimp_image_new_from_drawable (image->gimp, drawable);
g_object_set_data (G_OBJECT (clip_image), "offset-x",
GINT_TO_POINTER (off_x));
g_object_set_data (G_OBJECT (clip_image), "offset-y",
GINT_TO_POINTER (off_y));
gimp_container_remove (image->gimp->images, GIMP_OBJECT (clip_image));
gimp_set_clipboard_image (image->gimp, clip_image);
g_object_unref (clip_image);
@ -131,8 +138,15 @@ gimp_edit_copy (GimpImage *image,
gimp_channel_is_empty (gimp_image_get_mask (image)))
{
GimpImage *clip_image;
gint off_x, off_y;
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
clip_image = gimp_image_new_from_drawable (image->gimp, drawable);
g_object_set_data (G_OBJECT (clip_image), "offset-x",
GINT_TO_POINTER (off_x));
g_object_set_data (G_OBJECT (clip_image), "offset-y",
GINT_TO_POINTER (off_y));
gimp_container_remove (image->gimp->images, GIMP_OBJECT (clip_image));
gimp_set_clipboard_image (image->gimp, clip_image);
g_object_unref (clip_image);
@ -183,8 +197,102 @@ gimp_edit_copy_visible (GimpImage *image,
return NULL;
}
void
gimp_edit_get_paste_offset (GimpImage *image,
static GimpLayer *
gimp_edit_paste_get_layer (GimpImage *image,
GimpDrawable *drawable,
GimpObject *paste,
GimpPasteType *paste_type)
{
GimpLayer *layer = NULL;
const Babl *floating_format;
/* change paste type to NEW_LAYER for cases where we can't attach a
* floating selection
*/
if (! drawable ||
gimp_viewable_get_children (GIMP_VIEWABLE (drawable)) ||
gimp_item_is_content_locked (GIMP_ITEM (drawable)))
{
*paste_type = GIMP_PASTE_TYPE_NEW_LAYER;
}
/* floating pastes always have the pasted-to drawable's format with
* alpha; if drawable == NULL, user is pasting into an empty image
*/
if (drawable)
floating_format = gimp_drawable_get_format_with_alpha (drawable);
else
floating_format = gimp_image_get_layer_format (image, TRUE);
if (GIMP_IS_IMAGE (paste))
{
GType layer_type;
layer = gimp_image_get_layer_iter (GIMP_IMAGE (paste))->data;
switch (*paste_type)
{
case GIMP_PASTE_TYPE_FLOATING:
case GIMP_PASTE_TYPE_FLOATING_INTO:
/* when pasting as floating selection, force creation of a
* plain layer, so gimp_item_convert() will collapse a
* group layer
*/
layer_type = GIMP_TYPE_LAYER;
break;
case GIMP_PASTE_TYPE_NEW_LAYER:
layer_type = G_TYPE_FROM_INSTANCE (layer);
break;
default:
g_return_val_if_reached (NULL);
}
layer = GIMP_LAYER (gimp_item_convert (GIMP_ITEM (layer),
image, layer_type));
switch (*paste_type)
{
case GIMP_PASTE_TYPE_FLOATING:
case GIMP_PASTE_TYPE_FLOATING_INTO:
/* when pasting as floating selection, get rid of the layer mask,
* and make sure the layer has the right format
*/
if (gimp_layer_get_mask (layer))
gimp_layer_apply_mask (layer, GIMP_MASK_DISCARD, FALSE);
if (gimp_drawable_get_format (GIMP_DRAWABLE (layer)) !=
floating_format)
{
gimp_drawable_convert_type (GIMP_DRAWABLE (layer), image,
gimp_drawable_get_base_type (drawable),
gimp_drawable_get_precision (drawable),
TRUE,
NULL,
GEGL_DITHER_NONE, GEGL_DITHER_NONE,
FALSE, NULL);
}
break;
default:
break;
}
}
else if (GIMP_IS_BUFFER (paste))
{
layer = gimp_layer_new_from_buffer (GIMP_BUFFER (paste), image,
floating_format,
_("Pasted Layer"),
GIMP_OPACITY_OPAQUE,
gimp_image_get_default_new_layer_mode (image));
}
return layer;
}
static void
gimp_edit_paste_get_viewport_offset (GimpImage *image,
GimpDrawable *drawable,
GimpObject *paste,
gint viewport_x,
@ -321,119 +429,45 @@ gimp_edit_get_paste_offset (GimpImage *image,
}
}
GimpLayer *
gimp_edit_paste (GimpImage *image,
static void
gimp_edit_paste_get_paste_offset (GimpImage *image,
GimpDrawable *drawable,
GimpObject *paste,
GimpPasteType paste_type,
gint viewport_x,
gint viewport_y,
gint viewport_width,
gint viewport_height)
gint *offset_x,
gint *offset_y)
{
GimpLayer *layer = NULL;
const Babl *floating_format;
gint offset_x;
gint offset_y;
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
g_return_val_if_fail (drawable == NULL || GIMP_IS_DRAWABLE (drawable), NULL);
g_return_val_if_fail (drawable == NULL ||
gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
g_return_val_if_fail (GIMP_IS_IMAGE (paste) || GIMP_IS_BUFFER (paste), NULL);
/* change paste type to NEW_LAYER for cases where we can't attach a
* floating selection
*/
if (! drawable ||
gimp_viewable_get_children (GIMP_VIEWABLE (drawable)) ||
gimp_item_is_content_locked (GIMP_ITEM (drawable)))
{
paste_type = GIMP_PASTE_TYPE_NEW_LAYER;
}
/* floating pastes always have the pasted-to drawable's format with
* alpha; if drawable == NULL, user is pasting into an empty image
*/
if (drawable)
floating_format = gimp_drawable_get_format_with_alpha (drawable);
else
floating_format = gimp_image_get_layer_format (image, TRUE);
g_return_if_fail (GIMP_IS_IMAGE (image));
g_return_if_fail (drawable == NULL || GIMP_IS_DRAWABLE (drawable));
g_return_if_fail (drawable == NULL ||
gimp_item_is_attached (GIMP_ITEM (drawable)));
g_return_if_fail (GIMP_IS_VIEWABLE (paste));
g_return_if_fail (offset_x != NULL);
g_return_if_fail (offset_y != NULL);
if (GIMP_IS_IMAGE (paste))
{
GType layer_type;
layer = gimp_image_get_layer_iter (GIMP_IMAGE (paste))->data;
switch (paste_type)
{
case GIMP_PASTE_TYPE_FLOATING:
case GIMP_PASTE_TYPE_FLOATING_INTO:
/* when pasting as floating selection, force creation of a
* plain layer, so gimp_item_convert() will collapse a
* group layer
*/
layer_type = GIMP_TYPE_LAYER;
break;
case GIMP_PASTE_TYPE_NEW_LAYER:
layer_type = G_TYPE_FROM_INSTANCE (layer);
break;
default:
g_return_val_if_reached (NULL);
}
layer = GIMP_LAYER (gimp_item_convert (GIMP_ITEM (layer),
image, layer_type));
switch (paste_type)
{
case GIMP_PASTE_TYPE_FLOATING:
case GIMP_PASTE_TYPE_FLOATING_INTO:
/* when pasting as floating selection, get rid of the layer mask,
* and make sure the layer has the right format
*/
if (gimp_layer_get_mask (layer))
gimp_layer_apply_mask (layer, GIMP_MASK_DISCARD, FALSE);
if (gimp_drawable_get_format (GIMP_DRAWABLE (layer)) !=
floating_format)
{
gimp_drawable_convert_type (GIMP_DRAWABLE (layer), image,
gimp_drawable_get_base_type (drawable),
gimp_drawable_get_precision (drawable),
TRUE,
NULL,
GEGL_DITHER_NONE, GEGL_DITHER_NONE,
FALSE, NULL);
}
break;
default:
break;
}
*offset_x = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (paste),
"offset-x"));
*offset_y = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (paste),
"offset-y"));
}
else if (GIMP_IS_BUFFER (paste))
{
layer = gimp_layer_new_from_buffer (GIMP_BUFFER (paste), image,
floating_format,
_("Pasted Layer"),
GIMP_OPACITY_OPAQUE,
gimp_image_get_default_new_layer_mode (image));
GimpBuffer *buffer = GIMP_BUFFER (paste);
*offset_x = buffer->offset_x;
*offset_y = buffer->offset_y;
}
}
if (! layer)
return NULL;
gimp_edit_get_paste_offset (image, drawable, GIMP_OBJECT (layer),
viewport_x,
viewport_y,
viewport_width,
viewport_height,
&offset_x,
&offset_y);
static GimpLayer *
gimp_edit_paste_paste (GimpImage *image,
GimpDrawable *drawable,
GimpLayer *layer,
GimpPasteType paste_type,
gint offset_x,
gint offset_y)
{
gimp_item_translate (GIMP_ITEM (layer), offset_x, offset_y, FALSE);
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_PASTE,
@ -442,6 +476,7 @@ gimp_edit_paste (GimpImage *image,
switch (paste_type)
{
case GIMP_PASTE_TYPE_FLOATING:
case GIMP_PASTE_TYPE_FLOATING_IN_PLACE:
/* if there is a selection mask clear it - this might not
* always be desired, but in general, it seems like the correct
* behavior
@ -452,16 +487,18 @@ gimp_edit_paste (GimpImage *image,
/* fall thru */
case GIMP_PASTE_TYPE_FLOATING_INTO:
case GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE:
floating_sel_attach (layer, drawable);
break;
case GIMP_PASTE_TYPE_NEW_LAYER:
case GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE:
{
GimpLayer *parent = NULL;
gint position = 0;
/* always add on top of the passed layer, where we would
* attach a floating selection
/* always add on top of a passed layer, where we would attach
* a floating selection
*/
if (GIMP_IS_LAYER (drawable))
{
@ -479,6 +516,58 @@ gimp_edit_paste (GimpImage *image,
return layer;
}
GimpLayer *
gimp_edit_paste (GimpImage *image,
GimpDrawable *drawable,
GimpObject *paste,
GimpPasteType paste_type,
gint viewport_x,
gint viewport_y,
gint viewport_width,
gint viewport_height)
{
GimpLayer *layer;
gint offset_x = 0;
gint offset_y = 0;
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
g_return_val_if_fail (drawable == NULL || GIMP_IS_DRAWABLE (drawable), NULL);
g_return_val_if_fail (drawable == NULL ||
gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
g_return_val_if_fail (GIMP_IS_IMAGE (paste) || GIMP_IS_BUFFER (paste), NULL);
layer = gimp_edit_paste_get_layer (image, drawable, paste, &paste_type);
if (! layer)
return NULL;
switch (paste_type)
{
case GIMP_PASTE_TYPE_FLOATING:
case GIMP_PASTE_TYPE_FLOATING_INTO:
case GIMP_PASTE_TYPE_NEW_LAYER:
gimp_edit_paste_get_viewport_offset (image, drawable, GIMP_OBJECT (layer),
viewport_x,
viewport_y,
viewport_width,
viewport_height,
&offset_x,
&offset_y);
break;
case GIMP_PASTE_TYPE_FLOATING_IN_PLACE:
case GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE:
case GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE:
gimp_edit_paste_get_paste_offset (image, drawable, paste,
&offset_x,
&offset_y);
break;
}
return gimp_edit_paste_paste (image, drawable, layer, paste_type,
offset_x, offset_y);
}
GimpImage *
gimp_edit_paste_as_new_image (Gimp *gimp,
GimpObject *paste)

View File

@ -31,16 +31,6 @@ GimpBuffer * gimp_edit_copy_visible (GimpImage *image,
GimpContext *context,
GError **error);
void gimp_edit_get_paste_offset (GimpImage *image,
GimpDrawable *drawable,
GimpObject *paste,
gint viewport_x,
gint viewport_y,
gint viewport_width,
gint viewport_height,
gint *offset_x,
gint *offset_y);
GimpLayer * gimp_edit_paste (GimpImage *image,
GimpDrawable *drawable,
GimpObject *paste,

View File

@ -42,6 +42,7 @@
#include "gimpview.h"
#include "gimpviewrendererbuffer.h"
#include "gimpuimanager.h"
#include "gimpwidgets-utils.h"
#include "gimp-intl.h"
@ -186,15 +187,24 @@ gimp_buffer_view_new (GimpViewType view_type,
buffer_view->paste_button =
gimp_editor_add_action_button (GIMP_EDITOR (editor->view), "buffers",
"buffers-paste", NULL);
"buffers-paste",
"buffers-paste-in-place",
gimp_get_extend_selection_mask (),
NULL);
buffer_view->paste_into_button =
gimp_editor_add_action_button (GIMP_EDITOR (editor->view), "buffers",
"buffers-paste-into", NULL);
"buffers-paste-into",
"buffers-paste-into-in-place",
gimp_get_extend_selection_mask (),
NULL);
buffer_view->paste_as_new_layer_button =
gimp_editor_add_action_button (GIMP_EDITOR (editor->view), "buffers",
"buffers-paste-as-new-layer", NULL);
"buffers-paste-as-new-layer",
"buffers-paste-as-new-layer-in-place",
gimp_get_extend_selection_mask (),
NULL);
buffer_view->paste_as_new_image_button =
gimp_editor_add_action_button (GIMP_EDITOR (editor->view), "buffers",

View File

@ -56,8 +56,11 @@
#define GIMP_HELP_EDIT_COPY "gimp-edit-copy"
#define GIMP_HELP_EDIT_COPY_VISIBLE "gimp-edit-copy-visible"
#define GIMP_HELP_EDIT_PASTE "gimp-edit-paste"
#define GIMP_HELP_EDIT_PASTE_IN_PLACE "gimp-edit-paste-in-place"
#define GIMP_HELP_EDIT_PASTE_INTO "gimp-edit-paste-into"
#define GIMP_HELP_EDIT_PASTE_INTO_IN_PLACE "gimp-edit-paste-into-in-place"
#define GIMP_HELP_EDIT_PASTE_AS_NEW_LAYER "gimp-edit-paste-as-new-layer"
#define GIMP_HELP_EDIT_PASTE_AS_NEW_LAYER_IN_PLACE "gimp-edit-paste-as-new-layer-in-place"
#define GIMP_HELP_EDIT_PASTE_AS_NEW_IMAGE "gimp-edit-paste-as-new-image"
#define GIMP_HELP_EDIT_CLEAR "gimp-edit-clear"
#define GIMP_HELP_EDIT_FILL_FG "gimp-edit-fill-fg"
@ -552,8 +555,11 @@
#define GIMP_HELP_BUFFER_CUT "gimp-buffer-cut"
#define GIMP_HELP_BUFFER_COPY "gimp-buffer-copy"
#define GIMP_HELP_BUFFER_PASTE "gimp-buffer-paste"
#define GIMP_HELP_BUFFER_PASTE_IN_PLACE "gimp-buffer-paste-in-place"
#define GIMP_HELP_BUFFER_PASTE_INTO "gimp-buffer-paste-into"
#define GIMP_HELP_BUFFER_PASTE_INTO_IN_PLACE "gimp-buffer-paste-into-in-place"
#define GIMP_HELP_BUFFER_PASTE_AS_NEW_LAYER "gimp-buffer-paste-as-new-layer"
#define GIMP_HELP_BUFFER_PASTE_AS_NEW_LAYER_IN_PLACE "gimp-buffer-paste-as-new-layer-in-place"
#define GIMP_HELP_BUFFER_PASTE_AS_NEW_IMAGE "gimp-buffer-paste-as-new-image"
#define GIMP_HELP_BUFFER_DELETE "gimp-buffer-delete"

View File

@ -4,8 +4,11 @@
<ui>
<popup action="buffers-popup">
<menuitem action="buffers-paste" />
<menuitem action="buffers-paste-in-place" />
<menuitem action="buffers-paste-into" />
<menuitem action="buffers-paste-into-in-place" />
<menuitem action="buffers-paste-as-new-layer" />
<menuitem action="buffers-paste-as-new-layer-in-place" />
<menuitem action="buffers-paste-as-new-image" />
<menuitem action="buffers-delete" />
<separator />

View File

@ -193,10 +193,13 @@
</placeholder>
<placeholder name="Paste">
<menuitem action="edit-paste" />
<menuitem action="edit-paste-in-place" />
<menuitem action="edit-paste-into" />
<menuitem action="edit-paste-into-in-place" />
</placeholder>
<menu action="edit-paste-as-menu" name="Paste as">
<menuitem action="edit-paste-as-new-layer" />
<menuitem action="edit-paste-as-new-layer-in-place" />
<menuitem action="edit-paste-as-new-image-short" />
</menu>
<menu action="edit-buffer-menu" name="Buffer">