summaryrefslogtreecommitdiffstats
path: root/src/desktop.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/desktop.cpp')
-rw-r--r--src/desktop.cpp682
1 files changed, 373 insertions, 309 deletions
diff --git a/src/desktop.cpp b/src/desktop.cpp
index d482d0d7f..c56c42267 100644
--- a/src/desktop.cpp
+++ b/src/desktop.cpp
@@ -23,12 +23,11 @@
#ifdef HAVE_CONFIG_H
-# include "config.h"
+#include <config.h>
#endif
#include "ui/dialog/dialog-manager.h"
#include <glibmm/i18n.h>
-#include <sigc++/functors/mem_fun.h>
#include <2geom/transforms.h>
#include <2geom/rect.h>
@@ -41,39 +40,30 @@
#include "desktop-style.h"
#include "device-manager.h"
#include "display/canvas-arena.h"
+#include "display/canvas-debug.h"
#include "display/canvas-grid.h"
+#include "display/canvas-rotate.h"
#include "display/canvas-temporary-item-list.h"
#include "display/drawing-group.h"
#include "display/gnome-canvas-acetate.h"
-#include "display/drawing.h"
#include "display/snap-indicator.h"
#include "display/sodipodi-ctrlrect.h"
#include "display/sp-canvas-group.h"
-#include "display/sp-canvas.h"
#include "display/sp-canvas-util.h"
-#include "document.h"
#include "document-undo.h"
#include "event-log.h"
#include "helper/action-context.h"
#include "ui/interface.h"
#include "layer-fns.h"
#include "layer-manager.h"
-#include "layer-model.h"
-#include "macros.h"
#include "message-context.h"
#include "message-stack.h"
-#include "preferences.h"
#include "resource-manager.h"
#include "ui/tools/select-tool.h"
-#include "selection.h"
-#include "sp-item-group.h"
-#include "sp-item-group.h"
#include "sp-namedview.h"
#include "sp-root.h"
-#include "sp-defs.h"
#include "ui/tool-factory.h"
#include "widgets/desktop-widget.h"
-#include "xml/repr.h"
#include "helper/action.h" //sp_action_perform
// TODO those includes are only for node tool quick zoom. Remove them after fixing it.
@@ -132,15 +122,10 @@ SPDesktop::SPDesktop() :
_widget( NULL ),
_guides_message_context( NULL ),
_active( false ),
- _w2d(),
- _d2w(),
_doc2dt( Geom::Scale(1, -1) ),
_image_render_observer(this, "/options/rendering/imageinoutlinemode"),
grids_visible( false )
{
- _d2w.setIdentity();
- _w2d.setIdentity();
-
layers = new Inkscape::LayerModel();
layers->_layer_activated_signal.connect(sigc::bind(sigc::ptr_fun(_layer_activated), this));
layers->_layer_deactivated_signal.connect(sigc::bind(sigc::ptr_fun(_layer_deactivated), this));
@@ -237,10 +222,10 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas, Inkscape::UI::View::EditWid
// 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);
+ 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);
+ controls = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
// Set the select tool as the active tool.
set_event_context2("/tools/select");
@@ -268,7 +253,8 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas, Inkscape::UI::View::EditWid
_doc2dt[5] = document->getHeight().value("px");
sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (drawing), _doc2dt);
- _modified_connection = namedview->connectModified(sigc::bind<2>(sigc::ptr_fun(&_namedview_modified), this));
+ _modified_connection =
+ namedview->connectModified(sigc::bind<2>(sigc::ptr_fun(&_namedview_modified), this));
Inkscape::DrawingItem *ai = document->getRoot()->invoke_show(
SP_CANVAS_ARENA (drawing)->drawing,
@@ -330,6 +316,10 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas, Inkscape::UI::View::EditWid
temporary_item_list = new Inkscape::Display::TemporaryItemList( this );
snapindicator = new Inkscape::Display::SnapIndicator ( this );
+
+ canvas_rotate = sp_canvas_item_new (root, SP_TYPE_CANVAS_ROTATE, NULL);
+ sp_canvas_item_hide( canvas_rotate );
+ // canvas_debug = sp_canvas_item_new (main, SP_TYPE_CANVAS_DEBUG, NULL);
}
@@ -491,7 +481,7 @@ SPDesktop::remove_temporary_canvasitem (Inkscape::Display::TemporaryItem * tempi
}
void SPDesktop::redrawDesktop() {
- sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw
+ sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _current_affine.d2w()); // redraw
}
void SPDesktop::_setDisplayMode(Inkscape::RenderMode mode) {
@@ -745,164 +735,299 @@ Geom::Point SPDesktop::point() const
{
Geom::Point p = _widget->getPointer();
Geom::Point pw = sp_canvas_window_to_world (canvas, p);
- p = w2d(pw);
-
Geom::Rect const r = canvas->getViewbox();
- Geom::Point r0 = w2d(r.min());
- Geom::Point r1 = w2d(r.max());
-
- 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])
- {
+ if (r.interiorContains(pw)) {
+ p = w2d(pw);
return p;
- } else {
- return (r0 + r1) / 2;
}
+
+ // Shouldn't happen
+ std::cerr << "SPDesktop::point(): point outside of canvas!" << std::endl;
+ Geom::Point r0 = w2d(r.min());
+ Geom::Point r1 = w2d(r.max());
+ return (r0 + r1) / 2.0;
}
+
/**
- * Put current zoom data in history list.
+ * Revert back to previous transform if possible. Note: current transform is
+ * always at front of stack.
*/
void
-SPDesktop::push_current_zoom (std::list<Geom::Rect> &history)
+SPDesktop::prev_transform()
{
- Geom::Rect area = get_display_area();
+ if (transforms_past.empty()) {
+ std::cerr << "SPDesktop::prev_transform: current transform missing!" << std::endl;
+ return;
+ }
- if (history.empty() || history.front() != area) {
- history.push_front(area);
+ if (transforms_past.size() == 1) {
+ messageStack()->flash(Inkscape::WARNING_MESSAGE, _("No previous transform."));
+ return;
}
+
+ // Push current transform into future transforms list.
+ transforms_future.push_front( _current_affine );
+
+ // Remove the current transform from the past transforms list.
+ transforms_past.pop_front();
+
+ // restore previous transform
+ _current_affine = transforms_past.front();
+ set_display_area (false);
+
}
+
/**
- * Set viewbox (x0, x1, y0 and y1 are in document pixels. Border is in screen pixels).
+ * Set transform to next in list.
*/
-void
-SPDesktop::set_display_area (double x0, double y0, double x1, double y1, double border, bool log)
+void SPDesktop::next_transform()
{
- g_assert(_widget);
- bool zoomChanged = false;
-
- // save the zoom
- if (log) {
- push_current_zoom(zooms_past);
- // if we do a logged zoom, our zoom-forward list is invalidated, so delete it
- zooms_future.clear();
+ if (transforms_future.empty()) {
+ this->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("No next transform."));
+ return;
}
- double const cx = 0.5 * (x0 + x1);
- double const cy = 0.5 * (y0 + y1);
+ // restore next transform
+ _current_affine = transforms_future.front();
+ set_display_area (false);
- // FIXME: This 2geom idiom doesn't allow us to declare dbox const
- Geom::Rect viewbox = canvas->getViewbox();
- viewbox.expandBy(-border);
+ // remove the just-used transform from the future transforms list
+ transforms_future.pop_front();
- double scale = _d2w.descrim();
- double newscale;
- if (((x1 - x0) * viewbox.dimensions()[Geom::Y]) > ((y1 - y0) * viewbox.dimensions()[Geom::X])) {
- newscale = viewbox.dimensions()[Geom::X] / (x1 - x0);
- } else {
- newscale = viewbox.dimensions()[Geom::Y] / (y1 - y0);
- }
+ // push current transform into past transforms list
+ transforms_past.push_front( _current_affine );
+}
- newscale = CLAMP(newscale, SP_DESKTOP_ZOOM_MIN, SP_DESKTOP_ZOOM_MAX); // unit: 'screen pixels' per 'document pixels'
- int clear = FALSE;
- if (!Geom::are_near(newscale, scale, Geom::EPSILON * scale)) {
- // zoom changed - set new zoom factors
- _d2w = Geom::Scale(newscale, -newscale);
- _w2d = Geom::Scale(1/newscale, 1/-newscale);
- redrawDesktop();
- clear = TRUE;
- zoomChanged = true;
+/**
+ * Clear transform lists.
+ */
+void
+SPDesktop::clear_transform_history()
+{
+ transforms_past.clear();
+ transforms_future.clear();
+}
+
+
+/**
+ * Does all the dirty work in setting the display area.
+ * _current_affine must already be full updated (including offset).
+ * log: if true, save transform in transform stack for reuse.
+ */
+void
+SPDesktop::set_display_area (bool log)
+{
+ // Save the transform
+ if (log) {
+ transforms_past.push_front( _current_affine );
+ // if we do a logged transform, our transform-forward list is invalidated, so delete it
+ transforms_future.clear();
}
- /* 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;
+ redrawDesktop();
// Scroll
- canvas->scrollTo(x0 * newscale - border, y1 * -newscale - border, clear);
+ Geom::Point offset = _current_affine.getOffset();
+ canvas->scrollTo(offset, true);
+ // To do: if transform unchanged call with 'false' (redraw only newly exposed areas).
- /* 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);
+ /* Update perspective lines if we are in the 3D box tool (so that infinite ones are shown
+ * correctly) */
if (SP_IS_BOX3D_CONTEXT(event_context)) {
SP_BOX3D_CONTEXT(event_context)->_vpdrag->updateLines();
}
_widget->updateRulers();
- _widget->updateScrollbars(_d2w.descrim());
+ _widget->updateScrollbars(_current_affine.getZoom());
_widget->updateZoom();
+ _widget->updateRotation();
- if ( zoomChanged ) {
- signal_zoom_changed.emit(_d2w.descrim());
- }
+ signal_zoom_changed.emit(_current_affine.getZoom());
}
-void SPDesktop::set_display_area(Geom::Rect const &a, Geom::Coord b, bool log)
+
+/**
+ * Map the drawing to the window so that 'c' lies at 'w' where where 'c'
+ * is a point on the canvas and 'w' is position in window in screen pixels.
+ */
+void
+SPDesktop::set_display_area (Geom::Point const &c, Geom::Point const &w, bool log)
{
- set_display_area(a.min()[Geom::X], a.min()[Geom::Y], a.max()[Geom::X], a.max()[Geom::Y], b, log);
+ // The relative offset needed to keep c at w.
+ Geom::Point offset = d2w(c) - w;
+ _current_affine.addOffset( offset );
+ set_display_area( log );
+}
+
+
+/**
+ * Map the center of rectangle 'r' (which specifies a non-rotated region of the
+ * drawing) to lie at the center of the window. The zoom factor is calculated such that
+ * the edges of 'r' closest to 'w' are 'border' length inside of the window (if
+ * there is no rotation). 'r' is in document pixel units, 'border' is in screen pixels.
+ */
+void
+SPDesktop::set_display_area( Geom::Rect const &r, double border, bool log)
+{
+ // Create a rectangle the size of the window aligned with origin.
+ Geom::Rect w( Geom::Point(), canvas->getViewbox().dimensions() ); // Not the SVG 'viewBox'.
+
+ // Shrink window to account for border padding.
+ w.expandBy( -border );
+
+ double zoom = 1.0;
+ // Determine which direction limits scale:
+ // if (r.width/w.width > r.height/w.height) then zoom using width.
+ // Avoiding division in test:
+ if ( r.width()*w.height() > r.height()*w.width() ) {
+ zoom = w.width() / r.width();
+ } else {
+ zoom = w.height() / r.height();
+ }
+ _current_affine.setScale( zoom );
+
+ // Zero offset, actual offset calculated later.
+ _current_affine.setOffset( Geom::Point( 0, 0 ) );
+
+ set_display_area( r.midpoint(), w.midpoint(), log );
}
+
/**
- * Return viewbox dimensions.
+ * Return viewbox dimensions. FixMe: Doesn't handle rotation. FixMe InvertedY
*/
Geom::Rect SPDesktop::get_display_area() const
{
Geom::Rect const viewbox = canvas->getViewbox();
-
- double const scale = _d2w[0];
+ double const scale = _current_affine.getZoom();
/// @fixme hardcoded desktop transform
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));
}
+
+/**
+ * Zoom keeping the point 'c' fixed in the desktop window.
+ */
+void
+SPDesktop::zoom_absolute_keep_point (Geom::Point const &c, double zoom)
+{
+ zoom = CLAMP (zoom, SP_DESKTOP_ZOOM_MIN, SP_DESKTOP_ZOOM_MAX);
+ Geom::Point w = d2w( c ); // Must be before zoom changed.
+ _current_affine.setScale( zoom );
+ set_display_area( c, w );
+}
+
+
+void
+SPDesktop::zoom_relative_keep_point (Geom::Point const &c, double zoom)
+{
+ double new_zoom = _current_affine.getZoom() * zoom;
+ zoom_absolute_keep_point( c, new_zoom );
+}
+
+
+/**
+ * Zoom aligning the point 'c' to the center of desktop window.
+ */
+void
+SPDesktop::zoom_absolute_center_point (Geom::Point const &c, double zoom)
+{
+ zoom = CLAMP (zoom, SP_DESKTOP_ZOOM_MIN, SP_DESKTOP_ZOOM_MAX);
+ _current_affine.setScale( zoom );
+ Geom::Rect viewbox = canvas->getViewbox();
+ set_display_area( c, viewbox.midpoint() );
+}
+
+
+void
+SPDesktop::zoom_relative_center_point (Geom::Point const &c, double zoom)
+{
+ double new_zoom = _current_affine.getZoom() * zoom;
+ zoom_absolute_center_point( c, new_zoom );
+}
+
+
/**
- * Revert back to previous zoom if possible.
+ * Set display area to origin and current document dimensions.
*/
void
-SPDesktop::prev_zoom()
+SPDesktop::zoom_page()
{
- if (zooms_past.empty()) {
- messageStack()->flash(Inkscape::WARNING_MESSAGE, _("No previous zoom."));
+ Geom::Rect d(Geom::Point(0, 0),
+ Geom::Point(doc()->getWidth().value("px"), doc()->getHeight().value("px")));
+
+ if (d.minExtent() < 1.0) {
return;
}
- // push current zoom into forward zooms list
- push_current_zoom (zooms_future);
+ set_display_area(d, 10);
+}
+
+/**
+ * Set display area to current document width.
+ */
+void
+SPDesktop::zoom_page_width()
+{
+ Geom::Rect const a = get_display_area();
- // restore previous zoom
- Geom::Rect past = zooms_past.front();
- set_display_area (past.left(), past.top(), past.right(), past.bottom(), 0, false);
+ if (doc()->getWidth().value("px") < 1.0) {
+ return;
+ }
- // remove the just-added zoom from the past zooms list
- zooms_past.pop_front();
+ Geom::Rect d(Geom::Point(0, a.midpoint()[Geom::Y]),
+ Geom::Point(doc()->getWidth().value("px"), a.midpoint()[Geom::Y]));
+
+ set_display_area(d, 10);
}
+
/**
- * Set zoom to next in list.
+ * Zoom to whole drawing.
*/
-void SPDesktop::next_zoom()
+void
+SPDesktop::zoom_drawing()
{
- if (zooms_future.empty()) {
- this->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("No next zoom."));
+ g_return_if_fail (doc() != NULL);
+ SPItem *docitem = doc()->getRoot();
+ g_return_if_fail (docitem != NULL);
+
+ docitem->bbox_valid = FALSE;
+ Geom::OptRect d = docitem->desktopVisualBounds();
+
+ /* Note that the second condition here indicates that
+ ** there are no items in the drawing.
+ */
+ if ( !d || d->minExtent() < 0.1 ) {
return;
}
- // push current zoom into past zooms list
- push_current_zoom (zooms_past);
+ set_display_area(*d, 10);
+}
+
+
+/**
+ * Zoom to selection.
+ */
+void
+SPDesktop::zoom_selection()
+{
+ Geom::OptRect const d = selection->visualBounds();
- // restore next zoom
- Geom::Rect future = zooms_future.front();
- set_display_area (future.left(), future.top(), future.right(), future.bottom(), 0, false);
+ if ( !d || d->minExtent() < 0.1 ) {
+ return;
+ }
- // remove the just-used zoom from the zooms_future list
- zooms_future.pop_front();
+ set_display_area(*d, 10);
}
+
/**
* Performs a quick zoom into what the user is working on.
*
@@ -914,8 +1039,8 @@ void SPDesktop::zoom_quick(bool enable)
return;
}
- if (enable == true) {
- _quick_zoom_stored_area = get_display_area();
+ if (enable) {
+ _quick_zoom_affine = _current_affine;
bool zoomed = false;
// TODO This needs to migrate into the node tool, but currently the design
@@ -927,7 +1052,7 @@ void SPDesktop::zoom_quick(bool enable)
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()) {
+ if (!Geom::are_near(area, 0)) {
set_display_area(nodes, true);
zoomed = true;
}
@@ -936,274 +1061,190 @@ void SPDesktop::zoom_quick(bool enable)
if (!zoomed) {
Geom::OptRect const d = selection->visualBounds();
- if (d && d->area() * 2.0 < _quick_zoom_stored_area.area()) {
+ if (d) {
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);
+ Geom::Rect const d_canvas = canvas->getViewbox(); // Not SVG 'viewBox'
+ Geom::Point midpoint = w2d(d_canvas.midpoint()); // Midpoint of drawing on canvas.
+ zoom_relative_center_point(midpoint, 2.0);
}
} else {
- set_display_area(_quick_zoom_stored_area, false);
+ _current_affine = _quick_zoom_affine;
+ set_display_area( false );
}
_quick_zoom_enabled = enable;
return;
}
+
/**
- * Zoom to point with absolute zoom factor.
+ * Tell widget to let zoom widget grab keyboard focus.
*/
void
-SPDesktop::zoom_absolute_keep_point (double cx, double cy, double px, double py, double zoom)
+SPDesktop::zoom_grab_focus()
{
- zoom = CLAMP (zoom, SP_DESKTOP_ZOOM_MIN, SP_DESKTOP_ZOOM_MAX);
-
- // 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(_d2w.descrim() - zoom) < 0.0001*zoom && (fabs(SP_DESKTOP_ZOOM_MAX - zoom) < 0.01 || fabs(SP_DESKTOP_ZOOM_MIN - zoom) < 0.000001))
- return;
-
- Geom::Rect const viewbox = canvas->getViewbox();
-
- 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,
- cx + (1 - px) * width2,
- cy + (1 - py) * height2,
- 0.0);
+ _widget->letZoomGrabFocus();
}
-/**
- * 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.
+ * Rotate keeping the point 'c' fixed in the desktop window.
*/
void
-SPDesktop::zoom_absolute (double cx, double cy, double zoom)
+SPDesktop::rotate_absolute_keep_point (Geom::Point const &c, double rotate)
+{
+ Geom::Point w = d2w( c ); // Must be before rotate changed.
+ _current_affine.setRotate( rotate );
+ set_display_area( c, w );
+}
+
+
+void
+SPDesktop::rotate_relative_keep_point (Geom::Point const &c, double rotate)
{
- zoom_absolute_keep_point (cx, cy, 0.5, 0.5, zoom);
+ Geom::Point w = d2w( c ); // Must be before rotate changed.
+ _current_affine.addRotate( rotate );
+ set_display_area( c, w );
}
+
/**
- * Zoom to point with relative zoom factor.
+ * Rotate aligning the point 'c' to the center of desktop window.
*/
-void
-SPDesktop::zoom_relative_keep_point (double cx, double cy, double zoom)
+void
+SPDesktop::rotate_absolute_center_point (Geom::Point const &c, double rotate)
{
- Geom::Rect const area = get_display_area();
-
- if (cx < area.min()[Geom::X]) {
- cx = area.min()[Geom::X];
- }
- if (cx > area.max()[Geom::X]) {
- cx = area.max()[Geom::X];
- }
- if (cy < area.min()[Geom::Y]) {
- cy = area.min()[Geom::Y];
- }
- if (cy > area.max()[Geom::Y]) {
- cy = area.max()[Geom::Y];
- }
+ _current_affine.setRotate( rotate );
+ Geom::Rect viewbox = canvas->getViewbox();
+ set_display_area( c, viewbox.midpoint() );
+}
- 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);
+void
+SPDesktop::rotate_relative_center_point (Geom::Point const &c, double rotate)
+{
+ _current_affine.addRotate( rotate );
+ Geom::Rect viewbox = canvas->getViewbox();
+ set_display_area( c, viewbox.midpoint() );
}
+
/**
- * Zoom to center with relative zoom factor.
+ * Flip keeping the point 'c' fixed in the desktop window.
*/
void
-SPDesktop::zoom_relative (double cx, double cy, double zoom)
+SPDesktop::flip_absolute_keep_point (Geom::Point const &c, CanvasFlip flip)
{
- gdouble scale = _d2w.descrim() * zoom;
- zoom_absolute (cx, cy, scale);
+ Geom::Point w = d2w( c ); // Must be before flip.
+ _current_affine.setFlip( flip );
+ set_display_area( c, w );
}
-/**
- * Set display area to origin and current document dimensions.
- */
+
void
-SPDesktop::zoom_page()
+SPDesktop::flip_relative_keep_point (Geom::Point const &c, CanvasFlip flip)
{
- Geom::Rect d(Geom::Point(0, 0),
- Geom::Point(doc()->getWidth().value("px"), doc()->getHeight().value("px")));
-
- if (d.minExtent() < 1.0) {
- return;
- }
-
- set_display_area(d, 10);
+ Geom::Point w = d2w( c ); // Must be before flip.
+ _current_affine.addFlip( flip );
+ set_display_area( c, w );
}
+
/**
- * Set display area to current document width.
+ * Flip aligning the point 'c' to the center of desktop window.
*/
-void
-SPDesktop::zoom_page_width()
+void
+SPDesktop::flip_absolute_center_point (Geom::Point const &c, CanvasFlip flip)
{
- Geom::Rect const a = get_display_area();
-
- if (doc()->getWidth().value("px") < 1.0) {
- return;
- }
+ _current_affine.setFlip( flip );
+ Geom::Rect viewbox = canvas->getViewbox();
+ set_display_area( c, viewbox.midpoint() );
+}
- Geom::Rect d(Geom::Point(0, a.midpoint()[Geom::Y]),
- Geom::Point(doc()->getWidth().value("px"), a.midpoint()[Geom::Y]));
- set_display_area(d, 10);
+void
+SPDesktop::flip_relative_center_point (Geom::Point const &c, CanvasFlip flip)
+{
+ _current_affine.addFlip( flip );
+ Geom::Rect viewbox = canvas->getViewbox();
+ set_display_area( c, viewbox.midpoint() );
}
+
/**
- * Zoom to selection.
+ * Scroll canvas by to a particular point (window coordinates).
*/
void
-SPDesktop::zoom_selection()
+SPDesktop::scroll_absolute (Geom::Point const &point, bool is_scrolling)
{
- Geom::OptRect const d = selection->visualBounds();
+ canvas->scrollTo(point, FALSE, is_scrolling);
+ _current_affine.setOffset( point );
- if ( !d || d->minExtent() < 0.1 ) {
- return;
- }
+ /* 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);
+ if (SP_IS_BOX3D_CONTEXT(event_context)) {
+ SP_BOX3D_CONTEXT(event_context)->_vpdrag->updateLines();
+ }
- set_display_area(*d, 10);
+ _widget->updateRulers();
+ _widget->updateScrollbars(_current_affine.getZoom());
}
-/**
- * Tell widget to let zoom widget grab keyboard focus.
- */
-void
-SPDesktop::zoom_grab_focus()
-{
- _widget->letZoomGrabFocus();
-}
/**
- * Zoom to whole drawing.
+ * Scroll canvas by specific coordinate amount (window coordinates).
*/
void
-SPDesktop::zoom_drawing()
+SPDesktop::scroll_relative (Geom::Point const &delta, bool is_scrolling)
{
- g_return_if_fail (doc() != NULL);
- SPItem *docitem = doc()->getRoot();
- g_return_if_fail (docitem != NULL);
-
- docitem->bbox_valid = FALSE;
- Geom::OptRect d = docitem->desktopVisualBounds();
-
- /* Note that the second condition here indicates that
- ** there are no items in the drawing.
- */
- if ( !d || d->minExtent() < 0.1 ) {
- return;
- }
-
- set_display_area(*d, 10);
+ Geom::Rect const viewbox = canvas->getViewbox();
+ scroll_absolute( viewbox.min() - delta, is_scrolling );
}
+
/**
* Scroll canvas by specific coordinate amount in svg coordinates.
*/
void
-SPDesktop::scroll_world_in_svg_coords (double dx, double dy, bool is_scrolling)
+SPDesktop::scroll_relative_in_svg_coords (double dx, double dy, bool is_scrolling)
{
- double scale = _d2w.descrim();
- scroll_world(dx*scale, dy*scale, is_scrolling);
+ double scale = _current_affine.getZoom();
+ scroll_relative(Geom::Point(dx*scale, dy*scale), is_scrolling);
}
+
/**
- * Scroll canvas by specific coordinate amount.
+ * Scroll screen so as to keep point 'p' visible in window.
+ * (Used, for example, when a node is being dragged.)
+ * 'p': The point in desktop coordinates.
+ * 'autoscrollspeed': The scroll speed (or zero to use preferences' value).
*/
-void
-SPDesktop::scroll_world (double dx, double dy, bool is_scrolling)
-{
- g_assert(_widget);
-
- Geom::Rect const viewbox = canvas->getViewbox();
-
- canvas->scrollTo(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);
- if (SP_IS_BOX3D_CONTEXT(event_context)) {
- SP_BOX3D_CONTEXT(event_context)->_vpdrag->updateLines();
- }
-
- _widget->updateRulers();
- _widget->updateScrollbars(_d2w.descrim());
-}
-
bool
SPDesktop::scroll_to_point (Geom::Point const &p, gdouble autoscrollspeed)
{
- using Geom::X;
- using Geom::Y;
-
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+ // autoscrolldistance is in screen pixels.
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 /= _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[X] > dbox.min()[X] && p[X] < dbox.max()[X]) ||
- !(p[Y] > dbox.min()[Y] && p[Y] < dbox.max()[Y]) ) {
-
- Geom::Point const s_w( p * (Geom::Affine)_d2w );
-
- gdouble x_to;
- 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[X];
-
- gdouble y_to;
- 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[Y];
-
- 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 );
+ Geom::Rect w = canvas->getViewbox(); // Window in screen coordinates.
+ w.expandBy(-autoscrolldistance); // Shrink window
+
+ Geom::Point c = d2w(p); // Point 'p' in screen coordinates.
+ if (!w.contains(c)) {
+
+ Geom::Point c2 = w.clamp(c); // Constrain c to window.
if (autoscrollspeed == 0)
autoscrollspeed = prefs->getDoubleLimited("/options/autoscrollspeed/value", 1, 0, 10);
if (autoscrollspeed != 0)
- scroll_world (autoscrollspeed * moved_w);
+ scroll_relative (autoscrollspeed * (c2 - c) );
return true;
}
@@ -1392,6 +1433,28 @@ SPDesktop::onWindowStateEvent (GdkEventWindowState* event)
return false;
}
+
+/**
+ * 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);
+ }
+}
+
+
void
SPDesktop::setToolboxFocusTo (gchar const *label)
{
@@ -1444,11 +1507,7 @@ void SPDesktop::setWaitingCursor()
GdkDisplay *display = gdk_display_get_default();
GdkCursor *waiting = gdk_cursor_new_for_display(display, GDK_WATCH);
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(getCanvas())), waiting);
-#if GTK_CHECK_VERSION(3,0,0)
g_object_unref(waiting);
-#else
- gdk_cursor_unref(waiting);
-#endif
// GDK needs the flush for the cursor change to take effect
gdk_flush();
waiting_cursor = true;
@@ -1545,13 +1604,18 @@ SPDesktop::setDocument (SPDocument *doc)
}
layers->setDocument(doc);
-
- // remove old EventLog if it exists (see also: bug #1071082)
- if (event_log) {
- doc->removeUndoObserver(*event_log);
- delete event_log;
- event_log = 0;
- }
+ selection->setDocument(doc);
+
+ if (event_log) {
+ // Remove it from the replaced document. This prevents Inkscape from
+ // crashing since we access it in the replaced document's destructor
+ // which results in an undefined behavior. (See also: bug #1670688)
+ if (this->doc()) {
+ this->doc()->removeUndoObserver(*event_log);
+ }
+ delete event_log;
+ event_log = 0;
+ }
/* setup EventLog */
event_log = new Inkscape::EventLog(doc);
@@ -1638,7 +1702,7 @@ SPDesktop::_onSelectionModified
(Inkscape::Selection */*selection*/, guint /*flags*/, SPDesktop *dt)
{
if (!dt->_widget) return;
- dt->_widget->updateScrollbars (dt->_d2w.descrim());
+ dt->_widget->updateScrollbars (dt->_current_affine.getZoom());
}
static void
@@ -1780,17 +1844,17 @@ static void _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop)
Geom::Affine SPDesktop::w2d() const
{
- return _w2d;
+ return _current_affine.w2d();
}
Geom::Point SPDesktop::w2d(Geom::Point const &p) const
{
- return p * _w2d;
+ return p * _current_affine.w2d();
}
Geom::Point SPDesktop::d2w(Geom::Point const &p) const
{
- return p * _d2w;
+ return p * _current_affine.d2w();
}
Geom::Affine SPDesktop::doc2dt() const