// SPDX-License-Identifier: GPL-2.0-or-later /** @file * Generic button widget *//* * Authors: * see git history * MenTaLguY * Lauris Kaplinski * bulia byak * * * Copyright (C) 2018 Authors * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ #include #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 :