Merge pull request #1000 from sirblackheart/native-gtk3-file-dialog

Experimental native gtk3 file dialog
This commit is contained in:
David Capello 2016-03-19 12:24:43 -03:00
commit f51de0bd73
5 changed files with 256 additions and 1 deletions

View File

@ -35,6 +35,8 @@ project(aseprite C CXX)
# CMakeCache.txt)
option(WITH_WEBP_SUPPORT "Enable support to load/save .webp files" off)
option(WITH_GTK_FILE_DIALOG_SUPPORT "Enable support for the experimental native GTK File Dialog" off)
option(WITH_DEPRECATED_GLIB_SUPPORT "Enable support for older glib versions" off)
option(USE_STATIC_LIBC "Use static version of C and C++ runtimes" off)
option(USE_SHARED_CURL "Use your installed copy of curl" off)
@ -360,6 +362,13 @@ if(UNIX AND NOT APPLE AND NOT BEOS)
if(XDGA_FOUND)
list(APPEND PLATFORM_LIBS Xxf86dga ${X11_LIBRARIES})
endif()
if(WITH_GTK_FILE_DIALOG_SUPPORT)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTKMM gtkmm-3.0)
include_directories(${GTKMM_INCLUDE_DIRS})
link_directories(${GTKMM_LIBRARY_DIRS})
endif()
endif()
# -- Windows --

View File

@ -97,7 +97,7 @@ if(USE_SKIA_BACKEND)
find_library(SKIA_OPENGL_LIBRARY opengl32)
find_library(SKIA_LIBEGL_LIBRARY libEGL.dll PATH "${SKIA_BUILD_OUT_DIR}")
if(SKIA_LIBEGL_LIBRARY)
add_definitions(-DSK_ANGLE=1)
add_definitions(-DSK_ANGLE=1)
endif()
endif()
else()
@ -193,6 +193,15 @@ if(APPLE)
osx/native_dialogs.mm)
endif()
if(WITH_GTK_FILE_DIALOG_SUPPORT AND UNIX AND NOT APPLE AND NOT BEOS)
if(WITH_DEPRECATED_GLIB_SUPPORT)
add_definitions(-DASEPRITE_DEPRECATED_GLIB_SUPPORT)
endif()
add_definitions(-DASEPRITE_WITH_GTK_FILE_DIALOG_SUPPORT)
list(APPEND SHE_SOURCES
gtk/native_dialogs.cpp)
endif()
add_library(she ${SHE_SOURCES})
target_link_libraries(she
@ -210,3 +219,8 @@ if(USE_SKIA_BACKEND)
target_link_libraries(she
${SKIA_LIBRARIES})
endif()
if(WITH_GTK_FILE_DIALOG_SUPPORT)
target_link_libraries(she
${GTKMM_LIBRARIES})
endif()

View File

@ -14,6 +14,9 @@
#elif defined(__APPLE__)
#include "she/osx/clipboard.h"
#include "she/osx/native_dialogs.h"
#elif defined(ASEPRITE_WITH_GTK_FILE_DIALOG_SUPPORT) && defined(__linux__)
#include "she/clipboard_simple.h"
#include "she/gtk/native_dialogs.h"
#else
#include "she/clipboard_simple.h"
#include "she/native_dialogs.h"
@ -56,6 +59,9 @@ public:
#elif defined(__APPLE__)
if (!m_nativeDialogs)
m_nativeDialogs = new NativeDialogsOSX();
#elif defined(ASEPRITE_WITH_GTK_FILE_DIALOG_SUPPORT) && defined(__linux__)
if (!m_nativeDialogs)
m_nativeDialogs = new NativeDialogsGTK3();
#endif
return m_nativeDialogs;
}

View File

