Implement issue #265 - command/keyboard shortcut for "last export" operation

- Add doc::ExportData with information about the last export operation.
- Add RepeatLastExport command.
- Add SaveFileBaseCommand as base Command class, to accept "filename"
  param.
- Add parameters to ExportSpriteSheet so we can call it without UI
  from "repeat last export".
This commit is contained in:
David Capello 2014-03-29 16:58:35 -03:00
parent 395be62b03
commit b16bf981d0
12 changed files with 606 additions and 280 deletions

View File

@ -14,6 +14,7 @@
<key command="SaveFileCopyAs" shortcut="Ctrl+Shift+C" />
<key command="CloseFile" shortcut="Ctrl+W" />
<key command="CloseAllFiles" shortcut="Ctrl+Shift+W" />
<key command="RepeatLastExport" shortcut="Ctrl+Shift+X" />
<key command="AdvancedMode" shortcut="F11" />
<key command="DeveloperConsole" shortcut="F12" />
<key command="Exit" shortcut="Alt+F4" />
@ -229,6 +230,7 @@
<separator />
<item command="ImportSpriteSheet" text="&amp;Import Sprite Sheet" />
<item command="ExportSpriteSheet" text="&amp;Export Sprite Sheet" />
<item command="RepeatLastExport" text="Repeat &amp;Last Export" />
<separator />
<item command="Exit" text="E&amp;xit" />
</menu>

View File

