// SPDX-License-Identifier: GPL-2.0-or-later /* * Author: * Tavmjong Bah * * Rewrite of code originally in desktop-widget.cpp. * * Copyright (C) 2020 Tavmjong Bah * * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ // The scrollbars, and canvas are tightly coupled so it makes sense to have a dedicated // widget to handle their interactions. The buttons are along for the ride. I don't see // how to add the buttons easily via a .ui file (which would allow the user to put any // buttons they want in their place). #include #include #include #include "canvas-grid.h" #include "desktop.h" // Hopefully temp. #include "desktop-events.h" // Hopefully temp. #include "display/control/canvas-item-drawing.h" // sticky #include "ui/icon-loader.h" #include "ui/widget/canvas.h" #include "ui/widget/ink-ruler.h" #include "widgets/desktop-widget.h" // Hopefully temp. namespace Inkscape { namespace UI { namespace Widget { CanvasGrid::CanvasGrid(SPDesktopWidget *dtw) { _dtw = dtw; set_name("CanvasGrid"); // Canvas _canvas = Gtk::manage(new Inkscape::UI::Widget::Canvas()); _canvas->set_hexpand(true); _canvas->set_vexpand(true); _canvas->set_can_focus(true); _canvas->signal_event().connect(sigc::mem_fun(*this, &CanvasGrid::SignalEvent)); // TEMP _canvas_overlay.add(*_canvas); _canvas_overlay.add_overlay(*_command_palette.get_base_widget()); // Horizontal Scrollbar _hadj = Gtk::Adjustment::create(0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0); _hadj->signal_value_changed().connect(sigc::mem_fun(_dtw, &SPDesktopWidget::on_adjustment_value_changed)); _hscrollbar = Gtk::manage(new Gtk::Scrollbar(_hadj, Gtk::ORIENTATION_HORIZONTAL)); _hscrollbar->set_name("CanvasScrollbar"); _hscrollbar->set_hexpand(true); _hscrollbar->set_no_show_all(); // Vertical Scrollbar _vadj = Gtk::Adjustment::create(0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0); _vadj->signal_value_changed().connect(sigc::mem_fun(_dtw, &SPDesktopWidget::on_adjustment_value_changed)); _vscrollbar = Gtk::manage(new Gtk::Scrollbar(_vadj, Gtk::ORIENTATION_VERTICAL)); _vscrollbar->set_name("CanvasScrollbar"); _vscrollbar->set_vexpand(true); _vscrollbar->set_no_show_all(); // Horizontal Ruler _hruler = Gtk::manage(new Inkscape::UI::Widget::Ruler(Gtk::ORIENTATION_HORIZONTAL)); _hruler->add_track_widget(*_canvas); _hruler->set_hexpand(true); // Tooltip/Unit set elsewhere. // For creating guides, etc. _hruler->signal_button_press_event().connect( sigc::bind(sigc::mem_fun(*_dtw, &SPDesktopWidget::on_ruler_box_button_press_event), _hruler, true)); _hruler->signal_button_release_event().connect( sigc::bind(sigc::mem_fun(*_dtw, &SPDesktopWidget::on_ruler_box_button_release_event), _hruler, true)); _hruler->signal_motion_notify_event().connect( sigc::bind(sigc::mem_fun(*_dtw, &SPDesktopWidget::on_ruler_box_motion_notify_event), _hruler, true)); // Vertical Ruler _vruler = Gtk::manage(new Inkscape::UI::Widget::Ruler(Gtk::ORIENTATION_VERTICAL)); _vruler->add_track_widget(*_canvas); _vruler->set_vexpand(true); // Tooltip/Unit set elsewhere. // For creating guides, etc. _vruler->signal_button_press_event().connect( sigc::bind(sigc::mem_fun(*_dtw, &SPDesktopWidget::on_ruler_box_button_press_event), _vruler, false)); _vruler->signal_button_release_event().connect( sigc::bind(sigc::mem_fun(*_dtw, &SPDesktopWidget::on_ruler_box_button_release_event), _vruler, false)); _vruler->signal_motion_notify_event().connect( sigc::bind(sigc::mem_fun(*_dtw, &SPDesktopWidget::on_ruler_box_motion_notify_event), _vruler, false)); // Guide Lock auto image1 = Gtk::manage(new Gtk::Image("object-locked", Gtk::ICON_SIZE_MENU)); _guide_lock = Gtk::manage(new Gtk::ToggleButton()); _guide_lock->set_name("LockGuides"); _guide_lock->add(*image1); _guide_lock->set_no_show_all(); // To be replaced by Gio::Action: _guide_lock->signal_toggled().connect(sigc::mem_fun(_dtw, &SPDesktopWidget::update_guides_lock)); _guide_lock->set_tooltip_text(_("Toggle lock of all guides in the document")); // CMS Adjust auto image2 = Gtk::manage(new Gtk::Image("color-management", Gtk::ICON_SIZE_MENU)); _cms_adjust = Gtk::manage(new Gtk::ToggleButton()); _cms_adjust->set_name("CMS_Adjust"); _cms_adjust->add(*image2); // Can't access via C++ API, fixed in Gtk4. gtk_actionable_set_action_name( GTK_ACTIONABLE(_cms_adjust->gobj()), "win.canvas-color-manage"); _cms_adjust->set_tooltip_text(_("Toggle color-managed display for this document window")); _cms_adjust->set_no_show_all(); // Sticky Zoom auto image3 = Gtk::manage(sp_get_icon_image("zoom-original", Gtk::ICON_SIZE_MENU)); _sticky_zoom = Gtk::manage(new Gtk::ToggleButton()); _sticky_zoom->set_name("StickyZoom"); _sticky_zoom->add(*image3); // To be replaced by Gio::Action: _sticky_zoom->signal_toggled().connect(sigc::mem_fun(_dtw, &SPDesktopWidget::sticky_zoom_toggled)); _sticky_zoom->set_tooltip_text(_("Zoom drawing if window size changes")); _sticky_zoom->set_no_show_all(); // Top row attach(*_guide_lock, 0, 0, 1, 1); attach(*_hruler, 1, 0, 1, 1); attach(*_sticky_zoom, 2, 0, 1, 1); // Middle row attach(*_vruler, 0, 1, 1, 1); attach(_canvas_overlay, 1, 1, 1, 1); attach(*_vscrollbar, 2, 1, 1, 1); // Bottom row attach(*_hscrollbar, 1, 2, 1, 1); attach(*_cms_adjust, 2, 2, 1, 1); // Update rulers on size change. signal_size_allocate().connect(sigc::mem_fun(*this, &CanvasGrid::OnSizeAllocate)); show_all(); } CanvasGrid::~CanvasGrid() { } // _dt2r should be a member of _canvas. // get_display_area should be a member of _canvas. void CanvasGrid::UpdateRulers() { Geom::Rect viewbox = _dtw->desktop->get_display_area().bounds(); // Use integer values of the canvas for calculating the display area, similar // to the integer values used for positioning the grid lines. (see Canvas::scrollTo(), // where ix and iy are rounded integer values; these values are stored in CanvasItemBuffer->rect, // and used for drawing the grid). By using the integer values here too, the ruler ticks // will be perfectly aligned to the grid double _dt2r = _dtw->_dt2r; Geom::Point _ruler_origin = _dtw->_ruler_origin; double lower_x = _dt2r * (viewbox.left() - _ruler_origin[Geom::X]); double upper_x = _dt2r * (viewbox.right() - _ruler_origin[Geom::X]); _hruler->set_range(lower_x, upper_x); double lower_y = _dt2r * (viewbox.bottom() - _ruler_origin[Geom::Y]); double upper_y = _dt2r * (viewbox.top() - _ruler_origin[Geom::Y]); if (_dtw->desktop->is_yaxisdown()) { std::swap(lower_y, upper_y); } _vruler->set_range(lower_y, upper_y); } void CanvasGrid::ShowScrollbars(bool state) { _show_scrollbars = state; if (_show_scrollbars) { // Show scrollbars _hscrollbar->show(); _vscrollbar->show(); _cms_adjust->show(); _cms_adjust->show_all_children(); _sticky_zoom->show(); _sticky_zoom->show_all_children(); } else { // Hide scrollbars _hscrollbar->hide(); _vscrollbar->hide(); _cms_adjust->hide(); _sticky_zoom->hide(); } } void CanvasGrid::ToggleScrollbars() { _show_scrollbars = !_show_scrollbars; ShowScrollbars(_show_scrollbars); // Will be replaced by actions auto prefs = Inkscape::Preferences::get(); prefs->setBool("/fullscreen/scrollbars/state", _show_scrollbars); prefs->setBool("/window/scrollbars/state", _show_scrollbars); } void CanvasGrid::ShowRulers(bool state) { // Sticky zoom button is always shown. We must adjust canvas when rulers are toggled or canvas // won't expand fully. _show_rulers = state; if (_show_rulers) { // Show rulers _hruler->show(); _vruler->show(); _guide_lock->show(); _guide_lock->show_all_children(); remove(_canvas_overlay); attach(_canvas_overlay, 1, 1, 1, 1); } else { // Hide rulers _hruler->hide(); _vruler->hide(); _guide_lock->hide(); remove(_canvas_overlay); attach(_canvas_overlay, 1, 0, 1, 2); } } void CanvasGrid::ToggleRulers() { _show_rulers = !_show_rulers; ShowRulers(_show_rulers); // Will be replaced by actions auto prefs = Inkscape::Preferences::get(); prefs->setBool("/fullscreen/rulers/state", _show_rulers); prefs->setBool("/window/rulers/state", _show_rulers); } void CanvasGrid::ToggleCommandPalette() { _command_palette.toggle(); } void CanvasGrid::ShowCommandPalette(bool state) { if (state) { _command_palette.open(); } _command_palette.close(); } // Update rulers on change of widget size, but only if allocation really changed. void CanvasGrid::OnSizeAllocate(Gtk::Allocation& allocation) { if (!(_allocation == allocation)) { // No != function defined! _allocation = allocation; UpdateRulers(); } } // This belong in Canvas class bool CanvasGrid::SignalEvent(GdkEvent *event) { if (event->type == GDK_BUTTON_PRESS) { _canvas->grab_focus(); _command_palette.close(); } if (event->type == GDK_BUTTON_PRESS && event->button.button == 3) { if (event->button.state & GDK_SHIFT_MASK) { _dtw->desktop->getCanvasDrawing()->set_sticky(true); } else { _dtw->desktop->getCanvasDrawing()->set_sticky(false); } } // Pass keyboard events back to the desktop root handler so TextTool can work if ((event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE) && !_canvas->get_current_canvas_item()) { return sp_desktop_root_handler(event, _dtw->desktop); } return false; } // TODO Add actions so we can set shortcuts. // * Sticky Zoom // * CMS Adjust // * Guide Lock } // 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:textwidth=99 :