Add option to resize the final output of "Save Copy As" command (fix #685)

This commit is contained in:
David Capello 2015-06-03 16:34:27 -03:00
parent c6f2c48d66
commit e0fea708f8
10 changed files with 169 additions and 32 deletions

View File

@ -145,6 +145,10 @@
<option id="opacity_step" type="int" default="28" migrate="Onionskin.OpacityStep" />
<option id="type" type="OnionskinType" default="OnionskinType::MERGE" migrate="Onionskin.Type" />
</section>
<section id="save_copy">
<option id="filename" type="std::string" />
<option id="resize_scale" type="double" default="1" />
</section>
<section id="sprite_sheet">
<option id="type" type="SpriteSheetType" default="SpriteSheetType::NONE" />
<option id="columns" type="int" default="0" />

View File

@ -20,6 +20,23 @@
<label text="File type:" />
<hbox cell_align="horizontal">
<combobox id="file_type" minwidth="70" />
<hbox id="resize_options">
<label text="Resize:" />
<combobox id="resize">
<listitem text="25%" value="0.25" />
<listitem text="50%" value="0.5" />
<listitem text="100%" value="1" />
<listitem text="200%" value="2" />
<listitem text="300%" value="3" />
<listitem text="400%" value="4" />
<listitem text="500%" value="5" />
<listitem text="600%" value="6" />
<listitem text="700%" value="7" />
<listitem text="800%" value="8" />
<listitem text="900%" value="9" />
<listitem text="1000%" value="10" />
</combobox>
</hbox>
<boxfiller />
<box horizontal="true" homogeneous="true">
<button text="&amp;OK" closewindow="true" id="ok" magnet="true" width="60" />

View File

@ -13,6 +13,7 @@
#include "app/app.h"
#include "app/commands/command.h"
#include "app/commands/commands.h"
#include "app/commands/params.h"
#include "app/console.h"
#include "app/context_access.h"
@ -20,9 +21,11 @@
#include "app/file_selector.h"
#include "app/job.h"
#include "app/modules/gui.h"
#include "app/pref/preferences.h"
#include "app/recent_files.h"
#include "app/ui/status_bar.h"
#include "base/bind.h"
#include "base/convert_to.h"
#include "base/fs.h"
#include "base/path.h"
#include "base/thread.h"
@ -32,6 +35,28 @@
namespace app {
class SaveAsCopyDelegate : public FileSelectorDelegate {
public:
SaveAsCopyDelegate(const app::Document* doc, double scale)
: m_doc(doc), m_resizeScale(scale) { }
bool hasResizeCombobox() override {
return true;
}
double getResizeScale() override {
return m_resizeScale;
}
void setResizeScale(double scale) override {
m_resizeScale = scale;
}
private:
const app::Document* m_doc;
double m_resizeScale;
};
class SaveFileJob : public Job, public IFileOpProgress {
public:
SaveFileJob(FileOp* fop)
@ -125,11 +150,19 @@ bool SaveFileBaseCommand::onEnabled(Context* context)
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable);
}
void SaveFileBaseCommand::saveAsDialog(const ContextReader& reader, const char* dlgTitle, bool markAsSaved)
bool SaveFileBaseCommand::saveAsDialog(Context* context,
const char* dlgTitle,
FileSelectorDelegate* delegate)
{
const Document* document = reader.document();
const Document* document = context->activeDocument();
std::string filename;
// If there is a delegate, we're doing a "Save Copy As", so we don't
// have to mark the file as saved.
bool saveCopyAs = (delegate != nullptr);
bool markAsSaved = (!saveCopyAs);
double scale = 1.0;
if (!m_filename.empty()) {
filename = m_filename;
}
@ -138,16 +171,23 @@ void SaveFileBaseCommand::saveAsDialog(const ContextReader& reader, const char*
filename = document->filename();
std::string newfilename = app::show_file_selector(
dlgTitle, filename, exts, FileSelectorType::Save);
dlgTitle, filename, exts,
FileSelectorType::Save,
delegate);
if (newfilename.empty())
return;
return false;
filename = newfilename;
if (delegate &&
delegate->hasResizeCombobox()) {
scale = delegate->getResizeScale();
}
}
std::string oldFilename;
{
ContextWriter writer(reader);
ContextWriter writer(context);
Document* documentWriter = writer.document();
oldFilename = documentWriter->filename();
@ -156,20 +196,53 @@ void SaveFileBaseCommand::saveAsDialog(const ContextReader& reader, const char*
m_selectedFilename = filename;
}
// Apply scale
bool undoResize = false;
if (scale != 1.0) {
Command* resizeCmd = CommandsModule::instance()->getCommandByName(CommandId::SpriteSize);
ASSERT(resizeCmd);
if (resizeCmd) {
int width = document->sprite()->width();
int height = document->sprite()->height();
int newWidth = int(double(width) * scale);
int newHeight = int(double(height) * scale);
if (newWidth < 1) newWidth = 1;
if (newHeight < 1) newHeight = 1;
if (width != newWidth || height != newHeight) {
Params params;
params.set("use-ui", "false");
params.set("width", base::convert_to<std::string>(newWidth).c_str());
params.set("height", base::convert_to<std::string>(newHeight).c_str());
params.set("resize-method", "nearest-neighbor"); // TODO add algorithm in the UI?
context->executeCommand(resizeCmd, params);
undoResize = true;
}
}
}
// Save the document
save_document_in_background(
reader.context(), const_cast<Document*>(document),
context, const_cast<Document*>(document),
markAsSaved, m_filenameFormat);
// Undo resize
if (undoResize) {
Command* undoCmd = CommandsModule::instance()->getCommandByName(CommandId::Undo);
if (undoCmd)
context->executeCommand(undoCmd);
}
{
ContextWriter writer(reader);
ContextWriter writer(context);
Document* documentWriter = writer.document();
if (documentWriter->isModified())
if (document->isModified())
documentWriter->setFilename(oldFilename);
else
documentWriter->incrementVersion();
}
return true;
}
//////////////////////////////////////////////////////////////////////
@ -192,23 +265,23 @@ SaveFileCommand::SaveFileCommand()
// [main thread]
void SaveFileCommand::onExecute(Context* context)
{
const ContextReader reader(context);
const Document* document(reader.document());
Document* document = context->activeDocument();
// If the document is associated to a file in the file-system, we can
// save it directly without user interaction.
if (document->isAssociatedToFile()) {
ContextWriter writer(reader);
ContextWriter writer(context);
Document* documentWriter = writer.document();
save_document_in_background(context, documentWriter, true,
save_document_in_background(
context, documentWriter, true,
m_filenameFormat.c_str());
}
// If the document isn't associated to a file, we must to show the
// save-as dialog to the user to select for first time the file-name
// for this document.
else {
saveAsDialog(reader, "Save File", true);
saveAsDialog(context, "Save File");
}
}
@ -228,8 +301,7 @@ SaveFileAsCommand::SaveFileAsCommand()
void SaveFileAsCommand::onExecute(Context* context)
{
const ContextReader reader(context);
saveAsDialog(reader, "Save As", true);
saveAsDialog(context, "Save As");
}
class SaveFileCopyAsCommand : public SaveFileBaseCommand {
@ -248,17 +320,29 @@ SaveFileCopyAsCommand::SaveFileCopyAsCommand()
void SaveFileCopyAsCommand::onExecute(Context* context)
{
const ContextReader reader(context);
const Document* document(reader.document());
std::string old_filename = document->filename();
const Document* document = context->activeDocument();
std::string oldFilename = document->filename();
// show "Save As" dialog
saveAsDialog(reader, "Save Copy As", false);
DocumentPreferences& docPref = Preferences::instance().document(document);
SaveAsCopyDelegate delegate(document, docPref.saveCopy.resizeScale());
// Is a default output filename in the preferences?
if (!docPref.saveCopy.filename().empty()) {
ContextWriter writer(context);
writer.document()->setFilename(
docPref.saveCopy.filename());
}
if (saveAsDialog(context, "Save Copy As", &delegate)) {
docPref.saveCopy.filename(document->filename());
docPref.saveCopy.resizeScale(delegate.getResizeScale());
}
// Restore the file name.
{
ContextWriter writer(reader);
writer.document()->setFilename(old_filename.c_str());
ContextWriter writer(context);
writer.document()->setFilename(oldFilename.c_str());
}
}

View File

@ -14,7 +14,7 @@
#include <string>
namespace app {
class ContextReader;
class FileSelectorDelegate;
class SaveFileBaseCommand : public Command {
public:
@ -28,7 +28,8 @@ namespace app {
void onLoadParams(const Params& params) override;
bool onEnabled(Context* context) override;
void saveAsDialog(const ContextReader& reader, const char* dlgTitle, bool markAsSaved);
bool saveAsDialog(Context* context, const char* dlgTitle,
FileSelectorDelegate* delegate = nullptr);
std::string m_filename;
std::string m_filenameFormat;

View File

@ -155,6 +155,7 @@ SpriteSizeCommand::SpriteSizeCommand()
"Sprite Size",
CmdRecordableFlag)
{
m_useUI = true;
m_width = 0;
m_height = 0;
m_scaleX = 1.0;
@ -169,6 +170,9 @@ Command* SpriteSizeCommand::clone() const
void SpriteSizeCommand::onLoadParams(const Params& params)
{
std::string useUI = params.get("use-ui");
m_useUI = (useUI.empty() || (useUI == "true"));
std::string width = params.get("width");
if (!width.empty()) {
m_width = std::strtol(width.c_str(), NULL, 10);
@ -208,7 +212,7 @@ void SpriteSizeCommand::onExecute(Context* context)
int new_height = (m_height ? m_height: int(sprite->height()*m_scaleY));
ResizeMethod resize_method = m_resizeMethod;
if (context->isUIAvailable()) {
if (m_useUI && context->isUIAvailable()) {
// load the window widget
base::UniquePtr<Window> window(app::load_widget<Window>("sprite_size.xml", "sprite_size"));
m_widthPx = app::find_widget<Entry>(window, "width_px");

View File

@ -49,6 +49,7 @@ namespace app {
ui::Entry* m_widthPerc;
ui::Entry* m_heightPerc;
bool m_useUI;
int m_width;
int m_height;
double m_scaleX;

View File

@ -21,10 +21,12 @@
namespace app {
std::string show_file_selector(const std::string& title,
std::string show_file_selector(
const std::string& title,
const std::string& initialPath,
const std::string& showExtensions,
FileSelectorType type)
FileSelectorType type,
FileSelectorDelegate* delegate)
{
if (Preferences::instance().experimental.useNativeFileDialog() &&
she::instance()->nativeDialogs()) {
@ -55,7 +57,7 @@ std::string show_file_selector(const std::string& title,
}
}
FileSelector fileSelector(type);
FileSelector fileSelector(type, delegate);
return fileSelector.show(title, initialPath, showExtensions);
}

View File

@ -15,11 +15,20 @@ namespace app {
enum class FileSelectorType { Open, Save };
class FileSelectorDelegate {
public:
virtual ~FileSelectorDelegate() { }
virtual bool hasResizeCombobox() = 0;
virtual double getResizeScale() = 0;
virtual void setResizeScale(double scale) = 0;
};
std::string show_file_selector(
const std::string& title,
const std::string& initialPath,
const std::string& showExtensions,
FileSelectorType type);
FileSelectorType type,
FileSelectorDelegate* delegate = nullptr);
} // namespace app

View File

@ -24,6 +24,7 @@
#include "app/ui/skin/skin_parts.h"
#include "app/widget_loader.h"
#include "base/bind.h"
#include "base/convert_to.h"
#include "base/fs.h"
#include "base/path.h"
#include "base/split_string.h"
@ -233,10 +234,13 @@ private:
FileSelector* m_filesel;
};
FileSelector::FileSelector(FileSelectorType type)
FileSelector::FileSelector(FileSelectorType type, FileSelectorDelegate* delegate)
: m_type(type)
, m_delegate(delegate)
, m_navigationLocked(false)
{
bool withResizeOptions = (delegate && delegate->hasResizeCombobox());
addChild(new ArrowNavigator(this));
m_fileName = new CustomFileNameEntry;
@ -288,6 +292,12 @@ FileSelector::FileSelector(FileSelectorType type)
m_fileList->FileSelected.connect(Bind<void>(&FileSelector::onFileListFileSelected, this));
m_fileList->FileAccepted.connect(Bind<void>(&FileSelector::onFileListFileAccepted, this));
m_fileList->CurrentFolderChanged.connect(Bind<void>(&FileSelector::onFileListCurrentFolderChanged, this));
resizeOptions()->setVisible(withResizeOptions);
if (withResizeOptions) {
resize()->setValue("1"); // 100% is default
resize()->setValue(base::convert_to<std::string>(m_delegate->getResizeScale()));
}
}
void FileSelector::goBack()
@ -570,6 +580,10 @@ again:
std::string lastpath = folder->getKeyName();
set_config_string("FileSelect", "CurrentDirectory",
lastpath.c_str());
if (m_delegate && m_delegate->hasResizeCombobox()) {
m_delegate->setResizeScale(base::convert_to<double>(resize()->getValue()));
}
}
return result;

View File

@ -30,7 +30,7 @@ namespace app {
class FileSelector : public app::gen::FileSelector {
public:
FileSelector(FileSelectorType type);
FileSelector(FileSelectorType type, FileSelectorDelegate* delegate);
void goBack();
void goForward();
@ -58,6 +58,7 @@ namespace app {
std::string getSelectedExtension() const;
FileSelectorType m_type;
FileSelectorDelegate* m_delegate;
std::string m_defExtension;
CustomFileNameEntry* m_fileName;
FileList* m_fileList;