X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fdesktop.cpp;h=bfde0ee9239314b859659f94579c7ab655dae924;hb=0dc33d4ce43e0bb49c63aa53b826ec4a1ff68e28;hp=7cc77cbab82650bfe90d4850b4594c0cded016b3;hpb=adf2a834bc87a6a22f3a99e8efb42a54dbfbb788;p=inkscape.git diff --git a/src/desktop.cpp b/src/desktop.cpp index 7cc77cbab..bfde0ee92 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -1,5 +1,3 @@ -#define __SP_DESKTOP_C__ - /** \file * Editable view implementation * @@ -10,9 +8,11 @@ * Ralf Stephan * John Bintz * Johan Engelen + * Jon A. Cruz + * Abhishek Sharma * * Copyright (C) 2007 Jon A. Cruz - * Copyright (C) 2006-2007 Johan Engelen + * Copyright (C) 2006-2008 Johan Engelen * Copyright (C) 2006 John Bintz * Copyright (C) 2004 MenTaLguY * Copyright (C) 1999-2002 Lauris Kaplinski @@ -57,6 +57,7 @@ #include #include +#include <2geom/rect.h> #include "macros.h" #include "inkscape-private.h" #include "desktop.h" @@ -69,7 +70,7 @@ #include "sp-namedview.h" #include "color.h" #include "sp-item-group.h" -#include "prefs-utils.h" +#include "preferences.h" #include "object-hierarchy.h" #include "helper/units.h" #include "display/canvas-arena.h" @@ -77,14 +78,24 @@ #include "display/gnome-canvas-acetate.h" #include "display/sodipodi-ctrlrect.h" #include "display/sp-canvas-util.h" -#include "libnr/nr-matrix-div.h" -#include "libnr/nr-rect-ops.h" +#include "display/canvas-temporary-item-list.h" +#include "display/snap-indicator.h" +#include "display/sp-canvas-group.h" #include "ui/dialog/dialog-manager.h" #include "xml/repr.h" #include "message-context.h" +#include "device-manager.h" +#include "layer-fns.h" #include "layer-manager.h" #include "event-log.h" #include "display/canvas-grid.h" +#include "widgets/desktop-widget.h" +#include "box3d-context.h" +#include "desktop-style.h" + +// TODO those includes are only for node tool quick zoom. Remove them after fixing it. +#include "ui/tool/node-tool.h" +#include "ui/tool/control-point-selection.h" #include "display/sp-canvas.h" @@ -99,7 +110,6 @@ static void _layer_hierarchy_changed(SPObject *top, SPObject *bottom, SPDesktop static void _reconstruction_start(SPDesktop * desktop); static void _reconstruction_finish(SPDesktop * desktop); static void _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop); -static void _update_snap_distances (SPDesktop *desktop); /** * Return new desktop object. @@ -114,6 +124,8 @@ SPDesktop::SPDesktop() : event_context( 0 ), layer_manager( 0 ), event_log( 0 ), + temporary_item_list( 0 ), + snapindicator( 0 ), acetate( 0 ), main( 0 ), gridgroup( 0 ), @@ -121,10 +133,12 @@ SPDesktop::SPDesktop() : drawing( 0 ), sketch( 0 ), controls( 0 ), + tempgroup ( 0 ), table( 0 ), page( 0 ), page_border( 0 ), current( 0 ), + _focusMode(false), zooms_past( 0 ), zooms_future( 0 ), dkey( 0 ), @@ -139,39 +153,46 @@ SPDesktop::SPDesktop() : gr_fill_or_stroke( true ), _layer_hierarchy( 0 ), _reconstruction_old_layer_id( 0 ), + _display_mode(Inkscape::RENDERMODE_NORMAL), _widget( 0 ), _inkscape( 0 ), _guides_message_context( 0 ), _active( false ), _w2d(), _d2w(), - _doc2dt( NR::Matrix(NR::scale(1, -1)) ), + _doc2dt( Geom::Scale(1, -1) ), grids_visible( false ) { - _d2w.set_identity(); - _w2d.set_identity(); + _d2w.setIdentity(); + _w2d.setIdentity(); selection = Inkscape::GC::release( new Inkscape::Selection(this) ); } void -SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas) +SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas, Inkscape::UI::View::EditWidgetInterface *widget) { + _widget = widget; + + // Temporary workaround for link order issues: + Inkscape::DeviceManager::getManager().getDevices(); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + _guides_message_context = new Inkscape::MessageContext(const_cast(messageStack())); - current = sp_repr_css_attr_inherited (inkscape_get_repr (INKSCAPE, "desktop"), "style"); + current = prefs->getStyle("/desktop/style"); namedview = nv; canvas = aCanvas; SPDocument *document = SP_OBJECT_DOCUMENT (namedview); /* Kill flicker */ - sp_document_ensure_up_to_date (document); + document->ensureUpToDate(); /* Setup Dialog Manager */ - _dlg_mgr = new Inkscape::UI::Dialog::DialogManager(); + _dlg_mgr = &Inkscape::UI::Dialog::DialogManager::getInstance(); - dkey = sp_item_display_key_new (1); + dkey = SPItem::display_key_new(1); /* Connect document */ setDocument (document); @@ -191,7 +212,7 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas) g_signal_connect (G_OBJECT (main), "event", G_CALLBACK (sp_desktop_root_handler), this); table = sp_canvas_item_new (main, SP_TYPE_CTRLRECT, NULL); - SP_CTRLRECT(table)->setRectangle(NR::Rect(NR::Point(-80000, -80000), NR::Point(80000, 80000))); + SP_CTRLRECT(table)->setRectangle(Geom::Rect(Geom::Point(-80000, -80000), Geom::Point(80000, 80000))); SP_CTRLRECT(table)->setColor(0x00000000, true, 0x00000000); sp_canvas_item_move_to_z (table, 0); @@ -202,9 +223,9 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas) drawing = sp_canvas_item_new (main, SP_TYPE_CANVAS_ARENA, NULL); g_signal_connect (G_OBJECT (drawing), "arena_event", G_CALLBACK (_arena_handler), this); - SP_CANVAS_ARENA (drawing)->arena->delta = prefs_get_double_attribute ("options.cursortolerance", "value", 1.0); // default is 1 px + SP_CANVAS_ARENA (drawing)->arena->delta = prefs->getDouble("/options/cursortolerance/value", 1.0); // default is 1 px - if (prefs_get_int_attribute("options.startmode", "outline", 0)) { + if (prefs->getBool("/options/startmode/outline")) { // Start in outline mode setDisplayModeOutline(); } else { @@ -212,9 +233,17 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas) setDisplayModeNormal(); } + // The order in which these canvas items are added determines the z-order. It's therefore + // important to add the tempgroup (which will contain the snapindicator) before adding the + // controls. Only this way one will be able to quickly (before the snap indicator has + // disappeared) reselect a node after snapping it. If the z-order is wrong however, this + // will not work (the snap indicator is on top of the node handler; is the snapindicator + // being selected? or does it intercept some of the events that should have gone to the + // node handler? see bug https://bugs.launchpad.net/inkscape/+bug/414142) gridgroup = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL); guides = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL); sketch = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL); + tempgroup = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL); controls = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL); /* Push select tool to the bottom of stack */ @@ -223,12 +252,12 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas) * call "set" instead of "push". Can we assume that there is only one * context ever? */ - push_event_context (SP_TYPE_SELECT_CONTEXT, "tools.select", SP_EVENT_CONTEXT_STATIC); + push_event_context (SP_TYPE_SELECT_CONTEXT, "/tools/select", SP_EVENT_CONTEXT_STATIC); // display rect and zoom are now handled in sp_desktop_widget_realize() - NR::Rect const d(NR::Point(0.0, 0.0), - NR::Point(sp_document_width(document), sp_document_height(document))); + Geom::Rect const d(Geom::Point(0.0, 0.0), + Geom::Point(document->getWidth(), document->getHeight())); SP_CTRLRECT(page)->setRectangle(d); SP_CTRLRECT(page_border)->setRectangle(d); @@ -245,18 +274,17 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas) /* Connect event for page resize */ - _doc2dt[5] = sp_document_height (document); + _doc2dt[5] = document->getHeight(); sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (drawing), _doc2dt); _modified_connection = namedview->connectModified(sigc::bind<2>(sigc::ptr_fun(&_namedview_modified), this)); - NRArenaItem *ai = sp_item_invoke_show (SP_ITEM (sp_document_root (document)), + NRArenaItem *ai = SP_ITEM(document->getRoot())->invoke_show( SP_CANVAS_ARENA (drawing)->arena, dkey, SP_ITEM_SHOW_DISPLAY); if (ai) { nr_arena_item_add_child (SP_CANVAS_ARENA (drawing)->root, ai, NULL); - nr_arena_item_unref (ai); } namedview->show(this); @@ -309,11 +337,30 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas) layer_manager = new Inkscape::LayerManager( this ); showGrids(namedview->grids_visible, false); + + temporary_item_list = new Inkscape::Display::TemporaryItemList( this ); + snapindicator = new Inkscape::Display::SnapIndicator ( this ); } void SPDesktop::destroy() { + if (snapindicator) { + delete snapindicator; + snapindicator = NULL; + } + if (temporary_item_list) { + delete temporary_item_list; + temporary_item_list = NULL; + } + + if (selection) { + delete selection; + selection = NULL; + } + + namedview->hide(this); + _activate_connection.disconnect(); _deactivate_connection.disconnect(); _sel_modified_connection.disconnect(); @@ -349,7 +396,7 @@ void SPDesktop::destroy() } if (drawing) { - sp_item_invoke_hide (SP_ITEM (sp_document_root (doc())), dkey); + SP_ITEM(doc()->getRoot())->invoke_hide(dkey); drawing = NULL; } @@ -365,30 +412,64 @@ SPDesktop::~SPDesktop() {} //-------------------------------------------------------------------- /* Public methods */ -void SPDesktop::setDisplayModeNormal() + +/* These methods help for temporarily showing things on-canvas. + * The *only* valid use of the TemporaryItem* that you get from add_temporary_canvasitem + * is when you want to prematurely remove the item from the canvas, by calling + * desktop->remove_temporary_canvasitem(tempitem). + */ +/** Note that lifetime is measured in milliseconds + * One should *not* keep a reference to the SPCanvasItem, the temporary item code will + * delete the object for you and the reference will become invalid without you knowing it. + * It is perfectly safe to ignore the returned pointer: the object is deleted by itself, so don't delete it elsewhere! + * The *only* valid use of the returned TemporaryItem* is as argument for SPDesktop::remove_temporary_canvasitem, + * because the object might be deleted already without you knowing it. + * move_to_bottom = true by default so the item does not interfere with handling of other items on the canvas like nodes. + */ +Inkscape::Display::TemporaryItem * +SPDesktop::add_temporary_canvasitem (SPCanvasItem *item, guint lifetime, bool move_to_bottom) { - SP_CANVAS_ARENA (drawing)->arena->rendermode = RENDERMODE_NORMAL; - canvas->rendermode = RENDERMODE_NORMAL; // canvas needs that for choosing the best buffer size - displayMode = RENDERMODE_NORMAL; - sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw - _widget->setTitle(SP_DOCUMENT_NAME(sp_desktop_document(this))); + if (move_to_bottom) { + sp_canvas_item_move_to_z(item, 0); + } + + return temporary_item_list->add_item(item, lifetime); } -void SPDesktop::setDisplayModeOutline() +/** It is perfectly safe to call this function while the object has already been deleted due to a timeout. +*/ +void +SPDesktop::remove_temporary_canvasitem (Inkscape::Display::TemporaryItem * tempitem) { - SP_CANVAS_ARENA (drawing)->arena->rendermode = RENDERMODE_OUTLINE; - canvas->rendermode = RENDERMODE_OUTLINE; // canvas needs that for choosing the best buffer size - displayMode = RENDERMODE_OUTLINE; - sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw - _widget->setTitle(SP_DOCUMENT_NAME(sp_desktop_document(this))); + // check for non-null temporary_item_list, because during destruction of desktop, some destructor might try to access this list! + if (tempitem && temporary_item_list) { + temporary_item_list->delete_item(tempitem); + } } -void SPDesktop::displayModeToggle() -{ - if (displayMode == RENDERMODE_OUTLINE) - setDisplayModeNormal(); - else - setDisplayModeOutline(); +void SPDesktop::_setDisplayMode(Inkscape::RenderMode mode) { + SP_CANVAS_ARENA (drawing)->arena->rendermode = mode; + canvas->rendermode = mode; + _display_mode = mode; + sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw + _widget->setTitle( sp_desktop_document(this)->getName() ); +} + +void SPDesktop::displayModeToggle() { + switch (_display_mode) { + case Inkscape::RENDERMODE_NORMAL: + _setDisplayMode(Inkscape::RENDERMODE_NO_FILTERS); + break; + case Inkscape::RENDERMODE_NO_FILTERS: + _setDisplayMode(Inkscape::RENDERMODE_OUTLINE); + break; + case Inkscape::RENDERMODE_OUTLINE: + _setDisplayMode(Inkscape::RENDERMODE_NORMAL); + break; +// case Inkscape::RENDERMODE_PRINT_COLORS_PREVIEW: + default: + _setDisplayMode(Inkscape::RENDERMODE_NORMAL); + } } /** @@ -415,10 +496,35 @@ SPObject *SPDesktop::currentLayer() const void SPDesktop::setCurrentLayer(SPObject *object) { g_return_if_fail(SP_IS_GROUP(object)); g_return_if_fail( currentRoot() == object || (currentRoot() && currentRoot()->isAncestorOf(object)) ); - // printf("Set Layer to ID: %s\n", SP_OBJECT_ID(object)); + // printf("Set Layer to ID: %s\n", object->getId()); _layer_hierarchy->setBottom(object); } +void SPDesktop::toggleLayerSolo(SPObject *object) { + g_return_if_fail(SP_IS_GROUP(object)); + g_return_if_fail( currentRoot() == object || (currentRoot() && currentRoot()->isAncestorOf(object)) ); + + bool othersShowing = false; + std::vector layers; + for ( SPObject* obj = Inkscape::next_layer(currentRoot(), object); obj; obj = Inkscape::next_layer(currentRoot(), obj) ) { + layers.push_back(obj); + othersShowing |= !SP_ITEM(obj)->isHidden(); + } + for ( SPObject* obj = Inkscape::previous_layer(currentRoot(), object); obj; obj = Inkscape::previous_layer(currentRoot(), obj) ) { + layers.push_back(obj); + othersShowing |= !SP_ITEM(obj)->isHidden(); + } + + + if ( SP_ITEM(object)->isHidden() ) { + SP_ITEM(object)->setHidden(false); + } + + for ( std::vector::iterator it = layers.begin(); it != layers.end(); ++it ) { + SP_ITEM(*it)->setHidden(othersShowing); + } +} + /** * Return layer that contains \a object. */ @@ -447,8 +553,8 @@ bool SPDesktop::isLayer(SPObject *object) const { */ bool SPDesktop::isWithinViewport (SPItem *item) const { - NR::Rect const viewport = get_display_area(); - NR::Maybe const bbox = sp_item_bbox_desktop(item); + Geom::Rect const viewport = get_display_area(); + Geom::OptRect const bbox = item->getBboxDesktop(); if (bbox) { return viewport.contains(*bbox); } else { @@ -499,6 +605,17 @@ SPDesktop::change_document (SPDocument *theDocument) selection->clear(); setDocument (theDocument); + + /* update the rulers, connect the desktop widget's signal to the new namedview etc. + (this can probably be done in a better way) */ + Gtk::Window *parent = this->getToplevel(); + g_assert(parent != NULL); + SPDesktopWidget *dtw = (SPDesktopWidget *) parent->get_data("desktopwidget"); + if (dtw) { + dtw->desktop = this; + } + dtw->updateNamedview(); + _namedview_modified (namedview, SP_OBJECT_MODIFIED_FLAG, this); _document_replaced_signal.emit (this, theDocument); } @@ -513,15 +630,23 @@ SPDesktop::set_event_context (GtkType type, const gchar *config) while (event_context) { ec = event_context; sp_event_context_deactivate (ec); - event_context = ec->next; + // we have to keep event_context valid during destruction - otherwise writing + // destructors is next to impossible + SPEventContext *next = ec->next; sp_event_context_finish (ec); g_object_unref (G_OBJECT (ec)); + event_context = next; } - Inkscape::XML::Node *repr = (config) ? inkscape_get_repr (_inkscape, config) : NULL; - ec = sp_event_context_new (type, this, repr, SP_EVENT_CONTEXT_STATIC); + // The event_context will be null. This means that it will be impossible + // to process any event invoked by the lines below. See for example bug + // LP #622350. Cutting and undoing again in the node tool resets the event + // context to the node tool. In this bug the line bellow invokes GDK_LEAVE_NOTIFY + // events which cannot be handled and must be discarded. + ec = sp_event_context_new (type, this, config, SP_EVENT_CONTEXT_STATIC); ec->next = event_context; event_context = ec; + // Now the event_context has been set again and we can process all events again sp_event_context_activate (ec); _event_context_changed_signal.emit (this, ec); } @@ -533,7 +658,6 @@ void SPDesktop::push_event_context (GtkType type, const gchar *config, unsigned int key) { SPEventContext *ref, *ec; - Inkscape::XML::Node *repr; if (event_context && event_context->key == key) return; ref = event_context; @@ -546,8 +670,7 @@ SPDesktop::push_event_context (GtkType type, const gchar *config, unsigned int k } if (event_context) sp_event_context_deactivate (event_context); - repr = (config) ? inkscape_get_repr (INKSCAPE, config) : NULL; - ec = sp_event_context_new (type, this, repr, key); + ec = sp_event_context_new (type, this, config, key); ec->next = event_context; event_context = ec; sp_event_context_activate (ec); @@ -558,60 +681,57 @@ SPDesktop::push_event_context (GtkType type, const gchar *config, unsigned int k * Sets the coordinate status to a given point */ void -SPDesktop::set_coordinate_status (NR::Point p) { +SPDesktop::set_coordinate_status (Geom::Point p) { _widget->setCoordinateStatus(p); } /** - * \see sp_document_item_from_list_at_point_bottom() + * \see SPDocument::getItemFromListAtPointBottom() */ -SPItem * -SPDesktop::item_from_list_at_point_bottom (const GSList *list, NR::Point const p) const +SPItem *SPDesktop::getItemFromListAtPointBottom(const GSList *list, Geom::Point const p) const { g_return_val_if_fail (doc() != NULL, NULL); - return sp_document_item_from_list_at_point_bottom (dkey, SP_GROUP (doc()->root), list, p); + return SPDocument::getItemFromListAtPointBottom(dkey, SP_GROUP (doc()->root), list, p); } /** - * \see sp_document_item_at_point() + * \see SPDocument::getItemAtPoint() */ -SPItem * -SPDesktop::item_at_point (NR::Point const p, bool into_groups, SPItem *upto) const +SPItem *SPDesktop::getItemAtPoint(Geom::Point const p, bool into_groups, SPItem *upto) const { g_return_val_if_fail (doc() != NULL, NULL); - return sp_document_item_at_point (doc(), dkey, p, into_groups, upto); + return doc()->getItemAtPoint( dkey, p, into_groups, upto); } /** - * \see sp_document_group_at_point() + * \see SPDocument::getGroupAtPoint() */ -SPItem * -SPDesktop::group_at_point (NR::Point const p) const +SPItem *SPDesktop::getGroupAtPoint(Geom::Point const p) const { g_return_val_if_fail (doc() != NULL, NULL); - return sp_document_group_at_point (doc(), dkey, p); + return doc()->getGroupAtPoint(dkey, p); } /** * \brief Returns the mouse point in document coordinates; if mouse is * outside the canvas, returns the center of canvas viewpoint */ -NR::Point +Geom::Point SPDesktop::point() const { - NR::Point p = _widget->getPointer(); - NR::Point pw = sp_canvas_window_to_world (canvas, p); + Geom::Point p = _widget->getPointer(); + Geom::Point pw = sp_canvas_window_to_world (canvas, p); p = w2d(pw); - NR::Rect const r = canvas->getViewbox(); + Geom::Rect const r = canvas->getViewbox(); - NR::Point r0 = w2d(r.min()); - NR::Point r1 = w2d(r.max()); + Geom::Point r0 = w2d(r.min()); + Geom::Point r1 = w2d(r.max()); - if (p[NR::X] >= r0[NR::X] && - p[NR::X] <= r1[NR::X] && - p[NR::Y] >= r1[NR::Y] && - p[NR::Y] <= r0[NR::Y]) + if (p[Geom::X] >= r0[Geom::X] && + p[Geom::X] <= r1[Geom::X] && + p[Geom::Y] >= r1[Geom::Y] && + p[Geom::Y] <= r0[Geom::Y]) { return p; } else { @@ -625,13 +745,13 @@ SPDesktop::point() const void SPDesktop::push_current_zoom (GList **history) { - NR::Rect const area = get_display_area(); + Geom::Rect const area = get_display_area(); NRRect *old_zoom = g_new(NRRect, 1); - old_zoom->x0 = area.min()[NR::X]; - old_zoom->x1 = area.max()[NR::X]; - old_zoom->y0 = area.min()[NR::Y]; - old_zoom->y1 = area.max()[NR::Y]; + old_zoom->x0 = area.min()[Geom::X]; + old_zoom->x1 = area.max()[Geom::X]; + old_zoom->y0 = area.min()[Geom::Y]; + old_zoom->y1 = area.max()[Geom::Y]; if ( *history == NULL || !( ( ((NRRect *) ((*history)->data))->x0 == old_zoom->x0 ) && ( ((NRRect *) ((*history)->data))->x1 == old_zoom->x1 ) && @@ -643,7 +763,7 @@ SPDesktop::push_current_zoom (GList **history) } /** - * Set viewbox. + * Set viewbox (x0, x1, y0 and y1 are in document pixels. Border is in screen pixels). */ void SPDesktop::set_display_area (double x0, double y0, double x1, double y1, double border, bool log) @@ -661,55 +781,61 @@ SPDesktop::set_display_area (double x0, double y0, double x1, double y1, double double const cx = 0.5 * (x0 + x1); double const cy = 0.5 * (y0 + y1); - NR::Rect const viewbox = NR::expand(canvas->getViewbox(), border); + // FIXME: This 2geom idiom doesn't allow us to declare dbox const + Geom::Rect viewbox = canvas->getViewbox(); + viewbox.expandBy(-border); - double scale = expansion(_d2w); + double scale = _d2w.descrim(); double newscale; - if (((x1 - x0) * viewbox.dimensions()[NR::Y]) > ((y1 - y0) * viewbox.dimensions()[NR::X])) { - newscale = viewbox.dimensions()[NR::X] / (x1 - x0); + if (((x1 - x0) * viewbox.dimensions()[Geom::Y]) > ((y1 - y0) * viewbox.dimensions()[Geom::X])) { + newscale = viewbox.dimensions()[Geom::X] / (x1 - x0); } else { - newscale = viewbox.dimensions()[NR::Y] / (y1 - y0); + newscale = viewbox.dimensions()[Geom::Y] / (y1 - y0); } - newscale = CLAMP(newscale, SP_DESKTOP_ZOOM_MIN, SP_DESKTOP_ZOOM_MAX); + newscale = CLAMP(newscale, SP_DESKTOP_ZOOM_MIN, SP_DESKTOP_ZOOM_MAX); // unit: 'screen pixels' per 'document pixels' int clear = FALSE; if (!NR_DF_TEST_CLOSE (newscale, scale, 1e-4 * scale)) { - /* Set zoom factors */ - _d2w = NR::Matrix(NR::scale(newscale, -newscale)); - _w2d = NR::Matrix(NR::scale(1/newscale, 1/-newscale)); + // zoom changed - set new zoom factors + _d2w = Geom::Scale(newscale, -newscale); + _w2d = Geom::Scale(1/newscale, 1/-newscale); sp_canvas_item_affine_absolute(SP_CANVAS_ITEM(main), _d2w); clear = TRUE; + signal_zoom_changed.emit(_d2w.descrim()); } - /* Calculate top left corner */ - x0 = cx - 0.5 * viewbox.dimensions()[NR::X] / newscale; - y1 = cy + 0.5 * viewbox.dimensions()[NR::Y] / newscale; + /* Calculate top left corner (in document pixels) */ + x0 = cx - 0.5 * viewbox.dimensions()[Geom::X] / newscale; + y1 = cy + 0.5 * viewbox.dimensions()[Geom::Y] / newscale; /* Scroll */ sp_canvas_scroll_to (canvas, x0 * newscale - border, y1 * -newscale - border, clear); + /* update perspective lines if we are in the 3D box tool (so that infinite ones are shown correctly) */ + sp_box3d_context_update_lines(event_context); + _widget->updateRulers(); - _widget->updateScrollbars(expansion(_d2w)); + _widget->updateScrollbars(_d2w.descrim()); _widget->updateZoom(); } -void SPDesktop::set_display_area(NR::Rect const &a, NR::Coord b, bool log) +void SPDesktop::set_display_area(Geom::Rect const &a, Geom::Coord b, bool log) { - set_display_area(a.min()[NR::X], a.min()[NR::Y], a.max()[NR::X], a.max()[NR::Y], b, log); + set_display_area(a.min()[Geom::X], a.min()[Geom::Y], a.max()[Geom::X], a.max()[Geom::Y], b, log); } /** * Return viewbox dimensions. */ -NR::Rect SPDesktop::get_display_area() const +Geom::Rect SPDesktop::get_display_area() const { - NR::Rect const viewbox = canvas->getViewbox(); + Geom::Rect const viewbox = canvas->getViewbox(); double const scale = _d2w[0]; - return NR::Rect(NR::Point(viewbox.min()[NR::X] / scale, viewbox.max()[NR::Y] / -scale), - NR::Point(viewbox.max()[NR::X] / scale, viewbox.min()[NR::Y] / -scale)); + return Geom::Rect(Geom::Point(viewbox.min()[Geom::X] / scale, viewbox.max()[Geom::Y] / -scale), + Geom::Point(viewbox.max()[Geom::X] / scale, viewbox.min()[Geom::Y] / -scale)); } /** @@ -762,6 +888,57 @@ SPDesktop::next_zoom() zooms_future = g_list_remove (zooms_future, ((NRRect *) zooms_future->data)); } +/** \brief Performs a quick zoom into what the user is working on + \param enable Whether we're going in or out of quick zoom + +*/ +void +SPDesktop::zoom_quick (bool enable) +{ + if (enable == _quick_zoom_enabled) { + return; + } + + if (enable == true) { + _quick_zoom_stored_area = get_display_area(); + bool zoomed = false; + + // TODO This needs to migrate into the node tool, but currently the design + // of this method is sufficiently wrong to prevent this. + if (!zoomed && INK_IS_NODE_TOOL(event_context)) { + InkNodeTool *nt = static_cast(event_context); + if (!nt->_selected_nodes->empty()) { + Geom::Rect nodes = *nt->_selected_nodes->bounds(); + double area = nodes.area(); + // do not zoom if a single cusp node is selected aand the bounds + // have zero area. + if (!Geom::are_near(area, 0) && area * 2.0 < _quick_zoom_stored_area.area()) { + set_display_area(nodes, true); + zoomed = true; + } + } + } + + if (!zoomed) { + Geom::OptRect const d = selection->bounds(); + if (d && d->area() * 2.0 < _quick_zoom_stored_area.area()) { + set_display_area(*d, true); + zoomed = true; + } + } + + if (!zoomed) { + zoom_relative(_quick_zoom_stored_area.midpoint()[Geom::X], _quick_zoom_stored_area.midpoint()[Geom::Y], 2.0); + zoomed = true; + } + } else { + set_display_area(_quick_zoom_stored_area, false); + } + + _quick_zoom_enabled = enable; + return; +} + /** * Zoom to point with absolute zoom factor. */ @@ -773,13 +950,13 @@ SPDesktop::zoom_absolute_keep_point (double cx, double cy, double px, double py, // maximum or minimum zoom reached, but there's no exact equality because of rounding errors; // this check prevents "sliding" when trying to zoom in at maximum zoom; /// \todo someone please fix calculations properly and remove this hack - if (fabs(expansion(_d2w) - zoom) < 0.0001*zoom && (fabs(SP_DESKTOP_ZOOM_MAX - zoom) < 0.01 || fabs(SP_DESKTOP_ZOOM_MIN - zoom) < 0.000001)) + if (fabs(_d2w.descrim() - zoom) < 0.0001*zoom && (fabs(SP_DESKTOP_ZOOM_MAX - zoom) < 0.01 || fabs(SP_DESKTOP_ZOOM_MIN - zoom) < 0.000001)) return; - NR::Rect const viewbox = canvas->getViewbox(); + Geom::Rect const viewbox = canvas->getViewbox(); - double const width2 = viewbox.dimensions()[NR::X] / zoom; - double const height2 = viewbox.dimensions()[NR::Y] / zoom; + double const width2 = viewbox.dimensions()[Geom::X] / zoom; + double const height2 = viewbox.dimensions()[Geom::Y] / zoom; set_display_area(cx - px * width2, cy - py * height2, @@ -788,6 +965,26 @@ SPDesktop::zoom_absolute_keep_point (double cx, double cy, double px, double py, 0.0); } +/** + * Apply the desktop's current style or the tool style to the object. + */ +void SPDesktop::applyCurrentOrToolStyle(SPObject *obj, Glib::ustring const &tool_path, bool with_text) +{ + SPCSSAttr *css_current = sp_desktop_get_style(this, with_text); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + if (prefs->getBool(tool_path + "/usecurrent") && css_current) { + obj->setCSS(css_current,"style"); + } else { + SPCSSAttr *css = prefs->getInheritedStyle(tool_path + "/style"); + obj->setCSS(css,"style"); + sp_repr_css_attr_unref(css); + } + if (css_current) { + sp_repr_css_attr_unref(css_current); + } +} + /** * Zoom to center with absolute zoom factor. */ @@ -803,24 +1000,24 @@ SPDesktop::zoom_absolute (double cx, double cy, double zoom) void SPDesktop::zoom_relative_keep_point (double cx, double cy, double zoom) { - NR::Rect const area = get_display_area(); + Geom::Rect const area = get_display_area(); - if (cx < area.min()[NR::X]) { - cx = area.min()[NR::X]; + if (cx < area.min()[Geom::X]) { + cx = area.min()[Geom::X]; } - if (cx > area.max()[NR::X]) { - cx = area.max()[NR::X]; + if (cx > area.max()[Geom::X]) { + cx = area.max()[Geom::X]; } - if (cy < area.min()[NR::Y]) { - cy = area.min()[NR::Y]; + if (cy < area.min()[Geom::Y]) { + cy = area.min()[Geom::Y]; } - if (cy > area.max()[NR::Y]) { - cy = area.max()[NR::Y]; + if (cy > area.max()[Geom::Y]) { + cy = area.max()[Geom::Y]; } - gdouble const scale = expansion(_d2w) * zoom; - double const px = (cx - area.min()[NR::X]) / area.dimensions()[NR::X]; - double const py = (cy - area.min()[NR::Y]) / area.dimensions()[NR::Y]; + gdouble const scale = _d2w.descrim() * zoom; + double const px = (cx - area.min()[Geom::X]) / area.dimensions()[Geom::X]; + double const py = (cy - area.min()[Geom::Y]) / area.dimensions()[Geom::Y]; zoom_absolute_keep_point(cx, cy, px, py, scale); } @@ -831,7 +1028,7 @@ SPDesktop::zoom_relative_keep_point (double cx, double cy, double zoom) void SPDesktop::zoom_relative (double cx, double cy, double zoom) { - gdouble scale = expansion(_d2w) * zoom; + gdouble scale = _d2w.descrim() * zoom; zoom_absolute (cx, cy, scale); } @@ -841,10 +1038,10 @@ SPDesktop::zoom_relative (double cx, double cy, double zoom) void SPDesktop::zoom_page() { - NR::Rect d(NR::Point(0, 0), - NR::Point(sp_document_width(doc()), sp_document_height(doc()))); + Geom::Rect d(Geom::Point(0, 0), + Geom::Point(doc()->getWidth(), doc()->getHeight())); - if (d.isEmpty(1.0)) { + if (d.minExtent() < 1.0) { return; } @@ -857,14 +1054,14 @@ SPDesktop::zoom_page() void SPDesktop::zoom_page_width() { - NR::Rect const a = get_display_area(); + Geom::Rect const a = get_display_area(); - if (sp_document_width(doc()) < 1.0) { + if (doc()->getWidth() < 1.0) { return; } - NR::Rect d(NR::Point(0, a.midpoint()[NR::Y]), - NR::Point(sp_document_width(doc()), a.midpoint()[NR::Y])); + Geom::Rect d(Geom::Point(0, a.midpoint()[Geom::Y]), + Geom::Point(doc()->getWidth(), a.midpoint()[Geom::Y])); set_display_area(d, 10); } @@ -875,9 +1072,9 @@ SPDesktop::zoom_page_width() void SPDesktop::zoom_selection() { - NR::Maybe const d = selection->bounds(); + Geom::OptRect const d = selection->bounds(); - if ( !d || d->isEmpty(0.1) ) { + if ( !d || d->minExtent() < 0.1 ) { return; } @@ -900,21 +1097,31 @@ void SPDesktop::zoom_drawing() { g_return_if_fail (doc() != NULL); - SPItem *docitem = SP_ITEM (sp_document_root (doc())); + SPItem *docitem = SP_ITEM(doc()->getRoot()); g_return_if_fail (docitem != NULL); - NR::Maybe d = sp_item_bbox_desktop(docitem); + Geom::OptRect d = docitem->getBboxDesktop(); /* Note that the second condition here indicates that ** there are no items in the drawing. */ - if ( !d || d->isEmpty(1.0) ) { + if ( !d || d->minExtent() < 0.1 ) { return; } set_display_area(*d, 10); } +/** + * Scroll canvas by specific coordinate amount in svg coordinates. + */ +void +SPDesktop::scroll_world_in_svg_coords (double dx, double dy, bool is_scrolling) +{ + double scale = _d2w.descrim(); + scroll_world(dx*scale, dy*scale, is_scrolling); +} + /** * Scroll canvas by specific coordinate amount. */ @@ -923,50 +1130,59 @@ SPDesktop::scroll_world (double dx, double dy, bool is_scrolling) { g_assert(_widget); - NR::Rect const viewbox = canvas->getViewbox(); + Geom::Rect const viewbox = canvas->getViewbox(); - sp_canvas_scroll_to(canvas, viewbox.min()[NR::X] - dx, viewbox.min()[NR::Y] - dy, FALSE, is_scrolling); + sp_canvas_scroll_to(canvas, viewbox.min()[Geom::X] - dx, viewbox.min()[Geom::Y] - dy, FALSE, is_scrolling); + + /* update perspective lines if we are in the 3D box tool (so that infinite ones are shown correctly) */ + sp_box3d_context_update_lines(event_context); _widget->updateRulers(); - _widget->updateScrollbars(expansion(_d2w)); + _widget->updateScrollbars(_d2w.descrim()); } bool -SPDesktop::scroll_to_point (NR::Point const *p, gdouble autoscrollspeed) +SPDesktop::scroll_to_point (Geom::Point const &p, gdouble autoscrollspeed) { - gdouble autoscrolldistance = (gdouble) prefs_get_int_attribute_limited ("options.autoscrolldistance", "value", 0, -1000, 10000); + using Geom::X; + using Geom::Y; + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gdouble autoscrolldistance = (gdouble) prefs->getIntLimited("/options/autoscrolldistance/value", 0, -1000, 10000); // autoscrolldistance is in screen pixels, but the display area is in document units - autoscrolldistance /= expansion(_d2w); - NR::Rect const dbox = NR::expand(get_display_area(), -autoscrolldistance); + autoscrolldistance /= _d2w.descrim(); + // FIXME: This 2geom idiom doesn't allow us to declare dbox const + Geom::Rect dbox = get_display_area(); + dbox.expandBy(-autoscrolldistance); - if (!((*p)[NR::X] > dbox.min()[NR::X] && (*p)[NR::X] < dbox.max()[NR::X]) || - !((*p)[NR::Y] > dbox.min()[NR::Y] && (*p)[NR::Y] < dbox.max()[NR::Y]) ) { + if (!(p[X] > dbox.min()[X] && p[X] < dbox.max()[X]) || + !(p[Y] > dbox.min()[Y] && p[Y] < dbox.max()[Y]) ) { - NR::Point const s_w( (*p) * _d2w ); + Geom::Point const s_w( p * (Geom::Matrix)_d2w ); gdouble x_to; - if ((*p)[NR::X] < dbox.min()[NR::X]) - x_to = dbox.min()[NR::X]; - else if ((*p)[NR::X] > dbox.max()[NR::X]) - x_to = dbox.max()[NR::X]; + if (p[X] < dbox.min()[X]) + x_to = dbox.min()[X]; + else if (p[X] > dbox.max()[X]) + x_to = dbox.max()[X]; else - x_to = (*p)[NR::X]; + x_to = p[X]; gdouble y_to; - if ((*p)[NR::Y] < dbox.min()[NR::Y]) - y_to = dbox.min()[NR::Y]; - else if ((*p)[NR::Y] > dbox.max()[NR::Y]) - y_to = dbox.max()[NR::Y]; + if (p[Y] < dbox.min()[Y]) + y_to = dbox.min()[Y]; + else if (p[Y] > dbox.max()[Y]) + y_to = dbox.max()[Y]; else - y_to = (*p)[NR::Y]; + y_to = p[Y]; - NR::Point const d_dt(x_to, y_to); - NR::Point const d_w( d_dt * _d2w ); - NR::Point const moved_w( d_w - s_w ); + Geom::Point const d_dt(x_to, y_to); + Geom::Point const d_w( d_dt * _d2w ); + Geom::Point const moved_w( d_w - s_w ); if (autoscrollspeed == 0) - autoscrollspeed = prefs_get_double_attribute_limited ("options.autoscrollspeed", "value", 1, 0, 10); + autoscrollspeed = prefs->getDoubleLimited("/options/autoscrollspeed/value", 1, 0, 10); if (autoscrollspeed != 0) scroll_world (autoscrollspeed * moved_w); @@ -1012,6 +1228,33 @@ SPDesktop::fullscreen() _widget->setFullscreen(); } +/** \brief Checks to see if the user is working in focused mode + + Returns the value of \c _focusMode +*/ +bool +SPDesktop::is_focusMode() +{ + return _focusMode; +} + +/** \brief Changes whether the user is in focus mode or not + \param mode Which mode the view should be in + +*/ +void +SPDesktop::focusMode (bool mode) +{ + if (mode == _focusMode) { return; } + + _focusMode = mode; + + layoutWidget(); + //sp_desktop_widget_layout(SPDesktopWidget); + + return; +} + void SPDesktop::getWindowGeometry (gint &x, gint &y, gint &w, gint &h) { @@ -1019,7 +1262,7 @@ SPDesktop::getWindowGeometry (gint &x, gint &y, gint &w, gint &h) } void -SPDesktop::setWindowPosition (NR::Point p) +SPDesktop::setWindowPosition (Geom::Point p) { _widget->setPosition (p); } @@ -1086,9 +1329,11 @@ SPDesktop::shutdown() bool SPDesktop::onDeleteUI (GdkEventAny*) { - if(shutdown()) return true; - destroyWidget(); - return false; + if(shutdown()) + return true; + + destroyWidget(); + return false; } /** @@ -1101,7 +1346,7 @@ bool SPDesktop::onDeleteUI (GdkEventAny*) bool SPDesktop::onWindowStateEvent (GdkEventWindowState* event) { - // Record the desktop window's state + // Record the desktop window's state window_state = event->new_window_state; // Layout may differ depending on full-screen mode or not @@ -1110,7 +1355,7 @@ SPDesktop::onWindowStateEvent (GdkEventWindowState* event) layoutWidget(); } - return false; + return false; } void @@ -1140,14 +1385,14 @@ SPDesktop::isToolboxButtonActive (gchar const *id) void SPDesktop::emitToolSubselectionChanged(gpointer data) { - _tool_subselection_changed.emit(data); - inkscape_subselection_changed (this); + _tool_subselection_changed.emit(data); + inkscape_subselection_changed (this); } void SPDesktop::updateNow() { - sp_canvas_update_now(canvas); + sp_canvas_update_now(canvas); } void @@ -1166,14 +1411,9 @@ void SPDesktop::setWaitingCursor() GdkCursor *waiting = gdk_cursor_new(GDK_WATCH); gdk_window_set_cursor(GTK_WIDGET(sp_desktop_canvas(this))->window, waiting); gdk_cursor_unref(waiting); + // GDK needs the flush for the cursor change to take effect + gdk_flush(); waiting_cursor = true; - - // Stupidly broken GDK cannot just set the new cursor right now - it needs some main loop iterations for that - // Since setting waiting_cursor is usually immediately followed by some Real Work, we must run the iterations here - // CAUTION: iterations may redraw, and redraw may be interrupted, so you cannot assume that anything is the same - // after the call to setWaitingCursor as it was before - while( Gtk::Main::events_pending() ) - Gtk::Main::iteration(); } void SPDesktop::clearWaitingCursor() @@ -1195,8 +1435,7 @@ void SPDesktop::toggleGrids() } } else { //there is no grid present at the moment. add a rectangular grid and make it visible - Inkscape::XML::Node *repr = SP_OBJECT_REPR(namedview); - Inkscape::CanvasGrid::writeNewGridToRepr(repr, sp_desktop_document(this), Inkscape::GRID_RECTANGULAR); + namedview->writeNewGrid(sp_desktop_document(this), Inkscape::GRID_RECTANGULAR); showGrids(true); } } @@ -1212,6 +1451,11 @@ void SPDesktop::showGrids(bool show, bool dirty_document) } } +void SPDesktop::toggleSnapGlobal() +{ + bool v = namedview->getSnapGlobal(); + namedview->setSnapGlobal(!v); +} //---------------------------------------------------------------------- // Callback implementations. The virtual ones are connected by the view. @@ -1219,7 +1463,7 @@ void SPDesktop::showGrids(bool show, bool dirty_document) void SPDesktop::onPositionSet (double x, double y) { - _widget->viewSetPosition (NR::Point(x,y)); + _widget->viewSetPosition (Geom::Point(x,y)); } void @@ -1253,7 +1497,7 @@ SPDesktop::setDocument (SPDocument *doc) { if (this->doc() && doc) { namedview->hide(this); - sp_item_invoke_hide (SP_ITEM (sp_document_root (this->doc())), dkey); + SP_ITEM(this->doc()->getRoot())->invoke_hide(dkey); } if (_layer_hierarchy) { @@ -1264,7 +1508,7 @@ SPDesktop::setDocument (SPDocument *doc) _layer_hierarchy->connectAdded(sigc::bind(sigc::ptr_fun(_layer_activated), this)); _layer_hierarchy->connectRemoved(sigc::bind(sigc::ptr_fun(_layer_deactivated), this)); _layer_hierarchy->connectChanged(sigc::bind(sigc::ptr_fun(_layer_hierarchy_changed), this)); - _layer_hierarchy->setTop(SP_DOCUMENT_ROOT(doc)); + _layer_hierarchy->setTop(doc->getRoot()); /* setup EventLog */ event_log = new Inkscape::EventLog(doc); @@ -1284,13 +1528,12 @@ SPDesktop::setDocument (SPDocument *doc) _modified_connection = namedview->connectModified(sigc::bind<2>(sigc::ptr_fun(&_namedview_modified), this)); number = namedview->getViewCount(); - ai = sp_item_invoke_show (SP_ITEM (sp_document_root (doc)), + ai = SP_ITEM(doc->getRoot())->invoke_show( SP_CANVAS_ARENA (drawing)->arena, dkey, SP_ITEM_SHOW_DISPLAY); if (ai) { nr_arena_item_add_child (SP_CANVAS_ARENA (drawing)->root, ai, NULL); - nr_arena_item_unref (ai); } namedview->show(this); /* Ugly hack */ @@ -1327,7 +1570,7 @@ SPDesktop::onDocumentResized (gdouble width, gdouble height) { _doc2dt[5] = height; sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (drawing), _doc2dt); - NR::Rect const a(NR::Point(0, 0), NR::Point(width, height)); + Geom::Rect const a(Geom::Point(0, 0), Geom::Point(width, height)); SP_CTRLRECT(page)->setRectangle(a); SP_CTRLRECT(page_border)->setRectangle(a); } @@ -1352,7 +1595,7 @@ SPDesktop::_onSelectionModified (Inkscape::Selection */*selection*/, guint /*flags*/, SPDesktop *dt) { if (!dt->_widget) return; - dt->_widget->updateScrollbars (expansion(dt->_d2w)); + dt->_widget->updateScrollbars (dt->_d2w.descrim()); } static void @@ -1415,7 +1658,7 @@ static void _reconstruction_start (SPDesktop * desktop) { // printf("Desktop, starting reconstruction\n"); - desktop->_reconstruction_old_layer_id = g_strdup(SP_OBJECT_ID(desktop->currentLayer())); + desktop->_reconstruction_old_layer_id = g_strdup(desktop->currentLayer()->getId()); desktop->_layer_hierarchy->setBottom(desktop->currentRoot()); /* @@ -1457,12 +1700,6 @@ _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop) if (flags & SP_OBJECT_MODIFIED_FLAG) { - /* Recalculate snap distances */ - /* FIXME: why is the desktop getting involved in setting up something - ** that is entirely to do with the namedview? - */ - _update_snap_distances (desktop); - /* Show/hide page background */ if (nv->pagecolor & 0xff) { sp_canvas_item_show (desktop->table); @@ -1488,7 +1725,7 @@ _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop) int order = sp_canvas_item_order (desktop->page_border); int morder = sp_canvas_item_order (desktop->drawing); if (morder > order) sp_canvas_item_raise (desktop->page_border, - morder - order); + morder - order); } } else { sp_canvas_item_hide (desktop->page_border); @@ -1504,77 +1741,57 @@ _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop) ((CtrlRect *) desktop->page_border)->setShadow(0, 0x00000000); } + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (SP_RGBA32_A_U(nv->pagecolor) < 128 || (SP_RGBA32_R_U(nv->pagecolor) + SP_RGBA32_G_U(nv->pagecolor) + SP_RGBA32_B_U(nv->pagecolor)) >= 384) { // the background color is light or transparent, use black outline - SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = prefs_get_int_attribute("options.wireframecolors", "onlight", 0xff); + SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = prefs->getInt("/options/wireframecolors/onlight", 0xff); } else { // use white outline - SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = prefs_get_int_attribute("options.wireframecolors", "ondark", 0xffffffff); + SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = prefs->getInt("/options/wireframecolors/ondark", 0xffffffff); } } } -/** - * Callback to reset snapper's distances. - */ -static void -_update_snap_distances (SPDesktop *desktop) -{ - SPUnit const &px = sp_unit_get_by_id(SP_UNIT_PX); - - SPNamedView &nv = *desktop->namedview; - - //tell all grid snappers - for ( GSList const *l = nv.grids; l != NULL; l = l->next) { - Inkscape::CanvasGrid *grid = (Inkscape::CanvasGrid*) l->data; - grid->snapper->setDistance(sp_convert_distance_full(nv.gridtolerance, - *nv.gridtoleranceunit, - px)); - } - - nv.snap_manager.guide.setDistance(sp_convert_distance_full(nv.guidetolerance, - *nv.guidetoleranceunit, - px)); - nv.snap_manager.object.setDistance(sp_convert_distance_full(nv.objecttolerance, - *nv.objecttoleranceunit, - px)); -} - - -NR::Matrix SPDesktop::w2d() const +Geom::Matrix SPDesktop::w2d() const { return _w2d; } -NR::Point SPDesktop::w2d(NR::Point const &p) const +Geom::Point SPDesktop::w2d(Geom::Point const &p) const { return p * _w2d; } -NR::Point SPDesktop::d2w(NR::Point const &p) const +Geom::Point SPDesktop::d2w(Geom::Point const &p) const { return p * _d2w; } -NR::Matrix SPDesktop::doc2dt() const +Geom::Matrix SPDesktop::doc2dt() const { return _doc2dt; } -NR::Point SPDesktop::doc2dt(NR::Point const &p) const +Geom::Matrix SPDesktop::dt2doc() const +{ + // doc2dt is its own inverse + return _doc2dt; +} + +Geom::Point SPDesktop::doc2dt(Geom::Point const &p) const { return p * _doc2dt; } -NR::Point SPDesktop::dt2doc(NR::Point const &p) const +Geom::Point SPDesktop::dt2doc(Geom::Point const &p) const { - return p / _doc2dt; + return p * dt2doc(); } -/** +/* * Pop event context from desktop's context stack. Never used. */ // void @@ -1616,4 +1833,4 @@ NR::Point SPDesktop::dt2doc(NR::Point const &p) const fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :