diff options
Diffstat (limited to 'src/ui/view')
-rw-r--r-- | src/ui/view/README | 51 | ||||
-rw-r--r-- | src/ui/view/svg-view-widget.cpp | 261 | ||||
-rw-r--r-- | src/ui/view/svg-view-widget.h | 97 | ||||
-rw-r--r-- | src/ui/view/view-widget.cpp | 58 | ||||
-rw-r--r-- | src/ui/view/view-widget.h | 56 | ||||
-rw-r--r-- | src/ui/view/view.cpp | 124 | ||||
-rw-r--r-- | src/ui/view/view.h | 145 |
7 files changed, 792 insertions, 0 deletions
diff --git a/src/ui/view/README b/src/ui/view/README new file mode 100644 index 0000000..9316f8b --- /dev/null +++ b/src/ui/view/README @@ -0,0 +1,51 @@ + +This directory contains the class Inkscape::UI::View::View and related items. + +View is an abstract base class for all UI document views. Documents +can be displayed by more than one window, each having its own view +(e.g. zoom level, selection, etc.). + +View is the base class for: + +* SPDesktop +* SVGView REMOVED + +SPViewWidget is the base for: + +* SPDocumentWidget +* SPSVGViewWidget REMOVED + +SPSVGViewWidget has been replaced by SVGViewWidget, see below. + + +SPViewWidget: + Contains a GtkEventBox and holds a View. + +SPDesktopWidget: + Contains: + VBox + HBox + GtkGrid + GtkPaned + GtkGrid + SPCanvas + Plus lots of other junk. + + +SVGViewWidget: + Used many places as a convenient way to show an SVG (file dialog, Inkview). + Derived, rather uselessly, from Gtk::Scrollbar. + It no longer is dependent on View (and really doesn't belong here anymore). + + It contains: SPCanvas + +To do: + + +* Convert everything to C++. +* Evaluate moving SPDesktopWidget down the widget stack. + It doesn't use the EventBox of SPViewWidget! + +A DesktopViewWidget should contain: + DesktopView (aka SPDesktop) + SPCanvas diff --git a/src/ui/view/svg-view-widget.cpp b/src/ui/view/svg-view-widget.cpp new file mode 100644 index 0000000..45755e2 --- /dev/null +++ b/src/ui/view/svg-view-widget.cpp @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** + * @file + * A light-weight widget containing an Inkscape canvas for rendering an SVG. + */ +/* + * Authors: + * Tavmjong Bah <tavmjong@free.fr> + * + * Includes code moved from svg-view.cpp authored by: + * MenTaLGuy + * Ralf Stephan <ralf@ark.in-berlin.de> + * Jon A. Cruz <jon@joncruz.org> + * + * Copyright (C) 2018 Authors + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * Read the file 'COPYING' for more information. + * + */ + +#include <iostream> + +#include "svg-view-widget.h" + +#include "document.h" + +#include "2geom/transforms.h" + +#include "display/drawing.h" +#include "display/control/canvas-item.h" +#include "display/control/canvas-item-drawing.h" +#include "display/control/canvas-item-group.h" + +#include "object/sp-item.h" +#include "object/sp-root.h" + +#include "ui/widget/canvas.h" + +#include "util/units.h" + +namespace Inkscape { +namespace UI { +namespace View { + +/** + * Callback connected with drawing_event. + */ +// This hasn't worked since at least 0.48. It should result in a cursor change over <a></a> links. +// There should be a better way of doing this. See note in canvas-arena.cpp. +static bool _drawing_handler(GdkEvent *event, Inkscape::DrawingItem *drawing_item, SVGViewWidget *svgview) +{ + static gdouble x, y; + static gboolean active = FALSE; + SPEvent spev; + + SPItem *spitem = (drawing_item) ? drawing_item->getItem() : nullptr; + + switch (event->type) { + case GDK_BUTTON_PRESS: + if (event->button.button == 1) { + active = TRUE; + x = event->button.x; + y = event->button.y; + } + break; + case GDK_BUTTON_RELEASE: + if (event->button.button == 1) { + if (active && (event->button.x == x) && + (event->button.y == y)) { + spev.type = SPEvent::ACTIVATE; + if ( spitem != nullptr ) + { + spitem->emitEvent (spev); + } + } + } + active = FALSE; + break; + case GDK_MOTION_NOTIFY: + active = FALSE; + break; + case GDK_ENTER_NOTIFY: + spev.type = SPEvent::MOUSEOVER; + spev.view = svgview; + if ( spitem != nullptr ) + { + spitem->emitEvent (spev); + } + break; + case GDK_LEAVE_NOTIFY: + spev.type = SPEvent::MOUSEOUT; + spev.view = svgview; + if ( spitem != nullptr ) + { + spitem->emitEvent (spev); + } + break; + default: + break; + } + + return true; +} + + +/** + * A light-weight widget containing an SPCanvas for rendering an SVG. + */ +SVGViewWidget::SVGViewWidget(SPDocument* document) +{ + _canvas = Gtk::make_managed<Inkscape::UI::Widget::Canvas>(); + add(*_canvas); + + _parent = new Inkscape::CanvasItemGroup(_canvas->get_canvas_item_root()); + _drawing = new Inkscape::CanvasItemDrawing(_parent); + _canvas->set_drawing(_drawing->get_drawing()); + _drawing->connect_drawing_event(sigc::bind(sigc::ptr_fun(_drawing_handler), this)); + + setDocument(document); + + show_all(); +} + +SVGViewWidget::~SVGViewWidget() +{ + if (_document) { + _document = nullptr; + } +} + +void +SVGViewWidget::setDocument(SPDocument* document) +{ + // Clear old document + if (_document) { + _document->getRoot()->invoke_hide(_dkey); // Removed from display tree + } + + // Add new document + if (document) { + _document = document; + + Inkscape::DrawingItem *drawing_item = document->getRoot()->invoke_show( + *_drawing->get_drawing(), + _dkey, + SP_ITEM_SHOW_DISPLAY); + + if (drawing_item) { + _drawing->get_drawing()->root()->prependChild(drawing_item); + } + + doRescale (); + } +} + +void +SVGViewWidget::setResize(int width, int height) +{ + // Triggers size_allocation which calls SVGViewWidget::size_allocate. + set_size_request(width, height); + queue_resize(); +} + +void +SVGViewWidget::on_size_allocate(Gtk::Allocation& allocation) +{ + if (!(_allocation == allocation)) { + _allocation = allocation; + + double width = allocation.get_width(); + double height = allocation.get_height(); + + if (width < 0.0 || height < 0.0) { + std::cerr << "SVGViewWidget::size_allocate: negative dimensions!" << std::endl; + Gtk::Bin::on_size_allocate(allocation); + return; + } + + _rescale = true; + _keepaspect = true; + _width = width; + _height = height; + + doRescale (); + } + + Gtk::Bin::on_size_allocate(allocation); +} + +void +SVGViewWidget::doRescale() +{ + if (!_document) { + std::cerr << "SVGViewWidget::doRescale: No document!" << std::endl; + return; + } + + if (_document->getWidth().value("px") < 1e-9) { + std::cerr << "SVGViewWidget::doRescale: Width too small!" << std::endl; + return; + } + + if (_document->getHeight().value("px") < 1e-9) { + std::cerr << "SVGViewWidget::doRescale: Height too small!" << std::endl; + return; + } + + double x_offset = 0.0; + double y_offset = 0.0; + if (_rescale) { + _hscale = _width / _document->getWidth().value("px"); + _vscale = _height / _document->getHeight().value("px"); + if (_keepaspect) { + if (_hscale > _vscale) { + _hscale = _vscale; + x_offset = (_document->getWidth().value("px") * _hscale - _width) / 2.0; + } else { + _vscale = _hscale; + y_offset = (_document->getHeight().value("px") * _vscale - _height) / 2.0; + } + } + } + + if (_drawing) { + _canvas->set_affine(Geom::Scale(_hscale, _vscale)); + _canvas->set_pos(Geom::Point(x_offset, y_offset)); + } +} + +void +SVGViewWidget::mouseover() +{ + GdkDisplay *display = gdk_display_get_default(); + GdkCursor *cursor = gdk_cursor_new_for_display(display, GDK_HAND2); + GdkWindow *window = gtk_widget_get_window (GTK_WIDGET(_canvas->gobj())); + gdk_window_set_cursor(window, cursor); + g_object_unref(cursor); +} + +void +SVGViewWidget::mouseout() +{ + GdkWindow *window = gtk_widget_get_window (GTK_WIDGET(_canvas->gobj())); + gdk_window_set_cursor(window, nullptr); +} + +} // Namespace View +} // 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 : diff --git a/src/ui/view/svg-view-widget.h b/src/ui/view/svg-view-widget.h new file mode 100644 index 0000000..e12e7aa --- /dev/null +++ b/src/ui/view/svg-view-widget.h @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** + * @file + * A light-weight widget containing an SPCanvas with for rendering an SVG. + */ +/* + * Authors: + * Tavmjong Bah <tavmjong@free.fr> + * + * Copyright (C) 2018 Authors + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * Read the file 'COPYING' for more information. + * + */ + +#ifndef INKSCAPE_UI_SVG_VIEW_WIDGET_VARIATIONS_H +#define INKSCAPE_UI_SVG_VIEW_WIDGET_VARIATIONS_H + + +#include <gtkmm.h> + +class SPDocument; + +namespace Inkscape { + +class CanvasItemDrawing; +class CanvasItemGroup; + +namespace UI { + +namespace Widget { +class Canvas; +} + +namespace View { + +/** + * A light-weight widget containing an Inkscape canvas for rendering an SVG. + */ +class SVGViewWidget : public Gtk::Bin { + +public: + SVGViewWidget(SPDocument* document); + ~SVGViewWidget() override; + void setDocument( SPDocument* document); + void setResize( int width, int height); + void on_size_allocate(Gtk::Allocation& allocation) override; + +private: + + Inkscape::UI::Widget::Canvas *_canvas; + +// From SVGView --------------------------------- + +public: + SPDocument* _document = nullptr; + unsigned int _dkey = 0; + Inkscape::CanvasItemGroup *_parent = nullptr; + Inkscape::CanvasItemDrawing *_drawing = nullptr; + Gtk::Allocation _allocation; + double _hscale = 1.0; ///< horizontal scale + double _vscale = 1.0; ///< vertical scale + bool _rescale = false; ///< whether to rescale automatically + bool _keepaspect = false; + double _width = 0.0; + double _height = 0.0; + + /** + * Helper function that sets rescale ratio. + */ + void doRescale(); + + /** + * Change cursor (used for links). + */ + void mouseover(); + void mouseout(); + +}; + +} // Namespace View +} // Namespace UI +} // Namespace Inkscape + +#endif // INKSCAPE_UI_SVG_VIEW_WIDGET + +/* + 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 : diff --git a/src/ui/view/view-widget.cpp b/src/ui/view/view-widget.cpp new file mode 100644 index 0000000..2b749cc --- /dev/null +++ b/src/ui/view/view-widget.cpp @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * Ralf Stephan <ralf@ark.in-berlin.de> + * + * Copyright (C) 2001-2002 Lauris Kaplinski + * Copyright (C) 2001 Ximian, Inc. + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "view.h" +#include "view-widget.h" + +/** + * Callback to disconnect from view and destroy SPViewWidget. + * + * Apparently, this gets only called when a desktop is closed, but then twice! + */ +void SPViewWidget::on_unrealize() +{ + SPViewWidget *vw = this; + + if (vw->view) { + vw->view->close(); + Inkscape::GC::release(vw->view); + vw->view = nullptr; + } + + parent_type::on_unrealize(); + + Inkscape::GC::request_early_collection(); +} + +void SPViewWidget::setView(view_type *view) +{ + auto vw = this; + g_return_if_fail(view != nullptr); + + g_return_if_fail(vw->view == nullptr); + + vw->view = view; + Inkscape::GC::anchor(view); +} + + + +/* + 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 : diff --git a/src/ui/view/view-widget.h b/src/ui/view/view-widget.h new file mode 100644 index 0000000..e67280d --- /dev/null +++ b/src/ui/view/view-widget.h @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#ifndef INKSCAPE_UI_VIEW_VIEWWIDGET_H +#define INKSCAPE_UI_VIEW_VIEWWIDGET_H + +/* + * Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * Ralf Stephan <ralf@ark.in-berlin.de> + * + * Copyright (C) 2001-2002 Lauris Kaplinski + * Copyright (C) 2001 Ximian, Inc. + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <gtkmm/eventbox.h> + + +namespace Inkscape { +namespace UI { +namespace View { +class View; +} // namespace View +} // namespace UI +} // namespace Inkscape + +/** + * SPViewWidget is a GUI widget that contain a single View. It is also + * an abstract base class with little functionality of its own. + */ +class SPViewWidget : public Gtk::EventBox { + using parent_type = Gtk::EventBox; + using view_type = Inkscape::UI::View::View; + + view_type *view = nullptr; + + public: + void on_unrealize() override; + + view_type *getView() { return view; } + + void setView(view_type *view); +}; + +#endif + +/* + 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 : diff --git a/src/ui/view/view.cpp b/src/ui/view/view.cpp new file mode 100644 index 0000000..2d5b9ab --- /dev/null +++ b/src/ui/view/view.cpp @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * Ralf Stephan <ralf@ark.in-berlin.de> + * Jon A. Cruz <jon@joncruz.org> + * + * Copyright (C) 2001-2002 Lauris Kaplinski + * Copyright (C) 2001 Ximian, Inc. + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <2geom/point.h> +#include <memory> +#include "document.h" +#include "view.h" +#include "message-stack.h" +#include "message-context.h" +#include "inkscape.h" + +namespace Inkscape { +namespace UI { +namespace View { + +static void +_onResized (double x, double y, View* v) +{ + v->onResized (x,y); +} + +static void +_onRedrawRequested (View* v) +{ + v->onRedrawRequested(); +} + +static void +_onStatusMessage (Inkscape::MessageType type, gchar const *message, View* v) +{ + v->onStatusMessage (type, message); +} + +static void +_onDocumentFilenameSet (gchar const* filename, View* v) +{ + v->onDocumentFilenameSet (filename); +} + +//-------------------------------------------------------------------- +View::View() +: _doc(nullptr) +{ + _message_stack = std::make_shared<Inkscape::MessageStack>(); + _tips_message_context = std::unique_ptr<Inkscape::MessageContext>(new Inkscape::MessageContext(_message_stack)); + + _resized_connection = _resized_signal.connect (sigc::bind (sigc::ptr_fun (&_onResized), this)); + _redraw_requested_connection = _redraw_requested_signal.connect (sigc::bind (sigc::ptr_fun (&_onRedrawRequested), this)); + + _message_changed_connection = _message_stack->connectChanged (sigc::bind (sigc::ptr_fun (&_onStatusMessage), this)); +} + +View::~View() +{ + _close(); +} + +void View::_close() { + _message_changed_connection.disconnect(); + + _tips_message_context = nullptr; + + _message_stack = nullptr; + + if (_doc) { + _document_uri_set_connection.disconnect(); + if (INKSCAPE.remove_document(_doc)) { + // this was the last view of this document, so delete it + // delete _doc; Delete now handled in Inkscape::Application + } + _doc = nullptr; + } +} + +void View::emitResized (double width, double height) +{ + _resized_signal.emit (width, height); +} + +void View::requestRedraw() +{ + _redraw_requested_signal.emit(); +} + +void View::setDocument(SPDocument *doc) { + g_return_if_fail(doc != nullptr); + + if (_doc) { + _document_uri_set_connection.disconnect(); + if (INKSCAPE.remove_document(_doc)) { + // this was the last view of this document, so delete it + // delete _doc; Delete now handled in Inkscape::Application + } + } + + INKSCAPE.add_document(doc); + + _doc = doc; + _document_uri_set_connection = _doc->connectFilenameSet(sigc::bind(sigc::ptr_fun(&_onDocumentFilenameSet), this)); + _document_filename_set_signal.emit( _doc->getDocumentFilename() ); +} + +}}} + +/* + 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 : diff --git a/src/ui/view/view.h b/src/ui/view/view.h new file mode 100644 index 0000000..3e3545a --- /dev/null +++ b/src/ui/view/view.h @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#ifndef INKSCAPE_UI_VIEW_VIEW_H +#define INKSCAPE_UI_VIEW_VIEW_H +/* + * Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * Ralf Stephan <ralf@ark.in-berlin.de> + * + * Copyright (C) 2001-2002 Lauris Kaplinski + * Copyright (C) 2001 Ximian, Inc. + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <gdk/gdk.h> +#include <cstddef> +#include <memory> +#include <sigc++/connection.h> +#include "message.h" +#include "inkgc/gc-managed.h" +#include "gc-finalized.h" +#include "gc-anchored.h" +#include <2geom/forward.h> + +/** + * Iterates until true or returns false. + * When used as signal accumulator, stops emission if one slot returns true. + */ +struct StopOnTrue { + typedef bool result_type; + + template<typename T_iterator> + result_type operator()(T_iterator first, T_iterator last) const{ + for (; first != last; ++first) + if (*first) return true; + return false; + } +}; + +/** + * Iterates until nonzero or returns 0. + * When used as signal accumulator, stops emission if one slot returns nonzero. + */ +struct StopOnNonZero { + typedef int result_type; + + template<typename T_iterator> + result_type operator()(T_iterator first, T_iterator last) const{ + for (; first != last; ++first) + if (*first) return *first; + return 0; + } +}; + +class SPDocument; + +namespace Inkscape { + class MessageContext; + class MessageStack; + namespace UI { + namespace View { + +/** + * View is an abstract base class of all UI document views. This + * includes both the editing window and the SVG preview, but does not + * include the non-UI RGBA buffer-based Inkscape::Drawing nor the XML editor or + * similar views. The View base class has very little functionality of + * its own. + */ +class View : public GC::Managed<>, + public GC::Finalized, + public GC::Anchored +{ +public: + + View(); + + /** + * Deletes and nulls all View message stacks and disconnects it from signals. + */ + ~View() override; + + void close() { _close(); } + + /// Returns a pointer to the view's document. + SPDocument *doc() const + { return _doc; } + /// Returns a pointer to the view's message stack. + std::shared_ptr<Inkscape::MessageStack> messageStack() const + { return _message_stack; } + /// Returns a pointer to the view's tipsMessageContext. + Inkscape::MessageContext *tipsMessageContext() const + { return _tips_message_context.get(); } + + void emitResized(gdouble width, gdouble height); + void requestRedraw(); + + virtual void onResized (double, double) {}; + virtual void onRedrawRequested() {}; + virtual void onStatusMessage (Inkscape::MessageType type, gchar const *message) {}; + virtual void onDocumentFilenameSet (gchar const* filename) {}; + +protected: + SPDocument *_doc; + std::shared_ptr<Inkscape::MessageStack> _message_stack; + std::unique_ptr<Inkscape::MessageContext> _tips_message_context; + + virtual void _close(); + + /** + * Disconnects the view from the document signals, connects the view + * to a new one, and emits the _document_set_signal on the view. + * + * This is code common to all subclasses and called from their + * setDocument() methods after they are done. + * + * @param doc The new document to connect the view to. + */ + virtual void setDocument(SPDocument *doc); + + sigc::signal<void,double,double> _resized_signal; + sigc::signal<void,gchar const*> _document_filename_set_signal; + sigc::signal<void> _redraw_requested_signal; + +private: + sigc::connection _resized_connection; + sigc::connection _redraw_requested_connection; + sigc::connection _message_changed_connection; // foreign + sigc::connection _document_uri_set_connection; // foreign +}; + +}}} + +#endif // INKSCAPE_UI_VIEW_VIEW_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 : |