1 #include "dialog.hpp"
2 #include "filesystem.hpp"
3 #include <cmath>
4 
Message(const std::string & text,std::function<void ()> && on_cancel,bool show_progress_bar)5 Dialog::Message::Message(const std::string &text, std::function<void()> &&on_cancel, bool show_progress_bar) : Gtk::Window(Gtk::WindowType::WINDOW_POPUP) {
6   auto g_application = g_application_get_default();
7   auto gio_application = Glib::wrap(g_application, true);
8   auto application = Glib::RefPtr<Gtk::Application>::cast_static(gio_application);
9   set_transient_for(*application->get_active_window());
10 
11   set_position(Gtk::WindowPosition::WIN_POS_CENTER_ON_PARENT);
12   set_modal(true);
13   set_type_hint(Gdk::WindowTypeHint::WINDOW_TYPE_HINT_NOTIFICATION);
14   property_decorated() = false;
15   set_skip_taskbar_hint(true);
16   auto visual = get_screen()->get_rgba_visual();
17   if(visual)
18     gtk_widget_set_visual(reinterpret_cast<GtkWidget *>(gobj()), visual->gobj());
19   get_style_context()->add_class("juci_message_window");
20 
21   auto vbox = Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL));
22   vbox->get_style_context()->add_class("juci_message_box");
23   auto hbox = Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_HORIZONTAL));
24   auto image = Gtk::manage(new Gtk::Image());
25   image->set_from_icon_name("dialog-information", Gtk::BuiltinIconSize::ICON_SIZE_BUTTON);
26   hbox->pack_start(*image, Gtk::PackOptions::PACK_SHRINK);
27   auto label = Gtk::manage(new Gtk::Label(text));
28   label->set_padding(7, 7);
29   hbox->pack_start(*label);
30   vbox->pack_start(*hbox);
31   if(on_cancel) {
32     auto cancel_button = Gtk::manage(new Gtk::Button("Cancel"));
33     cancel_button->signal_clicked().connect([label, on_cancel = std::move(on_cancel)] {
34       label->set_text("Canceling...");
35       if(on_cancel)
36         on_cancel();
37     });
38     vbox->pack_start(*cancel_button);
39   }
40   if(show_progress_bar)
41     vbox->pack_start(progress_bar);
42   add(*vbox);
43   show_all_children();
44   show_now();
45 
46   while(Gtk::Main::events_pending())
47     Gtk::Main::iteration();
48 }
49 
set_fraction(double fraction)50 void Dialog::Message::set_fraction(double fraction) {
51   progress_bar.set_fraction(fraction);
52 }
53 
on_delete_event(GdkEventAny * event)54 bool Dialog::Message::on_delete_event(GdkEventAny *event) {
55   return true;
56 }
57 
gtk_dialog(const boost::filesystem::path & path,const std::string & title,const std::vector<std::pair<std::string,Gtk::ResponseType>> & buttons,Gtk::FileChooserAction action)58 std::string Dialog::gtk_dialog(const boost::filesystem::path &path, const std::string &title,
59                                const std::vector<std::pair<std::string, Gtk::ResponseType>> &buttons,
60                                Gtk::FileChooserAction action) {
61   // Workaround for crash on MacOS when filtering files in file/folder dialogs.
62   // See also https://github.com/cppit/jucipp/issues/259.
63   // TODO 2018: check if this bug has been fixed
64 #ifdef __APPLE__
65   class FileChooserDialog : public Gtk::FileChooserDialog {
66     Gtk::FileChooserAction action;
67 
68   public:
69     FileChooserDialog(const Glib::ustring &title, Gtk::FileChooserAction action) : Gtk::FileChooserDialog(title, action), action(action) {}
70 
71   protected:
72     bool on_key_press_event(GdkEventKey *event) override {
73       if(action == Gtk::FileChooserAction::FILE_CHOOSER_ACTION_OPEN || action == Gtk::FileChooserAction::FILE_CHOOSER_ACTION_SELECT_FOLDER) {
74         auto unicode = gdk_keyval_to_unicode(event->keyval);
75         if(unicode > 31 && unicode != 127)
76           return true;
77       }
78       return Gtk::FileChooserDialog::on_key_press_event(event);
79     }
80   };
81   FileChooserDialog dialog(title, action);
82 #else
83   Gtk::FileChooserDialog dialog(title, action);
84 #endif
85 
86   auto g_application = g_application_get_default();
87   auto gio_application = Glib::wrap(g_application, true);
88   auto application = Glib::RefPtr<Gtk::Application>::cast_static(gio_application);
89   dialog.set_transient_for(*application->get_active_window());
90   dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ON_PARENT);
91 
92   if(title == "Save File As")
93     gtk_file_chooser_set_filename(reinterpret_cast<GtkFileChooser *>(dialog.gobj()), path.string().c_str());
94   else if(!path.empty())
95     gtk_file_chooser_set_current_folder(reinterpret_cast<GtkFileChooser *>(dialog.gobj()), path.string().c_str());
96   else {
97     auto current_path = filesystem::get_current_path();
98     if(!current_path.empty())
99       gtk_file_chooser_set_current_folder(reinterpret_cast<GtkFileChooser *>(dialog.gobj()), current_path.string().c_str());
100   }
101 
102   for(auto &button : buttons)
103     dialog.add_button(button.first, button.second);
104   return dialog.run() == Gtk::RESPONSE_OK ? dialog.get_filename() : "";
105 }
106 
open_folder(const boost::filesystem::path & path)107 std::string Dialog::open_folder(const boost::filesystem::path &path) {
108   return gtk_dialog(path, "Open Folder",
109                     {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL), std::make_pair("Open", Gtk::RESPONSE_OK)},
110                     Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
111 }
112 
new_file(const boost::filesystem::path & path)113 std::string Dialog::new_file(const boost::filesystem::path &path) {
114   return gtk_dialog(path, "New File",
115                     {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL), std::make_pair("Save", Gtk::RESPONSE_OK)},
116                     Gtk::FILE_CHOOSER_ACTION_SAVE);
117 }
118 
new_folder(const boost::filesystem::path & path)119 std::string Dialog::new_folder(const boost::filesystem::path &path) {
120   return gtk_dialog(path, "New Folder",
121                     {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL), std::make_pair("Create", Gtk::RESPONSE_OK)},
122                     Gtk::FILE_CHOOSER_ACTION_CREATE_FOLDER);
123 }
124 
open_file(const boost::filesystem::path & path)125 std::string Dialog::open_file(const boost::filesystem::path &path) {
126   return gtk_dialog(path, "Open File",
127                     {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL), std::make_pair("Select", Gtk::RESPONSE_OK)},
128                     Gtk::FILE_CHOOSER_ACTION_OPEN);
129 }
130 
save_file_as(const boost::filesystem::path & path)131 std::string Dialog::save_file_as(const boost::filesystem::path &path) {
132   return gtk_dialog(path, "Save File As",
133                     {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL), std::make_pair("Save", Gtk::RESPONSE_OK)},
134                     Gtk::FILE_CHOOSER_ACTION_SAVE);
135 }
136