summaryrefslogtreecommitdiffstats
path: root/src/ui/dialog/startup.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/dialog/startup.cpp')
-rw-r--r--src/ui/dialog/startup.cpp849
1 files changed, 849 insertions, 0 deletions
diff --git a/src/ui/dialog/startup.cpp b/src/ui/dialog/startup.cpp
new file mode 100644
index 0000000..21510cf
--- /dev/null
+++ b/src/ui/dialog/startup.cpp
@@ -0,0 +1,849 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief A dialog for the about screen
+ *
+ * Copyright (C) Martin Owens 2019 <doctormo@gmail.com>
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "startup.h"
+
+#include <fstream>
+#include <glibmm/i18n.h>
+#include <streambuf>
+#include <string>
+
+#include "color-rgba.h"
+#include "file.h"
+#include "inkscape-application.h"
+#include "inkscape-version-info.h"
+#include "inkscape-version.h"
+#include "inkscape.h"
+#include "io/resource.h"
+#include "object/sp-namedview.h"
+#include "preferences.h"
+#include "ui/dialog/filedialog.h"
+#include "ui/shortcuts.h"
+#include "ui/themes.h"
+#include "ui/util.h"
+#include "util/units.h"
+
+using namespace Inkscape::IO;
+using namespace Inkscape::UI::View;
+using Inkscape::Util::unit_table;
+
+namespace Inkscape {
+namespace UI {
+namespace Dialog {
+
+class NameIdCols: public Gtk::TreeModel::ColumnRecord {
+ public:
+ // These types must match those for the model in the .glade file
+ NameIdCols() {
+ this->add(this->col_name);
+ this->add(this->col_id);
+ }
+ Gtk::TreeModelColumn<Glib::ustring> col_name;
+ Gtk::TreeModelColumn<Glib::ustring> col_id;
+};
+
+class CanvasCols: public Gtk::TreeModel::ColumnRecord {
+ public:
+ // These types must match those for the model in the .glade file
+ CanvasCols() {
+ this->add(this->id);
+ this->add(this->name);
+ this->add(this->icon_filename);
+ this->add(this->pagecolor);
+ this->add(this->checkered);
+ this->add(this->bordercolor);
+ this->add(this->shadow);
+ }
+ Gtk::TreeModelColumn<Glib::ustring> id;
+ Gtk::TreeModelColumn<Glib::ustring> name;
+ Gtk::TreeModelColumn<Glib::ustring> icon_filename;
+ Gtk::TreeModelColumn<Glib::ustring> pagecolor;
+ Gtk::TreeModelColumn<bool> checkered;
+ Gtk::TreeModelColumn<Glib::ustring> bordercolor;
+ Gtk::TreeModelColumn<bool> shadow;
+};
+
+class TemplateCols: public Gtk::TreeModel::ColumnRecord {
+ public:
+ // These types must match those for the model in the .glade file
+ TemplateCols() {
+ this->add(this->name);
+ this->add(this->icon);
+ this->add(this->filename);
+ this->add(this->width);
+ this->add(this->height);
+ }
+ Gtk::TreeModelColumn<Glib::ustring> name;
+ Gtk::TreeModelColumn<Glib::ustring> icon;
+ Gtk::TreeModelColumn<Glib::ustring> filename;
+ Gtk::TreeModelColumn<Glib::ustring> width;
+ Gtk::TreeModelColumn<Glib::ustring> height;
+};
+
+
+class ThemeCols: public Gtk::TreeModel::ColumnRecord {
+ public:
+ // These types must match those for the model in the .glade file
+ ThemeCols() {
+ this->add(this->id);
+ this->add(this->name);
+ this->add(this->theme);
+ this->add(this->icons);
+ this->add(this->base);
+ this->add(this->base_dark);
+ this->add(this->success);
+ this->add(this->warn);
+ this->add(this->error);
+ this->add(this->symbolic);
+ this->add(this->smallicons);
+ this->add(this->enabled);
+ }
+ Gtk::TreeModelColumn<Glib::ustring> id;
+ Gtk::TreeModelColumn<Glib::ustring> name;
+ Gtk::TreeModelColumn<Glib::ustring> theme;
+ Gtk::TreeModelColumn<Glib::ustring> icons;
+ Gtk::TreeModelColumn<Glib::ustring> base;
+ Gtk::TreeModelColumn<Glib::ustring> base_dark;
+ Gtk::TreeModelColumn<Glib::ustring> success;
+ Gtk::TreeModelColumn<Glib::ustring> warn;
+ Gtk::TreeModelColumn<Glib::ustring> error;
+ Gtk::TreeModelColumn<bool> symbolic;
+ Gtk::TreeModelColumn<bool> smallicons;
+ Gtk::TreeModelColumn<bool> enabled;
+};
+
+/**
+ * Color is store as a string in the form #RRGGBBAA, '0' means "unset"
+ *
+ * @param color - The string color from glade.
+ */
+unsigned int get_color_value(const Glib::ustring color)
+{
+ Gdk::RGBA gdk_color = Gdk::RGBA(color);
+ ColorRGBA sp_color(gdk_color.get_red(), gdk_color.get_green(),
+ gdk_color.get_blue(), gdk_color.get_alpha());
+ return sp_color.getIntValue();
+}
+
+StartScreen::StartScreen()
+ : Gtk::Dialog()
+{
+ set_can_focus(true);
+ grab_focus();
+ set_can_default(true);
+ grab_default();
+ set_urgency_hint(true); // Draw user's attention to this window!
+ set_modal(true);
+ set_position(Gtk::WIN_POS_CENTER_ALWAYS);
+ set_default_size(700, 360);
+
+ Glib::ustring gladefile = Resource::get_filename(Resource::UIS, "inkscape-start.glade");
+
+ try {
+ builder = Gtk::Builder::create_from_file(gladefile);
+ } catch (const Glib::Error &ex) {
+ g_error("Glade file loading failed for boot screen");
+ // cleanup?
+ }
+
+ // Get window from Glade file.
+ builder->get_widget("start-screen-window", window);
+ set_name("start-screen-window");
+ set_title(Inkscape::inkscape_version());
+
+ // Get references to various widgets used globally.
+ builder->get_widget("tabs", tabs);
+ builder->get_widget("kinds", kinds);
+ builder->get_widget("banner", banners);
+ builder->get_widget("themes", themes);
+ builder->get_widget("recent_treeview", recent_treeview);
+
+ // Get references to various widget used locally. (In order of appearance.)
+ Gtk::ComboBox* canvas = nullptr;
+ Gtk::ComboBox* keys = nullptr;
+ Gtk::Button* save = nullptr;
+ Gtk::Button* thanks = nullptr;
+ Gtk::Button* close_btn = nullptr;
+ Gtk::Button* new_btn = nullptr;
+ Gtk::Button* show_toggle = nullptr;
+ Gtk::Switch* dark_toggle = nullptr;
+ builder->get_widget("canvas", canvas);
+ builder->get_widget("keys", keys);
+ builder->get_widget("save", save);
+ builder->get_widget("thanks", thanks);
+ builder->get_widget("show_toggle", show_toggle);
+ builder->get_widget("dark_toggle", dark_toggle);
+ builder->get_widget("load", load_btn);
+ builder->get_widget("new", new_btn);
+ builder->get_widget("close_window", close_btn);
+
+ // Unparent to move to our dialog window.
+ auto parent = banners->get_parent();
+ parent->remove(*banners);
+ parent->remove(*tabs);
+
+ // Add signals and setup things.
+ auto prefs = Inkscape::Preferences::get();
+
+ tabs->signal_switch_page().connect(sigc::mem_fun(*this, &StartScreen::notebook_switch));
+
+ // Setup the lists of items
+ enlist_recent_files();
+ enlist_keys();
+ filter_themes();
+ set_active_combo("themes", prefs->getString("/options/boot/theme"));
+ set_active_combo("canvas", prefs->getString("/options/boot/canvas"));
+
+ // initialise dark depending on prefs and background
+ refresh_dark_switch();
+
+ // Welcome! tab
+ std::string welcome_text_file = Resource::get_filename_string(Resource::SCREENS, "start-welcome-text.svg", true);
+ Gtk::Image *welcome_text;
+ builder->get_widget("welcome_text", welcome_text);
+ welcome_text->set(welcome_text_file);
+
+ canvas->signal_changed().connect(sigc::mem_fun(*this, &StartScreen::canvas_changed));
+ keys->signal_changed().connect(sigc::mem_fun(*this, &StartScreen::keyboard_changed));
+ themes->signal_changed().connect(sigc::mem_fun(*this, &StartScreen::theme_changed));
+ dark_toggle->property_active().signal_changed().connect(sigc::mem_fun(*this, &StartScreen::theme_changed));
+ save->signal_clicked().connect(sigc::bind<Gtk::Button *>(sigc::mem_fun(*this, &StartScreen::notebook_next), save));
+
+ // "Supported by You" tab
+ thanks->signal_clicked().connect(sigc::bind<Gtk::Button *>(sigc::mem_fun(*this, &StartScreen::notebook_next), thanks));
+
+ // "Time to Draw" tab
+ recent_treeview->signal_row_activated().connect(sigc::hide(sigc::hide((sigc::mem_fun(*this, &StartScreen::load_document)))));
+ recent_treeview->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &StartScreen::on_recent_changed));
+ kinds->signal_switch_page().connect(sigc::mem_fun(*this, &StartScreen::on_kind_changed));
+ load_btn->set_sensitive(true);
+
+ for (auto widget : kinds->get_children()) {
+ auto container = dynamic_cast<Gtk::Container *>(widget);
+ if (container) {
+ widget = container->get_children()[0];
+ }
+ auto template_list = dynamic_cast<Gtk::IconView *>(widget);
+ if (template_list) {
+ template_list->signal_selection_changed().connect([=]() { response(GTK_RESPONSE_APPLY); });
+ }
+ }
+
+ show_toggle->signal_clicked().connect(sigc::mem_fun(*this, &StartScreen::show_toggle));
+ load_btn->signal_clicked().connect(sigc::mem_fun(*this, &StartScreen::load_document));
+ new_btn->signal_clicked().connect([=] { response(GTK_RESPONSE_APPLY); });
+ close_btn->signal_clicked().connect([=] { response(GTK_RESPONSE_CANCEL); });
+
+ // Reparent to our dialog window
+ set_titlebar(*banners);
+ Gtk::Box* box = get_content_area();
+ box->add(*tabs);
+
+ // Show the first tab ONLY on the first run for this version
+ std::string opt_shown = "/options/boot/shown/ver";
+ opt_shown += Inkscape::version_string_without_revision;
+ _first_open = prefs->getBool(opt_shown, false);
+ if(!_first_open) {
+ theme_changed();
+ tabs->set_current_page(0);
+ prefs->setBool(opt_shown, true);
+ } else {
+ tabs->set_current_page(2);
+ notebook_switch(nullptr, 2);
+ }
+
+ set_modal(true);
+ set_position(Gtk::WIN_POS_CENTER_ALWAYS);
+ property_resizable() = false;
+ set_default_size(700, 360);
+ show();
+}
+
+StartScreen::~StartScreen()
+{
+ // These are "owned" by builder... don't delete them!
+ banners->get_parent()->remove(*banners);
+ tabs->get_parent()->remove(*tabs);
+}
+
+/**
+ * Return the active row of the named combo box.
+ *
+ * @param widget_name - The name of the widget in the glade file
+ * @return Gtk Row object ready for use.
+ * @throws Three errors depending on where it failed.
+ */
+Gtk::TreeModel::Row
+StartScreen::active_combo(std::string widget_name)
+{
+ Gtk::ComboBox *combo;
+ builder->get_widget(widget_name, combo);
+ if (!combo) throw 1;
+ Gtk::TreeModel::iterator iter = combo->get_active();
+ if (!iter) throw 2;
+ Gtk::TreeModel::Row row = *iter;
+ if (!row) throw 3;
+ return row;
+}
+
+/**
+ * Set the active item in the combo based on the unique_id (column set in glade)
+ *
+ * @param widget_name - The name of the widget in the glade file
+ * @param unique_id - The column id to activate, sets to first item if blank.
+ */
+void
+StartScreen::set_active_combo(std::string widget_name, std::string unique_id)
+{
+ Gtk::ComboBox *combo;
+ builder->get_widget(widget_name, combo);
+ if (combo) {
+ if (unique_id.empty()) {
+ combo->set_active(0); // Select the first
+ } else if(!combo->set_active_id(unique_id)) {
+ combo->set_active(-1); // Select nothing
+ }
+ }
+}
+
+/**
+ * When a notbook is switched, reveal the right banner image (gtk signal).
+ */
+void
+StartScreen::notebook_switch(Gtk::Widget *tab, guint page_num)
+{
+ int page = 0;
+ for (auto banner : banners->get_children()) {
+ if (auto revealer = dynamic_cast<Gtk::Revealer *>(banner)) {
+ revealer->set_reveal_child(page == page_num);
+ page++;
+ }
+ }
+}
+
+void
+StartScreen::enlist_recent_files()
+{
+ NameIdCols cols;
+ if (!recent_treeview) return;
+ // We're not sure why we have to ask C for the TreeStore object
+ auto store = Glib::wrap(GTK_LIST_STORE(gtk_tree_view_get_model(recent_treeview->gobj())));
+ store->clear();
+
+ // Open [other]
+ Gtk::TreeModel::Row first_row = *(store->append());
+ first_row[cols.col_name] = _("Browse for other files...");
+ first_row[cols.col_id] = "";
+ recent_treeview->get_selection()->select(store->get_path(first_row));
+
+ Glib::RefPtr<Gtk::RecentManager> manager = Gtk::RecentManager::get_default();
+ for (auto item : manager->get_items()) {
+ if (item->has_application(g_get_prgname())
+ || item->has_application("org.inkscape.Inkscape")
+ || item->has_application("inkscape")
+ || item->has_application("inkscape.exe")
+ ) {
+ // This uri is a GVFS uri, so parse it with that or it will fail.
+ auto file = Gio::File::create_for_uri(item->get_uri());
+ std::string path = file->get_path();
+ if (!path.empty() && Glib::file_test(path, Glib::FILE_TEST_IS_REGULAR)
+ && item->get_mime_type() == "image/svg+xml") {
+ Gtk::TreeModel::Row row = *(store->append());
+ row[cols.col_name] = item->get_display_name();
+ row[cols.col_id] = item->get_uri();
+ }
+ }
+ }
+}
+
+/**
+ * Called when a new recent document is selected.
+ */
+void
+StartScreen::on_recent_changed()
+{
+ // TODO: In the future this is where previews and other information can be loaded.
+}
+
+/**
+ * Called when the left side tabs are changed.
+ */
+void
+StartScreen::on_kind_changed(Gtk::Widget *tab, guint page_num)
+{
+ if (page_num == 0) {
+ load_btn->show();
+ } else {
+ load_btn->hide();
+ }
+}
+
+/**
+ * Called when new button clicked or template is double clicked, or escape pressed.
+ */
+void
+StartScreen::new_document()
+{
+ Glib::ustring filename = sp_file_default_template_uri();
+ Glib::ustring width = "";
+ Glib::ustring height = "";
+
+ // Find requested file name.
+ Glib::RefPtr<Gio::File> file;
+ if (kinds) {
+ Gtk::Widget *selected_widget = kinds->get_children()[kinds->get_current_page()];
+ auto container = dynamic_cast<Gtk::Container *>(selected_widget);
+ if (container) {
+ selected_widget = container->get_children()[0];
+ }
+
+ auto template_list = dynamic_cast<Gtk::IconView *>(selected_widget);
+ if (template_list) {
+ auto items = template_list->get_selected_items();
+ if (!items.empty()) {
+ auto iter = template_list->get_model()->get_iter(items[0]);
+ Gtk::TreeModel::Row row = *iter;
+ if (row) {
+ TemplateCols cols;
+ Glib::ustring template_filename = row[cols.filename];
+ if (!(template_filename == "-")) {
+ filename = Resource::get_filename_string(
+ Resource::TEMPLATES, template_filename.c_str(), true);
+ }
+ // This isn't used on opening, just for checking it's existence.
+ file = Gio::File::create_for_path(filename);
+ width = row[cols.width];
+ height = row[cols.height];
+ }
+ }
+ }
+ }
+
+ if (!file) {
+ // Failure to open, so open up a new document instead.
+ file = Gio::File::create_for_path(filename);
+ }
+
+ if (!file) {
+ // We're really messed up... so give up!
+ std::cerr << "StartScreen::load_document(): Failed to find: " << filename << std::endl;
+ return;
+ }
+
+ // Now we have filename, open document.
+ auto app = InkscapeApplication::instance();
+
+ // If it was a template file, modify the document according to user's input.
+ _document = app->document_new (filename);
+ auto nv = _document->getNamedView();
+
+ if (!width.empty()) {
+ // Set the width, height and default display units for the selected template
+ auto q_width = unit_table.parseQuantity(width);
+ _document->setWidthAndHeight(q_width, unit_table.parseQuantity(height), true);
+ nv->setAttribute("inkscape:document-units", q_width.unit->abbr);
+ _document->setDocumentScale(1.0);
+ }
+
+ DocumentUndo::clearUndo(_document);
+ _document->setModifiedSinceSave(false);
+}
+
+/**
+ * Called when load button clicked.
+ */
+void
+StartScreen::load_document()
+{
+ NameIdCols cols;
+ auto prefs = Inkscape::Preferences::get();
+ auto app = InkscapeApplication::instance();
+
+ if (!recent_treeview)
+ return;
+
+ auto iter = recent_treeview->get_selection()->get_selected();
+ if (iter) {
+ Gtk::TreeModel::Row row = *iter;
+ if (row) {
+ Glib::ustring _file = row[cols.col_id];
+ Glib::RefPtr<Gio::File> file;
+
+ if (!_file.empty()) {
+ file = Gio::File::create_for_uri(_file);
+ } else {
+ Glib::ustring open_path = prefs->getString("/dialogs/open/path");
+ if (open_path.empty()) {
+ open_path = g_get_home_dir();
+ open_path.append(G_DIR_SEPARATOR_S);
+ }
+
+ // Browse for file instead
+ auto browser = Inkscape::UI::Dialog::FileOpenDialog::create(
+ *this, open_path, Inkscape::UI::Dialog::SVG_TYPES, _("Open a different file"));
+
+ if (browser->show()) {
+ prefs->setString("/dialogs/open/path", browser->getCurrentDirectory());
+ file = Gio::File::create_for_path(browser->getFilename());
+ delete browser;
+ } else {
+ delete browser;
+ return; // Cancel
+ }
+ }
+
+ // Now we have filename, open document.
+ bool canceled = false;
+ _document = app->document_open(file, &canceled);
+
+ if (!canceled && _document) {
+ // We're done, hand back to app.
+ response(GTK_RESPONSE_OK);
+ }
+ }
+ }
+}
+
+/**
+ * When a button needs to go to the next notebook page.
+ */
+void
+StartScreen::notebook_next(Gtk::Widget *button)
+{
+ int page = tabs->get_current_page();
+ if (page == 2) {
+ response(GTK_RESPONSE_CANCEL); // Only occurs from keypress.
+ } else {
+ tabs->set_current_page(page + 1);
+ }
+}
+
+/**
+ * When a key is pressed in the main window.
+ */
+bool
+StartScreen::on_key_press_event(GdkEventKey* event)
+{
+#ifdef GDK_WINDOWING_QUARTZ
+ // On macOS only, if user press Cmd+Q => exit
+ if (event->keyval == 'q' && event->state == (GDK_MOD2_MASK | GDK_META_MASK)) {
+ close();
+ return false;
+ }
+#endif
+ switch (event->keyval) {
+ case GDK_KEY_Escape:
+ // Prevent loading any selected items
+ response(GTK_RESPONSE_CANCEL);
+ return true;
+ case GDK_KEY_Return:
+ notebook_next(nullptr);
+ return true;
+ }
+
+ return false;
+}
+
+void
+StartScreen::on_response(int response_id)
+{
+ if (response_id == GTK_RESPONSE_DELETE_EVENT) {
+ // Don't open a window for force closing.
+ return;
+ }
+ if (response_id == GTK_RESPONSE_CANCEL) {
+ kinds = nullptr;
+ if (_first_open) {
+ // Disable the screen if the user cancels on their first run.
+ auto prefs = Inkscape::Preferences::get();
+ prefs->setBool("/options/boot/enabled", false);
+ }
+ }
+ if (response_id != GTK_RESPONSE_OK) {
+ // Most actions cause a new document to appear.
+ new_document();
+ }
+}
+
+void
+StartScreen::show_toggle()
+{
+ Gtk::ToggleButton *button;
+ builder->get_widget("show_toggle", button);
+ if (button) {
+ auto prefs = Inkscape::Preferences::get();
+ prefs->setBool("/options/boot/enabled", button->get_active());
+ } else {
+ g_warning("Can't find toggle button widget.");
+ }
+}
+
+/**
+ * Refresh theme in-place so user can see a semi-preview. This theme selection
+ * is not meant to be perfect, but hint to the user that they can set the
+ * theme if they want.
+ *
+ * @param theme_name - The name of the theme to load.
+ */
+void
+StartScreen::refresh_theme(Glib::ustring theme_name)
+{
+ auto const screen = Gdk::Screen::get_default();
+ if (INKSCAPE.themecontext->getContrastThemeProvider()) {
+ Gtk::StyleContext::remove_provider_for_screen(screen, INKSCAPE.themecontext->getContrastThemeProvider());
+ }
+ auto settings = Gtk::Settings::get_default();
+
+ auto prefs = Inkscape::Preferences::get();
+
+ settings->property_gtk_theme_name() = theme_name;
+ settings->property_gtk_application_prefer_dark_theme() = prefs->getBool("/theme/preferDarkTheme", true);
+ settings->property_gtk_icon_theme_name() = prefs->getString("/theme/iconTheme", prefs->getString("/theme/defaultIconTheme", ""));
+
+ if (prefs->getBool("/theme/symbolicIcons", false)) {
+ get_style_context()->add_class("symbolic");
+ get_style_context()->remove_class("regular");
+ } else {
+ get_style_context()->add_class("regular");
+ get_style_context()->remove_class("symbolic");
+ }
+
+ if (INKSCAPE.themecontext->getColorizeProvider()) {
+ Gtk::StyleContext::remove_provider_for_screen(screen, INKSCAPE.themecontext->getColorizeProvider());
+ }
+ if (!prefs->getBool("/theme/symbolicDefaultHighColors", false)) {
+ Gtk::CssProvider::create();
+ Glib::ustring css_str = INKSCAPE.themecontext->get_symbolic_colors();
+ try {
+ INKSCAPE.themecontext->getColorizeProvider()->load_from_data(css_str);
+ } catch (const Gtk::CssProviderError &ex) {
+ g_critical("CSSProviderError::load_from_data(): failed to load '%s'\n(%s)", css_str.c_str(), ex.what().c_str());
+ }
+ Gtk::StyleContext::add_provider_for_screen(screen, INKSCAPE.themecontext->getColorizeProvider(),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ }
+ // set dark switch and disable if there is no prefer option for dark
+ refresh_dark_switch();
+
+ INKSCAPE.themecontext->getChangeThemeSignal().emit();
+}
+
+/**
+ * Set the theme, icon pack and other theme options from a set defined
+ * in the glade file. The combo box has a number of columns with the needed
+ * data describing how to set up the theme.
+ */
+void
+StartScreen::theme_changed()
+{
+ auto prefs = Inkscape::Preferences::get();
+
+ ThemeCols cols;
+ try {
+ auto row = active_combo("themes");
+ Glib::ustring theme_id = row[cols.id];
+ if (theme_id == "custom") return;
+ prefs->setString("/options/boot/theme", row[cols.id]);
+
+ // Update theme from combo.
+ Glib::ustring icons = row[cols.icons];
+ prefs->setBool("/toolbox/tools/small", row[cols.smallicons]);
+ prefs->setString("/theme/gtkTheme", row[cols.theme]);
+ prefs->setString("/theme/iconTheme", icons);
+ prefs->setBool("/theme/symbolicIcons", row[cols.symbolic]);
+
+ Gtk::Switch* dark_toggle = nullptr;
+ builder->get_widget("dark_toggle", dark_toggle);
+ bool is_dark = dark_toggle->get_active();
+ prefs->setBool("/theme/preferDarkTheme", is_dark);
+ prefs->setBool("/theme/darkTheme", is_dark);
+ // Symbolic icon colours
+ if (get_color_value(row[cols.base]) == 0) {
+ prefs->setBool("/theme/symbolicDefaultBaseColors", true);
+ prefs->setBool("/theme/symbolicDefaultHighColors", true);
+ } else {
+ Glib::ustring prefix = "/theme/" + icons;
+ prefs->setBool("/theme/symbolicDefaultBaseColors", false);
+ prefs->setBool("/theme/symbolicDefaultHighColors", false);
+ if (is_dark) {
+ prefs->setUInt(prefix + "/symbolicBaseColor", get_color_value(row[cols.base_dark]));
+ } else {
+ prefs->setUInt(prefix + "/symbolicBaseColor", get_color_value(row[cols.base]));
+ }
+ prefs->setUInt(prefix + "/symbolicSuccessColor", get_color_value(row[cols.success]));
+ prefs->setUInt(prefix + "/symbolicWarningColor", get_color_value(row[cols.warn]));
+ prefs->setUInt(prefix + "/symbolicErrorColor", get_color_value(row[cols.error]));
+ }
+
+ refresh_theme(prefs->getString("/theme/gtkTheme", prefs->getString("/theme/defaultGtkTheme", "")));
+ } catch(int e) {
+ g_warning("Couldn't find theme value.");
+ }
+}
+
+/**
+ * Called when the canvas dropdown changes.
+ */
+void
+StartScreen::canvas_changed()
+{
+ CanvasCols cols;
+ try {
+ auto row = active_combo("canvas");
+
+ auto prefs = Inkscape::Preferences::get();
+ prefs->setString("/options/boot/canvas", row[cols.id]);
+
+ Gdk::RGBA gdk_color = Gdk::RGBA(row[cols.pagecolor]);
+ SPColor sp_color(gdk_color.get_red(), gdk_color.get_green(), gdk_color.get_blue());
+ prefs->setString("/template/base/pagecolor", sp_color.toString());
+ prefs->setDouble("/template/base/pageopacity", gdk_color.get_alpha());
+
+ Gdk::RGBA gdk_border = Gdk::RGBA(row[cols.bordercolor]);
+ SPColor sp_border(gdk_border.get_red(), gdk_border.get_green(), gdk_border.get_blue());
+ prefs->setString("/template/base/bordercolor", sp_border.toString());
+ prefs->setDouble("/template/base/borderopacity", gdk_border.get_alpha());
+
+ prefs->setBool("/template/base/pagecheckerboard", row[cols.checkered]);
+ prefs->setInt("/template/base/pageshadow", row[cols.shadow] ? 2 : 0);
+
+ } catch(int e) {
+ g_warning("Couldn't find canvas value.");
+ }
+}
+
+void
+StartScreen::filter_themes()
+{
+ ThemeCols cols;
+ // We need to disable themes which aren't available.
+ auto store = Glib::wrap(GTK_LIST_STORE(gtk_combo_box_get_model(themes->gobj())));
+ auto available = INKSCAPE.themecontext->get_available_themes();
+
+ // Detect use of custom theme here, detect defaults used in many systems.
+ auto settings = Gtk::Settings::get_default();
+ Glib::ustring theme_name = settings->property_gtk_theme_name();
+ Glib::ustring icons_name = settings->property_gtk_icon_theme_name();
+
+ bool has_system_theme = false;
+ if (theme_name != "Adwaita" || icons_name != "hicolor") {
+ has_system_theme = true;
+ /* Enable if/when we want custom to be the default.
+ if (prefs->getString("/options/boot/theme").empty()) {
+ prefs->setString("/options/boot/theme", "system")
+ theme_changed();
+ }*/
+ }
+
+ for(auto row : store->children()) {
+ Glib::ustring theme = row[cols.theme];
+ if (!row[cols.enabled]) {
+ // Available themes; We only "enable" them, we don't disable them.
+ row[cols.enabled] = available.find(theme) != available.end();
+ } else if(row[cols.id] == "system" && !has_system_theme) {
+ // Disable system theme option if not available.
+ row[cols.enabled] = false;
+ }
+ }
+}
+
+void
+StartScreen::enlist_keys()
+{
+ NameIdCols cols;
+ Gtk::ComboBox *keys;
+ builder->get_widget("keys", keys);
+ if (!keys) return;
+
+ auto store = Glib::wrap(GTK_LIST_STORE(gtk_combo_box_get_model(keys->gobj())));
+ store->clear();
+
+ for(auto item: Inkscape::Shortcuts::get_file_names()){
+ Gtk::TreeModel::Row row = *(store->append());
+ row[cols.col_name] = item.first;
+ row[cols.col_id] = item.second;
+ }
+
+ auto prefs = Inkscape::Preferences::get();
+ auto current = prefs->getString("/options/kbshortcuts/shortcutfile");
+ if (current.empty()) {
+ current = "inkscape.xml";
+ }
+ keys->set_active_id(current);
+}
+
+/**
+ * Set the keys file based on the keys set in the enlist above
+ */
+void
+StartScreen::keyboard_changed()
+{
+ NameIdCols cols;
+ try {
+ auto row = active_combo("keys");
+ auto prefs = Inkscape::Preferences::get();
+ Glib::ustring set_to = row[cols.col_id];
+ prefs->setString("/options/kbshortcuts/shortcutfile", set_to);
+ Inkscape::Shortcuts::getInstance().init();
+
+ Gtk::InfoBar* keys_warning;
+ builder->get_widget("keys_warning", keys_warning);
+ if (set_to != "inkscape.xml" && set_to != "default.xml") {
+ keys_warning->set_message_type(Gtk::MessageType::MESSAGE_WARNING);
+ keys_warning->show();
+ } else {
+ keys_warning->hide();
+ }
+ } catch(int e) {
+ g_warning("Couldn't find keys value.");
+ }
+}
+
+/**
+ * Set Dark Switch based on current selected theme.
+ * We will disable switch if current theme doesn't have prefer dark theme option.
+ */
+
+void StartScreen::refresh_dark_switch()
+{
+ auto prefs = Inkscape::Preferences::get();
+
+ Gtk::Container *window = dynamic_cast<Gtk::Container *>(get_toplevel());
+ bool dark = INKSCAPE.themecontext->isCurrentThemeDark(window);
+ prefs->setBool("/theme/preferDarkTheme", dark);
+ prefs->setBool("/theme/darkTheme", dark);
+
+ auto themes = INKSCAPE.themecontext->get_available_themes();
+ Glib::ustring current_theme = prefs->getString("/theme/gtkTheme", prefs->getString("/theme/defaultGtkTheme", ""));
+
+ Gtk::Switch *dark_toggle = nullptr;
+ builder->get_widget("dark_toggle", dark_toggle);
+
+ if (!themes[current_theme]) {
+ dark_toggle->set_sensitive(false);
+ } else {
+ dark_toggle->set_sensitive(true);
+ }
+ dark_toggle->set_active(dark);
+}
+
+} // namespace Dialog
+} // namespace UI
+} // namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :