Code

Monster commit. New grid infrastructure. The old gridmanagement code is still there...
authorjohanengelen <johanengelen@users.sourceforge.net>
Tue, 20 Mar 2007 19:58:07 +0000 (19:58 +0000)
committerjohanengelen <johanengelen@users.sourceforge.net>
Tue, 20 Mar 2007 19:58:07 +0000 (19:58 +0000)
src/desktop.cpp
src/display/canvas-grid.cpp
src/display/canvas-grid.h
src/snap.cpp
src/sp-namedview.cpp
src/sp-namedview.h
src/ui/dialog/document-properties.cpp
src/ui/dialog/document-properties.h
src/ui/widget/registered-widget.cpp
src/ui/widget/registered-widget.h

index ea002b872810d105bfa4e8137ba7d88f6a5e17c0..4727f3e511e564de3194df3cf7fc9a2e78eea74d 100644 (file)
@@ -83,6 +83,7 @@
 #include "message-context.h"
 #include "layer-manager.h"
 #include "event-log.h"
+#include "display/canvas-grid.h"
 
 namespace Inkscape { namespace XML { class Node; }}
 
@@ -1407,12 +1408,22 @@ _update_snap_distances (SPDesktop *desktop)
 
     SPNamedView &nv = *desktop->namedview;
 
+    
+    // FIXME GRID: make one gridsnapper object that snaps to all enabled grids by calling their snappers.
     nv.snap_manager.grid.setDistance(sp_convert_distance_full(nv.gridtolerance,
                                                                       *nv.gridtoleranceunit,
                                                                       px));
     nv.snap_manager.axonomgrid.setDistance(sp_convert_distance_full(nv.gridtolerance,
                                                                       *nv.gridtoleranceunit,
                                                                       px));
+    //new 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));
index 17f5e7e8cf654f145376382c9a56c481b873ce84..853fc011e522371b0c6907c248b0a870ca312c3b 100644 (file)
@@ -1,9 +1,8 @@
 #define INKSCAPE_CANVAS_GRID_C
 
 /*
- * CXYGrid
  *
- * Copyright (C) Johan Engelen 2006 <johan@shouraizou.nl>
+ * Copyright (C) Johan Engelen 2006-2007 <johan@shouraizou.nl>
  * Copyright (C) Lauris Kaplinski 2000
  *
  */
 #include "canvas-grid.h"
 #include "display-forward.h"
 #include <libnr/nr-pixops.h>
