diff options
Diffstat (limited to 'src/ui/widget/button.cpp')
-rw-r--r-- | src/ui/widget/button.cpp | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/src/ui/widget/button.cpp b/src/ui/widget/button.cpp new file mode 100644 index 0000000..f119c06 --- /dev/null +++ b/src/ui/widget/button.cpp @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * Generic button widget + *//* + * Authors: + * see git history + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * + * + * Copyright (C) 2018 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <glibmm.h> + +#include "button.h" +#include "helper/action-context.h" +#include "helper/action.h" +#include "shortcuts.h" +#include "ui/icon-loader.h" + +namespace Inkscape { +namespace UI { +namespace Widget { + +Button::~Button() +{ + if (_action) { + _c_set_active.disconnect(); + _c_set_sensitive.disconnect(); + g_object_unref(_action); + } + + if (_doubleclick_action) { + set_doubleclick_action(nullptr); + } +} + +void +Button::get_preferred_width_vfunc(int &minimal_width, int &natural_width) const +{ + auto child = get_child(); + + if (child) { + child->get_preferred_width(minimal_width, natural_width); + } else { + minimal_width = 0; + natural_width = 0; + } + + auto context = get_style_context(); + + auto padding = context->get_padding(context->get_state()); + auto border = context->get_border(context->get_state()); + + minimal_width += MAX(2, padding.get_left() + padding.get_right() + border.get_left() + border.get_right()); + natural_width += MAX(2, padding.get_left() + padding.get_right() + border.get_left() + border.get_right()); +} + +void +Button::get_preferred_height_vfunc(int &minimal_height, int &natural_height) const +{ + auto child = get_child(); + + if (child) { + child->get_preferred_height(minimal_height, natural_height); + } else { + minimal_height = 0; + natural_height = 0; + } + + auto context = get_style_context(); + + auto padding = context->get_padding(context->get_state()); + auto border = context->get_border(context->get_state()); + + minimal_height += MAX(2, padding.get_top() + padding.get_bottom() + border.get_top() + border.get_bottom()); + natural_height += MAX(2, padding.get_top() + padding.get_bottom() + border.get_top() + border.get_bottom()); +} + +void +Button::on_clicked() +{ + if (_type == BUTTON_TYPE_TOGGLE) { + Gtk::Button::on_clicked(); + } +} + +bool +Button::process_event(GdkEvent *event) +{ + switch (event->type) { + case GDK_2BUTTON_PRESS: + if (_doubleclick_action) { + sp_action_perform(_doubleclick_action, nullptr); + } + return true; + break; + default: + break; + } + + return false; +} + +void +Button::perform_action() +{ + if (_action) { + sp_action_perform(_action, nullptr); + } +} + +Button::Button(GtkIconSize size, + ButtonType type, + SPAction *action, + SPAction *doubleclick_action) + : + _action(nullptr), + _doubleclick_action(nullptr), + _type(type), + _lsize(CLAMP(size, GTK_ICON_SIZE_MENU, GTK_ICON_SIZE_DIALOG)) +{ + set_border_width(0); + + set_can_focus(false); + set_can_default(false); + + _on_clicked = signal_clicked().connect(sigc::mem_fun(*this, &Button::perform_action)); + + signal_event().connect(sigc::mem_fun(*this, &Button::process_event)); + + set_action(action); + + if (doubleclick_action) { + set_doubleclick_action(doubleclick_action); + } + + // The Inkscape style is no-relief buttons + set_relief(Gtk::RELIEF_NONE); +} + +void +Button::toggle_set_down(bool down) +{ + _on_clicked.block(); + set_active(down); + _on_clicked.unblock(); +} + +void +Button::set_doubleclick_action(SPAction *action) +{ + if (_doubleclick_action) { + g_object_unref(_doubleclick_action); + } + _doubleclick_action = action; + if (action) { + g_object_ref(action); + } +} + +void +Button::set_action(SPAction *action) +{ + Gtk::Widget *child; + + if (_action) { + _c_set_active.disconnect(); + _c_set_sensitive.disconnect(); + child = get_child(); + if (child) { + remove(); + } + g_object_unref(_action); + } + + _action = action; + if (action) { + g_object_ref(action); + _c_set_active = action->signal_set_active.connect( + sigc::mem_fun(*this, &Button::action_set_active)); + + _c_set_sensitive = action->signal_set_sensitive.connect( + sigc::mem_fun(*this, &Gtk::Widget::set_sensitive)); + + if (action->image) { + child = Glib::wrap(sp_get_icon_image(action->image, _lsize)); + child->show(); + add(*child); + } + } + + set_composed_tooltip(action); +} + +void +Button::action_set_active(bool active) +{ + if (_type != BUTTON_TYPE_TOGGLE) { + return; + } + + /* temporarily lobotomized until SPActions are per-view */ + if (false && !active != !get_active()) { + toggle_set_down(active); + } +} + +void +Button::set_composed_tooltip(SPAction *action) +{ + if (action) { + unsigned int shortcut = sp_shortcut_get_primary(action->verb); + if (shortcut != GDK_KEY_VoidSymbol) { + // there's both action and shortcut + + gchar *key = sp_shortcut_get_label(shortcut); + + gchar *tip = g_strdup_printf("%s (%s)", action->tip, key); + set_tooltip_text(tip); + g_free(tip); + g_free(key); + } else { + // action has no shortcut + set_tooltip_text(action->tip); + } + } else { + // no action + set_tooltip_text(nullptr); + } +} + +Button::Button(GtkIconSize size, + ButtonType type, + Inkscape::UI::View::View *view, + const gchar *name, + const gchar *tip) + : + _action(nullptr), + _doubleclick_action(nullptr), + _type(type), + _lsize(CLAMP(size, GTK_ICON_SIZE_MENU, GTK_ICON_SIZE_DIALOG)) +{ + set_border_width(0); + + set_can_focus(false); + set_can_default(false); + + _on_clicked = signal_clicked().connect(sigc::mem_fun(*this, &Button::perform_action)); + signal_event().connect(sigc::mem_fun(*this, &Button::process_event)); + + auto action = sp_action_new(Inkscape::ActionContext(view), name, name, tip, name, nullptr); + set_action(action); + g_object_unref(action); +} + +} // namespace Widget +} // 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 : |