From a69a120e147c649b4c2ce161b6aff40b5cf02146 Mon Sep 17 00:00:00 2001 From: Gaspar Capello Date: Fri, 6 Jul 2018 16:22:44 -0300 Subject: [PATCH] Flip command changes to moving pixels state (fix #1738) --- src/app/commands/cmd_flip.cpp | 266 ++++++++++++---------- src/app/ui/editor/editor.cpp | 8 + src/app/ui/editor/editor.h | 3 + src/app/ui/editor/moving_pixels_state.cpp | 5 + src/app/ui/editor/moving_pixels_state.h | 1 + src/app/ui/editor/standby_state.cpp | 8 + src/app/ui/editor/standby_state.h | 5 +- 7 files changed, 169 insertions(+), 127 deletions(-) diff --git a/src/app/commands/cmd_flip.cpp b/src/app/commands/cmd_flip.cpp index 6f4fde275..3fb57540b 100644 --- a/src/app/commands/cmd_flip.cpp +++ b/src/app/commands/cmd_flip.cpp @@ -21,10 +21,15 @@ #include "app/document_api.h" #include "app/document_range.h" #include "app/i18n/strings.h" +#include "app/modules/editors.h" #include "app/modules/gui.h" +#include "app/tools/tool_box.h" #include "app/transaction.h" +#include "app/ui/editor/editor.h" +#include "app/ui/editor/moving_pixels_state.h" #include "app/ui/status_bar.h" #include "app/ui/timeline/timeline.h" +#include "app/ui/toolbar.h" #include "app/util/expand_cel_canvas.h" #include "app/util/range_utils.h" #include "doc/algorithm/flip_image.h" @@ -37,6 +42,7 @@ #include "fmt/format.h" #include "gfx/size.h" + namespace app { FlipCommand::FlipCommand() @@ -63,156 +69,164 @@ bool FlipCommand::onEnabled(Context* context) void FlipCommand::onExecute(Context* context) { + Site site = context->activeSite(); + Timeline* timeline = App::instance()->timeline(); + LockTimelineRange lockRange(timeline); + + CelList cels; + if (m_flipMask) { + auto range = timeline->range(); + if (range.enabled()) { + cels = get_unlocked_unique_cels(site.sprite(), range); + } + else if (site.cel() && + site.layer() && + site.layer()->isEditable()) { + // If we want to flip the visible mask for the current cel, + // we can go to MovingPixelsState. + if (static_cast(site.document())->isMaskVisible()) { + // Select marquee tool + if (tools::Tool* tool = App::instance()->toolBox() + ->getToolById(tools::WellKnownTools::RectangularMarquee)) { + ToolBar::instance()->selectTool(tool); + current_editor->startFlipTransformation(m_flipType); + return; + } + } + cels.push_back(site.cel()); + } + + if (cels.empty()) { + StatusBar::instance()->showTip( + 1000, Strings::statusbar_tips_all_layers_are_locked().c_str()); + return; + } + } + // Flip the whole sprite (even locked layers) + else { + for (Cel* cel : site.sprite()->uniqueCels()) + cels.push_back(cel); + } + ContextWriter writer(context); Document* document = writer.document(); Sprite* sprite = writer.sprite(); + Transaction transaction(writer.context(), friendlyName()); + DocumentApi api = document->getApi(transaction); + + Mask* mask = document->mask(); + if (m_flipMask && document->isMaskVisible()) { + Site site = *writer.site(); - { - Transaction transaction(writer.context(), friendlyName()); - DocumentApi api = document->getApi(transaction); + for (Cel* cel : cels) { + // TODO add support to flip masked part of a reference layer + if (cel->layer()->isReference()) + continue; - Timeline* timeline = App::instance()->timeline(); - LockTimelineRange lockRange(timeline); + site.frame(cel->frame()); + site.layer(cel->layer()); - CelList cels; - if (m_flipMask) { - auto range = timeline->range(); - if (range.enabled()) { - cels = get_unlocked_unique_cels(sprite, range); - } - else if (writer.cel() && - writer.layer() && - writer.layer()->isEditable()) { - cels.push_back(writer.cel()); - } + int x, y; + Image* image = site.image(&x, &y); + if (!image) + continue; - if (cels.empty()) { - StatusBar::instance()->showTip( - 1000, Strings::statusbar_tips_all_layers_are_locked().c_str()); - return; - } - } - // Flip the whole sprite (even locked layers) - else { - for (Cel* cel : sprite->uniqueCels()) - cels.push_back(cel); - } - - Mask* mask = document->mask(); - if (m_flipMask && document->isMaskVisible()) { - Site site = *writer.site(); - - for (Cel* cel : cels) { - // TODO add support to flip masked part of a reference layer - if (cel->layer()->isReference()) + // When the mask is inside the cel, we can try to flip the + // pixels inside the image. + if (cel->bounds().contains(mask->bounds())) { + gfx::Rect flipBounds = mask->bounds(); + flipBounds.offset(-x, -y); + flipBounds &= image->bounds(); + if (flipBounds.isEmpty()) continue; - site.frame(cel->frame()); - site.layer(cel->layer()); + if (mask->bitmap() && !mask->isRectangular()) + transaction.execute(new cmd::FlipMaskedCel(cel, m_flipType)); + else + api.flipImage(image, flipBounds, m_flipType); - int x, y; - Image* image = site.image(&x, &y); - if (!image) + if (cel->layer()->isTransparent()) + transaction.execute(new cmd::TrimCel(cel)); + } + // When the mask is bigger than the cel bounds, we have to + // expand the cel, make the flip, and shrink it again. + else { + gfx::Rect flipBounds = (sprite->bounds() & mask->bounds()); + if (flipBounds.isEmpty()) continue; - // When the mask is inside the cel, we can try to flip the - // pixels inside the image. - if (cel->bounds().contains(mask->bounds())) { - gfx::Rect flipBounds = mask->bounds(); - flipBounds.offset(-x, -y); - flipBounds &= image->bounds(); - if (flipBounds.isEmpty()) - continue; + ExpandCelCanvas expand( + site, cel->layer(), + TiledMode::NONE, transaction, + ExpandCelCanvas::None); - if (mask->bitmap() && !mask->isRectangular()) - transaction.execute(new cmd::FlipMaskedCel(cel, m_flipType)); - else - api.flipImage(image, flipBounds, m_flipType); + expand.validateDestCanvas(gfx::Region(flipBounds)); - if (cel->layer()->isTransparent()) - transaction.execute(new cmd::TrimCel(cel)); - } - // When the mask is bigger than the cel bounds, we have to - // expand the cel, make the flip, and shrink it again. - else { - gfx::Rect flipBounds = (sprite->bounds() & mask->bounds()); - if (flipBounds.isEmpty()) - continue; + if (mask->bitmap() && !mask->isRectangular()) + doc::algorithm::flip_image_with_mask( + expand.getDestCanvas(), mask, m_flipType, + document->bgColor(cel->layer())); + else + doc::algorithm::flip_image( + expand.getDestCanvas(), + flipBounds, m_flipType); - ExpandCelCanvas expand( - site, cel->layer(), - TiledMode::NONE, transaction, - ExpandCelCanvas::None); - - expand.validateDestCanvas(gfx::Region(flipBounds)); - - if (mask->bitmap() && !mask->isRectangular()) - doc::algorithm::flip_image_with_mask( - expand.getDestCanvas(), mask, m_flipType, - document->bgColor(cel->layer())); - else - doc::algorithm::flip_image( - expand.getDestCanvas(), - flipBounds, m_flipType); - - expand.commit(); - } + expand.commit(); } } - else { - for (Cel* cel : cels) { - Image* image = cel->image(); + } + else { + for (Cel* cel : cels) { + Image* image = cel->image(); - // Flip reference layer cel - if (cel->layer()->isReference()) { - gfx::RectF bounds = cel->boundsF(); + // Flip reference layer cel + if (cel->layer()->isReference()) { + gfx::RectF bounds = cel->boundsF(); - if (m_flipType == doc::algorithm::FlipHorizontal) - bounds.x = sprite->width() - bounds.w - bounds.x; - if (m_flipType == doc::algorithm::FlipVertical) - bounds.y = sprite->height() - bounds.h - bounds.y; + if (m_flipType == doc::algorithm::FlipHorizontal) + bounds.x = sprite->width() - bounds.w - bounds.x; + if (m_flipType == doc::algorithm::FlipVertical) + bounds.y = sprite->height() - bounds.h - bounds.y; - transaction.execute(new cmd::SetCelBoundsF(cel, bounds)); - } - else { - api.setCelPosition - (sprite, cel, - (m_flipType == doc::algorithm::FlipHorizontal ? - sprite->width() - image->width() - cel->x(): - cel->x()), - (m_flipType == doc::algorithm::FlipVertical ? - sprite->height() - image->height() - cel->y(): - cel->y())); - } - - api.flipImage(image, image->bounds(), m_flipType); + transaction.execute(new cmd::SetCelBoundsF(cel, bounds)); } + else { + api.setCelPosition + (sprite, cel, + (m_flipType == doc::algorithm::FlipHorizontal ? + sprite->width() - image->width() - cel->x(): + cel->x()), + (m_flipType == doc::algorithm::FlipVertical ? + sprite->height() - image->height() - cel->y(): + cel->y())); + } + + api.flipImage(image, image->bounds(), m_flipType); } - - // Flip the mask. - Image* maskBitmap = mask->bitmap(); - if (maskBitmap) { - transaction.execute(new cmd::FlipMask(document, m_flipType)); - - // Flip the mask position because the - if (!m_flipMask) - transaction.execute( - new cmd::SetMaskPosition( - document, - gfx::Point( - (m_flipType == doc::algorithm::FlipHorizontal ? - sprite->width() - mask->bounds().x2(): - mask->bounds().x), - (m_flipType == doc::algorithm::FlipVertical ? - sprite->height() - mask->bounds().y2(): - mask->bounds().y)))); - - document->generateMaskBoundaries(); - } - - transaction.commit(); } + // Flip the mask. + Image* maskBitmap = mask->bitmap(); + if (maskBitmap) { + transaction.execute(new cmd::FlipMask(document, m_flipType)); + + // Flip the mask position because the + if (!m_flipMask) + transaction.execute( + new cmd::SetMaskPosition( + document, + gfx::Point( + (m_flipType == doc::algorithm::FlipHorizontal ? + sprite->width() - mask->bounds().x2(): + mask->bounds().x), + (m_flipType == doc::algorithm::FlipVertical ? + sprite->height() - mask->bounds().y2(): + mask->bounds().y)))); + + document->generateMaskBoundaries(); + } + + transaction.commit(); update_screen_for_document(document); } diff --git a/src/app/ui/editor/editor.cpp b/src/app/ui/editor/editor.cpp index 4b108e796..ba94110c0 100644 --- a/src/app/ui/editor/editor.cpp +++ b/src/app/ui/editor/editor.cpp @@ -2238,6 +2238,14 @@ void Editor::startSelectionTransformation(const gfx::Point& move, double angle) } } +void Editor::startFlipTransformation(doc::algorithm::FlipType flipType) +{ + if (MovingPixelsState* movingPixels = dynamic_cast(m_state.get())) + movingPixels->flip(flipType); + else if (StandbyState* standby = dynamic_cast(m_state.get())) + standby->startFlipTransformation(this, flipType); +} + void Editor::notifyScrollChanged() { m_observers.notifyScrollChanged(this); diff --git a/src/app/ui/editor/editor.h b/src/app/ui/editor/editor.h index 3c3205429..17b5e2868 100644 --- a/src/app/ui/editor/editor.h +++ b/src/app/ui/editor/editor.h @@ -19,6 +19,7 @@ #include "app/ui/editor/editor_observers.h" #include "app/ui/editor/editor_state.h" #include "app/ui/editor/editor_states_history.h" +#include "doc/algorithm/flip_type.h" #include "doc/document_observer.h" #include "doc/frame.h" #include "doc/image_buffer.h" @@ -218,6 +219,8 @@ namespace app { void pasteImage(const Image* image, const Mask* mask = nullptr); void startSelectionTransformation(const gfx::Point& move, double angle); + + void startFlipTransformation(doc::algorithm::FlipType flipType); // Used by EditorView to notify changes in the view's scroll // position. diff --git a/src/app/ui/editor/moving_pixels_state.cpp b/src/app/ui/editor/moving_pixels_state.cpp index a2baa538b..980bb92dd 100644 --- a/src/app/ui/editor/moving_pixels_state.cpp +++ b/src/app/ui/editor/moving_pixels_state.cpp @@ -133,6 +133,11 @@ void MovingPixelsState::rotate(double angle) { m_pixelsMovement->rotate(angle); } + +void MovingPixelsState::flip(doc::algorithm::FlipType flipType) +{ + m_pixelsMovement->flipImage(flipType); +} void MovingPixelsState::onEnterState(Editor* editor) { diff --git a/src/app/ui/editor/moving_pixels_state.h b/src/app/ui/editor/moving_pixels_state.h index 90f4de317..71b5f9f19 100644 --- a/src/app/ui/editor/moving_pixels_state.h +++ b/src/app/ui/editor/moving_pixels_state.h @@ -34,6 +34,7 @@ namespace app { void translate(const gfx::Point& delta); void rotate(double angle); + void flip(doc::algorithm::FlipType flipType); // EditorState virtual void onEnterState(Editor* editor) override; diff --git a/src/app/ui/editor/standby_state.cpp b/src/app/ui/editor/standby_state.cpp index 5891a0262..1634b1ee1 100644 --- a/src/app/ui/editor/standby_state.cpp +++ b/src/app/ui/editor/standby_state.cpp @@ -673,6 +673,14 @@ void StandbyState::startSelectionTransformation(Editor* editor, } } +void StandbyState::startFlipTransformation(Editor* editor, doc::algorithm::FlipType flipType) +{ + transformSelection(editor, NULL, NoHandle); + + if (MovingPixelsState* movingPixels = dynamic_cast(editor->getState().get())) + movingPixels->flip(flipType); +} + void StandbyState::transformSelection(Editor* editor, MouseMessage* msg, HandleType handle) { Document* document = editor->document(); diff --git a/src/app/ui/editor/standby_state.h b/src/app/ui/editor/standby_state.h index f97c74453..22084ef97 100644 --- a/src/app/ui/editor/standby_state.h +++ b/src/app/ui/editor/standby_state.h @@ -12,6 +12,7 @@ #include "app/ui/editor/editor_decorator.h" #include "app/ui/editor/handle_type.h" #include "app/ui/editor/state_with_wheel_behavior.h" +#include "doc/algorithm/flip_type.h" #include "obs/connection.h" namespace app { @@ -47,7 +48,9 @@ namespace app { virtual Transformation getTransformation(Editor* editor); void startSelectionTransformation(Editor* editor, const gfx::Point& move, double angle); - + + void startFlipTransformation(Editor* editor, doc::algorithm::FlipType flipType); + protected: void callEyedropper(Editor* editor, const ui::MouseMessage* msg); bool checkStartDrawingStraightLine(Editor* editor, const ui::MouseMessage* msg);