Code

Fix handle for LPERotateCopies
[inkscape.git] / src / desktop.cpp
index f58864955d01641cbc2c4bbf52c27592349caa09..932d79ff2e7dadfe24d1c6e3cee85e5db55c0d79 100644 (file)
@@ -12,7 +12,7 @@
  *   Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
  *
  * 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
 #include "display/gnome-canvas-acetate.h"
 #include "display/sodipodi-ctrlrect.h"
 #include "display/sp-canvas-util.h"
+#include "display/canvas-temporary-item-list.h"
+#include "display/snap-indicator.h"
 #include "libnr/nr-matrix-div.h"
 #include "libnr/nr-rect-ops.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 "display/sp-canvas.h"
 
@@ -114,6 +120,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,6 +129,7 @@ SPDesktop::SPDesktop() :
     drawing( 0 ),
     sketch( 0 ),
     controls( 0 ),
+    tempgroup ( 0 ),
     table( 0 ),
     page( 0 ),
     page_border( 0 ),
@@ -132,7 +141,6 @@ SPDesktop::SPDesktop() :
     window_state(0),
     interaction_disabled_counter( 0 ),
     waiting_cursor( false ),
-    perspectives (NULL),
     guides_active( false ),
     gr_item( 0 ),
     gr_point_type( 0 ),
@@ -140,6 +148,8 @@ SPDesktop::SPDesktop() :
     gr_fill_or_stroke( true ),
     _layer_hierarchy( 0 ),
     _reconstruction_old_layer_id( 0 ),
+    _display_mode(Inkscape::RENDERMODE_NORMAL),
+    _saved_display_mode(Inkscape::RENDERMODE_NORMAL),
     _widget( 0 ),
     _inkscape( 0 ),
     _guides_message_context( 0 ),
@@ -147,7 +157,7 @@ SPDesktop::SPDesktop() :
     _w2d(),
     _d2w(),
     _doc2dt( NR::Matrix(NR::scale(1, -1)) ),
-    grids_visible( true )
+    grids_visible( false )
 {
     _d2w.set_identity();
     _w2d.set_identity();
@@ -158,6 +168,9 @@ SPDesktop::SPDesktop() :
 void
 SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
 {
+    // Temporary workaround for link order issues:
+    Inkscape::DeviceManager::getManager().getDevices();
+
     _guides_message_context = new Inkscape::MessageContext(const_cast<Inkscape::MessageStack*>(messageStack()));
 
     current = sp_repr_css_attr_inherited (inkscape_get_repr (INKSCAPE, "desktop"), "style");
@@ -170,7 +183,7 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
     sp_document_ensure_up_to_date (document);
 
     /* Setup Dialog Manager */
-    _dlg_mgr = new Inkscape::UI::Dialog::DialogManager();
+    _dlg_mgr = &Inkscape::UI::Dialog::DialogManager::getInstance();
 
     dkey = sp_item_display_key_new (1);
 
@@ -217,6 +230,7 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
     guides = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
     sketch = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
     controls = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
+    tempgroup = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
 
     /* Push select tool to the bottom of stack */
     /** \todo
@@ -309,27 +323,26 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
     //   (Setting up after the connections are all in place, as it may use some of them)
     layer_manager = new Inkscape::LayerManager( this );
 
-    grids_visible = true;
+    showGrids(namedview->grids_visible, false);
 
-    /* Create initial perspective, append it to the list of existing perspectives
-       and make it the current perspective */
-    Box3D::Perspective3D *initial_persp = new Box3D::Perspective3D (
-                                          // VP in x-direction
-                                          Box3D::VanishingPoint( NR::Point(-50.0, 600.0),
-                                                                 NR::Point( -1.0,   0.0), Box3D::VP_FINITE),
-                                          // VP in y-direction
-                                          Box3D::VanishingPoint( NR::Point(500.0,1000.0),
-                                                                 NR::Point(  0.0,   1.0), Box3D::VP_INFINITE),
-                                          // VP in z-direction
-                                          Box3D::VanishingPoint( NR::Point(700.0, 600.0),
-                                                                 NR::Point(sqrt(3.0),1.0), Box3D::VP_FINITE));
-    this->add_perspective (initial_persp);
-    Box3D::Perspective3D::current_perspective = (Box3D::Perspective3D *) perspectives->data;
+    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;
+    }
+
+    namedview->hide(this);
+
     _activate_connection.disconnect();
     _deactivate_connection.disconnect();
     _sel_modified_connection.disconnect();
@@ -352,6 +365,12 @@ void SPDesktop::destroy()
 
     if (_layer_hierarchy) {
         delete _layer_hierarchy;
+//        _layer_hierarchy = NULL; //this should be here, but commented to find other bug somewhere else.
+    }
+
+    if (layer_manager) {
+        delete layer_manager;
+        layer_manager = NULL;
     }
 
     if (_inkscape) {
@@ -368,11 +387,6 @@ void SPDesktop::destroy()
 
     g_list_free (zooms_past);
     g_list_free (zooms_future);
-
-    for (GSList *p = this->perspectives; p != NULL; p = p->next) {
-        delete ((Box3D::Perspective3D *) p->data);
-    }
-    g_slist_free (perspectives);
 }
 
 SPDesktop::~SPDesktop() {}
@@ -380,30 +394,58 @@ 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;
+    // 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::_setDisplayMode(Inkscape::RenderMode mode) {
+    SP_CANVAS_ARENA (drawing)->arena->rendermode = mode;
+    canvas->rendermode = mode;
+    _display_mode = mode;
+    if (mode != Inkscape::RENDERMODE_OUTLINE) {
+        _saved_display_mode = _display_mode;
+    }
     sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw
     _widget->setTitle(SP_DOCUMENT_NAME(sp_desktop_document(this)));
 }
 
