diff options
Diffstat (limited to 'src/ui/widget/canvas.h')
-rw-r--r-- | src/ui/widget/canvas.h | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/src/ui/widget/canvas.h b/src/ui/widget/canvas.h new file mode 100644 index 0000000..f2a434a --- /dev/null +++ b/src/ui/widget/canvas.h @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifndef INKSCAPE_UI_WIDGET_CANVAS_H +#define INKSCAPE_UI_WIDGET_CANVAS_H +/* + * Authors: + * Tavmjong Bah + * PBS <pbs3141@gmail.com> + * + * Copyright (C) 2022 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <memory> +#include <gtkmm.h> +#include <2geom/rect.h> +#include <2geom/int-rect.h> +#include "display/rendermode.h" + +class SPDesktop; + +namespace Inkscape { + +class CanvasItem; +class CanvasItemGroup; +class Drawing; + +namespace UI { +namespace Widget { + +class CanvasPrivate; + +/** + * A Gtk::DrawingArea widget for Inkscape's canvas. + */ +class Canvas : public Gtk::DrawingArea +{ + using parent_type = Gtk::DrawingArea; + +public: + + Canvas(); + ~Canvas() override; + + /* Configuration */ + + // Desktop (Todo: Remove.) + void set_desktop(SPDesktop *desktop) { _desktop = desktop; } + SPDesktop *get_desktop() const { return _desktop; } + + // Drawing + void set_drawing(Inkscape::Drawing *drawing); + + // Canvas item root + CanvasItemGroup *get_canvas_item_root() const { return _canvas_item_root; } + + // Geometry + void set_pos (const Geom::IntPoint &pos); + void set_pos (const Geom::Point &fpos) { set_pos(fpos.round()); } + void set_affine(const Geom::Affine &affine); + const Geom::IntPoint& get_pos () const {return _pos;} + const Geom::Affine& get_affine() const {return _affine;} + + // Background + void set_background_color(guint32 rgba); + void set_background_checkerboard(guint32 rgba = 0xC4C4C4FF, bool use_alpha = false); + + // Rendering modes + void set_render_mode(Inkscape::RenderMode mode); + void set_color_mode (Inkscape::ColorMode mode); + void set_split_mode (Inkscape::SplitMode mode); + Inkscape::RenderMode get_render_mode() const { return _render_mode; } + Inkscape::ColorMode get_color_mode() const { return _color_mode; } + Inkscape::SplitMode get_split_mode() const { return _split_mode; } + + // CMS + void set_cms_key(std::string key) { + _cms_key = std::move(key); + _cms_active = !_cms_key.empty(); + } + const std::string& get_cms_key() const { return _cms_key; } + void set_cms_active(bool active) { _cms_active = active; } + bool get_cms_active() const { return _cms_active; } + + /* Observers */ + + // Geometry + Geom::IntPoint get_dimensions() const; + bool world_point_inside_canvas(Geom::Point const &world) const; // desktop-events.cpp + Geom::Point canvas_to_world(Geom::Point const &window) const; + Geom::IntRect get_area_world() const; + + // State + bool is_dragging() const { return _is_dragging; } // selection-chemistry.cpp + + // Encapsulation leaks + Cairo::RefPtr<Cairo::ImageSurface> get_backing_store() const; // canvas-item-rotate.cpp + Cairo::RefPtr<Cairo::Pattern> get_background_pattern() const { return _background; } // canvas-item-rect.cpp, canvas-item-ctrl.cpp + + /* Methods */ + + // Invalidation + void redraw_all(); // Mark everything as having changed. + void redraw_area(Geom::Rect& area); // Mark a rectangle of world space as having changed. + void redraw_area(int x0, int y0, int x1, int y1); + void redraw_area(Geom::Coord x0, Geom::Coord y0, Geom::Coord x1, Geom::Coord y1); + void request_update(); // Mark geometry as needing recalculation. + + // Gobblers (tool-base.cpp) + int gobble_key_events(guint keyval, guint mask); + void gobble_motion_events(guint mask); + + // Callback run on destructor of any canvas item + void canvas_item_destructed(Inkscape::CanvasItem *item); + + // State + Inkscape::CanvasItem *get_current_canvas_item() const { return _current_canvas_item; } + void set_current_canvas_item(Inkscape::CanvasItem *item) { + _current_canvas_item = item; + } + Inkscape::CanvasItem *get_grabbed_canvas_item() const { return _grabbed_canvas_item; } + void set_grabbed_canvas_item(Inkscape::CanvasItem *item, Gdk::EventMask mask) { + _grabbed_canvas_item = item; + _grabbed_event_mask = mask; + } + void set_drawing_disabled(bool disable); // Disable during path ops, etc. + void set_all_enter_events(bool on) { _all_enter_events = on; } + +protected: + + void get_preferred_width_vfunc (int &minimum_width, int &natural_width ) const override; + void get_preferred_height_vfunc(int &minimum_height, int &natural_height) const override; + + // Event handlers + bool on_scroll_event (GdkEventScroll* ) override; + bool on_button_event (GdkEventButton* ); + bool on_button_press_event (GdkEventButton* ) override; + bool on_button_release_event(GdkEventButton* ) override; + bool on_enter_notify_event (GdkEventCrossing*) override; + bool on_leave_notify_event (GdkEventCrossing*) override; + bool on_focus_in_event (GdkEventFocus* ) override; + bool on_key_press_event (GdkEventKey* ) override; + bool on_key_release_event (GdkEventKey* ) override; + bool on_motion_notify_event (GdkEventMotion* ) override; + + void on_realize() override; + void on_unrealize() override; + void on_size_allocate(Gtk::Allocation&) override; + bool on_draw(const Cairo::RefPtr<Cairo::Context>&) override; + +private: + + /* Configuration */ + + // Desktop + SPDesktop *_desktop = nullptr; + + // Drawing + Inkscape::Drawing *_drawing = nullptr; + + // Canvas item root + CanvasItemGroup *_canvas_item_root = nullptr; + + // Geometry + Geom::IntPoint _pos; ///< Coordinates of top-left pixel of canvas view within canvas. + Geom::Affine _affine; ///< The affine that we have been requested to draw at. + + // Background + Cairo::RefPtr<Cairo::Pattern> _background; ///< The background of the widget. + + // Rendering modes + Inkscape::RenderMode _render_mode = Inkscape::RenderMode::NORMAL; + Inkscape::SplitMode _split_mode = Inkscape::SplitMode::NORMAL; + Inkscape::ColorMode _color_mode = Inkscape::ColorMode::NORMAL; + + // CMS + std::string _cms_key; + bool _cms_active = false; + + /* Internal state */ + + // Event handling/item picking + GdkEvent _pick_event; ///< Event used to find currently selected item. + bool _in_repick; ///< For tracking recursion of pick_current_item(). + bool _left_grabbed_item; ///< ? + bool _all_enter_events; ///< Keep all enter events. Only set true in connector-tool.cpp. + bool _is_dragging; ///< Used in selection-chemistry to block undo/redo. + int _state; ///< Last known modifier state (SHIFT, CTRL, etc.). + + Inkscape::CanvasItem *_current_canvas_item; ///< Item containing cursor, nullptr if none. + Inkscape::CanvasItem *_current_canvas_item_new; ///< Item to become _current_item, nullptr if none. + Inkscape::CanvasItem *_grabbed_canvas_item; ///< Item that holds a pointer grab; nullptr if none. + Gdk::EventMask _grabbed_event_mask; + + // Drawing + bool _drawing_disabled = false; ///< Disable drawing during critical operations + bool _need_update = true; // Set true so setting CanvasItem bounds are calculated at least once. + + // Split view + Inkscape::SplitDirection _split_direction; + Geom::Point _split_position; + Inkscape::SplitDirection _hover_direction; + bool _split_dragging; + Geom::Point _split_drag_start; + + void add_clippath(const Cairo::RefPtr<Cairo::Context>&); + void set_cursor(); + + // Opaque pointer to implementation + friend class CanvasPrivate; + std::unique_ptr<CanvasPrivate> d; +}; + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +#endif // INKSCAPE_UI_WIDGET_CANVAS_H + +/* + 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 : |