mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-27 06:35:16 +00:00
The Zenity utility is not perfect, there are several issues to improve the UX, but it's good enough to offer a native file dialog on Linux without depending on huge dynamic GUI libraries (GTK+, Qt, etc.).
This commit is contained in:
parent
3e171d0f6a
commit
556c621eeb
@ -109,16 +109,6 @@ if(NOT LAF_OS_BACKEND)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Check valid gtk + libpng combination
|
||||
if(LAF_OS_WITH_GTK)
|
||||
if(NOT USE_SHARED_LIBPNG)
|
||||
message(FATAL_ERROR "Cannot compile with gtk and static libpng, set USE_SHARED_LIBPNG=ON")
|
||||
endif()
|
||||
if(NOT USE_SHARED_HARFBUZZ)
|
||||
message(FATAL_ERROR "Cannot compile with gtk and static HarfBuzz, set USE_SHARED_HARFBUZZ=ON")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_DRM AND NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/drm/CMakeLists.txt)
|
||||
message(FATAL_ERROR "Your Aseprite repository is incomplete, clone the drm repository")
|
||||
endif()
|
||||
|
2
laf
2
laf
@ -1 +1 @@
|
||||
Subproject commit f89c72e5bfdc6d8923fe0b3fbef15ec38333630a
|
||||
Subproject commit 5e936d76335172a4605dc09556a3bf8d54252b05
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -14,6 +14,7 @@
|
||||
#include "app/app.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "app/ui/file_selector.h"
|
||||
#include "base/fs.h"
|
||||
#include "os/native_dialogs.h"
|
||||
#include "os/system.h"
|
||||
#include "os/window.h"
|
||||
@ -37,7 +38,21 @@ bool show_file_selector(
|
||||
|
||||
if (dlg) {
|
||||
dlg->setTitle(title);
|
||||
|
||||
// Must be set before setFileName() as the Linux impl might
|
||||
// require the default extension to fix the initial file name
|
||||
// with the default extension.
|
||||
if (!defExtension.empty()) {
|
||||
dlg->setDefaultExtension(defExtension);
|
||||
}
|
||||
|
||||
#if LAF_LINUX // As the X11 version doesn't store the default path to
|
||||
// start navigating, we use our own
|
||||
// get_initial_path_to_select_filename()
|
||||
dlg->setFileName(get_initial_path_to_select_filename(initialPath));
|
||||
#else // !LAF_LINUX
|
||||
dlg->setFileName(initialPath);
|
||||
#endif
|
||||
|
||||
os::FileDialog::Type nativeType = os::FileDialog::Type::OpenFile;
|
||||
switch (type) {
|
||||
@ -56,17 +71,30 @@ bool show_file_selector(
|
||||
for (const auto& ext : extensions)
|
||||
dlg->addFilter(ext, ext + " files (*." + ext + ")");
|
||||
|
||||
if (!defExtension.empty())
|
||||
dlg->setDefaultExtension(defExtension);
|
||||
auto res = dlg->show(os::instance()->defaultWindow());
|
||||
if (res != os::FileDialog::Result::Error) {
|
||||
if (res == os::FileDialog::Result::OK) {
|
||||
if (type == FileSelectorType::OpenMultiple)
|
||||
dlg->getMultipleFileNames(output);
|
||||
else
|
||||
output.push_back(dlg->fileName());
|
||||
|
||||
bool res = dlg->show(os::instance()->defaultWindow());
|
||||
if (res) {
|
||||
if (type == FileSelectorType::OpenMultiple)
|
||||
dlg->getMultipleFileNames(output);
|
||||
else
|
||||
output.push_back(dlg->fileName());
|
||||
#if LAF_LINUX // Save the path in the configuration file
|
||||
if (!output.empty()) {
|
||||
set_current_dir_for_file_selector(base::get_file_path(output[0]));
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Fallback to default file selector if we weren't able to
|
||||
// open the native dialog...
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,4 +106,38 @@ bool show_file_selector(
|
||||
return fileSelector.show(title, initialPath, extensions, output);
|
||||
}
|
||||
|
||||
std::string get_initial_path_to_select_filename(const std::string& initialFilename)
|
||||
{
|
||||
std::string path = base::get_file_path(initialFilename);
|
||||
// If initialFilename doesn't contain a path/directory.
|
||||
if (path.empty()) {
|
||||
// Put the saved 'path' from the configuration file.
|
||||
path = base::join_path(get_current_dir_for_file_selector(),
|
||||
base::get_file_name(initialFilename));
|
||||
}
|
||||
else {
|
||||
path = initialFilename;
|
||||
}
|
||||
path = base::fix_path_separators(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string get_current_dir_for_file_selector()
|
||||
{
|
||||
std::string path = Preferences::instance().fileSelector.currentFolder();
|
||||
// If it's empty or the folder doesn't exist anymore, starts from
|
||||
// the docs folder by default.
|
||||
if (path.empty() ||
|
||||
path == "<empty>" ||
|
||||
!base::is_directory(path)) {
|
||||
path = base::get_user_docs_folder();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
void set_current_dir_for_file_selector(const std::string& dirPath)
|
||||
{
|
||||
Preferences::instance().fileSelector.currentFolder(dirPath);
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2023 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -28,6 +29,14 @@ namespace app {
|
||||
FileSelectorType type,
|
||||
base::paths& output);
|
||||
|
||||
std::string get_initial_path_to_select_filename(
|
||||
const std::string& initialFilename);
|
||||
|
||||
// Get/set the directory used for the file selector (custom one, and
|
||||
// the X11 native one).
|
||||
std::string get_current_dir_for_file_selector();
|
||||
void set_current_dir_for_file_selector(const std::string& dirPath);
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
||||
|
@ -410,28 +410,10 @@ bool FileSelector::show(
|
||||
|
||||
fs->refresh();
|
||||
|
||||
// we have to find where the user should begin to browse files (start_folder)
|
||||
std::string start_folder_path;
|
||||
IFileItem* start_folder = nullptr;
|
||||
|
||||
// If initialPath doesn't contain a path.
|
||||
if (base::get_file_path(initialPath).empty()) {
|
||||
// Get the saved `path' in the configuration file.
|
||||
std::string path = Preferences::instance().fileSelector.currentFolder();
|
||||
if (path == "<empty>") {
|
||||
start_folder_path = base::get_user_docs_folder();
|
||||
path = base::join_path(start_folder_path, initialPath);
|
||||
}
|
||||
start_folder = fs->getFileItemFromPath(path);
|
||||
}
|
||||
else {
|
||||
// Remove the filename.
|
||||
start_folder_path = base::join_path(base::get_file_path(initialPath), "");
|
||||
}
|
||||
start_folder_path = base::fix_path_separators(start_folder_path);
|
||||
|
||||
if (!start_folder)
|
||||
start_folder = fs->getFileItemFromPath(start_folder_path);
|
||||
// We have to find where the user should begin to browse files
|
||||
std::string start_folder_path =
|
||||
base::get_file_path(get_initial_path_to_select_filename(initialPath));
|
||||
IFileItem* start_folder = fs->getFileItemFromPath(start_folder_path);
|
||||
|
||||
FILESEL_TRACE("FILESEL: Start folder '%s' (%p)\n", start_folder_path.c_str(), start_folder);
|
||||
|
||||
@ -703,7 +685,7 @@ again:
|
||||
|
||||
// save the path in the configuration file
|
||||
std::string lastpath = folder->keyName();
|
||||
Preferences::instance().fileSelector.currentFolder(lastpath);
|
||||
set_current_dir_for_file_selector(lastpath);
|
||||
}
|
||||
Preferences::instance().fileSelector.zoom(m_fileList->zoom());
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user