Add support to rotate the selection/moving pixels (fix #161)

This commit is contained in:
David Capello 2015-08-13 21:47:30 -03:00
parent 62c6647710
commit 462f1f395e
11 changed files with 123 additions and 37 deletions

View File

@ -162,7 +162,7 @@ void MoveMaskCommand::onExecute(Context* context)
update_screen_for_document(writer.document());
}
else {
current_editor->startSelectionTransformation(gfx::Point(dx, dy));
current_editor->startSelectionTransformation(gfx::Point(dx, dy), 0.0);
}
break;

View File

@ -10,17 +10,21 @@
#endif
#include "app/app.h"
#include "app/commands/command.h"
#include "app/commands/cmd_rotate.h"
#include "app/commands/params.h"
#include "app/context_access.h"
#include "app/document_api.h"
#include "app/document_range.h"
#include "app/job.h"
#include "app/modules/editors.h"
#include "app/modules/gui.h"
#include "app/tools/tool_box.h"
#include "app/transaction.h"
#include "app/ui/color_bar.h"
#include "app/ui/editor/editor.h"
#include "app/ui/main_window.h"
#include "app/ui/timeline.h"
#include "app/ui/toolbar.h"
#include "app/util/range_utils.h"
#include "base/convert_to.h"
#include "doc/cel.h"
@ -32,24 +36,7 @@
namespace app {
class RotateCommand : public Command {
public:
RotateCommand();
Command* clone() const override { return new RotateCommand(*this); }
protected:
void onLoadParams(const Params& params) override;
bool onEnabled(Context* context) override;
void onExecute(Context* context) override;
std::string onGetFriendlyName() const override;
private:
bool m_flipMask;
int m_angle;
};
class RotateJob : public Job
{
class RotateJob : public Job {
ContextWriter m_writer;
Document* m_document;
Sprite* m_sprite;
@ -198,8 +185,8 @@ bool RotateCommand::onEnabled(Context* context)
void RotateCommand::onExecute(Context* context)
{
ContextReader reader(context);
{
Site site = context->activeSite();
CelList cels;
bool rotateSprite = false;
@ -207,13 +194,26 @@ void RotateCommand::onExecute(Context* context)
if (m_flipMask) {
DocumentRange range = App::instance()->getMainWindow()->getTimeline()->range();
if (range.enabled())
cels = get_unique_cels(reader.sprite(), range);
else if (reader.cel())
cels.push_back(reader.cel());
cels = get_unique_cels(site.sprite(), range);
else if (site.cel()) {
// If we want to rotate the visible mask for the current cel,
// we can go to MovingPixelsState.
if (static_cast<app::Document*>(site.document())->isMaskVisible()) {
// Select marquee tool
if (tools::Tool* tool = App::instance()->getToolBox()
->getToolById(tools::WellKnownTools::RectangularMarquee)) {
ToolBar::instance()->selectTool(tool);
current_editor->startSelectionTransformation(gfx::Point(0, 0), m_angle);
return;
}
}
cels.push_back(site.cel());
}
}
// Flip the whole sprite
else if (reader.sprite()) {
for (Cel* cel : reader.sprite()->uniqueCels())
else if (site.sprite()) {
for (Cel* cel : site.sprite()->uniqueCels())
cels.push_back(cel);
rotateSprite = true;
@ -222,12 +222,15 @@ void RotateCommand::onExecute(Context* context)
if (cels.empty()) // Nothing to do
return;
RotateJob job(reader, m_angle, cels, rotateSprite);
job.startJob();
job.waitJob();
ContextReader reader(context);
{
RotateJob job(reader, m_angle, cels, rotateSprite);
job.startJob();
job.waitJob();
}
reader.document()->generateMaskBoundaries();
update_screen_for_document(reader.document());
}
reader.document()->generateMaskBoundaries();
update_screen_for_document(reader.document());
}
std::string RotateCommand::onGetFriendlyName() const

View File

@ -0,0 +1,37 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifndef APP_COMMANDS_CMD_ROTATE_H_INCLUDED
#define APP_COMMANDS_CMD_ROTATE_H_INCLUDED
#pragma once
#include "app/commands/command.h"
namespace app {
class RotateCommand : public Command {
public:
RotateCommand();
Command* clone() const override { return new RotateCommand(*this); }
bool flipMask() const { return m_flipMask; }
int angle() const { return m_angle; }
protected:
void onLoadParams(const Params& params) override;
bool onEnabled(Context* context) override;
void onExecute(Context* context) override;
std::string onGetFriendlyName() const override;
private:
bool m_flipMask;
int m_angle;
};
} // namespace app
#endif // APP_COMMANDS_CMD_ROTATE_H_INCLUDED

View File

@ -50,6 +50,7 @@
#include "she/system.h"
#include "ui/ui.h"
#include <cmath>
#include <cstdio>
namespace app {
@ -1486,13 +1487,15 @@ void Editor::pasteImage(const Image* image, const Mask* mask)
setState(EditorStatePtr(new MovingPixelsState(this, NULL, pixelsMovement, NoHandle)));
}
void Editor::startSelectionTransformation(const gfx::Point& move)
void Editor::startSelectionTransformation(const gfx::Point& move, double angle)
{
if (MovingPixelsState* movingPixels = dynamic_cast<MovingPixelsState*>(m_state.get())) {
movingPixels->translate(move);
if (std::fabs(angle) > 1e-5)
movingPixels->rotate(angle);
}
else if (StandbyState* standby = dynamic_cast<StandbyState*>(m_state.get())) {
standby->startSelectionTransformation(this, move);
standby->startSelectionTransformation(this, move, angle);
}
}

View File

@ -179,7 +179,7 @@ namespace app {
void pasteImage(const Image* image, const Mask* mask);
void startSelectionTransformation(const gfx::Point& move);
void startSelectionTransformation(const gfx::Point& move, double angle);
// Used by EditorView to notify changes in the view's scroll
// position.

View File

@ -15,6 +15,7 @@
#include "app/color_utils.h"
#include "app/commands/cmd_flip.h"
#include "app/commands/cmd_move_mask.h"
#include "app/commands/cmd_rotate.h"
#include "app/commands/command.h"
#include "app/commands/commands.h"
#include "app/console.h"
@ -130,6 +131,11 @@ void MovingPixelsState::translate(const gfx::Point& delta)
m_pixelsMovement->dropImageTemporarily();
}
void MovingPixelsState::rotate(double angle)
{
m_pixelsMovement->rotate(angle);
}
void MovingPixelsState::onEnterState(Editor* editor)
{
StandbyState::onEnterState(editor);
@ -483,6 +489,17 @@ void MovingPixelsState::onBeforeCommandExecution(CommandExecutionEvent& ev)
return;
}
}
// Rotate is quite simple, we can add the angle to the current transformation.
else if (command->id() == CommandId::Rotate) {
if (RotateCommand* rotate = dynamic_cast<RotateCommand*>(command)) {
if (rotate->flipMask()) {
m_pixelsMovement->rotate(rotate->angle());
ev.cancel();
return;
}
}
}
if (m_pixelsMovement)
dropPixels();

View File

@ -34,6 +34,7 @@ namespace app {
virtual ~MovingPixelsState();
void translate(const gfx::Point& delta);
void rotate(double angle);
// EditorState
virtual void onEnterState(Editor* editor) override;

View File

@ -127,6 +127,20 @@ void PixelsMovement::flipImage(doc::algorithm::FlipType flipType)
}
}
void PixelsMovement::rotate(double angle)
{
ContextWriter writer(m_reader, 1000);
m_currentData.angle(m_currentData.angle() + PI * -angle / 180.0);
m_document->setTransformation(m_currentData);
redrawExtraImage();
redrawCurrentMask();
updateDocumentMask();
update_screen_for_document(m_document);
}
void PixelsMovement::cutMask()
{
{

View File

@ -86,6 +86,10 @@ namespace app {
// current selection instead of dropping and flipping it).
void flipImage(doc::algorithm::FlipType flipType);
// Rotates the image and the mask the given angle. It's used to
// simulate RotateCommand when we're inside MovingPixelsState.
void rotate(double angle);
const gfx::Transformation& getTransformation() const { return m_currentData; }
private:

View File

@ -48,6 +48,8 @@
#include "ui/system.h"
#include "ui/view.h"
#include <cmath>
namespace app {
using namespace ui;
@ -403,12 +405,17 @@ gfx::Transformation StandbyState::getTransformation(Editor* editor)
return t;
}
void StandbyState::startSelectionTransformation(Editor* editor, const gfx::Point& move)
void StandbyState::startSelectionTransformation(Editor* editor,
const gfx::Point& move,
double angle)
{
transformSelection(editor, NULL, NoHandle);
if (MovingPixelsState* movingPixels = dynamic_cast<MovingPixelsState*>(editor->getState().get()))
if (MovingPixelsState* movingPixels = dynamic_cast<MovingPixelsState*>(editor->getState().get())) {
movingPixels->translate(move);
if (std::fabs(angle) > 1e-5)
movingPixels->rotate(angle);
}
}
void StandbyState::transformSelection(Editor* editor, MouseMessage* msg, HandleType handle)

View File

@ -39,7 +39,7 @@ namespace app {
virtual gfx::Transformation getTransformation(Editor* editor);
void startSelectionTransformation(Editor* editor, const gfx::Point& move);
void startSelectionTransformation(Editor* editor, const gfx::Point& move, double angle);
protected:
// Returns true and changes to ScrollingState when "msg" says "the