+#include "desktop-handles.h"
+#include "helper/units.h"
+#include "svg/svg-color.h"
+#include "xml/node-event-vector.h"
+#include "sp-object.h"
+
+#include "sp-namedview.h"
+#include "inkscape.h"
+#include "desktop.h"
+#include "display/canvas-grid.h"
+#include "display/canvas-axonomgrid.h"
+#include "../document.h"
+
+
 
 namespace Inkscape {
+
+static void grid_canvasitem_class_init (GridCanvasItemClass *klass);
+static void grid_canvasitem_init (GridCanvasItem *grid);
+static void grid_canvasitem_destroy (GtkObject *object);
+
+static void grid_canvasitem_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags);
+static void grid_canvasitem_render (SPCanvasItem *item, SPCanvasBuf *buf);
+
+static SPCanvasItemClass * parent_class;
+
+GtkType
+grid_canvasitem_get_type (void)
+{
+    static GtkType grid_canvasitem_type = 0;
+
+    if (!grid_canvasitem_type) {
+        GtkTypeInfo grid_canvasitem_info = {
+            "GridCanvasItem",
+            sizeof (GridCanvasItem),
+            sizeof (GridCanvasItemClass),
+            (GtkClassInitFunc) grid_canvasitem_class_init,
+            (GtkObjectInitFunc) grid_canvasitem_init,
+            NULL, NULL,
+            (GtkClassInitFunc) NULL
+        };
+        grid_canvasitem_type = gtk_type_unique (sp_canvas_item_get_type (), &grid_canvasitem_info);
+    }
+    return grid_canvasitem_type;
+}
+
+static void
+grid_canvasitem_class_init (GridCanvasItemClass *klass)
+{
+    GtkObjectClass *object_class;
+    SPCanvasItemClass *item_class;
+
+    object_class = (GtkObjectClass *) klass;
+    item_class = (SPCanvasItemClass *) klass;
+
+    parent_class = (SPCanvasItemClass*)gtk_type_class (sp_canvas_item_get_type ());
+
+    object_class->destroy = grid_canvasitem_destroy;
+
+    item_class->update = grid_canvasitem_update;
+    item_class->render = grid_canvasitem_render;
+}
+
+static void
+grid_canvasitem_init (GridCanvasItem *griditem)
+{
+    griditem->grid = NULL;
+}
+
+static void
+grid_canvasitem_destroy (GtkObject *object)
+{
+    g_return_if_fail (object != NULL);
+    g_return_if_fail (INKSCAPE_IS_GRID_CANVASITEM (object));
+
+    if (GTK_OBJECT_CLASS (parent_class)->destroy)
+        (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+/**
+*/
+static void
+grid_canvasitem_render (SPCanvasItem * item, SPCanvasBuf * buf)
+{
+    GridCanvasItem *gridcanvasitem = INKSCAPE_GRID_CANVASITEM (item);
+
+    sp_canvas_prepare_buffer (buf);
+
+    if (gridcanvasitem->grid) gridcanvasitem->grid->Render(buf);
+}
+
+static void
+grid_canvasitem_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags)
+{
+    GridCanvasItem *gridcanvasitem = INKSCAPE_GRID_CANVASITEM (item);
+
+    if (parent_class->update)
+        (* parent_class->update) (item, affine, flags);
+
+    if (gridcanvasitem->grid) {
+        gridcanvasitem->grid->Update(affine, flags);
+
+        sp_canvas_request_redraw (item->canvas,
+                         -1000000, -1000000,
+                         1000000, 1000000);
+
+        item->x1 = item->y1 = -1000000;
+        item->x2 = item->y2 = 1000000;
+    }
+}
+
+
+
+// ##########################################################
+//   CanvasGrid
+
+    static Inkscape::XML::NodeEventVector const _repr_events = {
+        NULL, /* child_added */
+        NULL, /* child_removed */
+        CanvasGrid::on_repr_attr_changed,
+        NULL, /* content_changed */
+        NULL  /* order_changed */
+    };
+
+CanvasGrid::CanvasGrid(SPDesktop *desktop, Inkscape::XML::Node * in_repr)
+{
+    //create canvasitem
+    // FIXME: probably this creation has to be done on demand. I think for multiple desktops it is best if each has their own canvasitem, but share the same CanvasGrid object.
+    canvasitem = INKSCAPE_GRID_CANVASITEM( sp_canvas_item_new(sp_desktop_grid(desktop), INKSCAPE_TYPE_GRID_CANVASITEM, NULL) );
+    gtk_object_ref(GTK_OBJECT(canvasitem));    // since we're keeping a copy, we need to bump up the ref count
+    canvasitem->grid = this;
+
+    enabled = false;
+    visible = false;
+
+//    sp_canvas_item_hide(canvasitem);
+
+    repr = in_repr;
+    if (repr) {
+        repr->addListener (&_repr_events, this);
+    }
+    
+    namedview = sp_desktop_namedview(desktop);
+}
+
+CanvasGrid::~CanvasGrid()
+{
+    if (repr) {
+        repr->removeListenerByData (this);
+    }
+
+    sp_canvas_item_hide(canvasitem);
+   // deref canvasitem
+   gtk_object_unref(GTK_OBJECT(canvasitem));
+   g_free(canvasitem);
+   g_message("~CanvasGrid");
+}
+
+/*
+*  writes an <inkscape:grid> child to repr. 
+*/
+void 
+CanvasGrid::writeNewGridToRepr(Inkscape::XML::Node * repr, const char * gridtype)
+{
+    if (!repr) return;
+    if (!gridtype) return;
+    
+    // first create the child xml node, then hook it to repr. This order is important, to not set off listeners to repr before the new node is complete.
+    
+    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(sp_desktop_document(SP_ACTIVE_DESKTOP));
+    Inkscape::XML::Node *newnode;
+    newnode = xml_doc->createElement("inkscape:grid");
+    if (!strcmp(gridtype,"xygrid")) {
+        newnode->setAttribute("type","xygrid");
+    }
+    
+    repr->appendChild(newnode);
+
+    // FIXME: add this to history?
+//    sp_document_done(current_document, SP_VERB_DIALOG_XML_EDITOR,
+//                     _("Create new element node"));
+}
+
+/*
+* Creates a new CanvasGrid object of type gridtype 
+*/
+CanvasGrid* 
+CanvasGrid::NewGrid(SPDesktop *desktop, Inkscape::XML::Node * in_repr, const char * gridtype)
+{
+    if (!desktop) return NULL;
+    if (!in_repr) return NULL;
+    if (!gridtype) return NULL;
+    
+    if (!strcmp(gridtype,"xygrid")) {
+        return (CanvasGrid*) new CanvasXYGrid(desktop, in_repr);
+    }
+    
+    return NULL;
+}
+
+
+void
+CanvasGrid::hide()
+{
+    sp_canvas_item_hide(canvasitem);
+    visible = false;
+}
+
+void
+CanvasGrid::show()
+{
+    sp_canvas_item_show(canvasitem);
+    visible = true;
+}
+
+void
+CanvasGrid::on_repr_attr_changed (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive, void * data)
+{
+    if (!data)
+        return;
+
+    ((CanvasGrid*) data)->onReprAttrChanged(repr, key, oldval, newval, is_interactive);
+}
+
+
+
+// ##########################################################
+//   CanvasXYGrid
+
+static void grid_hline (SPCanvasBuf *buf, gint y, gint xs, gint xe, guint32 rgba);
+static void grid_vline (SPCanvasBuf *buf, gint x, gint ys, gint ye, guint32 rgba);
+
+
+/**
+* A DIRECT COPY-PASTE FROM DOCUMENT-PROPERTIES.CPP  TO QUICKLY GET RESULTS
+*
+ * Helper function that attachs widgets in a 3xn table. The widgets come in an
+ * array that has two entries per table row. The two entries code for four
+ * possible cases: (0,0) means insert space in first column; (0, non-0) means
+ * widget in columns 2-3; (non-0, 0) means label in columns 1-3; and
+ * (non-0, non-0) means two widgets in columns 2 and 3.
+**/
+#define SPACE_SIZE_X 15
+#define SPACE_SIZE_Y 10
+static inline void
+attach_all (Gtk::Table &table, const Gtk::Widget *arr[], unsigned size, int start = 0)
+{
+    for (unsigned i=0, r=start; i<size/sizeof(Gtk::Widget*); i+=2)
+    {
+        if (arr[i] && arr[i+1])
+        {
+            table.attach (const_cast<Gtk::Widget&>(*arr[i]),   1, 2, r, r+1,
+                      Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
+            table.attach (const_cast<Gtk::Widget&>(*arr[i+1]), 2, 3, r, r+1,
+                      Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
+        }
+        else
+        {
+            if (arr[i+1])
+                table.attach (const_cast<Gtk::Widget&>(*arr[i+1]), 1, 3, r, r+1,
+                      Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
+            else if (arr[i])
+            {
+                Gtk::Label& label = reinterpret_cast<Gtk::Label&> (const_cast<Gtk::Widget&>(*arr[i]));
+                label.set_alignment (0.0);
+                table.attach (label, 0, 3, r, r+1,
+                      Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
+            }
+            else
+            {
+                Gtk::HBox *space = manage (new Gtk::HBox);
+                space->set_size_request (SPACE_SIZE_X, SPACE_SIZE_Y);
+                table.attach (*space, 0, 1, r, r+1,
+                      (Gtk::AttachOptions)0, (Gtk::AttachOptions)0,0,0);
+            }
+        }
+        ++r;
+    }
+}
+
+CanvasXYGrid::CanvasXYGrid (SPDesktop *desktop, Inkscape::XML::Node * in_repr)
+    : CanvasGrid(desktop, in_repr), table(1, 1)
+{
+    origin[NR::X] = origin[NR::Y] = 0.0;
+//            nv->gridcolor = (nv->gridcolor & 0xff) | (DEFAULTGRIDCOLOR & 0xffffff00);
+//     case SP_ATTR_GRIDOPACITY:
+//            nv->gridcolor = (nv->gridcolor & 0xffffff00) | (DEFAULTGRIDCOLOR & 0xff);
+    color = 0xff3f3f20;
+    empcolor = 0xFF3F3F40;
+    empspacing = 5;
+    spacing[NR::X] = spacing[NR::Y] = 8.0;
+    gridunit = &sp_unit_get_by_id(SP_UNIT_PX);
+    
+    snapper = new CanvasXYGridSnapper(this, namedview, 0);
+    
+    // initialize widgets:
+    vbox.set_border_width(2);
+    table.set_spacings(2);
+    vbox.pack_start(table, false, false, 0);
+
+    _rumg.init (_("Grid _units:"), "units", _wr, repr);
+    _rsu_ox.init (_("_Origin X:"), _("X coordinate of grid origin"),
+                  "originx", _rumg, _wr, repr);
+    _rsu_oy.init (_("O_rigin Y:"), _("Y coordinate of grid origin"),
+                  "originy", _rumg, _wr, repr);
+    _rsu_sx.init (_("Spacing _X:"), _("Distance between vertical grid lines"),
+                  "spacingx", _rumg, _wr, repr);
+    _rsu_sy.init (_("Spacing _Y:"), _("Distance between horizontal grid lines"),
+                  "spacingy", _rumg, _wr, repr);
+    _rcp_gcol.init (_("Grid line _color:"), _("Grid line color"),
+                    _("Color of grid lines"), "color", "opacity", _wr, repr);
+    _rcp_gmcol.init (_("Ma_jor grid line color:"), _("Major grid line color"),
+                     _("Color of the major (highlighted) grid lines"),
+                     "empcolor", "empopacity", _wr, repr);
+    _rsi.init (_("_Major grid line every:"), _("lines"), "empspacing", _wr, repr);
+
+    const Gtk::Widget* widget_array[] =
+    {
+        0,                  _rcbgrid._button,
+        0,                  _rrb_gridtype._hbox,
+        _rumg._label,       _rumg._sel,
+        0,                  _rsu_ox.getSU(),
+        0,                  _rsu_oy.getSU(),
+        0,                  _rsu_sx.getSU(),
+        0,                  _rsu_sy.getSU(),
+        _rcp_gcol._label,   _rcp_gcol._cp,
+        0,                  0,
+        _rcp_gmcol._label,  _rcp_gmcol._cp,
+        _rsi._label,        &_rsi._hbox,
+    };
+
+    attach_all (table, widget_array, sizeof(widget_array));
+
+    vbox.show();
+
+    if (repr) readRepr();
+    updateWidgets();
+}
+
+CanvasXYGrid::~CanvasXYGrid ()
+{
+   if (snapper) delete snapper;
+}
+
+
+/* fixme: Collect all these length parsing methods and think common sane API */
+
+static gboolean sp_nv_read_length(const gchar *str, guint base, gdouble *val, const SPUnit **unit)
+{
+    if (!str) {
+        return FALSE;
+    }
+
+    gchar *u;
+    gdouble v = g_ascii_strtod(str, &u);
+    if (!u) {
+        return FALSE;
+    }
+    while (isspace(*u)) {
+        u += 1;
+    }
+
+    if (!*u) {
+        /* No unit specified - keep default */
+        *val = v;
+        return TRUE;
+    }
+
+    if (base & SP_UNIT_DEVICE) {
+        if (u[0] && u[1] && !isalnum(u[2]) && !strncmp(u, "px", 2)) {
+            *unit = &sp_unit_get_by_id(SP_UNIT_PX);
+            *val = v;
+            return TRUE;
+        }
+    }
+
+    if (base & SP_UNIT_ABSOLUTE) {
+        if (!strncmp(u, "pt", 2)) {
+            *unit = &sp_unit_get_by_id(SP_UNIT_PT);
+        } else if (!strncmp(u, "mm", 2)) {
+            *unit = &sp_unit_get_by_id(SP_UNIT_MM);
+        } else if (!strncmp(u, "cm", 2)) {
+            *unit = &sp_unit_get_by_id(SP_UNIT_CM);
+        } else if (!strncmp(u, "m", 1)) {
+            *unit = &sp_unit_get_by_id(SP_UNIT_M);
+        } else if (!strncmp(u, "in", 2)) {
+            *unit = &sp_unit_get_by_id(SP_UNIT_IN);
+        } else {
+            return FALSE;
+        }
+        *val = v;
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+static gboolean sp_nv_read_opacity(const gchar *str, guint32 *color)
+{
+    if (!str) {
+        return FALSE;
+    }
+
+    gchar *u;
+    gdouble v = g_ascii_strtod(str, &u);
+    if (!u) {
+        return FALSE;
+    }
+    v = CLAMP(v, 0.0, 1.0);
+
+    *color = (*color & 0xffffff00) | (guint32) floor(v * 255.9999);
+
+    return TRUE;
+}
+
+
+
+void
+CanvasXYGrid::readRepr()
+{
+    gchar const* value;
+    if ( (value = repr->attribute("originx")) ) {
+        sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &origin[NR::X], &gridunit);
+        origin[NR::X] = sp_units_get_pixels(origin[NR::X], *(gridunit));
+    }
+    if ( (value = repr->attribute("originy")) ) {
+        sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &origin[NR::Y], &gridunit);
+        origin[NR::Y] = sp_units_get_pixels(origin[NR::Y], *(gridunit));
+    }
+
+    if ( (value = repr->attribute("spacingx")) ) {
+        sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &spacing[NR::X], &gridunit);
+        spacing[NR::X] = sp_units_get_pixels(spacing[NR::X], *(gridunit));
+    }
+    if ( (value = repr->attribute("spacingy")) ) {
+        sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &spacing[NR::Y], &gridunit);
+        spacing[NR::Y] = sp_units_get_pixels(spacing[NR::Y], *(gridunit));
+    }
+
+    if ( (value = repr->attribute("color")) ) {
+        color = (color & 0xff) | sp_svg_read_color(value, color);
+    }
+
+    if ( (value = repr->attribute("empcolor")) ) {
+        empcolor = (empcolor & 0xff) | sp_svg_read_color(value, empcolor);
+    }
+
+    if ( (value = repr->attribute("opacity")) ) {
+        sp_nv_read_opacity(value, &color);
+    }
+    if ( (value = repr->attribute("empopacity")) ) {
+        sp_nv_read_opacity(value, &empcolor);
+    }
+
+    if ( (value = repr->attribute("empspacing")) ) {
+        empspacing = atoi(value);
+    }
+
+    sp_canvas_item_request_update (canvasitem);
+
+    return;
+}
+
+/**
+ * Called when XML node attribute changed; updates dialog widgets if change was not done by widgets themselves.
+ */
+void
+CanvasXYGrid::onReprAttrChanged (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive)
+{
+    readRepr();
+
+    if ( ! (_wr.isUpdating()) )
+        updateWidgets();
+}
+
+
+
+
+Gtk::Widget &
+CanvasXYGrid::getWidget()
+{
+    return vbox;
+}
+
+
+/**
+ * Update dialog widgets from object's values.
+ */
+void
+CanvasXYGrid::updateWidgets()
+{
+    if (_wr.isUpdating()) return;
+
+    _wr.setUpdating (true);
+
+//    _rrb_gridtype.setValue (nv->gridtype);
+    _rumg.setUnit (gridunit);
+
+    gdouble val;
+    val = origin[NR::X];
+    val = sp_pixels_get_units (val, *(gridunit));
+    _rsu_ox.setValue (val);
+    val = origin[NR::Y];
+    val = sp_pixels_get_units (val, *(gridunit));
+    _rsu_oy.setValue (val);
+    val = spacing[NR::X];
+    double gridx = sp_pixels_get_units (val, *(gridunit));
+    _rsu_sx.setValue (gridx);
+    val = spacing[NR::Y];
+    double gridy = sp_pixels_get_units (val, *(gridunit));
+    _rsu_sy.setValue (gridy);
+
+    _rcp_gcol.setRgba32 (color);
+    _rcp_gmcol.setRgba32 (empcolor);
+    _rsi.setValue (empspacing);
+
+    _wr.setUpdating (false);
+    
+    return;
+}
+
+
+
+void
+CanvasXYGrid::Update (NR::Matrix const &affine, unsigned int flags)
+{
+    ow = origin * affine;
+    sw = spacing * affine;
+    sw -= NR::Point(affine[4], affine[5]);
+
+    for(int dim = 0; dim < 2; dim++) {
+        gint scaling_factor = 5; //empspacing;
+
+        if (scaling_factor <= 1)
+            scaling_factor = 5;
+
+        scaled[dim] = FALSE;
+        sw[dim] = fabs (sw[dim]);
+        while (sw[dim] < 8.0) {
+            scaled[dim] = TRUE;
+            sw[dim] *= scaling_factor;
+            /* First pass, go up to the major line spacing, then
+               keep increasing by two. */
+            scaling_factor = 2;
+        }
+    }
+}
+
+void
+CanvasXYGrid::Render (SPCanvasBuf *buf)
+{
+    const gdouble sxg = floor ((buf->rect.x0 - ow[NR::X]) / sw[NR::X]) * sw[NR::X] + ow[NR::X];
+    const gint  xlinestart = (gint) Inkscape::round((sxg - ow[NR::X]) / sw[NR::X]);
+    const gdouble syg = floor ((buf->rect.y0 - ow[NR::Y]) / sw[NR::Y]) * sw[NR::Y] + ow[NR::Y];
+    const gint  ylinestart = (gint) Inkscape::round((syg - ow[NR::Y]) / sw[NR::Y]);
+
+    gint ylinenum;
+    gdouble y;
+    for (y = syg, ylinenum = ylinestart; y < buf->rect.y1; y += sw[NR::Y], ylinenum++) {
+        const gint y0 = (gint) Inkscape::round(y);
+
+        if (!scaled[NR::Y] && (ylinenum % 5 /*empspacing*/) == 0) {
+            grid_hline (buf, y0, buf->rect.x0, buf->rect.x1 - 1, empcolor);
+        } else {
+            grid_hline (buf, y0, buf->rect.x0, buf->rect.x1 - 1, color);
+        }
+    }
+
+    gint xlinenum;
+    gdouble x;
+    for (x = sxg, xlinenum = xlinestart; x < buf->rect.x1; x += sw[NR::X], xlinenum++) {
+        const gint ix = (gint) Inkscape::round(x);
+        if (!scaled[NR::X] && (xlinenum % 5 /*empspacing*/) == 0) {
+            grid_vline (buf, ix, buf->rect.y0, buf->rect.y1, empcolor);
+        } else {
+            grid_vline (buf, ix, buf->rect.y0, buf->rect.y1, color);
+        }
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/**
+ * \return x rounded to the nearest multiple of c1 plus c0.
+ *
+ * \note
+ * If c1==0 (and c0 is finite), then returns +/-inf.  This makes grid spacing of zero
+ * mean "ignore the grid in this dimention".  We're currently discussing "good" semantics
+ * for guide/grid snapping.
+ */
+
+/* FIXME: move this somewhere else, perhaps */
+static double round_to_nearest_multiple_plus(double x, double const c1, double const c0)
+{
+    return floor((x - c0) / c1 + .5) * c1 + c0;
+}
+
+CanvasXYGridSnapper::CanvasXYGridSnapper(CanvasXYGrid *grid, SPNamedView const *nv, NR::Coord const d) : LineSnapper(nv, d)
+{
+    this->grid = grid;
+}
+
+LineSnapper::LineList 
+CanvasXYGridSnapper::_getSnapLines(NR::Point const &p) const
+{
+    LineList s;
+
+    if ( grid == NULL ) {
+        return s;
+    }
+
+    for (unsigned int i = 0; i < 2; ++i) {
+
+        /* This is to make sure we snap to only visible grid lines */
+        double scaled_spacing = grid->sw[i]; // this is spacing of visible lines if screen pixels
+
+        // convert screen pixels to px
+        // FIXME: after we switch to snapping dist in screen pixels, this will be unnecessary
+        if (SP_ACTIVE_DESKTOP) {
+            scaled_spacing /= SP_ACTIVE_DESKTOP->current_zoom();
+        }
+
+        NR::Coord const rounded = round_to_nearest_multiple_plus(p[i],
+                                                                 scaled_spacing,
+                                                                 grid->origin[i]);
+
+        s.push_back(std::make_pair(NR::Dim2(i), rounded));
+    }
+
+    return s;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 
 enum {
     ARG_0,
@@ -36,7 +703,7 @@ static void cxygrid_set_arg (GtkObject *object, GtkArg *arg, guint arg_id);
 static void cxygrid_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags);
 static void cxygrid_render (SPCanvasItem *item, SPCanvasBuf *buf);
 
-static SPCanvasItemClass * parent_class;
+//static SPCanvasItemClass * parent_class;
 
 GtkType
 cxygrid_get_type (void)
@@ -197,7 +864,7 @@ grid_vline (SPCanvasBuf *buf, gint x, gint ys, gint ye, guint32 rgba)
     \brief  This function renders the grid on a particular canvas buffer
     \param  item  The grid to render on the buffer
     \param  buf   The buffer to render the grid on
-    
+
     This function gets called a touch more than you might believe,
     about once per tile.  This means that it could probably be optimized
     and help things out.
@@ -240,7 +907,7 @@ cxygrid_render (SPCanvasItem * item, SPCanvasBuf * buf)
         } else {
             grid_hline (buf, y0, buf->rect.x0, buf->rect.x1 - 1, grid->color);
         }
-    }     
+    }
 
     gint xlinenum;
     gdouble x;
@@ -291,10 +958,10 @@ cxygrid_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags
     sp_canvas_request_redraw (item->canvas,
                      -1000000, -1000000,
                      1000000, 1000000);
-                     
+
     item->x1 = item->y1 = -1000000;
     item->x2 = item->y2 = 1000000;
-}        
+}
 
 
 }; /* namespace Inkscape */