@ -68,6 +68,7 @@ add_library(app-lib
commands/cmd_remove_cel.cpp
commands/cmd_remove_frame.cpp
commands/cmd_remove_layer.cpp
commands/cmd_repeat_last_export.cpp
commands/cmd_reselect_mask.cpp
commands/cmd_rotate_canvas.cpp
commands/cmd_save_file.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
@ -20,8 +20,12 @@
#include "config.h"
#endif
#include "app/commands/cmd_export_sprite_sheet.h"
#include "app/commands/cmd_save_file.h"
#include "app/commands/command.h"
#include "app/commands/commands.h"
#include "app/commands/params.h"
#include "app/context.h"
#include "app/context_access.h"
#include "app/document.h"
@ -50,20 +54,19 @@ namespace app {
using namespace ui;
class ExportSpriteSheetWindow : public Window {
enum SpriteSheetType { HorizontalStrip, VerticalStrip, Matrix };
enum ExportAction { SaveCopyAs, SaveAs, Save, DoNotSave };
public:
typedef ExportSpriteSheetCommand::SpriteSheetType SpriteSheetType;
typedef ExportSpriteSheetCommand::ExportAction ExportAction;
ExportSpriteSheetWindow(Context* context)
: Window(WithTitleBar, "Export Sprite Sheet")
, m_context(context)
, m_document(context->getActiveDocument())
, m_grid(4, false)
, m_columnsLabel("Columns:")
, m_columns(4, "4")
, m_exportActionLabel("Export Action:")
, m_export("Export")
, m_cancel("Cancel")
, m_export("&Export")
, m_cancel("&Cancel")
, m_ok(false)
{
m_sheetType.addItem("Horizontal Strip");
m_sheetType.addItem("Vertical Strip");
@ -100,8 +103,20 @@ public:
onSheetTypeChange();
}
~ExportSpriteSheetWindow()
{
bool ok() const {
return m_ok;
}
SpriteSheetType spriteSheetType() const {
return (SpriteSheetType)m_sheetType.getSelectedItemIndex();
}
ExportAction exportAction() const {
return (ExportAction)m_exportAction.getSelectedItemIndex();
}
int columns() const {
return m_columns.getTextInt();
}
protected:
@ -110,7 +125,7 @@ protected:
{
bool state = false;
switch (m_sheetType.getSelectedItemIndex()) {
case Matrix:
case ExportSpriteSheetCommand::Matrix:
state = true;
break;
}
@ -125,170 +140,7 @@ protected:
void onExport()
{
Sprite* sprite = m_document->getSprite();
FrameNumber nframes = sprite->getTotalFrames();
int columns;
switch (m_sheetType.getSelectedItemIndex()) {
case HorizontalStrip:
columns = nframes;
break;
case VerticalStrip:
columns = 1;
break;
case Matrix:
columns = m_columns.getTextInt();
break;
}
columns = MID(1, columns, nframes);
int sheet_w = sprite->getWidth()*columns;
int sheet_h = sprite->getHeight()*((nframes/columns)+((nframes%columns)>0?1:0));
base::UniquePtr<Image> resultImage(Image::create(sprite->getPixelFormat(), sheet_w, sheet_h));
base::UniquePtr<Image> tempImage(Image::create(sprite->getPixelFormat(), sprite->getWidth(), sprite->getHeight()));
raster::clear_image(resultImage, 0);
int column = 0, row = 0;
for (FrameNumber frame(0); frame<nframes; ++frame) {
// TODO "tempImage" could not be necessary if we could specify
// destination clipping bounds in Sprite::render() function.
tempImage->clear(0);
sprite->render(tempImage, 0, 0, frame);
resultImage->copy(tempImage, column*sprite->getWidth(), row*sprite->getHeight());
if (++column >= columns) {
column = 0;
++row;
}
}
// Store the frame in the current editor so we can restore it
// after change and restore the setTotalFrames() number.
FrameNumber oldSelectedFrame = (current_editor ? current_editor->getFrame():
FrameNumber(0));
{
// The following steps modify the sprite, so we wrap all
// operations in a undo-transaction.
ContextWriter writer(m_context);
UndoTransaction undoTransaction(writer.context(), "Export Sprite Sheet", undo::ModifyDocument);
DocumentApi api = m_document->getApi();
// Add the layer in the sprite.
LayerImage* resultLayer = api.newLayer(sprite);
// Add the image into the sprite's stock
int indexInStock = api.addImageInStock(sprite, resultImage);
resultImage.release();
// Create the cel.
base::UniquePtr<Cel> resultCel(new Cel(FrameNumber(0), indexInStock));
// Add the cel in the layer.
api.addCel(resultLayer, resultCel);
resultCel.release();
// Copy the list of layers (because we will modify it in the iteration).
LayerList layers = sprite->getFolder()->getLayersList();
// Remove all other layers
for (LayerIterator it=layers.begin(), end=layers.end(); it!=end; ++it) {
if (*it != resultLayer)
api.removeLayer(*it);
}
// Change the number of frames (just one, the sprite sheet). As
// we are using the observable API, all DocumentView will change
// its current frame to frame 1. We'll try to restore the
// selected frame for the current_editor later.
api.setTotalFrames(sprite, FrameNumber(1));
// Set the size of the sprite to the tile size.
api.setSpriteSize(sprite, sheet_w, sheet_h);
undoTransaction.commit();
// Draw the document with the new dimensions in the screen.
update_screen_for_document(m_document);
}
// This flag indicates if we've to undo the last action (so we
// back to the original sprite dimensions).
bool undo = false;
// Do the "Export Action"
switch (m_exportAction.getSelectedItemIndex()) {
case SaveCopyAs:
{
Command* command = CommandsModule::instance()
->getCommandByName(CommandId::SaveFileCopyAs);
m_context->executeCommand(command);
}
// Always go back, as we are using "Save Copy As", so the user
// wants to continue editing the original sprite.
undo = true;
break;
case SaveAs:
{
Command* command = CommandsModule::instance()
->getCommandByName(CommandId::SaveFileAs);
m_context->executeCommand(command);
}
// If the command was cancelled, we go back to the original
// state, if the sprite sheet was saved then we don't undo
// because the user wants to edit the sprite sheet.
undo = (m_document->isModified());
break;
case Save:
{
Command* command = CommandsModule::instance()
->getCommandByName(CommandId::SaveFile);
m_context->executeCommand(command);
}
// Same case as "Save As"
undo = (m_document->isModified());
break;
case DoNotSave:
// Do not undo as the user wants to edit the sprite sheet
// before to save the file.
undo = false;
break;
}
// Undo the sprite sheet conversion
if (undo) {
if (m_document->getUndo()->canUndo()) {
m_document->getUndo()->doUndo();
// We've to restore the previously selected frame. As we've
// called setTotalFrames(), all document observers
// (current_editor included) have changed its current frame to
// the first one (to a visible/editable frame). The "undo"
// action doesn't restore the previously selected frame in
// observers, so at least we can restore the current_editor's
// frame.
if (current_editor)
current_editor->setFrame(oldSelectedFrame);
}
m_document->generateMaskBoundaries();
m_document->destroyExtraCel(); // Regenerate extras
// Redraw the sprite.
update_screen_for_document(m_document);
}
m_ok = true;
closeWindow(NULL);
}
@ -298,8 +150,6 @@ protected:
}
private:
Context* m_context;
Document* m_document;
Grid m_grid;
ComboBox m_sheetType;
Label m_columnsLabel;
@ -308,22 +158,14 @@ private:
ComboBox m_exportAction;
Button m_export;
Button m_cancel;
};
class ExportSpriteSheetCommand : public Command {
public:
ExportSpriteSheetCommand();
Command* clone() { return new ExportSpriteSheetCommand(*this); }
protected:
virtual bool onEnabled(Context* context) OVERRIDE;
virtual void onExecute(Context* context) OVERRIDE;
bool m_ok;
};
ExportSpriteSheetCommand::ExportSpriteSheetCommand()
: Command("ExportSpriteSheet",
"Export Sprite Sheet",
CmdRecordableFlag)
, m_useUI(true)
{
}
@ -334,8 +176,203 @@ bool ExportSpriteSheetCommand::onEnabled(Context* context)
void ExportSpriteSheetCommand::onExecute(Context* context)
{
base::UniquePtr<Window> window(new ExportSpriteSheetWindow(context));
window->openWindowInForeground();
if (m_useUI) {
base::UniquePtr<ExportSpriteSheetWindow> window(new ExportSpriteSheetWindow(context));
window->openWindowInForeground();
if (!window->ok())
return;
setType(window->spriteSheetType());
setAction(window->exportAction());
setColumns(window->columns());
}
Document* document(context->getActiveDocument());
Sprite* sprite = document->getSprite();
FrameNumber nframes = sprite->getTotalFrames();
int columns;
switch (m_type) {
case HorizontalStrip:
columns = nframes;
break;
case VerticalStrip:
columns = 1;
break;
case Matrix:
columns = m_columns;
break;
}
columns = MID(1, columns, nframes);
int sheet_w = sprite->getWidth()*columns;
int sheet_h = sprite->getHeight()*((nframes/columns)+((nframes%columns)>0?1:0));
base::UniquePtr<Image> resultImage(Image::create(sprite->getPixelFormat(), sheet_w, sheet_h));
base::UniquePtr<Image> tempImage(Image::create(sprite->getPixelFormat(), sprite->getWidth(), sprite->getHeight()));
raster::clear_image(resultImage, 0);
int column = 0, row = 0;
for (FrameNumber frame(0); frame<nframes; ++frame) {
// TODO "tempImage" could not be necessary if we could specify
// destination clipping bounds in Sprite::render() function.
tempImage->clear(0);
sprite->render(tempImage, 0, 0, frame);
resultImage->copy(tempImage, column*sprite->getWidth(), row*sprite->getHeight());
if (++column >= columns) {
column = 0;
++row;
}
}
// Store the frame in the current editor so we can restore it
// after change and restore the setTotalFrames() number.
FrameNumber oldSelectedFrame = (current_editor ? current_editor->getFrame():
FrameNumber(0));
{
// The following steps modify the sprite, so we wrap all
// operations in a undo-transaction.
ContextWriter writer(context);
UndoTransaction undoTransaction(writer.context(), "Export Sprite Sheet", undo::ModifyDocument);
DocumentApi api = document->getApi();
// Add the layer in the sprite.
LayerImage* resultLayer = api.newLayer(sprite);
// Add the image into the sprite's stock
int indexInStock = api.addImageInStock(sprite, resultImage);
resultImage.release();
// Create the cel.
base::UniquePtr<Cel> resultCel(new Cel(FrameNumber(0), indexInStock));
// Add the cel in the layer.
api.addCel(resultLayer, resultCel);
resultCel.release();
// Copy the list of layers (because we will modify it in the iteration).
LayerList layers = sprite->getFolder()->getLayersList();
// Remove all other layers
for (LayerIterator it=layers.begin(), end=layers.end(); it!=end; ++it) {
if (*it != resultLayer)
api.removeLayer(*it);
}
// Change the number of frames (just one, the sprite sheet). As
// we are using the observable API, all DocumentView will change
// its current frame to frame 1. We'll try to restore the
// selected frame for the current_editor later.
api.setTotalFrames(sprite, FrameNumber(1));
// Set the size of the sprite to the tile size.
api.setSpriteSize(sprite, sheet_w, sheet_h);
undoTransaction.commit();
// Draw the document with the new dimensions in the screen.
update_screen_for_document(document);
}
// This flag indicates if we've to undo the last action (so we
// back to the original sprite dimensions).
bool undo = false;
Params params;
if (!m_filename.empty())
params.set("filename", m_filename.c_str());
SaveFileBaseCommand* command = NULL;
// Do the "Export Action"
switch (m_action) {
case SaveCopyAs:
command = static_cast<SaveFileBaseCommand*>(CommandsModule::instance()
->getCommandByName(CommandId::SaveFileCopyAs));
context->executeCommand(command, &params);
// Always go back, as we are using "Save Copy As", so the user
// wants to continue editing the original sprite.
undo = true;
break;
case SaveAs:
command = static_cast<SaveFileBaseCommand*>(CommandsModule::instance()
->getCommandByName(CommandId::SaveFileAs));
context->executeCommand(command, &params);
// If the command was cancelled, we go back to the original
// state, if the sprite sheet was saved then we don't undo
// because the user wants to edit the sprite sheet.
undo = (document->isModified());
break;
case Save:
command = static_cast<SaveFileBaseCommand*>(CommandsModule::instance()
->getCommandByName(CommandId::SaveFile));
context->executeCommand(command, &params);
// Same case as "Save As"
undo = (document->isModified());
break;
case DoNotSave:
// Do not undo as the user wants to edit the sprite sheet
// before to save the file.
undo = false;
break;
}
// Set export data
if (command != NULL) {
doc::ExportData::Type type;
switch (m_type) {
case ExportSpriteSheetCommand::HorizontalStrip:
type = doc::ExportData::HorizontalStrip;
break;
case ExportSpriteSheetCommand::VerticalStrip:
type = doc::ExportData::VerticalStrip;
break;
case ExportSpriteSheetCommand::Matrix:
type = doc::ExportData::Matrix;
break;
}
doc::ExportDataPtr data(new doc::ExportData);
data->setType(type);
data->setColumns(columns);
data->setFilename(command->selectedFilename());
document->setExportData(data);
}
// Undo the sprite sheet conversion
if (undo) {
if (document->getUndo()->canUndo()) {
document->getUndo()->doUndo();
// We've to restore the previously selected frame. As we've
// called setTotalFrames(), all document observers
// (current_editor included) have changed its current frame to
// the first one (to a visible/editable frame). The "undo"
// action doesn't restore the previously selected frame in
// observers, so at least we can restore the current_editor's
// frame.
if (current_editor)
current_editor->setFrame(oldSelectedFrame);
}
document->generateMaskBoundaries();
document->destroyExtraCel(); // Regenerate extras
// Redraw the sprite.
update_screen_for_document(document);
}
}
Command* CommandFactory::createExportSpriteSheetCommand()

View File

@ -0,0 +1,60 @@
/* Aseprite
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef APP_COMMANDS_CMD_EXPORT_SPRITE_SHEET_H_INCLUDED
#define APP_COMMANDS_CMD_EXPORT_SPRITE_SHEET_H_INCLUDED
#include "app/commands/command.h"
#include "base/compiler_specific.h"
#include <string>
namespace app {
class ExportSpriteSheetCommand : public Command {
public:
enum SpriteSheetType { HorizontalStrip, VerticalStrip, Matrix };
enum ExportAction { SaveCopyAs, SaveAs, Save, DoNotSave };
ExportSpriteSheetCommand();
Command* clone() const OVERRIDE { return new ExportSpriteSheetCommand(*this); }
SpriteSheetType type() const { return m_type; }
ExportAction action() const { return m_action; }
void setUseUI(bool useUI) { m_useUI = useUI; }
void setType(SpriteSheetType type) { m_type = type; }
void setAction(ExportAction action) { m_action = action; }
void setColumns(int columns) { m_columns = columns; }
void setFileName(const std::string& filename) { m_filename = filename; }
protected:
virtual bool onEnabled(Context* context) OVERRIDE;
virtual void onExecute(Context* context) OVERRIDE;
private:
bool m_useUI;
SpriteSheetType m_type;
ExportAction m_action;
int m_columns;
std::string m_filename;
};
} // namespace app
#endif

View File

@ -0,0 +1,98 @@
/* Aseprite
* Copyright (C) 2001-2013 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/commands/cmd_export_sprite_sheet.h"
#include "app/commands/command.h"
#include "app/commands/commands.h"
#include "app/commands/params.h"
#include "app/context.h"
#include "app/context_access.h"
#include "base/compiler_specific.h"
namespace app {
class RepeatLastExportCommand : public Command {
public:
RepeatLastExportCommand();
Command* clone() { return new RepeatLastExportCommand(*this); }
protected:
virtual bool onEnabled(Context* context) OVERRIDE;
virtual void onExecute(Context* context) OVERRIDE;
};
RepeatLastExportCommand::RepeatLastExportCommand()
: Command("RepeatLastExport",
"Repeat Last Export",
CmdRecordableFlag)
{
}
bool RepeatLastExportCommand::onEnabled(Context* context)
{
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable);
}
void RepeatLastExportCommand::onExecute(Context* context)
{
base::UniquePtr<ExportSpriteSheetCommand> command(
static_cast<ExportSpriteSheetCommand*>(
CommandsModule::instance()->getCommandByName(CommandId::ExportSpriteSheet)->clone()));
{
const ContextReader reader(context);
const Document* document(reader.document());
doc::ExportDataPtr data = document->exportData();
if (data != NULL) {
command->setUseUI(false);
ExportSpriteSheetCommand::SpriteSheetType type;
switch (data->type()) {
case doc::ExportData::None: return;
case doc::ExportData::HorizontalStrip:
type = ExportSpriteSheetCommand::HorizontalStrip;
break;
case doc::ExportData::VerticalStrip:
type = ExportSpriteSheetCommand::VerticalStrip;
break;
case doc::ExportData::Matrix:
type = ExportSpriteSheetCommand::Matrix;
break;
}
command->setType(type);
command->setAction(ExportSpriteSheetCommand::SaveCopyAs);
command->setColumns(data->columns());
command->setFileName(data->filename());
}
}
context->executeCommand(command);
}
Command* CommandFactory::createRepeatLastExportCommand()
{
return new RepeatLastExportCommand;
}
} // namespace app

View File

@ -22,6 +22,7 @@
#include "app/app.h"
#include "app/commands/command.h"
#include "app/commands/params.h"
#include "app/console.h"
#include "app/context_access.h"
#include "app/file/file.h"
@ -101,105 +102,122 @@ static void save_document_in_background(Document* document, bool mark_as_saved)
//////////////////////////////////////////////////////////////////////
static bool confirm_readonly(const base::string& filename)
{
if (!base::has_readonly_attr(filename))
return true;
int ret = ui::Alert::show("Warning<<The file is read-only, do you really want to overwrite it?<<%s||&Yes||&No",
base::get_file_name(filename).c_str());
if (ret == 1) {
base::remove_readonly_attr(filename);
return true;
class SaveFileBaseCommand : public Command {
public:
SaveFileBaseCommand(const char* short_name, const char* friendly_name, CommandFlags flags)
: Command(short_name, friendly_name, flags) {
}
else
return false;
}
static void save_as_dialog(const ContextReader& reader, const char* dlg_title, bool mark_as_saved)
{
const Document* document = reader.document();
char exts[4096];
base::string filename;
base::string newfilename;
int ret;
protected:
void onLoadParams(Params* params) OVERRIDE {
m_filename = params->get("filename");
}
filename = document->getFilename();
get_writable_extensions(exts, sizeof(exts));
// Returns true if there is a current sprite to save.
// [main thread]
bool onEnabled(Context* context) OVERRIDE {
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable);
}
for (;;) {
newfilename = app::show_file_selector(dlg_title, filename, exts);
if (newfilename.empty())
return;
void saveAsDialog(const ContextReader& reader, const char* dlgTitle, bool markAsSaved)
{
const Document* document = reader.document();
base::string filename;
filename = newfilename;
if (!m_filename.empty()) {
filename = m_filename;
}
else {
filename = document->getFilename();
// Ask if the user wants overwrite the existent file.
if (base::file_exists(filename)) {
ret = ui::Alert::show("Warning<<The file already exists, overwrite it?<<%s||&Yes||&No||&Cancel",
base::get_file_name(filename).c_str());
char exts[4096];
get_writable_extensions(exts, sizeof(exts));
// Check for read-only attribute.
if (ret == 1) {
if (!confirm_readonly(filename))
ret = 2; // Select file again.
for (;;) {
base::string newfilename = app::show_file_selector(dlgTitle, filename, exts);
if (newfilename.empty())
return;
filename = newfilename;
// Ask if the user wants overwrite the existent file.
int ret = 0;
if (base::file_exists(filename)) {
ret = ui::Alert::show("Warning<<The file already exists, overwrite it?<<%s||&Yes||&No||&Cancel",
base::get_file_name(filename).c_str());
// Check for read-only attribute.
if (ret == 1) {
if (!confirmReadonly(filename))
ret = 2; // Select file again.
else
break;
}
}
else
break;
// "yes": we must continue with the operation...
if (ret == 1) {
break;
}
// "cancel" or <esc> per example: we back doing nothing
else if (ret != 2)
return;
// "no": we must back to select other file-name
}
}
else
break;
// "yes": we must continue with the operation...
if (ret == 1) {
break;
{
ContextWriter writer(reader);
Document* documentWriter = writer.document();
// Change the document file name
documentWriter->setFilename(filename.c_str());
m_selectedFilename = filename;
// Save the document
save_document_in_background(documentWriter, markAsSaved);
update_screen_for_document(documentWriter);
}
// "cancel" or <esc> per example: we back doing nothing
else if (ret != 2)
return;
// "no": we must back to select other file-name
}
static bool confirmReadonly(const std::string& filename)
{
ContextWriter writer(reader);
Document* documentWriter = writer.document();
if (!base::has_readonly_attr(filename))
return true;
// Change the document file name
documentWriter->setFilename(filename.c_str());
int ret = ui::Alert::show("Warning<<The file is read-only, do you really want to overwrite it?<<%s||&Yes||&No",
base::get_file_name(filename).c_str());
// Save the document
save_document_in_background(documentWriter, mark_as_saved);
update_screen_for_document(documentWriter);
if (ret == 1) {
base::remove_readonly_attr(filename);
return true;
}
else
return false;
}
}
class SaveFileCommand : public Command {
std::string m_filename;
std::string m_selectedFilename;
};
class SaveFileCommand : public SaveFileBaseCommand {
public:
SaveFileCommand();
Command* clone() { return new SaveFileCommand(*this); }
protected:
bool onEnabled(Context* context);
void onExecute(Context* context);
};
SaveFileCommand::SaveFileCommand()
: Command("SaveFile",
"Save File",
CmdRecordableFlag)
: SaveFileBaseCommand("SaveFile", "Save File", CmdRecordableFlag)
{
}
// Returns true if there is a current sprite to save.
// [main thread]
bool SaveFileCommand::onEnabled(Context* context)
{
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable);
}
// Saves the active document in a file.
// [main thread]
void SaveFileCommand::onExecute(Context* context)
@ -213,7 +231,7 @@ void SaveFileCommand::onExecute(Context* context)
ContextWriter writer(reader);
Document* documentWriter = writer.document();
if (!confirm_readonly(documentWriter->getFilename()))
if (!confirmReadonly(documentWriter->getFilename()))
return;
save_document_in_background(documentWriter, true);
@ -223,60 +241,44 @@ void SaveFileCommand::onExecute(Context* context)
// save-as dialog to the user to select for first time the file-name
// for this document.
else {
save_as_dialog(reader, "Save File", true);
saveAsDialog(reader, "Save File", true);
}
}
class SaveFileAsCommand : public Command {
class SaveFileAsCommand : public SaveFileBaseCommand {
public:
SaveFileAsCommand();
Command* clone() { return new SaveFileAsCommand(*this); }
protected:
bool onEnabled(Context* context);
void onExecute(Context* context);
};
SaveFileAsCommand::SaveFileAsCommand()
: Command("SaveFileAs",
"Save File As",
CmdRecordableFlag)
: SaveFileBaseCommand("SaveFileAs", "Save File As", CmdRecordableFlag)
{
}
bool SaveFileAsCommand::onEnabled(Context* context)
{
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable);
}
void SaveFileAsCommand::onExecute(Context* context)
{
const ContextReader reader(context);
save_as_dialog(reader, "Save As", true);
saveAsDialog(reader, "Save As", true);
}
class SaveFileCopyAsCommand : public Command {
class SaveFileCopyAsCommand : public SaveFileBaseCommand {
public:
SaveFileCopyAsCommand();
Command* clone() { return new SaveFileCopyAsCommand(*this); }
protected:
bool onEnabled(Context* context);
void onExecute(Context* context);
};
SaveFileCopyAsCommand::SaveFileCopyAsCommand()
: Command("SaveFileCopyAs",
"Save File Copy As",
CmdRecordableFlag)
: SaveFileBaseCommand("SaveFileCopyAs", "Save File Copy As", CmdRecordableFlag)
{
}
bool SaveFileCopyAsCommand::onEnabled(Context* context)
{
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable);
}
void SaveFileCopyAsCommand::onExecute(Context* context)
{
const ContextReader reader(context);
@ -284,7 +286,7 @@ void SaveFileCopyAsCommand::onExecute(Context* context)
base::string old_filename = document->getFilename();
// show "Save As" dialog
save_as_dialog(reader, "Save Copy As", false);
saveAsDialog(reader, "Save Copy As", false);
// Restore the file name.
{

View File

@ -0,0 +1,52 @@
/* Aseprite
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef APP_COMMANDS_CMD_SAVE_FILE_H_INCLUDED
#define APP_COMMANDS_CMD_SAVE_FILE_H_INCLUDED
#include "app/commands/command.h"
#include "base/compiler_specific.h"
#include <string>
namespace app {
class ContextReader;
class SaveFileBaseCommand : public Command {
public:
SaveFileBaseCommand(const char* shortName, const char* friendlyName, CommandFlags flags);
std::string selectedFilename() const {
return m_selectedFilename;
}
protected:
void onLoadParams(Params* params) OVERRIDE;
bool onEnabled(Context* context) OVERRIDE;
void saveAsDialog(const ContextReader& reader, const char* dlgTitle, bool markAsSaved);
static bool confirmReadonly(const std::string& filename);
std::string m_filename;
std::string m_selectedFilename;
};
} // namespace app
#endif

View File

@ -87,6 +87,7 @@ FOR_EACH_COMMAND(Refresh)
FOR_EACH_COMMAND(RemoveCel)
FOR_EACH_COMMAND(RemoveFrame)
FOR_EACH_COMMAND(RemoveLayer)
FOR_EACH_COMMAND(RepeatLastExport)
FOR_EACH_COMMAND(ReplaceColor)
FOR_EACH_COMMAND(ReselectMask)
FOR_EACH_COMMAND(RotateCanvas)

View File

@ -98,6 +98,17 @@ namespace app {
void addSprite(Sprite* sprite);
//////////////////////////////////////////////////////////////////////
// Export data
doc::ExportDataPtr exportData() const {
return m_document.exportData();
}
void setExportData(const doc::ExportDataPtr& data) {
return m_document.setExportData(data);
}
//////////////////////////////////////////////////////////////////////
// Notifications

View File

@ -10,6 +10,8 @@
#include "doc/document.h"
#include "doc/export_data.h"
namespace doc {
Document::Document()
@ -21,4 +23,9 @@ void Document::setFilename(const std::string& filename)
m_filename = filename;
}
void Document::setExportData(const ExportDataPtr& data)
{
m_exportData = data;
}
} // namespace doc

View File

@ -10,21 +10,28 @@
#include <string>
#include "doc/object.h"
#include "doc/export_data.h"
namespace doc {
class ExportData;
class Document : public Object {
public:
Document();
const std::string& filename() const { return m_filename; }
ExportDataPtr exportData() const { return m_exportData; }
void setFilename(const std::string& filename);
void setExportData(const ExportDataPtr& data);
private:
// Document's file name. From where it was loaded, where it is
// saved.
std::string m_filename;
ExportDataPtr m_exportData;
};
} // namespace doc

48
src/doc/export_data.h Normal file
View File

@ -0,0 +1,48 @@
// Aseprite Document Library
// Copyright (c) 2014 David Capello
//
// This source file is distributed under the terms of the MIT license,
// please read LICENSE.txt for more information.
#ifndef DOC_EXPORT_DATA_H_INCLUDED
#define DOC_EXPORT_DATA_H_INCLUDED
#include "base/shared_ptr.h"
#include "gfx/rect.h"
#include <string>
namespace doc {
class ExportData {
public:
enum Type {
None,
HorizontalStrip,
VerticalStrip,
Matrix
};
ExportData() : m_type(None) {
}
Type type() const { return m_type; }
int columns() const { return m_columns; }
const std::string& filename() const { return m_filename; }
void setType(Type type) { m_type = type; }
void setColumns(int columns) { m_columns = columns; }
void setFilename(const std::string& filename) {
m_filename = filename;
}
private:
Type m_type;
int m_columns;
std::string m_filename;
};
typedef SharedPtr<ExportData> ExportDataPtr;
} // namespace doc
#endif