mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-14 13:21:34 +00:00
Add support to rotate the selection/moving pixels (fix #161)
This commit is contained in:
parent
62c6647710
commit
462f1f395e
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
37
src/app/commands/cmd_rotate.h
Normal file
37
src/app/commands/cmd_rotate.h
Normal 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
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
{
|
||||
{
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user