-void SPDesktop::displayModeToggle()
-{
-    if (displayMode == RENDERMODE_OUTLINE)
-        setDisplayModeNormal();
-    else 
-        setDisplayModeOutline();
+void SPDesktop::displayModeToggle() {
+    if (_display_mode == Inkscape::RENDERMODE_OUTLINE) {
+        _setDisplayMode(_saved_display_mode);
+    } else {
+        _setDisplayMode(Inkscape::RENDERMODE_OUTLINE);
+    }
 }
 
 /**
@@ -424,7 +466,7 @@ SPObject *SPDesktop::currentLayer() const
 
 /**
  * Sets the current layer of the desktop.
- * 
+ *
  * Make \a object the top layer.
  */
 void SPDesktop::setCurrentLayer(SPObject *object) {
@@ -434,6 +476,31 @@ void SPDesktop::setCurrentLayer(SPObject *object) {
     _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<SPObject*> 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<SPObject*>::iterator it = layers.begin(); it != layers.end(); ++it ) {
+        SP_ITEM(*it)->setHidden(othersShowing);
+    }
+}
+
 /**
  * Return layer that contains \a object.
  */
@@ -514,6 +581,15 @@ 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;
+    sp_desktop_widget_update_namedview(dtw);
+
     _namedview_modified (namedview, SP_OBJECT_MODIFIED_FLAG, this);
     _document_replaced_signal.emit (this, theDocument);
 }
@@ -658,7 +734,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)
@@ -686,7 +762,7 @@ SPDesktop::set_display_area (double x0, double y0, double x1, double y1, double
         newscale = viewbox.dimensions()[NR::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)) {
@@ -697,13 +773,16 @@ SPDesktop::set_display_area (double x0, double y0, double x1, double y1, double
         clear = TRUE;
     }
 
-    /* Calculate top left corner */
+    /* Calculate top left corner (in document pixels) */
     x0 = cx - 0.5 * viewbox.dimensions()[NR::X] / newscale;
     y1 = cy + 0.5 * viewbox.dimensions()[NR::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->updateZoom();
@@ -714,45 +793,6 @@ void SPDesktop::set_display_area(NR::Rect const &a, NR::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);
 }
 
-/**
- * Add a perspective to the desktop if it doesn't exist yet
- */
-void
-SPDesktop::add_perspective (Box3D::Perspective3D * const persp)
-{
-    // check that the perspective is not yet linked to another desktop
-    if (persp->desktop != NULL) {
-        g_assert (persp->desktop == this);
-    }
-
-    // FIXME: Should we handle the case that the perspectives have equal VPs but are not identical?
-    //        If so, we need to take care of relinking the boxes, etc.
-    if (persp == NULL || g_slist_find (this->perspectives, persp)) return;
-    this->perspectives = g_slist_prepend (this->perspectives, persp);
-    persp->desktop = this;
-}
-
-void SPDesktop::remove_perspective (Box3D::Perspective3D * const persp)
-{
-    if (persp == NULL) return;
-    if (!g_slist_find (this->perspectives, persp)) {
-        g_warning ("Could not find perspective in current desktop. Not removed.\n");
-        return;
-    }
-    this->perspectives = g_slist_remove (this->perspectives, persp);
-}
-
-// find an existing perspective whose VPs are equal to those of persp
-Box3D::Perspective3D * SPDesktop::find_perspective (Box3D::Perspective3D * const persp)
-{
-    for (GSList *p = this->perspectives; p != NULL; p = p->next) {
-        if (*((Box3D::Perspective3D *) p->data) == *persp) {
-            return ((Box3D::Perspective3D *) p->data);
-        }
-    }
-    return NULL; // perspective was not found
-}
-
 /**
  * Return viewbox dimensions.
  */
@@ -969,6 +1009,16 @@ SPDesktop::zoom_drawing()
     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 = expansion(_d2w);
+    scroll_world(dx*scale, dy*scale, is_scrolling);
+}
+
 /**
  * Scroll canvas by specific coordinate amount.
  */
@@ -981,6 +1031,9 @@ SPDesktop::scroll_world (double dx, double dy, bool is_scrolling)
 
     sp_canvas_scroll_to(canvas, viewbox.min()[NR::X] - dx, viewbox.min()[NR::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));
 }
@@ -1140,9 +1193,11 @@ SPDesktop::shutdown()
 
 bool SPDesktop::onDeleteUI (GdkEventAny*)
 {
-       if(shutdown()) return true;
-       destroyWidget();
-       return false;
+    if(shutdown()) 
+        return true;
+
+    destroyWidget();
+    return false;
 }
 
 /**
@@ -1163,7 +1218,7 @@ SPDesktop::onWindowStateEvent (GdkEventWindowState* event)
     if (changed & (GDK_WINDOW_STATE_FULLSCREEN|GDK_WINDOW_STATE_MAXIMIZED)) {
         layoutWidget();
     }
-       
+
        return false;
 }
 
@@ -1179,6 +1234,12 @@ SPDesktop::setToolboxAdjustmentValue (gchar const* id, double val)
     _widget->setToolboxAdjustmentValue (id, val);
 }
 
+void
+SPDesktop::setToolboxSelectOneValue (gchar const* id, gint val)
+{
+    _widget->setToolboxSelectOneValue (id, val);
+}
+
 bool
 SPDesktop::isToolboxButtonActive (gchar const *id)
 {
@@ -1230,26 +1291,42 @@ void SPDesktop::clearWaitingCursor()
       sp_event_context_update_cursor(sp_desktop_event_context(this));
 }
 
-void SPDesktop::toggleGrid()
+void SPDesktop::toggleColorProfAdjust()
+{
+    _widget->toggleColorProfAdjust();
+}
+
+void SPDesktop::toggleGrids()
 {
     if (namedview->grids) {
         if(gridgroup) {
-            grids_visible = !grids_visible;
-            if (grids_visible) {
-                sp_canvas_item_show(SP_CANVAS_ITEM(gridgroup));
-            } else {
-                sp_canvas_item_hide(SP_CANVAS_ITEM(gridgroup));
-            }
+            showGrids(!grids_visible);
         }
     } 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);
-        grids_visible = true;
+        showGrids(true);
+    }
+}
+
+void SPDesktop::showGrids(bool show, bool dirty_document)
+{
+    grids_visible = show;
+    sp_namedview_show_grids(namedview, grids_visible, dirty_document);
+    if (show) {
         sp_canvas_item_show(SP_CANVAS_ITEM(gridgroup));
+    } else {
+        sp_canvas_item_hide(SP_CANVAS_ITEM(gridgroup));
     }
 }
 
+void SPDesktop::toggleSnapping()
+{
+    bool v = namedview->snap_manager.getSnapEnabledGlobally();
+    Inkscape::XML::Node *repr = SP_OBJECT_REPR(namedview);
+    sp_repr_set_boolean(repr, "inkscape:snap-global", !v);
+}
 
 //----------------------------------------------------------------------
 // Callback implementations. The virtual ones are connected by the view.
@@ -1261,7 +1338,7 @@ SPDesktop::onPositionSet (double x, double y)
 }
 
 void
-SPDesktop::onResized (double x, double y)
+SPDesktop::onResized (double /*x*/, double /*y*/)
 {
    // Nothing called here
 }
