| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  | // Aseprite
 | 
					
						
							| 
									
										
										
										
											2019-03-26 23:20:54 +08:00
										 |  |  | // Copyright (C) 2019  Igara Studio S.A.
 | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  | // 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"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 22:54:44 +08:00
										 |  |  | #include "app/doc.h"
 | 
					
						
							| 
									
										
										
										
											2018-06-27 21:00:19 +08:00
										 |  |  | #include "app/file/file.h"
 | 
					
						
							| 
									
										
										
										
											2018-03-16 22:26:13 +08:00
										 |  |  | #include "app/i18n/strings.h"
 | 
					
						
							| 
									
										
										
										
											2018-07-07 13:47:42 +08:00
										 |  |  | #include "app/site.h"
 | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  | #include "app/ui/layer_frame_comboboxes.h"
 | 
					
						
							| 
									
										
										
										
											2018-03-16 19:59:34 +08:00
										 |  |  | #include "app/ui_context.h"
 | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  | #include "base/bind.h"
 | 
					
						
							|  |  |  | #include "base/convert_to.h"
 | 
					
						
							|  |  |  | #include "base/fs.h"
 | 
					
						
							| 
									
										
										
										
											2018-06-27 21:00:19 +08:00
										 |  |  | #include "base/string.h"
 | 
					
						
							| 
									
										
										
										
											2018-03-16 19:59:34 +08:00
										 |  |  | #include "doc/frame_tag.h"
 | 
					
						
							|  |  |  | #include "doc/selected_frames.h"
 | 
					
						
							| 
									
										
										
										
											2018-03-16 22:26:13 +08:00
										 |  |  | #include "fmt/format.h"
 | 
					
						
							| 
									
										
										
										
											2018-06-27 21:00:19 +08:00
										 |  |  | #include "ui/alert.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace app { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 22:54:44 +08:00
										 |  |  | ExportFileWindow::ExportFileWindow(const Doc* doc) | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  |   : m_doc(doc) | 
					
						
							|  |  |  |   , m_docPref(Preferences::instance().document(doc)) | 
					
						
							| 
									
										
										
										
											2018-03-16 22:26:13 +08:00
										 |  |  |   , m_preferredResize(1) | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  | { | 
					
						
							|  |  |  |   // Is a default output filename in the preferences?
 | 
					
						
							|  |  |  |   if (!m_docPref.saveCopy.filename().empty()) { | 
					
						
							| 
									
										
										
										
											2018-03-16 21:08:52 +08:00
										 |  |  |     setOutputFilename(m_docPref.saveCopy.filename()); | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     std::string newFn = base::replace_extension( | 
					
						
							|  |  |  |       doc->filename(), | 
					
						
							| 
									
										
										
										
											2018-06-27 21:00:19 +08:00
										 |  |  |       defaultExtension()); | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  |     if (newFn == doc->filename()) { | 
					
						
							|  |  |  |       newFn = base::join_path( | 
					
						
							|  |  |  |         base::get_file_path(newFn), | 
					
						
							|  |  |  |         base::get_file_title(newFn) + "-export." + base::get_file_extension(newFn)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-03-16 21:08:52 +08:00
										 |  |  |     setOutputFilename(newFn); | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // 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()); | 
					
						
							| 
									
										
										
										
											2018-03-16 19:59:34 +08:00
										 |  |  |   fill_anidir_combobox(anidir(), m_docPref.saveCopy.aniDir()); | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  |   pixelRatio()->setSelected(m_docPref.saveCopy.applyPixelRatio()); | 
					
						
							| 
									
										
										
										
											2018-03-16 22:03:50 +08:00
										 |  |  |   forTwitter()->setSelected(m_docPref.saveCopy.forTwitter()); | 
					
						
							| 
									
										
										
										
											2018-03-16 22:26:13 +08:00
										 |  |  |   adjustResize()->setVisible(false); | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-02 01:31:27 +08:00
										 |  |  |   // Here we don't call updateAniDir() because it's already filled and
 | 
					
						
							|  |  |  |   // set by the function fill_anidir_combobox(). So if the user
 | 
					
						
							|  |  |  |   // exported a tag with a specific AniDir, we want to keep the option
 | 
					
						
							|  |  |  |   // in the preference (instead of the tag's AniDir).
 | 
					
						
							|  |  |  |   //updateAniDir();
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 22:26:13 +08:00
										 |  |  |   updateAdjustResizeButton(); | 
					
						
							| 
									
										
										
										
											2018-03-16 19:59:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 21:08:52 +08:00
										 |  |  |   outputFilename()->Change.connect( | 
					
						
							|  |  |  |     base::Bind<void>( | 
					
						
							|  |  |  |       [this]{ | 
					
						
							|  |  |  |         m_outputFilename = outputFilename()->text(); | 
					
						
							|  |  |  |         onOutputFilenameEntryChange(); | 
					
						
							|  |  |  |       })); | 
					
						
							|  |  |  |   outputFilenameBrowse()->Click.connect( | 
					
						
							|  |  |  |     base::Bind<void>( | 
					
						
							|  |  |  |       [this]{ | 
					
						
							|  |  |  |         std::string fn = SelectOutputFile(); | 
					
						
							|  |  |  |         if (!fn.empty()) { | 
					
						
							|  |  |  |           setOutputFilename(fn); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       })); | 
					
						
							| 
									
										
										
										
											2018-03-16 19:59:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 22:26:13 +08:00
										 |  |  |   resize()->Change.connect(base::Bind<void>(&ExportFileWindow::updateAdjustResizeButton, this)); | 
					
						
							| 
									
										
										
										
											2018-03-16 19:59:34 +08:00
										 |  |  |   frames()->Change.connect(base::Bind<void>(&ExportFileWindow::updateAniDir, this)); | 
					
						
							| 
									
										
										
										
											2018-03-16 22:26:13 +08:00
										 |  |  |   forTwitter()->Click.connect(base::Bind<void>(&ExportFileWindow::updateAdjustResizeButton, this)); | 
					
						
							|  |  |  |   adjustResize()->Click.connect(base::Bind<void>(&ExportFileWindow::onAdjustResize, this)); | 
					
						
							| 
									
										
										
										
											2018-06-27 21:00:19 +08:00
										 |  |  |   ok()->Click.connect(base::Bind<void>(&ExportFileWindow::onOK, this)); | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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()); | 
					
						
							| 
									
										
										
										
											2019-03-26 23:20:54 +08:00
										 |  |  |   m_docPref.saveCopy.aniDir(aniDirValue()); | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  |   m_docPref.saveCopy.frameTag(framesValue()); | 
					
						
							|  |  |  |   m_docPref.saveCopy.applyPixelRatio(applyPixelRatio()); | 
					
						
							| 
									
										
										
										
											2018-03-16 22:03:50 +08:00
										 |  |  |   m_docPref.saveCopy.forTwitter(isForTwitter()); | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 21:08:52 +08:00
										 |  |  | std::string ExportFileWindow::outputFilenameValue() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return base::join_path(m_outputPath, | 
					
						
							|  |  |  |                          m_outputFilename); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  | 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(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 19:59:34 +08:00
										 |  |  | doc::AniDir ExportFileWindow::aniDirValue() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return (doc::AniDir)anidir()->getSelectedItemIndex(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  | bool ExportFileWindow::applyPixelRatio() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return pixelRatio()->isSelected(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 22:03:50 +08:00
										 |  |  | bool ExportFileWindow::isForTwitter() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return forTwitter()->isSelected(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 21:08:52 +08:00
										 |  |  | void ExportFileWindow::setOutputFilename(const std::string& pathAndFilename) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   m_outputPath = base::get_file_path(pathAndFilename); | 
					
						
							|  |  |  |   m_outputFilename = base::get_file_name(pathAndFilename); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   updateOutputFilenameEntry(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ExportFileWindow::updateOutputFilenameEntry() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   outputFilename()->setText(m_outputFilename); | 
					
						
							|  |  |  |   onOutputFilenameEntryChange(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ExportFileWindow::onOutputFilenameEntryChange() | 
					
						
							| 
									
										
										
										
											2018-03-16 09:42:53 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-16 20:37:21 +08:00
										 |  |  |   ok()->setEnabled(!m_outputFilename.empty()); | 
					
						
							| 
									
										
										
										
											2018-03-16 09:42:53 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 19:59:34 +08:00
										 |  |  | void ExportFileWindow::updateAniDir() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   std::string framesValue = this->framesValue(); | 
					
						
							|  |  |  |   if (!framesValue.empty() && | 
					
						
							|  |  |  |       framesValue != kAllFrames && | 
					
						
							|  |  |  |       framesValue != kSelectedFrames) { | 
					
						
							|  |  |  |     SelectedFrames selFrames; | 
					
						
							|  |  |  |     FrameTag* frameTag = calculate_selected_frames( | 
					
						
							|  |  |  |       UIContext::instance()->activeSite(), framesValue, selFrames); | 
					
						
							|  |  |  |     if (frameTag) | 
					
						
							|  |  |  |       anidir()->setSelectedItemIndex(int(frameTag->aniDir())); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     anidir()->setSelectedItemIndex(int(doc::AniDir::FORWARD)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 22:26:13 +08:00
										 |  |  | void ExportFileWindow::updateAdjustResizeButton() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   // Calculate a better size for Twitter
 | 
					
						
							|  |  |  |   m_preferredResize = 1; | 
					
						
							|  |  |  |   while (m_preferredResize < 10 && | 
					
						
							|  |  |  |          (m_doc->width()*m_preferredResize < 240 || | 
					
						
							|  |  |  |           m_doc->height()*m_preferredResize < 240)) { | 
					
						
							|  |  |  |     ++m_preferredResize; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const bool newState = | 
					
						
							|  |  |  |     forTwitter()->isSelected() && | 
					
						
							|  |  |  |     ((int)resizeValue() < m_preferredResize); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (adjustResize()->isVisible() != newState) { | 
					
						
							|  |  |  |     adjustResize()->setVisible(newState); | 
					
						
							|  |  |  |     if (newState) | 
					
						
							|  |  |  |       adjustResize()->setText(fmt::format(Strings::export_file_adjust_resize(), | 
					
						
							|  |  |  |                                           100 * m_preferredResize)); | 
					
						
							|  |  |  |     adjustResize()->parent()->layout(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ExportFileWindow::onAdjustResize() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   resize()->setValue(base::convert_to<std::string>(m_preferredResize)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   adjustResize()->setVisible(false); | 
					
						
							|  |  |  |   adjustResize()->parent()->layout(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-27 21:00:19 +08:00
										 |  |  | void ExportFileWindow::onOK() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   base::paths exts = get_writable_extensions(); | 
					
						
							|  |  |  |   std::string ext = base::string_to_lower( | 
					
						
							|  |  |  |     base::get_file_extension(m_outputFilename)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Add default extension to output filename
 | 
					
						
							|  |  |  |   if (std::find(exts.begin(), exts.end(), ext) == exts.end()) { | 
					
						
							|  |  |  |     if (ext.empty()) { | 
					
						
							|  |  |  |       m_outputFilename = | 
					
						
							|  |  |  |         base::replace_extension(m_outputFilename, | 
					
						
							|  |  |  |                                 defaultExtension()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       ui::Alert::show( | 
					
						
							|  |  |  |         fmt::format(Strings::alerts_unknown_output_file_format_error(), ext)); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   closeWindow(ok()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::string ExportFileWindow::defaultExtension() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   auto& pref = Preferences::instance(); | 
					
						
							|  |  |  |   if (m_doc->sprite()->totalFrames() > 1) | 
					
						
							|  |  |  |     return pref.exportFile.animationDefaultExtension(); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     return pref.exportFile.imageDefaultExtension(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 07:34:01 +08:00
										 |  |  | } // namespace app
 |