index 7645d30f643a5b88b61dda84bbd7a3869423b653..f92c731cdfb761518e844b0ce4245d7639831525 100644 (file)
  */
 
 #include <display/sp-canvas.h>
+#include "xml/repr.h"
+#include <gtkmm/box.h>
+
+
+#include <gtkmm.h>
+#include "ui/widget/color-picker.h"
+#include "ui/widget/scalar-unit.h"
+
+#include "ui/widget/registered-widget.h"
+#include "ui/widget/registry.h"
+#include "ui/widget/tolerance-slider.h"
+
+#include "xml/node-event-vector.h"
+
+#include "snapper.h"
+#include "line-snapper.h"
+
+struct SPDesktop;
+struct SPNamedView;
 
 namespace Inkscape {
 
+#define INKSCAPE_TYPE_GRID_CANVASITEM            (Inkscape::grid_canvasitem_get_type ())
+#define INKSCAPE_GRID_CANVASITEM(obj)            (GTK_CHECK_CAST ((obj), INKSCAPE_TYPE_GRID_CANVASITEM, GridCanvasItem))
+#define INKSCAPE_GRID_CANVASITEM_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), INKSCAPE_TYPE_GRID_CANVASITEM, GridCanvasItem))
+#define INKSCAPE_IS_GRID_CANVASITEM(obj)         (GTK_CHECK_TYPE ((obj), INKSCAPE_TYPE_GRID_CANVASITEM))
+#define INKSCAPE_IS_GRID_CANVASITEM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), INKSCAPE_TYPE_GRID_CANVASITEM))
+
+class CanvasGrid;
+
+/** \brief  All the variables that are tracked for a grid specific
+            canvas item. */
+struct GridCanvasItem : public SPCanvasItem{
+    CanvasGrid *grid; // the owning grid object
+};
+
+struct GridCanvasItemClass {
+    SPCanvasItemClass parent_class;
+};
+
+/* Standard Gtk function */
+GtkType grid_canvasitem_get_type (void);
+
+
+
+class CanvasGrid {
+public:
+    CanvasGrid(SPDesktop *desktop, Inkscape::XML::Node * in_repr);
+    virtual ~CanvasGrid();
+    
+    static CanvasGrid* NewGrid(SPDesktop *desktop, Inkscape::XML::Node * in_repr, const char * gridtype);
+    static void writeNewGridToRepr(Inkscape::XML::Node * repr, const char * gridtype);
+    
+    virtual void Update (NR::Matrix const &affine, unsigned int flags) = 0;
+    virtual void Render (SPCanvasBuf *buf) = 0;
+    
+    virtual void readRepr() {};
+    virtual void onReprAttrChanged (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive) {};
+    
+    virtual Gtk::Widget & getWidget() = 0;
+
+    bool enabled;
+    bool visible;
+    void hide();
+    void show();
+
+    Inkscape::XML::Node * repr;
+    
+    Inkscape::Snapper* snapper;
+
+    static void on_repr_attr_changed (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive, void * data);
+protected:
+    GridCanvasItem * canvasitem;
+
+    SPNamedView * namedview;
+    
+    Gtk::VBox vbox;
+
+private:
+    CanvasGrid(const CanvasGrid&);
+    CanvasGrid& operator=(const CanvasGrid&);
+};
+
+
+class CanvasXYGrid : public CanvasGrid {
+public:
+    CanvasXYGrid(SPDesktop *desktop, Inkscape::XML::Node * in_repr);
+    ~CanvasXYGrid();
+
+    void Update (NR::Matrix const &affine, unsigned int flags);
+    void Render (SPCanvasBuf *buf);
+    
+    void readRepr();
+    void onReprAttrChanged (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive);
+    
+    Gtk::Widget & getWidget();
+
+    NR::Point origin;
+    guint32 color;
+    guint32 empcolor;
+    gint  empspacing;
+    SPUnit const* gridunit;
+
+    NR::Point spacing; /**< Spacing between elements of the grid */
+    bool scaled[2];    /**< Whether the grid is in scaled mode, which can
+                            be different in the X or Y direction, hense two
+                            variables */
+    NR::Point ow;      /**< Transformed origin by the affine for the zoom */
+    NR::Point sw;      /**< Transformed spacing by the affine for the zoom */
+private:
+    CanvasXYGrid(const CanvasXYGrid&);
+    CanvasXYGrid& operator=(const CanvasXYGrid&);
+    
+    void updateWidgets();
+
+    Gtk::Table table;
+    
+    Inkscape::UI::Widget::RegisteredCheckButton _rcbgrid, _rcbsnbb, _rcbsnnod;
+    Inkscape::UI::Widget::RegisteredRadioButtonPair _rrb_gridtype;
+    Inkscape::UI::Widget::RegisteredUnitMenu    _rumg, _rums;
+    Inkscape::UI::Widget::RegisteredScalarUnit  _rsu_ox, _rsu_oy, _rsu_sx, _rsu_sy, _rsu_ax, _rsu_az;
+    Inkscape::UI::Widget::RegisteredColorPicker _rcp_gcol, _rcp_gmcol;
+    Inkscape::UI::Widget::RegisteredSuffixedInteger _rsi;
+    
+    Inkscape::UI::Widget::Registry _wr;
+
+};
+
+
+
+class CanvasXYGridSnapper : public LineSnapper
+{
+public:
+    CanvasXYGridSnapper(CanvasXYGrid *grid, SPNamedView const *nv, NR::Coord const d);
+
+private:    
+    LineList _getSnapLines(NR::Point const &p) const;
+    
+    CanvasXYGrid *grid;
+}; 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 #define INKSCAPE_TYPE_CXYGRID            (Inkscape::cxygrid_get_type ())
 #define INKSCAPE_CXYGRID(obj)            (GTK_CHECK_CAST ((obj), INKSCAPE_TYPE_CXYGRID, CXYGrid))
 #define INKSCAPE_CXYGRID_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), INKSCAPE_TYPE_CXYGRID, CXYGridClass))
index 86fae1572520d8921ce2783b649b9e06fd54fd85..ff05858fd05f3b097ca17e60136f4458f3216e69 100644 (file)
@@ -9,7 +9,7 @@
  *   Frank Felfe <innerspace@iname.com>
  *   Carl Hetherington <inkscape@carlh.net>
  *
- * Copyright (C) 2006      Johan Engelen <johan@shouraizou.nl>
+ * Copyright (C) 2006-2007      Johan Engelen <johan@shouraizou.nl>
  * Copyright (C) 1999-2002 Authors
  *
  * Released under GNU GPL, read the file 'COPYING' for more information
@@ -21,6 +21,8 @@
 #include <libnr/nr-scale-ops.h>
 #include <libnr/nr-values.h>
 
+#include "display/canvas-grid.h"
+
 /**
  *  Construct a SnapManager for a SPNamedView.
  *
@@ -52,6 +54,18 @@ SnapManager::SnapperList SnapManager::getSnappers() const
     }
     s.push_back(&guide);
     s.push_back(&object);
+
+    //add new grid snappers that are active for this desktop
+//    SPDesktop* desktop = SP_ACTIVE_DESKTOP;
+//    if (desktop) {
+
+        for ( GSList const *l = _named_view->grids; l != NULL; l = l->next) {
+            Inkscape::CanvasGrid *grid = (Inkscape::CanvasGrid*) l->data;
+            s.push_back(grid->snapper);
+        }
+
+//    }
+
     return s;
 }
 
@@ -213,7 +227,7 @@ std::pair<NR::Point, bool> SnapManager::_snapTransformed(
 
     /* The current best transformation */
     NR::Point best_transformation = transformation;
-    
+
     /* The current best metric for the best transformation; lower is better, NR_HUGE
     ** means that we haven't snapped anything.
     */
@@ -249,7 +263,7 @@ std::pair<NR::Point, bool> SnapManager::_snapTransformed(
             default:
                 g_assert_not_reached();
         }
-        
+
         /* Snap it */
         Inkscape::SnappedPoint const snapped = constrained ?
             constrainedSnap(type, transformed, constraint, ignore) : freeSnap(type, transformed, ignore);
@@ -300,7 +314,7 @@ std::pair<NR::Point, bool> SnapManager::_snapTransformed(
             }
         }
     }