@ -0,0 +1,194 @@
// GTK Component of SHE library
// Copyright (C) 2016 Gabriel Rauter
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
//disable EMPTY_STRING macro already set in allegro, enabling it at the end of file
#pragma push_macro("EMPTY_STRING")
#undef EMPTY_STRING
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "she/gtk/native_dialogs.h"
#include "base/string.h"
#include "she/display.h"
#include "she/error.h"
#include <gtkmm/application.h>
#include <gtkmm/filechooserdialog.h>
#include <gtkmm/button.h>
#include <gtkmm/filefilter.h>
#include <gtkmm/image.h>
#include <gdkmm/pixbuf.h>
#include <glibmm/refptr.h>
#include <glibmm/miscutils.h>
#include <glibmm/fileutils.h>
#include <string>
#include <map>
namespace she {
class FileDialogGTK3 : public FileDialog, public Gtk::FileChooserDialog {
public:
FileDialogGTK3(Glib::RefPtr<Gtk::Application> app) :
Gtk::FileChooserDialog(""), m_app(app), m_cancel(true) {
this->add_button("_Cancel", Gtk::RESPONSE_CANCEL);
m_ok_button = this->add_button("_Open", Gtk::RESPONSE_OK);
this->set_default_response(Gtk::RESPONSE_OK);
m_filter_all = Gtk::FileFilter::create();
m_filter_all->set_name("All formats");
this->set_do_overwrite_confirmation();
if (FileDialogGTK3::lastUsedDir().empty()) {
#ifdef ASEPRITE_DEPRECATED_GLIB_SUPPORT
FileDialogGTK3::lastUsedDir() = Glib::get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS);
#else
FileDialogGTK3::lastUsedDir() = Glib::get_user_special_dir(Glib::USER_DIRECTORY_DOCUMENTS);
#endif
}
this->set_use_preview_label(false);
this->set_preview_widget(m_preview);
this->signal_update_preview().connect(sigc::mem_fun(this, &FileDialogGTK3::updatePreview));
}
void on_show() override {
//setting the filename only works properly when the dialog is shown
if (!m_file_name.empty()) {
if (this->get_action() == Gtk::FILE_CHOOSER_ACTION_OPEN) {
this->set_current_folder(m_file_name);
} else {
if (Glib::file_test(m_file_name, Glib::FILE_TEST_EXISTS)) {
this->set_filename(m_file_name);
} else {
this->set_current_folder(FileDialogGTK3::lastUsedDir());
this->set_current_name(m_file_name);
}
}
} else {
this->set_current_folder(FileDialogGTK3::lastUsedDir());
}
//TODO set position centered to parent window, need she::screen to provide info
this->set_position(Gtk::WIN_POS_CENTER);
Gtk::FileChooserDialog::on_show();
this->raise();
}
void on_response(int response_id) override {
switch(response_id) {
case(Gtk::RESPONSE_OK): {
m_cancel = false;
m_file_name = this->get_filename();
FileDialogGTK3::lastUsedDir() = this->get_current_folder();
break;
}
}
this->hide();
}
void dispose() override {
for (auto& window : m_app->get_windows()) {
window->close();
}
m_app->quit();
delete this;
}
void toOpenFile() override {
this->set_action(Gtk::FILE_CHOOSER_ACTION_OPEN);
m_ok_button->set_label("_Open");
}
void toSaveFile() override {
this->set_action(Gtk::FILE_CHOOSER_ACTION_SAVE);
m_ok_button->set_label("_Save");
}
void setTitle(const std::string& title) override {
this->set_title(title);
}
void setDefaultExtension(const std::string& extension) override {
m_default_extension = extension;
}
void addFilter(const std::string& extension, const std::string& description) override {
auto filter = Gtk::FileFilter::create();
filter->set_name(description);
filter->add_pattern("*." + extension);
m_filter_all->add_pattern("*." + extension);
m_filters[extension] = filter;
}
std::string fileName() override {
return m_file_name;
}
void setFileName(const std::string& filename) override {
m_file_name = filename;
}
void updatePreview() {
this->set_preview_widget_active(false);
std::string fileName = this->get_filename();
try {
if (!Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) {
auto previewPixbuf = Gdk::Pixbuf::create_from_file(fileName, 256, 256, true);
m_preview.set(previewPixbuf);
this->set_preview_widget_active();
}
} catch(Glib::Error e) {}
}
bool show(Display* parent) override {
//keep pointer on parent display to get information later
m_display = parent;
//add filters in order they will appear
this->add_filter(m_filter_all);
for (const auto& filter : m_filters) {
this->add_filter(filter.second) ;
if (filter.first.compare(m_default_extension) == 0) {
this->set_filter(filter.second);
}
}
auto filter_any = Gtk::FileFilter::create();
filter_any->set_name("Any files");
filter_any->add_pattern("*");
this->add_filter(filter_any);
//Run dialog in context of a gtk application so it can be destroys properly
m_app->run(*this);
return !m_cancel;
}
private:
std::string m_file_name;
std::string m_default_extension;
Glib::RefPtr<Gtk::FileFilter> m_filter_all;
std::map<std::string, Glib::RefPtr<Gtk::FileFilter>> m_filters;
Gtk::Button* m_ok_button;
Glib::RefPtr<Gtk::Application> m_app;
Gtk::Image m_preview;
Display* m_display;
bool m_cancel;
static std::string& lastUsedDir() { static std::string lastUsedDir; return lastUsedDir; }
};
NativeDialogsGTK3::NativeDialogsGTK3()
{
}
FileDialog* NativeDialogsGTK3::createFileDialog()
{
m_app = Gtk::Application::create();
FileDialog* dialog = new FileDialogGTK3(m_app);
return dialog;
}
} // namespace she
#pragma pop_macro("EMPTY_STRING")

View File

@ -0,0 +1,32 @@
// GTK Component of SHE library
// Copyright (C) 2016 Gabriel Rauter
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
//disable EMPTY_STRING macro already set in allegro, enabling it at the end of file
#pragma push_macro("EMPTY_STRING")
#undef EMPTY_STRING
#ifndef SHE_GTK_NATIVE_DIALOGS_H_INCLUDED
#define SHE_GTK_NATIVE_DIALOGS_H_INCLUDED
#pragma once
#include "she/native_dialogs.h"
#include <gtkmm/application.h>
#include <glibmm/refptr.h>
namespace she {
class NativeDialogsGTK3 : public NativeDialogs {
public:
NativeDialogsGTK3();
FileDialog* createFileDialog() override;
private:
Glib::RefPtr<Gtk::Application> m_app;
};
} // namespace she
#endif
#pragma pop_macro("EMPTY_STRING")