mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-29 21:33:12 +00:00
Add a special dialog for File > Export command
With this change we have moved all the file selector customization to a new special FileExportWindow. So the file selector is used only to select the output file (no more FileSelectorDelegate = now we can use the native file selector for File > Export).
This commit is contained in:
parent
10590da7c1
commit
8014c828af
@ -449,6 +449,16 @@ duplicate = Duplicate:
|
||||
as = As:
|
||||
merged_layers = Duplicate merged layers only
|
||||
|
||||
[export_file]
|
||||
title = Export File
|
||||
output_file = Output File:
|
||||
resize = Resize:
|
||||
layers = Layers:
|
||||
frames = Frames:
|
||||
pixel_ratio = Apply pixel ratio
|
||||
export = &Export
|
||||
cancel = &Cancel
|
||||
|
||||
[export_sprite_sheet]
|
||||
title = Export Sprite Sheet
|
||||
sheet_type = Sheet Type:
|
||||
@ -483,15 +493,6 @@ go_up_button_tooltip = Up to parent folder
|
||||
new_folder_button_tooltip = New folder
|
||||
file_name = File name:
|
||||
file_type = File type:
|
||||
resize = Resize:
|
||||
layeres = Layers:
|
||||
frames = Frames:
|
||||
|
||||
[file_selector_extras]
|
||||
resize = Resize:
|
||||
layers = Layers:
|
||||
frames = Frames:
|
||||
pixel_ratio = Apply pixel ratio
|
||||
|
||||
[font_popup]
|
||||
load = Load
|
||||
|
42
data/widgets/export_file.xml
Normal file
42
data/widgets/export_file.xml
Normal file
@ -0,0 +1,42 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2016-2018 by David Capello -->
|
||||
<gui>
|
||||
<window id="export_file" text="@.title">
|
||||
<grid columns="2">
|
||||
<label text="@.output_file" />
|
||||
<button id="output_filename" cell_align="horizontal" maxwidth="256" />
|
||||
|
||||
<label id="resize_label" text="@.resize" />
|
||||
<combobox id="resize" cell_align="horizontal">
|
||||
<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>
|
||||
|
||||
<label id="layers_label" text="@.layers" />
|
||||
<combobox id="layers" text="" cell_align="horizontal" />
|
||||
|
||||
<label id="frames_label" text="@.frames" />
|
||||
<combobox id="frames" text="" cell_align="horizontal" />
|
||||
|
||||
<check id="pixel_ratio" text="@.pixel_ratio" cell_hspan="2" />
|
||||
|
||||
<hbox cell_hspan="2">
|
||||
<boxfiller />
|
||||
<hbox homogeneous="true">
|
||||
<button text="@.export" minwidth="60" closewindow="true" id="ok" magnet="true" />
|
||||
<button text="@.cancel" minwidth="60" closewindow="true" />
|
||||
</hbox>
|
||||
</hbox>
|
||||
</grid>
|
||||
</window>
|
||||
</gui>
|
@ -1,5 +1,5 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2001-2017 by David Capello -->
|
||||
<!-- Copyright (C) 2001-2018 by David Capello -->
|
||||
<gui>
|
||||
<window id="file_selector" text="">
|
||||
<vbox id="main">
|
||||
@ -20,11 +20,6 @@
|
||||
<label text="@.file_type" />
|
||||
<hbox cell_align="horizontal">
|
||||
<combobox id="file_type" minwidth="70" />
|
||||
<vbox>
|
||||
<boxfiller />
|
||||
<link id="extra_options" text="" />
|
||||
<boxfiller />
|
||||
</vbox>
|
||||
<boxfiller />
|
||||
<box horizontal="true" homogeneous="true">
|
||||
<button text="@general.ok" closewindow="true" id="ok" magnet="true" width="60" />
|
||||
|
@ -1,31 +0,0 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2016-2017 by David Capello -->
|
||||
<gui>
|
||||
<vbox id="file_selector_extras">
|
||||
<grid columns="2">
|
||||
<label id="resize_label" text="@.resize" />
|
||||
<combobox id="resize" cell_align="horizontal">
|
||||
<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>
|
||||
|
||||
<label id="layers_label" text="@.layers" />
|
||||
<combobox id="layers" text="" cell_align="horizontal" />
|
||||
|
||||
<label id="frames_label" text="@.frames" />
|
||||
<combobox id="frames" text="" cell_align="horizontal" />
|
||||
|
||||
<check id="pixel_ratio" text="@.pixel_ratio" cell_hspan="2" />
|
||||
</grid>
|
||||
</vbox>
|
||||
</gui>
|
@ -480,6 +480,7 @@ add_library(app-lib
|
||||
ui/editor/tool_loop_impl.cpp
|
||||
ui/editor/transform_handles.cpp
|
||||
ui/editor/zooming_state.cpp
|
||||
ui/export_file_window.cpp
|
||||
ui/file_list.cpp
|
||||
ui/file_list_view.cpp
|
||||
ui/file_selector.cpp
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "app/pref/preferences.h"
|
||||
#include "app/recent_files.h"
|
||||
#include "app/restore_visible_layers.h"
|
||||
#include "app/ui/export_file_window.h"
|
||||
#include "app/ui/layer_frame_comboboxes.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "base/bind.h"
|
||||
@ -37,70 +38,6 @@
|
||||
|
||||
namespace app {
|
||||
|
||||
class SaveAsCopyDelegate : public FileSelectorDelegate {
|
||||
public:
|
||||
SaveAsCopyDelegate(const Sprite* sprite,
|
||||
const double scale,
|
||||
const std::string& layer,
|
||||
const std::string& frame,
|
||||
const bool applyPixelRatio)
|
||||
: m_sprite(sprite),
|
||||
m_resizeScale(scale),
|
||||
m_layer(layer),
|
||||
m_frame(frame),
|
||||
m_applyPixelRatio(applyPixelRatio) { }
|
||||
|
||||
bool hasResizeCombobox() override {
|
||||
return true;
|
||||
}
|
||||
|
||||
double getResizeScale() override {
|
||||
return m_resizeScale;
|
||||
}
|
||||
|
||||
void setResizeScale(double scale) override {
|
||||
m_resizeScale = scale;
|
||||
}
|
||||
|
||||
void fillLayersComboBox(ui::ComboBox* layers) override {
|
||||
fill_layers_combobox(m_sprite, layers, m_layer);
|
||||
}
|
||||
|
||||
void fillFramesComboBox(ui::ComboBox* frames) override {
|
||||
fill_frames_combobox(m_sprite, frames, m_frame);
|
||||
}
|
||||
|
||||
std::string getLayers() override { return m_layer; }
|
||||
std::string getFrames() override { return m_frame; }
|
||||
|
||||
void setLayers(const std::string& layer) override {
|
||||
m_layer = layer;
|
||||
}
|
||||
|
||||
void setFrames(const std::string& frame) override {
|
||||
m_frame = frame;
|
||||
}
|
||||
|
||||
void setApplyPixelRatio(bool applyPixelRatio) override {
|
||||
m_applyPixelRatio = applyPixelRatio;
|
||||
}
|
||||
|
||||
bool applyPixelRatio() const override {
|
||||
return m_applyPixelRatio;
|
||||
}
|
||||
|
||||
doc::PixelRatio pixelRatio() override {
|
||||
return m_sprite->pixelRatio();
|
||||
}
|
||||
|
||||
private:
|
||||
const Sprite* m_sprite;
|
||||
double m_resizeScale;
|
||||
std::string m_layer;
|
||||
std::string m_frame;
|
||||
bool m_applyPixelRatio;
|
||||
};
|
||||
|
||||
class SaveFileJob : public Job, public IFileOpProgress {
|
||||
public:
|
||||
SaveFileJob(FileOp* fop)
|
||||
@ -173,36 +110,31 @@ bool SaveFileBaseCommand::onEnabled(Context* context)
|
||||
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable);
|
||||
}
|
||||
|
||||
bool SaveFileBaseCommand::saveAsDialog(
|
||||
std::string SaveFileBaseCommand::saveAsDialog(
|
||||
Context* context,
|
||||
const std::string& dlgTitle,
|
||||
const std::string& forbiddenFilename,
|
||||
FileSelectorDelegate* delegate)
|
||||
const std::string& initialFilename,
|
||||
const bool markAsSaved,
|
||||
const bool saveInBackground,
|
||||
const std::string& forbiddenFilename)
|
||||
{
|
||||
const Document* document = context->activeDocument();
|
||||
Document* document = context->activeDocument();
|
||||
std::string filename;
|
||||
|
||||
// If there is a delegate, we're doing a "Save Copy As/Export", so we don't
|
||||
// have to mark the file as saved.
|
||||
const bool isExport = (delegate != nullptr);
|
||||
const bool markAsSaved = (!isExport);
|
||||
double xscale = 1.0;
|
||||
double yscale = 1.0;
|
||||
|
||||
if (!m_filename.empty()) {
|
||||
filename = m_filename;
|
||||
}
|
||||
else {
|
||||
base::paths exts = get_writable_extensions();
|
||||
filename = document->filename();
|
||||
filename = initialFilename;
|
||||
|
||||
again:;
|
||||
base::paths newfilename;
|
||||
if (!app::show_file_selector(
|
||||
dlgTitle, filename, exts,
|
||||
FileSelectorType::Save, newfilename,
|
||||
delegate))
|
||||
return false;
|
||||
FileSelectorType::Save,
|
||||
newfilename))
|
||||
return std::string();
|
||||
|
||||
filename = newfilename.front();
|
||||
if (!forbiddenFilename.empty() &&
|
||||
@ -211,110 +143,29 @@ bool SaveFileBaseCommand::saveAsDialog(
|
||||
ui::Alert::show(Strings::alerts_cannot_file_overwrite_on_export());
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (delegate &&
|
||||
delegate->hasResizeCombobox()) {
|
||||
xscale = yscale = delegate->getResizeScale();
|
||||
}
|
||||
}
|
||||
|
||||
std::string oldFilename;
|
||||
{
|
||||
ContextWriter writer(context);
|
||||
Document* documentWriter = writer.document();
|
||||
oldFilename = documentWriter->filename();
|
||||
|
||||
// Change the document file name
|
||||
documentWriter->setFilename(filename.c_str());
|
||||
m_selectedFilename = filename;
|
||||
if (saveInBackground) {
|
||||
saveDocumentInBackground(
|
||||
context, document,
|
||||
filename, markAsSaved);
|
||||
}
|
||||
|
||||
// Pixel ratio
|
||||
if (delegate &&
|
||||
delegate->applyPixelRatio()) {
|
||||
doc::PixelRatio pr = delegate->pixelRatio();
|
||||
xscale *= pr.w;
|
||||
yscale *= pr.h;
|
||||
}
|
||||
|
||||
// Apply scale
|
||||
bool undoResize = false;
|
||||
if (xscale != 1.0 || yscale != 1.0) {
|
||||
Command* resizeCmd = Commands::instance()->byId(CommandId::SpriteSize());
|
||||
ASSERT(resizeCmd);
|
||||
if (resizeCmd) {
|
||||
int width = document->sprite()->width();
|
||||
int height = document->sprite()->height();
|
||||
int newWidth = int(double(width) * xscale);
|
||||
int newHeight = int(double(height) * yscale);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
RestoreVisibleLayers layersVisibility;
|
||||
if (delegate) {
|
||||
Site site = context->activeSite();
|
||||
|
||||
// Selected layers to export
|
||||
calculate_visible_layers(site,
|
||||
delegate->getLayers(),
|
||||
layersVisibility);
|
||||
|
||||
// Selected frames to export
|
||||
SelectedFrames selFrames;
|
||||
FrameTag* frameTag = calculate_selected_frames(
|
||||
site, delegate->getFrames(), selFrames);
|
||||
if (frameTag)
|
||||
m_frameTag = frameTag->name();
|
||||
m_selFrames = selFrames;
|
||||
m_adjustFramesByFrameTag = false;
|
||||
}
|
||||
|
||||
// Save the document
|
||||
saveDocumentInBackground(context, const_cast<Document*>(document), markAsSaved);
|
||||
}
|
||||
|
||||
// Undo resize
|
||||
if (undoResize) {
|
||||
Command* undoCmd = Commands::instance()->byId(CommandId::Undo());
|
||||
if (undoCmd)
|
||||
context->executeCommand(undoCmd);
|
||||
}
|
||||
|
||||
{
|
||||
ContextWriter writer(context);
|
||||
Document* documentWriter = writer.document();
|
||||
|
||||
if (document->isModified())
|
||||
documentWriter->setFilename(oldFilename);
|
||||
else
|
||||
documentWriter->incrementVersion();
|
||||
}
|
||||
|
||||
return true;
|
||||
return filename;
|
||||
}
|
||||
|
||||
void SaveFileBaseCommand::saveDocumentInBackground(const Context* context,
|
||||
const app::Document* document,
|
||||
bool markAsSaved) const
|
||||
void SaveFileBaseCommand::saveDocumentInBackground(
|
||||
const Context* context,
|
||||
app::Document* document,
|
||||
const std::string& filename,
|
||||
const bool markAsSaved) const
|
||||
{
|
||||
base::UniquePtr<FileOp> fop(
|
||||
FileOp::createSaveDocumentOperation(
|
||||
context,
|
||||
FileOpROI(document, m_slice, m_frameTag,
|
||||
m_selFrames, m_adjustFramesByFrameTag),
|
||||
document->filename(),
|
||||
filename,
|
||||
m_filenameFormat));
|
||||
if (!fop)
|
||||
return;
|
||||
@ -328,20 +179,22 @@ void SaveFileBaseCommand::saveDocumentInBackground(const Context* context,
|
||||
|
||||
// We don't know if the file was saved correctly or not. So mark
|
||||
// it as it should be saved again.
|
||||
const_cast<Document*>(document)->impossibleToBackToSavedState();
|
||||
document->impossibleToBackToSavedState();
|
||||
}
|
||||
// If the job was cancelled, mark the document as modified.
|
||||
else if (fop->isStop()) {
|
||||
const_cast<Document*>(document)->impossibleToBackToSavedState();
|
||||
document->impossibleToBackToSavedState();
|
||||
}
|
||||
else if (context->isUIAvailable()) {
|
||||
App::instance()->recentFiles()->addRecentFile(document->filename().c_str());
|
||||
if (markAsSaved)
|
||||
const_cast<Document*>(document)->markAsSaved();
|
||||
|
||||
App::instance()->recentFiles()->addRecentFile(filename);
|
||||
if (markAsSaved) {
|
||||
document->markAsSaved();
|
||||
document->setFilename(filename);
|
||||
document->incrementVersion();
|
||||
}
|
||||
StatusBar::instance()
|
||||
->setStatusText(2000, "File %s, saved.",
|
||||
document->name().c_str());
|
||||
->setStatusText(2000, "File <%s> saved.",
|
||||
base::get_file_name(filename).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,13 +226,16 @@ void SaveFileCommand::onExecute(Context* context)
|
||||
const ContextReader reader(context);
|
||||
const Document* documentReader = reader.document();
|
||||
|
||||
saveDocumentInBackground(context, documentReader, true);
|
||||
saveDocumentInBackground(
|
||||
context, document,
|
||||
documentReader->filename(), true);
|
||||
}
|
||||
// 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(context, "Save File");
|
||||
saveAsDialog(context, "Save File",
|
||||
document->filename(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -399,7 +255,9 @@ SaveFileAsCommand::SaveFileAsCommand()
|
||||
|
||||
void SaveFileAsCommand::onExecute(Context* context)
|
||||
{
|
||||
saveAsDialog(context, "Save As");
|
||||
Document* document = context->activeDocument();
|
||||
saveAsDialog(context, "Save As",
|
||||
document->filename(), true);
|
||||
}
|
||||
|
||||
class SaveFileCopyAsCommand : public SaveFileBaseCommand {
|
||||
@ -418,46 +276,86 @@ SaveFileCopyAsCommand::SaveFileCopyAsCommand()
|
||||
|
||||
void SaveFileCopyAsCommand::onExecute(Context* context)
|
||||
{
|
||||
const Document* document = context->activeDocument();
|
||||
std::string oldFilename = document->filename();
|
||||
Document* doc = context->activeDocument();
|
||||
ExportFileWindow win(doc);
|
||||
|
||||
// show "Save As" dialog
|
||||
DocumentPreferences& docPref = Preferences::instance().document(document);
|
||||
win.SelectOutputFile.connect(
|
||||
[this, &win, context, doc]{
|
||||
return saveAsDialog(
|
||||
context, "Export",
|
||||
win.outputFilenameValue(), false, false,
|
||||
(doc->isAssociatedToFile() ? doc->filename():
|
||||
std::string()));
|
||||
});
|
||||
|
||||
base::UniquePtr<SaveAsCopyDelegate> delegate;
|
||||
if (context->isUIAvailable()) {
|
||||
delegate.reset(
|
||||
new SaveAsCopyDelegate(
|
||||
document->sprite(),
|
||||
docPref.saveCopy.resizeScale(),
|
||||
docPref.saveCopy.layer(),
|
||||
docPref.saveCopy.frameTag(),
|
||||
docPref.saveCopy.applyPixelRatio()));
|
||||
if (!win.show())
|
||||
return;
|
||||
|
||||
// Save the preferences used to export the file, so if we open the
|
||||
// window again, we will have the same options.
|
||||
win.savePref();
|
||||
|
||||
double xscale, yscale;
|
||||
xscale = yscale = win.resizeValue();
|
||||
|
||||
// Pixel ratio
|
||||
if (win.applyPixelRatio()) {
|
||||
doc::PixelRatio pr = doc->sprite()->pixelRatio();
|
||||
xscale *= pr.w;
|
||||
yscale *= pr.h;
|
||||
}
|
||||
|
||||
// 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, "Export",
|
||||
(document->isAssociatedToFile() ? oldFilename: std::string()),
|
||||
delegate)) {
|
||||
docPref.saveCopy.filename(document->filename());
|
||||
if (delegate) {
|
||||
docPref.saveCopy.resizeScale(delegate->getResizeScale());
|
||||
docPref.saveCopy.layer(delegate->getLayers());
|
||||
docPref.saveCopy.frameTag(delegate->getFrames());
|
||||
docPref.saveCopy.applyPixelRatio(delegate->applyPixelRatio());
|
||||
// Apply scale
|
||||
bool undoResize = false;
|
||||
if (xscale != 1.0 || yscale != 1.0) {
|
||||
Command* resizeCmd = Commands::instance()->byId(CommandId::SpriteSize());
|
||||
ASSERT(resizeCmd);
|
||||
if (resizeCmd) {
|
||||
int width = doc->sprite()->width();
|
||||
int height = doc->sprite()->height();
|
||||
int newWidth = int(double(width) * xscale);
|
||||
int newHeight = int(double(height) * yscale);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the file name.
|
||||
{
|
||||
ContextWriter writer(context);
|
||||
writer.document()->setFilename(oldFilename.c_str());
|
||||
RestoreVisibleLayers layersVisibility;
|
||||
Site site = context->activeSite();
|
||||
|
||||
// Selected layers to export
|
||||
calculate_visible_layers(site,
|
||||
win.layersValue(),
|
||||
layersVisibility);
|
||||
|
||||
// Selected frames to export
|
||||
SelectedFrames selFrames;
|
||||
FrameTag* frameTag = calculate_selected_frames(
|
||||
site, win.framesValue(), selFrames);
|
||||
if (frameTag)
|
||||
m_frameTag = frameTag->name();
|
||||
m_selFrames = selFrames;
|
||||
m_adjustFramesByFrameTag = false;
|
||||
|
||||
saveDocumentInBackground(
|
||||
context, doc, win.outputFilenameValue(), false);
|
||||
}
|
||||
|
||||
// Undo resize
|
||||
if (undoResize) {
|
||||
Command* undoCmd = Commands::instance()->byId(CommandId::Undo());
|
||||
if (undoCmd)
|
||||
context->executeCommand(undoCmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -15,31 +15,30 @@
|
||||
|
||||
namespace app {
|
||||
class Document;
|
||||
class FileSelectorDelegate;
|
||||
|
||||
class SaveFileBaseCommand : public Command {
|
||||
public:
|
||||
SaveFileBaseCommand(const char* id, CommandFlags flags);
|
||||
|
||||
std::string selectedFilename() const {
|
||||
return m_selectedFilename;
|
||||
}
|
||||
|
||||
protected:
|
||||
void onLoadParams(const Params& params) override;
|
||||
bool onEnabled(Context* context) override;
|
||||
|
||||
bool saveAsDialog(Context* context,
|
||||
const std::string& dlgTitle,
|
||||
const std::string& forbiddenFilename = std::string(),
|
||||
FileSelectorDelegate* delegate = nullptr);
|
||||
void saveDocumentInBackground(const Context* context,
|
||||
const app::Document* document,
|
||||
bool markAsSaved) const;
|
||||
std::string saveAsDialog(
|
||||
Context* context,
|
||||
const std::string& dlgTitle,
|
||||
const std::string& filename,
|
||||
const bool markAsSaved,
|
||||
const bool saveInBackground = true,
|
||||
const std::string& forbiddenFilename = std::string());
|
||||
void saveDocumentInBackground(
|
||||
const Context* context,
|
||||
app::Document* document,
|
||||
const std::string& filename,
|
||||
const bool markAsSaved) const;
|
||||
|
||||
std::string m_filename;
|
||||
std::string m_filenameFormat;
|
||||
std::string m_selectedFilename;
|
||||
std::string m_frameTag;
|
||||
std::string m_slice;
|
||||
doc::SelectedFrames m_selFrames;
|
||||
|
@ -24,8 +24,7 @@ bool show_file_selector(
|
||||
const std::string& initialPath,
|
||||
const base::paths& extensions,
|
||||
FileSelectorType type,
|
||||
base::paths& output,
|
||||
FileSelectorDelegate* delegate)
|
||||
base::paths& output)
|
||||
{
|
||||
const std::string defExtension =
|
||||
Preferences::instance().saveFile.defaultExtension();
|
||||
@ -71,7 +70,7 @@ bool show_file_selector(
|
||||
}
|
||||
}
|
||||
|
||||
FileSelector fileSelector(type, delegate);
|
||||
FileSelector fileSelector(type);
|
||||
|
||||
if (!defExtension.empty())
|
||||
fileSelector.setDefaultExtension(defExtension);
|
||||
|
@ -21,34 +21,12 @@ namespace app {
|
||||
|
||||
enum class FileSelectorType { Open, OpenMultiple, Save };
|
||||
|
||||
class FileSelectorDelegate {
|
||||
public:
|
||||
virtual ~FileSelectorDelegate() { }
|
||||
virtual bool hasResizeCombobox() = 0;
|
||||
virtual double getResizeScale() = 0;
|
||||
virtual void setResizeScale(double scale) = 0;
|
||||
|
||||
// TODO refactor this to avoid using a ui::ComboBox,
|
||||
// mainly to re-use this in the native file selector
|
||||
virtual void fillLayersComboBox(ui::ComboBox* layers) = 0;
|
||||
virtual void fillFramesComboBox(ui::ComboBox* frames) = 0;
|
||||
virtual std::string getLayers() = 0;
|
||||
virtual std::string getFrames() = 0;
|
||||
virtual void setLayers(const std::string& layers) = 0;
|
||||
virtual void setFrames(const std::string& frames) = 0;
|
||||
|
||||
virtual void setApplyPixelRatio(bool applyPixelRatio) = 0;
|
||||
virtual bool applyPixelRatio() const = 0;
|
||||
virtual doc::PixelRatio pixelRatio() = 0;
|
||||
};
|
||||
|
||||
bool show_file_selector(
|
||||
const std::string& title,
|
||||
const std::string& initialPath,
|
||||
const base::paths& extensions,
|
||||
FileSelectorType type,
|
||||
base::paths& output,
|
||||
FileSelectorDelegate* delegate = nullptr);
|
||||
base::paths& output);
|
||||
|
||||
} // namespace app
|
||||
|
||||
|
96
src/app/ui/export_file_window.cpp
Normal file
96
src/app/ui/export_file_window.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/ui/export_file_window.h"
|
||||
|
||||
#include "app/document.h"
|
||||
#include "app/ui/layer_frame_comboboxes.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/fs.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
ExportFileWindow::ExportFileWindow(const Document* doc)
|
||||
: m_doc(doc)
|
||||
, m_docPref(Preferences::instance().document(doc))
|
||||
{
|
||||
// Is a default output filename in the preferences?
|
||||
if (!m_docPref.saveCopy.filename().empty()) {
|
||||
outputFilename()->setText(m_docPref.saveCopy.filename());
|
||||
}
|
||||
else {
|
||||
std::string newFn = base::replace_extension(
|
||||
doc->filename(),
|
||||
doc->sprite()->totalFrames() > 1 ? "gif": "png");
|
||||
if (newFn == doc->filename()) {
|
||||
newFn = base::join_path(
|
||||
base::get_file_path(newFn),
|
||||
base::get_file_title(newFn) + "-export." + base::get_file_extension(newFn));
|
||||
}
|
||||
outputFilename()->setText(newFn);
|
||||
}
|
||||
|
||||
// Default export configuration
|
||||
resize()->setValue(
|
||||
base::convert_to<std::string>(m_docPref.saveCopy.resizeScale()));
|
||||
fill_layers_combobox(m_doc->sprite(), layers(), m_docPref.saveCopy.layer());
|
||||
fill_frames_combobox(m_doc->sprite(), frames(), m_docPref.saveCopy.frameTag());
|
||||
pixelRatio()->setSelected(m_docPref.saveCopy.applyPixelRatio());
|
||||
|
||||
outputFilename()->Click.connect(base::Bind<void>(
|
||||
[this]{
|
||||
std::string fn = SelectOutputFile();
|
||||
if (!fn.empty())
|
||||
outputFilename()->setText(fn);
|
||||
}));
|
||||
}
|
||||
|
||||
bool ExportFileWindow::show()
|
||||
{
|
||||
openWindowInForeground();
|
||||
return (closer() == ok());
|
||||
}
|
||||
|
||||
void ExportFileWindow::savePref()
|
||||
{
|
||||
m_docPref.saveCopy.filename(outputFilenameValue());
|
||||
m_docPref.saveCopy.resizeScale(resizeValue());
|
||||
m_docPref.saveCopy.layer(layersValue());
|
||||
m_docPref.saveCopy.frameTag(framesValue());
|
||||
m_docPref.saveCopy.applyPixelRatio(applyPixelRatio());
|
||||
}
|
||||
|
||||
std::string ExportFileWindow::outputFilenameValue() const
|
||||
{
|
||||
return outputFilename()->text();
|
||||
}
|
||||
|
||||
double ExportFileWindow::resizeValue() const
|
||||
{
|
||||
return base::convert_to<double>(resize()->getValue());
|
||||
}
|
||||
|
||||
std::string ExportFileWindow::layersValue() const
|
||||
{
|
||||
return layers()->getValue();
|
||||
}
|
||||
|
||||
std::string ExportFileWindow::framesValue() const
|
||||
{
|
||||
return frames()->getValue();
|
||||
}
|
||||
|
||||
bool ExportFileWindow::applyPixelRatio() const
|
||||
{
|
||||
return pixelRatio()->isSelected();
|
||||
}
|
||||
|
||||
} // namespace app
|
43
src/app/ui/export_file_window.h
Normal file
43
src/app/ui/export_file_window.h
Normal file
@ -0,0 +1,43 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_UI_EXPORT_FILE_WINDOW_H_INCLUDED
|
||||
#define APP_UI_EXPORT_FILE_WINDOW_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/pref/preferences.h"
|
||||
#include "obs/signal.h"
|
||||
|
||||
#include "export_file.xml.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace app {
|
||||
class Document;
|
||||
|
||||
class ExportFileWindow : protected app::gen::ExportFile {
|
||||
public:
|
||||
ExportFileWindow(const Document* doc);
|
||||
|
||||
bool show();
|
||||
void savePref();
|
||||
|
||||
std::string outputFilenameValue() const;
|
||||
double resizeValue() const;
|
||||
std::string layersValue() const;
|
||||
std::string framesValue() const;
|
||||
bool applyPixelRatio() const;
|
||||
|
||||
obs::signal<std::string()> SelectOutputFile;
|
||||
|
||||
private:
|
||||
const Document* m_doc;
|
||||
DocumentPreferences& m_docPref;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -261,90 +261,10 @@ private:
|
||||
FileSelector* m_filesel;
|
||||
};
|
||||
|
||||
class FileSelector::ExtrasWindow : public PopupWindow {
|
||||
public:
|
||||
ExtrasWindow(FileSelectorDelegate* delegate)
|
||||
: PopupWindow("",
|
||||
ClickBehavior::CloseOnClickInOtherWindow,
|
||||
EnterBehavior::CloseOnEnter)
|
||||
, m_delegate(delegate)
|
||||
, m_extras(new gen::FileSelectorExtras) {
|
||||
|
||||
setAutoRemap(false);
|
||||
setBorder(gfx::Border(4*guiscale()));
|
||||
|
||||
addChild(m_extras);
|
||||
m_extras->resize()->setValue(
|
||||
base::convert_to<std::string>(m_delegate->getResizeScale()));
|
||||
m_delegate->fillLayersComboBox(m_extras->layers());
|
||||
m_delegate->fillFramesComboBox(m_extras->frames());
|
||||
m_extras->pixelRatio()->setSelected(m_delegate->applyPixelRatio());
|
||||
|
||||
m_extras->resize()->Change.connect(&ExtrasWindow::onUpdateExtras, this);
|
||||
m_extras->layers()->Change.connect(&ExtrasWindow::onUpdateExtras, this);
|
||||
m_extras->frames()->Change.connect(&ExtrasWindow::onUpdateExtras, this);
|
||||
m_extras->pixelRatio()->Click.connect(base::Bind<void>(&ExtrasWindow::onUpdateExtras, this));
|
||||
}
|
||||
|
||||
std::string extrasLabel() const {
|
||||
std::string label = "Resize: " + m_extras->resize()->getSelectedItem()->text();
|
||||
|
||||
auto layerItem = dynamic_cast<ListItem*>(m_extras->layers()->getSelectedItem());
|
||||
if (layerItem &&
|
||||
!layerItem->getValue().empty())
|
||||
label += ", " + layerItem->text();
|
||||
|
||||
auto frameItem = dynamic_cast<ListItem*>(m_extras->frames()->getSelectedItem());
|
||||
if (frameItem && !frameItem->getValue().empty())
|
||||
label += ", " + frameItem->text();
|
||||
|
||||
if (m_extras->pixelRatio()->isSelected()) {
|
||||
PixelRatio pr = m_delegate->pixelRatio();
|
||||
label += " (";
|
||||
label += base::convert_to<std::string>(pr.w);
|
||||
label += ":";
|
||||
label += base::convert_to<std::string>(pr.h);
|
||||
label += ")";
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
double resizeValue() const {
|
||||
return base::convert_to<double>(m_extras->resize()->getValue());
|
||||
}
|
||||
|
||||
std::string layersValue() const {
|
||||
return m_extras->layers()->getValue();
|
||||
}
|
||||
|
||||
std::string framesValue() const {
|
||||
return m_extras->frames()->getValue();
|
||||
}
|
||||
|
||||
bool applyPixelRatio() const {
|
||||
return m_extras->pixelRatio()->isSelected();
|
||||
}
|
||||
|
||||
obs::signal<void()> UpdateExtras;
|
||||
|
||||
private:
|
||||
void onUpdateExtras() {
|
||||
UpdateExtras();
|
||||
}
|
||||
|
||||
FileSelectorDelegate* m_delegate;
|
||||
gen::FileSelectorExtras* m_extras;
|
||||
};
|
||||
|
||||
FileSelector::FileSelector(FileSelectorType type, FileSelectorDelegate* delegate)
|
||||
FileSelector::FileSelector(FileSelectorType type)
|
||||
: m_type(type)
|
||||
, m_delegate(delegate)
|
||||
, m_extras(nullptr)
|
||||
, m_navigationLocked(false)
|
||||
{
|
||||
bool withResizeOptions = (delegate && delegate->hasResizeCombobox());
|
||||
|
||||
addChild(new ArrowNavigator(this));
|
||||
|
||||
m_fileName = new CustomFileNameEntry;
|
||||
@ -374,15 +294,6 @@ FileSelector::FileSelector(FileSelectorType type, FileSelectorDelegate* delegate
|
||||
m_fileList->FileSelected.connect(base::Bind<void>(&FileSelector::onFileListFileSelected, this));
|
||||
m_fileList->FileAccepted.connect(base::Bind<void>(&FileSelector::onFileListFileAccepted, this));
|
||||
m_fileList->CurrentFolderChanged.connect(base::Bind<void>(&FileSelector::onFileListCurrentFolderChanged, this));
|
||||
|
||||
if (withResizeOptions) {
|
||||
extraOptions()->Click.connect(base::Bind<void>(&FileSelector::onExtraOptions, this));
|
||||
|
||||
m_extras = new ExtrasWindow(m_delegate);
|
||||
m_extras->UpdateExtras.connect(base::Bind<void>(&FileSelector::updateExtraLabel, this));
|
||||
}
|
||||
|
||||
updateExtraLabel();
|
||||
}
|
||||
|
||||
void FileSelector::setDefaultExtension(const std::string& extension)
|
||||
@ -392,7 +303,6 @@ void FileSelector::setDefaultExtension(const std::string& extension)
|
||||
|
||||
FileSelector::~FileSelector()
|
||||
{
|
||||
delete m_extras;
|
||||
}
|
||||
|
||||
void FileSelector::goBack()
|
||||
@ -722,15 +632,6 @@ again:
|
||||
std::string lastpath = folder->keyName();
|
||||
set_config_string("FileSelect", "CurrentDirectory",
|
||||
lastpath.c_str());
|
||||
|
||||
if (m_delegate &&
|
||||
m_delegate->hasResizeCombobox() &&
|
||||
m_extras) {
|
||||
m_delegate->setResizeScale(m_extras->resizeValue());
|
||||
m_delegate->setLayers(m_extras->layersValue());
|
||||
m_delegate->setFrames(m_extras->framesValue());
|
||||
m_delegate->setApplyPixelRatio(m_extras->applyPixelRatio());
|
||||
}
|
||||
}
|
||||
|
||||
return (!output.empty());
|
||||
@ -995,18 +896,6 @@ void FileSelector::onFileListCurrentFolderChanged()
|
||||
m_fileName->closeListBox();
|
||||
}
|
||||
|
||||
void FileSelector::onExtraOptions()
|
||||
{
|
||||
ASSERT(m_extras);
|
||||
|
||||
m_extras->remapWindow();
|
||||
gfx::Rect bounds = m_extras->bounds();
|
||||
ui::fit_bounds(BOTTOM, extraOptions()->bounds(), bounds);
|
||||
|
||||
m_extras->moveWindow(bounds);
|
||||
m_extras->openWindow();
|
||||
}
|
||||
|
||||
std::string FileSelector::getSelectedExtension() const
|
||||
{
|
||||
auto selExtItem = dynamic_cast<CustomFileExtensionItem*>(fileType()->getSelectedItem());
|
||||
@ -1016,20 +905,4 @@ std::string FileSelector::getSelectedExtension() const
|
||||
return m_defExtension;
|
||||
}
|
||||
|
||||
void FileSelector::updateExtraLabel()
|
||||
{
|
||||
if (!m_extras) {
|
||||
extraOptions()->setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
extraOptions()->setVisible(true);
|
||||
|
||||
std::string newLabel = m_extras->extrasLabel();
|
||||
if (extraOptions()->text() != newLabel) {
|
||||
extraOptions()->setText(newLabel);
|
||||
extraOptions()->window()->layout();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -29,7 +29,7 @@ namespace app {
|
||||
|
||||
class FileSelector : public app::gen::FileSelector {
|
||||
public:
|
||||
FileSelector(FileSelectorType type, FileSelectorDelegate* delegate);
|
||||
FileSelector(FileSelectorType type);
|
||||
~FileSelector();
|
||||
|
||||
void setDefaultExtension(const std::string& extension);
|
||||
@ -58,24 +58,19 @@ namespace app {
|
||||
void onFileListFileSelected();
|
||||
void onFileListFileAccepted();
|
||||
void onFileListCurrentFolderChanged();
|
||||
void onExtraOptions();
|
||||
std::string getSelectedExtension() const;
|
||||
void updateExtraLabel();
|
||||
|
||||
class ArrowNavigator;
|
||||
class CustomFileNameItem;
|
||||
class CustomFolderNameItem;
|
||||
class CustomFileNameEntry;
|
||||
class CustomFileExtensionItem;
|
||||
class ExtrasWindow;
|
||||
|
||||
FileSelectorType m_type;
|
||||
FileSelectorDelegate* m_delegate;
|
||||
std::string m_defExtension;
|
||||
CustomFileNameEntry* m_fileName;
|
||||
FileList* m_fileList;
|
||||
FileListView* m_fileView;
|
||||
ExtrasWindow* m_extras;
|
||||
|
||||
// If true the navigation_history isn't
|
||||
// modified if the current folder changes
|
||||
|
Loading…
x
Reference in New Issue
Block a user