-        
+
     // Using " < 1e6" instead of " < NR::HUGE" for catching some rounding errors
     // These rounding errors might be caused by NRRects, see bug #1584301
     return std::make_pair(best_transformation, best_metric < 1e6);
index d3792133bc788aae39e700e23f8cca8658d83212..75bb35cd584f556ac88b50150fdaba65efc0f1dd 100644 (file)
@@ -116,7 +116,8 @@ static void sp_namedview_init(SPNamedView *nv)
 
     nv->guides = NULL;
     nv->viewcount = 0;
-
+    nv->grids = NULL;
+    
     nv->default_layer_id = 0;
 
     nv->connector_spacing = defaultConnSpacing;
@@ -208,6 +209,13 @@ static void sp_namedview_release(SPObject *object)
         namedview->gridviews = g_slist_remove(namedview->gridviews, namedview->gridviews->data);
     }
 
+    // delete grids:
+    while ( namedview->grids ) {
+        Inkscape::CanvasGrid *gr = (Inkscape::CanvasGrid *)namedview->grids->data;
+        delete gr;
+        namedview->grids = g_slist_remove_link(namedview->grids, namedview->grids);
+    }
+    
     if (((SPObjectClass *) parent_class)->release) {
         ((SPObjectClass *) parent_class)->release(object);
     }
