diff options
Diffstat (limited to '')
-rw-r--r-- | src/ui/widget/canvas-grid.cpp | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/src/ui/widget/canvas-grid.cpp b/src/ui/widget/canvas-grid.cpp new file mode 100644 index 0000000..19b21d0 --- /dev/null +++ b/src/ui/widget/canvas-grid.cpp @@ -0,0 +1,318 @@ +// 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 <glibmm/i18n.h> +#include <gtkmm/enums.h> +#include <gtkmm/label.h> + +#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 : |