From 97be67338f149aaf4857b19dec0afa79a1bb815f Mon Sep 17 00:00:00 2001 From: johanengelen Date: Tue, 20 Mar 2007 19:58:07 +0000 Subject: [PATCH] Monster commit. New grid infrastructure. The old gridmanagement code is still there; this committed for testing purposes. Goal is to delete the old grid code later on. --- src/desktop.cpp | 11 + src/display/canvas-grid.cpp | 681 +++++++++++++++++++++++++- src/display/canvas-grid.h | 157 ++++++ src/snap.cpp | 22 +- src/sp-namedview.cpp | 122 +++-- src/sp-namedview.h | 5 + src/ui/dialog/document-properties.cpp | 276 ++++++++--- src/ui/dialog/document-properties.h | 14 + src/ui/widget/registered-widget.cpp | 89 ++-- src/ui/widget/registered-widget.h | 22 +- 10 files changed, 1253 insertions(+), 146 deletions(-) diff --git a/src/desktop.cpp b/src/desktop.cpp index ea002b872..4727f3e51 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -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)); diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index 17f5e7e8c..853fc011e 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -1,9 +1,8 @@ #define INKSCAPE_CANVAS_GRID_C /* - * CXYGrid * - * Copyright (C) Johan Engelen 2006 + * Copyright (C) Johan Engelen 2006-2007 * Copyright (C) Lauris Kaplinski 2000 * */ @@ -13,8 +12,676 @@ #include "canvas-grid.h" #include "display-forward.h" #include +#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 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(*arr[i]), 1, 2, r, r+1, + Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0); + table.attach (const_cast(*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(*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 (const_cast(*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 */ diff --git a/src/display/canvas-grid.h b/src/display/canvas-grid.h index 7645d30f6..f92c731cd 100644 --- a/src/display/canvas-grid.h +++ b/src/display/canvas-grid.h @@ -12,9 +12,166 @@ */ #include +#include "xml/repr.h" +#include + + +#include +#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)) diff --git a/src/snap.cpp b/src/snap.cpp index 86fae1572..ff05858fd 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -9,7 +9,7 @@ * Frank Felfe * Carl Hetherington * - * Copyright (C) 2006 Johan Engelen + * Copyright (C) 2006-2007 Johan Engelen * Copyright (C) 1999-2002 Authors * * Released under GNU GPL, read the file 'COPYING' for more information @@ -21,6 +21,8 @@ #include #include +#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 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 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 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); diff --git a/src/sp-namedview.cpp b/src/sp-namedview.cpp index d3792133b..75bb35cd5 100644 --- a/src/sp-namedview.cpp +++ b/src/sp-namedview.cpp @@ -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(l->data)->guides, (GCallback) sp_dt_guide_event); - if (static_cast(l->data)->guides_active) - sp_guide_sensitize(g, - sp_desktop_canvas(static_cast (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(l->data)->guides, (GCallback) sp_dt_guide_event); + if (static_cast(l->data)->guides_active) + sp_guide_sensitize(g, + sp_desktop_canvas(static_cast (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 diff --git a/src/sp-namedview.h b/src/sp-namedview.h index 619bf02cc..f3bb960e8 100644 --- a/src/sp-namedview.h +++ b/src/sp-namedview.h @@ -25,6 +25,10 @@ #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 */ diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp index c6b1b30a6..4f38eb3d9 100644 --- a/src/ui/dialog/document-properties.cpp +++ b/src/ui/dialog/document-properties.cpp @@ -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(*arr[i]), 1, 2, r, r+1, + table.attach (const_cast(*arr[i]), 1, 2, r, r+1, Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0); - table.attach (const_cast(*arr[i+1]), 2, 3, r, r+1, + table.attach (const_cast(*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(*arr[i+1]), 1, 3, r, r+1, + table.attach (const_cast(*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 (const_cast(*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 (_("Format")); _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 (_("Guides")); - 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 (_("Grid Snapping")); Gtk::Label *label_gu = manage (new Gtk::Label); label_gu->set_markup (_("Guide Snapping")); - - 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 (_("Creation")); + 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 (_("Defined grids")); + + 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: */ diff --git a/src/ui/dialog/document-properties.h b/src/ui/dialog/document-properties.h index 0f67508f2..b42c08609 100644 --- a/src/ui/dialog/document-properties.h +++ b/src/ui/dialog/document-properties.h @@ -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 diff --git a/src/ui/widget/registered-widget.cpp b/src/ui/widget/registered-widget.cpp index 25143b947..7869a1f72 100644 --- a/src/ui/widget/registered-widget.cpp +++ b/src/ui/widget/registered-widget.cpp @@ -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 = ≀ _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 = ≀ _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 = ≀ + + 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 = ≀ _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 = ≀ + + 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 = ≀ _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); } diff --git a/src/ui/widget/registered-widget.h b/src/ui/widget/registered-widget.h index 7138f4640..2b92d204d 100644 --- a/src/ui/widget/registered-widget.h +++ b/src/ui/widget/registered-widget.h @@ -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; }; -- 2.30.2