diff --git a/src/util/clipboard.cpp b/src/util/clipboard.cpp index 1fcacbdb2..508cb2427 100644 --- a/src/util/clipboard.cpp +++ b/src/util/clipboard.cpp @@ -155,10 +155,13 @@ void clipboard::copy(const DocumentReader& document) } } -void clipboard::copy_image(Image* image, Palette* pal) +void clipboard::copy_image(Image* image, Palette* pal, const gfx::Point& point) { set_clipboard(image_new_copy(image), pal ? new Palette(*pal): NULL, true); + + clipboard_x = point.x; + clipboard_y = point.y; } void clipboard::paste() diff --git a/src/util/clipboard.h b/src/util/clipboard.h index 5cc773f0b..adcc51ea0 100644 --- a/src/util/clipboard.h +++ b/src/util/clipboard.h @@ -19,6 +19,7 @@ #ifndef UTIL_CLIPBOARD_H_INCLUDED #define UTIL_CLIPBOARD_H_INCLUDED +#include "gfx/point.h" #include "gfx/size.h" #include "gui/base.h" @@ -28,11 +29,13 @@ class DocumentWriter; namespace clipboard { + // TODO Horrible API: refactor it. + bool can_paste(); void cut(DocumentWriter& document); void copy(const DocumentReader& document); - void copy_image(Image* image, Palette* palette); + void copy_image(Image* image, Palette* palette, const gfx::Point& point); void paste(); // Returns true and fills the specified "size"" with the image's diff --git a/src/widgets/editor/moving_pixels_state.cpp b/src/widgets/editor/moving_pixels_state.cpp index 88e310c3c..4cfc6914d 100644 --- a/src/widgets/editor/moving_pixels_state.cpp +++ b/src/widgets/editor/moving_pixels_state.cpp @@ -23,6 +23,7 @@ #include "app.h" #include "app/color_utils.h" #include "base/unique_ptr.h" +#include "commands/command.h" #include "commands/commands.h" #include "gfx/rect.h" #include "gui/manager.h" @@ -30,11 +31,13 @@ #include "gui/system.h" #include "gui/view.h" #include "modules/editors.h" +#include "modules/gui.h" #include "raster/mask.h" #include "raster/sprite.h" #include "tools/ink.h" #include "tools/tool.h" #include "ui_context.h" +#include "util/clipboard.h" #include "widgets/editor/editor.h" #include "widgets/editor/editor_customization_delegate.h" #include "widgets/editor/pixels_movement.h" @@ -46,6 +49,7 @@ MovingPixelsState::MovingPixelsState(Editor* editor, Message* msg, PixelsMovement* pixelsMovement, HandleType handle) : m_currentEditor(editor) + , m_discarded(false) { // MovingPixelsState needs a selection tool to avoid problems // sharing the extra cel between the drawing cursor preview and the @@ -107,7 +111,8 @@ EditorState::BeforeChangeAction MovingPixelsState::onBeforeChangeState(Editor* e // Drop pixels if we are changing to a non-temporary state (a // temporary state is something like ScrollingState). if (!newState || !newState->isTemporalState()) { - m_pixelsMovement->dropImage(); + if (!m_discarded) + m_pixelsMovement->dropImage(); editor->getDocument()->resetTransformation(); @@ -290,7 +295,7 @@ bool MovingPixelsState::onKeyDown(Editor* editor, Message* msg) if (msg->key.scancode == KEY_ENTER || // TODO make this key customizable msg->key.scancode == KEY_ENTER_PAD || - msg->key.scancode == KEY_ESC) { + msg->key.scancode == KEY_ESC ) { dropPixels(editor); // The escape key drop pixels and deselect the mask. @@ -301,6 +306,38 @@ bool MovingPixelsState::onKeyDown(Editor* editor, Message* msg) return true; } + else { + Command* cmd = get_command_from_key_message(msg); + if (cmd) { + // Intercept the "Cut" or "Copy" command to handle them locally + // with the current m_pixelsMovement data. + if (strcmp(cmd->short_name(), CommandId::Cut) == 0 || + strcmp(cmd->short_name(), CommandId::Copy) == 0) { + // Copy the floating image to the clipboard. + { + Document* document = editor->getDocument(); + gfx::Point origin; + UniquePtr floatingImage(m_pixelsMovement->getDraggedImageCopy(origin)); + clipboard::copy_image(floatingImage.get(), + document->getSprite()->getCurrentPalette(), + origin); + } + + // In case of "Cut" command. + if (strcmp(cmd->short_name(), CommandId::Cut) == 0) { + // Discard the dragged image. + m_pixelsMovement->discardImage(); + m_discarded = true; + + // Quit from MovingPixelsState, back to standby. + editor->backToPreviousState(); + } + + // Return true because we've used the keyboard shortcut. + return true; + } + } + } // Use StandbyState implementation return StandbyState::onKeyDown(editor, msg); diff --git a/src/widgets/editor/moving_pixels_state.h b/src/widgets/editor/moving_pixels_state.h index 723a6446e..a44b2072e 100644 --- a/src/widgets/editor/moving_pixels_state.h +++ b/src/widgets/editor/moving_pixels_state.h @@ -64,6 +64,10 @@ private: // Helper member to move/translate selection and pixels. PixelsMovement* m_pixelsMovement; Editor* m_currentEditor; + + // True if the image was discarded (e.g. when a "Cut" command was + // used to remove the dragged image). + bool m_discarded; }; #endif // WIDGETS_EDITOR_MOVING_PIXELS_STATE_H_INCLUDED diff --git a/src/widgets/editor/pixels_movement.cpp b/src/widgets/editor/pixels_movement.cpp index c2fe54163..0bf1f90a2 100644 --- a/src/widgets/editor/pixels_movement.cpp +++ b/src/widgets/editor/pixels_movement.cpp @@ -350,11 +350,42 @@ gfx::Rect PixelsMovement::moveImage(int x, int y, MoveModifier moveModifier) return gfx::Rect(0, 0, m_sprite->getWidth(), m_sprite->getHeight()); } +Image* PixelsMovement::getDraggedImageCopy(gfx::Point& origin) +{ + gfx::Transformation::Corners corners; + m_currentData.transformBox(corners); + + gfx::Point leftTop(corners[0]); + gfx::Point rightBottom(corners[0]); + for (size_t i=1; i corners[i].x) leftTop.x = corners[i].x; + if (leftTop.y > corners[i].y) leftTop.y = corners[i].y; + if (rightBottom.x < corners[i].x) rightBottom.x = corners[i].x; + if (rightBottom.y < corners[i].y) rightBottom.y = corners[i].y; + } + + int width = rightBottom.x - leftTop.x; + int height = rightBottom.y - leftTop.y; + UniquePtr image(image_new(m_sprite->getImgType(), width, height)); + image_clear(image, image->mask_color); + image_parallelogram(image, m_originalImage, + corners.leftTop().x-leftTop.x, corners.leftTop().y-leftTop.y, + corners.rightTop().x-leftTop.x, corners.rightTop().y-leftTop.y, + corners.rightBottom().x-leftTop.x, corners.rightBottom().y-leftTop.y, + corners.leftBottom().x-leftTop.x, corners.leftBottom().y-leftTop.y); + + origin = leftTop; + + return image.release(); +} + void PixelsMovement::stampImage() { const Cel* cel = m_documentReader->getExtraCel(); const Image* image = m_documentReader->getExtraCelImage(); + ASSERT(cel && image); + { DocumentWriter documentWriter(m_documentReader); { @@ -420,14 +451,33 @@ void PixelsMovement::dropImage() { m_isDragging = false; + // Stamp the image in the current layer. stampImage(); + // This is the end of the whole undo transaction. m_undoTransaction.commit(); + // Destroy the extra cel (this cel will be used by the drawing + // cursor surely). DocumentWriter documentWriter(m_documentReader); documentWriter->destroyExtraCel(); } +void PixelsMovement::discardImage() +{ + m_isDragging = false; + + // Deselect the mask (here we don't stamp the image). + m_undoTransaction.deselectMask(); + m_undoTransaction.commit(); + + // Destroy the extra cel and regenerate the mask boundaries (we've + // just deselect the mask). + DocumentWriter documentWriter(m_documentReader); + documentWriter->destroyExtraCel(); + documentWriter->generateMaskBoundaries(); +} + bool PixelsMovement::isDragging() const { return m_isDragging; diff --git a/src/widgets/editor/pixels_movement.h b/src/widgets/editor/pixels_movement.h index 9bc5d412b..bc438e8fa 100644 --- a/src/widgets/editor/pixels_movement.h +++ b/src/widgets/editor/pixels_movement.h @@ -63,11 +63,16 @@ public: // redrawn. gfx::Rect moveImage(int x, int y, MoveModifier moveModifier); + // Returns a copy of the current image being dragged with the + // current transformation. + Image* getDraggedImageCopy(gfx::Point& origin); + // Copies the image being dragged in the current position. void stampImage(); void dropImageTemporarily(); void dropImage(); + void discardImage(); bool isDragging() const; gfx::Rect getImageBounds();