Skip to content

Commit

Permalink
Merge pull request #35 from don-mccomb/master
Browse files Browse the repository at this point in the history
[Fixes bug #1064018] Data lost when pasting images onto smaller canvases.
  • Loading branch information
cameronwhite committed Nov 10, 2012
2 parents 1a9e5a4 + b867e01 commit 5ccaf12
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 172 deletions.
146 changes: 145 additions & 1 deletion Pinta.Core/Classes/Document.cs
@@ -1,4 +1,4 @@
//
//
// Document.cs
//
// Author:
Expand Down Expand Up @@ -28,9 +28,11 @@
using System.Linq;
using Mono.Unix;
using Gdk;
using Gtk;
using System.Collections.Generic;
using Cairo;
using System.ComponentModel;
using Pinta;

namespace Pinta.Core
{
Expand Down Expand Up @@ -278,6 +280,11 @@ public Layer CreateLayer ()
return CreateLayer (string.Format ("{0} {1}", Catalog.GetString ("Layer"), layer_name_int++));
}

public Layer CreateLayer (int width, int height)
{
return CreateLayer (string.Format ("{0} {1}", Catalog.GetString ("Layer"), layer_name_int++), width, height);
}

public Layer CreateLayer (string name)
{
return CreateLayer (name, ImageSize.Width, ImageSize.Height);
Expand All @@ -301,6 +308,16 @@ public void CreateSelectionLayer ()
(old.Surface as IDisposable).Dispose ();
}

public void CreateSelectionLayer (int width, int height)
{
Layer old = selection_layer;

selection_layer = CreateLayer (width, height);

if (old != null)
(old.Surface as IDisposable).Dispose ();
}

// Delete the current layer
public void DeleteCurrentLayer ()
{
Expand Down Expand Up @@ -705,6 +722,133 @@ public void SetCurrentLayer (Layer layer)
{
SetCurrentLayer (Layers.IndexOf (layer));
}

public void Paste (bool toNewLayer)
{
// Create a compound history item for recording several
// operations so that they can all be undone/redone together.
CompoundHistoryItem paste_action;
if (toNewLayer)
{
paste_action = new CompoundHistoryItem (Stock.Paste, Catalog.GetString ("Paste Into New Layer"));
}
else
{
paste_action = new CompoundHistoryItem (Stock.Paste, Catalog.GetString ("Paste"));
}

Gtk.Clipboard cb = Gtk.Clipboard.Get (Gdk.Atom.Intern ("CLIPBOARD", false));

// See if the current tool wants to handle the paste
// operation (e.g., the text tool could paste text)
if (!toNewLayer)
{
if (PintaCore.Tools.CurrentTool.TryHandlePaste (cb))
return;
}

PintaCore.Tools.Commit ();

Path p;

// Don't dispose this, as we're going to give it to the history
Gdk.Pixbuf image = cb.WaitForImage ();

if (image == null)
{
ShowClipboardEmptyDialog();
return;
}

Gdk.Size canvas_size = PintaCore.Workspace.ImageSize;

// If the image being pasted is larger than the canvas size, allow the user to optionally resize the canvas
if (image.Width > canvas_size.Width || image.Height > canvas_size.Height)
{
ResponseType response = ShowExpandCanvasDialog ();

if (response == ResponseType.Accept)
{
PintaCore.Workspace.ResizeCanvas (image.Width, image.Height,
Pinta.Core.Anchor.Center, paste_action);
PintaCore.Actions.View.UpdateCanvasScale ();
}
else if (response == ResponseType.Cancel || response == ResponseType.DeleteEvent)
{
return;
}
}

// If requested, create a new layer, make it the current
// layer and record it's creation in the history
if (toNewLayer)
{
Layer l = AddNewLayer (string.Empty);
SetCurrentLayer (l);
paste_action.Push (new AddLayerHistoryItem ("Menu.Layers.AddNewLayer.png", Catalog.GetString ("Add New Layer"), Layers.IndexOf (l)));
}

// Copy the paste to the temp layer
CreateSelectionLayer (image.Width, image.Height);
ShowSelectionLayer = true;

using (Cairo.Context g = new Cairo.Context (SelectionLayer.Surface))
{
g.DrawPixbuf (image, new Cairo.Point (0, 0));
p = g.CreateRectanglePath (new Cairo.Rectangle (0, 0, image.Width, image.Height));
}

PintaCore.Tools.SetCurrentTool (Catalog.GetString ("Move Selected Pixels"));

DocumentSelection old_selection = Selection.Clone();
bool old_show_selection = ShowSelection;

Selection.SelectionPath = p;
Selection.SelectionPolygons.Clear();
ShowSelection = true;

Workspace.Invalidate ();

paste_action.Push (new PasteHistoryItem (image, old_selection, old_show_selection));
History.PushNewItem (paste_action);
}

private ResponseType ShowExpandCanvasDialog ()
{
const string markup = "<span weight=\"bold\" size=\"larger\">{0}</span>\n\n{1}";
string primary = Catalog.GetString ("Image larger than canvas");
string secondary = Catalog.GetString ("The image being pasted is larger than the canvas size. What would you like to do?");
string message = string.Format (markup, primary, secondary);

var enlarge_dialog = new MessageDialog (PintaCore.Chrome.MainWindow, DialogFlags.Modal, MessageType.Question, ButtonsType.None, message);
enlarge_dialog.AddButton (Catalog.GetString ("Expand canvas"), ResponseType.Accept);
enlarge_dialog.AddButton (Catalog.GetString ("Don't change canvas size"), ResponseType.Reject);
enlarge_dialog.AddButton (Stock.Cancel, ResponseType.Cancel);
enlarge_dialog.DefaultResponse = ResponseType.Accept;

ResponseType response = (ResponseType)enlarge_dialog.Run ();

enlarge_dialog.Destroy ();

return response;
}

public static void ShowClipboardEmptyDialog()
{
var primary = Catalog.GetString ("Image cannot be pasted");
var secondary = Catalog.GetString ("The clipboard does not contain an image.");
var markup = "<span weight=\"bold\" size=\"larger\">{0}</span>\n\n{1}\n";
markup = string.Format (markup, primary, secondary);

var md = new MessageDialog (Pinta.Core.PintaCore.Chrome.MainWindow, DialogFlags.Modal,
MessageType.Error, ButtonsType.None, true,
markup);

md.AddButton (Stock.Ok, ResponseType.Yes);

md.Run ();
md.Destroy ();
}
#endregion

#region Protected Methods
Expand Down
95 changes: 9 additions & 86 deletions Pinta/Actions/Edit/PasteAction.cs
@@ -1,4 +1,4 @@
//
//
// PasteAction.cs
//
// Author:
Expand All @@ -25,7 +25,6 @@
// THE SOFTWARE.

using System;
using Cairo;
using Gtk;
using Mono.Unix;
using Pinta.Core;
Expand All @@ -34,8 +33,6 @@ namespace Pinta.Actions
{
class PasteAction : IActionHandler
{
private const string markup = "<span weight=\"bold\" size=\"larger\">{0}</span>\n\n{1}";

#region IActionHandler Members
public void Initialize ()
{
Expand All @@ -50,92 +47,18 @@ public void Uninitialize ()

private void Activated (object sender, EventArgs e)
{
Gtk.Clipboard cb = Gtk.Clipboard.Get (Gdk.Atom.Intern ("CLIPBOARD", false));
if (PintaCore.Tools.CurrentTool.TryHandlePaste (cb))
return;

PintaCore.Tools.Commit ();

Path p;

// Don't dispose this, as we're going to give it to the history
Gdk.Pixbuf image = cb.WaitForImage ();

if (image == null)
// If no documents are open, activate the
// PasteIntoNewImage action and abort this Paste action.
if (!PintaCore.Workspace.HasOpenDocuments)
{
Dialogs.ClipboardEmptyDialog.Show ();
PintaCore.Actions.Edit.PasteIntoNewImage.Activate();
return;
}
else if (!PintaCore.Workspace.HasOpenDocuments) {
// Create a new document if no documents are open.
PintaCore.Workspace.NewDocument (new Gdk.Size (image.Width, image.Height), true);
}

Document doc = PintaCore.Workspace.ActiveDocument;

Gdk.Size canvas_size = PintaCore.Workspace.ImageSize;

// Merge the (optional) canvas resize and the pasted image into a single history item.
var paste_action = new CompoundHistoryItem (Stock.Paste, Catalog.GetString ("Paste"));

// If the image being pasted is larger than the canvas size, allow the user to optionally resize the canvas
if (image.Width > canvas_size.Width || image.Height > canvas_size.Height)
{
ResponseType response = ShowExpandCanvasDialog ();

if (response == ResponseType.Accept)
{
PintaCore.Workspace.ResizeCanvas (image.Width, image.Height,
Pinta.Core.Anchor.Center, paste_action);
PintaCore.Actions.View.UpdateCanvasScale ();
}
else if (response == ResponseType.Cancel || response == ResponseType.DeleteEvent)
{
return;
}
}

// Copy the paste to the temp layer
doc.CreateSelectionLayer ();
doc.ShowSelectionLayer = true;

using (Cairo.Context g = new Cairo.Context (doc.SelectionLayer.Surface))
{
g.DrawPixbuf (image, new Cairo.Point (0, 0));
p = g.CreateRectanglePath (new Rectangle (0, 0, image.Width, image.Height));
}

PintaCore.Tools.SetCurrentTool (Catalog.GetString ("Move Selected Pixels"));

DocumentSelection old_selection = doc.Selection.Clone();
bool old_show_selection = doc.ShowSelection;

doc.Selection.SelectionPath = p;
doc.Selection.SelectionPolygons.Clear();
doc.ShowSelection = true;

doc.Workspace.Invalidate ();

paste_action.Push (new PasteHistoryItem (image, old_selection, old_show_selection));
doc.History.PushNewItem (paste_action);
}

private ResponseType ShowExpandCanvasDialog ()
{
string primary = Catalog.GetString ("Image larger than canvas");
string secondary = Catalog.GetString ("The image being pasted is larger than the canvas size. What would you like to do?");
string message = string.Format (markup, primary, secondary);

var enlarge_dialog = new MessageDialog (PintaCore.Chrome.MainWindow, DialogFlags.Modal, MessageType.Question, ButtonsType.None, message);
enlarge_dialog.AddButton (Catalog.GetString ("Expand canvas"), ResponseType.Accept);
enlarge_dialog.AddButton (Catalog.GetString ("Don't change canvas size"), ResponseType.Reject);
enlarge_dialog.AddButton (Stock.Cancel, ResponseType.Cancel);
enlarge_dialog.DefaultResponse = ResponseType.Accept;

ResponseType response = (ResponseType)enlarge_dialog.Run ();
enlarge_dialog.Destroy ();

return response;
// Paste into the active document.
// The 'false' argument indicates that paste should be
// performed into the current (not a new) layer.
PintaCore.Workspace.ActiveDocument.Paste (false);
}
}
}
2 changes: 1 addition & 1 deletion Pinta/Actions/Edit/PasteIntoNewImageAction.cs
Expand Up @@ -57,7 +57,7 @@ private void Activated (object sender, EventArgs e)
PintaCore.Actions.Edit.Paste.Activate ();
PintaCore.Actions.Edit.Deselect.Activate ();
} else {
Pinta.Dialogs.ClipboardEmptyDialog.Show ();
Pinta.Core.Document.ShowClipboardEmptyDialog ();
}
}
}
Expand Down
32 changes: 11 additions & 21 deletions Pinta/Actions/Edit/PasteIntoNewLayerAction.cs
Expand Up @@ -47,28 +47,18 @@ public void Uninitialize ()

private void Activated (object sender, EventArgs e)
{
Gtk.Clipboard cb = Gtk.Clipboard.Get (Gdk.Atom.Intern ("CLIPBOARD", false));

if (cb.WaitIsImageAvailable ()) {
PintaCore.Tools.Commit ();

Gdk.Pixbuf image = cb.WaitForImage ();

Layer l = PintaCore.Layers.AddNewLayer (string.Empty);

using (Cairo.Context g = new Cairo.Context (l.Surface))
g.DrawPixbuf (image, new Cairo.Point (0, 0));

// Make new layer the current layer
PintaCore.Layers.SetCurrentLayer (l);

PintaCore.Workspace.Invalidate ();

AddLayerHistoryItem hist = new AddLayerHistoryItem (Stock.Paste, Catalog.GetString ("Paste Into New Layer"), PintaCore.Layers.IndexOf (l));
PintaCore.History.PushNewItem (hist);
} else {
Pinta.Dialogs.ClipboardEmptyDialog.Show ();
// If no documents are open, activate the
// PasteIntoNewImage action and abort this Paste action.
if (!PintaCore.Workspace.HasOpenDocuments)
{
PintaCore.Actions.Edit.PasteIntoNewImage.Activate();
return;
}

// Paste into the active document.
// The 'true' argument indicates that paste should be
// performed into a new layer.
PintaCore.Workspace.ActiveDocument.Paste (true);
}
}
}

0 comments on commit 5ccaf12

Please sign in to comment.