mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-10 12:44:53 +00:00
Now we can rotate the current cel or a range of cels (related to issue #161)
This commit is contained in:
parent
27cfd60d1b
commit
d4f056100b
23
data/gui.xml
23
data/gui.xml
@ -399,6 +399,20 @@
|
|||||||
<item command="Paste" text="&Paste" />
|
<item command="Paste" text="&Paste" />
|
||||||
<item command="Clear" text="C&lear" />
|
<item command="Clear" text="C&lear" />
|
||||||
<separator />
|
<separator />
|
||||||
|
<menu text="&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 &Horizontal">
|
<item command="Flip" text="Flip &Horizontal">
|
||||||
<param name="target" value="mask" />
|
<param name="target" value="mask" />
|
||||||
<param name="orientation" value="horizontal" />
|
<param name="orientation" value="horizontal" />
|
||||||
@ -443,13 +457,16 @@
|
|||||||
<item command="SpriteSize" text="&Sprite Size..." />
|
<item command="SpriteSize" text="&Sprite Size..." />
|
||||||
<item command="CanvasSize" text="&Canvas Size..." />
|
<item command="CanvasSize" text="&Canvas Size..." />
|
||||||
<menu text="&Rotate Canvas">
|
<menu text="&Rotate Canvas">
|
||||||
<item command="RotateCanvas" text="180">
|
<item command="Rotate" text="180">
|
||||||
|
<param name="target" value="canvas" />
|
||||||
<param name="angle" value="180" />
|
<param name="angle" value="180" />
|
||||||
</item>
|
</item>
|
||||||
<item command="RotateCanvas" text="90 CW">
|
<item command="Rotate" text="90 CW">
|
||||||
|
<param name="target" value="canvas" />
|
||||||
<param name="angle" value="90" />
|
<param name="angle" value="90" />
|
||||||
</item>
|
</item>
|
||||||
<item command="RotateCanvas" text="90 CCW">
|
<item command="Rotate" text="90 CCW">
|
||||||
|
<param name="target" value="canvas" />
|
||||||
<param name="angle" value="-90" />
|
<param name="angle" value="-90" />
|
||||||
</item>
|
</item>
|
||||||
<separator />
|
<separator />
|
||||||
|
@ -72,7 +72,7 @@ add_library(app-lib
|
|||||||
commands/cmd_remove_layer.cpp
|
commands/cmd_remove_layer.cpp
|
||||||
commands/cmd_repeat_last_export.cpp
|
commands/cmd_repeat_last_export.cpp
|
||||||
commands/cmd_reselect_mask.cpp
|
commands/cmd_reselect_mask.cpp
|
||||||
commands/cmd_rotate_canvas.cpp
|
commands/cmd_rotate.cpp
|
||||||
commands/cmd_save_file.cpp
|
commands/cmd_save_file.cpp
|
||||||
commands/cmd_save_mask.cpp
|
commands/cmd_save_mask.cpp
|
||||||
commands/cmd_save_palette.cpp
|
commands/cmd_save_palette.cpp
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Aseprite
|
/* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -25,10 +25,14 @@
|
|||||||
#include "app/commands/params.h"
|
#include "app/commands/params.h"
|
||||||
#include "app/context_access.h"
|
#include "app/context_access.h"
|
||||||
#include "app/document_api.h"
|
#include "app/document_api.h"
|
||||||
|
#include "app/document_range.h"
|
||||||
#include "app/job.h"
|
#include "app/job.h"
|
||||||
#include "app/modules/gui.h"
|
#include "app/modules/gui.h"
|
||||||
#include "app/ui/color_bar.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/undo_transaction.h"
|
||||||
|
#include "app/util/range_utils.h"
|
||||||
#include "raster/cel.h"
|
#include "raster/cel.h"
|
||||||
#include "raster/image.h"
|
#include "raster/image.h"
|
||||||
#include "raster/mask.h"
|
#include "raster/mask.h"
|
||||||
@ -40,33 +44,39 @@
|
|||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
class RotateCanvasCommand : public Command {
|
class RotateCommand : public Command {
|
||||||
int m_angle;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RotateCanvasCommand();
|
RotateCommand();
|
||||||
Command* clone() const override { return new RotateCanvasCommand(*this); }
|
Command* clone() const override { return new RotateCommand(*this); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void onLoadParams(Params* params);
|
void onLoadParams(Params* params);
|
||||||
bool onEnabled(Context* context);
|
bool onEnabled(Context* context);
|
||||||
void onExecute(Context* context);
|
void onExecute(Context* context);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_flipMask;
|
||||||
|
int m_angle;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RotateCanvasJob : public Job
|
class RotateJob : public Job
|
||||||
{
|
{
|
||||||
ContextWriter m_writer;
|
ContextWriter m_writer;
|
||||||
Document* m_document;
|
Document* m_document;
|
||||||
Sprite* m_sprite;
|
Sprite* m_sprite;
|
||||||
int m_angle;
|
int m_angle;
|
||||||
|
CelList m_cels;
|
||||||
|
bool m_rotateSprite;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RotateCanvasJob(const ContextReader& reader, int angle)
|
RotateJob(const ContextReader& reader, int angle, const CelList& cels, bool rotateSprite)
|
||||||
: Job("Rotate Canvas")
|
: Job("Rotate Canvas")
|
||||||
, m_writer(reader)
|
, m_writer(reader)
|
||||||
, m_document(m_writer.document())
|
, m_document(m_writer.document())
|
||||||
, m_sprite(m_writer.sprite())
|
, m_sprite(m_writer.sprite())
|
||||||
|
, m_cels(cels)
|
||||||
|
, m_rotateSprite(rotateSprite)
|
||||||
{
|
{
|
||||||
m_angle = angle;
|
m_angle = angle;
|
||||||
}
|
}
|
||||||
@ -81,50 +91,41 @@ protected:
|
|||||||
UndoTransaction undoTransaction(m_writer.context(), "Rotate Canvas");
|
UndoTransaction undoTransaction(m_writer.context(), "Rotate Canvas");
|
||||||
DocumentApi api = m_document->getApi();
|
DocumentApi api = m_document->getApi();
|
||||||
|
|
||||||
// get all sprite cels
|
|
||||||
CelList cels;
|
|
||||||
m_sprite->getCels(cels);
|
|
||||||
|
|
||||||
// for each cel...
|
// for each cel...
|
||||||
for (CelIterator it = cels.begin(); it != cels.end(); ++it) {
|
int i = 0;
|
||||||
Cel* cel = *it;
|
for (Cel* cel : m_cels) {
|
||||||
Image* image = cel->image();
|
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
|
// rotate the image
|
||||||
switch (m_angle) {
|
Image* new_image = Image::create(image->pixelFormat(),
|
||||||
case 180:
|
m_angle == 180 ? image->width(): image->height(),
|
||||||
api.setCelPosition(m_sprite, cel,
|
m_angle == 180 ? image->height(): image->width());
|
||||||
m_sprite->width() - cel->x() - image->width(),
|
raster::rotate_image(image, new_image, m_angle);
|
||||||
m_sprite->height() - cel->y() - image->height());
|
|
||||||
break;
|
api.replaceStockImage(m_sprite, cel->imageIndex(), new_image);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// for each stock's image
|
jobProgress((float)i / m_cels.size());
|
||||||
for (int i=0; i<m_sprite->stock()->size(); ++i) {
|
++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());
|
|
||||||
|
|
||||||
// cancel all the operation?
|
// cancel all the operation?
|
||||||
if (isCanceled())
|
if (isCanceled())
|
||||||
@ -168,7 +169,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// change the sprite's size
|
// 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());
|
api.setSpriteSize(m_sprite, m_sprite->height(), m_sprite->width());
|
||||||
|
|
||||||
// commit changes
|
// commit changes
|
||||||
@ -177,32 +178,56 @@ protected:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
RotateCanvasCommand::RotateCanvasCommand()
|
RotateCommand::RotateCommand()
|
||||||
: Command("RotateCanvas",
|
: Command("Rotate",
|
||||||
"Rotate Canvas",
|
"Rotate Canvas",
|
||||||
CmdRecordableFlag)
|
CmdRecordableFlag)
|
||||||
{
|
{
|
||||||
|
m_flipMask = false;
|
||||||
m_angle = 0;
|
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")) {
|
if (params->has_param("angle")) {
|
||||||
m_angle = ustrtol(params->get("angle").c_str(), NULL, 10);
|
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 |
|
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
|
||||||
ContextFlags::HasActiveSprite);
|
ContextFlags::HasActiveSprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RotateCanvasCommand::onExecute(Context* context)
|
void RotateCommand::onExecute(Context* context)
|
||||||
{
|
{
|
||||||
ContextReader reader(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.startJob();
|
||||||
job.waitJob();
|
job.waitJob();
|
||||||
}
|
}
|
||||||
@ -210,9 +235,9 @@ void RotateCanvasCommand::onExecute(Context* context)
|
|||||||
update_screen_for_document(reader.document());
|
update_screen_for_document(reader.document());
|
||||||
}
|
}
|
||||||
|
|
||||||
Command* CommandFactory::createRotateCanvasCommand()
|
Command* CommandFactory::createRotateCommand()
|
||||||
{
|
{
|
||||||
return new RotateCanvasCommand;
|
return new RotateCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
@ -91,7 +91,7 @@ FOR_EACH_COMMAND(RemoveLayer)
|
|||||||
FOR_EACH_COMMAND(RepeatLastExport)
|
FOR_EACH_COMMAND(RepeatLastExport)
|
||||||
FOR_EACH_COMMAND(ReplaceColor)
|
FOR_EACH_COMMAND(ReplaceColor)
|
||||||
FOR_EACH_COMMAND(ReselectMask)
|
FOR_EACH_COMMAND(ReselectMask)
|
||||||
FOR_EACH_COMMAND(RotateCanvas)
|
FOR_EACH_COMMAND(Rotate)
|
||||||
FOR_EACH_COMMAND(SaveFile)
|
FOR_EACH_COMMAND(SaveFile)
|
||||||
FOR_EACH_COMMAND(SaveFileAs)
|
FOR_EACH_COMMAND(SaveFileAs)
|
||||||
FOR_EACH_COMMAND(SaveFileCopyAs)
|
FOR_EACH_COMMAND(SaveFileCopyAs)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user