diff options
Diffstat (limited to '')
-rw-r--r-- | src/ui/dialog/dialog-base.cpp | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/src/ui/dialog/dialog-base.cpp b/src/ui/dialog/dialog-base.cpp new file mode 100644 index 0000000..8ddc5c4 --- /dev/null +++ b/src/ui/dialog/dialog-base.cpp @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/** @file + * @brief A base class for all dialogs. + * + * Authors: see git history + * Tavmjong Bah + * + * Copyright (c) 2018 Tavmjong Bah, Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "dialog-base.h" + +#include <glibmm/i18n.h> +#include <glibmm/main.h> +#include <glibmm/refptr.h> +#include <gtkmm/cssprovider.h> +#include <gtkmm/notebook.h> +#include <gtkmm/scrolledwindow.h> +#include <iostream> + +#include "inkscape.h" +#include "desktop.h" +#include "ui/dialog/dialog-data.h" +#include "ui/dialog/dialog-notebook.h" +#include "ui/dialog-events.h" +// get_latin_keyval +#include "ui/tools/tool-base.h" +#include "widgets/spw-utilities.h" +#include "ui/widget/canvas.h" +#include "ui/util.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + +/** + * DialogBase constructor. + * + * @param prefs_path characteristic path to load/save dialog position. + * @param dialog_type is the "type" string for the dialog. + */ +DialogBase::DialogBase(gchar const *prefs_path, Glib::ustring dialog_type) + : Gtk::Box(Gtk::ORIENTATION_VERTICAL) + , desktop(nullptr) + , document(nullptr) + , selection(nullptr) + , _name("DialogBase") + , _prefs_path(prefs_path) + , _dialog_type(dialog_type) + , _app(InkscapeApplication::instance()) +{ + auto const &dialog_data = get_dialog_data(); + + // Derive a pretty display name for the dialog. + auto it = dialog_data.find(dialog_type); + if (it != dialog_data.end()) { + + _name = it->second.label; // Already translated + + // remove ellipsis and mnemonics + int pos = _name.find("...", 0); + if (pos >= 0 && pos < _name.length() - 2) { + _name.erase(pos, 3); + } + pos = _name.find("…", 0); + if (pos >= 0 && pos < _name.length()) { + _name.erase(pos, 1); + } + pos = _name.find("_", 0); + if (pos >= 0 && pos < _name.length()) { + _name.erase(pos, 1); + } + } + + set_name(_dialog_type); // Essential for dialog functionality + property_margin().set_value(1); // Essential for dialog UI + ensure_size(); +} + +DialogBase::~DialogBase() { +#ifdef _WIN32 + // this is bad, but it supposedly fixes some resizng problem on Windows + ensure_size(); +#endif + + unsetDesktop(); +}; + +void DialogBase::ensure_size() { + if (desktop) { + resize_widget_children(desktop->getToplevel()); + } +} + +void DialogBase::on_map() { + // Update asks the dialogs if they need their Gtk widgets updated. + update(); + // Set the desktop on_map, although we might want to be smarter about this. + // Note: Inkscape::Application::instance().active_desktop() is used here, as it contains current desktop at + // the time of dialog creation. Formerly used _app.get_active_view() did not at application start-up. + setDesktop(Inkscape::Application::instance().active_desktop()); + parent_type::on_map(); +} + +bool DialogBase::on_key_press_event(GdkEventKey* key_event) { + switch (Inkscape::UI::Tools::get_latin_keyval(key_event)) { + case GDK_KEY_Escape: + defocus_dialog(); + return true; + } + + return parent_type::on_key_press_event(key_event); +} + + +/** + * Highlight notebook where dialog already exists. + */ +void DialogBase::blink() +{ + Gtk::Notebook *notebook = dynamic_cast<Gtk::Notebook *>(get_parent()); + if (notebook && notebook->get_is_drawable()) { + // Switch notebook to this dialog. + notebook->set_current_page(notebook->page_num(*this)); + notebook->get_style_context()->add_class("blink"); + + // Add timer to turn off blink. + sigc::slot<bool> slot = sigc::mem_fun(*this, &DialogBase::blink_off); + sigc::connection connection = Glib::signal_timeout().connect(slot, 1000); // msec + } +} + +void DialogBase::focus_dialog() { + if (auto window = dynamic_cast<Gtk::Window*>(get_toplevel())) { + window->present(); + } + + // widget that had focus, if any + if (auto child = get_focus_child()) { + child->grab_focus(); + } + else { + // find first focusable widget + if (auto child = sp_find_focusable_widget(this)) { + child->grab_focus(); + } + } +} + +void DialogBase::defocus_dialog() { + if (auto wnd = dynamic_cast<Gtk::Window*>(get_toplevel())) { + // defocus floating dialog: + sp_dialog_defocus_cpp(wnd); + + // for docked dialogs, move focus to canvas + if (auto desktop = getDesktop()) { + desktop->getCanvas()->grab_focus(); + } + } +} + +/** + * Callback to reset the dialog highlight. + */ +bool DialogBase::blink_off() +{ + Gtk::Notebook *notebook = dynamic_cast<Gtk::Notebook *>(get_parent()); + if (notebook && notebook->get_is_drawable()) { + notebook->get_style_context()->remove_class("blink"); + } + return false; +} + +/** + * Called when the desktop might have changed for this dialog. + */ +void DialogBase::setDesktop(SPDesktop *new_desktop) +{ + if (desktop == new_desktop) { + return; + } + + unsetDesktop(); + + if (new_desktop) { + desktop = new_desktop; + + if (desktop->selection) { + selection = desktop->selection; + _select_changed = selection->connectChanged(sigc::mem_fun(*this, &DialogBase::selectionChanged_impl)); + _select_modified = selection->connectModified(sigc::mem_fun(*this, &DialogBase::selectionModified_impl)); + } + + _doc_replaced = desktop->connectDocumentReplaced(sigc::hide<0>(sigc::mem_fun(*this, &DialogBase::setDocument))); + _desktop_destroyed = desktop->connectDestroy(sigc::mem_fun(*this, &DialogBase::desktopDestroyed)); + this->setDocument(desktop->getDocument()); + + if (desktop->selection) { + this->selectionChanged(selection); + } + set_sensitive(true); + } + + desktopReplaced(); +} + +// +void DialogBase::fix_inner_scroll(Gtk::Widget *scrollwindow) +{ + auto scrollwin = dynamic_cast<Gtk::ScrolledWindow *>(scrollwindow); + auto viewport = dynamic_cast<Gtk::ScrolledWindow *>(scrollwin->get_child()); + Gtk::Widget *child = nullptr; + if (viewport) { //some widgets has viewportother not + child = viewport->get_child(); + } else { + child = scrollwin->get_child(); + } + if (child && scrollwin) { + Glib::RefPtr<Gtk::Adjustment> adjustment = scrollwin->get_vadjustment(); + child->signal_scroll_event().connect([=](GdkEventScroll* event) { + auto container = dynamic_cast<Gtk::Container *>(this); + if (container) { + std::vector<Gtk::Widget*> widgets = container->get_children(); + if (widgets.size()) { + auto parentscroll = dynamic_cast<Gtk::ScrolledWindow *>(widgets[0]); + if (parentscroll) { + if (event->delta_y > 0 && (adjustment->get_value() + adjustment->get_page_size()) == adjustment->get_upper()) { + parentscroll->event((GdkEvent*)event); + return true; + } else if (event->delta_y < 0 && adjustment->get_value() == adjustment->get_lower()) { + parentscroll->event((GdkEvent*)event); + return true; + } + } + } + } + return false; + }); + } +} + +/** + * implementation method that call to main function only when tab is showing + */ +void +DialogBase::selectionChanged_impl(Inkscape::Selection *selection) { + if (_showing) { + selectionChanged(selection); + } +} + +/** + * implementation method that call to main function only when tab is showing + */ +void +DialogBase::selectionModified_impl(Inkscape::Selection *selection, guint flags) { + if (_showing) { + selectionModified(selection, flags); + } +} + +/** + * function called from notebook dialog that performs an update of the dialog and sets the dialog showing state true + */ +void +DialogBase::setShowing(bool showing) { + _showing = showing; + selectionChanged(getSelection()); +} + +/** + * Called to destruct desktops, must not call virtuals + */ +void DialogBase::unsetDesktop() +{ + desktop = nullptr; + document = nullptr; + selection = nullptr; + _desktop_destroyed.disconnect(); + _doc_replaced.disconnect(); + _select_changed.disconnect(); + _select_modified.disconnect(); +} + +void DialogBase::desktopDestroyed(SPDesktop* old_desktop) +{ + if (old_desktop == desktop && desktop) { + unsetDesktop(); + set_sensitive(false); + } +} + +/** + * Called when the document might have changed, called from setDesktop too. + */ +void DialogBase::setDocument(SPDocument *new_document) +{ + if (document != new_document) { + document = new_document; + documentReplaced(); + } +} + +} // 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 : |