@@ -552,6 +560,8 @@ static void sp_namedview_set(SPObject *object, unsigned int key, const gchar *va
 
 static void sp_namedview_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
 {
+g_message("named view:: child added");
+
     SPNamedView *nv = (SPNamedView *) object;
 
     if (((SPObjectClass *) (parent_class))->child_added) {
@@ -559,27 +569,42 @@ static void sp_namedview_child_added(SPObject *object, Inkscape::XML::Node *chil
     }
 
     const gchar *id = child->attribute("id");
-    SPObject *no = object->document->getObjectById(id);
-    g_assert(SP_IS_OBJECT(no));
-
-    if (SP_IS_GUIDE(no)) {
-        SPGuide *g = (SPGuide *) no;
-        nv->guides = g_slist_prepend(nv->guides, g);
-        g_object_set(G_OBJECT(g), "color", nv->guidecolor, "hicolor", nv->guidehicolor, NULL);
-        if (nv->editable) {
-            for (GSList *l = nv->views; l != NULL; l = l->next) {
-                sp_guide_show(g, static_cast<SPDesktop*>(l->data)->guides, (GCallback) sp_dt_guide_event);
-                if (static_cast<SPDesktop*>(l->data)->guides_active)
-                    sp_guide_sensitize(g,
-                                       sp_desktop_canvas(static_cast<SPDesktop*> (l->data)),
-                                       TRUE);
-                if (nv->showguides) {
-                    for (GSList *v = SP_GUIDE(g)->views; v != NULL; v = v->next) {
-                        sp_canvas_item_show(SP_CANVAS_ITEM(v->data));
-                    }
-                } else {
-                    for (GSList *v = SP_GUIDE(g)->views; v != NULL; v = v->next) {
-                        sp_canvas_item_hide(SP_CANVAS_ITEM(v->data));
+    if (!strcmp(child->name(), "inkscape:grid")) {
+        // check for which grid-type
+        Inkscape::CanvasGrid* addedgrid;
+        const char * gridtype = child->attribute("type");
+        if (!gridtype) {
+            gridtype = "xygrid"; // use this as default gridtype when none is specified
+            child->setAttribute("type", gridtype);
+        }
+        addedgrid = Inkscape::CanvasXYGrid::NewGrid( (SPDesktop*) nv->views->data, child, gridtype);
+        if (addedgrid) {
+            nv->grids = g_slist_append(nv->grids, addedgrid);
+            addedgrid->show();
+        }
+    } else {
+        SPObject *no = object->document->getObjectById(id);
+        g_assert(SP_IS_OBJECT(no));
+
+        if (SP_IS_GUIDE(no)) {
+            SPGuide *g = (SPGuide *) no;
+            nv->guides = g_slist_prepend(nv->guides, g);
+            g_object_set(G_OBJECT(g), "color", nv->guidecolor, "hicolor", nv->guidehicolor, NULL);
+            if (nv->editable) {
+                for (GSList *l = nv->views; l != NULL; l = l->next) {
+                    sp_guide_show(g, static_cast<SPDesktop*>(l->data)->guides, (GCallback) sp_dt_guide_event);
+                    if (static_cast<SPDesktop*>(l->data)->guides_active)
+                        sp_guide_sensitize(g,
+                                           sp_desktop_canvas(static_cast<SPDesktop*> (l->data)),
+                                           TRUE);
+                    if (nv->showguides) {
+                        for (GSList *v = SP_GUIDE(g)->views; v != NULL; v = v->next) {
+                            sp_canvas_item_show(SP_CANVAS_ITEM(v->data));
+                        }
+                    } else {
+                        for (GSList *v = SP_GUIDE(g)->views; v != NULL; v = v->next) {
+                            sp_canvas_item_hide(SP_CANVAS_ITEM(v->data));
+                        }
                     }
                 }
             }
@@ -589,17 +614,29 @@ static void sp_namedview_child_added(SPObject *object, Inkscape::XML::Node *chil
 
 static void sp_namedview_remove_child(SPObject *object, Inkscape::XML::Node *child)
 {
+g_message("named view:: child removed");
     SPNamedView *nv = (SPNamedView *) object;
 
-    GSList **ref = &nv->guides;
-    for ( GSList *iter = nv->guides ; iter ; iter = iter->next ) {
-        if ( SP_OBJECT_REPR((SPObject *)iter->data) == child ) {
-            *ref = iter->next;
-            iter->next = NULL;
-            g_slist_free_1(iter);
-            break;
+    if (!strcmp(child->name(), "inkscape:grid")) {
+        for ( GSList *iter = nv->grids ; iter ; iter = iter->next ) {
+            Inkscape::CanvasGrid *gr = (Inkscape::CanvasGrid *)iter->data;
+            if ( gr->repr == child ) {
+                delete gr;
+                nv->grids = g_slist_remove_link(nv->grids, iter);
+                break;
+            }
+        }
+    } else {
+        GSList **ref = &nv->guides;
+        for ( GSList *iter = nv->guides ; iter ; iter = iter->next ) {
+            if ( SP_OBJECT_REPR((SPObject *)iter->data) == child ) {
+                *ref = iter->next;
+                iter->next = NULL;
+                g_slist_free_1(iter);
+                break;
+            }
+            ref = &iter->next;
         }
-        ref = &iter->next;
     }
 
     if (((SPObjectClass *) (parent_class))->remove_child) {
@@ -651,6 +688,22 @@ void SPNamedView::show(SPDesktop *desktop)
     // since we're keeping a copy, we need to bump up the ref count
     gtk_object_ref(GTK_OBJECT(item));
     gridviews = g_slist_prepend(gridviews, item);
+    
+    // generate grids specified in SVG:
+    Inkscape::XML::Node *repr = SP_OBJECT_REPR(this);
+    if (repr) {
+        for (Inkscape::XML::Node * child = repr->firstChild() ; child != NULL; child = child->next() ) {
+            if (!strcmp(child->name(), "inkscape:grid")) {
+                Inkscape::CanvasXYGrid* addedgrid = new Inkscape::CanvasXYGrid(desktop, child);
+                if (addedgrid) {
+                    grids = g_slist_append(grids, addedgrid);
+                    addedgrid->enabled = true;
+                    addedgrid->show();
+                }
+            }
+        }
+    }
+    
 
     sp_namedview_setup_grid(this);
 }
@@ -779,6 +832,13 @@ void SPNamedView::hide(SPDesktop const *desktop)
             gridviews = g_slist_remove(gridviews, l->data);
         }
     }
+    
+    // delete grids:
+    while ( grids ) {
+        Inkscape::CanvasGrid *gr = (Inkscape::CanvasGrid *)grids->data;
+        delete gr;
+        grids = g_slist_remove_link(grids, grids);
+    }
 }
 
 void SPNamedView::activateGuides(gpointer desktop, gboolean active)
@@ -1035,4 +1095,4 @@ SPMetric SPNamedView::getDefaultMetric() const
   fill-column:99
   End:
 */
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtab
index 619bf02ccb062c95f237f32901938bdadca8995c..f3bb960e824fc741a959ec75824be86f57d5e1df 100644 (file)
 #include "sp-metric.h"
 #include "snap.h"
 
+namespace Inkscape {
+class CanvasGrid;
+}
+
 enum {
     SP_BORDER_LAYER_BOTTOM,
     SP_BORDER_LAYER_TOP
@@ -49,6 +53,7 @@ struct SPNamedView : public SPObjectGroup {
 
     SnapManager snap_manager;
     //GridManager grid_manager;
+    GSList * grids;
 
     SPUnit const *gridunit;
     /* Grid data is in points regardless of unit */
index c6b1b30a64a17c35106630ed09ee2f2116c35c2e..4f38eb3d9d472805d99912ec420c8d7fdb9b39ab 100644 (file)
@@ -38,6 +38,8 @@
 
 #include "document-properties.h"
 
+#include "display/canvas-grid.h"
+
 using std::pair;
 
 namespace Inkscape {
@@ -53,14 +55,16 @@ namespace Dialog {
 
 static DocumentProperties *_instance = 0;
 
+static void on_child_added(Inkscape::XML::Node *repr, Inkscape::XML::Node *child, Inkscape::XML::Node *ref, void * data);
+static void on_child_removed(Inkscape::XML::Node *repr, Inkscape::XML::Node *child, Inkscape::XML::Node *ref, void * data);
 static void on_repr_attr_changed (Inkscape::XML::Node *, gchar const *, gchar const *, gchar const *, bool, gpointer);
 static void on_doc_replaced (SPDesktop* dt, SPDocument* doc);
 static void on_activate_desktop (Inkscape::Application *, SPDesktop* dt, void*);
 static void on_deactivate_desktop (Inkscape::Application *, SPDesktop* dt, void*);
 
 static Inkscape::XML::NodeEventVector const _repr_events = {
-    NULL, /* child_added */
-    NULL, /* child_removed */
+    on_child_added, /* child_added */
+    on_child_removed, /* child_removed */
     on_repr_attr_changed,
     NULL, /* content_changed */
     NULL  /* order_changed */
@@ -86,11 +90,13 @@ DocumentProperties::destroy()
     }
 }
 
-DocumentProperties::DocumentProperties() 
+DocumentProperties::DocumentProperties()
     : Dialog ("dialogs.documentoptions", SP_VERB_DIALOG_NAMEDVIEW),
       _page_page(1, 1), _page_grid(1, 1), _page_guides(1, 1),
-      _page_snap(1, 1), 
-      _prefs_path("dialogs.documentoptions")
+      _page_snap(1, 1), _page_grids(1, 1),
+      _prefs_path("dialogs.documentoptions"),
+      _grids_button_new(_("_New"), _("Create new grid.")),
+      _grids_button_remove(_("_Remove"), _("Remove selected grid."))
 {
     set_resizable (false);
     _tt.enable();
@@ -100,10 +106,15 @@ DocumentProperties::DocumentProperties()
     _notebook.append_page(_page_page,      _("Page"));
     _notebook.append_page(_page_grid,      _("Grid/Guides"));
     _notebook.append_page(_page_snap,      _("Snap"));
+    _notebook.append_page(_page_grids,     _("Grids setup"));
 
     build_page();
     build_grid();
     build_snap();
+    build_gridspage();
+
+    _grids_button_new.signal_clicked().connect(sigc::mem_fun(*this, &DocumentProperties::onNewGrid));
+    _grids_button_remove.signal_clicked().connect(sigc::mem_fun(*this, &DocumentProperties::onRemoveGrid));
 }
 
 void
@@ -120,10 +131,10 @@ DocumentProperties::init()
 
     g_signal_connect(G_OBJECT(INKSCAPE), "activate_desktop",
                      G_CALLBACK(on_activate_desktop), 0);
-    
+
     g_signal_connect(G_OBJECT(INKSCAPE), "deactivate_desktop",
                      G_CALLBACK(on_deactivate_desktop), 0);
-    
+
     show_all_children();
     if (prefs_get_int_attribute("dialogs.documentoptions", "axonomgrid_enabled", 0) != 1) {
         _rrb_gridtype._hbox->hide();
@@ -134,7 +145,7 @@ DocumentProperties::init()
     present();
 }
 
-DocumentProperties::~DocumentProperties() 
+DocumentProperties::~DocumentProperties()
 {
     Inkscape::XML::Node *repr = SP_OBJECT_REPR(sp_desktop_namedview(SP_ACTIVE_DESKTOP));
     repr->removeListenerByData (this);
@@ -159,28 +170,28 @@ attach_all (Gtk::Table &table, const Gtk::Widget *arr[], unsigned size, int star
     {
         if (arr[i] && arr[i+1])
         {
-            table.attach (const_cast<Gtk::Widget&>(*arr[i]),   1, 2, r, r+1, 
+            table.attach (const_cast<Gtk::Widget&>(*arr[i]),   1, 2, r, r+1,
                       Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
-            table.attach (const_cast<Gtk::Widget&>(*arr[i+1]), 2, 3, r, r+1, 
+            table.attach (const_cast<Gtk::Widget&>(*arr[i+1]), 2, 3, r, r+1,
                       Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
         }
         else
         {
             if (arr[i+1])
-                table.attach (const_cast<Gtk::Widget&>(*arr[i+1]), 1, 3, r, r+1, 
+                table.attach (const_cast<Gtk::Widget&>(*arr[i+1]), 1, 3, r, r+1,
                       Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
             else if (arr[i])
             {
                 Gtk::Label& label = reinterpret_cast<Gtk::Label&> (const_cast<Gtk::Widget&>(*arr[i]));
                 label.set_alignment (0.0);
-                table.attach (label, 0, 3, r, r+1, 
+                table.attach (label, 0, 3, r, r+1,
                       Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
             }
             else
             {
                 Gtk::HBox *space = manage (new Gtk::HBox);
                 space->set_size_request (SPACE_SIZE_X, SPACE_SIZE_Y);
-                table.attach (*space, 0, 1, r, r+1, 
+                table.attach (*space, 0, 1, r, r+1,
                       (Gtk::AttachOptions)0, (Gtk::AttachOptions)0,0,0);
             }
         }
@@ -211,7 +222,7 @@ DocumentProperties::build_page()
     label_for->set_markup (_("<b>Format</b>"));
     _page_sizer.init (_wr);
 
-    const Gtk::Widget* widget_array[] = 
+    const Gtk::Widget* widget_array[] =
     {
         label_gen,         0,
         _rum_deflt._label, _rum_deflt._sel,
@@ -226,7 +237,7 @@ DocumentProperties::build_page()
         0,                 _rcb_shad._button,
         _rcp_bord._label,  _rcp_bord._cp,
     };
-    
+
     attach_all (_page_page.table(), widget_array, sizeof(widget_array));
 }
 
@@ -237,36 +248,36 @@ DocumentProperties::build_grid()
 
     /// \todo FIXME: gray out snapping when grid is off.
     /// Dissenting view: you want snapping without grid.
-    
+
     _rcbgrid.init (_("_Show grid"), _("Show or hide grid"), "showgrid", _wr);
     _rrb_gridtype.init (_("Grid type:"), _("Normal (2D)"), _("Axonometric (3D)"),
                 _("The normal grid with vertical and horizontal lines."),
                 _("A grid with vertical lines and two diagonal line groups, each representing the projection of a primary axis."),
                 "gridtype", _wr);
-    
+
     _rumg.init (_("Grid _units:"), "grid_units", _wr);
-    _rsu_ox.init (_("_Origin X:"), _("X coordinate of grid origin"), 
+    _rsu_ox.init (_("_Origin X:"), _("X coordinate of grid origin"),
                   "gridoriginx", _rumg, _wr);
-    _rsu_oy.init (_("O_rigin Y:"), _("Y coordinate of grid origin"), 
+    _rsu_oy.init (_("O_rigin Y:"), _("Y coordinate of grid origin"),
                   "gridoriginy", _rumg, _wr);
-    _rsu_sx.init (_("Spacing _X:"), _("Distance between vertical grid lines"), 
+    _rsu_sx.init (_("Spacing _X:"), _("Distance between vertical grid lines"),
                   "gridspacingx", _rumg, _wr);
-    _rsu_sy.init (_("Spacing _Y:"), _("Distance between horizontal grid lines"), 
+    _rsu_sy.init (_("Spacing _Y:"), _("Distance between horizontal grid lines"),
                   "gridspacingy", _rumg, _wr);
-    _rsu_ax.init (_("Angle X:"), _("Angle of x-axis of axonometric grid"), 
+    _rsu_ax.init (_("Angle X:"), _("Angle of x-axis of axonometric grid"),
                   "gridanglex", _rumg, _wr);
-    _rsu_az.init (_("Angle Z:"), _("Angle of z-axis of axonometric grid"), 
+    _rsu_az.init (_("Angle Z:"), _("Angle of z-axis of axonometric grid"),
                   "gridanglez", _rumg, _wr);
-    _rcp_gcol.init (_("Grid line _color:"), _("Grid line color"), 
+    _rcp_gcol.init (_("Grid line _color:"), _("Grid line color"),
                     _("Color of grid lines"), "gridcolor", "gridopacity", _wr);
-    _rcp_gmcol.init (_("Ma_jor grid line color:"), _("Major grid line color"), 
-                     _("Color of the major (highlighted) grid lines"), 
+    _rcp_gmcol.init (_("Ma_jor grid line color:"), _("Major grid line color"),
+                     _("Color of the major (highlighted) grid lines"),
                      "gridempcolor", "gridempopacity", _wr);
     _rsi.init (_("_Major grid line every:"), _("lines"), "gridempspacing", _wr);
     _rcb_sgui.init (_("Show _guides"), _("Show or hide guides"), "showguides", _wr);
-    _rcp_gui.init (_("Guide co_lor:"), _("Guideline color"), 
+    _rcp_gui.init (_("Guide co_lor:"), _("Guideline color"),
                    _("Color of guidelines"), "guidecolor", "guideopacity", _wr);
-    _rcp_hgui.init (_("_Highlight color:"), _("Highlighted guideline color"), 
+    _rcp_hgui.init (_("_Highlight color:"), _("Highlighted guideline color"),
                     _("Color of a guideline when it is under mouse"),
                     "guidehicolor", "guidehiopacity", _wr);
     Gtk::Label *label_grid = manage (new Gtk::Label);
@@ -274,11 +285,11 @@ DocumentProperties::build_grid()
     Gtk::Label *label_gui = manage (new Gtk::Label);
     label_gui->set_markup (_("<b>Guides</b>"));
 
-    const Gtk::Widget* widget_array[] = 
+    const Gtk::Widget* widget_array[] =
     {
         label_grid,         0,
         0,                  _rcbgrid._button,
-        0,                  _rrb_gridtype._hbox, 
+        0,                  _rrb_gridtype._hbox,
         _rumg._label,       _rumg._sel,
         0,                  _rsu_ox.getSU(),
         0,                  _rsu_oy.getSU(),
@@ -286,7 +297,7 @@ DocumentProperties::build_grid()
         0,                  _rsu_sy.getSU(),
         0,                  _rsu_ax.getSU(),
         0,                  _rsu_az.getSU(),
-        _rcp_gcol._label,   _rcp_gcol._cp, 
+        _rcp_gcol._label,   _rcp_gcol._cp,
         0,                  0,
         _rcp_gmcol._label,  _rcp_gmcol._cp,
         _rsi._label,        &_rsi._hbox,
@@ -305,40 +316,40 @@ DocumentProperties::build_snap()
 {
     _page_snap.show();
 
-    _rcbsnbo.init (_("_Snap bounding boxes to objects"), 
-                _("Snap the edges of the object bounding boxes to other objects"), 
+    _rcbsnbo.init (_("_Snap bounding boxes to objects"),
+                _("Snap the edges of the object bounding boxes to other objects"),
                 "inkscape:object-bbox", _wr);
-    _rcbsnnob.init (_("Snap nodes _to objects"), 
-                _("Snap the nodes of objects to other objects"), 
+    _rcbsnnob.init (_("Snap nodes _to objects"),
+                _("Snap the nodes of objects to other objects"),
                 "inkscape:object-points", _wr);
-    _rcbsnop.init (_("Snap to object _paths"), 
-                _("Snap to other object paths"), 
+    _rcbsnop.init (_("Snap to object _paths"),
+                _("Snap to other object paths"),
                 "inkscape:object-paths", _wr);
-    _rcbsnon.init (_("Snap to object _nodes"), 
-                _("Snap to other object nodes"), 
+    _rcbsnon.init (_("Snap to object _nodes"),
+                _("Snap to other object nodes"),
                 "inkscape:object-nodes", _wr);
     _rsu_sno.init (_("Snap s_ensitivity:"), _("Always snap"),
                   _("Controls max. snapping distance from object"),
                   _("If set, objects snap to the nearest object when moved, regardless of distance"),
                   "objecttolerance", _wr);
-    _rcbsnbb.init (_("Snap _bounding boxes to grid"), 
-                _("Snap the edges of the object bounding boxes"), 
+    _rcbsnbb.init (_("Snap _bounding boxes to grid"),
+                _("Snap the edges of the object bounding boxes"),
                 "inkscape:grid-bbox", _wr);
-    _rcbsnnod.init (_("Snap nodes to _grid"), 
-                _("Snap path nodes, text baselines, ellipse centers, etc."), 
+    _rcbsnnod.init (_("Snap nodes to _grid"),
+                _("Snap path nodes, text baselines, ellipse centers, etc."),
                 "inkscape:grid-points", _wr);
     _rsu_sn.init (_("Snap sens_itivity:"), _("Always snap"),
                   _("Controls max. snapping distance from grid"),
                   _("If set, objects snap to the nearest grid line when moved, regardless of distance"),
                   "gridtolerance", _wr);
-    _rcb_snpgui.init (_("Snap bounding boxes to g_uides"),  
-                     _("Snap the edges of the object bounding boxes"), 
+    _rcb_snpgui.init (_("Snap bounding boxes to g_uides"),
+                     _("Snap the edges of the object bounding boxes"),
                      "inkscape:guide-bbox", _wr);
-    _rcb_snbgui.init (_("Snap p_oints to guides"), 
-                _("Snap path nodes, text baselines, ellipse centers, etc."), 
+    _rcb_snbgui.init (_("Snap p_oints to guides"),
+                _("Snap path nodes, text baselines, ellipse centers, etc."),
                 "inkscape:guide-points", _wr);
     _rsu_gusn.init (_("Snap sensiti_vity:"), _("Always snap"),
-                _("Controls max. snapping distance from guides"), 
+                _("Controls max. snapping distance from guides"),
                 _("If set, objects snap to the nearest guide when moved, regardless of distance"),
                 "guidetolerance", _wr);
 //    _rrb_pix.init (_("Sensitivity:"), _("S_creen pixels"), _("p_x units"),
@@ -351,8 +362,8 @@ DocumentProperties::build_snap()
     label_gr->set_markup (_("<b>Grid Snapping</b>"));
     Gtk::Label *label_gu = manage (new Gtk::Label);
     label_gu->set_markup (_("<b>Guide Snapping</b>"));
-     
-    const Gtk::Widget* array[] = 
+
+    const Gtk::Widget* array[] =
     {
         label_o,            0,
         0,                  _rcbsnbo._button,
@@ -378,15 +389,85 @@ DocumentProperties::build_snap()
  }
 
 /**
- * Update dialog widgets from desktop.
+* Called for _updating_ the dialog (e.g. when a new grid was manually added in XML)
+*/
+void
+DocumentProperties::update_gridspage()
+{
+    SPDesktop *dt = SP_ACTIVE_DESKTOP;
+    SPNamedView *nv = sp_desktop_namedview(dt);
+
+    //remove all tabs
+    while (_grids_notebook.get_current_page() != -1) {
+        _grids_notebook.remove_page(-1);
+    }
+
+    //add tabs
+    for (GSList const * l = nv->grids; l != NULL; l = l->next) {
+        Inkscape::CanvasGrid * grid = (Inkscape::CanvasGrid*) l->data;
+        _grids_notebook.append_page(grid->getWidget(), grid->repr->attribute("id"));
+
+    }
+    _grids_notebook.show_all();
+
+    const Gtk::Widget* widget_array[] =
+    {
+        (Gtk::Widget*) &_grids_notebook, 0
+    };
+    attach_all (_page_grids.table(), widget_array, sizeof(widget_array),3); // FIXME: a hack to let GTK show all tabs, otherwise XML manually added grids setting widgets do no show.
+}
+
+/**
+ * Build grid page of dialog.
+ */
+void
+DocumentProperties::build_gridspage()
+{
+    _page_grids.show();
+
+    SPDesktop *dt = SP_ACTIVE_DESKTOP;
+    SPNamedView *nv = sp_desktop_namedview(dt);
+
+    Gtk::Label* label_crea = manage (new Gtk::Label);
+    label_crea->set_markup (_("<b>Creation</b>"));
+    Gtk::Label* label_crea_type = manage (new Gtk::Label);
+    label_crea_type->set_markup (_("Gridtype"));
+    
+    _grids_entry_gridtype.set_text(Glib::ustring("xygrid"));
+    
+    Gtk::Label* label_def = manage (new Gtk::Label);
+    label_def->set_markup (_("<b>Defined grids</b>"));
+
+    for (GSList const * l = nv->grids; l != NULL; l = l->next) {
+        Inkscape::CanvasGrid * grid = (Inkscape::CanvasGrid*) l->data;
+        _grids_notebook.append_page(grid->getWidget(), grid->repr->attribute("id"));
+    }
+
+    const Gtk::Widget* widget_array[] =
+    {
+        label_crea, 0,
+        label_crea_type, (Gtk::Widget*) &_grids_entry_gridtype,
+        (Gtk::Widget*) &_grids_button_new,         (Gtk::Widget*) &_grids_button_remove, 
+        label_def,         0,
+        (Gtk::Widget*) &_grids_notebook, 0
+    };
+
+    attach_all (_page_grids.table(), widget_array, sizeof(widget_array));
+}
+
+
+
+/**
+ * Update dialog widgets from desktop. Also call updateWidget routines of the grids.
  */
 void
 DocumentProperties::update()
 {
     if (_wr.isUpdating()) return;
-    
+
     SPDesktop *dt = SP_ACTIVE_DESKTOP;
     SPNamedView *nv = sp_desktop_namedview(dt);
+
     _wr.setUpdating (true);
     set_sensitive (true);
 
@@ -396,8 +477,8 @@ DocumentProperties::update()
     _rcb_bord.setActive (nv->borderlayer == SP_BORDER_LAYER_TOP);
     _rcp_bord.setRgba32 (nv->bordercolor);
     _rcb_shad.setActive (nv->showpageshadow);
-    
-    if (nv->doc_units) 
+
+    if (nv->doc_units)
         _rum_deflt.setUnit (nv->doc_units);
 
     double const doc_w_px = sp_document_width(sp_desktop_document(dt));
@@ -408,7 +489,7 @@ DocumentProperties::update()
     _rcbgrid.setActive (nv->showgrid);
     _rrb_gridtype.setValue (nv->gridtype);
     _rumg.setUnit (nv->gridunit);
-    
+
     gdouble val;
     val = nv->gridorigin[NR::X];
     val = sp_pixels_get_units (val, *(nv->gridunit));
@@ -443,16 +524,20 @@ DocumentProperties::update()
     _rcbsnop.setActive (nv->snap_manager.object.getSnapToPaths());
     _rcbsnop.setActive (nv->snap_manager.object.getSnapToNodes());
     _rsu_sno.setValue (nv->objecttolerance, nv->has_abs_tolerance);
-     
+
     _rcbsnbb.setActive (nv->snap_manager.grid.getSnapTo(Inkscape::Snapper::BBOX_POINT));
     _rcbsnnod.setActive (nv->snap_manager.grid.getSnapTo(Inkscape::Snapper::SNAP_POINT));
     _rsu_sn.setValue (nv->gridtolerance, nv->has_abs_tolerance);
-    
+
     _rcb_snpgui.setActive (nv->snap_manager.guide.getSnapTo(Inkscape::Snapper::BBOX_POINT));
     _rcb_snbgui.setActive (nv->snap_manager.guide.getSnapTo(Inkscape::Snapper::SNAP_POINT));
     _rsu_gusn.setValue (nv->guidetolerance, nv->has_abs_tolerance);
 //    _rrb_pix.setValue (true);
 
+    //-----------------------------------------------------------grids page
+
+    update_gridspage();
+
     _wr.setUpdating (false);
 }
 
@@ -469,12 +554,34 @@ DocumentProperties::on_response (int id)
         _rcp_gmcol.closeWindow();
         _rcp_gui.closeWindow();
         _rcp_hgui.closeWindow();
-    } 
-    
+    }
+
     if (id == Gtk::RESPONSE_CLOSE)
         hide();
 }
 
+
+
+static void
+on_child_added(Inkscape::XML::Node *repr, Inkscape::XML::Node *child, Inkscape::XML::Node *ref, void * data)
+{
+    if (!_instance)
+        return;
+
+    _instance->update_gridspage();
+}
+
+static void
+on_child_removed(Inkscape::XML::Node *repr, Inkscape::XML::Node *child, Inkscape::XML::Node *ref, void * data)
+{
+    if (!_instance)
+        return;
+
+    _instance->update_gridspage();
+}
+
+
+
 /**
  * Called when XML node attribute changed; updates dialog widgets.
  */
@@ -487,7 +594,7 @@ on_repr_attr_changed (Inkscape::XML::Node *, gchar const *, gchar const *, gchar
     _instance->update();
 }
 
-static void 
+static void
 on_activate_desktop (Inkscape::Application *, SPDesktop* dt, void*)
 {
     if (!_instance)
@@ -501,7 +608,7 @@ on_activate_desktop (Inkscape::Application *, SPDesktop* dt, void*)
     _instance->update();
 }
 
-static void 
+static void
 on_deactivate_desktop (Inkscape::Application *, SPDesktop* dt, void*)
 {
     if (!_instance)
@@ -514,7 +621,7 @@ on_deactivate_desktop (Inkscape::Application *, SPDesktop* dt, void*)
     _instance->_doc_replaced_connection.disconnect();
 }
 
-static void 
+static void
 on_doc_replaced (SPDesktop* dt, SPDocument* doc)
 {
     if (!_instance)
@@ -528,6 +635,49 @@ on_doc_replaced (SPDesktop* dt, SPDocument* doc)
 }
 
 
+
+
+/*########################################################################
+# BUTTON CLICK HANDLERS    (callbacks)
+########################################################################*/
+
+void
+DocumentProperties::onNewGrid()
+{
+    Inkscape::XML::Node *repr = SP_OBJECT_REPR(sp_desktop_namedview(SP_ACTIVE_DESKTOP));
+
+    Glib::ustring typestring = _grids_entry_gridtype.get_text();
+    CanvasGrid::writeNewGridToRepr(repr, typestring.c_str()); // FIXME ofcourse user should supply choice for gridtype 
+}
+
+
+void
+DocumentProperties::onRemoveGrid()
+{
+    gint pagenum = _grids_notebook.get_current_page();
+    Gtk::Widget *page = _grids_notebook.get_nth_page(pagenum);
+    Glib::ustring tabtext = _grids_notebook.get_tab_label_text(*page);
+    
+    // find the grid with name tabtext (it's id) and delete that one.
+    SPDesktop *dt = SP_ACTIVE_DESKTOP;
+    SPNamedView *nv = sp_desktop_namedview(dt);
+    Inkscape::CanvasGrid * found_grid = NULL;
+    for (GSList const * l = nv->grids; l != NULL; l = l->next) {
+        Inkscape::CanvasGrid * grid = (Inkscape::CanvasGrid*) l->data;
+        gchar const *idtext = grid->repr->attribute("id");
+        if ( !strcmp(tabtext.c_str(), idtext) ) {
+            found_grid = grid;
+            break; // break out of for-loop
+        }
+    }
+    if (found_grid) {
+        // delete the grid that corresponds with the selected tab
+        // when the grid is deleted from SVG, the SPNamedview handler automatically deletes the object, so found_grid becomes an invalid pointer!
+        found_grid->repr->parent()->removeChild(found_grid->repr);
+    }
+}
+
+
 } // namespace Dialog
 } // namespace UI
 } // namespace Inkscape
@@ -537,7 +687,7 @@ on_doc_replaced (SPDesktop* dt, SPDocument* doc)
   mode:c++
   c-file-style:"stroustrup"
   c-file-offsets:((innamespace . 0)(inline-open . 0))
-  indent-tabs-mode:nil
+  indent-tabs-mode:nilu
   fill-column:99
   End:
 */
index 0f67508f2d4e47cedd560a0b48c7cf58a6b52bc5..b42c0860910c0989e3814dbf8411932dc8721321 100644 (file)
@@ -42,11 +42,14 @@ public:
     static void destroy();
     sigc::connection _doc_replaced_connection;
 
+    void  update_gridspage();
+    
 protected:
     void  build_page();
     void  build_grid();
     void  build_guides();
     void  build_snap();
+    void  build_gridspage();
     void  init();
     virtual void  on_response (int);
 
@@ -55,7 +58,9 @@ protected:
 
     NotebookPage   _page_page, _page_grid, _page_guides;
     NotebookPage   _page_snap;
+    NotebookPage   _page_grids;
 
+    //---------------------------------------------------------------
     RegisteredCheckButton _rcb_canb, _rcb_bord, _rcb_shad;
     RegisteredColorPicker _rcp_bg, _rcp_bord;
     RegisteredUnitMenu    _rum_deflt;
@@ -78,6 +83,11 @@ protected:
     ToleranceSlider       _rsu_sno;
     RegisteredRadioButtonPair _rrb_pix;
     //---------------------------------------------------------------
+    Gtk::Notebook   _grids_notebook;
+    Gtk::Button     _grids_button_new;
+    Gtk::Button     _grids_button_remove;
+    Gtk::Entry      _grids_entry_gridtype;
+    //---------------------------------------------------------------
 
     gchar * _prefs_path;
     Registry _wr;
@@ -85,6 +95,10 @@ protected:
 private:
     DocumentProperties();
     virtual ~DocumentProperties();
+
+    // callback methods for buttons on grids page.
+    void onNewGrid();
+    void onRemoveGrid();    
 };
 
 } // namespace Dialog
index 25143b9475198de67c19056492f6415e236600a2..7869a1f72da94d39fee074628b9455b54a01f02d 100644 (file)
@@ -59,7 +59,7 @@ RegisteredCheckButton::~RegisteredCheckButton()
 }
 
 void
-RegisteredCheckButton::init (const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Registry& wr, bool right)
+RegisteredCheckButton::init (const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Registry& wr, bool right, Inkscape::XML::Node* repr_in)
 {
     _button = new Gtk::CheckButton;
     _tt.set_tip (*_button, tip);
@@ -70,6 +70,8 @@ RegisteredCheckButton::init (const Glib::ustring& label, const Glib::ustring& ti
     _key = key;
     _wr = &wr;
     _toggled_connection = _button->signal_toggled().connect (sigc::mem_fun (*this, &RegisteredCheckButton::on_toggled));
+
+    repr = repr_in;
 }
 
 void
@@ -91,7 +93,9 @@ RegisteredCheckButton::on_toggled()
 
     SPDocument *doc = sp_desktop_document(dt);
 
-    Inkscape::XML::Node *repr = SP_OBJECT_REPR (sp_desktop_namedview(dt));
+    if (!repr)
+        repr = SP_OBJECT_REPR (sp_desktop_namedview(dt));
+
     _wr->setUpdating (true);
 
     bool saved = sp_document_get_undo_sensitive (doc);
@@ -101,7 +105,7 @@ RegisteredCheckButton::on_toggled()
     sp_document_set_undo_sensitive (doc, saved);
     sp_document_done (doc, SP_VERB_NONE,
                       /* TODO: annotate */ "registered-widget.cpp:103");
-    
+
     _wr->setUpdating (false);
 }
 
@@ -118,7 +122,7 @@ RegisteredUnitMenu::~RegisteredUnitMenu()
 }
 
 void
-RegisteredUnitMenu::init (const Glib::ustring& label, const Glib::ustring& key, Registry& wr)
+RegisteredUnitMenu::init (const Glib::ustring& label, const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in)
 {
     _label = new Gtk::Label (label, 1.0, 0.5);
     _label->set_use_underline (true);
@@ -128,9 +132,11 @@ RegisteredUnitMenu::init (const Glib::ustring& label, const Glib::ustring& key,
     _wr = &wr;
     _key = key;
     _changed_connection = _sel->signal_changed().connect (sigc::mem_fun (*this, &RegisteredUnitMenu::on_changed));
+
+    repr = repr_in;
 }
 
-void 
+void
 RegisteredUnitMenu::setUnit (const SPUnit* unit)
 {
     _sel->setUnit (sp_unit_get_abbreviation (unit));
@@ -143,7 +149,7 @@ RegisteredUnitMenu::on_changed()
         return;
 
     SPDesktop *dt = SP_ACTIVE_DESKTOP;
-    if (!dt) 
+    if (!dt)
         return;
 
     Inkscape::SVGOStringStream os;
@@ -154,13 +160,14 @@ RegisteredUnitMenu::on_changed()
     SPDocument *doc = sp_desktop_document(dt);
     bool saved = sp_document_get_undo_sensitive (doc);
     sp_document_set_undo_sensitive (doc, false);
-    Inkscape::XML::Node *repr = SP_OBJECT_REPR (sp_desktop_namedview(dt));
+    if (!repr)
+        repr = SP_OBJECT_REPR (sp_desktop_namedview(dt));
     repr->setAttribute(_key.c_str(), os.str().c_str());
     doc->rroot->setAttribute("sodipodi:modified", "true");
     sp_document_set_undo_sensitive (doc, saved);
-    sp_document_done (doc, SP_VERB_NONE, 
+    sp_document_done (doc, SP_VERB_NONE,
                       /* TODO: annotate */ "registered-widget.cpp:162");
-    
+
     _wr->setUpdating (false);
 }
 
@@ -177,7 +184,7 @@ RegisteredScalarUnit::~RegisteredScalarUnit()
 }
 
 void
-RegisteredScalarUnit::init (const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, const RegisteredUnitMenu &rum, Registry& wr)
+RegisteredScalarUnit::init (const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, const RegisteredUnitMenu &rum, Registry& wr, Inkscape::XML::Node* repr_in)
 {
     _widget = new ScalarUnit (label, tip, UNIT_TYPE_LINEAR, "", "", rum._sel);
     _widget->initScalar (-1e6, 1e6);
@@ -187,6 +194,8 @@ RegisteredScalarUnit::init (const Glib::ustring& label, const Glib::ustring& tip
     _um = rum._sel;
     _value_changed_connection = _widget->signal_value_changed().connect (sigc::mem_fun (*this, &RegisteredScalarUnit::on_value_changed));
     _wr = &wr;
+
+    repr = repr_in;
 }
 
 ScalarUnit*
@@ -195,7 +204,7 @@ RegisteredScalarUnit::getSU()
     return _widget;
 }
 
-void 
+void
 RegisteredScalarUnit::setValue (double val)
 {
     _widget->setValue (val);
@@ -209,7 +218,7 @@ RegisteredScalarUnit::on_value_changed()
         return;
 
     SPDesktop *dt = SP_ACTIVE_DESKTOP;
-    if (!dt) 
+    if (!dt)
         return;
 
     Inkscape::SVGOStringStream os;
@@ -222,13 +231,14 @@ RegisteredScalarUnit::on_value_changed()
     SPDocument *doc = sp_desktop_document(dt);
     bool saved = sp_document_get_undo_sensitive (doc);
     sp_document_set_undo_sensitive (doc, false);
-    Inkscape::XML::Node *repr = SP_OBJECT_REPR (sp_desktop_namedview(dt));
+    if (!repr)
+        repr = SP_OBJECT_REPR (sp_desktop_namedview(dt));
     repr->setAttribute(_key.c_str(), os.str().c_str());
     doc->rroot->setAttribute("sodipodi:modified", "true");
     sp_document_set_undo_sensitive (doc, saved);
-    sp_document_done (doc, SP_VERB_NONE, 
+    sp_document_done (doc, SP_VERB_NONE,
                       /* TODO: annotate */ "registered-widget.cpp:230");
-    
+
     _wr->setUpdating (false);
 }
 
@@ -245,7 +255,7 @@ RegisteredColorPicker::~RegisteredColorPicker()
 }
 
 void
-RegisteredColorPicker::init (const Glib::ustring& label, const Glib::ustring& title, const Glib::ustring& tip, const Glib::ustring& ckey, const Glib::ustring& akey, Registry& wr)
+RegisteredColorPicker::init (const Glib::ustring& label, const Glib::ustring& title, const Glib::ustring& tip, const Glib::ustring& ckey, const Glib::ustring& akey, Registry& wr, Inkscape::XML::Node* repr_in)
 {
     _label = new Gtk::Label (label, 1.0, 0.5);
     _label->set_use_underline (true);
@@ -255,9 +265,11 @@ RegisteredColorPicker::init (const Glib::ustring& label, const Glib::ustring& ti
     _akey = akey;
     _wr = &wr;
     _changed_connection = _cp->connectChanged (sigc::mem_fun (*this, &RegisteredColorPicker::on_changed));
+
+    repr = repr_in;
 }
 
-void 
+void
 RegisteredColorPicker::setRgba32 (guint32 rgba)
 {
     _cp->setRgba32 (rgba);
@@ -276,7 +288,8 @@ RegisteredColorPicker::on_changed (guint32 rgba)
         return;
 
     _wr->setUpdating (true);
-    Inkscape::XML::Node *repr = SP_OBJECT_REPR(sp_desktop_namedview(SP_ACTIVE_DESKTOP));
+    if (!repr)
+        repr = SP_OBJECT_REPR (sp_desktop_namedview(SP_ACTIVE_DESKTOP));
     gchar c[32];
     sp_svg_write_color(c, 32, rgba);
     repr->setAttribute(_ckey.c_str(), c);
@@ -286,7 +299,7 @@ RegisteredColorPicker::on_changed (guint32 rgba)
 
 RegisteredSuffixedInteger::RegisteredSuffixedInteger()
 : _label(0), _sb(0),
-  _adj(0.0,0.0,100.0,1.0,1.0,1.0), 
+  _adj(0.0,0.0,100.0,1.0,1.0,1.0),
   _suffix(0)
 {
 }
@@ -300,7 +313,7 @@ RegisteredSuffixedInteger::~RegisteredSuffixedInteger()
 }
 
 void
-RegisteredSuffixedInteger::init (const Glib::ustring& label, const Glib::ustring& suffix, const Glib::ustring& key, Registry& wr)
+RegisteredSuffixedInteger::init (const Glib::ustring& label, const Glib::ustring& suffix, const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in)
 {
     _key = key;
     _label = new Gtk::Label (label);
@@ -314,9 +327,11 @@ RegisteredSuffixedInteger::init (const Glib::ustring& label, const Glib::ustring
 
     _changed_connection = _adj.signal_value_changed().connect (sigc::mem_fun(*this, &RegisteredSuffixedInteger::on_value_changed));
     _wr = &wr;
+
+    repr = repr_in;
 }
 
-void 
+void
 RegisteredSuffixedInteger::setValue (int i)
 {
     _adj.set_value (i);
@@ -329,17 +344,18 @@ RegisteredSuffixedInteger::on_value_changed()
         return;
 
     _wr->setUpdating (true);
-    
+
     SPDesktop* dt = SP_ACTIVE_DESKTOP;
-    Inkscape::XML::Node *repr = SP_OBJECT_REPR(sp_desktop_namedview(dt));
+    if (!repr)
+        repr = SP_OBJECT_REPR (sp_desktop_namedview(dt));
     Inkscape::SVGOStringStream os;
     int value = int(_adj.get_value());
     os << value;
 
     repr->setAttribute(_key.c_str(), os.str().c_str());
-    sp_document_done(sp_desktop_document(dt), SP_VERB_NONE, 
+    sp_document_done(sp_desktop_document(dt), SP_VERB_NONE,
                      /* TODO: annotate */ "registered-widget.cpp:341");
-    
+
     _wr->setUpdating (false);
 }
 
@@ -354,10 +370,10 @@ RegisteredRadioButtonPair::~RegisteredRadioButtonPair()
 }
 
 void
-RegisteredRadioButtonPair::init (const Glib::ustring& label, 
-const Glib::ustring& label1, const Glib::ustring& label2, 
-const Glib::ustring& tip1, const Glib::ustring& tip2, 
-const Glib::ustring& key, Registry& wr)
+RegisteredRadioButtonPair::init (const Glib::ustring& label,
+const Glib::ustring& label1, const Glib::ustring& label2,
+const Glib::ustring& tip1, const Glib::ustring& tip2,
+const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in)
 {
     _hbox = new Gtk::HBox;
     _hbox->add (*manage (new Gtk::Label (label)));
@@ -372,9 +388,11 @@ const Glib::ustring& key, Registry& wr)
     _key = key;
     _wr = &wr;
     _changed_connection = _rb1->signal_toggled().connect (sigc::mem_fun (*this, &RegisteredRadioButtonPair::on_value_changed));
+
+    repr = repr_in;
 }
 
-void 
+void
 RegisteredRadioButtonPair::setValue (bool second)
 {
     if (second) _rb2->set_active();
@@ -388,22 +406,23 @@ RegisteredRadioButtonPair::on_value_changed()
         return;
 
     SPDesktop *dt = SP_ACTIVE_DESKTOP;
-    if (!dt) 
+    if (!dt)
         return;
 
     _wr->setUpdating (true);
-    
+
     bool second = _rb2->get_active();
     SPDocument *doc = sp_desktop_document(dt);
     bool saved = sp_document_get_undo_sensitive (doc);
     sp_document_set_undo_sensitive (doc, false);
-    Inkscape::XML::Node *repr = SP_OBJECT_REPR (sp_desktop_namedview(dt));
+    if (!repr)
+        repr = SP_OBJECT_REPR (sp_desktop_namedview(dt));
     repr->setAttribute(_key.c_str(), second ? "true" : "false");
     doc->rroot->setAttribute("sodipodi:modified", "true");
     sp_document_set_undo_sensitive (doc, saved);
-    sp_document_done (doc, SP_VERB_NONE, 
+    sp_document_done (doc, SP_VERB_NONE,
                       /* TODO: annotate */ "registered-widget.cpp:405");
-    
+
     _wr->setUpdating (false);
 }
 
index 7138f464084f103c8c577bfd5e6e97ddb3adcd7c..2b92d204d5be640f609d3c6ffb668aac49351ca3 100644 (file)
@@ -37,7 +37,7 @@ class RegisteredCheckButton {
 public:
     RegisteredCheckButton();
     ~RegisteredCheckButton();
-    void init (const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Registry& wr, bool right=true);
+    void init (const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Registry& wr, bool right=true, Inkscape::XML::Node* repr_in=NULL);
     void setActive (bool);
 
     Gtk::ToggleButton *_button;
@@ -48,13 +48,14 @@ protected:
     Registry    *_wr;
     Glib::ustring      _key;
     void on_toggled();
+    Inkscape::XML::Node *repr;
 };
 
 class RegisteredUnitMenu {
 public:
     RegisteredUnitMenu();
     ~RegisteredUnitMenu();
-    void init (const Glib::ustring& label, const Glib::ustring& key, Registry& wr);
+    void init (const Glib::ustring& label, const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in=NULL);
     void setUnit (const SPUnit*);
     Gtk::Label   *_label;
     UnitMenu     *_sel;
@@ -64,6 +65,7 @@ protected:
     void on_changed();
     Registry     *_wr;
     Glib::ustring _key;
+    Inkscape::XML::Node *repr;
 };
 
 class RegisteredScalarUnit {
@@ -74,7 +76,8 @@ public:
             const Glib::ustring& tip, 
             const Glib::ustring& key, 
             const RegisteredUnitMenu &rum,
-            Registry& wr);
+            Registry& wr,
+            Inkscape::XML::Node* repr_in=NULL);
     ScalarUnit* getSU();
     void setValue (double);
 
@@ -85,6 +88,7 @@ protected:
     Registry         *_wr;
     Glib::ustring    _key;
     void on_value_changed();
+    Inkscape::XML::Node *repr;
 };
 
 class RegisteredColorPicker {
@@ -96,7 +100,8 @@ public:
             const Glib::ustring& tip, 
             const Glib::ustring& ckey, 
             const Glib::ustring& akey,
-            Registry& wr);
+            Registry& wr,
+            Inkscape::XML::Node* repr_in=NULL);
     void setRgba32 (guint32);
     void closeWindow();
 
@@ -108,6 +113,7 @@ protected:
     Registry      *_wr;
     void on_changed (guint32);
     sigc::connection _changed_connection;
+    Inkscape::XML::Node *repr;
 };
 
 class RegisteredSuffixedInteger {
@@ -117,7 +123,8 @@ public:
     void init (const Glib::ustring& label1, 
                const Glib::ustring& label2, 
                const Glib::ustring& key,
-               Registry& wr);
+               Registry& wr,
+               Inkscape::XML::Node* repr_in=NULL);
     void setValue (int);
     Gtk::Label *_label;
     Gtk::HBox _hbox;
@@ -130,6 +137,7 @@ protected:
     Registry        *_wr;
     sigc::connection _changed_connection;
     void on_value_changed();
+    Inkscape::XML::Node *repr;
 };
 
 class RegisteredRadioButtonPair {
@@ -142,7 +150,8 @@ public:
                const Glib::ustring& tip1, 
                const Glib::ustring& tip2, 
                const Glib::ustring& key,
-               Registry& wr);
+               Registry& wr,
+               Inkscape::XML::Node* repr_in=NULL);
     void setValue (bool second);
     Gtk::HBox *_hbox;
 
@@ -153,6 +162,7 @@ protected:
     Registry        *_wr;
     sigc::connection _changed_connection;
     void on_value_changed();
+    Inkscape::XML::Node *repr;
 };