Now we can rotate the current cel or a range of cels (related to issue #161)

This commit is contained in:
David Capello 2014-08-25 09:06:38 -03:00
parent 27cfd60d1b
commit d4f056100b
4 changed files with 103 additions and 61 deletions

View File

@ -399,6 +399,20 @@
<item command="Paste" text="&amp;Paste" />
<item command="Clear" text="C&amp;lear" />
<separator />
<menu text="&amp;Rotate">
<item command="Rotate" text="180">
<param name="target" value="mask" />
<param name="angle" value="180" />
</item>
<item command="Rotate" text="90 CW">
<param name="target" value="mask" />
<param name="angle" value="90" />
</item>
<item command="Rotate" text="90 CCW">
<param name="target" value="mask" />
<param name="angle" value="-90" />
</item>
</menu>
<item command="Flip" text="Flip &amp;Horizontal">
<param name="target" value="mask" />
<param name="orientation" value="horizontal" />
@ -443,13 +457,16 @@
<item command="SpriteSize" text="&amp;Sprite Size..." />
<item command="CanvasSize" text="&amp;Canvas Size..." />
<menu text="&amp;Rotate Canvas">
<item command="RotateCanvas" text="180">
<item command="Rotate" text="180">
<param name="target" value="canvas" />
<param name="angle" value="180" />
</item>
<item command="RotateCanvas" text="90 CW">
<item command="Rotate" text="90 CW">
<param name="target" value="canvas" />
<param name="angle" value="90" />
</item>
<item command="RotateCanvas" text="90 CCW">
<item command="Rotate" text="90 CCW">
<param name="target" value="canvas" />
<param name="angle" value="-90" />
</item>
<separator />

View File

@ -72,7 +72,7 @@ add_library(app-lib
commands/cmd_remove_layer.cpp
commands/cmd_repeat_last_export.cpp
commands/cmd_reselect_mask.cpp
commands/cmd_rotate_canvas.cpp
commands/cmd_rotate.cpp
commands/cmd_save_file.cpp
commands/cmd_save_mask.cpp
commands/cmd_save_palette.cpp

View File

@ -1,5 +1,5 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -25,10 +25,14 @@
#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/gui.h"
#include "app/ui/color_bar.h"
#include "app/ui/main_window.h"
#include "app/ui/timeline.h"
#include "app/undo_transaction.h"
#include "app/util/range_utils.h"
#include "raster/cel.h"
#include "raster/image.h"
#include "raster/mask.h"
@ -40,33 +44,39 @@
namespace app {
class RotateCanvasCommand : public Command {
int m_angle;
class RotateCommand : public Command {
public:
RotateCanvasCommand();
Command* clone() const override { return new RotateCanvasCommand(*this); }
RotateCommand();
Command* clone() const override { return new RotateCommand(*this); }
protected:
void onLoadParams(Params* params);
bool onEnabled(Context* context);
void onExecute(Context* context);
private:
bool m_flipMask;
int m_angle;
};
class RotateCanvasJob : public Job
class RotateJob : public Job
{
ContextWriter m_writer;
Document* m_document;
Sprite* m_sprite;
int m_angle;
CelList m_cels;
bool m_rotateSprite;
public:
RotateCanvasJob(const ContextReader& reader, int angle)
RotateJob(const ContextReader& reader, int angle, const CelList& cels, bool rotateSprite)
: Job("Rotate Canvas")
, m_writer(reader)
, m_document(m_writer.document())
, m_sprite(m_writer.sprite())
, m_cels(cels)
, m_rotateSprite(rotateSprite)
{
m_angle = angle;
}
@ -81,50 +91,41 @@ protected:
UndoTransaction undoTransaction(m_writer.context(), "Rotate Canvas");
DocumentApi api = m_document->getApi();
// get all sprite cels
CelList cels;
m_sprite->getCels(cels);
// for each cel...
for (CelIterator it = cels.begin(); it != cels.end(); ++it) {
Cel* cel = *it;
int i = 0;
for (Cel* cel : m_cels) {
Image* image = cel->image();
if (image) {
// change it location
switch (m_angle) {
case 180:
api.setCelPosition(m_sprite, cel,
m_sprite->width() - cel->x() - image->width(),
m_sprite->height() - cel->y() - image->height());
break;
case 90:
api.setCelPosition(m_sprite, cel,
m_sprite->height() - cel->y() - image->height(),
cel->x());
break;
case -90:
api.setCelPosition(m_sprite, cel,
cel->y(),
m_sprite->width() - cel->x() - image->width());
break;
}
// change it location
switch (m_angle) {
case 180:
api.setCelPosition(m_sprite, cel,
m_sprite->width() - cel->x() - image->width(),
m_sprite->height() - cel->y() - image->height());
break;
case 90:
api.setCelPosition(m_sprite, cel,
m_sprite->height() - cel->y() - image->height(),
cel->x());
break;
case -90:
api.setCelPosition(m_sprite, cel,
cel->y(),
m_sprite->width() - cel->x() - image->width());
break;
// rotate the image
Image* new_image = Image::create(image->pixelFormat(),
m_angle == 180 ? image->width(): image->height(),
m_angle == 180 ? image->height(): image->width());
raster::rotate_image(image, new_image, m_angle);
api.replaceStockImage(m_sprite, cel->imageIndex(), new_image);
}
}
// for each stock's image
for (int i=0; i<m_sprite->stock()->size(); ++i) {
Image* image = m_sprite->stock()->getImage(i);
if (!image)
continue;
// rotate the image
Image* new_image = Image::create(image->pixelFormat(),
m_angle == 180 ? image->width(): image->height(),
m_angle == 180 ? image->height(): image->width());
raster::rotate_image(image, new_image, m_angle);
api.replaceStockImage(m_sprite, i, new_image);
jobProgress((float)i / m_sprite->stock()->size());
jobProgress((float)i / m_cels.size());
++i;
// cancel all the operation?
if (isCanceled())
@ -168,7 +169,7 @@ protected:
}
// change the sprite's size
if (m_angle != 180)
if (m_rotateSprite && m_angle != 180)
api.setSpriteSize(m_sprite, m_sprite->height(), m_sprite->width());
// commit changes
@ -177,32 +178,56 @@ protected:
};
RotateCanvasCommand::RotateCanvasCommand()
: Command("RotateCanvas",
RotateCommand::RotateCommand()
: Command("Rotate",
"Rotate Canvas",
CmdRecordableFlag)
{
m_flipMask = false;
m_angle = 0;
}
void RotateCanvasCommand::onLoadParams(Params* params)
void RotateCommand::onLoadParams(Params* params)
{
std::string target = params->get("target");
m_flipMask = (target == "mask");
if (params->has_param("angle")) {
m_angle = ustrtol(params->get("angle").c_str(), NULL, 10);
}
}
bool RotateCanvasCommand::onEnabled(Context* context)
bool RotateCommand::onEnabled(Context* context)
{
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
ContextFlags::HasActiveSprite);
}
void RotateCanvasCommand::onExecute(Context* context)
void RotateCommand::onExecute(Context* context)
{
ContextReader reader(context);
{
RotateCanvasJob job(reader, m_angle);
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_cels_in_range(reader.sprite(), range);
else if (reader.cel())
cels.push_back(reader.cel());
}
// Flip the whole sprite
else if (reader.sprite()) {
reader.sprite()->getCels(cels);
rotateSprite = true;
}
if (cels.empty()) // Nothing to do
return;
RotateJob job(reader, m_angle, cels, rotateSprite);
job.startJob();
job.waitJob();
}
@ -210,9 +235,9 @@ void RotateCanvasCommand::onExecute(Context* context)
update_screen_for_document(reader.document());
}
Command* CommandFactory::createRotateCanvasCommand()
Command* CommandFactory::createRotateCommand()
{
return new RotateCanvasCommand;
return new RotateCommand;
}
} // namespace app

View File

@ -91,7 +91,7 @@ FOR_EACH_COMMAND(RemoveLayer)
FOR_EACH_COMMAND(RepeatLastExport)
FOR_EACH_COMMAND(ReplaceColor)
FOR_EACH_COMMAND(ReselectMask)
FOR_EACH_COMMAND(RotateCanvas)
FOR_EACH_COMMAND(Rotate)
FOR_EACH_COMMAND(SaveFile)
FOR_EACH_COMMAND(SaveFileAs)
FOR_EACH_COMMAND(SaveFileCopyAs)