@@ -1387,7 +1464,7 @@ SPDesktop::_onDeactivate (SPDesktop* dt)
 
 void
 SPDesktop::_onSelectionModified
-(Inkscape::Selection *selection, guint flags, SPDesktop *dt)
+(Inkscape::Selection */*selection*/, guint /*flags*/, SPDesktop *dt)
 {
     if (!dt->_widget) return;
     dt->_widget->updateScrollbars (expansion(dt->_d2w));
@@ -1417,7 +1494,7 @@ _onSelectionChanged
  * \todo fixme
  */
 static gint
-_arena_handler (SPCanvasArena *arena, NRArenaItem *ai, GdkEvent *event, SPDesktop *desktop)
+_arena_handler (SPCanvasArena */*arena*/, NRArenaItem *ai, GdkEvent *event, SPDesktop *desktop)
 {
     if (ai) {
         SPItem *spi = (SPItem*)NR_ARENA_ITEM_GET_DATA (ai);
@@ -1442,7 +1519,7 @@ _layer_deactivated(SPObject *layer, SPDesktop *desktop) {
 
 /// Callback
 static void
-_layer_hierarchy_changed(SPObject *top, SPObject *bottom,
+_layer_hierarchy_changed(SPObject */*top*/, SPObject *bottom,
                                          SPDesktop *desktop)
 {
     desktop->_layer_changed_signal.emit (bottom);
@@ -1534,7 +1611,7 @@ _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop)
                     ((CtrlRect *) desktop->page)->setShadow(0, 0x00000000);
                 }
         }
-       
+
         /* Show/hide page shadow */
         if (nv->showpageshadow && nv->pageshadow) {
             ((CtrlRect *) desktop->page_border)->setShadow(nv->pageshadow, nv->bordercolor);
@@ -1567,15 +1644,15 @@ _update_snap_distances (SPDesktop *desktop)
     //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,
+        grid->snapper->setSnapperTolerance(sp_convert_distance_full(nv.gridtolerance,
                                                                       *nv.gridtoleranceunit,
                                                                       px));
     }
-    
-    nv.snap_manager.guide.setDistance(sp_convert_distance_full(nv.guidetolerance,
+
+    nv.snap_manager.guide.setSnapperTolerance(sp_convert_distance_full(nv.guidetolerance,
                                                                        *nv.guidetoleranceunit,
                                                                        px));
-    nv.snap_manager.object.setDistance(sp_convert_distance_full(nv.objecttolerance,
+    nv.snap_manager.object.setSnapperTolerance(sp_convert_distance_full(nv.objecttolerance,
                                                                         *nv.objecttoleranceunit,
                                                                         px));
 }