summaryrefslogtreecommitdiff
path: root/src/gui_gtk.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui_gtk.cc')
-rw-r--r--src/gui_gtk.cc141
1 files changed, 133 insertions, 8 deletions
diff --git a/src/gui_gtk.cc b/src/gui_gtk.cc
index 14c1f63..55ce88a 100644
--- a/src/gui_gtk.cc
+++ b/src/gui_gtk.cc
@@ -919,6 +919,15 @@ public:
values_.emplace_back(new NumberValue(id, label, description, value));
}
+ void add_file(std::string const& id, std::string const& label,
+ std::string const& value,
+ std::string const& description,
+ bool must_exist,
+ std::vector<Filter> const& filter) override {
+ values_.emplace_back(new FileValue(id, label, description, value,
+ must_exist, filter));
+ }
+
std::string get_string(std::string const& id) const override {
for (auto const& value : values_) {
if (value->id_ == id && value->type_ == STRING) {
@@ -948,6 +957,26 @@ public:
return 0;
}
+ std::string get_file(std::string const& id) const override {
+ for (auto const& value : values_) {
+ if (value->id_ == id && value->type_ == FILE) {
+ auto v = static_cast<FileValue*>(value.get());
+ if (v->must_exist_ && v->chooser_) {
+ std::string ret;
+ auto file = gtk_file_chooser_get_filename(v->chooser_);
+ if (file) {
+ ret.assign(file);
+ g_free(file);
+ }
+ return ret;
+ }
+ return v->value_;
+ }
+ }
+ assert(false);
+ return "";
+ }
+
void set_error(std::string const& error) override {
if (!error_) {
assert(false);
@@ -984,12 +1013,13 @@ public:
auto label = gtk_label_new(text_.c_str());
gtk_label_set_width_chars(GTK_LABEL(label), 35);
gtk_label_set_line_wrap(GTK_LABEL(label), true);
- gtk_grid_attach(GTK_GRID(grid), label, 0, row++, 2, 1);
+ gtk_grid_attach(GTK_GRID(grid), label, 0, row++, 3, 1);
}
for (auto& value : values_) {
auto label = gtk_label_new(value->label_.c_str());
value->entry_ = gtk_entry_new();
gtk_entry_set_activates_default(GTK_ENTRY(value->entry_), true);
+ GtkWidget* extra = nullptr;
switch (value->type_) {
case STRING:
gtk_entry_set_text(GTK_ENTRY(value->entry_),
@@ -1004,9 +1034,49 @@ public:
GTK_INPUT_PURPOSE_DIGITS);
break;
}
+ case FILE: {
+ auto v = static_cast<FileValue*>(value.get());
+ if (v->must_exist_) {
+ gtk_widget_destroy(value->entry_);
+ auto button = gtk_file_chooser_button_new(
+ v->label_.c_str(), GTK_FILE_CHOOSER_ACTION_OPEN);
+ v->chooser_ = GTK_FILE_CHOOSER(button);
+ value->entry_ = button;
+ } else {
+ auto chooser = gtk_file_chooser_native_new(
+ v->label_.c_str(),
+ GTK_WINDOW(dialog_),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ nullptr, nullptr);
+ extra = gtk_button_new_with_label("...");
+ g_signal_connect(G_OBJECT(extra), "clicked",
+ G_CALLBACK(show_filechooser), v);
+ v->chooser_ = GTK_FILE_CHOOSER(chooser);
+ gtk_editable_set_editable(GTK_EDITABLE(value->entry_), false);
+ gtk_file_chooser_set_do_overwrite_confirmation(v->chooser_, true);
+ }
+ if (!v->value_.empty()) {
+ gtk_file_chooser_set_filename(v->chooser_, v->value_.c_str());
+ }
+ for (auto const& filter : v->filter_) {
+ auto f = gtk_file_filter_new();
+ gtk_file_filter_set_name(f, filter.name.c_str());
+ for (auto const& mask : filter.masks) {
+ gtk_file_filter_add_pattern(f, mask.c_str());
+ }
+ gtk_file_chooser_add_filter(v->chooser_, f);
+ }
+ break;
+ }
}
gtk_grid_attach(GTK_GRID(grid), label, 0, row, 1, 1);
- gtk_grid_attach(GTK_GRID(grid), value->entry_, 1, row++, 1, 1);
+ if (extra) {
+ gtk_grid_attach(GTK_GRID(grid), value->entry_, 1, row, 1, 1);
+ gtk_grid_attach(GTK_GRID(grid), extra, 2, row, 1, 1);
+ } else {
+ gtk_grid_attach(GTK_GRID(grid), value->entry_, 1, row, 2, 1);
+ }
+ row++;
if (!value->description_.empty()) {
auto desc = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(desc),
@@ -1014,15 +1084,15 @@ public:
gtk_widget_set_halign(GTK_WIDGET(desc), GTK_ALIGN_END);
gtk_label_set_line_wrap(GTK_LABEL(desc), true);
gtk_label_set_max_width_chars(GTK_LABEL(desc), 35);
- gtk_grid_attach(GTK_GRID(grid), desc, 0, row++, 2, 1);
+ gtk_grid_attach(GTK_GRID(grid), desc, 0, row++, 3, 1);
}
}
error_ = gtk_label_new("");
gtk_label_set_xalign(GTK_LABEL(error_), 0.0);
- gtk_grid_attach(GTK_GRID(grid), error_, 0, row++, 2, 1);
+ gtk_grid_attach(GTK_GRID(grid), error_, 0, row++, 3, 1);
gtk_container_add(GTK_CONTAINER(content_area), grid);
gtk_widget_show_all(dialog_);
- row = add_extra_widgets(GTK_GRID(grid), row);
+ row = add_extra_widgets(GTK_GRID(grid), row, 3);
gtk_widget_hide(error_);
gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT);
gint result;
@@ -1041,6 +1111,22 @@ public:
get_number(value->entry_,
&static_cast<NumberValue*>(value.get())->value_);
break;
+ case FILE: {
+ auto v = static_cast<FileValue*>(value.get());
+ if (v->must_exist_) {
+ auto file = gtk_file_chooser_get_filename(v->chooser_);
+ if (file) {
+ v->value_ = file;
+ g_free(file);
+ } else {
+ v->value_.clear();
+ }
+ } else {
+ g_object_unref(v->chooser_);
+ }
+ v->chooser_ = nullptr;
+ break;
+ }
}
value->entry_ = nullptr;
}
@@ -1055,6 +1141,7 @@ protected:
enum Type {
STRING,
NUMBER,
+ FILE,
};
struct Value {
@@ -1089,6 +1176,20 @@ protected:
}
};
+ struct FileValue : public Value {
+ std::string value_;
+ bool must_exist_;
+ std::vector<Filter> filter_;
+ GtkFileChooser* chooser_;
+
+ FileValue(std::string const& id, std::string const& label,
+ std::string const& description, std::string const& value,
+ bool must_exist, std::vector<Filter> const& filter)
+ : Value(FILE, id, label, description), value_(value),
+ must_exist_(must_exist), filter_(filter) {
+ }
+ };
+
virtual bool notify_about_to_close() {
auto it = observers_.notify();
while (it.has_next()) {
@@ -1110,7 +1211,31 @@ protected:
return false;
}
- virtual gint add_extra_widgets(GtkGrid* UNUSED(grid), gint row) {
+ static void safe_entry_from_filename(GtkWidget* widget,
+ std::string const& filename) {
+ auto str = g_filename_to_utf8(filename.data(), filename.size(),
+ nullptr, nullptr, nullptr);
+ if (str) {
+ gtk_entry_set_text(GTK_ENTRY(widget), str);
+ g_free(str);
+ } else {
+ gtk_entry_set_text(GTK_ENTRY(widget), "");
+ }
+ }
+
+ static void show_filechooser(GtkButton* UNUSED(button), gpointer user_data) {
+ auto value = reinterpret_cast<FileValue*>(user_data);
+ auto ret = gtk_native_dialog_run(GTK_NATIVE_DIALOG(value->chooser_));
+ if (ret == GTK_RESPONSE_ACCEPT) {
+ auto file = gtk_file_chooser_get_filename(value->chooser_);
+ value->value_ = file;
+ g_free(file);
+ safe_entry_from_filename(value->entry_, value->value_);
+ }
+ }
+
+ virtual gint add_extra_widgets(GtkGrid* UNUSED(grid), gint row,
+ gint UNUSED(colspan)) {
return row;
}
@@ -1157,10 +1282,10 @@ public:
}
private:
- gint add_extra_widgets(GtkGrid* layout, gint row) override {
+ gint add_extra_widgets(GtkGrid* layout, gint row, gint colspan) override {
assert(!spinner_);
spinner_ = gtk_spinner_new();
- gtk_grid_attach(layout, spinner_, 0, row++, 2, 1);
+ gtk_grid_attach(layout, spinner_, 0, row++, colspan, 1);
return row;
}