Skip to content

Commit

Permalink
Add support to rotate the selection/moving pixels (fix #161)
Browse files Browse the repository at this point in the history
  • Loading branch information
dacap committed Aug 14, 2015
1 parent 62c6647 commit 462f1f3
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 37 deletions.
2 changes: 1 addition & 1 deletion src/app/commands/cmd_move_mask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
63 changes: 33 additions & 30 deletions src/app/commands/cmd_rotate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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;
Expand Down Expand Up @@ -198,22 +185,35 @@ bool RotateCommand::onEnabled(Context* context)

void RotateCommand::onExecute(Context* context)
{
ContextReader reader(context);
{
Site site = context->activeSite();
CelList cels;
bool rotateSprite = false;

// Flip the mask or current cel
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;
Expand All @@ -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
Expand Down
37 changes: 37 additions & 0 deletions src/app/commands/cmd_rotate.h
Original file line number Diff line number Diff line change
@@ -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
7 changes: 5 additions & 2 deletions src/app/ui/editor/editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include "she/system.h"
#include "ui/ui.h"

#include <cmath>
#include <cstdio>

namespace app {
Expand Down Expand Up @@ -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);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/app/ui/editor/editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
17 changes: 17 additions & 0 deletions src/app/ui/editor/moving_pixels_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions src/app/ui/editor/moving_pixels_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
14 changes: 14 additions & 0 deletions src/app/ui/editor/pixels_movement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
{
Expand Down
4 changes: 4 additions & 0 deletions src/app/ui/editor/pixels_movement.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
11 changes: 9 additions & 2 deletions src/app/ui/editor/standby_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
#include "ui/system.h"
#include "ui/view.h"

#include <cmath>

namespace app {

using namespace ui;
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/app/ui/editor/standby_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 462f1f3

Please sign in to comment.