diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2013-09-19 22:33:11 +0000 |
|---|---|---|
| committer | Jabiertxof <jtx@jtx.marker.es> | 2013-09-19 22:33:11 +0000 |
| commit | 4bda89e32e33c7bdff5d3ea3c1ceee1f806de9f7 (patch) | |
| tree | caeb924426bcc861badc6fa81318b67460b26d47 /src | |
| parent | Update to trunk (diff) | |
| parent | updates for cmake (diff) | |
| download | inkscape-4bda89e32e33c7bdff5d3ea3c1ceee1f806de9f7.tar.gz inkscape-4bda89e32e33c7bdff5d3ea3c1ceee1f806de9f7.zip | |
Update to trunk
(bzr r11950.1.141)
Diffstat (limited to 'src')
360 files changed, 21263 insertions, 21142 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 42e091f43..67c5be11a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -40,16 +40,17 @@ set(sp_SRC sp-item-update-cns.cpp sp-item.cpp sp-line.cpp + sp-linear-gradient.cpp sp-lpe-item.cpp sp-mask.cpp sp-mesh-array.cpp + sp-mesh-gradient.cpp sp-mesh-patch.cpp sp-mesh-row.cpp sp-metadata.cpp sp-missing-glyph.cpp sp-namedview.cpp sp-object-group.cpp - sp-object-repr.cpp sp-object.cpp sp-offset.cpp sp-paint-server.cpp @@ -57,11 +58,11 @@ set(sp_SRC sp-pattern.cpp sp-polygon.cpp sp-polyline.cpp + sp-radial-gradient.cpp sp-rect.cpp sp-root.cpp sp-script.cpp sp-shape.cpp - # sp-skeleton.cpp sp-spiral.cpp sp-star.cpp sp-stop.cpp @@ -93,6 +94,7 @@ set(sp_SRC sp-defs.h sp-desc.h sp-ellipse.h + sp-factory.h sp-filter-primitive.h sp-filter-reference.h sp-filter-units.h @@ -104,7 +106,6 @@ set(sp_SRC sp-font.h sp-glyph-kerning.h sp-glyph.h - sp-gradient-fns.h sp-gradient-reference.h sp-gradient-spread.h sp-gradient-test.h @@ -122,23 +123,18 @@ set(sp_SRC sp-item-update-cns.h sp-item.h sp-line.h - sp-linear-gradient-fns.h sp-linear-gradient.h sp-lpe-item.h sp-marker-loc.h sp-mask.h sp-mesh-array.h - sp-mesh-gradient-fns.h sp-mesh-gradient.h - sp-mesh-patch-fns.h sp-mesh-patch.h - sp-mesh-row-fns.h sp-mesh-row.h sp-metadata.h sp-missing-glyph.h sp-namedview.h sp-object-group.h - sp-object-repr.h sp-object.h sp-offset.h sp-paint-server-reference.h @@ -147,13 +143,11 @@ set(sp_SRC sp-pattern.h sp-polygon.h sp-polyline.h - sp-radial-gradient-fns.h sp-radial-gradient.h sp-rect.h sp-root.h sp-script.h sp-shape.h - # sp-skeleton.h sp-spiral.h sp-star.h sp-stop.h @@ -359,6 +353,7 @@ set(inkscape_SRC event.h extract-uri-test.h extract-uri.h + factory.h file.h fill-or-stroke.h filter-chemistry.h @@ -395,7 +390,7 @@ set(inkscape_SRC knotholder.h layer-fns.h layer-manager.h - layer-model.h + layer-model.h line-geometry.h line-snapper.h lpe-tool-context.h @@ -476,6 +471,7 @@ set(inkscape_SRC text-context.h text-editing.h text-tag-attributes.h + tool-factory.h tools-switch.h transf_mat_3x4.h tweak-context.h @@ -492,7 +488,7 @@ set(inkscape_SRC ) if(WIN32) - list(APPEND inkscape_SRC + list(APPEND inkscape_SRC registrytool.cpp #deptool.cpp winmain.cpp @@ -560,6 +556,7 @@ add_subdirectory(libuemf) add_subdirectory(libvpsc) add_subdirectory(livarot) add_subdirectory(libnrtype) +add_subdirectory(libdepixelize) get_property(inkscape_global_SRC GLOBAL PROPERTY inkscape_global_SRC) @@ -598,6 +595,7 @@ target_link_libraries(inkscape livarot_LIB uemf_LIB 2geom_LIB + depixelize_LIB ${INKSCAPE_LIBS} ) diff --git a/src/Makefile.am b/src/Makefile.am index 77ba1f567..a0c240252 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,16 +23,16 @@ endif noinst_LIBRARIES = \ - libinkscape.a \ - dom/libdom.a \ - libcroco/libcroco.a \ - libavoid/libavoid.a \ - $(internal_GDL) \ - libuemf/libuemf.a \ - libcola/libcola.a \ - libvpsc/libvpsc.a \ - livarot/libvarot.a \ - 2geom/lib2geom.a \ + dom/libdom.a \ + libcroco/libcroco.a \ + libavoid/libavoid.a \ + $(internal_GDL) \ + libuemf/libuemf.a \ + libcola/libcola.a \ + libvpsc/libvpsc.a \ + livarot/libvarot.a \ + 2geom/lib2geom.a \ + libdepixelize/libdepixelize.a \ libinkversion.a all_libs = \ @@ -139,6 +139,7 @@ include ui/widget/Makefile_insert include util/Makefile_insert include trace/Makefile_insert include 2geom/Makefile_insert +include libdepixelize/Makefile_insert # Extra files not mentioned as sources to include in the source tarball EXTRA_DIST += \ @@ -182,8 +183,8 @@ EXTRA_DIST += \ io/crystalegg.xml \ io/doc2html.xsl \ show-preview.bmp \ - sp-skeleton.cpp sp-skeleton.h \ winconsole.cpp \ + libdepixelize/makefile.in \ $(CXXTEST_TEMPLATE) # Extra files to remove when doing "make distclean" @@ -197,13 +198,13 @@ DISTCLEANFILES = \ # ################################################ # this should speed up the build -libinkscape_a_SOURCES = $(ink_common_sources) +#libinkscape_a_SOURCES = $(ink_common_sources) -inkscape_SOURCES += main.cpp $(win32_sources) +inkscape_SOURCES += main.cpp $(ink_common_sources) $(win32_sources) inkscape_LDADD = $(all_libs) inkscape_LDFLAGS = $(kdeldflags) $(mwindows) -inkview_SOURCES += inkview.cpp $(win32_sources) +inkview_SOURCES += inkview.cpp $(ink_common_sources) $(win32_sources) inkview_LDADD = $(all_libs) inkview_LDFLAGS = $(mwindows) diff --git a/src/Makefile_insert b/src/Makefile_insert index 0cc4e7460..e719f8894 100644 --- a/src/Makefile_insert +++ b/src/Makefile_insert @@ -55,6 +55,7 @@ ink_common_sources += \ event-context.cpp event-context.h \ event-log.cpp event-log.h event.h \ extract-uri.cpp extract-uri.h \ + factory.h \ file.cpp file.h \ fill-or-stroke.h \ filter-chemistry.cpp filter-chemistry.h \ @@ -141,7 +142,7 @@ ink_common_sources += \ shape-editor.cpp shape-editor.h \ shortcuts.cpp shortcuts.h \ snap.cpp snap.h \ - snap-enums.h snap-candidate.h \ + snap-enums.h snap-candidate.h \ snapped-curve.cpp snapped-curve.h \ snapped-line.cpp snapped-line.h \ snapped-point.cpp snapped-point.h \ @@ -155,6 +156,7 @@ ink_common_sources += \ sp-defs.cpp sp-defs.h \ sp-desc.cpp sp-desc.h \ sp-ellipse.cpp sp-ellipse.h \ + sp-factory.h \ sp-filter.cpp sp-filter.h number-opt-number.h \ sp-filter-primitive.cpp sp-filter-primitive.h \ sp-filter-reference.cpp sp-filter-reference.h \ @@ -167,7 +169,6 @@ ink_common_sources += \ sp-glyph.cpp sp-glyph.h \ sp-glyph-kerning.cpp sp-glyph-kerning.h \ sp-gradient.cpp sp-gradient.h \ - sp-gradient-fns.h \ sp-gradient-reference.cpp sp-gradient-reference.h \ sp-gradient-spread.h \ sp-gradient-units.h \ @@ -183,8 +184,7 @@ ink_common_sources += \ sp-item-rm-unsatisfied-cns.cpp sp-item-rm-unsatisfied-cns.h \ sp-item-transform.cpp sp-item-transform.h \ sp-item-update-cns.cpp sp-item-update-cns.h \ - sp-linear-gradient-fns.h \ - sp-linear-gradient.h \ + sp-linear-gradient.cpp sp-linear-gradient.h \ sp-line.cpp sp-line.h \ splivarot.cpp splivarot.h \ sp-lpe-item.cpp sp-lpe-item.h \ @@ -192,17 +192,13 @@ ink_common_sources += \ sp-mask.cpp sp-mask.h \ sp-metadata.cpp sp-metadata.h \ sp-mesh-array.cpp sp-mesh-array.h \ - sp-mesh-gradient-fns.h \ - sp-mesh-gradient.h \ - sp-mesh-patch-fns.h \ + sp-mesh-gradient.cpp sp-mesh-gradient.h \ sp-mesh-patch.cpp sp-mesh-patch.h \ - sp-mesh-row-fns.h \ sp-mesh-row.cpp sp-mesh-row.h \ sp-missing-glyph.cpp sp-missing-glyph.h \ sp-namedview.cpp sp-namedview.h \ sp-object.cpp sp-object.h \ sp-object-group.cpp sp-object-group.h \ - sp-object-repr.cpp sp-object-repr.h \ sp-offset.cpp sp-offset.h \ sp-paint-server.cpp sp-paint-server.h \ sp-paint-server-reference.h \ @@ -210,8 +206,7 @@ ink_common_sources += \ sp-pattern.cpp sp-pattern.h \ sp-polygon.cpp sp-polygon.h \ sp-polyline.cpp sp-polyline.h \ - sp-radial-gradient-fns.h \ - sp-radial-gradient.h \ + sp-radial-gradient.cpp sp-radial-gradient.h \ sp-rect.cpp sp-rect.h \ sp-root.cpp sp-root.h \ sp-script.cpp sp-script.h \ @@ -244,6 +239,7 @@ ink_common_sources += \ text-context.cpp text-context.h \ text-editing.cpp text-editing.h \ text-tag-attributes.h \ + tool-factory.h \ tools-switch.cpp tools-switch.h \ transf_mat_3x4.cpp transf_mat_3x4.h \ tweak-context.h tweak-context.cpp \ diff --git a/src/arc-context.cpp b/src/arc-context.cpp index 115f45493..10e56f621 100644 --- a/src/arc-context.cpp +++ b/src/arc-context.cpp @@ -48,144 +48,102 @@ using Inkscape::DocumentUndo; -static void sp_arc_context_dispose(GObject *object); +#include "tool-factory.h" -static void sp_arc_context_setup(SPEventContext *ec); -static void sp_arc_context_finish(SPEventContext *ec); -static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent *event); -static gint sp_arc_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event); +namespace { + SPEventContext* createArcContext() { + return new SPArcContext(); + } -static void sp_arc_drag(SPArcContext *ec, Geom::Point pt, guint state); -static void sp_arc_finish(SPArcContext *ec); -static void sp_arc_cancel(SPArcContext *ec); - -G_DEFINE_TYPE(SPArcContext, sp_arc_context, SP_TYPE_EVENT_CONTEXT); - -static void sp_arc_context_class_init(SPArcContextClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - SPEventContextClass *event_context_class = SP_EVENT_CONTEXT_CLASS(klass); - - object_class->dispose = sp_arc_context_dispose; + bool arcContextRegistered = ToolFactory::instance().registerObject("/tools/shapes/arc", createArcContext); +} - event_context_class->setup = sp_arc_context_setup; - event_context_class->finish = sp_arc_context_finish; - event_context_class->root_handler = sp_arc_context_root_handler; - event_context_class->item_handler = sp_arc_context_item_handler; +const std::string& SPArcContext::getPrefsPath() { + return SPArcContext::prefsPath; } -static void sp_arc_context_init(SPArcContext *arc_context) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(arc_context); +const std::string SPArcContext::prefsPath = "/tools/shapes/arc"; - event_context->cursor_shape = cursor_ellipse_xpm; - event_context->hot_x = 4; - event_context->hot_y = 4; - event_context->xp = 0; - event_context->yp = 0; - event_context->tolerance = 0; - event_context->within_tolerance = false; - event_context->item_to_select = NULL; - event_context->tool_url = "/tools/shapes/arc"; - arc_context->item = NULL; +SPArcContext::SPArcContext() : SPEventContext() { + this->cursor_shape = cursor_ellipse_xpm; + this->hot_x = 4; + this->hot_y = 4; + this->xp = 0; + this->yp = 0; + this->tolerance = 0; + this->within_tolerance = false; + this->item_to_select = NULL; + //this->tool_url = "/tools/shapes/arc"; - new (&arc_context->sel_changed_connection) sigc::connection(); + this->arc = NULL; } -static void sp_arc_context_finish(SPEventContext *ec) -{ - SPArcContext *ac = SP_ARC_CONTEXT(ec); - SPDesktop *desktop = ec->desktop; - +void SPArcContext::finish() { sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), GDK_CURRENT_TIME); - sp_arc_finish(ac); - ac->sel_changed_connection.disconnect(); + this->finishItem(); + this->sel_changed_connection.disconnect(); - if ((SP_EVENT_CONTEXT_CLASS(sp_arc_context_parent_class))->finish) { - (SP_EVENT_CONTEXT_CLASS(sp_arc_context_parent_class))->finish(ec); - } + SPEventContext::finish(); } -static void sp_arc_context_dispose(GObject *object) -{ - SPEventContext *ec = SP_EVENT_CONTEXT(object); - SPArcContext *ac = SP_ARC_CONTEXT(object); +SPArcContext::~SPArcContext() { + this->enableGrDrag(false); - ec->enableGrDrag(false); + this->sel_changed_connection.disconnect(); - ac->sel_changed_connection.disconnect(); - ac->sel_changed_connection.~connection(); - - delete ec->shape_editor; - ec->shape_editor = NULL; + delete this->shape_editor; + this->shape_editor = NULL; /* fixme: This is necessary because we do not grab */ - if (ac->item) { - sp_arc_finish(ac); + if (this->arc) { + this->finishItem(); } - - delete ac->_message_context; - - G_OBJECT_CLASS(sp_arc_context_parent_class)->dispose(object); } /** * Callback that processes the "changed" signal on the selection; * destroys old and creates new knotholder. */ -static void sp_arc_context_selection_changed(Inkscape::Selection * selection, gpointer data) -{ - SPArcContext *ac = SP_ARC_CONTEXT(data); - SPEventContext *ec = SP_EVENT_CONTEXT(ac); - - ec->shape_editor->unset_item(SH_KNOTHOLDER); - SPItem *item = selection->singleItem(); - ec->shape_editor->set_item(item, SH_KNOTHOLDER); +void SPArcContext::selection_changed(Inkscape::Selection* selection) { + this->shape_editor->unset_item(SH_KNOTHOLDER); + this->shape_editor->set_item(selection->singleItem(), SH_KNOTHOLDER); } -static void sp_arc_context_setup(SPEventContext *ec) -{ - SPArcContext *ac = SP_ARC_CONTEXT(ec); - Inkscape::Selection *selection = sp_desktop_selection(ec->desktop); +void SPArcContext::setup() { + SPEventContext::setup(); - if ((SP_EVENT_CONTEXT_CLASS(sp_arc_context_parent_class))->setup) { - (SP_EVENT_CONTEXT_CLASS(sp_arc_context_parent_class))->setup(ec); - } + Inkscape::Selection *selection = sp_desktop_selection(this->desktop); - ec->shape_editor = new ShapeEditor(ec->desktop); + this->shape_editor = new ShapeEditor(this->desktop); - SPItem *item = sp_desktop_selection(ec->desktop)->singleItem(); + SPItem *item = sp_desktop_selection(this->desktop)->singleItem(); if (item) { - ec->shape_editor->set_item(item, SH_KNOTHOLDER); + this->shape_editor->set_item(item, SH_KNOTHOLDER); } - ac->sel_changed_connection.disconnect(); - ac->sel_changed_connection = selection->connectChanged( - sigc::bind(sigc::ptr_fun(&sp_arc_context_selection_changed), (gpointer) ac) - ); + this->sel_changed_connection.disconnect(); + this->sel_changed_connection = selection->connectChanged( + sigc::mem_fun(this, &SPArcContext::selection_changed) + ); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/tools/shapes/selcue")) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } if (prefs->getBool("/tools/shapes/gradientdrag")) { - ec->enableGrDrag(); + this->enableGrDrag(); } - - ac->_message_context = new Inkscape::MessageContext(ec->desktop->messageStack()); } -static gint sp_arc_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event) -{ - SPDesktop *desktop = event_context->desktop; +bool SPArcContext::item_handler(SPItem* item, GdkEvent* event) { gint ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { - Inkscape::setup_for_drag_start(desktop, event_context, event); + if (event->button.button == 1 && !this->space_panning) { + Inkscape::setup_for_drag_start(desktop, this, event); ret = TRUE; } break; @@ -194,37 +152,36 @@ static gint sp_arc_context_item_handler(SPEventContext *event_context, SPItem *i break; } - if ((SP_EVENT_CONTEXT_CLASS(sp_arc_context_parent_class))->item_handler) { - ret = (SP_EVENT_CONTEXT_CLASS(sp_arc_context_parent_class))->item_handler(event_context, item, event); - } +// if ((SP_EVENT_CONTEXT_CLASS(sp_arc_context_parent_class))->item_handler) { +// ret = (SP_EVENT_CONTEXT_CLASS(sp_arc_context_parent_class))->item_handler(event_context, item, event); +// } + // CPPIFY: ret is overwritten... + ret = SPEventContext::item_handler(item, event); return ret; } -static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent *event) -{ +bool SPArcContext::root_handler(GdkEvent* event) { static bool dragging; - SPDesktop *desktop = event_context->desktop; Inkscape::Selection *selection = sp_desktop_selection(desktop); - SPArcContext *ac = SP_ARC_CONTEXT(event_context); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - event_context->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); + this->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); gint ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { - + if (event->button.button == 1 && !this->space_panning) { dragging = true; - ac->center = Inkscape::setup_for_drag_start(desktop, event_context, event); + + this->center = Inkscape::setup_for_drag_start(desktop, this, event); /* Snap center */ SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); - m.freeSnapReturnByRef(ac->center, Inkscape::SNAPSOURCE_NODE_HANDLE); + m.freeSnapReturnByRef(this->center, Inkscape::SNAPSOURCE_NODE_HANDLE); sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), GDK_KEY_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | @@ -235,27 +192,26 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent } break; case GDK_MOTION_NOTIFY: - if (dragging && (event->motion.state & GDK_BUTTON1_MASK) && !event_context->space_panning) { - - if ( event_context->within_tolerance - && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance ) - && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) { + if (dragging && (event->motion.state & GDK_BUTTON1_MASK) && !this->space_panning) { + if ( this->within_tolerance + && ( abs( (gint) event->motion.x - this->xp ) < this->tolerance ) + && ( abs( (gint) event->motion.y - this->yp ) < this->tolerance ) ) { break; // do not drag if we're within tolerance from origin } // Once the user has moved farther than tolerance from the original location // (indicating they intend to draw, not click), then always process the // motion notify coordinates as given (no snapping back to origin) - event_context->within_tolerance = false; + this->within_tolerance = false; Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point motion_dt(desktop->w2d(motion_w)); - sp_arc_drag(ac, motion_dt, event->motion.state); + this->drag(motion_dt, event->motion.state); gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; - } else if (!sp_event_context_knot_mouseover(ac)){ + } else if (!sp_event_context_knot_mouseover(this)){ SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); @@ -266,31 +222,34 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent } break; case GDK_BUTTON_RELEASE: - event_context->xp = event_context->yp = 0; - if (event->button.button == 1 && !event_context->space_panning) { + this->xp = this->yp = 0; + if (event->button.button == 1 && !this->space_panning) { dragging = false; - sp_event_context_discard_delayed_snap_event(event_context); - if (!event_context->within_tolerance) { + sp_event_context_discard_delayed_snap_event(this); + + if (!this->within_tolerance) { // we've been dragging, finish the arc - sp_arc_finish(ac); - } else if (event_context->item_to_select) { + this->finishItem(); + } else if (this->item_to_select) { // no dragging, select clicked item if any if (event->button.state & GDK_SHIFT_MASK) { - selection->toggle(event_context->item_to_select); + selection->toggle(this->item_to_select); } else { - selection->set(event_context->item_to_select); + selection->set(this->item_to_select); } } else { // click in an empty space selection->clear(); } - event_context->xp = 0; - event_context->yp = 0; - event_context->item_to_select = NULL; + + this->xp = 0; + this->yp = 0; + this->item_to_select = NULL; ret = TRUE; } sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); break; + case GDK_KEY_PRESS: switch (get_group0_keyval (&event->key)) { case GDK_KEY_Alt_L: @@ -302,12 +261,13 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent case GDK_KEY_Meta_L: // Meta is when you press Shift+Alt (at least on my machine) case GDK_KEY_Meta_R: if (!dragging) { - sp_event_show_modifier_tip(event_context->defaultMessageContext(), event, + sp_event_show_modifier_tip(this->defaultMessageContext(), event, _("<b>Ctrl</b>: make circle or integer-ratio ellipse, snap arc/segment angle"), _("<b>Shift</b>: draw around the starting point"), NULL); } break; + case GDK_KEY_Up: case GDK_KEY_Down: case GDK_KEY_KP_Up: @@ -316,6 +276,7 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent if (!MOD__CTRL_ONLY(event)) ret = TRUE; break; + case GDK_KEY_x: case GDK_KEY_X: if (MOD__ALT_ONLY(event)) { @@ -323,38 +284,42 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent ret = TRUE; } break; + case GDK_KEY_Escape: if (dragging) { dragging = false; - sp_event_context_discard_delayed_snap_event(event_context); + sp_event_context_discard_delayed_snap_event(this); // if drawing, cancel, otherwise pass it up for deselecting - sp_arc_cancel(ac); + this->cancel(); ret = TRUE; } break; + case GDK_KEY_space: if (dragging) { - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), - event->button.time); + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); dragging = false; - sp_event_context_discard_delayed_snap_event(event_context); - if (!event_context->within_tolerance) { + sp_event_context_discard_delayed_snap_event(this); + + if (!this->within_tolerance) { // we've been dragging, finish the arc - sp_arc_finish(ac); + this->finishItem(); } // do not return true, so that space would work switching to selector } break; + case GDK_KEY_Delete: case GDK_KEY_KP_Delete: case GDK_KEY_BackSpace: - ret = event_context->deleteSelectedDrag(MOD__CTRL_ONLY(event)); + ret = this->deleteSelectedDrag(MOD__CTRL_ONLY(event)); break; default: break; } break; + case GDK_KEY_RELEASE: switch (event->key.keyval) { case GDK_KEY_Alt_L: @@ -365,32 +330,28 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent case GDK_KEY_Shift_R: case GDK_KEY_Meta_L: // Meta is when you press Shift+Alt case GDK_KEY_Meta_R: - event_context->defaultMessageContext()->clear(); + this->defaultMessageContext()->clear(); break; + default: break; } break; + default: break; } if (!ret) { - if ((SP_EVENT_CONTEXT_CLASS(sp_arc_context_parent_class))->root_handler) { - ret = (SP_EVENT_CONTEXT_CLASS(sp_arc_context_parent_class))->root_handler(event_context, event); - } + ret = SPEventContext::root_handler(event); } return ret; } -static void sp_arc_drag(SPArcContext *ac, Geom::Point pt, guint state) -{ - SPDesktop *desktop = SP_EVENT_CONTEXT(ac)->desktop; - - if (!ac->item) { - - if (Inkscape::have_viable_layer(desktop, ac->_message_context) == false) { +void SPArcContext::drag(Geom::Point pt, guint state) { + if (!this->arc) { + if (Inkscape::have_viable_layer(desktop, this->message_context) == false) { return; } @@ -402,33 +363,38 @@ static void sp_arc_drag(SPArcContext *ac, Geom::Point pt, guint state) // Set style sp_desktop_apply_style_tool(desktop, repr, "/tools/shapes/arc", false); - ac->item = SP_ITEM(desktop->currentLayer()->appendChildRepr(repr)); + this->arc = SP_ARC(desktop->currentLayer()->appendChildRepr(repr)); Inkscape::GC::release(repr); - ac->item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); - ac->item->updateRepr(); + this->arc->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); + this->arc->updateRepr(); desktop->canvas->forceFullRedrawAfterInterruptions(5); } bool ctrl_save = false; + if ((state & GDK_MOD1_MASK) && (state & GDK_CONTROL_MASK) && !(state & GDK_SHIFT_MASK)) { // if Alt is pressed without Shift in addition to Control, temporarily drop the CONTROL mask // so that the ellipse is not constrained to integer ratios ctrl_save = true; state = state ^ GDK_CONTROL_MASK; } - Geom::Rect r = Inkscape::snap_rectangular_box(desktop, ac->item, pt, ac->center, state); + + Geom::Rect r = Inkscape::snap_rectangular_box(desktop, this->arc, pt, this->center, state); + if (ctrl_save) { state = state ^ GDK_CONTROL_MASK; } Geom::Point dir = r.dimensions() / 2; + if (state & GDK_MOD1_MASK) { /* With Alt let the ellipse pass through the mouse pointer */ Geom::Point c = r.midpoint(); + if (!ctrl_save) { if (fabs(dir[Geom::X]) > 1E-6 && fabs(dir[Geom::Y]) > 1E-6) { - Geom::Affine const i2d ( (ac->item)->i2dt_affine() ); + Geom::Affine const i2d ( (this->arc)->i2dt_affine() ); Geom::Point new_dir = pt * i2d - c; new_dir[Geom::X] *= dir[Geom::Y] / dir[Geom::X]; double lambda = new_dir.length() / dir[Geom::Y]; @@ -443,18 +409,21 @@ static void sp_arc_drag(SPArcContext *ac, Geom::Point pt, guint state) } } - sp_arc_position_set(SP_ARC(ac->item), + sp_arc_position_set(SP_ARC(this->arc), r.midpoint()[Geom::X], r.midpoint()[Geom::Y], r.dimensions()[Geom::X] / 2, r.dimensions()[Geom::Y] / 2); double rdimx = r.dimensions()[Geom::X]; double rdimy = r.dimensions()[Geom::Y]; + Inkscape::Util::Quantity rdimx_q = Inkscape::Util::Quantity(rdimx, "px"); Inkscape::Util::Quantity rdimy_q = Inkscape::Util::Quantity(rdimy, "px"); GString *xs = g_string_new(rdimx_q.string(*desktop->namedview->doc_units).c_str()); GString *ys = g_string_new(rdimy_q.string(*desktop->namedview->doc_units).c_str()); + if (state & GDK_CONTROL_MASK) { int ratio_x, ratio_y; + if (fabs (rdimx) > fabs (rdimy)) { ratio_x = (int) rint (rdimx / rdimy); ratio_y = 1; @@ -462,56 +431,50 @@ static void sp_arc_drag(SPArcContext *ac, Geom::Point pt, guint state) ratio_x = 1; ratio_y = (int) rint (rdimy / rdimx); } - ac->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Ellipse</b>: %s × %s (constrained to ratio %d:%d); with <b>Shift</b> to draw around the starting point"), xs->str, ys->str, ratio_x, ratio_y); + + this->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Ellipse</b>: %s × %s (constrained to ratio %d:%d); with <b>Shift</b> to draw around the starting point"), xs->str, ys->str, ratio_x, ratio_y); } else { - ac->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Ellipse</b>: %s × %s; with <b>Ctrl</b> to make square or integer-ratio ellipse; with <b>Shift</b> to draw around the starting point"), xs->str, ys->str); + this->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Ellipse</b>: %s × %s; with <b>Ctrl</b> to make square or integer-ratio ellipse; with <b>Shift</b> to draw around the starting point"), xs->str, ys->str); } + g_string_free(xs, FALSE); g_string_free(ys, FALSE); } -static void sp_arc_finish(SPArcContext *ac) -{ - ac->_message_context->clear(); - - if (ac->item != NULL) { +void SPArcContext::finishItem() { + this->message_context->clear(); - SPGenericEllipse *ge = SP_GENERICELLIPSE(SP_ARC(ac->item)); - if (ge->rx.computed == 0 || ge->ry.computed == 0) { - sp_arc_cancel(ac); // Don't allow the creating of zero sized arc, for example when the start and and point snap to the snap grid point + if (this->arc != NULL) { + if (this->arc->rx.computed == 0 || this->arc->ry.computed == 0) { + this->cancel(); // Don't allow the creating of zero sized arc, for example when the start and and point snap to the snap grid point return; } - SPDesktop *desktop = SP_EVENT_CONTEXT(ac)->desktop; - - SP_OBJECT(ac->item)->updateRepr(); + this->arc->updateRepr(); desktop->canvas->endForcedFullRedraws(); - sp_desktop_selection(desktop)->set(ac->item); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC, - _("Create ellipse")); + sp_desktop_selection(desktop)->set(this->arc); - ac->item = NULL; + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC, _("Create ellipse")); + + this->arc = NULL; } } -static void sp_arc_cancel(SPArcContext *ac) -{ - SPDesktop *desktop = SP_EVENT_CONTEXT(ac)->desktop; - +void SPArcContext::cancel() { sp_desktop_selection(desktop)->clear(); sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0); - if (ac->item != NULL) { - SP_OBJECT(ac->item)->deleteObject(); - ac->item = NULL; + if (this->arc != NULL) { + this->arc->deleteObject(); + this->arc = NULL; } - ac->within_tolerance = false; - ac->xp = 0; - ac->yp = 0; - ac->item_to_select = NULL; + this->within_tolerance = false; + this->xp = 0; + this->yp = 0; + this->item_to_select = NULL; desktop->canvas->endForcedFullRedraws(); diff --git a/src/arc-context.h b/src/arc-context.h index 3e4f5412d..56eb02943 100644 --- a/src/arc-context.h +++ b/src/arc-context.h @@ -21,29 +21,38 @@ #include <2geom/point.h> #include "event-context.h" -#define SP_TYPE_ARC_CONTEXT (sp_arc_context_get_type()) -#define SP_ARC_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_ARC_CONTEXT, SPArcContext)) -#define SP_ARC_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_ARC_CONTEXT, SPArcContextClass)) -#define SP_IS_ARC_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_ARC_CONTEXT)) -#define SP_IS_ARC_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_ARC_CONTEXT)) - -struct SPArcContext : public SPEventContext { - SPItem *item; - Geom::Point center; +#include "sp-ellipse.h" - sigc::connection sel_changed_connection; +#define SP_ARC_CONTEXT(obj) (dynamic_cast<SPArcContext*>((SPEventContext*)obj)) +#define SP_IS_ARC_CONTEXT(obj) (dynamic_cast<const SPArcContext*>(const SPEventContext*(obj)) != NULL) - Inkscape::MessageContext *_message_context; -}; +class SPArcContext : public SPEventContext { +public: + SPArcContext(); + virtual ~SPArcContext(); -struct SPArcContextClass { - SPEventContextClass parent_class; -}; + static const std::string prefsPath; + + virtual void setup(); + virtual void finish(); + virtual bool root_handler(GdkEvent* event); + virtual bool item_handler(SPItem* item, GdkEvent* event); -/* Standard Gtk function */ + virtual const std::string& getPrefsPath(); -GType sp_arc_context_get_type(void); +private: + SPArc *arc; + Geom::Point center; + + sigc::connection sel_changed_connection; + + void selection_changed(Inkscape::Selection* selection); + + void drag(Geom::Point pt, guint state); + void finishItem(); + void cancel(); +}; #endif /* !SEEN_ARC_CONTEXT_H */ diff --git a/src/box3d-context.cpp b/src/box3d-context.cpp index 7491520de..912c67801 100644 --- a/src/box3d-context.cpp +++ b/src/box3d-context.cpp @@ -52,115 +52,77 @@ using Inkscape::DocumentUndo; -static void sp_box3d_context_dispose(GObject *object); +#include "tool-factory.h" -static void sp_box3d_context_setup(SPEventContext *ec); -static void sp_box3d_context_finish(SPEventContext *ec); +namespace { + SPEventContext* createBox3dContext() { + return new Box3DContext(); + } -static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEvent *event); -static gint sp_box3d_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event); - -static void sp_box3d_drag(Box3DContext &bc, guint state); -static void sp_box3d_finish(Box3DContext *bc); - -G_DEFINE_TYPE(Box3DContext, sp_box3d_context, SP_TYPE_EVENT_CONTEXT); - -static void sp_box3d_context_class_init(Box3DContextClass *klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - SPEventContextClass *event_context_class = (SPEventContextClass *) klass; - - object_class->dispose = sp_box3d_context_dispose; - - event_context_class->setup = sp_box3d_context_setup; - event_context_class->finish = sp_box3d_context_finish; - event_context_class->root_handler = sp_box3d_context_root_handler; - event_context_class->item_handler = sp_box3d_context_item_handler; + bool box3dContextRegistered = ToolFactory::instance().registerObject("/tools/shapes/3dbox", createBox3dContext); } -static void sp_box3d_context_init(Box3DContext *box3d_context) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(box3d_context); +const std::string& Box3DContext::getPrefsPath() { + return Box3DContext::prefsPath; +} - event_context->cursor_shape = cursor_3dbox_xpm; - event_context->hot_x = 4; - event_context->hot_y = 4; - event_context->xp = 0; - event_context->yp = 0; - event_context->tolerance = 0; - event_context->within_tolerance = false; - event_context->item_to_select = NULL; +const std::string Box3DContext::prefsPath = "/tools/shapes/3dbox"; - box3d_context->item = NULL; +Box3DContext::Box3DContext() : SPEventContext() { + this->cursor_shape = cursor_3dbox_xpm; + this->hot_x = 4; + this->hot_y = 4; + this->xp = 0; + this->yp = 0; + this->tolerance = 0; + this->within_tolerance = false; + this->item_to_select = NULL; - box3d_context->ctrl_dragged = false; - box3d_context->extruded = false; + this->box3d = NULL; - box3d_context->_vpdrag = NULL; + this->ctrl_dragged = false; + this->extruded = false; - new (&box3d_context->sel_changed_connection) sigc::connection(); + this->_vpdrag = NULL; } -static void sp_box3d_context_finish(SPEventContext *ec) -{ - Box3DContext *bc = SP_BOX3D_CONTEXT(ec); - SPDesktop *desktop = ec->desktop; - +void Box3DContext::finish() { sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), GDK_CURRENT_TIME); - sp_box3d_finish(bc); - bc->sel_changed_connection.disconnect(); -// sp_repr_remove_listener_by_data(cc->active_shape_repr, cc); + this->finishItem(); + this->sel_changed_connection.disconnect(); - if (((SPEventContextClass *) sp_box3d_context_parent_class)->finish) { - ((SPEventContextClass *) sp_box3d_context_parent_class)->finish(ec); - } + SPEventContext::finish(); } -static void sp_box3d_context_dispose(GObject *object) -{ - Box3DContext *bc = SP_BOX3D_CONTEXT(object); - SPEventContext *ec = SP_EVENT_CONTEXT(object); +Box3DContext::~Box3DContext() { + this->enableGrDrag(false); - ec->enableGrDrag(false); + delete (this->_vpdrag); + this->_vpdrag = NULL; - delete (bc->_vpdrag); - bc->_vpdrag = NULL; + this->sel_changed_connection.disconnect(); - bc->sel_changed_connection.disconnect(); - bc->sel_changed_connection.~connection(); - - delete ec->shape_editor; - ec->shape_editor = NULL; + delete this->shape_editor; + this->shape_editor = NULL; /* fixme: This is necessary because we do not grab */ - if (bc->item) { - sp_box3d_finish(bc); - } - - if (bc->_message_context) { - delete bc->_message_context; + if (this->box3d) { + this->finishItem(); } - - G_OBJECT_CLASS(sp_box3d_context_parent_class)->dispose(object); } /** * Callback that processes the "changed" signal on the selection; * destroys old and creates new knotholder. */ -static void sp_box3d_context_selection_changed(Inkscape::Selection *selection, gpointer data) -{ - Box3DContext *bc = SP_BOX3D_CONTEXT(data); - SPEventContext *ec = SP_EVENT_CONTEXT(bc); - - ec->shape_editor->unset_item(SH_KNOTHOLDER); - SPItem *item = selection->singleItem(); - ec->shape_editor->set_item(item, SH_KNOTHOLDER); +void Box3DContext::selection_changed(Inkscape::Selection* selection) { + this->shape_editor->unset_item(SH_KNOTHOLDER); + this->shape_editor->set_item(selection->singleItem(), SH_KNOTHOLDER); if (selection->perspList().size() == 1) { // selecting a single box changes the current perspective - ec->desktop->doc()->setCurrentPersp3D(selection->perspList().front()); + this->desktop->doc()->setCurrentPersp3D(selection->perspList().front()); } } @@ -183,50 +145,41 @@ static void sp_box3d_context_ensure_persp_in_defs(SPDocument *document) { } } -static void sp_box3d_context_setup(SPEventContext *ec) -{ - Box3DContext *bc = SP_BOX3D_CONTEXT(ec); - - if (((SPEventContextClass *) sp_box3d_context_parent_class)->setup) { - ((SPEventContextClass *) sp_box3d_context_parent_class)->setup(ec); - } +void Box3DContext::setup() { + SPEventContext::setup(); - ec->shape_editor = new ShapeEditor(ec->desktop); + this->shape_editor = new ShapeEditor(this->desktop); - SPItem *item = sp_desktop_selection(ec->desktop)->singleItem(); + SPItem *item = sp_desktop_selection(this->desktop)->singleItem(); if (item) { - ec->shape_editor->set_item(item, SH_KNOTHOLDER); + this->shape_editor->set_item(item, SH_KNOTHOLDER); } - bc->sel_changed_connection.disconnect(); - bc->sel_changed_connection = sp_desktop_selection(ec->desktop)->connectChanged( - sigc::bind(sigc::ptr_fun(&sp_box3d_context_selection_changed), (gpointer)bc) + this->sel_changed_connection.disconnect(); + this->sel_changed_connection = sp_desktop_selection(this->desktop)->connectChanged( + sigc::mem_fun(this, &Box3DContext::selection_changed) ); - bc->_vpdrag = new Box3D::VPDrag(sp_desktop_document (ec->desktop)); + this->_vpdrag = new Box3D::VPDrag(sp_desktop_document(this->desktop)); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/tools/shapes/selcue")) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } if (prefs->getBool("/tools/shapes/gradientdrag")) { - ec->enableGrDrag(); + this->enableGrDrag(); } - - bc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack()); } -static gint sp_box3d_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event) -{ - SPDesktop *desktop = event_context->desktop; - +bool Box3DContext::item_handler(SPItem* item, GdkEvent* event) { gint ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: - if ( event->button.button == 1 && !event_context->space_panning) { - Inkscape::setup_for_drag_start(desktop, event_context, event); + if ( event->button.button == 1 && !this->space_panning) { + Inkscape::setup_for_drag_start(desktop, this, event); ret = TRUE; } break; @@ -235,55 +188,53 @@ static gint sp_box3d_context_item_handler(SPEventContext *event_context, SPItem break; } - if (((SPEventContextClass *) sp_box3d_context_parent_class)->item_handler) { - ret = ((SPEventContextClass *) sp_box3d_context_parent_class)->item_handler(event_context, item, event); - } +// if (((SPEventContextClass *) sp_box3d_context_parent_class)->item_handler) { +// ret = ((SPEventContextClass *) sp_box3d_context_parent_class)->item_handler(event_context, item, event); +// } + // CPPIFY: ret is always overwritten... + ret = SPEventContext::item_handler(item, event); return ret; } -static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEvent *event) -{ +bool Box3DContext::root_handler(GdkEvent* event) { static bool dragging; - SPDesktop *desktop = event_context->desktop; SPDocument *document = sp_desktop_document (desktop); Inkscape::Selection *selection = sp_desktop_selection (desktop); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int const snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12); - Box3DContext *bc = SP_BOX3D_CONTEXT(event_context); Persp3D *cur_persp = document->getCurrentPersp3D(); - event_context->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); + this->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); gint ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: - if ( event->button.button == 1 && !event_context->space_panning) { - Geom::Point const button_w(event->button.x, - event->button.y); + if ( event->button.button == 1 && !this->space_panning) { + Geom::Point const button_w(event->button.x, event->button.y); Geom::Point button_dt(desktop->w2d(button_w)); // save drag origin - event_context->xp = (gint) button_w[Geom::X]; - event_context->yp = (gint) button_w[Geom::Y]; - event_context->within_tolerance = true; + this->xp = (gint) button_w[Geom::X]; + this->yp = (gint) button_w[Geom::Y]; + this->within_tolerance = true; - // remember clicked item, *not* disregarding groups (since a 3D box is a group), honoring Alt - event_context->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, event->button.state & GDK_CONTROL_MASK); + // remember clicked box3d, *not* disregarding groups (since a 3D box is a group), honoring Alt + this->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, event->button.state & GDK_CONTROL_MASK); dragging = true; SnapManager &m = desktop->namedview->snap_manager; - m.setup(desktop, true, bc->item); + m.setup(desktop, true, this->box3d); m.freeSnapReturnByRef(button_dt, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); - bc->center = button_dt; + this->center = button_dt; - bc->drag_origin = button_dt; - bc->drag_ptB = button_dt; - bc->drag_ptC = button_dt; + this->drag_origin = button_dt; + this->drag_ptB = button_dt; + this->drag_ptC = button_dt; // This can happen after saving when the last remaining perspective was purged and must be recreated. if (!cur_persp) { @@ -292,11 +243,11 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven } /* Projective preimages of clicked point under current perspective */ - bc->drag_origin_proj = cur_persp->perspective_impl->tmat.preimage (button_dt, 0, Proj::Z); - bc->drag_ptB_proj = bc->drag_origin_proj; - bc->drag_ptC_proj = bc->drag_origin_proj; - bc->drag_ptC_proj.normalize(); - bc->drag_ptC_proj[Proj::Z] = 0.25; + this->drag_origin_proj = cur_persp->perspective_impl->tmat.preimage (button_dt, 0, Proj::Z); + this->drag_ptB_proj = this->drag_origin_proj; + this->drag_ptC_proj = this->drag_origin_proj; + this->drag_ptC_proj.normalize(); + this->drag_ptC_proj[Proj::Z] = 0.25; sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), ( GDK_KEY_PRESS_MASK | @@ -307,66 +258,67 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven ret = TRUE; } break; + case GDK_MOTION_NOTIFY: - if ( dragging - && ( event->motion.state & GDK_BUTTON1_MASK ) && !event_context->space_panning) - { - if ( event_context->within_tolerance - && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance ) - && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) { + if (dragging && ( event->motion.state & GDK_BUTTON1_MASK ) && !this->space_panning) { + if ( this->within_tolerance + && ( abs( (gint) event->motion.x - this->xp ) < this->tolerance ) + && ( abs( (gint) event->motion.y - this->yp ) < this->tolerance ) ) { break; // do not drag if we're within tolerance from origin } // Once the user has moved farther than tolerance from the original location // (indicating they intend to draw, not click), then always process the // motion notify coordinates as given (no snapping back to origin) - event_context->within_tolerance = false; + this->within_tolerance = false; Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point motion_dt(desktop->w2d(motion_w)); SnapManager &m = desktop->namedview->snap_manager; - m.setup(desktop, true, bc->item); + m.setup(desktop, true, this->box3d); m.freeSnapReturnByRef(motion_dt, Inkscape::SNAPSOURCE_NODE_HANDLE); - bc->ctrl_dragged = event->motion.state & GDK_CONTROL_MASK; + this->ctrl_dragged = event->motion.state & GDK_CONTROL_MASK; - if (event->motion.state & GDK_SHIFT_MASK && !bc->extruded && bc->item) { - // once shift is pressed, set bc->extruded - bc->extruded = true; + if ((event->motion.state & GDK_SHIFT_MASK) && !this->extruded && this->box3d) { + // once shift is pressed, set this->extruded + this->extruded = true; } - if (!bc->extruded) { - bc->drag_ptB = motion_dt; - bc->drag_ptC = motion_dt; + if (!this->extruded) { + this->drag_ptB = motion_dt; + this->drag_ptC = motion_dt; - bc->drag_ptB_proj = cur_persp->perspective_impl->tmat.preimage (motion_dt, 0, Proj::Z); - bc->drag_ptC_proj = bc->drag_ptB_proj; - bc->drag_ptC_proj.normalize(); - bc->drag_ptC_proj[Proj::Z] = 0.25; + this->drag_ptB_proj = cur_persp->perspective_impl->tmat.preimage (motion_dt, 0, Proj::Z); + this->drag_ptC_proj = this->drag_ptB_proj; + this->drag_ptC_proj.normalize(); + this->drag_ptC_proj[Proj::Z] = 0.25; } else { // Without Ctrl, motion of the extruded corner is constrained to the // perspective line from drag_ptB to vanishing point Y. - if (!bc->ctrl_dragged) { + if (!this->ctrl_dragged) { /* snapping */ - Box3D::PerspectiveLine pline (bc->drag_ptB, Proj::Z, document->getCurrentPersp3D()); - bc->drag_ptC = pline.closest_to (motion_dt); + Box3D::PerspectiveLine pline (this->drag_ptB, Proj::Z, document->getCurrentPersp3D()); + this->drag_ptC = pline.closest_to (motion_dt); - bc->drag_ptB_proj.normalize(); - bc->drag_ptC_proj = cur_persp->perspective_impl->tmat.preimage (bc->drag_ptC, bc->drag_ptB_proj[Proj::X], Proj::X); + this->drag_ptB_proj.normalize(); + this->drag_ptC_proj = cur_persp->perspective_impl->tmat.preimage (this->drag_ptC, this->drag_ptB_proj[Proj::X], Proj::X); } else { - bc->drag_ptC = motion_dt; + this->drag_ptC = motion_dt; - bc->drag_ptB_proj.normalize(); - bc->drag_ptC_proj = cur_persp->perspective_impl->tmat.preimage (motion_dt, bc->drag_ptB_proj[Proj::X], Proj::X); + this->drag_ptB_proj.normalize(); + this->drag_ptC_proj = cur_persp->perspective_impl->tmat.preimage (motion_dt, this->drag_ptB_proj[Proj::X], Proj::X); } - m.freeSnapReturnByRef(bc->drag_ptC, Inkscape::SNAPSOURCE_NODE_HANDLE); + + m.freeSnapReturnByRef(this->drag_ptC, Inkscape::SNAPSOURCE_NODE_HANDLE); } + m.unSetup(); - sp_box3d_drag(*bc, event->motion.state); + this->drag(event->motion.state); ret = TRUE; - } else if (!sp_event_context_knot_mouseover(bc)) { + } else if (!sp_event_context_knot_mouseover(this)) { SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); @@ -376,33 +328,36 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven m.unSetup(); } break; + case GDK_BUTTON_RELEASE: - event_context->xp = event_context->yp = 0; - if ( event->button.button == 1 && !event_context->space_panning) { + this->xp = this->yp = 0; + + if (event->button.button == 1 && !this->space_panning) { dragging = false; - sp_event_context_discard_delayed_snap_event(event_context); + sp_event_context_discard_delayed_snap_event(this); - if (!event_context->within_tolerance) { + if (!this->within_tolerance) { // we've been dragging, finish the box - sp_box3d_finish(bc); - } else if (event_context->item_to_select) { - // no dragging, select clicked item if any + this->finishItem(); + } else if (this->item_to_select) { + // no dragging, select clicked box3d if any if (event->button.state & GDK_SHIFT_MASK) { - selection->toggle(event_context->item_to_select); + selection->toggle(this->item_to_select); } else { - selection->set(event_context->item_to_select); + selection->set(this->item_to_select); } } else { // click in an empty space selection->clear(); } - event_context->item_to_select = NULL; + this->item_to_select = NULL; ret = TRUE; sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); } break; + case GDK_KEY_PRESS: switch (get_group0_keyval (&event->key)) { case GDK_KEY_Up: @@ -492,7 +447,7 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven } if (MOD__SHIFT_ONLY(event)) { persp3d_toggle_VPs(selection->perspList(), Proj::X); - bc->_vpdrag->updateLines(); // FIXME: Shouldn't this be done automatically? + this->_vpdrag->updateLines(); // FIXME: Shouldn't this be done automatically? ret = true; } break; @@ -501,7 +456,7 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven case GDK_KEY_Y: if (MOD__SHIFT_ONLY(event)) { persp3d_toggle_VPs(selection->perspList(), Proj::Y); - bc->_vpdrag->updateLines(); // FIXME: Shouldn't this be done automatically? + this->_vpdrag->updateLines(); // FIXME: Shouldn't this be done automatically? ret = true; } break; @@ -510,7 +465,7 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven case GDK_KEY_Z: if (MOD__SHIFT_ONLY(event)) { persp3d_toggle_VPs(selection->perspList(), Proj::Z); - bc->_vpdrag->updateLines(); // FIXME: Shouldn't this be done automatically? + this->_vpdrag->updateLines(); // FIXME: Shouldn't this be done automatically? ret = true; } break; @@ -525,55 +480,50 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); dragging = false; - sp_event_context_discard_delayed_snap_event(event_context); - if (!event_context->within_tolerance) { + sp_event_context_discard_delayed_snap_event(this); + if (!this->within_tolerance) { // we've been dragging, finish the box - sp_box3d_finish(bc); + this->finishItem(); } // do not return true, so that space would work switching to selector } break; + case GDK_KEY_Delete: case GDK_KEY_KP_Delete: case GDK_KEY_BackSpace: - ret = event_context->deleteSelectedDrag(MOD__CTRL_ONLY(event)); + ret = this->deleteSelectedDrag(MOD__CTRL_ONLY(event)); break; default: break; } break; + default: break; } if (!ret) { - if (((SPEventContextClass *) sp_box3d_context_parent_class)->root_handler) { - ret = ((SPEventContextClass *) sp_box3d_context_parent_class)->root_handler(event_context, event); - } + ret = SPEventContext::root_handler(event); } return ret; } -static void sp_box3d_drag(Box3DContext &bc, guint /*state*/) -{ - SPDesktop *desktop = bc.desktop; - - if (!bc.item) { - - if (Inkscape::have_viable_layer(desktop, bc._message_context) == false) { +void Box3DContext::drag(guint state) { + if (!this->box3d) { + if (Inkscape::have_viable_layer(desktop, this->message_context) == false) { return; } // Create object - SPBox3D *box3d = 0; - box3d = SPBox3D::createBox3D((SPItem *)desktop->currentLayer()); + SPBox3D *box3d = SPBox3D::createBox3D((SPItem*)desktop->currentLayer()); // Set style desktop->applyCurrentOrToolStyle(box3d, "/tools/shapes/3dbox", false); - bc.item = box3d; + this->box3d = box3d; // TODO: Incorporate this in box3d-side.cpp! for (int i = 0; i < 6; ++i) { @@ -593,13 +543,14 @@ static void sp_box3d_drag(Box3DContext &bc, guint /*state*/) Glib::ustring descr = "/desktop/"; descr += box3d_side_axes_string(side); descr += "/style"; + Glib::ustring cur_style = prefs->getString(descr); bool use_current = prefs->getBool("/tools/shapes/3dbox/usecurrent", false); + if (use_current && !cur_style.empty()) { // use last used style side->setAttribute("style", cur_style.data()); - } else { // use default style GString *pstring = g_string_new(""); @@ -610,71 +561,59 @@ static void sp_box3d_drag(Box3DContext &bc, guint /*state*/) side->updateRepr(); // calls box3d_side_write() and updates, e.g., the axes string description } - box3d_set_z_orders(SP_BOX3D(bc.item)); - bc.item->updateRepr(); + box3d_set_z_orders(this->box3d); + this->box3d->updateRepr(); // TODO: It would be nice to show the VPs during dragging, but since there is no selection // at this point (only after finishing the box), we must do this "manually" - /* bc._vpdrag->updateDraggers(); */ + /* this._vpdrag->updateDraggers(); */ desktop->canvas->forceFullRedrawAfterInterruptions(5); } - g_assert(bc.item); - - SPBox3D *box = SP_BOX3D(bc.item); + g_assert(this->box3d); - box->orig_corner0 = bc.drag_origin_proj; - box->orig_corner7 = bc.drag_ptC_proj; + this->box3d->orig_corner0 = this->drag_origin_proj; + this->box3d->orig_corner7 = this->drag_ptC_proj; - box3d_check_for_swapped_coords(box); + box3d_check_for_swapped_coords(this->box3d); /* we need to call this from here (instead of from box3d_position_set(), for example) because z-order setting must not interfere with display updates during undo/redo */ - box3d_set_z_orders (box); + box3d_set_z_orders (this->box3d); - box3d_position_set(box); + box3d_position_set(this->box3d); // status text - bc._message_context->setF(Inkscape::NORMAL_MESSAGE, _("<b>3D Box</b>; with <b>Shift</b> to extrude along the Z axis")); + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("<b>3D Box</b>; with <b>Shift</b> to extrude along the Z axis")); } -static void sp_box3d_finish(Box3DContext *bc) -{ - bc->_message_context->clear(); - bc->ctrl_dragged = false; - bc->extruded = false; +void Box3DContext::finishItem() { + this->message_context->clear(); + this->ctrl_dragged = false; + this->extruded = false; - if ( bc->item != NULL ) { - SPDesktop * desktop = SP_EVENT_CONTEXT_DESKTOP(bc); - SPDocument *doc = sp_desktop_document(desktop); - if (!doc || !doc->getCurrentPersp3D()) - return; + if (this->box3d != NULL) { + SPDocument *doc = sp_desktop_document(this->desktop); - SPBox3D *box = SP_BOX3D(bc->item); + if (!doc || !doc->getCurrentPersp3D()) { + return; + } - box->orig_corner0 = bc->drag_origin_proj; - box->orig_corner7 = bc->drag_ptC_proj; + this->box3d->orig_corner0 = this->drag_origin_proj; + this->box3d->orig_corner7 = this->drag_ptC_proj; - box->updateRepr(); + this->box3d->updateRepr(); - box3d_relabel_corners(box); + box3d_relabel_corners(this->box3d); desktop->canvas->endForcedFullRedraws(); - sp_desktop_selection(desktop)->set(bc->item); + sp_desktop_selection(desktop)->set(this->box3d); DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_3DBOX, _("Create 3D box")); - bc->item = NULL; - } -} - -void sp_box3d_context_update_lines(SPEventContext *ec) { - /* update perspective lines if we are in the 3D box tool (so that infinite ones are shown correctly) */ - if (SP_IS_BOX3D_CONTEXT (ec)) { - Box3DContext *bc = SP_BOX3D_CONTEXT (ec); - bc->_vpdrag->updateLines(); + this->box3d = NULL; } } diff --git a/src/box3d-context.h b/src/box3d-context.h index 70ff87ad1..044d79d7d 100644 --- a/src/box3d-context.h +++ b/src/box3d-context.h @@ -21,14 +21,29 @@ #include "proj_pt.h" #include "vanishing-point.h" -#define SP_TYPE_BOX3D_CONTEXT (sp_box3d_context_get_type ()) -#define SP_BOX3D_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_BOX3D_CONTEXT, Box3DContext)) -#define SP_BOX3D_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_BOX3D_CONTEXT, Box3DContextClass)) -#define SP_IS_BOX3D_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_BOX3D_CONTEXT)) -#define SP_IS_BOX3D_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_BOX3D_CONTEXT)) - -struct Box3DContext : public SPEventContext { - SPItem *item; +#include "box3d.h" + +#define SP_BOX3D_CONTEXT(obj) (dynamic_cast<Box3DContext*>((SPEventContext*)obj)) +#define SP_IS_BOX3D_CONTEXT(obj) (dynamic_cast<const Box3DContext*>((const SPEventContext*)obj) != NULL) + +class Box3DContext : public SPEventContext { +public: + Box3DContext(); + virtual ~Box3DContext(); + + Box3D::VPDrag * _vpdrag; + + static const std::string prefsPath; + + virtual void setup(); + virtual void finish(); + virtual bool root_handler(GdkEvent* event); + virtual bool item_handler(SPItem* item, GdkEvent* event); + + virtual const std::string& getPrefsPath(); + +private: + SPBox3D* box3d; Geom::Point center; /** @@ -50,23 +65,14 @@ struct Box3DContext : public SPEventContext { bool ctrl_dragged; /* whether we are ctrl-dragging */ bool extruded; /* whether shift-dragging already occured (i.e. the box is already extruded) */ - Box3D::VPDrag * _vpdrag; - sigc::connection sel_changed_connection; - Inkscape::MessageContext *_message_context; -}; + void selection_changed(Inkscape::Selection* selection); -struct Box3DContextClass { - SPEventContextClass parent_class; + void drag(guint state); + void finishItem(); }; -/* Standard Gtk function */ - -GType sp_box3d_context_get_type (void); - -void sp_box3d_context_update_lines(SPEventContext *ec); - #endif /* __SP_BOX3D_CONTEXT_H__ */ /* diff --git a/src/box3d-side.cpp b/src/box3d-side.cpp index fc18207b0..d3d3b82a2 100644 --- a/src/box3d-side.cpp +++ b/src/box3d-side.cpp @@ -24,54 +24,35 @@ #include "desktop-style.h" #include "box3d.h" -struct SPPathClass; - -static void box3d_side_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static Inkscape::XML::Node *box3d_side_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void box3d_side_set (SPObject *object, unsigned int key, const gchar *value); -static void box3d_side_update (SPObject *object, SPCtx *ctx, guint flags); - -static void box3d_side_set_shape (SPShape *shape); - static void box3d_side_compute_corner_ids(Box3DSide *side, unsigned int corners[4]); -G_DEFINE_TYPE(Box3DSide, box3d_side, SP_TYPE_SHAPE); +#include "sp-factory.h" -static void box3d_side_class_init(Box3DSideClass *klass) -{ - SPObjectClass *sp_object_class = reinterpret_cast<SPObjectClass *>(klass); - SPShapeClass *shape_class = reinterpret_cast<SPShapeClass *>(klass); +namespace { + SPObject* createBox3DSide() { + return new Box3DSide(); + } - sp_object_class->build = box3d_side_build; - sp_object_class->write = box3d_side_write; - sp_object_class->set = box3d_side_set; - sp_object_class->update = box3d_side_update; + bool box3DSideRegistered = SPFactory::instance().registerObject("inkscape:box3dside", createBox3DSide); +} - shape_class->set_shape = box3d_side_set_shape; +Box3DSide::Box3DSide() : SPPolygon() { + this->dir1 = Box3D::NONE; + this->dir2 = Box3D::NONE; + this->front_or_rear = Box3D::FRONT; } -static void -box3d_side_init (Box3DSide * side) -{ - side->dir1 = Box3D::NONE; - side->dir2 = Box3D::NONE; - side->front_or_rear = Box3D::FRONT; +Box3DSide::~Box3DSide() { } -static void box3d_side_build(SPObject * object, SPDocument * document, Inkscape::XML::Node * repr) -{ - if ((SP_OBJECT_CLASS(box3d_side_parent_class))->build) { - (SP_OBJECT_CLASS(box3d_side_parent_class))->build(object, document, repr); - } +void Box3DSide::build(SPDocument * document, Inkscape::XML::Node * repr) { + SPPolygon::build(document, repr); - object->readAttr( "inkscape:box3dsidetype" ); + this->readAttr( "inkscape:box3dsidetype" ); } -static Inkscape::XML::Node * -box3d_side_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - Box3DSide *side = SP_BOX3D_SIDE (object); +Inkscape::XML::Node* Box3DSide::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { // this is where we end up when saving as plain SVG (also in other circumstances?) // thus we don' set "sodipodi:type" so that the box is only saved as an ordinary svg:path @@ -79,32 +60,29 @@ box3d_side_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape:: } if (flags & SP_OBJECT_WRITE_EXT) { - sp_repr_set_int(repr, "inkscape:box3dsidetype", side->dir1 ^ side->dir2 ^ side->front_or_rear); + sp_repr_set_int(repr, "inkscape:box3dsidetype", this->dir1 ^ this->dir2 ^ this->front_or_rear); } - static_cast<SPShape *>(object)->setShape(); + this->set_shape(); /* Duplicate the path */ - SPCurve const *curve = (SP_SHAPE(object))->_curve; + SPCurve const *curve = this->_curve; + //Nulls might be possible if this called iteratively if ( !curve ) { return NULL; } + char *d = sp_svg_write_path ( curve->get_pathvector() ); repr->setAttribute("d", d); g_free (d); - if ((SP_OBJECT_CLASS(box3d_side_parent_class))->write) - (SP_OBJECT_CLASS(box3d_side_parent_class))->write (object, xml_doc, repr, flags); + SPPolygon::write(xml_doc, repr, flags); return repr; } -static void -box3d_side_set (SPObject *object, unsigned int key, const gchar *value) -{ - Box3DSide *side = SP_BOX3D_SIDE (object); - +void Box3DSide::set(unsigned int key, const gchar* value) { // TODO: In case the box was recreated (by undo, e.g.) we need to recreate the path // (along with other info?) from the parent box. @@ -117,26 +95,25 @@ box3d_side_set (SPObject *object, unsigned int key, const gchar *value) if (!Box3D::is_face_id(desc)) { g_print ("desc is not a face id: =%s=\n", value); } + g_return_if_fail (Box3D::is_face_id (desc)); + Box3D::Axis plane = (Box3D::Axis) (desc & 0x7); plane = (Box3D::is_plane(plane) ? plane : Box3D::orth_plane_or_axis(plane)); - side->dir1 = Box3D::extract_first_axis_direction(plane); - side->dir2 = Box3D::extract_second_axis_direction(plane); - side->front_or_rear = (Box3D::FrontOrRear) (desc & 0x8); + this->dir1 = Box3D::extract_first_axis_direction(plane); + this->dir2 = Box3D::extract_second_axis_direction(plane); + this->front_or_rear = (Box3D::FrontOrRear) (desc & 0x8); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } break; default: - if ((SP_OBJECT_CLASS(box3d_side_parent_class))->set) - (SP_OBJECT_CLASS(box3d_side_parent_class))->set (object, key, value); + SPPolygon::set(key, value); break; } } -static void -box3d_side_update (SPObject *object, SPCtx *ctx, guint flags) -{ +void Box3DSide::update(SPCtx* ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B; // since we change the description, it's not a "just translation" anymore } @@ -144,11 +121,11 @@ box3d_side_update (SPObject *object, SPCtx *ctx, guint flags) if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - static_cast<SPShape *>(object)->setShape (); + + this->set_shape(); } - if ((SP_OBJECT_CLASS(box3d_side_parent_class))->update) - (SP_OBJECT_CLASS(box3d_side_parent_class))->update (object, ctx, flags); + SPPolygon::update(ctx, flags); } /* Create a new Box3DSide and append it to the parent box */ @@ -173,30 +150,30 @@ int Box3DSide::getFaceId() void box3d_side_position_set (Box3DSide *side) { - box3d_side_set_shape (SP_SHAPE (side)); + side->set_shape(); // This call is responsible for live update of the sides during the initial drag side->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } -void -box3d_side_set_shape (SPShape *shape) -{ - Box3DSide *side = SP_BOX3D_SIDE (shape); - if (!side->document->getRoot()) { +void Box3DSide::set_shape() { + if (!this->document->getRoot()) { // avoid a warning caused by sp_document_height() (which is called from sp_item_i2d_affine() below) // when reading a file containing 3D boxes return; } - SPObject *parent = side->parent; + SPObject *parent = this->parent; + if (!SP_IS_BOX3D(parent)) { - g_warning ("Parent of 3D box side is not a 3D box.\n"); + g_warning("Parent of 3D box side is not a 3D box.\n"); return; } + SPBox3D *box = SP_BOX3D(parent); - Persp3D *persp = box3d_side_perspective(side); + Persp3D *persp = box3d_side_perspective(this); + if (!persp) { return; } @@ -207,7 +184,7 @@ box3d_side_set_shape (SPShape *shape) // resulting path. unsigned int corners[4]; - box3d_side_compute_corner_ids(side, corners); + box3d_side_compute_corner_ids(this, corners); SPCurve *c = new SPCurve(); @@ -226,17 +203,21 @@ box3d_side_set_shape (SPShape *shape) c->lineto(box3d_get_corner_screen(box, corners[3])); c->closepath(); - /* Reset the shape'scurve to the "original_curve" + /* Reset the this'scurve to the "original_curve" * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ - shape->setCurveInsync( c, TRUE); - if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(shape)) && sp_lpe_item_path_effects_enabled(SP_LPE_ITEM(shape))) { + this->setCurveInsync( c, TRUE); + + if (sp_lpe_item_has_path_effect(this) && sp_lpe_item_path_effects_enabled(this)) { SPCurve *c_lpe = c->copy(); - bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM (shape), c_lpe); + bool success = sp_lpe_item_perform_path_effect(this, c_lpe); + if (success) { - shape->setCurveInsync( c_lpe, TRUE); + this->setCurveInsync(c_lpe, TRUE); } + c_lpe->unref(); } + c->unref(); } @@ -244,19 +225,24 @@ gchar *box3d_side_axes_string(Box3DSide *side) { GString *pstring = g_string_new(""); g_string_printf (pstring, "%s", Box3D::string_from_axes ((Box3D::Axis) (side->dir1 ^ side->dir2))); + switch ((Box3D::Axis) (side->dir1 ^ side->dir2)) { case Box3D::XY: g_string_append_printf (pstring, (side->front_or_rear == Box3D::FRONT) ? "front" : "rear"); break; + case Box3D::XZ: g_string_append_printf (pstring, (side->front_or_rear == Box3D::FRONT) ? "top" : "bottom"); break; + case Box3D::YZ: g_string_append_printf (pstring, (side->front_or_rear == Box3D::FRONT) ? "right" : "left"); break; + default: break; } + return pstring->str; } diff --git a/src/box3d-side.h b/src/box3d-side.h index dee775fca..04bd196c2 100644 --- a/src/box3d-side.h +++ b/src/box3d-side.h @@ -16,29 +16,32 @@ #include "sp-polygon.h" #include "axis-manip.h" -#define SP_TYPE_BOX3D_SIDE (box3d_side_get_type ()) -#define SP_BOX3D_SIDE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_BOX3D_SIDE, Box3DSide)) -#define SP_BOX3D_SIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_BOX3D_SIDE, Box3DSideClass)) -#define SP_IS_BOX3D_SIDE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_BOX3D_SIDE)) -#define SP_IS_BOX3D_SIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_BOX3D_SIDE)) + +#define SP_BOX3D_SIDE(obj) (dynamic_cast<Box3DSide*>((SPObject*)obj)) +#define SP_IS_BOX3D_SIDE(obj) (dynamic_cast<const Box3DSide*>((SPObject*)obj) != NULL) class SPBox3D; -struct Persp3D; +class Persp3D; // FIXME: Would it be better to inherit from SPPath instead? -struct Box3DSide : public SPPolygon { +class Box3DSide : public SPPolygon { +public: + Box3DSide(); + virtual ~Box3DSide(); + Box3D::Axis dir1; Box3D::Axis dir2; Box3D::FrontOrRear front_or_rear; int getFaceId(); static Box3DSide * createBox3DSide(SPBox3D *box); -}; -struct Box3DSideClass { - SPPolygonClass parent_class; -}; + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void set(unsigned int key, gchar const* value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + virtual void update(SPCtx *ctx, guint flags); -GType box3d_side_get_type (void); + virtual void set_shape(); +}; void box3d_side_position_set (Box3DSide *side); // FIXME: Replace this by box3d_side_set_shape?? diff --git a/src/box3d.cpp b/src/box3d.cpp index ed0f717d4..0f528a592 100644 --- a/src/box3d.cpp +++ b/src/box3d.cpp @@ -39,50 +39,35 @@ #include "desktop-handles.h" #include "macros.h" -static void box3d_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void box3d_release(SPObject *object); -static void box3d_set(SPObject *object, unsigned int key, const gchar *value); -static void box3d_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *box3d_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -static gchar *box3d_description(SPItem *item); -static Geom::Affine box3d_set_transform(SPItem *item, Geom::Affine const &xform); -static void box3d_convert_to_guides(SPItem *item); - static void box3d_ref_changed(SPObject *old_ref, SPObject *ref, SPBox3D *box); static gint counter = 0; -G_DEFINE_TYPE(SPBox3D, box3d, SP_TYPE_GROUP); +#include "sp-factory.h" -static void box3d_class_init(SPBox3DClass *klass) -{ - SPObjectClass *sp_object_class = SP_OBJECT_CLASS(klass); - SPItemClass *item_class = SP_ITEM_CLASS(klass); - - sp_object_class->build = box3d_build; - sp_object_class->release = box3d_release; - sp_object_class->set = box3d_set; - sp_object_class->write = box3d_write; - sp_object_class->update = box3d_update; - - item_class->description = box3d_description; - item_class->set_transform = box3d_set_transform; - item_class->convert_to_guides = box3d_convert_to_guides; +namespace { + SPObject* createBox3D() { + return new SPBox3D(); + } + + bool box3DRegistered = SPFactory::instance().registerObject("inkscape:box3d", createBox3D); } -static void -box3d_init(SPBox3D *box) -{ - box->persp_href = NULL; - box->persp_ref = new Persp3DReference(box); +SPBox3D::SPBox3D() : SPGroup() { + this->my_counter = 0; + this->swapped = Box3D::NONE; + + this->persp_href = NULL; + this->persp_ref = new Persp3DReference(this); } -static void box3d_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if ((SP_OBJECT_CLASS(box3d_parent_class))->build) { - (SP_OBJECT_CLASS(box3d_parent_class))->build(object, document, repr); - } +SPBox3D::~SPBox3D() { +} + +void SPBox3D::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPBox3D* object = this; + + SPGroup::build(document, repr); SPBox3D *box = SP_BOX3D (object); box->my_counter = counter++; @@ -104,13 +89,9 @@ static void box3d_build(SPObject *object, SPDocument *document, Inkscape::XML::N } } -/** - * Virtual release of SPBox3D members before destruction. - */ -static void -box3d_release(SPObject *object) -{ - SPBox3D *box = SP_BOX3D(object); +void SPBox3D::release() { + SPBox3D* object = this; + SPBox3D *box = object; if (box->persp_href) { g_free(box->persp_href); @@ -143,14 +124,12 @@ box3d_release(SPObject *object) */ } - if ((SP_OBJECT_CLASS(box3d_parent_class))->release) - (SP_OBJECT_CLASS(box3d_parent_class))->release(object); + SPGroup::release(); } -static void -box3d_set(SPObject *object, unsigned int key, const gchar *value) -{ - SPBox3D *box = SP_BOX3D(object); +void SPBox3D::set(unsigned int key, const gchar* value) { + SPBox3D* object = this; + SPBox3D *box = object; switch (key) { case SP_ATTR_INKSCAPE_BOX3D_PERSPECTIVE_ID: @@ -195,9 +174,7 @@ box3d_set(SPObject *object, unsigned int key, const gchar *value) } break; default: - if ((SP_OBJECT_CLASS(box3d_parent_class))->set) { - (SP_OBJECT_CLASS(box3d_parent_class))->set(object, key, value); - } + SPGroup::set(key, value); break; } } @@ -218,9 +195,7 @@ box3d_ref_changed(SPObject *old_ref, SPObject *ref, SPBox3D *box) } } -static void -box3d_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPBox3D::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { /* FIXME?: Perhaps the display updates of box sides should be instantiated from here, but this @@ -230,14 +205,12 @@ box3d_update(SPObject *object, SPCtx *ctx, guint flags) } // Invoke parent method - if ((SP_OBJECT_CLASS(box3d_parent_class))->update) - (SP_OBJECT_CLASS(box3d_parent_class))->update(object, ctx, flags); + SPGroup::update(ctx, flags); } - -static Inkscape::XML::Node * box3d_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPBox3D *box = SP_BOX3D(object); +Inkscape::XML::Node* SPBox3D::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { + SPBox3D* object = this; + SPBox3D *box = object; if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { // this is where we end up when saving as plain SVG (also in other circumstances?) @@ -277,19 +250,16 @@ static Inkscape::XML::Node * box3d_write(SPObject *object, Inkscape::XML::Docume box->save_corner7 = box->orig_corner7; } - if ((SP_OBJECT_CLASS(box3d_parent_class))->write) { - (SP_OBJECT_CLASS(box3d_parent_class))->write(object, xml_doc, repr, flags); - } + SPGroup::write(xml_doc, repr, flags); return repr; } -static gchar * -box3d_description(SPItem *item) -{ - g_return_val_if_fail(SP_IS_BOX3D(item), NULL); +gchar* SPBox3D::description() { + SPBox3D* item = this; - return g_strdup(_("<b>3D Box</b>")); + g_return_val_if_fail(SP_IS_BOX3D(item), NULL); + return g_strdup(_("<b>3D Box</b>")); } void box3d_position_set(SPBox3D *box) @@ -303,10 +273,9 @@ void box3d_position_set(SPBox3D *box) } } -static Geom::Affine -box3d_set_transform(SPItem *item, Geom::Affine const &xform) -{ - SPBox3D *box = SP_BOX3D(item); +Geom::Affine SPBox3D::set_transform(Geom::Affine const &xform) { + SPBox3D* item = this; + SPBox3D *box = item; // We don't apply the transform to the box directly but instead to its perspective (which is // done in sp_selection_apply_affine). Here we only adjust strokes, patterns, etc. @@ -1365,9 +1334,10 @@ box3d_push_back_corner_pair(SPBox3D *box, std::list<std::pair<Geom::Point, Geom: box3d_get_corner_screen(box, c2, false))); } -void -box3d_convert_to_guides(SPItem *item) { - SPBox3D *box = SP_BOX3D(item); +void SPBox3D::convert_to_guides() { + SPBox3D* item = this; + SPBox3D *box = item; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (!prefs->getBool("/tools/shapes/3dbox/convertguides", true)) { diff --git a/src/box3d.h b/src/box3d.h index 320edadf4..18d99d60a 100644 --- a/src/box3d.h +++ b/src/box3d.h @@ -21,16 +21,17 @@ #include "axis-manip.h" #define SP_TYPE_BOX3D (box3d_get_type ()) -#define SP_BOX3D(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_BOX3D, SPBox3D)) -#define SP_BOX3D_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_BOX3D, Box3DClass)) -#define SP_IS_BOX3D(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_BOX3D)) -#define SP_IS_BOX3D_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_BOX3D)) +#define SP_BOX3D(obj) (dynamic_cast<SPBox3D*>((SPObject*)obj)) +#define SP_IS_BOX3D(obj) (dynamic_cast<const SPBox3D*>((SPObject*)obj) != NULL) -struct Persp3D; +class Persp3D; class Persp3DReference; class SPBox3D : public SPGroup { public: + SPBox3D(); + virtual ~SPBox3D(); + gint z_orders[6]; // z_orders[i] holds the ID of the face at position #i in the group (from top to bottom) gchar *persp_href; @@ -50,14 +51,17 @@ public: * Create a SPBox3D and append it to the parent. */ static SPBox3D * createBox3D(SPItem * parent); -}; -class SPBox3DClass { -public: - SPGroupClass parent_class; -}; + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void release(); + virtual void set(unsigned int key, gchar const* value); + virtual void update(SPCtx *ctx, guint flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); -GType box3d_get_type (void); + virtual gchar *description(); + virtual Geom::Affine set_transform(Geom::Affine const &transform); + virtual void convert_to_guides(); +}; void box3d_position_set (SPBox3D *box); Proj::Pt3 box3d_get_proj_corner (SPBox3D const *box, guint id); diff --git a/src/cms-system.h b/src/cms-system.h index ecaba956e..c528deb94 100644 --- a/src/cms-system.h +++ b/src/cms-system.h @@ -15,7 +15,7 @@ class SPDocument; namespace Inkscape { -struct ColorProfile; +class ColorProfile; class CMSSystem { public: diff --git a/src/color-profile.cpp b/src/color-profile.cpp index 01e6d7062..e8a6a9c98 100644 --- a/src/color-profile.cpp +++ b/src/color-profile.cpp @@ -50,7 +50,6 @@ #include <glibmm/convert.h> using Inkscape::ColorProfile; -using Inkscape::ColorProfileClass; using Inkscape::ColorProfileImpl; namespace @@ -103,8 +102,6 @@ extern guint update_in_progress; #define DEBUG_MESSAGE(key, ...) #endif // DEBUG_LCMS -static SPObjectClass *cprof_parent_class; - namespace Inkscape { class ColorProfileImpl { @@ -182,99 +179,65 @@ cmsHPROFILE ColorProfileImpl::getNULLProfile() { #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -/** - * Register ColorProfile class and return its type. - */ -GType Inkscape::colorprofile_get_type() -{ - return ColorProfile::getType(); -} - -GType ColorProfile::getType() -{ - static GType type = 0; - if (!type) { - GTypeInfo info = { - sizeof(ColorProfileClass), - NULL, NULL, - (GClassInitFunc) ColorProfile::classInit, - NULL, NULL, - sizeof(ColorProfile), - 16, - (GInstanceInitFunc) ColorProfile::init, - NULL, /* value_table */ - }; - type = g_type_register_static( SP_TYPE_OBJECT, "ColorProfile", &info, static_cast<GTypeFlags>(0) ); - } - return type; -} -/** - * ColorProfile vtable initialization. - */ -void ColorProfile::classInit( ColorProfileClass *klass ) -{ - SPObjectClass *sp_object_class = reinterpret_cast<SPObjectClass *>(klass); +#include "sp-factory.h" - cprof_parent_class = static_cast<SPObjectClass*>(g_type_class_ref(SP_TYPE_OBJECT)); +namespace { + SPObject* createColorProfile() { + return new Inkscape::ColorProfile(); + } - sp_object_class->release = ColorProfile::release; - sp_object_class->build = ColorProfile::build; - sp_object_class->set = ColorProfile::set; - sp_object_class->write = ColorProfile::write; + bool rectRegistered = SPFactory::instance().registerObject("svg:color-profile", createColorProfile); } -/** - * Callback for ColorProfile object initialization. - */ -void ColorProfile::init( ColorProfile *cprof ) -{ - cprof->impl = new ColorProfileImpl(); +ColorProfile::ColorProfile() : SPObject() { + this->impl = new ColorProfileImpl(); - cprof->href = 0; - cprof->local = 0; - cprof->name = 0; - cprof->intentStr = 0; - cprof->rendering_intent = Inkscape::RENDERING_INTENT_UNKNOWN; + this->href = 0; + this->local = 0; + this->name = 0; + this->intentStr = 0; + this->rendering_intent = Inkscape::RENDERING_INTENT_UNKNOWN; +} + +ColorProfile::~ColorProfile() { } /** * Callback: free object */ -void ColorProfile::release( SPObject *object ) -{ +void ColorProfile::release() { // Unregister ourselves - if ( object->document ) { - object->document->removeResource("iccprofile", object); + if ( this->document ) { + this->document->removeResource("iccprofile", this); } - ColorProfile *cprof = COLORPROFILE(object); - if ( cprof->href ) { - g_free( cprof->href ); - cprof->href = 0; + if ( this->href ) { + g_free( this->href ); + this->href = 0; } - if ( cprof->local ) { - g_free( cprof->local ); - cprof->local = 0; + if ( this->local ) { + g_free( this->local ); + this->local = 0; } - if ( cprof->name ) { - g_free( cprof->name ); - cprof->name = 0; + if ( this->name ) { + g_free( this->name ); + this->name = 0; } - if ( cprof->intentStr ) { - g_free( cprof->intentStr ); - cprof->intentStr = 0; + if ( this->intentStr ) { + g_free( this->intentStr ); + this->intentStr = 0; } #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - cprof->impl->_clearProfile(); + this->impl->_clearProfile(); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - delete cprof->impl; - cprof->impl = 0; + delete this->impl; + this->impl = 0; } #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) @@ -304,44 +267,39 @@ void ColorProfileImpl::_clearProfile() /** * Callback: set attributes from associated repr. */ -void ColorProfile::build( SPObject *object, SPDocument *document, Inkscape::XML::Node *repr ) -{ - ColorProfile *cprof = COLORPROFILE(object); - g_assert(cprof->href == 0); - g_assert(cprof->local == 0); - g_assert(cprof->name == 0); - g_assert(cprof->intentStr == 0); - - if (cprof_parent_class->build) { - (* cprof_parent_class->build)(object, document, repr); - } - object->readAttr( "xlink:href" ); - object->readAttr( "local" ); - object->readAttr( "name" ); - object->readAttr( "rendering-intent" ); +void ColorProfile::build(SPDocument *document, Inkscape::XML::Node *repr) { + g_assert(this->href == 0); + g_assert(this->local == 0); + g_assert(this->name == 0); + g_assert(this->intentStr == 0); + + SPObject::build(document, repr); + + this->readAttr( "xlink:href" ); + this->readAttr( "local" ); + this->readAttr( "name" ); + this->readAttr( "rendering-intent" ); // Register if ( document ) { - document->addResource( "iccprofile", object ); + document->addResource( "iccprofile", this ); } } + /** * Callback: set attribute. */ -void ColorProfile::set( SPObject *object, unsigned key, gchar const *value ) -{ - ColorProfile *cprof = COLORPROFILE(object); - +void ColorProfile::set(unsigned key, gchar const *value) { switch (key) { case SP_ATTR_XLINK_HREF: - if ( cprof->href ) { - g_free( cprof->href ); - cprof->href = 0; + if ( this->href ) { + g_free( this->href ); + this->href = 0; } if ( value ) { - cprof->href = g_strdup( value ); - if ( *cprof->href ) { + this->href = g_strdup( value ); + if ( *this->href ) { #if HAVE_LIBLCMS1 cmsErrorAction( LCMS_ERROR_SHOW ); #endif @@ -352,10 +310,10 @@ void ColorProfile::set( SPObject *object, unsigned key, gchar const *value ) //LCMSAPI cmsHPROFILE LCMSEXPORT cmsOpenProfileFromMem(LPVOID MemPtr, cmsUInt32Number dwSize); // Try to open relative - SPDocument *doc = object->document; + SPDocument *doc = this->document; if (!doc) { doc = SP_ACTIVE_DOCUMENT; - g_warning("object has no document. using active"); + g_warning("this has no document. using active"); } //# 1. Get complete URI of document gchar const *docbase = doc->getURI(); @@ -365,7 +323,7 @@ void ColorProfile::set( SPObject *object, unsigned key, gchar const *value ) docbase = ""; } - gchar* escaped = g_uri_escape_string(cprof->href, "!*'();:@=+$,/?#[]", TRUE); + gchar* escaped = g_uri_escape_string(this->href, "!*'();:@=+$,/?#[]", TRUE); //g_message("docbase:%s\n", docbase); org::w3c::dom::URI docUri(docbase); @@ -375,108 +333,100 @@ void ColorProfile::set( SPObject *object, unsigned key, gchar const *value ) // the w3c specs. All absolute and relative issues are considered org::w3c::dom::URI cprofUri = docUri.resolve(hrefUri); gchar* fullname = g_uri_unescape_string(cprofUri.getNativePath().c_str(), ""); - cprof->impl->_clearProfile(); - cprof->impl->_profHandle = cmsOpenProfileFromFile( fullname, "r" ); - if ( cprof->impl->_profHandle ) { - cprof->impl->_profileSpace = cmsGetColorSpace( cprof->impl->_profHandle ); - cprof->impl->_profileClass = cmsGetDeviceClass( cprof->impl->_profHandle ); + this->impl->_clearProfile(); + this->impl->_profHandle = cmsOpenProfileFromFile( fullname, "r" ); + if ( this->impl->_profHandle ) { + this->impl->_profileSpace = cmsGetColorSpace( this->impl->_profHandle ); + this->impl->_profileClass = cmsGetDeviceClass( this->impl->_profHandle ); } - DEBUG_MESSAGE( lcmsOne, "cmsOpenProfileFromFile( '%s'...) = %p", fullname, (void*)cprof->impl->_profHandle ); + DEBUG_MESSAGE( lcmsOne, "cmsOpenProfileFromFile( '%s'...) = %p", fullname, (void*)this->impl->_profHandle ); g_free(escaped); escaped = 0; g_free(fullname); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) } } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_LOCAL: - if ( cprof->local ) { - g_free( cprof->local ); - cprof->local = 0; + if ( this->local ) { + g_free( this->local ); + this->local = 0; } - cprof->local = g_strdup( value ); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->local = g_strdup( value ); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_NAME: - if ( cprof->name ) { - g_free( cprof->name ); - cprof->name = 0; + if ( this->name ) { + g_free( this->name ); + this->name = 0; } - cprof->name = g_strdup( value ); - DEBUG_MESSAGE( lcmsTwo, "<color-profile> name set to '%s'", cprof->name ); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->name = g_strdup( value ); + DEBUG_MESSAGE( lcmsTwo, "<color-profile> name set to '%s'", this->name ); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_RENDERING_INTENT: - if ( cprof->intentStr ) { - g_free( cprof->intentStr ); - cprof->intentStr = 0; + if ( this->intentStr ) { + g_free( this->intentStr ); + this->intentStr = 0; } - cprof->intentStr = g_strdup( value ); + this->intentStr = g_strdup( value ); if ( value ) { if ( strcmp( value, "auto" ) == 0 ) { - cprof->rendering_intent = RENDERING_INTENT_AUTO; + this->rendering_intent = RENDERING_INTENT_AUTO; } else if ( strcmp( value, "perceptual" ) == 0 ) { - cprof->rendering_intent = RENDERING_INTENT_PERCEPTUAL; + this->rendering_intent = RENDERING_INTENT_PERCEPTUAL; } else if ( strcmp( value, "relative-colorimetric" ) == 0 ) { - cprof->rendering_intent = RENDERING_INTENT_RELATIVE_COLORIMETRIC; + this->rendering_intent = RENDERING_INTENT_RELATIVE_COLORIMETRIC; } else if ( strcmp( value, "saturation" ) == 0 ) { - cprof->rendering_intent = RENDERING_INTENT_SATURATION; + this->rendering_intent = RENDERING_INTENT_SATURATION; } else if ( strcmp( value, "absolute-colorimetric" ) == 0 ) { - cprof->rendering_intent = RENDERING_INTENT_ABSOLUTE_COLORIMETRIC; + this->rendering_intent = RENDERING_INTENT_ABSOLUTE_COLORIMETRIC; } else { - cprof->rendering_intent = RENDERING_INTENT_UNKNOWN; + this->rendering_intent = RENDERING_INTENT_UNKNOWN; } } else { - cprof->rendering_intent = RENDERING_INTENT_UNKNOWN; + this->rendering_intent = RENDERING_INTENT_UNKNOWN; } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; default: - if (cprof_parent_class->set) { - (* cprof_parent_class->set)(object, key, value); - } + SPObject::set(key, value); break; } - } /** * Callback: write attributes to associated repr. */ -Inkscape::XML::Node* ColorProfile::write( SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags ) -{ - ColorProfile *cprof = COLORPROFILE(object); - +Inkscape::XML::Node* ColorProfile::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:color-profile"); } - if ( (flags & SP_OBJECT_WRITE_ALL) || cprof->href ) { - repr->setAttribute( "xlink:href", cprof->href ); + if ( (flags & SP_OBJECT_WRITE_ALL) || this->href ) { + repr->setAttribute( "xlink:href", this->href ); } - if ( (flags & SP_OBJECT_WRITE_ALL) || cprof->local ) { - repr->setAttribute( "local", cprof->local ); + if ( (flags & SP_OBJECT_WRITE_ALL) || this->local ) { + repr->setAttribute( "local", this->local ); } - if ( (flags & SP_OBJECT_WRITE_ALL) || cprof->name ) { - repr->setAttribute( "name", cprof->name ); + if ( (flags & SP_OBJECT_WRITE_ALL) || this->name ) { + repr->setAttribute( "name", this->name ); } - if ( (flags & SP_OBJECT_WRITE_ALL) || cprof->intentStr ) { - repr->setAttribute( "rendering-intent", cprof->intentStr ); + if ( (flags & SP_OBJECT_WRITE_ALL) || this->intentStr ) { + repr->setAttribute( "rendering-intent", this->intentStr ); } - if (cprof_parent_class->write) { - (* cprof_parent_class->write)(object, xml_doc, repr, flags); - } + SPObject::write(xml_doc, repr, flags); return repr; } diff --git a/src/color-profile.h b/src/color-profile.h index 184481ce8..2da757b91 100644 --- a/src/color-profile.h +++ b/src/color-profile.h @@ -24,22 +24,16 @@ class ColorProfileImpl; /** - * The SPColorProfile vtable. - */ -struct ColorProfileClass { - SPObjectClass parent_class; -}; - -/** * Color Profile. */ -struct ColorProfile : public SPObject { +class ColorProfile : public SPObject { +public: + ColorProfile(); + virtual ~ColorProfile(); + friend cmsHPROFILE colorprofile_get_handle( SPDocument*, guint*, gchar const* ); friend class CMSSystem; - static GType getType(); - static void classInit( ColorProfileClass *klass ); - static std::vector<Glib::ustring> getBaseProfileDirs(); static std::vector<Glib::ustring> getProfileFiles(); static std::vector<std::pair<Glib::ustring, Glib::ustring> > getProfileFilesWithNames(); @@ -61,26 +55,22 @@ struct ColorProfile : public SPObject { gchar* intentStr; guint rendering_intent; -private: - static void init( ColorProfile *cprof ); +protected: + ColorProfileImpl *impl; - static void release( SPObject *object ); - static void build( SPObject *object, SPDocument *document, Inkscape::XML::Node *repr ); - static void set( SPObject *object, unsigned key, gchar const *value ); - static Inkscape::XML::Node *write( SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags ); + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); - ColorProfileImpl *impl; -}; + virtual void set(unsigned int key, const gchar* value); -GType colorprofile_get_type(); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); +}; } // namespace Inkscape -#define COLORPROFILE_TYPE (Inkscape::colorprofile_get_type()) -#define COLORPROFILE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), COLORPROFILE_TYPE, Inkscape::ColorProfile)) -#define COLORPROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), COLORPROFILE_TYPE, Inkscape::ColorProfileClass)) -#define IS_COLORPROFILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), COLORPROFILE_TYPE)) -#define IS_COLORPROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), COLORPROFILE_TYPE)) +//#define COLORPROFILE_TYPE (Inkscape::colorprofile_get_type()) +#define COLORPROFILE(obj) ((Inkscape::ColorProfile*)obj) +#define IS_COLORPROFILE(obj) (dynamic_cast<const Inkscape::ColorProfile*>((SPObject*)obj)) #endif // !SEEN_COLOR_PROFILE_H diff --git a/src/common-context.cpp b/src/common-context.cpp index ff99b5c0b..fb984cbf1 100644 --- a/src/common-context.cpp +++ b/src/common-context.cpp @@ -9,6 +9,7 @@ #include "streq.h" #include "preferences.h" #include "display/sp-canvas-item.h" +#include "desktop.h" #define MIN_PRESSURE 0.0 #define MAX_PRESSURE 1.0 @@ -18,166 +19,136 @@ #define DRAG_DEFAULT 1.0 #define DRAG_MAX 1.0 +SPCommonContext::SPCommonContext() : SPEventContext() { + this->tremor = 0; + this->usetilt = 0; + this->is_drawing = false; + this->xtilt = 0; + this->ytilt = 0; + this->usepressure = 0; -static void sp_common_context_dispose(GObject *object); - -static void sp_common_context_setup(SPEventContext *ec); -static void sp_common_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val); - -static gint sp_common_context_root_handler(SPEventContext *event_context, GdkEvent *event); - -G_DEFINE_TYPE(SPCommonContext, sp_common_context, SP_TYPE_EVENT_CONTEXT); - -static void sp_common_context_class_init(SPCommonContextClass *klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - SPEventContextClass *event_context_class = SP_EVENT_CONTEXT_CLASS(klass); - - object_class->dispose = sp_common_context_dispose; - - event_context_class->setup = sp_common_context_setup; - event_context_class->set = sp_common_context_set; - event_context_class->root_handler = sp_common_context_root_handler; -} - -static void sp_common_context_init(SPCommonContext *ctx) -{ // ctx->cursor_shape = cursor_eraser_xpm; // ctx->hot_x = 4; // ctx->hot_y = 4; - ctx->accumulated = 0; - ctx->segments = 0; - ctx->currentcurve = 0; - ctx->currentshape = 0; - ctx->npoints = 0; - ctx->cal1 = 0; - ctx->cal2 = 0; - ctx->repr = 0; + this->accumulated = 0; + this->segments = 0; + this->currentcurve = 0; + this->currentshape = 0; + this->npoints = 0; + this->cal1 = 0; + this->cal2 = 0; + this->repr = 0; /* Common values */ - ctx->cur = Geom::Point(0,0); - ctx->last = Geom::Point(0,0); - ctx->vel = Geom::Point(0,0); - ctx->vel_max = 0; - ctx->acc = Geom::Point(0,0); - ctx->ang = Geom::Point(0,0); - ctx->del = Geom::Point(0,0); + this->cur = Geom::Point(0,0); + this->last = Geom::Point(0,0); + this->vel = Geom::Point(0,0); + this->vel_max = 0; + this->acc = Geom::Point(0,0); + this->ang = Geom::Point(0,0); + this->del = Geom::Point(0,0); /* attributes */ - ctx->dragging = FALSE; + this->dragging = FALSE; - ctx->mass = 0.3; - ctx->drag = DRAG_DEFAULT; - ctx->angle = 30.0; - ctx->width = 0.2; - ctx->pressure = DEFAULT_PRESSURE; + this->mass = 0.3; + this->drag = DRAG_DEFAULT; + this->angle = 30.0; + this->width = 0.2; + this->pressure = DEFAULT_PRESSURE; - ctx->vel_thin = 0.1; - ctx->flatness = 0.9; - ctx->cap_rounding = 0.0; + this->vel_thin = 0.1; + this->flatness = 0.9; + this->cap_rounding = 0.0; - ctx->abs_width = false; + this->abs_width = false; } -static void sp_common_context_dispose(GObject *object) -{ - SPCommonContext *ctx = SP_COMMON_CONTEXT(object); - - if (ctx->accumulated) { - ctx->accumulated = ctx->accumulated->unref(); - ctx->accumulated = 0; +SPCommonContext::~SPCommonContext() { + if (this->accumulated) { + this->accumulated = this->accumulated->unref(); + this->accumulated = 0; } - while (ctx->segments) { - sp_canvas_item_destroy(SP_CANVAS_ITEM(ctx->segments->data)); - ctx->segments = g_slist_remove(ctx->segments, ctx->segments->data); + while (this->segments) { + sp_canvas_item_destroy(SP_CANVAS_ITEM(this->segments->data)); + this->segments = g_slist_remove(this->segments, this->segments->data); } - if (ctx->currentcurve) { - ctx->currentcurve = ctx->currentcurve->unref(); - ctx->currentcurve = 0; - } - if (ctx->cal1) { - ctx->cal1 = ctx->cal1->unref(); - ctx->cal1 = 0; - } - if (ctx->cal2) { - ctx->cal2 = ctx->cal2->unref(); - ctx->cal2 = 0; + if (this->currentcurve) { + this->currentcurve = this->currentcurve->unref(); + this->currentcurve = 0; } - if (ctx->currentshape) { - sp_canvas_item_destroy(ctx->currentshape); - ctx->currentshape = 0; + if (this->cal1) { + this->cal1 = this->cal1->unref(); + this->cal1 = 0; } - if (ctx->_message_context) { - delete ctx->_message_context; - ctx->_message_context = 0; + if (this->cal2) { + this->cal2 = this->cal2->unref(); + this->cal2 = 0; } - G_OBJECT_CLASS(sp_common_context_parent_class)->dispose(object); -} - - -static void sp_common_context_setup(SPEventContext *ec) -{ - if ( SP_EVENT_CONTEXT_CLASS(sp_common_context_parent_class)->setup ) { - SP_EVENT_CONTEXT_CLASS(sp_common_context_parent_class)->setup(ec); + if (this->currentshape) { + sp_canvas_item_destroy(this->currentshape); + this->currentshape = 0; } } -static void sp_common_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *value) -{ - SPCommonContext *ctx = SP_COMMON_CONTEXT(ec); - Glib::ustring path = value->getEntryName(); +void SPCommonContext::set(const Inkscape::Preferences::Entry& value) { + Glib::ustring path = value.getEntryName(); // ignore preset modifications - static Glib::ustring const presets_path = ec->pref_observer->observed_path + "/preset"; - Glib::ustring const &full_path = value->getPath(); - if (full_path.compare(0, presets_path.size(), presets_path) == 0) return; + static Glib::ustring const presets_path = this->pref_observer->observed_path + "/preset"; + Glib::ustring const &full_path = value.getPath(); + + if (full_path.compare(0, presets_path.size(), presets_path) == 0) { + return; + } if (path == "mass") { - ctx->mass = 0.01 * CLAMP(value->getInt(10), 0, 100); + this->mass = 0.01 * CLAMP(value.getInt(10), 0, 100); } else if (path == "wiggle") { - ctx->drag = CLAMP((1 - 0.01 * value->getInt()), - DRAG_MIN, DRAG_MAX); // drag is inverse to wiggle + this->drag = CLAMP((1 - 0.01 * value.getInt()), DRAG_MIN, DRAG_MAX); // drag is inverse to wiggle } else if (path == "angle") { - ctx->angle = CLAMP(value->getDouble(), -90, 90); + this->angle = CLAMP(value.getDouble(), -90, 90); } else if (path == "width") { - ctx->width = 0.01 * CLAMP(value->getInt(10), 1, 100); + this->width = 0.01 * CLAMP(value.getInt(10), 1, 100); } else if (path == "thinning") { - ctx->vel_thin = 0.01 * CLAMP(value->getInt(10), -100, 100); + this->vel_thin = 0.01 * CLAMP(value.getInt(10), -100, 100); } else if (path == "tremor") { - ctx->tremor = 0.01 * CLAMP(value->getInt(), 0, 100); + this->tremor = 0.01 * CLAMP(value.getInt(), 0, 100); } else if (path == "flatness") { - ctx->flatness = 0.01 * CLAMP(value->getInt(), 0, 100); + this->flatness = 0.01 * CLAMP(value.getInt(), 0, 100); } else if (path == "usepressure") { - ctx->usepressure = value->getBool(); + this->usepressure = value.getBool(); } else if (path == "usetilt") { - ctx->usetilt = value->getBool(); + this->usetilt = value.getBool(); } else if (path == "abs_width") { - ctx->abs_width = value->getBool(); + this->abs_width = value.getBool(); } else if (path == "cap_rounding") { - ctx->cap_rounding = value->getDouble(); + this->cap_rounding = value.getDouble(); } } -static gint sp_common_context_root_handler(SPEventContext *event_context, GdkEvent *event) -{ - gint ret = FALSE; +/* Get normalized point */ +Geom::Point SPCommonContext::getNormalizedPoint(Geom::Point v) const { + Geom::Rect drect = this->desktop->get_display_area(); + + double const max = MAX ( drect.dimensions()[Geom::X], drect.dimensions()[Geom::Y] ); - // TODO add common hanlding + return Geom::Point(( v[Geom::X] - drect.min()[Geom::X] ) / max, ( v[Geom::Y] - drect.min()[Geom::Y] ) / max); +} +/* Get view point */ +Geom::Point SPCommonContext::getViewPoint(Geom::Point n) const { + Geom::Rect drect = this->desktop->get_display_area(); - if ( !ret ) { - if ( SP_EVENT_CONTEXT_CLASS(sp_common_context_parent_class)->root_handler ) { - ret = SP_EVENT_CONTEXT_CLASS(sp_common_context_parent_class)->root_handler(event_context, event); - } - } + double const max = MAX ( drect.dimensions()[Geom::X], drect.dimensions()[Geom::Y] ); - return ret; + return Geom::Point(n[Geom::X] * max + drect.min()[Geom::X], n[Geom::Y] * max + drect.min()[Geom::Y]); } /* diff --git a/src/common-context.h b/src/common-context.h index 8903be391..dc4c82251 100644 --- a/src/common-context.h +++ b/src/common-context.h @@ -23,15 +23,16 @@ #include "display/curve.h" #include <2geom/point.h> -#define SP_TYPE_COMMON_CONTEXT (sp_common_context_get_type()) -#define SP_COMMON_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_COMMON_CONTEXT, SPCommonContext)) -#define SP_COMMON_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_COMMON_CONTEXT, SPCommonContextClass)) -#define SP_IS_COMMON_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_COMMON_CONTEXT)) -#define SP_IS_COMMON_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_COMMON_CONTEXT)) - #define SAMPLING_SIZE 8 /* fixme: ?? */ -struct SPCommonContext : public SPEventContext { +class SPCommonContext : public SPEventContext { +public: + SPCommonContext(); + virtual ~SPCommonContext(); + + virtual void set(const Inkscape::Preferences::Entry& val); + +protected: /** accumulated shape which ultimately goes in svg:path */ SPCurve *accumulated; @@ -88,17 +89,16 @@ struct SPCommonContext : public SPEventContext { double tremor; double cap_rounding; - Inkscape::MessageContext *_message_context; + //Inkscape::MessageContext *_message_context; bool is_drawing; /** uses absolute width independent of zoom */ bool abs_width; -}; - -struct SPCommonContextClass : public SPEventContextClass{}; -GType sp_common_context_get_type(void); + Geom::Point getViewPoint(Geom::Point n) const; + Geom::Point getNormalizedPoint(Geom::Point v) const; +}; #endif // COMMON_CONTEXT_H_SEEN diff --git a/src/conn-avoid-ref.cpp b/src/conn-avoid-ref.cpp index 15a8392c4..c0d05e3c4 100644 --- a/src/conn-avoid-ref.cpp +++ b/src/conn-avoid-ref.cpp @@ -260,7 +260,7 @@ static std::vector<Geom::Point> approxItemWithPoints(SPItem const *item, const G } else if (SP_IS_SHAPE(item)) { - SP_SHAPE(item)->setShape(); + SP_SHAPE(item)->set_shape(); SPCurve* item_curve = SP_SHAPE(item)->getCurve(); // make sure it has an associated curve if (item_curve) diff --git a/src/connector-context.cpp b/src/connector-context.cpp index 9468894a0..c79c58125 100644 --- a/src/connector-context.cpp +++ b/src/connector-context.cpp @@ -109,14 +109,6 @@ using Inkscape::DocumentUndo; -static void sp_connector_context_dispose(GObject *object); - -static void sp_connector_context_setup(SPEventContext *ec); -static void sp_connector_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val); -static void sp_connector_context_finish(SPEventContext *ec); -static gint sp_connector_context_root_handler(SPEventContext *ec, GdkEvent *event); -static gint sp_connector_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event); - // Stuff borrowed from DrawContext static void spcc_connector_set_initial_point(SPConnectorContext *cc, Geom::Point const p); static void spcc_connector_set_subsequent_point(SPConnectorContext *cc, Geom::Point const p); @@ -142,7 +134,6 @@ static bool conn_pt_handle_test(SPConnectorContext *cc, Geom::Point& p, gchar ** static void cc_select_handle(SPKnot* knot); static void cc_deselect_handle(SPKnot* knot); static bool cc_item_is_shape(SPItem *item); -static void cc_selection_changed(Inkscape::Selection *selection, gpointer data); static void cc_connector_rerouting_finish(SPConnectorContext *const cc, Geom::Point *const p); @@ -171,184 +162,165 @@ static Inkscape::XML::NodeEventVector layer_repr_events = { NULL /* order_changed */ }; -G_DEFINE_TYPE(SPConnectorContext, sp_connector_context, SP_TYPE_EVENT_CONTEXT); -static void -sp_connector_context_class_init(SPConnectorContextClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - SPEventContextClass *event_context_class = SP_EVENT_CONTEXT_CLASS(klass); +#include "tool-factory.h" - object_class->dispose = sp_connector_context_dispose; +namespace { + SPEventContext* createConnectorContext() { + return new SPConnectorContext(); + } - event_context_class->setup = sp_connector_context_setup; - event_context_class->set = sp_connector_context_set; - event_context_class->finish = sp_connector_context_finish; - event_context_class->root_handler = sp_connector_context_root_handler; - event_context_class->item_handler = sp_connector_context_item_handler; + bool connectorContextRegistered = ToolFactory::instance().registerObject("/tools/connector", createConnectorContext); } +const std::string& SPConnectorContext::getPrefsPath() { + return SPConnectorContext::prefsPath; +} -static void -sp_connector_context_init(SPConnectorContext *cc) -{ - SPEventContext *ec = SP_EVENT_CONTEXT(cc); +const std::string SPConnectorContext::prefsPath = "/tools/connector"; - ec->cursor_shape = cursor_connector_xpm; - ec->hot_x = 1; - ec->hot_y = 1; - ec->xp = 0; - ec->yp = 0; +SPConnectorContext::SPConnectorContext() : SPEventContext() { + this->red_curve = 0; + this->isOrthogonal = false; + this->c1 = 0; + this->red_bpath = 0; + this->green_curve = 0; + this->selection = 0; + this->cl0 = 0; + this->cl1 = 0; + this->c0 = 0; - cc->red_color = 0xff00007f; + this->cursor_shape = cursor_connector_xpm; + this->hot_x = 1; + this->hot_y = 1; + this->xp = 0; + this->yp = 0; - cc->newconn = NULL; - cc->newConnRef = NULL; - cc->curvature = 0.0; + this->red_color = 0xff00007f; - cc->sel_changed_connection = sigc::connection(); + this->newconn = NULL; + this->newConnRef = NULL; + this->curvature = 0.0; - cc->active_shape = NULL; - cc->active_shape_repr = NULL; - cc->active_shape_layer_repr = NULL; + this->sel_changed_connection = sigc::connection(); - cc->active_conn = NULL; - cc->active_conn_repr = NULL; + this->active_shape = NULL; + this->active_shape_repr = NULL; + this->active_shape_layer_repr = NULL; - cc->active_handle = NULL; + this->active_conn = NULL; + this->active_conn_repr = NULL; - cc->selected_handle = NULL; + this->active_handle = NULL; - cc->clickeditem = NULL; - cc->clickedhandle = NULL; + this->selected_handle = NULL; - new (&cc->knots) SPKnotList(); + this->clickeditem = NULL; + this->clickedhandle = NULL; for (int i = 0; i < 2; ++i) { - cc->endpt_handle[i] = NULL; - cc->endpt_handler_id[i] = 0; + this->endpt_handle[i] = NULL; + this->endpt_handler_id[i] = 0; } - cc->shref = NULL; - cc->ehref = NULL; - cc->npoints = 0; - cc->state = SP_CONNECTOR_CONTEXT_IDLE; + + this->shref = NULL; + this->ehref = NULL; + this->npoints = 0; + this->state = SP_CONNECTOR_CONTEXT_IDLE; } - -static void -sp_connector_context_dispose(GObject *object) -{ - SPConnectorContext *cc = SP_CONNECTOR_CONTEXT(object); - - cc->sel_changed_connection.disconnect(); +SPConnectorContext::~SPConnectorContext() { + this->sel_changed_connection.disconnect(); for (int i = 0; i < 2; ++i) { - if (cc->endpt_handle[1]) { - g_object_unref(cc->endpt_handle[i]); - cc->endpt_handle[i] = NULL; + if (this->endpt_handle[1]) { + g_object_unref(this->endpt_handle[i]); + this->endpt_handle[i] = NULL; } } - if (cc->shref) { - g_free(cc->shref); - cc->shref = NULL; + + if (this->shref) { + g_free(this->shref); + this->shref = NULL; } - if (cc->ehref) { - g_free(cc->shref); - cc->shref = NULL; + + if (this->ehref) { + g_free(this->shref); + this->shref = NULL; } - g_assert( cc->newConnRef == NULL ); - - G_OBJECT_CLASS(sp_connector_context_parent_class)->dispose(object); + + g_assert( this->newConnRef == NULL ); } +void SPConnectorContext::setup() { + SPEventContext::setup(); -static void -sp_connector_context_setup(SPEventContext *ec) -{ - SPConnectorContext *cc = SP_CONNECTOR_CONTEXT(ec); - SPDesktop *dt = ec->desktop; + this->selection = sp_desktop_selection(this->desktop); - if ((SP_EVENT_CONTEXT_CLASS(sp_connector_context_parent_class))->setup) { - (SP_EVENT_CONTEXT_CLASS(sp_connector_context_parent_class))->setup(ec); - } - - cc->selection = sp_desktop_selection(dt); - - cc->sel_changed_connection.disconnect(); - cc->sel_changed_connection = cc->selection->connectChanged( - sigc::bind(sigc::ptr_fun(&cc_selection_changed), - (gpointer) cc)); + this->sel_changed_connection.disconnect(); + this->sel_changed_connection = this->selection->connectChanged( + sigc::mem_fun(this, &SPConnectorContext::selection_changed) + ); /* Create red bpath */ - cc->red_bpath = sp_canvas_bpath_new(sp_desktop_sketch(ec->desktop), NULL); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(cc->red_bpath), cc->red_color, + this->red_bpath = sp_canvas_bpath_new(sp_desktop_sketch(this->desktop), NULL); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->red_bpath), this->red_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(cc->red_bpath), 0x00000000, + sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(this->red_bpath), 0x00000000, SP_WIND_RULE_NONZERO); /* Create red curve */ - cc->red_curve = new SPCurve(); + this->red_curve = new SPCurve(); /* Create green curve */ - cc->green_curve = new SPCurve(); + this->green_curve = new SPCurve(); // Notice the initial selection. - cc_selection_changed(cc->selection, (gpointer) cc); + //cc_selection_changed(this->selection, (gpointer) this); + this->selection_changed(this->selection); - cc->within_tolerance = false; + this->within_tolerance = false; - sp_event_context_read(ec, "curvature"); - sp_event_context_read(ec, "orthogonal"); + sp_event_context_read(this, "curvature"); + sp_event_context_read(this, "orthogonal"); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/tools/connector/selcue", 0)) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } // Make sure we see all enter events for canvas items, // even if a mouse button is depressed. - dt->canvas->gen_all_enter_events = true; + this->desktop->canvas->gen_all_enter_events = true; } - -static void -sp_connector_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val) -{ - SPConnectorContext *cc = SP_CONNECTOR_CONTEXT(ec); - +void SPConnectorContext::set(const Inkscape::Preferences::Entry& val) { /* fixme: Proper error handling for non-numeric data. Use a locale-independent function like * g_ascii_strtod (or a thin wrapper that does the right thing for invalid values inf/nan). */ - Glib::ustring name = val->getEntryName(); - if ( name == "curvature" ) { - cc->curvature = val->getDoubleLimited(); // prevents NaN and +/-Inf from messing up - } - else if ( name == "orthogonal" ) { - cc->isOrthogonal = val->getBool(); + Glib::ustring name = val.getEntryName(); + + if (name == "curvature") { + this->curvature = val.getDoubleLimited(); // prevents NaN and +/-Inf from messing up + } else if (name == "orthogonal") { + this->isOrthogonal = val.getBool(); } } -static void -sp_connector_context_finish(SPEventContext *ec) -{ - SPConnectorContext *cc = SP_CONNECTOR_CONTEXT(ec); +void SPConnectorContext::finish() { + spcc_connector_finish(this); + this->state = SP_CONNECTOR_CONTEXT_IDLE; - spcc_connector_finish(cc); - cc->state = SP_CONNECTOR_CONTEXT_IDLE; + SPEventContext::finish(); - if ((SP_EVENT_CONTEXT_CLASS(sp_connector_context_parent_class))->finish) { - (SP_EVENT_CONTEXT_CLASS(sp_connector_context_parent_class))->finish(ec); + if (this->selection) { + this->selection = NULL; } - if (cc->selection) { - cc->selection = NULL; - } - cc_clear_active_shape(cc); - cc_clear_active_conn(cc); + cc_clear_active_shape(this); + cc_clear_active_conn(this); // Restore the default event generating behaviour. - SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(ec); - desktop->canvas->gen_all_enter_events = false; + this->desktop->canvas->gen_all_enter_events = false; } - //----------------------------------------------------------------------------- @@ -445,59 +417,54 @@ cc_deselect_handle(SPKnot* knot) sp_knot_update_ctrl(knot); } -static gint -sp_connector_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event) -{ +bool SPConnectorContext::item_handler(SPItem* item, GdkEvent* event) { gint ret = FALSE; - SPDesktop *desktop = event_context->desktop; - - SPConnectorContext *cc = SP_CONNECTOR_CONTEXT(event_context); - Geom::Point p(event->button.x, event->button.y); switch (event->type) { case GDK_BUTTON_RELEASE: - if (event->button.button == 1 && !event_context->space_panning) { - if ((cc->state == SP_CONNECTOR_CONTEXT_DRAGGING) && - (event_context->within_tolerance)) - { - spcc_reset_colors(cc); - cc->state = SP_CONNECTOR_CONTEXT_IDLE; + if (event->button.button == 1 && !this->space_panning) { + if ((this->state == SP_CONNECTOR_CONTEXT_DRAGGING) && this->within_tolerance) { + spcc_reset_colors(this); + this->state = SP_CONNECTOR_CONTEXT_IDLE; } - if (cc->state != SP_CONNECTOR_CONTEXT_IDLE) { + + if (this->state != SP_CONNECTOR_CONTEXT_IDLE) { // Doing something else like rerouting. break; } + // find out clicked item, honoring Alt - SPItem *item = sp_event_context_find_item(desktop, - p, event->button.state & GDK_MOD1_MASK, FALSE); + SPItem *item = sp_event_context_find_item(desktop, p, event->button.state & GDK_MOD1_MASK, FALSE); if (event->button.state & GDK_SHIFT_MASK) { - cc->selection->toggle(item); + this->selection->toggle(item); } else { - cc->selection->set(item); + this->selection->set(item); /* When selecting a new item, do not allow showing connection points on connectors. (yet?) */ - if ( item != cc->active_shape && !cc_item_is_connector( item ) ) - cc_set_active_shape( cc, item ); + + if (item != this->active_shape && !cc_item_is_connector(item)) { + cc_set_active_shape(this, item); + } } - ret = TRUE; + ret = TRUE; } break; + case GDK_ENTER_NOTIFY: - { - if (!cc->selected_handle) - { + if (!this->selected_handle) { if (cc_item_is_shape(item)) { - cc_set_active_shape(cc, item); + cc_set_active_shape(this, item); } + ret = TRUE; } break; - } + default: break; } @@ -505,28 +472,24 @@ sp_connector_context_item_handler(SPEventContext *event_context, SPItem *item, G return ret; } - -gint -sp_connector_context_root_handler(SPEventContext *ec, GdkEvent *event) -{ - SPConnectorContext *const cc = SP_CONNECTOR_CONTEXT(ec); - +bool SPConnectorContext::root_handler(GdkEvent* event) { gint ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: - ret = connector_handle_button_press(cc, event->button); + ret = connector_handle_button_press(this, event->button); break; case GDK_MOTION_NOTIFY: - ret = connector_handle_motion_notify(cc, event->motion); + ret = connector_handle_motion_notify(this, event->motion); break; case GDK_BUTTON_RELEASE: - ret = connector_handle_button_release(cc, event->button); + ret = connector_handle_button_release(this, event->button); break; + case GDK_KEY_PRESS: - ret = connector_handle_key_press(cc, get_group0_keyval (&event->key)); + ret = connector_handle_key_press(this, get_group0_keyval (&event->key)); break; default: @@ -534,11 +497,7 @@ sp_connector_context_root_handler(SPEventContext *ec, GdkEvent *event) } if (!ret) { - gint (*const parent_root_handler)(SPEventContext *, GdkEvent *) - = (SP_EVENT_CONTEXT_CLASS(sp_connector_context_parent_class))->root_handler; - if (parent_root_handler) { - ret = parent_root_handler(ec, event); - } + ret = SPEventContext::root_handler(event); } return ret; @@ -559,7 +518,7 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(cc); - if (Inkscape::have_viable_layer(desktop, cc->_message_context) == false) { + if (Inkscape::have_viable_layer(desktop, cc->message_context) == false) { return TRUE; } @@ -1137,7 +1096,7 @@ cc_generic_knot_handler(SPCanvasItem *, GdkEvent *event, SPKnot *knot) static gboolean endpt_handler(SPKnot */*knot*/, GdkEvent *event, SPConnectorContext *cc) { - g_assert( SP_IS_CONNECTOR_CONTEXT(cc) ); + //g_assert( SP_IS_CONNECTOR_CONTEXT(cc) ); gboolean consumed = FALSE; @@ -1458,32 +1417,24 @@ void cc_selection_set_avoid(bool const set_avoid) DocumentUndo::done(document, SP_VERB_CONTEXT_CONNECTOR, event_desc); } - -static void -cc_selection_changed(Inkscape::Selection *selection, gpointer data) -{ - SPConnectorContext *cc = SP_CONNECTOR_CONTEXT(data); - //SPEventContext *ec = SP_EVENT_CONTEXT(cc); - +void SPConnectorContext::selection_changed(Inkscape::Selection *selection) { SPItem *item = selection->singleItem(); - if (cc->active_conn == item) - { + if (this->active_conn == item) { // Nothing to change. return; } - if (item == NULL) - { - cc_clear_active_conn(cc); + + if (item == NULL) { + cc_clear_active_conn(this); return; } if (cc_item_is_connector(item)) { - cc_set_active_conn(cc, item); + cc_set_active_conn(this, item); } } - static void shape_event_attr_deleted(Inkscape::XML::Node */*repr*/, Inkscape::XML::Node *child, Inkscape::XML::Node */*ref*/, gpointer data) diff --git a/src/connector-context.h b/src/connector-context.h index 597feac38..1c4bfc34d 100644 --- a/src/connector-context.h +++ b/src/connector-context.h @@ -20,11 +20,8 @@ #include "libavoid/connector.h" #include <glibmm/i18n.h> -#define SP_TYPE_CONNECTOR_CONTEXT (sp_connector_context_get_type()) -#define SP_CONNECTOR_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_CONNECTOR_CONTEXT, SPConnectorContext)) -#define SP_CONNECTOR_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_CONNECTOR_CONTEXT, SPConnectorContextClass)) -#define SP_IS_CONNECTOR_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_CONNECTOR_CONTEXT)) -#define SP_IS_CONNECTOR_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_CONNECTOR_CONTEXT)) +#define SP_CONNECTOR_CONTEXT(obj) (dynamic_cast<SPConnectorContext*>((SPEventContext*)obj)) +//#define SP_IS_CONNECTOR_CONTEXT(obj) (dynamic_cast<const SPConnectorContext*>((const SPEventContext*)obj) != NULL) struct SPKnot; class SPCurve; @@ -45,7 +42,11 @@ enum { typedef std::map<SPKnot *, int> SPKnotList; -struct SPConnectorContext : public SPEventContext { +class SPConnectorContext : public SPEventContext { +public: + SPConnectorContext(); + virtual ~SPConnectorContext(); + Inkscape::Selection *selection; Geom::Point p[5]; @@ -92,11 +93,20 @@ struct SPConnectorContext : public SPEventContext { gchar *shref; gchar *ehref; SPCanvasItem *c0, *c1, *cl0, *cl1; -}; -struct SPConnectorContextClass : public SPEventContextClass { }; + static const std::string prefsPath; + + virtual void setup(); + virtual void finish(); + virtual void set(const Inkscape::Preferences::Entry& val); + virtual bool root_handler(GdkEvent* event); + virtual bool item_handler(SPItem* item, GdkEvent* event); -GType sp_connector_context_get_type(); + virtual const std::string& getPrefsPath(); + +private: + void selection_changed(Inkscape::Selection *selection); +}; void cc_selection_set_avoid(bool const set_ignore); void cc_create_connection_point(SPConnectorContext* cc); diff --git a/src/context-fns.h b/src/context-fns.h index 12d6e6194..43a45e4c7 100644 --- a/src/context-fns.h +++ b/src/context-fns.h @@ -16,7 +16,7 @@ class SPDesktop; class SPItem; -struct SPEventContext; +class SPEventContext; const double goldenratio = 1.61803398874989484820; // golden ratio diff --git a/src/desktop-handles.cpp b/src/desktop-handles.cpp index f7ffbed70..ebfa22c3e 100644 --- a/src/desktop-handles.cpp +++ b/src/desktop-handles.cpp @@ -15,13 +15,13 @@ #include "desktop.h" #include "desktop-handles.h" -SPEventContext * -sp_desktop_event_context (SPDesktop const * desktop) -{ - g_return_val_if_fail (desktop != NULL, NULL); - - return desktop->event_context; -} +//SPEventContext * +//sp_desktop_event_context (SPDesktop const * desktop) +//{ +// g_return_val_if_fail (desktop != NULL, NULL); +// +// return desktop->event_context; +//} Inkscape::Selection * sp_desktop_selection (SPDesktop const * desktop) diff --git a/src/desktop-handles.h b/src/desktop-handles.h index cca929369..9413f075b 100644 --- a/src/desktop-handles.h +++ b/src/desktop-handles.h @@ -16,8 +16,8 @@ class SPDesktop; class SPDocument; -struct SPEventContext; -struct SPNamedView; +class SPEventContext; +class SPNamedView; struct SPCanvas; struct SPCanvasGroup; struct SPCanvasItem; @@ -34,7 +34,7 @@ namespace Inkscape { #define SP_COORDINATES_UNDERLINE_X (1 << Geom::X) #define SP_COORDINATES_UNDERLINE_Y (1 << Geom::Y) -SPEventContext * sp_desktop_event_context (SPDesktop const * desktop); +//SPEventContext * sp_desktop_event_context (SPDesktop const * desktop); Inkscape::Selection * sp_desktop_selection (SPDesktop const * desktop); SPDocument * sp_desktop_document (SPDesktop const * desktop); SPCanvas * sp_desktop_canvas (SPDesktop const * desktop); diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index c632f9033..f8fad9711 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -200,7 +200,7 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write if (!intercepted) { // If we have an event context, update its cursor (TODO: it could be neater to do this with the signal sent above, but what if the signal gets intercepted?) if (desktop->event_context) { - sp_event_context_update_cursor(desktop->event_context); + desktop->event_context->sp_event_context_update_cursor(); } // Remove text attributes if not text... diff --git a/src/desktop.cpp b/src/desktop.cpp index 13e339abe..69d83d8da 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -235,7 +235,9 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas, Inkscape::UI::View::EditWid * call "set" instead of "push". Can we assume that there is only one * context ever? */ - push_event_context (SP_TYPE_SELECT_CONTEXT, "/tools/select", SP_EVENT_CONTEXT_STATIC); + //push_event_context (SP_TYPE_SELECT_CONTEXT, "/tools/select", SP_EVENT_CONTEXT_STATIC); + //set_event_context(SP_TYPE_SELECT_CONTEXT, "/tools/select"); + set_event_context2("/tools/select"); // display rect and zoom are now handled in sp_desktop_widget_realize() @@ -359,11 +361,18 @@ void SPDesktop::destroy() g_signal_handlers_disconnect_by_func(G_OBJECT (main), (gpointer) G_CALLBACK(sp_desktop_root_handler), this); g_signal_handlers_disconnect_by_func(G_OBJECT (drawing), (gpointer) G_CALLBACK(_arena_handler), this); - while (event_context) { - SPEventContext *ec = event_context; - event_context = ec->next; - sp_event_context_finish (ec); - g_object_unref (G_OBJECT (ec)); +// while (event_context) { +// SPEventContext *ec = event_context; +// event_context = ec->next; +// sp_event_context_finish (ec); +// g_object_unref (G_OBJECT (ec)); +// } + //sp_event_context_finish(event_context); + event_context->finish(); + //g_object_unref(G_OBJECT(event_context)); + if (event_context) { + delete event_context; + event_context = 0; } delete layers; @@ -391,6 +400,65 @@ SPDesktop::~SPDesktop() { } + +SPEventContext* SPDesktop::getEventContext() const { + return event_context; +} + +Inkscape::Selection* SPDesktop::getSelection() const { + return selection; +} + +SPDocument* SPDesktop::getDocument() const { + return doc(); +} + +SPCanvas* SPDesktop::getCanvas() const { + return SP_CANVAS_ITEM(main)->canvas; +} + +SPCanvasItem* SPDesktop::getAcetate() const { + return acetate; +} + +SPCanvasGroup* SPDesktop::getMain() const { + return main; +} + +SPCanvasGroup* SPDesktop::getGridGroup() const { + return gridgroup; +} + +SPCanvasGroup* SPDesktop::getGuides() const { + return guides; +} + +SPCanvasItem* SPDesktop::getDrawing() const { + return drawing; +} + +SPCanvasGroup* SPDesktop::getSketch() const { + return sketch; +} + +SPCanvasGroup* SPDesktop::getControls() const { + return controls; +} + +SPCanvasGroup* SPDesktop::getTempGroup() const { + return tempgroup; +} + +Inkscape::MessageStack* SPDesktop::getMessageStack() const { + return messageStack(); +} + +SPNamedView* SPDesktop::getNamedView() const { + return namedview; +} + + + //-------------------------------------------------------------------- /* Public methods */ @@ -600,62 +668,89 @@ SPDesktop::change_document (SPDocument *theDocument) _document_replaced_signal.emit (this, theDocument); } + +#include "tool-factory.h" + +void SPDesktop::set_event_context2(const std::string& toolName) { + SPEventContext* ec_old = event_context; + + if (ec_old) { + ec_old->deactivate(); + } + + SPEventContext* ec_new = ToolFactory::instance().createObject(toolName); + ec_new->desktop = this; + ec_new->message_context = new Inkscape::MessageContext(this->messageStack()); + ec_new->setup(); + + event_context = ec_new; + + if (ec_old) { + ec_old->finish(); + delete ec_old; + } + + sp_event_context_activate(event_context); + + _event_context_changed_signal.emit(this, event_context); +} + /** * Make desktop switch event contexts. */ -void -SPDesktop::set_event_context (GType type, const gchar *config) -{ - SPEventContext *ec; - while (event_context) { - ec = event_context; - sp_event_context_deactivate (ec); - // we have to keep event_context valid during destruction - otherwise writing - // destructors is next to impossible - SPEventContext *next = ec->next; - sp_event_context_finish (ec); - g_object_unref (G_OBJECT (ec)); - event_context = next; - } - - // The event_context will be null. This means that it will be impossible - // to process any event invoked by the lines below. See for example bug - // LP #622350. Cutting and undoing again in the node tool resets the event - // context to the node tool. In this bug the line bellow invokes GDK_LEAVE_NOTIFY - // events which cannot be handled and must be discarded. - ec = sp_event_context_new (type, this, config, SP_EVENT_CONTEXT_STATIC); - ec->next = event_context; - event_context = ec; - // Now the event_context has been set again and we can process all events again - sp_event_context_activate (ec); - _event_context_changed_signal.emit (this, ec); -} +//void +//SPDesktop::set_event_context (GType type, const gchar *config) +//{ +// //SPEventContext *ec; +// //while (event_context) { +// //ec = event_context; +// sp_event_context_deactivate (event_context); +// // we have to keep event_context valid during destruction - otherwise writing +// // destructors is next to impossible +// // SPEventContext *next = ec->next; +// sp_event_context_finish (event_context); +// g_object_unref (G_OBJECT (event_context)); +// // event_context = next; +// //} +// +// // The event_context will be null. This means that it will be impossible +// // to process any event invoked by the lines below. See for example bug +// // LP #622350. Cutting and undoing again in the node tool resets the event +// // context to the node tool. In this bug the line bellow invokes GDK_LEAVE_NOTIFY +// // events which cannot be handled and must be discarded. +// event_context = sp_event_context_new (type, this, config, SP_EVENT_CONTEXT_STATIC); +// // ec->next = event_context; +// //event_context = ec; +// // Now the event_context has been set again and we can process all events again +// sp_event_context_activate (event_context); +// _event_context_changed_signal.emit (this, event_context); +//} /** * Push event context onto desktop's context stack. */ -void -SPDesktop::push_event_context (GType type, const gchar *config, unsigned int key) -{ - SPEventContext *ref, *ec; - - if (event_context && event_context->key == key) return; - ref = event_context; - while (ref && ref->next && ref->next->key != key) ref = ref->next; - if (ref && ref->next) { - ec = ref->next; - ref->next = ec->next; - sp_event_context_finish (ec); - g_object_unref (G_OBJECT (ec)); - } - - if (event_context) sp_event_context_deactivate (event_context); - ec = sp_event_context_new (type, this, config, key); - ec->next = event_context; - event_context = ec; - sp_event_context_activate (ec); - _event_context_changed_signal.emit (this, ec); -} +//void +//SPDesktop::push_event_context (GType type, const gchar *config, unsigned int key) +//{ +// SPEventContext *ref, *ec; +// +// if (event_context && event_context->key == key) return; +// ref = event_context; +// while (ref && ref->next && ref->next->key != key) ref = ref->next; +// if (ref && ref->next) { +// ec = ref->next; +// ref->next = ec->next; +// sp_event_context_finish (ec); +// g_object_unref (G_OBJECT (ec)); +// } +// +// if (event_context) sp_event_context_deactivate (event_context); +// ec = sp_event_context_new (type, this, config, key); +// ec->next = event_context; +// event_context = ec; +// sp_event_context_activate (ec); +// _event_context_changed_signal.emit (this, ec); +//} /** * Sets the coordinate status to a given point @@ -786,7 +881,10 @@ SPDesktop::set_display_area (double x0, double y0, double x1, double y1, double canvas->scrollTo(x0 * newscale - border, y1 * -newscale - border, clear); /* update perspective lines if we are in the 3D box tool (so that infinite ones are shown correctly) */ - sp_box3d_context_update_lines(event_context); + //sp_box3d_context_update_lines(event_context); + if (SP_IS_BOX3D_CONTEXT(event_context)) { + SP_BOX3D_CONTEXT(event_context)->_vpdrag->updateLines(); + } _widget->updateRulers(); _widget->updateScrollbars(_d2w.descrim()); @@ -1107,7 +1205,10 @@ SPDesktop::scroll_world (double dx, double dy, bool is_scrolling) canvas->scrollTo(viewbox.min()[Geom::X] - dx, viewbox.min()[Geom::Y] - dy, FALSE, is_scrolling); /* update perspective lines if we are in the 3D box tool (so that infinite ones are shown correctly) */ - sp_box3d_context_update_lines(event_context); + //sp_box3d_context_update_lines(event_context); + if (SP_IS_BOX3D_CONTEXT(event_context)) { + SP_BOX3D_CONTEXT(event_context)->_vpdrag->updateLines(); + } _widget->updateRulers(); _widget->updateScrollbars(_d2w.descrim()); @@ -1407,10 +1508,10 @@ void SPDesktop::setWaitingCursor() waiting_cursor = true; } -void SPDesktop::clearWaitingCursor() -{ - if (waiting_cursor) - sp_event_context_update_cursor(sp_desktop_event_context(this)); +void SPDesktop::clearWaitingCursor() { + if (waiting_cursor) { + this->event_context->sp_event_context_update_cursor(); + } } void SPDesktop::toggleColorProfAdjust() @@ -1822,6 +1923,7 @@ SPDesktop::show_dialogs() mapVerbPreference.insert(std::make_pair ((int)SP_VERB_DIALOG_DISPLAY, "/dialogs/preferences") ); mapVerbPreference.insert(std::make_pair ((int)SP_VERB_SELECTION_GRIDTILE, "/dialogs/gridtiler") ); mapVerbPreference.insert(std::make_pair ((int)SP_VERB_SELECTION_TRACE, "/dialogs/trace") ); + mapVerbPreference.insert(std::make_pair ((int)SP_VERB_SELECTION_PIXEL_ART, "/dialogs/pixelart") ); mapVerbPreference.insert(std::make_pair ((int)SP_VERB_DIALOG_TEXT, "/dialogs/textandfont") ); mapVerbPreference.insert(std::make_pair ((int)SP_VERB_DIALOG_EXPORT, "/dialogs/export") ); mapVerbPreference.insert(std::make_pair ((int)SP_VERB_DIALOG_XML_EDITOR, "/dialogs/xml") ); diff --git a/src/desktop.h b/src/desktop.h index 9a3c609d0..938c2153a 100644 --- a/src/desktop.h +++ b/src/desktop.h @@ -41,9 +41,9 @@ class SPCSSAttr; struct SPCanvas; struct SPCanvasItem; struct SPCanvasGroup; -struct SPEventContext; +class SPEventContext; class SPItem; -struct SPNamedView; +class SPNamedView; class SPObject; struct SPStyle; typedef struct _DocumentInterface DocumentInterface;//struct DocumentInterface; @@ -135,6 +135,21 @@ public: Inkscape::Display::TemporaryItemList *temporary_item_list; Inkscape::Display::SnapIndicator *snapindicator; + SPEventContext* getEventContext() const; + Inkscape::Selection* getSelection() const; + SPDocument* getDocument() const; + SPCanvas* getCanvas() const; + SPCanvasItem* getAcetate() const; + SPCanvasGroup* getMain() const; + SPCanvasGroup* getGridGroup() const; + SPCanvasGroup* getGuides() const; + SPCanvasItem* getDrawing() const; + SPCanvasGroup* getSketch() const; + SPCanvasGroup* getControls() const; + SPCanvasGroup* getTempGroup() const; + Inkscape::MessageStack* getMessageStack() const; + SPNamedView* getNamedView() const; + SPCanvasItem *acetate; SPCanvasGroup *main; SPCanvasGroup *gridgroup; @@ -279,8 +294,11 @@ public: void activate_guides (bool activate); void change_document (SPDocument *document); - void set_event_context (GType type, const gchar *config); - void push_event_context (GType type, const gchar *config, unsigned int key); + + void set_event_context2(const std::string& toolName); + + //void set_event_context (GType type, const gchar *config); + //void push_event_context (GType type, const gchar *config, unsigned int key); void set_coordinate_status (Geom::Point p); SPItem *getItemFromListAtPointBottom(const GSList *list, Geom::Point const p) const; diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 755553033..451f0b509 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -15,6 +15,8 @@ #include "display/cairo-utils.h" #include <stdexcept> +#include <glib/gstdio.h> +#include <glibmm/fileutils.h> #include <2geom/pathvector.h> #include <2geom/bezier-curve.h> #include <2geom/hvlinesegment.h> @@ -28,6 +30,8 @@ #include "helper/geom-curves.h" #include "display/cairo-templates.h" +static void ink_cairo_pixbuf_cleanup(guchar *, void *); + /** * Key for cairo_surface_t to keep track of current color interpolation value * Only the address of the structure is used, it is never initialized. See: @@ -116,6 +120,380 @@ Cairo::RefPtr<CairoContext> CairoContext::create(Cairo::RefPtr<Cairo::Surface> c return ret; } + +/* The class below implement the following hack: + * + * The pixels formats of Cairo and GdkPixbuf are different. + * GdkPixbuf accesses pixels as bytes, alpha is not premultiplied, + * and successive bytes of a single pixel contain R, G, B and A components. + * Cairo accesses pixels as 32-bit ints, alpha is premultiplied, + * and each int contains as 0xAARRGGBB, accessed with bitwise operations. + * + * In other words, on a little endian system, a GdkPixbuf will contain: + * char *data = "rgbargbargba...." + * int *data = { 0xAABBGGRR, 0xAABBGGRR, 0xAABBGGRR, ... } + * while a Cairo image surface will contain: + * char *data = "bgrabgrabgra...." + * int *data = { 0xAARRGGBB, 0xAARRGGBB, 0xAARRGGBB, ... } + * + * It is possible to convert between these two formats (almost) losslessly. + * Some color information from partially transparent regions of the image + * is lost, but the result when displaying this image will remain the same. + * + * The class allows interoperation between GdkPixbuf + * and Cairo surfaces without creating a copy of the image. + * This is implemented by creating a GdkPixbuf and a Cairo image surface + * which share their data. Depending on what is needed at a given time, + * the pixels are converted in place to the Cairo or the GdkPixbuf format. + */ + +/** Create a pixbuf from a Cairo surface. + * The constructor takes ownership of the passed surface, + * so it should not be destroyed. */ +Pixbuf::Pixbuf(cairo_surface_t *s) + : _pixbuf(gdk_pixbuf_new_from_data( + cairo_image_surface_get_data(s), GDK_COLORSPACE_RGB, TRUE, 8, + cairo_image_surface_get_width(s), cairo_image_surface_get_height(s), + cairo_image_surface_get_stride(s), NULL, NULL)) + , _surface(s) + , _mod_time(0) + , _pixel_format(PF_CAIRO) + , _cairo_store(true) +{} + +/** Create a pixbuf from a GdkPixbuf. + * The constructor takes ownership of the passed GdkPixbuf reference, + * so it should not be unrefed. */ +Pixbuf::Pixbuf(GdkPixbuf *pb) + : _pixbuf(pb) + , _surface(0) + , _mod_time(0) + , _pixel_format(PF_GDK) + , _cairo_store(false) +{ + _forceAlpha(); + _surface = cairo_image_surface_create_for_data( + gdk_pixbuf_get_pixels(_pixbuf), CAIRO_FORMAT_ARGB32, + gdk_pixbuf_get_width(_pixbuf), gdk_pixbuf_get_height(_pixbuf), gdk_pixbuf_get_rowstride(_pixbuf)); +} + +Pixbuf::Pixbuf(Inkscape::Pixbuf const &other) + : _pixbuf(gdk_pixbuf_copy(other._pixbuf)) + , _surface(cairo_image_surface_create_for_data( + gdk_pixbuf_get_pixels(_pixbuf), CAIRO_FORMAT_ARGB32, + gdk_pixbuf_get_width(_pixbuf), gdk_pixbuf_get_height(_pixbuf), gdk_pixbuf_get_rowstride(_pixbuf))) + , _mod_time(other._mod_time) + , _path(other._path) + , _pixel_format(other._pixel_format) + , _cairo_store(false) +{} + +Pixbuf::~Pixbuf() +{ + if (_cairo_store) { + g_object_unref(_pixbuf); + cairo_surface_destroy(_surface); + } else { + cairo_surface_destroy(_surface); + g_object_unref(_pixbuf); + } +} + +Pixbuf *Pixbuf::create_from_data_uri(gchar const *uri_data) +{ + Pixbuf *pixbuf = NULL; + + bool data_is_image = false; + bool data_is_base64 = false; + + gchar const *data = uri_data; + + while (*data) { + if (strncmp(data,"base64",6) == 0) { + /* base64-encoding */ + data_is_base64 = true; + data_is_image = true; // Illustrator produces embedded images without MIME type, so we assume it's image no matter what + data += 6; + } + else if (strncmp(data,"image/png",9) == 0) { + /* PNG image */ + data_is_image = true; + data += 9; + } + else if (strncmp(data,"image/jpg",9) == 0) { + /* JPEG image */ + data_is_image = true; + data += 9; + } + else if (strncmp(data,"image/jpeg",10) == 0) { + /* JPEG image */ + data_is_image = true; + data += 10; + } + else if (strncmp(data,"image/jp2",9) == 0) { + /* JPEG2000 image */ + data_is_image = true; + data += 9; + } + else { /* unrecognized option; skip it */ + while (*data) { + if (((*data) == ';') || ((*data) == ',')) { + break; + } + data++; + } + } + if ((*data) == ';') { + data++; + continue; + } + if ((*data) == ',') { + data++; + break; + } + } + + if ((*data) && data_is_image && data_is_base64) { + GdkPixbuf *buf = NULL; + GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); + + if (!loader) return NULL; + + gsize decoded_len = 0; + guchar *decoded = g_base64_decode(data, &decoded_len); + + if (gdk_pixbuf_loader_write(loader, decoded, decoded_len, NULL)) { + gdk_pixbuf_loader_close(loader, NULL); + buf = gdk_pixbuf_loader_get_pixbuf(loader); + if (buf) { + g_object_ref(buf); + pixbuf = new Pixbuf(buf); + + GdkPixbufFormat *fmt = gdk_pixbuf_loader_get_format(loader); + gchar *fmt_name = gdk_pixbuf_format_get_name(fmt); + pixbuf->_setMimeData(decoded, decoded_len, fmt_name); + g_free(fmt_name); + } else { + g_free(decoded); + } + } else { + g_free(decoded); + } + g_object_unref(loader); + } + + return pixbuf; +} + +Pixbuf *Pixbuf::create_from_file(std::string const &fn) +{ + Pixbuf *pb = NULL; + // test correctness of filename + if (!g_file_test(fn.c_str(), G_FILE_TEST_EXISTS)) { + return NULL; + } + struct stat stdir; + int val = g_stat(fn.c_str(), &stdir); + if (val == 0 && stdir.st_mode & S_IFDIR){ + return NULL; + } + + // we need to load the entire file into memory, + // since we'll store it as MIME data + gchar *data = NULL; + gsize len = 0; + GError *error; + + if (g_file_get_contents(fn.c_str(), &data, &len, &error)) { + + GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); + gdk_pixbuf_loader_write(loader, (guchar *) data, len, NULL); + gdk_pixbuf_loader_close(loader, NULL); + + GdkPixbuf *buf = gdk_pixbuf_loader_get_pixbuf(loader); + if (buf) { + g_object_ref(buf); + pb = new Pixbuf(buf); + pb->_mod_time = stdir.st_mtime; + pb->_path = fn; + + GdkPixbufFormat *fmt = gdk_pixbuf_loader_get_format(loader); + gchar *fmt_name = gdk_pixbuf_format_get_name(fmt); + pb->_setMimeData((guchar *) data, len, fmt_name); + g_free(fmt_name); + } else { + g_free(data); + } + g_object_unref(loader); + + // TODO: we could also read DPI, ICC profile, gamma correction, and other information + // from the file. This can be done by using format-specific libraries e.g. libpng. + } else { + return NULL; + } + + return pb; +} + +/** + * Converts the pixbuf to GdkPixbuf pixel format. + * The returned pixbuf can be used e.g. in calls to gdk_pixbuf_save(). + */ +GdkPixbuf *Pixbuf::getPixbufRaw(bool convert_format) +{ + if (convert_format) { + ensurePixelFormat(PF_GDK); + } + return _pixbuf; +} + +/** + * Converts the pixbuf to Cairo pixel format and returns an image surface + * which can be used as a source. + * + * The returned surface is owned by the GdkPixbuf and should not be freed. + * Calling this function causes the pixbuf to be unsuitable for use + * with GTK drawing functions until ensurePixelFormat(Pixbuf::PIXEL_FORMAT_PIXBUF) is called. + */ +cairo_surface_t *Pixbuf::getSurfaceRaw(bool convert_format) +{ + if (convert_format) { + ensurePixelFormat(PF_CAIRO); + } + return _surface; +} + +/* Declaring this function in the header requires including <gdkmm/pixbuf.h>, + * which stupidly includes <glibmm.h> which in turn pulls in <glibmm/threads.h>. + * However, since glib 2.32, <glibmm/threads.h> has to be included before <glib.h> + * when compiling with G_DISABLE_DEPRECATED, as we do in non-release builds. + * This necessitates spamming a lot of files with #include <glibmm/threads.h> + * at the top. + * + * Since we don't really use gdkmm, do not define this function for now. */ + +/* +Glib::RefPtr<Gdk::Pixbuf> Pixbuf::getPixbuf(bool convert_format = true) +{ + g_object_ref(_pixbuf); + Glib::RefPtr<Gdk::Pixbuf> p(getPixbuf(convert_format)); + return p; +} +*/ + +Cairo::RefPtr<Cairo::Surface> Pixbuf::getSurface(bool convert_format) +{ + Cairo::RefPtr<Cairo::Surface> p(new Cairo::Surface(getSurfaceRaw(convert_format), false)); + return p; +} + +/** Retrieves the original compressed data for the surface, if any. + * The returned data belongs to the object and should not be freed. */ +guchar const *Pixbuf::getMimeData(gsize &len, std::string &mimetype) const +{ + static gchar const *mimetypes[] = { + CAIRO_MIME_TYPE_JPEG, CAIRO_MIME_TYPE_JP2, CAIRO_MIME_TYPE_PNG, NULL }; + static guint mimetypes_len = g_strv_length(const_cast<gchar**>(mimetypes)); + + guchar const *data = NULL; + + for (guint i = 0; i < mimetypes_len; ++i) { + unsigned long len_long = 0; + cairo_surface_get_mime_data(const_cast<cairo_surface_t*>(_surface), mimetypes[i], &data, &len_long); + if (data != NULL) { + len = len_long; + mimetype = mimetypes[i]; + break; + } + } + + return data; +} + +int Pixbuf::width() const { + return gdk_pixbuf_get_width(const_cast<GdkPixbuf*>(_pixbuf)); +} +int Pixbuf::height() const { + return gdk_pixbuf_get_height(const_cast<GdkPixbuf*>(_pixbuf)); +} +int Pixbuf::rowstride() const { + return gdk_pixbuf_get_rowstride(const_cast<GdkPixbuf*>(_pixbuf)); +} +guchar const *Pixbuf::pixels() const { + return gdk_pixbuf_get_pixels(const_cast<GdkPixbuf*>(_pixbuf)); +} +guchar *Pixbuf::pixels() { + return gdk_pixbuf_get_pixels(_pixbuf); +} +void Pixbuf::markDirty() { + cairo_surface_mark_dirty(_surface); +} + +void Pixbuf::_forceAlpha() +{ + if (gdk_pixbuf_get_has_alpha(_pixbuf)) return; + + GdkPixbuf *old = _pixbuf; + _pixbuf = gdk_pixbuf_add_alpha(old, FALSE, 0, 0, 0); + g_object_unref(old); +} + +void Pixbuf::_setMimeData(guchar *data, gsize len, Glib::ustring const &format) +{ + gchar const *mimetype = NULL; + + if (format == "jpeg") { + mimetype = CAIRO_MIME_TYPE_JPEG; + } else if (format == "jpeg2000") { + mimetype = CAIRO_MIME_TYPE_JP2; + } else if (format == "png") { + mimetype = CAIRO_MIME_TYPE_PNG; + } + + if (mimetype != NULL) { + cairo_surface_set_mime_data(_surface, mimetype, data, len, g_free, data); + //g_message("Setting Cairo MIME data: %s", mimetype); + } else { + g_free(data); + //g_message("Not setting Cairo MIME data: unknown format %s", name.c_str()); + } +} + +void Pixbuf::ensurePixelFormat(PixelFormat fmt) +{ + if (_pixel_format == PF_GDK) { + if (fmt == PF_GDK) { + return; + } + if (fmt == PF_CAIRO) { + convert_pixels_pixbuf_to_argb32( + gdk_pixbuf_get_pixels(_pixbuf), + gdk_pixbuf_get_width(_pixbuf), + gdk_pixbuf_get_height(_pixbuf), + gdk_pixbuf_get_rowstride(_pixbuf)); + _pixel_format = fmt; + return; + } + g_assert_not_reached(); + } + if (_pixel_format == PF_CAIRO) { + if (fmt == PF_GDK) { + convert_pixels_argb32_to_pixbuf( + gdk_pixbuf_get_pixels(_pixbuf), + gdk_pixbuf_get_width(_pixbuf), + gdk_pixbuf_get_height(_pixbuf), + gdk_pixbuf_get_rowstride(_pixbuf)); + _pixel_format = fmt; + return; + } + if (fmt == PF_CAIRO) { + return; + } + g_assert_not_reached(); + } + g_assert_not_reached(); +} + } // namespace Inkscape /* @@ -371,129 +749,6 @@ ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m) cairo_pattern_set_matrix(cp, &cm); } -void -ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y) -{ - cairo_surface_t *pbs = ink_cairo_surface_get_for_pixbuf(pb); - cairo_set_source_surface(ct, pbs, x, y); -} - -/* The functions below implement the following hack: - * - * The pixels formats of Cairo and GdkPixbuf are different. - * GdkPixbuf accesses pixels as bytes, alpha is not premultiplied, - * and successive bytes of a single pixel contain R, G, B and A components. - * Cairo accesses pixels as 32-bit ints, alpha is premultiplied, - * and each int contains as 0xAARRGGBB, accessed with bitwise operations. - * - * In other words, on a little endian system, a GdkPixbuf will contain: - * char *data = "rgbargbargba...." - * int *data = { 0xAABBGGRR, 0xAABBGGRR, 0xAABBGGRR, ... } - * while a Cairo image surface will contain: - * char *data = "bgrabgrabgra...." - * int *data = { 0xAARRGGBB, 0xAARRGGBB, 0xAARRGGBB, ... } - * - * It is possible to convert between these two formats (almost) losslessly. - * Some color information from partially transparent regions of the image - * is lost, but the result when displaying this image will remain the same. - * - * The functions below allow interoperation between GdkPixbuf - * and Cairo surfaces, allowing pixbufs to be used as Cairo sources, - * and saving Cairo surfaces using GdkPixbuf APIs. - * This is implemented by creating a GdkPixbuf and a Cairo image surface - * which share their data. Depending on what is needed at a given time, - * the pixels are converted in place to the Cairo or the GdkPixbuf format. - * In this way, only one copy of the image data is needed. - * - * Given either a GdkPixbuf or a Cairo surface, these functions create - * the other object and convert to its format. The returned object should be - * freed using cairo_surface_destroy or g_object_unref when it's no longer - * needed. - * - * Memory ownership semantics: - * Regardless of whether the pixels are stored in memory originally belonging - * to Cairo surface or to GdkPixbuf, the GdkPixbuf is the master object. - * To free the memory, unref the GdkPixbuf ONLY. - */ - -/** - * Converts the pixbuf to Cairo pixel format and returns an image surface - * which can be used as a source. - * - * The returned surface is owned by the GdkPixbuf and should not be freed. - * Calling this function causes the pixbuf to be unsuitable for use - * with GTK drawing functions until ink_pixbuf_ensure_normal() is called. - * - * @bug You have to call g_object_set_data(G_OBJECT(pb), "cairo_surface", NULL) - * when unrefing the last reference to the pixbuf. Otherwise there will be - * crashes, because cairo_surface_destroy is called after the pixbuf data - * is already freed. - */ -cairo_surface_t * -ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb) -{ - cairo_surface_t *pbs = - reinterpret_cast<cairo_surface_t*>(g_object_get_data(G_OBJECT(pb), "cairo_surface")); - - ink_pixbuf_ensure_argb32(pb); - - if (pbs == NULL) { - guchar *data = gdk_pixbuf_get_pixels(pb); - int w = gdk_pixbuf_get_width(pb); - int h = gdk_pixbuf_get_height(pb); - int stride = gdk_pixbuf_get_rowstride(pb); - - // create a surface that stores the data - pbs = cairo_image_surface_create_for_data( - data, CAIRO_FORMAT_ARGB32, w, h, stride); - - g_object_set_data_full(G_OBJECT(pb), "cairo_surface", pbs, (GDestroyNotify) cairo_surface_destroy); - cairo_surface_set_user_data(pbs, &ink_pixbuf_key, pb, NULL); - } - - return pbs; -} - -/** - * Converts the Cairo surface to GdkPixbuf pixel format. - * GdkPixbuf takes ownership of the passed surface reference, - * so it should NOT be freed after calling this function. - */ -GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s) -{ - GdkPixbuf *pb = reinterpret_cast<GdkPixbuf*>(cairo_surface_get_user_data(s, &ink_pixbuf_key)); - if (pb == NULL) { - pb = gdk_pixbuf_new_from_data( - cairo_image_surface_get_data(s), GDK_COLORSPACE_RGB, TRUE, 8, - cairo_image_surface_get_width(s), cairo_image_surface_get_height(s), - cairo_image_surface_get_stride(s), NULL, NULL); - - g_object_set_data_full(G_OBJECT(pb), "pixel_format", g_strdup("argb32"), g_free); - g_object_set_data_full(G_OBJECT(pb), "cairo_surface", s, (GDestroyNotify) cairo_surface_destroy); - - cairo_surface_set_user_data(s, &ink_pixbuf_key, pb, NULL); - } else { - g_warning("Received surface which is already owned by GdkPixbuf"); - g_object_ref(pb); - } - - ink_pixbuf_ensure_normal(pb); - - return pb; -} - -/** - * Cleanup function for GdkPixbuf. - * This function should be passed as the GdkPixbufDestroyNotify parameter - * to gdk_pixbuf_new_from_data when creating a GdkPixbuf backed by - * a Cairo surface. - */ -void ink_cairo_pixbuf_cleanup(guchar * /*pixels*/, void *data) -{ - cairo_surface_t *surface = reinterpret_cast<cairo_surface_t*>(data); - cairo_surface_destroy(surface); -} - /** * Create an exact copy of a surface. * Creates a surface that has the same type, content type, dimensions and contents @@ -833,6 +1088,44 @@ ink_cairo_pattern_create_checkerboard() return p; } +/** + * Converts the Cairo surface to a GdkPixbuf pixel format, + * without allocating extra memory. + * + * This function is intended mainly for creating previews displayed by GTK. + * For loading images for display on the canvas, use the Inkscape::Pixbuf object. + * + * The returned GdkPixbuf takes ownership of the passed surface reference, + * so it should NOT be freed after calling this function. + */ +GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s) +{ + guchar *pixels = cairo_image_surface_get_data(s); + int w = cairo_image_surface_get_width(s); + int h = cairo_image_surface_get_height(s); + int rs = cairo_image_surface_get_stride(s); + + convert_pixels_argb32_to_pixbuf(pixels, w, h, rs); + + GdkPixbuf *pb = gdk_pixbuf_new_from_data( + pixels, GDK_COLORSPACE_RGB, TRUE, 8, + w, h, rs, ink_cairo_pixbuf_cleanup, s); + + return pb; +} + +/** + * Cleanup function for GdkPixbuf. + * This function should be passed as the GdkPixbufDestroyNotify parameter + * to gdk_pixbuf_new_from_data when creating a GdkPixbuf backed by + * a Cairo surface. + */ +static void ink_cairo_pixbuf_cleanup(guchar * /*pixels*/, void *data) +{ + cairo_surface_t *surface = static_cast<cairo_surface_t*>(data); + cairo_surface_destroy(surface); +} + /* The following two functions use "from" instead of "to", because when you write: val1 = argb32_from_pixbuf(val1); the name of the format is closer to the value in that format. */ diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h index 289d4e01f..505e2ca77 100644 --- a/src/display/cairo-utils.h +++ b/src/display/cairo-utils.h @@ -12,14 +12,15 @@ #ifndef SEEN_INKSCAPE_DISPLAY_CAIRO_UTILS_H #define SEEN_INKSCAPE_DISPLAY_CAIRO_UTILS_H +#include <boost/noncopyable.hpp> +//#include <glibmm/threads.h> // workaround #include <glib.h> #include <cairomm/cairomm.h> +//#include <gdkmm/pixbuf.h> #include <2geom/forward.h> #include "style.h" struct SPColor; -struct _GdkPixbuf; -typedef struct _GdkPixbuf GdkPixbuf; namespace Inkscape { @@ -80,15 +81,61 @@ public: static Cairo::RefPtr<CairoContext> create(Cairo::RefPtr<Cairo::Surface> const &target); }; -} // namespace Inkscape +/** Class to hold image data for raster images. + * Allows easy interoperation with GdkPixbuf and Cairo. */ +class Pixbuf { +public: + enum PixelFormat { + PF_CAIRO = 1, + PF_GDK = 2, + PF_LAST + }; + + explicit Pixbuf(cairo_surface_t *s); + explicit Pixbuf(GdkPixbuf *pb); + Pixbuf(Inkscape::Pixbuf const &other); + ~Pixbuf(); + + GdkPixbuf *getPixbufRaw(bool convert_format = true); + //Glib::RefPtr<Gdk::Pixbuf> getPixbuf(bool convert_format = true); + + cairo_surface_t *getSurfaceRaw(bool convert_format = true); + Cairo::RefPtr<Cairo::Surface> getSurface(bool convert_format = true); + + int width() const; + int height() const; + int rowstride() const; + guchar const *pixels() const; + guchar *pixels(); + void markDirty(); + + bool hasMimeData() const; + guchar const *getMimeData(gsize &len, std::string &mimetype) const; + std::string const &originalPath() const { return _path; } + time_t modificationTime() const { return _mod_time; } -enum InkPixelFormat { - INK_PIXEL_FORMAT_NONE, - INK_PIXEL_FORMAT_CAIRO, - INK_PIXEL_FORMAT_PIXBUF, - INK_PIXEL_FORMAT_LAST + PixelFormat pixelFormat() const { return _pixel_format; } + void ensurePixelFormat(PixelFormat fmt); + + static Pixbuf *create_from_data_uri(gchar const *uri); + static Pixbuf *create_from_file(std::string const &fn); + +private: + void _ensurePixelsARGB32(); + void _ensurePixelsPixbuf(); + void _forceAlpha(); + void _setMimeData(guchar *data, gsize len, Glib::ustring const &format); + + GdkPixbuf *_pixbuf; + cairo_surface_t *_surface; + time_t _mod_time; + std::string _path; + PixelFormat _pixel_format; + bool _cairo_store; }; +} // namespace Inkscape + // TODO: these declarations may not be needed in the header extern cairo_user_data_key_t ink_color_interpolation_key; extern cairo_user_data_key_t ink_pixbuf_key; @@ -102,7 +149,6 @@ void ink_cairo_set_source_color(cairo_t *ct, SPColor const &color, double opacit void ink_cairo_set_source_rgba32(cairo_t *ct, guint32 rgba); void ink_cairo_transform(cairo_t *ct, Geom::Affine const &m); void ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m); -void ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y); void ink_matrix_to_2geom(Geom::Affine &, cairo_matrix_t const &); void ink_matrix_to_cairo(cairo_matrix_t &, Geom::Affine const &); @@ -125,13 +171,9 @@ int ink_cairo_surface_linear_to_srgb(cairo_surface_t *surface); cairo_pattern_t *ink_cairo_pattern_create_checkerboard(); +GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s); void convert_pixels_pixbuf_to_argb32(guchar *data, int w, int h, int rs); void convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int rs); -void ink_pixbuf_ensure_argb32(GdkPixbuf *); -void ink_pixbuf_ensure_normal(GdkPixbuf *); -cairo_surface_t *ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb); -GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s); -void ink_cairo_pixbuf_cleanup(guchar *pixels, void *surface); G_GNUC_CONST guint32 argb32_from_pixbuf(guint32 in); G_GNUC_CONST guint32 pixbuf_from_argb32(guint32 in); diff --git a/src/display/canvas-axonomgrid.h b/src/display/canvas-axonomgrid.h index f58ea3aca..4e5af863d 100644 --- a/src/display/canvas-axonomgrid.h +++ b/src/display/canvas-axonomgrid.h @@ -14,7 +14,7 @@ struct SPCanvasBuf; class SPDesktop; -struct SPNamedView; +class SPNamedView; namespace Inkscape { namespace XML { diff --git a/src/display/canvas-grid.h b/src/display/canvas-grid.h index 70b4bf744..56ed86e94 100644 --- a/src/display/canvas-grid.h +++ b/src/display/canvas-grid.h @@ -13,7 +13,7 @@ #include "line-snapper.h" class SPDesktop; -struct SPNamedView; +class SPNamedView; struct SPCanvasBuf; class SPDocument; diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index 46f066b8e..0b661a450 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -22,34 +22,23 @@ namespace Inkscape { DrawingImage::DrawingImage(Drawing &drawing) : DrawingItem(drawing) , _pixbuf(NULL) - , _surface(NULL) // this is owned by _pixbuf! , _style(NULL) , _new_surface(NULL) {} DrawingImage::~DrawingImage() { - if (_style) + if (_style) { sp_style_unref(_style); - if (_pixbuf) { - if (_new_surface) cairo_surface_destroy(_new_surface); - g_object_unref(_pixbuf); } + + // _pixbuf is owned by SPImage - do not delete it } void -DrawingImage::setARGB32Pixbuf(GdkPixbuf *pb) +DrawingImage::setPixbuf(Inkscape::Pixbuf *pb) { - // when done in this order, it won't break if pb == image->pixbuf and the refcount is 1 - if (pb != NULL) { - g_object_ref (pb); - } - if (_pixbuf != NULL) { - g_object_unref(_pixbuf); - // unrefing the pixbuf also destroys surface - } _pixbuf = pb; - _surface = pb ? ink_cairo_surface_get_for_pixbuf(pb) : NULL; _markForUpdate(STATE_ALL, false); } @@ -86,8 +75,8 @@ DrawingImage::bounds() const { if (!_pixbuf) return _clipbox; - double pw = gdk_pixbuf_get_width(_pixbuf); - double ph = gdk_pixbuf_get_height(_pixbuf); + double pw = _pixbuf->width(); + double ph = _pixbuf->height(); double vw = pw * _scale[Geom::X]; double vh = ph * _scale[Geom::Y]; Geom::Point wh(vw, vh); @@ -143,14 +132,16 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar // See https://bugs.launchpad.net/inkscape/+bug/804162 Geom::Scale expansion(_ctm.expansion()); - int orgwidth = cairo_image_surface_get_width(_surface); - int orgheight = cairo_image_surface_get_height(_surface); + int orgwidth = _pixbuf->width(); + int orgheight = _pixbuf->height(); if (_scale[Geom::X]*expansion[Geom::X]*orgwidth*255.0<1.0 || _scale[Geom::Y]*expansion[Geom::Y]*orgheight*255.0<1.0) { // Resized image too small to actually see anything return RENDER_OK; } - + + _pixbuf->ensurePixelFormat(Inkscape::Pixbuf::PF_CAIRO); + // Split scale*expansion in a part that is <= 1.0 and a part that is >= 1.0. We only take care of the part <= 1.0. Geom::Scale scaleExpansionSmall(std::min<Geom::Coord>(fabs(_scale[Geom::X]*expansion[Geom::X]),1),std::min<Geom::Coord>(fabs(_scale[Geom::Y]*expansion[Geom::Y]),1)); Geom::Scale scaleExpansionLarge(_scale[Geom::X]*expansion[Geom::X]/scaleExpansionSmall[Geom::X],_scale[Geom::Y]*expansion[Geom::Y]/scaleExpansionSmall[Geom::Y]); @@ -161,7 +152,7 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar ct.scale(expansion.inverse()); // This should not include scale (see derivation above) ct.translate(_origin*expansion); ct.scale(scaleExpansionLarge); - ct.setSource(_surface, 0, 0); + ct.setSource(_pixbuf->getSurfaceRaw(), 0, 0); } else if (!_new_surface || (newSize-_rescaledSize).length()>0.1) { // Rescaled image is sufficiently different from cached image to recompute if (_new_surface) cairo_surface_destroy(_new_surface); @@ -200,13 +191,13 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar } } + cairo_surface_t *surface = _pixbuf->getSurfaceRaw(); _new_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, newwidth,newheight); - unsigned char * orgdata = cairo_image_surface_get_data(_surface); + unsigned char * orgdata = cairo_image_surface_get_data(surface); unsigned char * newdata = cairo_image_surface_get_data(_new_surface); - int orgstride = cairo_image_surface_get_stride(_surface); + int orgstride = cairo_image_surface_get_stride(surface); int newstride = cairo_image_surface_get_stride(_new_surface); - - //cairo_surface_flush(_surface); + cairo_surface_flush(_new_surface); for(int y=0; y<newheight; y++) { @@ -245,7 +236,7 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar // TODO: If Cairo's problems are gone, uncomment the following: //ct.translate(_origin); //ct.scale(_scale); - //ct.setSource(_surface, 0, 0); + //ct.setSource(_pixbuf->getSurfaceRaw(), 0, 0); //ct.paint(_opacity); ct.paint(); @@ -315,10 +306,10 @@ DrawingImage::_pickItem(Geom::Point const &p, double delta, unsigned /*sticky*/) return NULL; } else { - unsigned char *const pixels = gdk_pixbuf_get_pixels(_pixbuf); - int width = gdk_pixbuf_get_width(_pixbuf); - int height = gdk_pixbuf_get_height(_pixbuf); - int rowstride = gdk_pixbuf_get_rowstride(_pixbuf); + unsigned char *const pixels = _pixbuf->pixels(); + int width = _pixbuf->width(); + int height = _pixbuf->height(); + int rowstride = _pixbuf->rowstride(); Geom::Point tp = p * _ctm.inverse(); Geom::Rect r = bounds(); @@ -336,8 +327,17 @@ DrawingImage::_pickItem(Geom::Point const &p, double delta, unsigned /*sticky*/) unsigned char *pix_ptr = pixels + iy * rowstride + ix * 4; // pick if the image is less than 99% transparent - float alpha = (pix_ptr[3] / 255.0f) * _opacity; - return alpha > 0.01 ? this : NULL; + guint32 alpha = 0; + if (_pixbuf->pixelFormat() == Inkscape::Pixbuf::PF_CAIRO) { + guint32 px = *reinterpret_cast<guint32 const *>(pix_ptr); + alpha = (px & 0xff000000) >> 24; + } else if (_pixbuf->pixelFormat() == Inkscape::Pixbuf::PF_GDK) { + alpha = pix_ptr[3]; + } else { + throw std::runtime_error("Unrecognized pixel format"); + } + float alpha_f = (alpha / 255.0f) * _opacity; + return alpha_f > 0.01 ? this : NULL; } } diff --git a/src/display/drawing-image.h b/src/display/drawing-image.h index 593185c97..58e6de72e 100644 --- a/src/display/drawing-image.h +++ b/src/display/drawing-image.h @@ -19,6 +19,7 @@ #include "display/drawing-item.h" namespace Inkscape { +class Pixbuf; class DrawingImage : public DrawingItem @@ -27,7 +28,7 @@ public: DrawingImage(Drawing &drawing); ~DrawingImage(); - void setARGB32Pixbuf(GdkPixbuf *pb); + void setPixbuf(Inkscape::Pixbuf *pb); void setStyle(SPStyle *style); void setScale(double sx, double sy); void setOrigin(Geom::Point const &o); @@ -41,8 +42,7 @@ protected: DrawingItem *stop_at); virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); - GdkPixbuf *_pixbuf; - cairo_surface_t *_surface; + Inkscape::Pixbuf *_pixbuf; SPStyle *_style; cairo_surface_t *_new_surface; // Part of hack around Cairo bug diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 1814dd615..a9836a9e3 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -284,7 +284,7 @@ DrawingItem::setZOrder(unsigned z) void DrawingItem::setItemBounds(Geom::OptRect const &bounds) { - _item_bbox = bounds; + if (bounds) _filter_bbox = bounds; } /** @@ -352,7 +352,7 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne if (to_update & STATE_BBOX) { // compute drawbox - if (_filter && render_filters) { + if (_filter && render_filters && _bbox) { Geom::IntRect newbox(*_bbox); _filter->area_enlarge(newbox, this); _drawbox = Geom::OptIntRect(newbox); diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index 4a516512b..8020659db 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -89,7 +89,7 @@ public: Geom::OptIntRect geometricBounds() const { return _bbox; } Geom::OptIntRect visualBounds() const { return _drawbox; } - Geom::OptRect itemBounds() const { return _item_bbox; } + Geom::OptRect filterBounds() const { return _filter_bbox; } Geom::Affine ctm() const { return _ctm; } Geom::Affine transform() const { return _transform ? *_transform : Geom::identity(); } Drawing &drawing() const { return _drawing; } @@ -175,7 +175,7 @@ protected: Geom::Affine _ctm; ///< Total transform from item coords to display coords Geom::OptIntRect _bbox; ///< Bounding box in display (pixel) coords including stroke Geom::OptIntRect _drawbox; ///< Full visual bounding box - enlarged by filters, shrunk by clips and masks - Geom::OptRect _item_bbox; ///< Geometric bounding box in item coordinates + Geom::OptRect _filter_bbox; ///< Used by filters when settings bounds DrawingItem *_clip; DrawingItem *_mask; diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp index e80f12486..e689d0755 100644 --- a/src/display/drawing-shape.cpp +++ b/src/display/drawing-shape.cpp @@ -179,8 +179,8 @@ DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigne // update fill and stroke paints. // this cannot be done during nr_arena_shape_update, because we need a Cairo context // to render svg:pattern - has_fill = _nrstyle.prepareFill(ct, _item_bbox); - has_stroke = _nrstyle.prepareStroke(ct, _item_bbox); + has_fill = _nrstyle.prepareFill(ct, _bbox); + has_stroke = _nrstyle.prepareStroke(ct, _bbox); has_stroke &= (_nrstyle.stroke_width != 0); if (has_fill || has_stroke) { diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 55d54b770..fa9ce4ff8 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -398,8 +398,8 @@ unsigned DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &/*are using Geom::X; using Geom::Y; - has_fill = _nrstyle.prepareFill( ct, _item_bbox); - has_stroke = _nrstyle.prepareStroke(ct, _item_bbox); + has_fill = _nrstyle.prepareFill( ct, _bbox); + has_stroke = _nrstyle.prepareStroke(ct, _bbox); if (has_fill || has_stroke) { Geom::Affine rotinv; diff --git a/src/display/nr-filter-diffuselighting.h b/src/display/nr-filter-diffuselighting.h index 15cc8e1ff..043a5eb39 100644 --- a/src/display/nr-filter-diffuselighting.h +++ b/src/display/nr-filter-diffuselighting.h @@ -19,9 +19,9 @@ #include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" -struct SPFeDistantLight; -struct SPFePointLight; -struct SPFeSpotLight; +class SPFeDistantLight; +class SPFePointLight; +class SPFeSpotLight; struct SVGICCColor; namespace Inkscape { diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index b9d73f0ad..4ca4cd07c 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -30,6 +30,7 @@ FilterImage::FilterImage() : SVGElem(0) , document(0) , feImageHref(0) + , image(0) , broken_ref(false) { } @@ -41,7 +42,7 @@ FilterImage::~FilterImage() { if (feImageHref) g_free(feImageHref); - g_object_set_data(G_OBJECT(image->gobj()), "cairo_surface", NULL); + delete image; } void FilterImage::render_cairo(FilterSlot &slot) @@ -131,50 +132,38 @@ void FilterImage::render_cairo(FilterSlot &slot) // External image, like <image> if (!image && !broken_ref) { broken_ref = true; - try { - /* TODO: If feImageHref is absolute, then use that (preferably handling the - * case that it's not a file URI). Otherwise, go up the tree looking - * for an xml:base attribute, and use that as the base URI for resolving - * the relative feImageHref URI. Otherwise, if document->base is valid, - * then use that as the base URI. Otherwise, use feImageHref directly - * (i.e. interpreting it as relative to our current working directory). - * (See http://www.w3.org/TR/xmlbase/#resolution .) */ - gchar *fullname = feImageHref; - if ( !g_file_test( fullname, G_FILE_TEST_EXISTS ) ) { - // Try to load from relative postion combined with document base - if( document ) { - fullname = g_build_filename( document->getBase(), feImageHref, NULL ); - } - } - if ( !g_file_test( fullname, G_FILE_TEST_EXISTS ) ) { - // Should display Broken Image png. - g_warning("FilterImage::render: Can not find: %s", feImageHref ); - return; + + /* TODO: If feImageHref is absolute, then use that (preferably handling the + * case that it's not a file URI). Otherwise, go up the tree looking + * for an xml:base attribute, and use that as the base URI for resolving + * the relative feImageHref URI. Otherwise, if document->base is valid, + * then use that as the base URI. Otherwise, use feImageHref directly + * (i.e. interpreting it as relative to our current working directory). + * (See http://www.w3.org/TR/xmlbase/#resolution .) */ + gchar *fullname = feImageHref; + if ( !g_file_test( fullname, G_FILE_TEST_EXISTS ) ) { + // Try to load from relative postion combined with document base + if( document ) { + fullname = g_build_filename( document->getBase(), feImageHref, NULL ); } - image = Gdk::Pixbuf::create_from_file(fullname); - if( fullname != feImageHref ) g_free( fullname ); } - catch (const Glib::FileError & e) - { - g_warning("caught Glib::FileError in FilterImage::render: %s", e.what().data() ); + if ( !g_file_test( fullname, G_FILE_TEST_EXISTS ) ) { + // Should display Broken Image png. + g_warning("FilterImage::render: Can not find: %s", feImageHref ); return; } - catch (const Gdk::PixbufError & e) - { - g_warning("Gdk::PixbufError in FilterImage::render: %s", e.what().data() ); + image = Inkscape::Pixbuf::create_from_file(fullname); + if( fullname != feImageHref ) g_free( fullname ); + + if ( !image ) { + g_warning("FilterImage::render: failed to load image: %s", feImageHref); return; } - if ( !image ) return; broken_ref = false; - - bool has_alpha = image->get_has_alpha(); - if (!has_alpha) { - image = image->add_alpha(false, 0, 0, 0); - } } - cairo_surface_t *image_surface = ink_cairo_surface_get_for_pixbuf(image->gobj()); + cairo_surface_t *image_surface = image->getSurfaceRaw(); Geom::Rect sa = slot.get_slot_area(); cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, @@ -199,7 +188,7 @@ void FilterImage::render_cairo(FilterSlot &slot) // Check aspect ratio of image vs. viewport double feAspect = feImageHeight/feImageWidth; - double aspect = (double)image->get_height()/(double)image->get_width(); + double aspect = (double)image->height()/(double)image->width(); bool ratio = (feAspect < aspect); double ax, ay; // Align side @@ -274,8 +263,8 @@ void FilterImage::render_cairo(FilterSlot &slot) } } - double scaleX = feImageWidth / image->get_width(); - double scaleY = feImageHeight / image->get_height(); + double scaleX = feImageWidth / image->width(); + double scaleY = feImageHeight / image->height(); cairo_translate(ct, feImageX, feImageY); cairo_scale(ct, scaleX, scaleY); @@ -302,8 +291,8 @@ void FilterImage::set_href(const gchar *href){ if (feImageHref) g_free (feImageHref); feImageHref = (href) ? g_strdup (href) : NULL; - g_object_set_data(G_OBJECT(image->gobj()), "cairo_surface", NULL); - image.reset(); + delete image; + image = NULL; broken_ref = false; } diff --git a/src/display/nr-filter-image.h b/src/display/nr-filter-image.h index f45f42265..69691ac99 100644 --- a/src/display/nr-filter-image.h +++ b/src/display/nr-filter-image.h @@ -12,14 +12,14 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <gdkmm/pixbuf.h> #include "display/nr-filter-primitive.h" -#include <glibmm/refptr.h> class SPDocument; class SPItem; namespace Inkscape { +class Pixbuf; + namespace Filters { class FilterSlot; @@ -43,7 +43,7 @@ public: private: SPDocument *document; gchar *feImageHref; - Glib::RefPtr<Gdk::Pixbuf> image; + Inkscape::Pixbuf *image; float feImageX, feImageY, feImageWidth, feImageHeight; unsigned int aspect_align, aspect_clip; bool broken_ref; diff --git a/src/display/nr-filter-specularlighting.h b/src/display/nr-filter-specularlighting.h index 0d1c0644f..c57e3a9ff 100644 --- a/src/display/nr-filter-specularlighting.h +++ b/src/display/nr-filter-specularlighting.h @@ -17,9 +17,9 @@ #include "display/nr-light-types.h" #include "display/nr-filter-primitive.h" -struct SPFeDistantLight; -struct SPFePointLight; -struct SPFeSpotLight; +class SPFeDistantLight; +class SPFePointLight; +class SPFeSpotLight; struct SVGICCColor; namespace Inkscape { diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 4f2a18531..a0103cbb0 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -114,13 +114,16 @@ int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, D Geom::Affine trans = item->ctm(); -// Geom::OptRect filter_area = filter_effect_area(item->itemBounds()); // disabled, already done in visualBounds - Geom::OptRect filter_area = item->itemBounds(); // see LP Bug 1188336 - if (!filter_area) return 1; + // Get filter are, the filter_effect_area is already done in visualBounds + Geom::OptRect filter_area = item->filterBounds(); + // Use the geometricBounds as a backup solution + if (!filter_area || (filter_area->hasZeroArea() && + filter_area->min()[Geom::X] == 0 && filter_area->min()[Geom::Y] == 0)) + filter_area = item->geometricBounds(); FilterUnits units(_filter_units, _primitive_units); units.set_ctm(trans); - units.set_item_bbox(item->itemBounds()); + units.set_item_bbox(filter_area); units.set_filter_area(*filter_area); std::pair<double,double> resolution @@ -200,7 +203,7 @@ void Filter::area_enlarge(Geom::IntRect &bbox, Inkscape::DrawingItem const *item } Geom::Rect item_bbox; - Geom::OptRect maybe_bbox = item->itemBounds(); + Geom::OptRect maybe_bbox = item->geometricBounds(); if (maybe_bbox.isEmpty()) { // Code below needs a bounding box return; diff --git a/src/display/nr-light.h b/src/display/nr-light.h index 022243bfc..0c1235483 100644 --- a/src/display/nr-light.h +++ b/src/display/nr-light.h @@ -13,9 +13,9 @@ #include "display/nr-light-types.h" #include <2geom/forward.h> -struct SPFeDistantLight; -struct SPFePointLight; -struct SPFeSpotLight; +class SPFeDistantLight; +class SPFePointLight; +class SPFeSpotLight; namespace Inkscape { namespace Filters { diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp index a18bc0523..cd7e9575f 100644 --- a/src/display/nr-style.cpp +++ b/src/display/nr-style.cpp @@ -211,8 +211,10 @@ bool NRStyle::prepareFill(Inkscape::DrawingContext &ct, Geom::OptRect const &pai if (!fill_pattern) { switch (fill.type) { case PAINT_SERVER: { - fill_pattern = sp_paint_server_create_pattern(fill.server, ct.raw(), paintbox, fill.opacity); - } break; + //fill_pattern = sp_paint_server_create_pattern(fill.server, ct.raw(), paintbox, fill.opacity); + fill_pattern = fill.server->pattern_new(ct.raw(), paintbox, fill.opacity); + + } break; case PAINT_COLOR: { SPColor const &c = fill.color; fill_pattern = cairo_pattern_create_rgba( @@ -236,8 +238,10 @@ bool NRStyle::prepareStroke(Inkscape::DrawingContext &ct, Geom::OptRect const &p if (!stroke_pattern) { switch (stroke.type) { case PAINT_SERVER: { - stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct.raw(), paintbox, stroke.opacity); - } break; + //stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct.raw(), paintbox, stroke.opacity); + stroke_pattern = stroke.server->pattern_new(ct.raw(), paintbox, stroke.opacity); + + } break; case PAINT_COLOR: { SPColor const &c = stroke.color; stroke_pattern = cairo_pattern_create_rgba( diff --git a/src/display/nr-style.h b/src/display/nr-style.h index df4c4f921..8fd736cc3 100644 --- a/src/display/nr-style.h +++ b/src/display/nr-style.h @@ -16,7 +16,7 @@ #include <2geom/rect.h> #include "color.h" -struct SPPaintServer; +class SPPaintServer; struct SPStyle; namespace Inkscape { diff --git a/src/display/nr-svgfonts.h b/src/display/nr-svgfonts.h index 1101f93f2..e1bb047bb 100644 --- a/src/display/nr-svgfonts.h +++ b/src/display/nr-svgfonts.h @@ -17,9 +17,9 @@ #include <sigc++/connection.h> class SvgFont; -struct SPFont; -struct SPGlyph; -struct SPMissingGlyph; +class SPFont; +class SPGlyph; +class SPMissingGlyph; struct _GdkEventExpose; typedef _GdkEventExpose GdkEventExpose; diff --git a/src/document.cpp b/src/document.cpp index 0b742e491..ec831745c 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -57,9 +57,9 @@ #include "preferences.h" #include "profile-manager.h" #include "rdf.h" +#include "sp-factory.h" #include "sp-item-group.h" #include "sp-namedview.h" -#include "sp-object-repr.h" #include "sp-symbol.h" #include "transf_mat_3x4.h" #include "util/units.h" @@ -348,7 +348,21 @@ SPDocument *SPDocument::createDoc(Inkscape::XML::Document *rdoc, } document->name = g_strdup(name); - document->root = sp_object_repr_build_tree(document, rroot); + // Create SPRoot element + const std::string typeString = NodeTraits::get_type_string(*rroot); + SPObject* rootObj = SPFactory::instance().createObject(typeString); + document->root = dynamic_cast<SPRoot*>(rootObj); + + if (document->root == 0) { + // Node is not a valid root element + delete rootObj; + + // fixme: what to do here? + throw; + } + + // Recursively build object tree + document->root->invoke_build(document, rroot, false); /* fixme: Not sure about this, but lets assume ::build updates */ rroot->setAttribute("inkscape:version", Inkscape::version_string); diff --git a/src/document.h b/src/document.h index 6782c6206..63332f431 100644 --- a/src/document.h +++ b/src/document.h @@ -33,8 +33,8 @@ class Router; class SPItem; class SPObject; -struct SPGroup; -struct SPRoot; +class SPGroup; +class SPRoot; namespace Inkscape { struct Application; @@ -53,7 +53,7 @@ namespace Inkscape { class SPDefs; class SP3DBox; -struct Persp3D; +class Persp3D; class Persp3DImpl; class SPItemCtx; diff --git a/src/doxygen-main.cpp b/src/doxygen-main.cpp index a1d3f3604..e581b8708 100644 --- a/src/doxygen-main.cpp +++ b/src/doxygen-main.cpp @@ -245,7 +245,6 @@ namespace XML {} * - SPLinearGradient * - SPRadialGradient * - SPPattern [\ref sp-pattern.cpp, \ref sp-pattern.h] - * - SPSkeleton [\ref sp-skeleton.cpp, \ref sp-skeleton.h] * - SPStop [\ref sp-stop.h] * - SPString [\ref sp-string.cpp, \ref sp-string.h] * - SPStyleElem [\ref sp-style-elem.cpp, \ref sp-style-elem.h] diff --git a/src/draw-anchor.h b/src/draw-anchor.h index 89ff8b180..1ca2b9888 100644 --- a/src/draw-anchor.h +++ b/src/draw-anchor.h @@ -8,7 +8,7 @@ #include <glib.h> #include <2geom/point.h> -struct SPDrawContext; +class SPDrawContext; class SPCurve; struct SPCanvasItem; diff --git a/src/draw-context.cpp b/src/draw-context.cpp index a907bdde4..34b80e3eb 100644 --- a/src/draw-context.cpp +++ b/src/draw-context.cpp @@ -50,14 +50,6 @@ using Inkscape::DocumentUndo; -static void sp_draw_context_dispose(GObject *object); - -static void sp_draw_context_setup(SPEventContext *ec); -static void sp_draw_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val); -static void sp_draw_context_finish(SPEventContext *ec); - -static gint sp_draw_context_root_handler(SPEventContext *event_context, GdkEvent *event); - static void spdc_selection_changed(Inkscape::Selection *sel, SPDrawContext *dc); static void spdc_selection_modified(Inkscape::Selection *sel, guint flags, SPDrawContext *dc); @@ -74,146 +66,109 @@ static void spdc_flush_white(SPDrawContext *dc, SPCurve *gc); static void spdc_reset_white(SPDrawContext *dc); static void spdc_free_colors(SPDrawContext *dc); -G_DEFINE_TYPE(SPDrawContext, sp_draw_context, SP_TYPE_EVENT_CONTEXT); +SPDrawContext::SPDrawContext() : SPEventContext() { + this->selection = 0; + this->grab = 0; + this->anchor_statusbar = false; -static void sp_draw_context_class_init(SPDrawContextClass *klass) -{ - GObjectClass *object_class; - SPEventContextClass *ec_class; + this->attach = FALSE; - object_class = (GObjectClass *)klass; - ec_class = SP_EVENT_CONTEXT_CLASS(klass); + this->red_color = 0xff00007f; + this->blue_color = 0x0000ff7f; + this->green_color = 0x00ff007f; + this->red_curve_is_valid = false; - object_class->dispose = sp_draw_context_dispose; + this->red_bpath = NULL; + this->red_curve = NULL; - ec_class->setup = sp_draw_context_setup; - ec_class->set = sp_draw_context_set; - ec_class->finish = sp_draw_context_finish; - ec_class->root_handler = sp_draw_context_root_handler; -} - -static void sp_draw_context_init(SPDrawContext *dc) -{ - dc->attach = FALSE; + this->blue_bpath = NULL; + this->blue_curve = NULL; - dc->red_color = 0xff00007f; - dc->blue_color = 0x0000ff7f; - dc->green_color = 0x00ff007f; - dc->red_curve_is_valid = false; + this->green_bpaths = NULL; + this->green_curve = NULL; + this->green_anchor = NULL; + this->green_closed = false; - dc->red_bpath = NULL; - dc->red_curve = NULL; - - dc->blue_bpath = NULL; - dc->blue_curve = NULL; - - dc->green_bpaths = NULL; - dc->green_curve = NULL; - dc->green_anchor = NULL; - dc->green_closed = false; - - dc->white_item = NULL; - dc->white_curves = NULL; - dc->white_anchors = NULL; - - dc->sa = NULL; - dc->ea = NULL; + this->white_item = NULL; + this->white_curves = NULL; + this->white_anchors = NULL; - dc->waiting_LPE_type = Inkscape::LivePathEffect::INVALID_LPE; + this->sa = NULL; + this->ea = NULL; - new (&dc->sel_changed_connection) sigc::connection(); - new (&dc->sel_modified_connection) sigc::connection(); + this->waiting_LPE_type = Inkscape::LivePathEffect::INVALID_LPE; } -static void sp_draw_context_dispose(GObject *object) -{ - SPDrawContext *dc = SP_DRAW_CONTEXT(object); - - dc->sel_changed_connection.~connection(); - dc->sel_modified_connection.~connection(); - - if (dc->grab) { - sp_canvas_item_ungrab(dc->grab, GDK_CURRENT_TIME); - dc->grab = NULL; +SPDrawContext::~SPDrawContext() { + if (this->grab) { + sp_canvas_item_ungrab(this->grab, GDK_CURRENT_TIME); + this->grab = NULL; } - if (dc->selection) { - dc->selection = NULL; + if (this->selection) { + this->selection = NULL; } - spdc_free_colors(dc); - - G_OBJECT_CLASS(sp_draw_context_parent_class)->dispose(object); + spdc_free_colors(this); } -static void sp_draw_context_setup(SPEventContext *ec) -{ - SPDrawContext *dc = SP_DRAW_CONTEXT(ec); - SPDesktop *dt = ec->desktop; - - if ((SP_EVENT_CONTEXT_CLASS(sp_draw_context_parent_class))->setup) { - (SP_EVENT_CONTEXT_CLASS(sp_draw_context_parent_class))->setup(ec); - } +void SPDrawContext::setup() { + SPEventContext::setup(); - dc->selection = sp_desktop_selection(dt); + this->selection = sp_desktop_selection(desktop); // Connect signals to track selection changes - dc->sel_changed_connection = dc->selection->connectChanged( - sigc::bind(sigc::ptr_fun(&spdc_selection_changed), dc) + this->sel_changed_connection = this->selection->connectChanged( + sigc::bind(sigc::ptr_fun(&spdc_selection_changed), this) ); - dc->sel_modified_connection = dc->selection->connectModified( - sigc::bind(sigc::ptr_fun(&spdc_selection_modified), dc) + this->sel_modified_connection = this->selection->connectModified( + sigc::bind(sigc::ptr_fun(&spdc_selection_modified), this) ); // Create red bpath - dc->red_bpath = sp_canvas_bpath_new(sp_desktop_sketch(ec->desktop), NULL); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->red_bpath), dc->red_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); + this->red_bpath = sp_canvas_bpath_new(sp_desktop_sketch(this->desktop), NULL); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->red_bpath), this->red_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); // Create red curve - dc->red_curve = new SPCurve(); + this->red_curve = new SPCurve(); // Create blue bpath - dc->blue_bpath = sp_canvas_bpath_new(sp_desktop_sketch(ec->desktop), NULL); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->blue_bpath), dc->blue_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); + this->blue_bpath = sp_canvas_bpath_new(sp_desktop_sketch(this->desktop), NULL); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->blue_bpath), this->blue_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); // Create blue curve - dc->blue_curve = new SPCurve(); + this->blue_curve = new SPCurve(); // Create green curve - dc->green_curve = new SPCurve(); + this->green_curve = new SPCurve(); // No green anchor by default - dc->green_anchor = NULL; - dc->green_closed = FALSE; + this->green_anchor = NULL; + this->green_closed = FALSE; - dc->attach = TRUE; - spdc_attach_selection(dc, dc->selection); + this->attach = TRUE; + spdc_attach_selection(this, this->selection); } -static void sp_draw_context_finish(SPEventContext *ec) -{ - SPDrawContext *dc = SP_DRAW_CONTEXT(ec); - - dc->sel_changed_connection.disconnect(); - dc->sel_modified_connection.disconnect(); +void SPDrawContext::finish() { + this->sel_changed_connection.disconnect(); + this->sel_modified_connection.disconnect(); - if (dc->grab) { - sp_canvas_item_ungrab(dc->grab, GDK_CURRENT_TIME); + if (this->grab) { + sp_canvas_item_ungrab(this->grab, GDK_CURRENT_TIME); } - if (dc->selection) { - dc->selection = NULL; + if (this->selection) { + this->selection = NULL; } - spdc_free_colors(dc); + spdc_free_colors(this); } -static void sp_draw_context_set(SPEventContext */*ec*/, Inkscape::Preferences::Entry */*val*/) -{ +void SPDrawContext::set(const Inkscape::Preferences::Entry& value) { } -gint sp_draw_context_root_handler(SPEventContext *ec, GdkEvent *event) -{ +bool SPDrawContext::root_handler(GdkEvent* event) { gint ret = FALSE; switch (event->type) { @@ -237,9 +192,7 @@ gint sp_draw_context_root_handler(SPEventContext *ec, GdkEvent *event) } if (!ret) { - if ((SP_EVENT_CONTEXT_CLASS(sp_draw_context_parent_class))->root_handler) { - ret = (SP_EVENT_CONTEXT_CLASS(sp_draw_context_parent_class))->root_handler(ec, event); - } + ret = SPEventContext::root_handler(event); } return ret; diff --git a/src/draw-context.h b/src/draw-context.h index f930fa858..011d5e131 100644 --- a/src/draw-context.h +++ b/src/draw-context.h @@ -20,14 +20,10 @@ #include "event-context.h" #include "live_effects/effect.h" -G_BEGIN_DECLS /* Freehand context */ -#define SP_TYPE_DRAW_CONTEXT (sp_draw_context_get_type()) -#define SP_DRAW_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_DRAW_CONTEXT, SPDrawContext)) -#define SP_DRAW_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_DRAW_CONTEXT, SPDrawContextClass)) -#define SP_IS_DRAW_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_DRAW_CONTEXT)) -#define SP_IS_DRAW_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_DRAW_CONTEXT)) +#define SP_DRAW_CONTEXT(obj) (dynamic_cast<SPDrawContext*>((SPEventContext*)obj)) +#define SP_IS_DRAW_CONTEXT(obj) (dynamic_cast<const SPDrawContext*>((const SPEventContext*)obj) != NULL) struct SPDrawAnchor; namespace Inkscape @@ -35,7 +31,11 @@ namespace Inkscape class Selection; } -struct SPDrawContext : public SPEventContext{ +class SPDrawContext : public SPEventContext { +public: + SPDrawContext(); + virtual ~SPDrawContext(); + Inkscape::Selection *selection; SPCanvasItem *grab; @@ -80,11 +80,13 @@ struct SPDrawContext : public SPEventContext{ bool red_curve_is_valid; bool anchor_statusbar; -}; -struct SPDrawContextClass : public SPEventContextClass{}; - -GType sp_draw_context_get_type(void) G_GNUC_CONST; +protected: + virtual void setup(); + virtual void finish(); + virtual void set(const Inkscape::Preferences::Entry& val); + virtual bool root_handler(GdkEvent* event); +}; /** * Returns FIRST active anchor (the activated one). @@ -121,7 +123,6 @@ void spdc_check_for_and_apply_waiting_LPE(SPDrawContext *dc, SPItem *item); */ void spdc_create_single_dot(SPEventContext *ec, Geom::Point const &pt, char const *tool, guint event_state); -G_END_DECLS #endif // SEEN_SP_DRAW_CONTEXT_H /* diff --git a/src/dropper-context.cpp b/src/dropper-context.cpp index 57ddc1656..7dfe203ba 100644 --- a/src/dropper-context.cpp +++ b/src/dropper-context.cpp @@ -48,74 +48,49 @@ using Inkscape::DocumentUndo; -typedef struct -{ - double R; - double G; - double B; - double alpha; - - unsigned int dragging : 1; - - SPCanvasItem *grabbed; - SPCanvasItem *area; - Geom::Point centre; -} SPDropperContextPrivate; - -#define SP_DROPPER_CONTEXT_GET_PRIVATE(dc) \ - G_TYPE_INSTANCE_GET_PRIVATE(dc, SP_TYPE_DROPPER_CONTEXT, SPDropperContextPrivate) - -static void sp_dropper_context_class_init(SPDropperContextClass *klass); -static void sp_dropper_context_init(SPDropperContext *dc); - -static void sp_dropper_context_setup(SPEventContext *ec); -static void sp_dropper_context_finish(SPEventContext *ec); - -static gint sp_dropper_context_root_handler(SPEventContext *ec, GdkEvent * event); - -static SPEventContextClass *parent_class; - static GdkCursor *cursor_dropper_fill = NULL; static GdkCursor *cursor_dropper_stroke = NULL; -G_DEFINE_TYPE(SPDropperContext, sp_dropper_context, SP_TYPE_EVENT_CONTEXT); +#include "tool-factory.h" -static void -sp_dropper_context_class_init(SPDropperContextClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - SPEventContextClass *ec_class = SP_EVENT_CONTEXT_CLASS(klass); +namespace { + SPEventContext* createDropperContext() { + return new SPDropperContext(); + } - parent_class = SP_EVENT_CONTEXT_CLASS(g_type_class_peek_parent(klass)); + bool dropperContextRegistered = ToolFactory::instance().registerObject("/tools/dropper", createDropperContext); +} - ec_class->setup = sp_dropper_context_setup; - ec_class->finish = sp_dropper_context_finish; - ec_class->root_handler = sp_dropper_context_root_handler; - - g_type_class_add_private(object_class, sizeof(SPDropperContext)); +const std::string& SPDropperContext::getPrefsPath() { + return SPDropperContext::prefsPath; } -static void sp_dropper_context_init(SPDropperContext *dc) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(dc); - event_context->cursor_shape = cursor_dropper_f_xpm; - event_context->hot_x = 7; - event_context->hot_y = 7; +const std::string SPDropperContext::prefsPath = "/tools/dropper"; + +SPDropperContext::SPDropperContext() : SPEventContext() { + this->R = 0; + this->G = 0; + this->B = 0; + this->alpha = 0; + this->dragging = false; + + this->grabbed = 0; + this->area = 0; + this->centre = Geom::Point(0, 0); + + this->cursor_shape = cursor_dropper_f_xpm; + this->hot_x = 7; + this->hot_y = 7; cursor_dropper_fill = sp_cursor_new_from_xpm(cursor_dropper_f_xpm , 7, 7); cursor_dropper_stroke = sp_cursor_new_from_xpm(cursor_dropper_s_xpm , 7, 7); - } -static void -sp_dropper_context_setup(SPEventContext *ec) -{ - SPDropperContext *dc = SP_DROPPER_CONTEXT(ec); - SPDropperContextPrivate *priv = SP_DROPPER_CONTEXT_GET_PRIVATE(dc); +SPDropperContext::~SPDropperContext() { +} - if ((SP_EVENT_CONTEXT_CLASS(parent_class))->setup) { - (SP_EVENT_CONTEXT_CLASS(parent_class))->setup(ec); - } +void SPDropperContext::setup() { + SPEventContext::setup(); /* TODO: have a look at sp_dyna_draw_context_setup where the same is done.. generalize? at least make it an arcto! */ SPCurve *c = new SPCurve(); @@ -126,38 +101,35 @@ sp_dropper_context_setup(SPEventContext *ec) c->curveto(1, -C1, C1, -1, 0, -1 ); c->curveto(-C1, -1, -1, -C1, -1, 0 ); c->closepath(); - priv->area = sp_canvas_bpath_new(sp_desktop_controls(ec->desktop), c); + this->area = sp_canvas_bpath_new(sp_desktop_controls(this->desktop), c); c->unref(); - sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(priv->area), 0x00000000,(SPWindRule)0); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(priv->area), 0x0000007f, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - sp_canvas_item_hide(priv->area); + + sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(this->area), 0x00000000,(SPWindRule)0); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->area), 0x0000007f, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); + sp_canvas_item_hide(this->area); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/tools/dropper/selcue")) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } if (prefs->getBool("/tools/dropper/gradientdrag")) { - ec->enableGrDrag(); + this->enableGrDrag(); } } -static void -sp_dropper_context_finish(SPEventContext *ec) -{ - SPDropperContext *dc = SP_DROPPER_CONTEXT(ec); - SPDropperContextPrivate *priv = SP_DROPPER_CONTEXT_GET_PRIVATE(dc); - - ec->enableGrDrag(false); +void SPDropperContext::finish() { + this->enableGrDrag(false); - if (priv->grabbed) { - sp_canvas_item_ungrab(priv->grabbed, GDK_CURRENT_TIME); - priv->grabbed = NULL; + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, GDK_CURRENT_TIME); + this->grabbed = NULL; } - if (priv->area) { - sp_canvas_item_destroy(priv->area); - priv->area = NULL; + if (this->area) { + sp_canvas_item_destroy(this->area); + this->area = NULL; } if (cursor_dropper_fill) { @@ -168,6 +140,7 @@ sp_dropper_context_finish(SPEventContext *ec) #endif cursor_dropper_fill = NULL; } + if (cursor_dropper_stroke) { #if GTK_CHECK_VERSION(3,0,0) g_object_unref(cursor_dropper_stroke); @@ -176,42 +149,25 @@ sp_dropper_context_finish(SPEventContext *ec) #endif cursor_dropper_fill = NULL; } - - //Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - //prefs->setBool("/tools/dropper/onetimepick", false); - } /** * Returns the current dropper context color. */ -guint32 -sp_dropper_context_get_color(SPEventContext *ec) -{ - SPDropperContext *dc = SP_DROPPER_CONTEXT(ec); - SPDropperContextPrivate *priv = SP_DROPPER_CONTEXT_GET_PRIVATE(dc); +guint32 SPDropperContext::get_color() { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - int pick = prefs->getInt("/tools/dropper/pick", - SP_DROPPER_PICK_VISIBLE); - + int pick = prefs->getInt("/tools/dropper/pick", SP_DROPPER_PICK_VISIBLE); bool setalpha = prefs->getBool("/tools/dropper/setalpha", true); - return SP_RGBA32_F_COMPOSE(priv->R, - priv->G, - priv->B, - (pick == SP_DROPPER_PICK_ACTUAL && setalpha) ? priv->alpha - : 1.0); + return SP_RGBA32_F_COMPOSE(this->R, + this->G, + this->B, + (pick == SP_DROPPER_PICK_ACTUAL && setalpha) ? this->alpha : 1.0); } -static gint -sp_dropper_context_root_handler(SPEventContext *event_context, - GdkEvent *event) -{ - SPDropperContext *dc = SP_DROPPER_CONTEXT(event_context); - SPDropperContextPrivate *priv = SP_DROPPER_CONTEXT_GET_PRIVATE(dc); - SPDesktop *desktop = event_context->desktop; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); +bool SPDropperContext::root_handler(GdkEvent* event) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int ret = FALSE; @@ -220,16 +176,16 @@ sp_dropper_context_root_handler(SPEventContext *event_context, switch (event->type) { case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { - priv->centre = Geom::Point(event->button.x, event->button.y); - priv->dragging = TRUE; + if (event->button.button == 1 && !this->space_panning) { + this->centre = Geom::Point(event->button.x, event->button.y); + this->dragging = true; ret = TRUE; } sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK, NULL, event->button.time); - priv->grabbed = SP_CANVAS_ITEM(desktop->acetate); + this->grabbed = SP_CANVAS_ITEM(desktop->acetate); break; case GDK_MOTION_NOTIFY: @@ -237,7 +193,7 @@ sp_dropper_context_root_handler(SPEventContext *event_context, // pass on middle and right drag ret = FALSE; break; - } else if (!event_context->space_panning) { + } else if (!this->space_panning) { // otherwise, constantly calculate color no matter is any button pressed or not // If one time pick with stroke set the pixmap @@ -250,25 +206,25 @@ sp_dropper_context_root_handler(SPEventContext *event_context, double rw = 0.0; double R(0), G(0), B(0), A(0); - if (priv->dragging) { + if (this->dragging) { // calculate average // radius - rw = std::min(Geom::L2(Geom::Point(event->button.x, event->button.y) - priv->centre), 400.0); + rw = std::min(Geom::L2(Geom::Point(event->button.x, event->button.y) - this->centre), 400.0); if (rw == 0) { // happens sometimes, little idea why... break; } - Geom::Point const cd = desktop->w2d(priv->centre); + Geom::Point const cd = desktop->w2d(this->centre); Geom::Affine const w2dt = desktop->w2d(); const double scale = rw * w2dt.descrim(); Geom::Affine const sm( Geom::Scale(scale, scale) * Geom::Translate(cd) ); - sp_canvas_item_affine_absolute(priv->area, sm); - sp_canvas_item_show(priv->area); + sp_canvas_item_affine_absolute(this->area, sm); + sp_canvas_item_show(this->area); /* Get buffer */ - Geom::Rect r(priv->centre, priv->centre); + Geom::Rect r(this->centre, this->centre); r.expandBy(rw); if (!r.hasZeroArea()) { Geom::IntRect area = r.roundOutwards(); @@ -307,13 +263,13 @@ sp_dropper_context_root_handler(SPEventContext *event_context, } // remember color - priv->R = R; - priv->G = G; - priv->B = B; - priv->alpha = A; + this->R = R; + this->G = G; + this->B = B; + this->alpha = A; // status message - double alpha_to_set = setalpha? priv->alpha : 1.0; + double alpha_to_set = setalpha? this->alpha : 1.0; guint32 c32 = SP_RGBA32_F_COMPOSE(R, G, B, alpha_to_set); gchar c[64]; @@ -323,15 +279,14 @@ sp_dropper_context_root_handler(SPEventContext *event_context, // locale-sensitive printf is OK, since this goes to the UI, not into SVG gchar *alpha = g_strdup_printf(_(" alpha %.3g"), alpha_to_set); // where the color is picked, to show in the statusbar - gchar *where = priv->dragging ? g_strdup_printf(_(", averaged with radius %d"), (int) rw) : g_strdup_printf(_(" under cursor")); + gchar *where = this->dragging ? g_strdup_printf(_(", averaged with radius %d"), (int) rw) : g_strdup_printf(_(" under cursor")); // message, to show in the statusbar - const gchar *message = priv->dragging ? _("<b>Release mouse</b> to set color.") : _("<b>Click</b> to set fill, <b>Shift+click</b> to set stroke; <b>drag</b> to average color in area; with <b>Alt</b> to pick inverse color; <b>Ctrl+C</b> to copy the color under mouse to clipboard"); - event_context->defaultMessageContext()->setF( + const gchar *message = this->dragging ? _("<b>Release mouse</b> to set color.") : _("<b>Click</b> to set fill, <b>Shift+click</b> to set stroke; <b>drag</b> to average color in area; with <b>Alt</b> to pick inverse color; <b>Ctrl+C</b> to copy the color under mouse to clipboard"); + + this->defaultMessageContext()->setF( Inkscape::NORMAL_MESSAGE, "<b>%s%s</b>%s. %s", c, - (pick == SP_DROPPER_PICK_VISIBLE)? "" : alpha, - where, message - ); + (pick == SP_DROPPER_PICK_VISIBLE) ? "" : alpha, where, message); g_free(where); g_free(alpha); @@ -339,20 +294,21 @@ sp_dropper_context_root_handler(SPEventContext *event_context, ret = TRUE; } break; + case GDK_BUTTON_RELEASE: - if (event->button.button == 1 && !event_context->space_panning) - { - sp_canvas_item_hide(priv->area); - priv->dragging = FALSE; + if (event->button.button == 1 && !this->space_panning) { + sp_canvas_item_hide(this->area); + this->dragging = false; - if (priv->grabbed) { - sp_canvas_item_ungrab(priv->grabbed, event->button.time); - priv->grabbed = NULL; + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, event->button.time); + this->grabbed = NULL; } - double alpha_to_set = setalpha? priv->alpha : 1.0; + double alpha_to_set = setalpha? this->alpha : 1.0; bool fill = !(event->button.state & GDK_SHIFT_MASK); // Stroke if Shift key held + if (prefs->getBool("/tools/dropper/onetimepick", false)) { // "One time" pick from Fill/Stroke dialog stroke page, always apply fill or stroke (ignore <Shift> key) fill = (prefs->getInt("/dialogs/fillstroke/page", 0) == 0) ? true : false; @@ -361,7 +317,7 @@ sp_dropper_context_root_handler(SPEventContext *event_context, // do the actual color setting sp_desktop_set_color(desktop, (event->button.state & GDK_MOD1_MASK)? - ColorRGBA(1 - priv->R, 1 - priv->G, 1 - priv->B, alpha_to_set) : ColorRGBA(priv->R, priv->G, priv->B, alpha_to_set), + ColorRGBA(1 - this->R, 1 - this->G, 1 - this->B, alpha_to_set) : ColorRGBA(this->R, this->G, this->B, alpha_to_set), false, fill); // REJON: set aux. toolbar input to hex color! @@ -384,6 +340,7 @@ sp_dropper_context_root_handler(SPEventContext *event_context, ret = TRUE; } break; + case GDK_KEY_PRESS: switch (get_group0_keyval(&event->key)) { case GDK_KEY_Up: @@ -395,6 +352,7 @@ sp_dropper_context_root_handler(SPEventContext *event_context, ret = TRUE; } break; + case GDK_KEY_Escape: sp_desktop_selection(desktop)->clear(); case GDK_KEY_Shift_L: @@ -409,6 +367,7 @@ sp_dropper_context_root_handler(SPEventContext *event_context, break; } break; + case GDK_KEY_RELEASE: switch (get_group0_keyval(&event->key)) { case GDK_KEY_Shift_L: @@ -418,18 +377,18 @@ sp_dropper_context_root_handler(SPEventContext *event_context, gdk_window_set_cursor(window, cursor_dropper_fill); } break; + default: break; } break; + default: break; } if (!ret) { - if ((SP_EVENT_CONTEXT_CLASS(parent_class))->root_handler) { - ret = (SP_EVENT_CONTEXT_CLASS(parent_class))->root_handler(event_context, event); - } + ret = SPEventContext::root_handler(event); } return ret; diff --git a/src/dropper-context.h b/src/dropper-context.h index be4b543ae..6e1015644 100644 --- a/src/dropper-context.h +++ b/src/dropper-context.h @@ -14,30 +14,42 @@ #include "event-context.h" -G_BEGIN_DECLS - -#define SP_TYPE_DROPPER_CONTEXT (sp_dropper_context_get_type ()) -#define SP_DROPPER_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_DROPPER_CONTEXT, SPDropperContext)) -#define SP_IS_DROPPER_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_DROPPER_CONTEXT)) +#define SP_DROPPER_CONTEXT(obj) (dynamic_cast<SPDropperContext*>((SPEventContext*)obj)) +#define SP_IS_DROPPER_CONTEXT(obj) (dynamic_cast<const SPDropperContext*>((const SPEventContext*)obj) != NULL) enum { SP_DROPPER_PICK_VISIBLE, SP_DROPPER_PICK_ACTUAL }; -struct SPDropperContext { - SPEventContext event_context; -}; +class SPDropperContext : public SPEventContext { +public: + SPDropperContext(); + virtual ~SPDropperContext(); -struct SPDropperContextClass { - SPEventContextClass parent_class; -}; + static const std::string prefsPath; + + virtual const std::string& getPrefsPath(); -GType sp_dropper_context_get_type (void); + guint32 get_color(); -guint32 sp_dropper_context_get_color(SPEventContext *ec); +protected: + virtual void setup(); + virtual void finish(); + virtual bool root_handler(GdkEvent* event); -G_END_DECLS +private: + double R; + double G; + double B; + double alpha; + + bool dragging; + + SPCanvasItem* grabbed; + SPCanvasItem* area; + Geom::Point centre; +}; #endif diff --git a/src/dyna-draw-context.cpp b/src/dyna-draw-context.cpp index c37f9cb4b..05ebc3a4a 100644 --- a/src/dyna-draw-context.cpp +++ b/src/dyna-draw-context.cpp @@ -81,164 +81,129 @@ using Inkscape::DocumentUndo; #define DYNA_MIN_WIDTH 1.0e-6 -static void sp_dyna_draw_context_dispose(GObject *object); +static void add_cap(SPCurve *curve, Geom::Point const &from, Geom::Point const &to, double rounding); -static void sp_dyna_draw_context_setup(SPEventContext *ec); -static void sp_dyna_draw_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *value); -static gint sp_dyna_draw_context_root_handler(SPEventContext *ec, GdkEvent *event); -static void clear_current(SPDynaDrawContext *dc); -static void set_to_accumulated(SPDynaDrawContext *dc, bool unionize, bool subtract); -static void add_cap(SPCurve *curve, Geom::Point const &from, Geom::Point const &to, double rounding); -static bool accumulate_calligraphic(SPDynaDrawContext *dc); +#include "tool-factory.h" -static void fit_and_split(SPDynaDrawContext *ddc, gboolean release); +namespace { + SPEventContext* createCalligraphicContext() { + return new SPDynaDrawContext(); + } -static void sp_dyna_draw_reset(SPDynaDrawContext *ddc, Geom::Point p); -static Geom::Point sp_dyna_draw_get_npoint(SPDynaDrawContext const *ddc, Geom::Point v); -static Geom::Point sp_dyna_draw_get_vpoint(SPDynaDrawContext const *ddc, Geom::Point n); -static void draw_temporary_box(SPDynaDrawContext *dc); + bool calligraphicContextRegistered = ToolFactory::instance().registerObject("/tools/calligraphic", createCalligraphicContext); +} -G_DEFINE_TYPE(SPDynaDrawContext, sp_dyna_draw_context, SP_TYPE_COMMON_CONTEXT); +const std::string& SPDynaDrawContext::getPrefsPath() { + return SPDynaDrawContext::prefsPath; +} -static void -sp_dyna_draw_context_class_init(SPDynaDrawContextClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - SPEventContextClass *event_context_class = SP_EVENT_CONTEXT_CLASS(klass); - object_class->dispose = sp_dyna_draw_context_dispose; +const std::string SPDynaDrawContext::prefsPath = "/tools/calligraphic"; - event_context_class->setup = sp_dyna_draw_context_setup; - event_context_class->set = sp_dyna_draw_context_set; - event_context_class->root_handler = sp_dyna_draw_context_root_handler; -} +SPDynaDrawContext::SPDynaDrawContext() : SPCommonContext() { + this->cursor_shape = cursor_calligraphy_xpm; + this->hot_x = 4; + this->hot_y = 4; -static void -sp_dyna_draw_context_init(SPDynaDrawContext *ddc) -{ - ddc->cursor_shape = cursor_calligraphy_xpm; - ddc->hot_x = 4; - ddc->hot_y = 4; - - ddc->vel_thin = 0.1; - ddc->flatness = 0.9; - ddc->cap_rounding = 0.0; - - ddc->abs_width = false; - ddc->keep_selected = true; - - ddc->hatch_spacing = 0; - ddc->hatch_spacing_step = 0; - new (&ddc->hatch_pointer_past) std::list<double>(); - new (&ddc->hatch_nearest_past) std::list<double>(); - new (&ddc->inertia_vectors) std::list<Geom::Point>(); - new (&ddc->hatch_vectors) std::list<Geom::Point>(); - ddc->hatch_last_nearest = Geom::Point(0,0); - ddc->hatch_last_pointer = Geom::Point(0,0); - ddc->hatch_escaped = false; - ddc->hatch_area = NULL; - ddc->hatch_item = NULL; - ddc->hatch_livarot_path = NULL; - - ddc->trace_bg = false; - ddc->just_started_drawing = false; -} + this->vel_thin = 0.1; + this->flatness = 0.9; + this->cap_rounding = 0.0; -static void -sp_dyna_draw_context_dispose(GObject *object) -{ - SPDynaDrawContext *ddc = SP_DYNA_DRAW_CONTEXT(object); + this->abs_width = false; + this->keep_selected = true; - if (ddc->hatch_area) { - sp_canvas_item_destroy(ddc->hatch_area); - ddc->hatch_area = NULL; - } + this->hatch_spacing = 0; + this->hatch_spacing_step = 0; + this->hatch_last_nearest = Geom::Point(0,0); + this->hatch_last_pointer = Geom::Point(0,0); + this->hatch_escaped = false; + this->hatch_area = NULL; + this->hatch_item = NULL; + this->hatch_livarot_path = NULL; - G_OBJECT_CLASS(sp_dyna_draw_context_parent_class)->dispose(object); + this->trace_bg = false; + this->just_started_drawing = false; +} - ddc->hatch_pointer_past.~list(); - ddc->hatch_nearest_past.~list(); - ddc->inertia_vectors.~list(); - ddc->hatch_vectors.~list(); +SPDynaDrawContext::~SPDynaDrawContext() { + if (this->hatch_area) { + sp_canvas_item_destroy(this->hatch_area); + this->hatch_area = NULL; + } } -static void -sp_dyna_draw_context_setup(SPEventContext *ec) -{ - SPDynaDrawContext *ddc = SP_DYNA_DRAW_CONTEXT(ec); +void SPDynaDrawContext::setup() { + SPCommonContext::setup(); - if ((SP_EVENT_CONTEXT_CLASS(sp_dyna_draw_context_parent_class))->setup) - (SP_EVENT_CONTEXT_CLASS(sp_dyna_draw_context_parent_class))->setup(ec); + this->accumulated = new SPCurve(); + this->currentcurve = new SPCurve(); - ddc->accumulated = new SPCurve(); - ddc->currentcurve = new SPCurve(); + this->cal1 = new SPCurve(); + this->cal2 = new SPCurve(); - ddc->cal1 = new SPCurve(); - ddc->cal2 = new SPCurve(); + this->currentshape = sp_canvas_item_new(sp_desktop_sketch(this->desktop), SP_TYPE_CANVAS_BPATH, NULL); + sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(this->currentshape), DDC_RED_RGBA, SP_WIND_RULE_EVENODD); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->currentshape), 0x00000000, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - ddc->currentshape = sp_canvas_item_new(sp_desktop_sketch(ec->desktop), SP_TYPE_CANVAS_BPATH, NULL); - sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(ddc->currentshape), DDC_RED_RGBA, SP_WIND_RULE_EVENODD); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(ddc->currentshape), 0x00000000, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); /* fixme: Cannot we cascade it to root more clearly? */ - g_signal_connect(G_OBJECT(ddc->currentshape), "event", G_CALLBACK(sp_desktop_root_handler), ec->desktop); + g_signal_connect(G_OBJECT(this->currentshape), "event", G_CALLBACK(sp_desktop_root_handler), this->desktop); { /* TODO: this can be done either with an arcto, and should maybe also be put in a general file (other tools use this as well) */ SPCurve *c = new SPCurve(); + const double C1 = 0.552; + c->moveto(-1,0); c->curveto(-1, C1, -C1, 1, 0, 1 ); c->curveto(C1, 1, 1, C1, 1, 0 ); c->curveto(1, -C1, C1, -1, 0, -1 ); c->curveto(-C1, -1, -1, -C1, -1, 0 ); c->closepath(); - ddc->hatch_area = sp_canvas_bpath_new(sp_desktop_controls(ec->desktop), c); + + this->hatch_area = sp_canvas_bpath_new(sp_desktop_controls(this->desktop), c); + c->unref(); - sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(ddc->hatch_area), 0x00000000,(SPWindRule)0); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(ddc->hatch_area), 0x0000007f, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - sp_canvas_item_hide(ddc->hatch_area); + + sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(this->hatch_area), 0x00000000,(SPWindRule)0); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->hatch_area), 0x0000007f, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); + sp_canvas_item_hide(this->hatch_area); } - sp_event_context_read(ec, "mass"); - sp_event_context_read(ec, "wiggle"); - sp_event_context_read(ec, "angle"); - sp_event_context_read(ec, "width"); - sp_event_context_read(ec, "thinning"); - sp_event_context_read(ec, "tremor"); - sp_event_context_read(ec, "flatness"); - sp_event_context_read(ec, "tracebackground"); - sp_event_context_read(ec, "usepressure"); - sp_event_context_read(ec, "usetilt"); - sp_event_context_read(ec, "abs_width"); - sp_event_context_read(ec, "keep_selected"); - sp_event_context_read(ec, "cap_rounding"); - - ddc->is_drawing = false; - ddc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack()); + sp_event_context_read(this, "mass"); + sp_event_context_read(this, "wiggle"); + sp_event_context_read(this, "angle"); + sp_event_context_read(this, "width"); + sp_event_context_read(this, "thinning"); + sp_event_context_read(this, "tremor"); + sp_event_context_read(this, "flatness"); + sp_event_context_read(this, "tracebackground"); + sp_event_context_read(this, "usepressure"); + sp_event_context_read(this, "usetilt"); + sp_event_context_read(this, "abs_width"); + sp_event_context_read(this, "keep_selected"); + sp_event_context_read(this, "cap_rounding"); + + this->is_drawing = false; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/tools/calligraphic/selcue")) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } } -static void -sp_dyna_draw_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val) -{ - SPDynaDrawContext *ddc = SP_DYNA_DRAW_CONTEXT(ec); - Glib::ustring path = val->getEntryName(); +void SPDynaDrawContext::set(const Inkscape::Preferences::Entry& val) { + Glib::ustring path = val.getEntryName(); if (path == "tracebackground") { - ddc->trace_bg = val->getBool(); + this->trace_bg = val.getBool(); } else if (path == "keep_selected") { - ddc->keep_selected = val->getBool(); + this->keep_selected = val.getBool(); } else { //pass on up to parent class to handle common attributes. - if ( SP_COMMON_CONTEXT_CLASS(sp_dyna_draw_context_parent_class)->set ) { - SP_COMMON_CONTEXT_CLASS(sp_dyna_draw_context_parent_class)->set(ec, val); - } + SPCommonContext::set(val); } //g_print("DDC: %g %g %g %g\n", ddc->mass, ddc->drag, ddc->angle, ddc->width); @@ -250,66 +215,64 @@ flerp(double f0, double f1, double p) return f0 + ( f1 - f0 ) * p; } -/* Get normalized point */ -static Geom::Point -sp_dyna_draw_get_npoint(SPDynaDrawContext const *dc, Geom::Point v) -{ - Geom::Rect drect = SP_EVENT_CONTEXT(dc)->desktop->get_display_area(); - double const max = MAX ( drect.dimensions()[Geom::X], drect.dimensions()[Geom::Y] ); - return Geom::Point(( v[Geom::X] - drect.min()[Geom::X] ) / max, ( v[Geom::Y] - drect.min()[Geom::Y] ) / max); +///* Get normalized point */ +//Geom::Point SPDynaDrawContext::getNormalizedPoint(Geom::Point v) const { +// Geom::Rect drect = desktop->get_display_area(); +// +// double const max = MAX ( drect.dimensions()[Geom::X], drect.dimensions()[Geom::Y] ); +// +// return Geom::Point(( v[Geom::X] - drect.min()[Geom::X] ) / max, ( v[Geom::Y] - drect.min()[Geom::Y] ) / max); +//} +// +///* Get view point */ +//Geom::Point SPDynaDrawContext::getViewPoint(Geom::Point n) const { +// Geom::Rect drect = desktop->get_display_area(); +// +// double const max = MAX ( drect.dimensions()[Geom::X], drect.dimensions()[Geom::Y] ); +// +// return Geom::Point(n[Geom::X] * max + drect.min()[Geom::X], n[Geom::Y] * max + drect.min()[Geom::Y]); +//} + +void SPDynaDrawContext::reset(Geom::Point p) { + this->last = this->cur = this->getNormalizedPoint(p); + + this->vel = Geom::Point(0,0); + this->vel_max = 0; + this->acc = Geom::Point(0,0); + this->ang = Geom::Point(0,0); + this->del = Geom::Point(0,0); } -/* Get view point */ -static Geom::Point -sp_dyna_draw_get_vpoint(SPDynaDrawContext const *dc, Geom::Point n) -{ - Geom::Rect drect = SP_EVENT_CONTEXT(dc)->desktop->get_display_area(); - double const max = MAX ( drect.dimensions()[Geom::X], drect.dimensions()[Geom::Y] ); - return Geom::Point(n[Geom::X] * max + drect.min()[Geom::X], n[Geom::Y] * max + drect.min()[Geom::Y]); -} +void SPDynaDrawContext::extinput(GdkEvent *event) { + if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &this->pressure)) { + this->pressure = CLAMP (this->pressure, DDC_MIN_PRESSURE, DDC_MAX_PRESSURE); + } else { + this->pressure = DDC_DEFAULT_PRESSURE; + } -static void -sp_dyna_draw_reset(SPDynaDrawContext *dc, Geom::Point p) -{ - dc->last = dc->cur = sp_dyna_draw_get_npoint(dc, p); - dc->vel = Geom::Point(0,0); - dc->vel_max = 0; - dc->acc = Geom::Point(0,0); - dc->ang = Geom::Point(0,0); - dc->del = Geom::Point(0,0); -} + if (gdk_event_get_axis (event, GDK_AXIS_XTILT, &this->xtilt)) { + this->xtilt = CLAMP (this->xtilt, DDC_MIN_TILT, DDC_MAX_TILT); + } else { + this->xtilt = DDC_DEFAULT_TILT; + } -static void -sp_dyna_draw_extinput(SPDynaDrawContext *dc, GdkEvent *event) -{ - if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &dc->pressure)) - dc->pressure = CLAMP (dc->pressure, DDC_MIN_PRESSURE, DDC_MAX_PRESSURE); - else - dc->pressure = DDC_DEFAULT_PRESSURE; - - if (gdk_event_get_axis (event, GDK_AXIS_XTILT, &dc->xtilt)) - dc->xtilt = CLAMP (dc->xtilt, DDC_MIN_TILT, DDC_MAX_TILT); - else - dc->xtilt = DDC_DEFAULT_TILT; - - if (gdk_event_get_axis (event, GDK_AXIS_YTILT, &dc->ytilt)) - dc->ytilt = CLAMP (dc->ytilt, DDC_MIN_TILT, DDC_MAX_TILT); - else - dc->ytilt = DDC_DEFAULT_TILT; + if (gdk_event_get_axis (event, GDK_AXIS_YTILT, &this->ytilt)) { + this->ytilt = CLAMP (this->ytilt, DDC_MIN_TILT, DDC_MAX_TILT); + } else { + this->ytilt = DDC_DEFAULT_TILT; + } } -static gboolean -sp_dyna_draw_apply(SPDynaDrawContext *dc, Geom::Point p) -{ - Geom::Point n = sp_dyna_draw_get_npoint(dc, p); +bool SPDynaDrawContext::apply(Geom::Point p) { + Geom::Point n = this->getNormalizedPoint(p); /* Calculate mass and drag */ - double const mass = flerp(1.0, 160.0, dc->mass); - double const drag = flerp(0.0, 0.5, dc->drag * dc->drag); + double const mass = flerp(1.0, 160.0, this->mass); + double const drag = flerp(0.0, 0.5, this->drag * this->drag); /* Calculate force and acceleration */ - Geom::Point force = n - dc->cur; + Geom::Point force = n - this->cur; // If force is below the absolute threshold DYNA_EPSILON, // or we haven't yet reached DYNA_VEL_START (i.e. at the beginning of stroke) @@ -318,27 +281,27 @@ sp_dyna_draw_apply(SPDynaDrawContext *dc, Geom::Point p) // This prevents flips, blobs, and jerks caused by microscopic tremor of the tablet pen, // especially bothersome at the start of the stroke where we don't yet have the inertia to // smooth them out. - if ( Geom::L2(force) < DYNA_EPSILON || (dc->vel_max < DYNA_VEL_START && Geom::L2(force) < DYNA_EPSILON_START)) { + if ( Geom::L2(force) < DYNA_EPSILON || (this->vel_max < DYNA_VEL_START && Geom::L2(force) < DYNA_EPSILON_START)) { return FALSE; } - dc->acc = force / mass; + this->acc = force / mass; /* Calculate new velocity */ - dc->vel += dc->acc; + this->vel += this->acc; - if (Geom::L2(dc->vel) > dc->vel_max) - dc->vel_max = Geom::L2(dc->vel); + if (Geom::L2(this->vel) > this->vel_max) + this->vel_max = Geom::L2(this->vel); /* Calculate angle of drawing tool */ double a1; - if (dc->usetilt) { + if (this->usetilt) { // 1a. calculate nib angle from input device tilt: - gdouble length = std::sqrt(dc->xtilt*dc->xtilt + dc->ytilt*dc->ytilt);; + gdouble length = std::sqrt(this->xtilt*this->xtilt + this->ytilt*this->ytilt);; if (length > 0) { - Geom::Point ang1 = Geom::Point(dc->ytilt/length, dc->xtilt/length); + Geom::Point ang1 = Geom::Point(this->ytilt/length, this->xtilt/length); a1 = atan2(ang1); } else @@ -346,17 +309,17 @@ sp_dyna_draw_apply(SPDynaDrawContext *dc, Geom::Point p) } else { // 1b. fixed dc->angle (absolutely flat nib): - double const radians = ( (dc->angle - 90) / 180.0 ) * M_PI; + double const radians = ( (this->angle - 90) / 180.0 ) * M_PI; Geom::Point ang1 = Geom::Point(-sin(radians), cos(radians)); a1 = atan2(ang1); } // 2. perpendicular to dc->vel (absolutely non-flat nib): - gdouble const mag_vel = Geom::L2(dc->vel); + gdouble const mag_vel = Geom::L2(this->vel); if ( mag_vel < DYNA_EPSILON ) { return FALSE; } - Geom::Point ang2 = Geom::rot90(dc->vel) / mag_vel; + Geom::Point ang2 = Geom::rot90(this->vel) / mag_vel; // 3. Average them using flatness parameter: // calculate angles @@ -374,53 +337,51 @@ sp_dyna_draw_apply(SPDynaDrawContext *dc, Geom::Point p) a2 += 2*M_PI; // find the flatness-weighted bisector angle, unflip if a2 was flipped // FIXME: when dc->vel is oscillating around the fixed angle, the new_ang flips back and forth. How to avoid this? - double new_ang = a1 + (1 - dc->flatness) * (a2 - a1) - (flipped? M_PI : 0); + double new_ang = a1 + (1 - this->flatness) * (a2 - a1) - (flipped? M_PI : 0); // Try to detect a sudden flip when the new angle differs too much from the previous for the // current velocity; in that case discard this move - double angle_delta = Geom::L2(Geom::Point (cos (new_ang), sin (new_ang)) - dc->ang); - if ( angle_delta / Geom::L2(dc->vel) > 4000 ) { + double angle_delta = Geom::L2(Geom::Point (cos (new_ang), sin (new_ang)) - this->ang); + if ( angle_delta / Geom::L2(this->vel) > 4000 ) { return FALSE; } // convert to point - dc->ang = Geom::Point (cos (new_ang), sin (new_ang)); + this->ang = Geom::Point (cos (new_ang), sin (new_ang)); // g_print ("force %g acc %g vel_max %g vel %g a1 %g a2 %g new_ang %g\n", Geom::L2(force), Geom::L2(dc->acc), dc->vel_max, Geom::L2(dc->vel), a1, a2, new_ang); /* Apply drag */ - dc->vel *= 1.0 - drag; + this->vel *= 1.0 - drag; /* Update position */ - dc->last = dc->cur; - dc->cur += dc->vel; + this->last = this->cur; + this->cur += this->vel; return TRUE; } -static void -sp_dyna_draw_brush(SPDynaDrawContext *dc) -{ - g_assert( dc->npoints >= 0 && dc->npoints < SAMPLING_SIZE ); +void SPDynaDrawContext::brush() { + g_assert( this->npoints >= 0 && this->npoints < SAMPLING_SIZE ); // How much velocity thins strokestyle - double vel_thin = flerp (0, 160, dc->vel_thin); + double vel_thin = flerp (0, 160, this->vel_thin); // Influence of pressure on thickness - double pressure_thick = (dc->usepressure ? dc->pressure : 1.0); + double pressure_thick = (this->usepressure ? this->pressure : 1.0); // get the real brush point, not the same as pointer (affected by hatch tracking and/or mass // drag) - Geom::Point brush = sp_dyna_draw_get_vpoint(dc, dc->cur); - Geom::Point brush_w = SP_EVENT_CONTEXT(dc)->desktop->d2w(brush); + Geom::Point brush = this->getViewPoint(this->cur); + Geom::Point brush_w = SP_EVENT_CONTEXT(this)->desktop->d2w(brush); double trace_thick = 1; - if (dc->trace_bg) { + if (this->trace_bg) { // pick single pixel double R, G, B, A; Geom::IntRect area = Geom::IntRect::from_xywh(brush_w.floor(), Geom::IntPoint(1, 1)); cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); - sp_canvas_arena_render_surface(SP_CANVAS_ARENA(sp_desktop_drawing(SP_EVENT_CONTEXT(dc)->desktop)), s, area); + sp_canvas_arena_render_surface(SP_CANVAS_ARENA(sp_desktop_drawing(SP_EVENT_CONTEXT(this)->desktop)), s, area); ink_cairo_surface_average_color_premul(s, R, G, B, A); cairo_surface_destroy(s); double max = MAX (MAX (R, G), B); @@ -430,10 +391,10 @@ sp_dyna_draw_brush(SPDynaDrawContext *dc) //g_print ("L %g thick %g\n", L, trace_thick); } - double width = (pressure_thick * trace_thick - vel_thin * Geom::L2(dc->vel)) * dc->width; + double width = (pressure_thick * trace_thick - vel_thin * Geom::L2(this->vel)) * this->width; double tremble_left = 0, tremble_right = 0; - if (dc->tremor > 0) { + if (this->tremor > 0) { // obtain two normally distributed random variables, using polar Box-Muller transform double x1, x2, w, y1, y2; do { @@ -450,28 +411,28 @@ sp_dyna_draw_brush(SPDynaDrawContext *dc) // (2) deflection depends on width, but is upped for small widths for better visual uniformity across widths; // (3) deflection somewhat depends on speed, to prevent fast strokes looking // comparatively smooth and slow ones excessively jittery - tremble_left = (y1)*dc->tremor * (0.15 + 0.8*width) * (0.35 + 14*Geom::L2(dc->vel)); - tremble_right = (y2)*dc->tremor * (0.15 + 0.8*width) * (0.35 + 14*Geom::L2(dc->vel)); + tremble_left = (y1)*this->tremor * (0.15 + 0.8*width) * (0.35 + 14*Geom::L2(this->vel)); + tremble_right = (y2)*this->tremor * (0.15 + 0.8*width) * (0.35 + 14*Geom::L2(this->vel)); } - if ( width < 0.02 * dc->width ) { - width = 0.02 * dc->width; + if ( width < 0.02 * this->width ) { + width = 0.02 * this->width; } double dezoomify_factor = 0.05 * 1000; - if (!dc->abs_width) { - dezoomify_factor /= SP_EVENT_CONTEXT(dc)->desktop->current_zoom(); + if (!this->abs_width) { + dezoomify_factor /= SP_EVENT_CONTEXT(this)->desktop->current_zoom(); } - Geom::Point del_left = dezoomify_factor * (width + tremble_left) * dc->ang; - Geom::Point del_right = dezoomify_factor * (width + tremble_right) * dc->ang; + Geom::Point del_left = dezoomify_factor * (width + tremble_left) * this->ang; + Geom::Point del_right = dezoomify_factor * (width + tremble_right) * this->ang; - dc->point1[dc->npoints] = brush + del_left; - dc->point2[dc->npoints] = brush - del_right; + this->point1[this->npoints] = brush + del_left; + this->point2[this->npoints] = brush - del_right; - dc->del = 0.5*(del_left + del_right); + this->del = 0.5*(del_left + del_right); - dc->npoints++; + this->npoints++; } static void @@ -480,53 +441,45 @@ sp_ddc_update_toolbox (SPDesktop *desktop, const gchar *id, double value) desktop->setToolboxAdjustmentValue (id, value); } -static void -calligraphic_cancel(SPDynaDrawContext *dc) -{ - SPDesktop *desktop = SP_EVENT_CONTEXT(dc)->desktop; - dc->dragging = FALSE; - dc->is_drawing = false; +void SPDynaDrawContext::cancel() { + this->dragging = false; + this->is_drawing = false; + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0); - /* Remove all temporary line segments */ - while (dc->segments) { - sp_canvas_item_destroy(SP_CANVAS_ITEM(dc->segments->data)); - dc->segments = g_slist_remove(dc->segments, dc->segments->data); - } - /* reset accumulated curve */ - dc->accumulated->reset(); - clear_current(dc); - if (dc->repr) { - dc->repr = NULL; - } -} + /* Remove all temporary line segments */ + while (this->segments) { + sp_canvas_item_destroy(SP_CANVAS_ITEM(this->segments->data)); + this->segments = g_slist_remove(this->segments, this->segments->data); + } -gint -sp_dyna_draw_context_root_handler(SPEventContext *event_context, - GdkEvent *event) -{ - SPDynaDrawContext *dc = SP_DYNA_DRAW_CONTEXT(event_context); - SPDesktop *desktop = event_context->desktop; + /* reset accumulated curve */ + this->accumulated->reset(); + this->clear_current(); + if (this->repr) { + this->repr = NULL; + } +} + +bool SPDynaDrawContext::root_handler(GdkEvent* event) { gint ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { - - SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(dc); - - if (Inkscape::have_viable_layer(desktop, dc->_message_context) == false) { + if (event->button.button == 1 && !this->space_panning) { + if (Inkscape::have_viable_layer(desktop, this->message_context) == false) { return TRUE; } - dc->accumulated->reset(); - if (dc->repr) { - dc->repr = NULL; + this->accumulated->reset(); + + if (this->repr) { + this->repr = NULL; } /* initialize first point */ - dc->npoints = 0; + this->npoints = 0; sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), ( GDK_KEY_PRESS_MASK | @@ -539,8 +492,8 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, ret = TRUE; desktop->canvas->forceFullRedrawAfterInterruptions(3); - dc->is_drawing = true; - dc->just_started_drawing = true; + this->is_drawing = true; + this->just_started_drawing = true; } break; case GDK_MOTION_NOTIFY: @@ -548,9 +501,9 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point motion_dt(desktop->w2d(motion_w)); - sp_dyna_draw_extinput(dc, event); + this->extinput(event); - dc->_message_context->clear(); + this->message_context->clear(); // for hatching: double hatch_dist = 0; @@ -566,12 +519,12 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, // One item selected, and it's a path; // let's try to track it as a guide - if (selected != dc->hatch_item) { - dc->hatch_item = selected; - if (dc->hatch_livarot_path) - delete dc->hatch_livarot_path; - dc->hatch_livarot_path = Path_for_item (dc->hatch_item, true, true); - dc->hatch_livarot_path->ConvertWithBackData(0.01); + if (selected != this->hatch_item) { + this->hatch_item = selected; + if (this->hatch_livarot_path) + delete this->hatch_livarot_path; + this->hatch_livarot_path = Path_for_item (this->hatch_item, true, true); + this->hatch_livarot_path->ConvertWithBackData(0.01); } // calculate pointer point in the guide item's coords @@ -579,8 +532,8 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, pointer = motion_dt * motion_to_curve; // calculate the nearest point on the guide path - boost::optional<Path::cut_position> position = get_nearest_position_on_Path(dc->hatch_livarot_path, pointer); - nearest = get_point_on_Path(dc->hatch_livarot_path, position->piece, position->t); + boost::optional<Path::cut_position> position = get_nearest_position_on_Path(this->hatch_livarot_path, pointer); + nearest = get_point_on_Path(this->hatch_livarot_path, position->piece, position->t); // distance from pointer to nearest @@ -588,16 +541,16 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, // unit-length vector hatch_unit_vector = (pointer - nearest)/hatch_dist; - dc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Guide path selected</b>; start drawing along the guide with <b>Ctrl</b>")); + this->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Guide path selected</b>; start drawing along the guide with <b>Ctrl</b>")); } else { - dc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Select a guide path</b> to track with <b>Ctrl</b>")); + this->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Select a guide path</b> to track with <b>Ctrl</b>")); } } - if ( dc->is_drawing && (event->motion.state & GDK_BUTTON1_MASK) && !event_context->space_panning) { - dc->dragging = TRUE; + if ( this->is_drawing && (event->motion.state & GDK_BUTTON1_MASK) && !this->space_panning) { + this->dragging = TRUE; - if (event->motion.state & GDK_CONTROL_MASK && dc->hatch_item) { // hatching + if (event->motion.state & GDK_CONTROL_MASK && this->hatch_item) { // hatching #define HATCH_VECTOR_ELEMENTS 12 #define INERTIA_ELEMENTS 24 @@ -619,33 +572,33 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, // mass recommended; with zero mass, jerks are still quite noticeable). double speed = 1; - if (Geom::L2(dc->hatch_last_nearest) != 0) { + if (Geom::L2(this->hatch_last_nearest) != 0) { // the distance nearest moved since the last motion event - double nearest_moved = Geom::L2(nearest - dc->hatch_last_nearest); + double nearest_moved = Geom::L2(nearest - this->hatch_last_nearest); // the distance pointer moved since the last motion event - double pointer_moved = Geom::L2(pointer - dc->hatch_last_pointer); + double pointer_moved = Geom::L2(pointer - this->hatch_last_pointer); // store them in stacks limited to SPEED_ELEMENTS - dc->hatch_nearest_past.push_front(nearest_moved); - if (dc->hatch_nearest_past.size() > SPEED_ELEMENTS) - dc->hatch_nearest_past.pop_back(); - dc->hatch_pointer_past.push_front(pointer_moved); - if (dc->hatch_pointer_past.size() > SPEED_ELEMENTS) - dc->hatch_pointer_past.pop_back(); + this->hatch_nearest_past.push_front(nearest_moved); + if (this->hatch_nearest_past.size() > SPEED_ELEMENTS) + this->hatch_nearest_past.pop_back(); + this->hatch_pointer_past.push_front(pointer_moved); + if (this->hatch_pointer_past.size() > SPEED_ELEMENTS) + this->hatch_pointer_past.pop_back(); // If the stacks are full, - if (dc->hatch_nearest_past.size() == SPEED_ELEMENTS) { + if (this->hatch_nearest_past.size() == SPEED_ELEMENTS) { // calculate the sums of all stored movements - double nearest_sum = std::accumulate (dc->hatch_nearest_past.begin(), dc->hatch_nearest_past.end(), 0.0); - double pointer_sum = std::accumulate (dc->hatch_pointer_past.begin(), dc->hatch_pointer_past.end(), 0.0); + double nearest_sum = std::accumulate (this->hatch_nearest_past.begin(), this->hatch_nearest_past.end(), 0.0); + double pointer_sum = std::accumulate (this->hatch_pointer_past.begin(), this->hatch_pointer_past.end(), 0.0); // and divide to get the speed speed = nearest_sum/pointer_sum; //g_print ("nearest sum %g pointer_sum %g speed %g\n", nearest_sum, pointer_sum, speed); } } - if ( dc->hatch_escaped // already escaped, do not reattach + if ( this->hatch_escaped // already escaped, do not reattach || (speed < SPEED_MIN) // stuck; most likely reached end of traced stroke - || (dc->hatch_spacing > 0 && hatch_dist > 50 * dc->hatch_spacing) // went too far from the guide + || (this->hatch_spacing > 0 && hatch_dist > 50 * this->hatch_spacing) // went too far from the guide ) { // We are NOT attracted to the guide! @@ -653,12 +606,12 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, // Remember hatch_escaped so we don't get // attracted again until the end of this stroke - dc->hatch_escaped = true; + this->hatch_escaped = true; - if (dc->inertia_vectors.size() >= INERTIA_ELEMENTS/2) { // move by inertia - Geom::Point moved_past_escape = motion_dt - dc->inertia_vectors.front(); + if (this->inertia_vectors.size() >= INERTIA_ELEMENTS/2) { // move by inertia + Geom::Point moved_past_escape = motion_dt - this->inertia_vectors.front(); Geom::Point inertia = - dc->inertia_vectors.front() - dc->inertia_vectors.back(); + this->inertia_vectors.front() - this->inertia_vectors.back(); double dot = Geom::dot (moved_past_escape, inertia); dot /= Geom::L2(moved_past_escape) * Geom::L2(inertia); @@ -666,7 +619,7 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, if (dot > 0) { // mouse is still moving in approx the same direction Geom::Point should_have_moved = (inertia) * (1/Geom::L2(inertia)) * Geom::L2(moved_past_escape); - motion_dt = dc->inertia_vectors.front() + + motion_dt = this->inertia_vectors.front() + (INERTIA_FORCE * should_have_moved + (1 - INERTIA_FORCE) * moved_past_escape); } } @@ -677,19 +630,19 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, // summed, to detect if we accidentally flipped to the other side of the // guide Geom::Point hatch_vector_accumulated = std::accumulate - (dc->hatch_vectors.begin(), dc->hatch_vectors.end(), Geom::Point(0,0)); + (this->hatch_vectors.begin(), this->hatch_vectors.end(), Geom::Point(0,0)); double dot = Geom::dot (pointer - nearest, hatch_vector_accumulated); dot /= Geom::L2(pointer - nearest) * Geom::L2(hatch_vector_accumulated); - if (dc->hatch_spacing != 0) { // spacing was already set + if (this->hatch_spacing != 0) { // spacing was already set double target; if (speed > SPEED_NORMAL) { // all ok, strictly obey the spacing - target = dc->hatch_spacing; + target = this->hatch_spacing; } else { // looks like we're starting to lose speed, // so _gradually_ let go attraction to prevent jerks - target = (dc->hatch_spacing * speed + hatch_dist * (SPEED_NORMAL - speed))/SPEED_NORMAL; + target = (this->hatch_spacing * speed + hatch_dist * (SPEED_NORMAL - speed))/SPEED_NORMAL; } if (!IS_NAN(dot) && dot < -0.5) {// flip target = -target; @@ -700,91 +653,91 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, // some limited feedback: allow persistent pulling to slightly change // the spacing - dc->hatch_spacing += (hatch_dist - dc->hatch_spacing)/3500; + this->hatch_spacing += (hatch_dist - this->hatch_spacing)/3500; // return it to the desktop coords motion_dt = new_pointer * motion_to_curve.inverse(); if (speed >= SPEED_NORMAL) { - dc->inertia_vectors.push_front(motion_dt); - if (dc->inertia_vectors.size() > INERTIA_ELEMENTS) - dc->inertia_vectors.pop_back(); + this->inertia_vectors.push_front(motion_dt); + if (this->inertia_vectors.size() > INERTIA_ELEMENTS) + this->inertia_vectors.pop_back(); } } else { // this is the first motion event, set the dist - dc->hatch_spacing = hatch_dist; + this->hatch_spacing = hatch_dist; } // remember last points - dc->hatch_last_pointer = pointer; - dc->hatch_last_nearest = nearest; + this->hatch_last_pointer = pointer; + this->hatch_last_nearest = nearest; - dc->hatch_vectors.push_front(pointer - nearest); - if (dc->hatch_vectors.size() > HATCH_VECTOR_ELEMENTS) - dc->hatch_vectors.pop_back(); + this->hatch_vectors.push_front(pointer - nearest); + if (this->hatch_vectors.size() > HATCH_VECTOR_ELEMENTS) + this->hatch_vectors.pop_back(); } - dc->_message_context->set(Inkscape::NORMAL_MESSAGE, dc->hatch_escaped? _("Tracking: <b>connection to guide path lost!</b>") : _("<b>Tracking</b> a guide path")); + this->message_context->set(Inkscape::NORMAL_MESSAGE, this->hatch_escaped? _("Tracking: <b>connection to guide path lost!</b>") : _("<b>Tracking</b> a guide path")); } else { - dc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Drawing</b> a calligraphic stroke")); + this->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Drawing</b> a calligraphic stroke")); } - if (dc->just_started_drawing) { - dc->just_started_drawing = false; - sp_dyna_draw_reset(dc, motion_dt); + if (this->just_started_drawing) { + this->just_started_drawing = false; + this->reset(motion_dt); } - if (!sp_dyna_draw_apply(dc, motion_dt)) { + if (!this->apply(motion_dt)) { ret = TRUE; break; } - if ( dc->cur != dc->last ) { - sp_dyna_draw_brush(dc); - g_assert( dc->npoints > 0 ); - fit_and_split(dc, FALSE); + if ( this->cur != this->last ) { + this->brush(); + g_assert( this->npoints > 0 ); + this->fit_and_split(false); } ret = TRUE; } // Draw the hatching circle if necessary if (event->motion.state & GDK_CONTROL_MASK) { - if (dc->hatch_spacing == 0 && hatch_dist != 0) { + if (this->hatch_spacing == 0 && hatch_dist != 0) { // Haven't set spacing yet: gray, center free, update radius live Geom::Point c = desktop->w2d(motion_w); Geom::Affine const sm (Geom::Scale(hatch_dist, hatch_dist) * Geom::Translate(c)); - sp_canvas_item_affine_absolute(dc->hatch_area, sm); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->hatch_area), 0x7f7f7fff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - sp_canvas_item_show(dc->hatch_area); - } else if (dc->dragging && !dc->hatch_escaped) { + sp_canvas_item_affine_absolute(this->hatch_area, sm); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->hatch_area), 0x7f7f7fff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); + sp_canvas_item_show(this->hatch_area); + } else if (this->dragging && !this->hatch_escaped) { // Tracking: green, center snapped, fixed radius Geom::Point c = motion_dt; - Geom::Affine const sm (Geom::Scale(dc->hatch_spacing, dc->hatch_spacing) * Geom::Translate(c)); - sp_canvas_item_affine_absolute(dc->hatch_area, sm); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->hatch_area), 0x00FF00ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - sp_canvas_item_show(dc->hatch_area); - } else if (dc->dragging && dc->hatch_escaped) { + Geom::Affine const sm (Geom::Scale(this->hatch_spacing, this->hatch_spacing) * Geom::Translate(c)); + sp_canvas_item_affine_absolute(this->hatch_area, sm); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->hatch_area), 0x00FF00ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); + sp_canvas_item_show(this->hatch_area); + } else if (this->dragging && this->hatch_escaped) { // Tracking escaped: red, center free, fixed radius Geom::Point c = motion_dt; - Geom::Affine const sm (Geom::Scale(dc->hatch_spacing, dc->hatch_spacing) * Geom::Translate(c)); + Geom::Affine const sm (Geom::Scale(this->hatch_spacing, this->hatch_spacing) * Geom::Translate(c)); - sp_canvas_item_affine_absolute(dc->hatch_area, sm); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->hatch_area), 0xFF0000ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - sp_canvas_item_show(dc->hatch_area); + sp_canvas_item_affine_absolute(this->hatch_area, sm); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->hatch_area), 0xFF0000ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); + sp_canvas_item_show(this->hatch_area); } else { // Not drawing but spacing set: gray, center snapped, fixed radius - Geom::Point c = (nearest + dc->hatch_spacing * hatch_unit_vector) * motion_to_curve.inverse(); + Geom::Point c = (nearest + this->hatch_spacing * hatch_unit_vector) * motion_to_curve.inverse(); if (!IS_NAN(c[Geom::X]) && !IS_NAN(c[Geom::Y])) { - Geom::Affine const sm (Geom::Scale(dc->hatch_spacing, dc->hatch_spacing) * Geom::Translate(c)); - sp_canvas_item_affine_absolute(dc->hatch_area, sm); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->hatch_area), 0x7f7f7fff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - sp_canvas_item_show(dc->hatch_area); + Geom::Affine const sm (Geom::Scale(this->hatch_spacing, this->hatch_spacing) * Geom::Translate(c)); + sp_canvas_item_affine_absolute(this->hatch_area, sm); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->hatch_area), 0x7f7f7fff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); + sp_canvas_item_show(this->hatch_area); } } } else { - sp_canvas_item_hide(dc->hatch_area); + sp_canvas_item_hide(this->hatch_area); } } break; @@ -797,54 +750,54 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); desktop->canvas->endForcedFullRedraws(); - dc->is_drawing = false; + this->is_drawing = false; - if (dc->dragging && event->button.button == 1 && !event_context->space_panning) { - dc->dragging = FALSE; + if (this->dragging && event->button.button == 1 && !this->space_panning) { + this->dragging = FALSE; - sp_dyna_draw_apply(dc, motion_dt); + this->apply(motion_dt); /* Remove all temporary line segments */ - while (dc->segments) { - sp_canvas_item_destroy(SP_CANVAS_ITEM(dc->segments->data)); - dc->segments = g_slist_remove(dc->segments, dc->segments->data); + while (this->segments) { + sp_canvas_item_destroy(SP_CANVAS_ITEM(this->segments->data)); + this->segments = g_slist_remove(this->segments, this->segments->data); } /* Create object */ - fit_and_split(dc, TRUE); - if (accumulate_calligraphic(dc)) - set_to_accumulated(dc, event->button.state & GDK_SHIFT_MASK, event->button.state & GDK_MOD1_MASK); // performs document_done + this->fit_and_split(true); + if (this->accumulate()) + this->set_to_accumulated(event->button.state & GDK_SHIFT_MASK, event->button.state & GDK_MOD1_MASK); // performs document_done else g_warning ("Failed to create path: invalid data in dc->cal1 or dc->cal2"); /* reset accumulated curve */ - dc->accumulated->reset(); + this->accumulated->reset(); - clear_current(dc); - if (dc->repr) { - dc->repr = NULL; + this->clear_current(); + if (this->repr) { + this->repr = NULL; } - if (!dc->hatch_pointer_past.empty()) dc->hatch_pointer_past.clear(); - if (!dc->hatch_nearest_past.empty()) dc->hatch_nearest_past.clear(); - if (!dc->inertia_vectors.empty()) dc->inertia_vectors.clear(); - if (!dc->hatch_vectors.empty()) dc->hatch_vectors.clear(); - dc->hatch_last_nearest = Geom::Point(0,0); - dc->hatch_last_pointer = Geom::Point(0,0); - dc->hatch_escaped = false; - dc->hatch_item = NULL; - dc->hatch_livarot_path = NULL; - dc->just_started_drawing = false; - - if (dc->hatch_spacing != 0 && !dc->keep_selected) { + if (!this->hatch_pointer_past.empty()) this->hatch_pointer_past.clear(); + if (!this->hatch_nearest_past.empty()) this->hatch_nearest_past.clear(); + if (!this->inertia_vectors.empty()) this->inertia_vectors.clear(); + if (!this->hatch_vectors.empty()) this->hatch_vectors.clear(); + this->hatch_last_nearest = Geom::Point(0,0); + this->hatch_last_pointer = Geom::Point(0,0); + this->hatch_escaped = false; + this->hatch_item = NULL; + this->hatch_livarot_path = NULL; + this->just_started_drawing = false; + + if (this->hatch_spacing != 0 && !this->keep_selected) { // we do not select the newly drawn path, so increase spacing by step - if (dc->hatch_spacing_step == 0) { - dc->hatch_spacing_step = dc->hatch_spacing; + if (this->hatch_spacing_step == 0) { + this->hatch_spacing_step = this->hatch_spacing; } - dc->hatch_spacing += dc->hatch_spacing_step; + this->hatch_spacing += this->hatch_spacing_step; } - dc->_message_context->clear(); + this->message_context->clear(); ret = TRUE; } break; @@ -855,53 +808,53 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, case GDK_KEY_Up: case GDK_KEY_KP_Up: if (!MOD__CTRL_ONLY(event)) { - dc->angle += 5.0; - if (dc->angle > 90.0) - dc->angle = 90.0; - sp_ddc_update_toolbox (desktop, "calligraphy-angle", dc->angle); + this->angle += 5.0; + if (this->angle > 90.0) + this->angle = 90.0; + sp_ddc_update_toolbox (desktop, "calligraphy-angle", this->angle); ret = TRUE; } break; case GDK_KEY_Down: case GDK_KEY_KP_Down: if (!MOD__CTRL_ONLY(event)) { - dc->angle -= 5.0; - if (dc->angle < -90.0) - dc->angle = -90.0; - sp_ddc_update_toolbox (desktop, "calligraphy-angle", dc->angle); + this->angle -= 5.0; + if (this->angle < -90.0) + this->angle = -90.0; + sp_ddc_update_toolbox (desktop, "calligraphy-angle", this->angle); ret = TRUE; } break; case GDK_KEY_Right: case GDK_KEY_KP_Right: if (!MOD__CTRL_ONLY(event)) { - dc->width += 0.01; - if (dc->width > 1.0) - dc->width = 1.0; - sp_ddc_update_toolbox (desktop, "altx-calligraphy", dc->width * 100); // the same spinbutton is for alt+x + this->width += 0.01; + if (this->width > 1.0) + this->width = 1.0; + sp_ddc_update_toolbox (desktop, "altx-calligraphy", this->width * 100); // the same spinbutton is for alt+x ret = TRUE; } break; case GDK_KEY_Left: case GDK_KEY_KP_Left: if (!MOD__CTRL_ONLY(event)) { - dc->width -= 0.01; - if (dc->width < 0.01) - dc->width = 0.01; - sp_ddc_update_toolbox (desktop, "altx-calligraphy", dc->width * 100); + this->width -= 0.01; + if (this->width < 0.01) + this->width = 0.01; + sp_ddc_update_toolbox (desktop, "altx-calligraphy", this->width * 100); ret = TRUE; } break; case GDK_KEY_Home: case GDK_KEY_KP_Home: - dc->width = 0.01; - sp_ddc_update_toolbox (desktop, "altx-calligraphy", dc->width * 100); + this->width = 0.01; + sp_ddc_update_toolbox (desktop, "altx-calligraphy", this->width * 100); ret = TRUE; break; case GDK_KEY_End: case GDK_KEY_KP_End: - dc->width = 1.0; - sp_ddc_update_toolbox (desktop, "altx-calligraphy", dc->width * 100); + this->width = 1.0; + sp_ddc_update_toolbox (desktop, "altx-calligraphy", this->width * 100); ret = TRUE; break; case GDK_KEY_x: @@ -912,17 +865,17 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, } break; case GDK_KEY_Escape: - if (dc->is_drawing) { + if (this->is_drawing) { // if drawing, cancel, otherwise pass it up for deselecting - calligraphic_cancel (dc); + this->cancel(); ret = TRUE; } break; case GDK_KEY_z: case GDK_KEY_Z: - if (MOD__CTRL_ONLY(event) && dc->is_drawing) { + if (MOD__CTRL_ONLY(event) && this->is_drawing) { // if drawing, cancel, otherwise pass it up for undo - calligraphic_cancel (dc); + this->cancel(); ret = TRUE; } break; @@ -935,48 +888,44 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, switch (get_group0_keyval(&event->key)) { case GDK_KEY_Control_L: case GDK_KEY_Control_R: - dc->_message_context->clear(); - dc->hatch_spacing = 0; - dc->hatch_spacing_step = 0; + this->message_context->clear(); + this->hatch_spacing = 0; + this->hatch_spacing_step = 0; break; default: break; } + break; default: break; } if (!ret) { - if ((SP_EVENT_CONTEXT_CLASS(sp_dyna_draw_context_parent_class))->root_handler) { - ret = (SP_EVENT_CONTEXT_CLASS(sp_dyna_draw_context_parent_class))->root_handler(event_context, event); - } +// if ((SP_EVENT_CONTEXT_CLASS(sp_dyna_draw_context_parent_class))->root_handler) { +// ret = (SP_EVENT_CONTEXT_CLASS(sp_dyna_draw_context_parent_class))->root_handler(event_context, event); +// } + ret = SPCommonContext::root_handler(event); } return ret; } -static void -clear_current(SPDynaDrawContext *dc) -{ +void SPDynaDrawContext::clear_current() { /* reset bpath */ - sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(dc->currentshape), NULL); + sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(this->currentshape), NULL); /* reset curve */ - dc->currentcurve->reset(); - dc->cal1->reset(); - dc->cal2->reset(); + this->currentcurve->reset(); + this->cal1->reset(); + this->cal2->reset(); /* reset points */ - dc->npoints = 0; + this->npoints = 0; } -static void -set_to_accumulated(SPDynaDrawContext *dc, bool unionize, bool subtract) -{ - SPDesktop *desktop = SP_EVENT_CONTEXT(dc)->desktop; - - if (!dc->accumulated->is_empty()) { - if (!dc->repr) { +void SPDynaDrawContext::set_to_accumulated(bool unionize, bool subtract) { + if (!this->accumulated->is_empty()) { + if (!this->repr) { /* Create object */ Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); @@ -984,36 +933,37 @@ set_to_accumulated(SPDynaDrawContext *dc, bool unionize, bool subtract) /* Set style */ sp_desktop_apply_style_tool (desktop, repr, "/tools/calligraphic", false); - dc->repr = repr; + this->repr = repr; - SPItem *item=SP_ITEM(desktop->currentLayer()->appendChildRepr(dc->repr)); - Inkscape::GC::release(dc->repr); + SPItem *item=SP_ITEM(desktop->currentLayer()->appendChildRepr(this->repr)); + Inkscape::GC::release(this->repr); item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); item->updateRepr(); } - Geom::PathVector pathv = dc->accumulated->get_pathvector() * desktop->dt2doc(); + + Geom::PathVector pathv = this->accumulated->get_pathvector() * desktop->dt2doc(); gchar *str = sp_svg_write_path(pathv); g_assert( str != NULL ); - dc->repr->setAttribute("d", str); + this->repr->setAttribute("d", str); g_free(str); if (unionize) { - sp_desktop_selection(desktop)->add(dc->repr); + sp_desktop_selection(desktop)->add(this->repr); sp_selected_path_union_skip_undo(sp_desktop_selection(desktop), desktop); } else if (subtract) { - sp_desktop_selection(desktop)->add(dc->repr); + sp_desktop_selection(desktop)->add(this->repr); sp_selected_path_diff_skip_undo(sp_desktop_selection(desktop), desktop); } else { - if (dc->keep_selected) { - sp_desktop_selection(desktop)->set(dc->repr); + if (this->keep_selected) { + sp_desktop_selection(desktop)->set(this->repr); } } - } else { - if (dc->repr) { - sp_repr_unparent(dc->repr); + if (this->repr) { + sp_repr_unparent(this->repr); } - dc->repr = NULL; + + this->repr = NULL; } DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_CALLIGRAPHIC, @@ -1035,54 +985,54 @@ add_cap(SPCurve *curve, } } -static bool -accumulate_calligraphic(SPDynaDrawContext *dc) -{ - if ( - dc->cal1->is_empty() || - dc->cal2->is_empty() || - (dc->cal1->get_segment_count() <= 0) || - dc->cal1->first_path()->closed() - ) { - dc->cal1->reset(); - dc->cal2->reset(); - return false; // failure - } +bool SPDynaDrawContext::accumulate() { + if ( + this->cal1->is_empty() || + this->cal2->is_empty() || + (this->cal1->get_segment_count() <= 0) || + this->cal1->first_path()->closed() + ) { - SPCurve *rev_cal2 = dc->cal2->create_reverse(); - if ( - (rev_cal2->get_segment_count() <= 0) || - rev_cal2->first_path()->closed() - ) { - rev_cal2->unref(); - dc->cal1->reset(); - dc->cal2->reset(); - return false; // failure - } + this->cal1->reset(); + this->cal2->reset(); + + return false; // failure + } + + SPCurve *rev_cal2 = this->cal2->create_reverse(); + + if ((rev_cal2->get_segment_count() <= 0) || rev_cal2->first_path()->closed()) { + rev_cal2->unref(); - Geom::Curve const * dc_cal1_firstseg = dc->cal1->first_segment(); - Geom::Curve const * rev_cal2_firstseg = rev_cal2->first_segment(); - Geom::Curve const * dc_cal1_lastseg = dc->cal1->last_segment(); - Geom::Curve const * rev_cal2_lastseg = rev_cal2->last_segment(); + this->cal1->reset(); + this->cal2->reset(); - dc->accumulated->reset(); /* Is this required ?? */ + return false; // failure + } - dc->accumulated->append(dc->cal1, false); + Geom::Curve const * dc_cal1_firstseg = this->cal1->first_segment(); + Geom::Curve const * rev_cal2_firstseg = rev_cal2->first_segment(); + Geom::Curve const * dc_cal1_lastseg = this->cal1->last_segment(); + Geom::Curve const * rev_cal2_lastseg = rev_cal2->last_segment(); - add_cap(dc->accumulated, dc_cal1_lastseg->finalPoint(), rev_cal2_firstseg->initialPoint(), dc->cap_rounding); + this->accumulated->reset(); /* Is this required ?? */ - dc->accumulated->append(rev_cal2, true); + this->accumulated->append(this->cal1, false); - add_cap(dc->accumulated, rev_cal2_lastseg->finalPoint(), dc_cal1_firstseg->initialPoint(), dc->cap_rounding); + add_cap(this->accumulated, dc_cal1_lastseg->finalPoint(), rev_cal2_firstseg->initialPoint(), this->cap_rounding); - dc->accumulated->closepath(); + this->accumulated->append(rev_cal2, true); - rev_cal2->unref(); + add_cap(this->accumulated, rev_cal2_lastseg->finalPoint(), dc_cal1_firstseg->initialPoint(), this->cap_rounding); - dc->cal1->reset(); - dc->cal2->reset(); + this->accumulated->closepath(); - return true; // success + rev_cal2->unref(); + + this->cal1->reset(); + this->cal2->reset(); + + return true; // success } static double square(double const x) @@ -1090,48 +1040,45 @@ static double square(double const x) return x * x; } -static void -fit_and_split(SPDynaDrawContext *dc, gboolean release) -{ - SPDesktop *desktop = SP_EVENT_CONTEXT(dc)->desktop; - +void SPDynaDrawContext::fit_and_split(bool release) { double const tolerance_sq = square( desktop->w2d().descrim() * TOLERANCE_CALLIGRAPHIC ); #ifdef DYNA_DRAW_VERBOSE g_print("[F&S:R=%c]", release?'T':'F'); #endif - if (!( dc->npoints > 0 && dc->npoints < SAMPLING_SIZE )) + if (!( this->npoints > 0 && this->npoints < SAMPLING_SIZE )) { return; // just clicked + } - if ( dc->npoints == SAMPLING_SIZE - 1 || release ) { + if ( this->npoints == SAMPLING_SIZE - 1 || release ) { #define BEZIER_SIZE 4 #define BEZIER_MAX_BEZIERS 8 #define BEZIER_MAX_LENGTH ( BEZIER_SIZE * BEZIER_MAX_BEZIERS ) #ifdef DYNA_DRAW_VERBOSE g_print("[F&S:#] dc->npoints:%d, release:%s\n", - dc->npoints, release ? "TRUE" : "FALSE"); + this->npoints, release ? "TRUE" : "FALSE"); #endif /* Current calligraphic */ - if ( dc->cal1->is_empty() || dc->cal2->is_empty() ) { + if ( this->cal1->is_empty() || this->cal2->is_empty() ) { /* dc->npoints > 0 */ /* g_print("calligraphics(1|2) reset\n"); */ - dc->cal1->reset(); - dc->cal2->reset(); + this->cal1->reset(); + this->cal2->reset(); - dc->cal1->moveto(dc->point1[0]); - dc->cal2->moveto(dc->point2[0]); + this->cal1->moveto(this->point1[0]); + this->cal2->moveto(this->point2[0]); } Geom::Point b1[BEZIER_MAX_LENGTH]; - gint const nb1 = Geom::bezier_fit_cubic_r(b1, dc->point1, dc->npoints, + gint const nb1 = Geom::bezier_fit_cubic_r(b1, this->point1, this->npoints, tolerance_sq, BEZIER_MAX_BEZIERS); g_assert( nb1 * BEZIER_SIZE <= gint(G_N_ELEMENTS(b1)) ); Geom::Point b2[BEZIER_MAX_LENGTH]; - gint const nb2 = Geom::bezier_fit_cubic_r(b2, dc->point2, dc->npoints, + gint const nb2 = Geom::bezier_fit_cubic_r(b2, this->point2, this->npoints, tolerance_sq, BEZIER_MAX_BEZIERS); g_assert( nb2 * BEZIER_SIZE <= gint(G_N_ELEMENTS(b2)) ); @@ -1142,56 +1089,56 @@ fit_and_split(SPDynaDrawContext *dc, gboolean release) #endif /* CanvasShape */ if (! release) { - dc->currentcurve->reset(); - dc->currentcurve->moveto(b1[0]); + this->currentcurve->reset(); + this->currentcurve->moveto(b1[0]); for (Geom::Point *bp1 = b1; bp1 < b1 + BEZIER_SIZE * nb1; bp1 += BEZIER_SIZE) { - dc->currentcurve->curveto(bp1[1], bp1[2], bp1[3]); + this->currentcurve->curveto(bp1[1], bp1[2], bp1[3]); } - dc->currentcurve->lineto(b2[BEZIER_SIZE*(nb2-1) + 3]); + this->currentcurve->lineto(b2[BEZIER_SIZE*(nb2-1) + 3]); for (Geom::Point *bp2 = b2 + BEZIER_SIZE * ( nb2 - 1 ); bp2 >= b2; bp2 -= BEZIER_SIZE) { - dc->currentcurve->curveto(bp2[2], bp2[1], bp2[0]); + this->currentcurve->curveto(bp2[2], bp2[1], bp2[0]); } // FIXME: dc->segments is always NULL at this point?? - if (!dc->segments) { // first segment - add_cap(dc->currentcurve, b2[0], b1[0], dc->cap_rounding); + if (!this->segments) { // first segment + add_cap(this->currentcurve, b2[0], b1[0], this->cap_rounding); } - dc->currentcurve->closepath(); - sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(dc->currentshape), dc->currentcurve); + this->currentcurve->closepath(); + sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(this->currentshape), this->currentcurve); } /* Current calligraphic */ for (Geom::Point *bp1 = b1; bp1 < b1 + BEZIER_SIZE * nb1; bp1 += BEZIER_SIZE) { - dc->cal1->curveto(bp1[1], bp1[2], bp1[3]); + this->cal1->curveto(bp1[1], bp1[2], bp1[3]); } for (Geom::Point *bp2 = b2; bp2 < b2 + BEZIER_SIZE * nb2; bp2 += BEZIER_SIZE) { - dc->cal2->curveto(bp2[1], bp2[2], bp2[3]); + this->cal2->curveto(bp2[1], bp2[2], bp2[3]); } } else { /* fixme: ??? */ #ifdef DYNA_DRAW_VERBOSE g_print("[fit_and_split] failed to fit-cubic.\n"); #endif - draw_temporary_box(dc); + this->draw_temporary_box(); - for (gint i = 1; i < dc->npoints; i++) { - dc->cal1->lineto(dc->point1[i]); + for (gint i = 1; i < this->npoints; i++) { + this->cal1->lineto(this->point1[i]); } - for (gint i = 1; i < dc->npoints; i++) { - dc->cal2->lineto(dc->point2[i]); + for (gint i = 1; i < this->npoints; i++) { + this->cal2->lineto(this->point2[i]); } } /* Fit and draw and copy last point */ #ifdef DYNA_DRAW_VERBOSE - g_print("[%d]Yup\n", dc->npoints); + g_print("[%d]Yup\n", this->npoints); #endif if (!release) { - g_assert(!dc->currentcurve->is_empty()); + g_assert(!this->currentcurve->is_empty()); SPCanvasItem *cbp = sp_canvas_item_new(sp_desktop_sketch(desktop), SP_TYPE_CANVAS_BPATH, NULL); - SPCurve *curve = dc->currentcurve->copy(); + SPCurve *curve = this->currentcurve->copy(); sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH (cbp), curve); curve->unref(); @@ -1207,36 +1154,36 @@ fit_and_split(SPDynaDrawContext *dc, gboolean release) /* fixme: Cannot we cascade it to root more clearly? */ g_signal_connect(G_OBJECT(cbp), "event", G_CALLBACK(sp_desktop_root_handler), desktop); - dc->segments = g_slist_prepend(dc->segments, cbp); + this->segments = g_slist_prepend(this->segments, cbp); } - dc->point1[0] = dc->point1[dc->npoints - 1]; - dc->point2[0] = dc->point2[dc->npoints - 1]; - dc->npoints = 1; + this->point1[0] = this->point1[this->npoints - 1]; + this->point2[0] = this->point2[this->npoints - 1]; + this->npoints = 1; } else { - draw_temporary_box(dc); + this->draw_temporary_box(); } } -static void -draw_temporary_box(SPDynaDrawContext *dc) -{ - dc->currentcurve->reset(); +void SPDynaDrawContext::draw_temporary_box() { + this->currentcurve->reset(); - dc->currentcurve->moveto(dc->point2[dc->npoints-1]); - for (gint i = dc->npoints-2; i >= 0; i--) { - dc->currentcurve->lineto(dc->point2[i]); + this->currentcurve->moveto(this->point2[this->npoints-1]); + + for (gint i = this->npoints-2; i >= 0; i--) { + this->currentcurve->lineto(this->point2[i]); } - for (gint i = 0; i < dc->npoints; i++) { - dc->currentcurve->lineto(dc->point1[i]); + + for (gint i = 0; i < this->npoints; i++) { + this->currentcurve->lineto(this->point1[i]); } - if (dc->npoints >= 2) { - add_cap(dc->currentcurve, dc->point1[dc->npoints-1], dc->point2[dc->npoints-1], dc->cap_rounding); + if (this->npoints >= 2) { + add_cap(this->currentcurve, this->point1[this->npoints-1], this->point2[this->npoints-1], this->cap_rounding); } - dc->currentcurve->closepath(); - sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(dc->currentshape), dc->currentcurve); + this->currentcurve->closepath(); + sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(this->currentshape), this->currentcurve); } /* diff --git a/src/dyna-draw-context.h b/src/dyna-draw-context.h index 8509e450b..36a429a8d 100644 --- a/src/dyna-draw-context.h +++ b/src/dyna-draw-context.h @@ -21,12 +21,6 @@ #include "common-context.h" #include "splivarot.h" -#define SP_TYPE_DYNA_DRAW_CONTEXT (sp_dyna_draw_context_get_type()) -#define SP_DYNA_DRAW_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_DYNA_DRAW_CONTEXT, SPDynaDrawContext)) -#define SP_DYNA_DRAW_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_DYNA_DRAW_CONTEXT, SPDynaDrawContextClass)) -#define SP_IS_DYNA_DRAW_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_DYNA_DRAW_CONTEXT)) -#define SP_IS_DYNA_DRAW_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_DYNA_DRAW_CONTEXT)) - #define DDC_MIN_PRESSURE 0.0 #define DDC_MAX_PRESSURE 1.0 #define DDC_DEFAULT_PRESSURE 1.0 @@ -35,7 +29,20 @@ #define DDC_MAX_TILT 1.0 #define DDC_DEFAULT_TILT 0.0 -struct SPDynaDrawContext : public SPCommonContext { +class SPDynaDrawContext : public SPCommonContext { +public: + SPDynaDrawContext(); + virtual ~SPDynaDrawContext(); + + static const std::string prefsPath; + + virtual void setup(); + virtual void set(const Inkscape::Preferences::Entry& val); + virtual bool root_handler(GdkEvent* event); + + virtual const std::string& getPrefsPath(); + +private: /** newly created object remain selected */ bool keep_selected; @@ -52,11 +59,18 @@ struct SPDynaDrawContext : public SPCommonContext { SPCanvasItem *hatch_area; bool just_started_drawing; bool trace_bg; -}; -struct SPDynaDrawContextClass : public SPEventContextClass{}; - -GType sp_dyna_draw_context_get_type(void); + void clear_current(); + void set_to_accumulated(bool unionize, bool subtract); + bool accumulate(); + void fit_and_split(bool release); + void draw_temporary_box(); + void cancel(); + void brush(); + bool apply(Geom::Point p); + void extinput(GdkEvent *event); + void reset(Geom::Point p); +}; #endif // SP_DYNA_DRAW_CONTEXT_H_SEEN diff --git a/src/eraser-context.cpp b/src/eraser-context.cpp index a337f941b..b2df86434 100644 --- a/src/eraser-context.cpp +++ b/src/eraser-context.cpp @@ -83,73 +83,47 @@ using Inkscape::DocumentUndo; #define DRAG_DEFAULT 1.0 #define DRAG_MAX 1.0 -static void sp_eraser_context_dispose(GObject *object); +#include "tool-factory.h" -static void sp_eraser_context_setup(SPEventContext *ec); -static void sp_eraser_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val); -static gint sp_eraser_context_root_handler(SPEventContext *ec, GdkEvent *event); +namespace { + SPEventContext* createEraserContext() { + return new SPEraserContext(); + } -static void clear_current(SPEraserContext *dc); -static void set_to_accumulated(SPEraserContext *dc); -static void add_cap(SPCurve *curve, Geom::Point const &pre, Geom::Point const &from, Geom::Point const &to, Geom::Point const &post, double rounding); -static void accumulate_eraser(SPEraserContext *dc); - -static void fit_and_split(SPEraserContext *erc, gboolean release); - -static void sp_eraser_reset(SPEraserContext *erc, Geom::Point p); -static Geom::Point sp_eraser_get_npoint(SPEraserContext const *erc, Geom::Point v); -static Geom::Point sp_eraser_get_vpoint(SPEraserContext const *erc, Geom::Point n); -static void draw_temporary_box(SPEraserContext *dc); - -G_DEFINE_TYPE(SPEraserContext, sp_eraser_context, SP_TYPE_COMMON_CONTEXT); + bool eraserContextRegistered = ToolFactory::instance().registerObject("/tools/eraser", createEraserContext); +} -static void -sp_eraser_context_class_init(SPEraserContextClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - SPEventContextClass *event_context_class = SP_EVENT_CONTEXT_CLASS(klass); +const std::string& SPEraserContext::getPrefsPath() { + return SPEraserContext::prefsPath; +} - object_class->dispose = sp_eraser_context_dispose; +const std::string SPEraserContext::prefsPath = "/tools/eraser"; - event_context_class->setup = sp_eraser_context_setup; - event_context_class->set = sp_eraser_context_set; - event_context_class->root_handler = sp_eraser_context_root_handler; +SPEraserContext::SPEraserContext() : SPCommonContext() { + this->cursor_shape = cursor_eraser_xpm; + this->hot_x = 4; + this->hot_y = 4; } -static void -sp_eraser_context_init(SPEraserContext *erc) -{ - erc->cursor_shape = cursor_eraser_xpm; - erc->hot_x = 4; - erc->hot_y = 4; +SPEraserContext::~SPEraserContext() { } -static void -sp_eraser_context_dispose(GObject *object) -{ - G_OBJECT_CLASS(sp_eraser_context_parent_class)->dispose(object); -} +void SPEraserContext::setup() { + SPCommonContext::setup(); -static void -sp_eraser_context_setup(SPEventContext *ec) -{ - SPEraserContext *erc = SP_ERASER_CONTEXT(ec); - SPDesktop *desktop = ec->desktop; + this->accumulated = new SPCurve(); + this->currentcurve = new SPCurve(); - if ((SP_EVENT_CONTEXT_CLASS(sp_eraser_context_parent_class))->setup) - (SP_EVENT_CONTEXT_CLASS(sp_eraser_context_parent_class))->setup(ec); + this->cal1 = new SPCurve(); + this->cal2 = new SPCurve(); - erc->accumulated = new SPCurve(); - erc->currentcurve = new SPCurve(); + this->currentshape = sp_canvas_item_new(sp_desktop_sketch(desktop), SP_TYPE_CANVAS_BPATH, NULL); - erc->cal1 = new SPCurve(); - erc->cal2 = new SPCurve(); + sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(this->currentshape), ERC_RED_RGBA, SP_WIND_RULE_EVENODD); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->currentshape), 0x00000000, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - erc->currentshape = sp_canvas_item_new(sp_desktop_sketch(desktop), SP_TYPE_CANVAS_BPATH, NULL); - sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(erc->currentshape), ERC_RED_RGBA, SP_WIND_RULE_EVENODD); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(erc->currentshape), 0x00000000, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); /* fixme: Cannot we cascade it to root more clearly? */ - g_signal_connect(G_OBJECT(erc->currentshape), "event", G_CALLBACK(sp_desktop_root_handler), desktop); + g_signal_connect(G_OBJECT(this->currentshape), "event", G_CALLBACK(sp_desktop_root_handler), desktop); /* static ProfileFloatElement f_profile[PROFILE_FLOAT_SIZE] = { @@ -163,39 +137,28 @@ static ProfileFloatElement f_profile[PROFILE_FLOAT_SIZE] = { }; */ - sp_event_context_read(ec, "mass"); - sp_event_context_read(ec, "wiggle"); - sp_event_context_read(ec, "angle"); - sp_event_context_read(ec, "width"); - sp_event_context_read(ec, "thinning"); - sp_event_context_read(ec, "tremor"); - sp_event_context_read(ec, "flatness"); - sp_event_context_read(ec, "tracebackground"); - sp_event_context_read(ec, "usepressure"); - sp_event_context_read(ec, "usetilt"); - sp_event_context_read(ec, "abs_width"); - sp_event_context_read(ec, "cap_rounding"); - - erc->is_drawing = false; - - erc->_message_context = new Inkscape::MessageContext(desktop->messageStack()); + sp_event_context_read(this, "mass"); + sp_event_context_read(this, "wiggle"); + sp_event_context_read(this, "angle"); + sp_event_context_read(this, "width"); + sp_event_context_read(this, "thinning"); + sp_event_context_read(this, "tremor"); + sp_event_context_read(this, "flatness"); + sp_event_context_read(this, "tracebackground"); + sp_event_context_read(this, "usepressure"); + sp_event_context_read(this, "usetilt"); + sp_event_context_read(this, "abs_width"); + sp_event_context_read(this, "cap_rounding"); + + this->is_drawing = false; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/tools/eraser/selcue", 0) != 0) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } -// TODO temp force: - ec->enableSelectionCue(); - -} -static void -sp_eraser_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val) -{ - //pass on up to parent class to handle common attributes. - if (SP_EVENT_CONTEXT_CLASS(sp_eraser_context_parent_class)->set ) { - SP_EVENT_CONTEXT_CLASS(sp_eraser_context_parent_class)->set(ec, val); - } + // TODO temp force: + this->enableSelectionCue(); } static double @@ -204,66 +167,42 @@ flerp(double f0, double f1, double p) return f0 + ( f1 - f0 ) * p; } -/* Get normalized point */ -static Geom::Point -sp_eraser_get_npoint(SPEraserContext const *dc, Geom::Point v) -{ - Geom::Rect drect = SP_EVENT_CONTEXT(dc)->desktop->get_display_area(); - double const max = MAX ( drect.dimensions()[Geom::X], drect.dimensions()[Geom::Y] ); - return Geom::Point(( v[Geom::X] - drect.min()[Geom::X] ) / max, ( v[Geom::Y] - drect.min()[Geom::Y] ) / max); -} - -/* Get view point */ -static Geom::Point -sp_eraser_get_vpoint(SPEraserContext const *dc, Geom::Point n) -{ - Geom::Rect drect = SP_EVENT_CONTEXT(dc)->desktop->get_display_area(); - double const max = MAX ( drect.dimensions()[Geom::X], drect.dimensions()[Geom::Y] ); - return Geom::Point(n[Geom::X] * max + drect.min()[Geom::X], n[Geom::Y] * max + drect.min()[Geom::Y]); +void SPEraserContext::reset(Geom::Point p) { + this->last = this->cur = getNormalizedPoint(p); + this->vel = Geom::Point(0,0); + this->vel_max = 0; + this->acc = Geom::Point(0,0); + this->ang = Geom::Point(0,0); + this->del = Geom::Point(0,0); } -static void -sp_eraser_reset(SPEraserContext *dc, Geom::Point p) -{ - dc->last = dc->cur = sp_eraser_get_npoint(dc, p); - dc->vel = Geom::Point(0,0); - dc->vel_max = 0; - dc->acc = Geom::Point(0,0); - dc->ang = Geom::Point(0,0); - dc->del = Geom::Point(0,0); -} - -static void -sp_eraser_extinput(SPEraserContext *dc, GdkEvent *event) -{ - if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &dc->pressure)) - dc->pressure = CLAMP (dc->pressure, ERC_MIN_PRESSURE, ERC_MAX_PRESSURE); +void SPEraserContext::extinput(GdkEvent *event) { + if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &this->pressure)) + this->pressure = CLAMP (this->pressure, ERC_MIN_PRESSURE, ERC_MAX_PRESSURE); else - dc->pressure = ERC_DEFAULT_PRESSURE; + this->pressure = ERC_DEFAULT_PRESSURE; - if (gdk_event_get_axis (event, GDK_AXIS_XTILT, &dc->xtilt)) - dc->xtilt = CLAMP (dc->xtilt, ERC_MIN_TILT, ERC_MAX_TILT); + if (gdk_event_get_axis (event, GDK_AXIS_XTILT, &this->xtilt)) + this->xtilt = CLAMP (this->xtilt, ERC_MIN_TILT, ERC_MAX_TILT); else - dc->xtilt = ERC_DEFAULT_TILT; + this->xtilt = ERC_DEFAULT_TILT; - if (gdk_event_get_axis (event, GDK_AXIS_YTILT, &dc->ytilt)) - dc->ytilt = CLAMP (dc->ytilt, ERC_MIN_TILT, ERC_MAX_TILT); + if (gdk_event_get_axis (event, GDK_AXIS_YTILT, &this->ytilt)) + this->ytilt = CLAMP (this->ytilt, ERC_MIN_TILT, ERC_MAX_TILT); else - dc->ytilt = ERC_DEFAULT_TILT; + this->ytilt = ERC_DEFAULT_TILT; } -static gboolean -sp_eraser_apply(SPEraserContext *dc, Geom::Point p) -{ - Geom::Point n = sp_eraser_get_npoint(dc, p); +bool SPEraserContext::apply(Geom::Point p) { + Geom::Point n = getNormalizedPoint(p); /* Calculate mass and drag */ - double const mass = flerp(1.0, 160.0, dc->mass); - double const drag = flerp(0.0, 0.5, dc->drag * dc->drag); + double const mass = flerp(1.0, 160.0, this->mass); + double const drag = flerp(0.0, 0.5, this->drag * this->drag); /* Calculate force and acceleration */ - Geom::Point force = n - dc->cur; + Geom::Point force = n - this->cur; // If force is below the absolute threshold ERASER_EPSILON, // or we haven't yet reached ERASER_VEL_START (i.e. at the beginning of stroke) @@ -272,27 +211,27 @@ sp_eraser_apply(SPEraserContext *dc, Geom::Point p) // This prevents flips, blobs, and jerks caused by microscopic tremor of the tablet pen, // especially bothersome at the start of the stroke where we don't yet have the inertia to // smooth them out. - if ( Geom::L2(force) < ERASER_EPSILON || (dc->vel_max < ERASER_VEL_START && Geom::L2(force) < ERASER_EPSILON_START)) { + if ( Geom::L2(force) < ERASER_EPSILON || (this->vel_max < ERASER_VEL_START && Geom::L2(force) < ERASER_EPSILON_START)) { return FALSE; } - dc->acc = force / mass; + this->acc = force / mass; /* Calculate new velocity */ - dc->vel += dc->acc; + this->vel += this->acc; - if (Geom::L2(dc->vel) > dc->vel_max) - dc->vel_max = Geom::L2(dc->vel); + if (Geom::L2(this->vel) > this->vel_max) + this->vel_max = Geom::L2(this->vel); /* Calculate angle of drawing tool */ double a1; - if (dc->usetilt) { + if (this->usetilt) { // 1a. calculate nib angle from input device tilt: - gdouble length = std::sqrt(dc->xtilt*dc->xtilt + dc->ytilt*dc->ytilt);; + gdouble length = std::sqrt(this->xtilt*this->xtilt + this->ytilt*this->ytilt);; if (length > 0) { - Geom::Point ang1 = Geom::Point(dc->ytilt/length, dc->xtilt/length); + Geom::Point ang1 = Geom::Point(this->ytilt/length, this->xtilt/length); a1 = atan2(ang1); } else @@ -300,17 +239,17 @@ sp_eraser_apply(SPEraserContext *dc, Geom::Point p) } else { // 1b. fixed dc->angle (absolutely flat nib): - double const radians = ( (dc->angle - 90) / 180.0 ) * M_PI; + double const radians = ( (this->angle - 90) / 180.0 ) * M_PI; Geom::Point ang1 = Geom::Point(-sin(radians), cos(radians)); a1 = atan2(ang1); } // 2. perpendicular to dc->vel (absolutely non-flat nib): - gdouble const mag_vel = Geom::L2(dc->vel); + gdouble const mag_vel = Geom::L2(this->vel); if ( mag_vel < ERASER_EPSILON ) { return FALSE; } - Geom::Point ang2 = Geom::rot90(dc->vel) / mag_vel; + Geom::Point ang2 = Geom::rot90(this->vel) / mag_vel; // 3. Average them using flatness parameter: // calculate angles @@ -328,52 +267,50 @@ sp_eraser_apply(SPEraserContext *dc, Geom::Point p) a2 += 2*M_PI; // find the flatness-weighted bisector angle, unflip if a2 was flipped // FIXME: when dc->vel is oscillating around the fixed angle, the new_ang flips back and forth. How to avoid this? - double new_ang = a1 + (1 - dc->flatness) * (a2 - a1) - (flipped? M_PI : 0); + double new_ang = a1 + (1 - this->flatness) * (a2 - a1) - (flipped? M_PI : 0); // Try to detect a sudden flip when the new angle differs too much from the previous for the // current velocity; in that case discard this move - double angle_delta = Geom::L2(Geom::Point (cos (new_ang), sin (new_ang)) - dc->ang); - if ( angle_delta / Geom::L2(dc->vel) > 4000 ) { + double angle_delta = Geom::L2(Geom::Point (cos (new_ang), sin (new_ang)) - this->ang); + if ( angle_delta / Geom::L2(this->vel) > 4000 ) { return FALSE; } // convert to point - dc->ang = Geom::Point (cos (new_ang), sin (new_ang)); + this->ang = Geom::Point (cos (new_ang), sin (new_ang)); // g_print ("force %g acc %g vel_max %g vel %g a1 %g a2 %g new_ang %g\n", Geom::L2(force), Geom::L2(dc->acc), dc->vel_max, Geom::L2(dc->vel), a1, a2, new_ang); /* Apply drag */ - dc->vel *= 1.0 - drag; + this->vel *= 1.0 - drag; /* Update position */ - dc->last = dc->cur; - dc->cur += dc->vel; + this->last = this->cur; + this->cur += this->vel; return TRUE; } -static void -sp_eraser_brush(SPEraserContext *dc) -{ - g_assert( dc->npoints >= 0 && dc->npoints < SAMPLING_SIZE ); +void SPEraserContext::brush() { + g_assert( this->npoints >= 0 && this->npoints < SAMPLING_SIZE ); // How much velocity thins strokestyle - double vel_thin = flerp (0, 160, dc->vel_thin); + double vel_thin = flerp (0, 160, this->vel_thin); // Influence of pressure on thickness - double pressure_thick = (dc->usepressure ? dc->pressure : 1.0); + double pressure_thick = (this->usepressure ? this->pressure : 1.0); // get the real brush point, not the same as pointer (affected by hatch tracking and/or mass // drag) - Geom::Point brush = sp_eraser_get_vpoint(dc, dc->cur); + Geom::Point brush = getViewPoint(this->cur); //Geom::Point brush_w = SP_EVENT_CONTEXT(dc)->desktop->d2w(brush); double trace_thick = 1; - double width = (pressure_thick * trace_thick - vel_thin * Geom::L2(dc->vel)) * dc->width; + double width = (pressure_thick * trace_thick - vel_thin * Geom::L2(this->vel)) * this->width; double tremble_left = 0, tremble_right = 0; - if (dc->tremor > 0) { + if (this->tremor > 0) { // obtain two normally distributed random variables, using polar Box-Muller transform double x1, x2, w, y1, y2; do { @@ -390,28 +327,28 @@ sp_eraser_brush(SPEraserContext *dc) // (2) deflection depends on width, but is upped for small widths for better visual uniformity across widths; // (3) deflection somewhat depends on speed, to prevent fast strokes looking // comparatively smooth and slow ones excessively jittery - tremble_left = (y1)*dc->tremor * (0.15 + 0.8*width) * (0.35 + 14*Geom::L2(dc->vel)); - tremble_right = (y2)*dc->tremor * (0.15 + 0.8*width) * (0.35 + 14*Geom::L2(dc->vel)); + tremble_left = (y1)*this->tremor * (0.15 + 0.8*width) * (0.35 + 14*Geom::L2(this->vel)); + tremble_right = (y2)*this->tremor * (0.15 + 0.8*width) * (0.35 + 14*Geom::L2(this->vel)); } - if ( width < 0.02 * dc->width ) { - width = 0.02 * dc->width; + if ( width < 0.02 * this->width ) { + width = 0.02 * this->width; } double dezoomify_factor = 0.05 * 1000; - if (!dc->abs_width) { - dezoomify_factor /= SP_EVENT_CONTEXT(dc)->desktop->current_zoom(); + if (!this->abs_width) { + dezoomify_factor /= SP_EVENT_CONTEXT(this)->desktop->current_zoom(); } - Geom::Point del_left = dezoomify_factor * (width + tremble_left) * dc->ang; - Geom::Point del_right = dezoomify_factor * (width + tremble_right) * dc->ang; + Geom::Point del_left = dezoomify_factor * (width + tremble_left) * this->ang; + Geom::Point del_right = dezoomify_factor * (width + tremble_right) * this->ang; - dc->point1[dc->npoints] = brush + del_left; - dc->point2[dc->npoints] = brush - del_right; + this->point1[this->npoints] = brush + del_left; + this->point2[this->npoints] = brush - del_right; - dc->del = 0.5*(del_left + del_right); + this->del = 0.5*(del_left + del_right); - dc->npoints++; + this->npoints++; } static void @@ -420,60 +357,52 @@ sp_erc_update_toolbox (SPDesktop *desktop, const gchar *id, double value) desktop->setToolboxAdjustmentValue (id, value); } -static void -eraser_cancel(SPEraserContext *dc) -{ - SPDesktop *desktop = SP_EVENT_CONTEXT(dc)->desktop; - dc->dragging = FALSE; - dc->is_drawing = false; +void SPEraserContext::cancel() { + SPDesktop *desktop = SP_EVENT_CONTEXT(this)->desktop; + this->dragging = FALSE; + this->is_drawing = false; sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0); /* Remove all temporary line segments */ - while (dc->segments) { - sp_canvas_item_destroy(SP_CANVAS_ITEM(dc->segments->data)); - dc->segments = g_slist_remove(dc->segments, dc->segments->data); + while (this->segments) { + sp_canvas_item_destroy(SP_CANVAS_ITEM(this->segments->data)); + this->segments = g_slist_remove(this->segments, this->segments->data); } /* reset accumulated curve */ - dc->accumulated->reset(); - clear_current(dc); - if (dc->repr) { - dc->repr = NULL; + this->accumulated->reset(); + this->clear_current(); + if (this->repr) { + this->repr = NULL; } } - -gint -sp_eraser_context_root_handler(SPEventContext *event_context, - GdkEvent *event) -{ - SPEraserContext *dc = SP_ERASER_CONTEXT(event_context); - SPDesktop *desktop = event_context->desktop; - +bool SPEraserContext::root_handler(GdkEvent* event) { gint ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { - - if (Inkscape::have_viable_layer(desktop, dc->_message_context) == false) { + if (event->button.button == 1 && !this->space_panning) { + if (Inkscape::have_viable_layer(desktop, this->message_context) == false) { return TRUE; } - Geom::Point const button_w(event->button.x, - event->button.y); + Geom::Point const button_w(event->button.x, event->button.y); Geom::Point const button_dt(desktop->w2d(button_w)); - sp_eraser_reset(dc, button_dt); - sp_eraser_extinput(dc, event); - sp_eraser_apply(dc, button_dt); - dc->accumulated->reset(); - if (dc->repr) { - dc->repr = NULL; + + this->reset(button_dt); + this->extinput(event); + this->apply(button_dt); + + this->accumulated->reset(); + + if (this->repr) { + this->repr = NULL; } Inkscape::Rubberband::get(desktop)->start(desktop, button_dt); Inkscape::Rubberband::get(desktop)->setMode(RUBBERBAND_MODE_TOUCHPATH); /* initialize first point */ - dc->npoints = 0; + this->npoints = 0; sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), ( GDK_KEY_PRESS_MASK | @@ -486,76 +415,77 @@ sp_eraser_context_root_handler(SPEventContext *event_context, ret = TRUE; desktop->canvas->forceFullRedrawAfterInterruptions(3); - dc->is_drawing = true; + this->is_drawing = true; } break; - case GDK_MOTION_NOTIFY: - { - Geom::Point const motion_w(event->motion.x, - event->motion.y); - Geom::Point motion_dt(desktop->w2d(motion_w)); - sp_eraser_extinput(dc, event); - dc->_message_context->clear(); + case GDK_MOTION_NOTIFY: { + Geom::Point const motion_w(event->motion.x, event->motion.y); + Geom::Point motion_dt(desktop->w2d(motion_w) + ); + this->extinput(event); + + this->message_context->clear(); - if ( dc->is_drawing && (event->motion.state & GDK_BUTTON1_MASK) && !event_context->space_panning) { - dc->dragging = TRUE; + if ( this->is_drawing && (event->motion.state & GDK_BUTTON1_MASK) && !this->space_panning) { + this->dragging = TRUE; - dc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Drawing</b> an eraser stroke")); + this->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Drawing</b> an eraser stroke")); - if (!sp_eraser_apply(dc, motion_dt)) { + if (!this->apply(motion_dt)) { ret = TRUE; break; } - if ( dc->cur != dc->last ) { - sp_eraser_brush(dc); - g_assert( dc->npoints > 0 ); - fit_and_split(dc, FALSE); + if ( this->cur != this->last ) { + this->brush(); + g_assert( this->npoints > 0 ); + this->fit_and_split(false); } + ret = TRUE; } + Inkscape::Rubberband::get(desktop)->move(motion_dt); } break; - - case GDK_BUTTON_RELEASE: - { + case GDK_BUTTON_RELEASE: { Geom::Point const motion_w(event->button.x, event->button.y); Geom::Point const motion_dt(desktop->w2d(motion_w)); sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); desktop->canvas->endForcedFullRedraws(); - dc->is_drawing = false; + this->is_drawing = false; - if (dc->dragging && event->button.button == 1 && !event_context->space_panning) { - dc->dragging = FALSE; + if (this->dragging && event->button.button == 1 && !this->space_panning) { + this->dragging = FALSE; - sp_eraser_apply(dc, motion_dt); + this->apply(motion_dt); /* Remove all temporary line segments */ - while (dc->segments) { - sp_canvas_item_destroy(SP_CANVAS_ITEM(dc->segments->data)); - dc->segments = g_slist_remove(dc->segments, dc->segments->data); + while (this->segments) { + sp_canvas_item_destroy(SP_CANVAS_ITEM(this->segments->data)); + this->segments = g_slist_remove(this->segments, this->segments->data); } /* Create object */ - fit_and_split(dc, TRUE); - accumulate_eraser(dc); - set_to_accumulated(dc); // performs document_done + this->fit_and_split(true); + this->accumulate(); + this->set_to_accumulated(); // performs document_done /* reset accumulated curve */ - dc->accumulated->reset(); + this->accumulated->reset(); - clear_current(dc); - if (dc->repr) { - dc->repr = NULL; + this->clear_current(); + if (this->repr) { + this->repr = NULL; } - dc->_message_context->clear(); + this->message_context->clear(); ret = TRUE; } + if (Inkscape::Rubberband::get(desktop)->is_started()) { Inkscape::Rubberband::get(desktop)->stop(); } @@ -568,55 +498,73 @@ sp_eraser_context_root_handler(SPEventContext *event_context, case GDK_KEY_Up: case GDK_KEY_KP_Up: if (!MOD__CTRL_ONLY(event)) { - dc->angle += 5.0; - if (dc->angle > 90.0) - dc->angle = 90.0; - sp_erc_update_toolbox (desktop, "eraser-angle", dc->angle); + this->angle += 5.0; + + if (this->angle > 90.0) { + this->angle = 90.0; + } + + sp_erc_update_toolbox (desktop, "eraser-angle", this->angle); ret = TRUE; } break; + case GDK_KEY_Down: case GDK_KEY_KP_Down: if (!MOD__CTRL_ONLY(event)) { - dc->angle -= 5.0; - if (dc->angle < -90.0) - dc->angle = -90.0; - sp_erc_update_toolbox (desktop, "eraser-angle", dc->angle); + this->angle -= 5.0; + + if (this->angle < -90.0) { + this->angle = -90.0; + } + + sp_erc_update_toolbox (desktop, "eraser-angle", this->angle); ret = TRUE; } break; + case GDK_KEY_Right: case GDK_KEY_KP_Right: if (!MOD__CTRL_ONLY(event)) { - dc->width += 0.01; - if (dc->width > 1.0) - dc->width = 1.0; - sp_erc_update_toolbox (desktop, "altx-eraser", dc->width * 100); // the same spinbutton is for alt+x + this->width += 0.01; + + if (this->width > 1.0) { + this->width = 1.0; + } + + sp_erc_update_toolbox (desktop, "altx-eraser", this->width * 100); // the same spinbutton is for alt+x ret = TRUE; } break; + case GDK_KEY_Left: case GDK_KEY_KP_Left: if (!MOD__CTRL_ONLY(event)) { - dc->width -= 0.01; - if (dc->width < 0.01) - dc->width = 0.01; - sp_erc_update_toolbox (desktop, "altx-eraser", dc->width * 100); + this->width -= 0.01; + + if (this->width < 0.01) { + this->width = 0.01; + } + + sp_erc_update_toolbox (desktop, "altx-eraser", this->width * 100); ret = TRUE; } break; + case GDK_KEY_Home: case GDK_KEY_KP_Home: - dc->width = 0.01; - sp_erc_update_toolbox (desktop, "altx-eraser", dc->width * 100); + this->width = 0.01; + sp_erc_update_toolbox (desktop, "altx-eraser", this->width * 100); ret = TRUE; break; + case GDK_KEY_End: case GDK_KEY_KP_End: - dc->width = 1.0; - sp_erc_update_toolbox (desktop, "altx-eraser", dc->width * 100); + this->width = 1.0; + sp_erc_update_toolbox (desktop, "altx-eraser", this->width * 100); ret = TRUE; break; + case GDK_KEY_x: case GDK_KEY_X: if (MOD__ALT_ONLY(event)) { @@ -624,22 +572,26 @@ sp_eraser_context_root_handler(SPEventContext *event_context, ret = TRUE; } break; + case GDK_KEY_Escape: Inkscape::Rubberband::get(desktop)->stop(); - if (dc->is_drawing) { + + if (this->is_drawing) { // if drawing, cancel, otherwise pass it up for deselecting - eraser_cancel (dc); + this->cancel(); ret = TRUE; } break; + case GDK_KEY_z: case GDK_KEY_Z: - if (MOD__CTRL_ONLY(event) && dc->is_drawing) { + if (MOD__CTRL_ONLY(event) && this->is_drawing) { // if drawing, cancel, otherwise pass it up for undo - eraser_cancel (dc); + this->cancel(); ret = TRUE; } break; + default: break; } @@ -649,49 +601,43 @@ sp_eraser_context_root_handler(SPEventContext *event_context, switch (get_group0_keyval(&event->key)) { case GDK_KEY_Control_L: case GDK_KEY_Control_R: - dc->_message_context->clear(); + this->message_context->clear(); break; + default: break; } + break; default: break; } if (!ret) { - if ((SP_EVENT_CONTEXT_CLASS(sp_eraser_context_parent_class))->root_handler) { - ret = (SP_EVENT_CONTEXT_CLASS(sp_eraser_context_parent_class))->root_handler(event_context, event); - } + ret = SPCommonContext::root_handler(event); } return ret; } - -static void -clear_current(SPEraserContext *dc) -{ +void SPEraserContext::clear_current() { // reset bpath - sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(dc->currentshape), NULL); + sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(this->currentshape), NULL); // reset curve - dc->currentcurve->reset(); - dc->cal1->reset(); - dc->cal2->reset(); + this->currentcurve->reset(); + this->cal1->reset(); + this->cal2->reset(); // reset points - dc->npoints = 0; + this->npoints = 0; } -static void -set_to_accumulated(SPEraserContext *dc) -{ - SPDesktop *desktop = SP_EVENT_CONTEXT(dc)->desktop; +void SPEraserContext::set_to_accumulated() { bool workDone = false; - if (!dc->accumulated->is_empty()) { - if (!dc->repr) { + if (!this->accumulated->is_empty()) { + if (!this->repr) { /* Create object */ Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); @@ -699,20 +645,22 @@ set_to_accumulated(SPEraserContext *dc) /* Set style */ sp_desktop_apply_style_tool (desktop, repr, "/tools/eraser", false); - dc->repr = repr; + this->repr = repr; + + SPItem *item=SP_ITEM(desktop->currentLayer()->appendChildRepr(this->repr)); + Inkscape::GC::release(this->repr); - SPItem *item=SP_ITEM(desktop->currentLayer()->appendChildRepr(dc->repr)); - Inkscape::GC::release(dc->repr); item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); item->updateRepr(); } - Geom::PathVector pathv = dc->accumulated->get_pathvector() * desktop->dt2doc(); + + Geom::PathVector pathv = this->accumulated->get_pathvector() * desktop->dt2doc(); gchar *str = sp_svg_write_path(pathv); g_assert( str != NULL ); - dc->repr->setAttribute("d", str); + this->repr->setAttribute("d", str); g_free(str); - if ( dc->repr ) { + if ( this->repr ) { bool wasSelection = false; Inkscape::Selection *selection = sp_desktop_selection(desktop); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -720,11 +668,12 @@ set_to_accumulated(SPEraserContext *dc) gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0; Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); - SPItem* acid = SP_ITEM(desktop->doc()->getObjectByRepr(dc->repr)); + SPItem* acid = SP_ITEM(desktop->doc()->getObjectByRepr(this->repr)); Geom::OptRect eraserBbox = acid->visualBounds(); Geom::Rect bounds = (*eraserBbox) * desktop->doc2dt(); std::vector<SPItem*> remainingItems; GSList* toWorkOn = 0; + if (selection->isEmpty()) { if ( eraserMode ) { toWorkOn = sp_desktop_document(desktop)->getItemsPartiallyInBox(desktop->dkey, bounds); @@ -732,6 +681,7 @@ set_to_accumulated(SPEraserContext *dc) Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop); toWorkOn = sp_desktop_document(desktop)->getItemsAtPoints(desktop->dkey, r->getPoints()); } + toWorkOn = g_slist_remove( toWorkOn, acid ); } else { toWorkOn = g_slist_copy(const_cast<GSList*>(selection->itemList())); @@ -742,23 +692,28 @@ set_to_accumulated(SPEraserContext *dc) if ( eraserMode ) { for (GSList *i = toWorkOn ; i ; i = i->next ) { SPItem *item = SP_ITEM(i->data); + if ( eraserMode ) { Geom::OptRect bbox = item->visualBounds(); + if (bbox && bbox->intersects(*eraserBbox)) { - Inkscape::XML::Node* dup = dc->repr->duplicate(xml_doc); - dc->repr->parent()->appendChild(dup); + Inkscape::XML::Node* dup = this->repr->duplicate(xml_doc); + this->repr->parent()->appendChild(dup); Inkscape::GC::release(dup); // parent takes over selection->set(item); selection->add(dup); sp_selected_path_diff_skip_undo(selection, desktop); workDone = true; // TODO set this only if something was cut. + if ( !selection->isEmpty() ) { // If the item was not completely erased, track the new remainder. GSList *nowSel = g_slist_copy(const_cast<GSList *>(selection->itemList())); + for (GSList const *i2 = nowSel ; i2 ; i2 = i2->next ) { remainingItems.push_back(SP_ITEM(i2->data)); } + g_slist_free(nowSel); } } else { @@ -770,6 +725,7 @@ set_to_accumulated(SPEraserContext *dc) for (GSList *i = toWorkOn ; i ; i = i->next ) { sp_object_ref( SP_ITEM(i->data), 0 ); } + for (GSList *i = toWorkOn ; i ; i = i->next ) { SPItem *item = SP_ITEM(i->data); item->deleteObject(true); @@ -786,6 +742,7 @@ set_to_accumulated(SPEraserContext *dc) } selection->clear(); + if ( wasSelection ) { if ( !remainingItems.empty() ) { selection->add(remainingItems.begin(), remainingItems.end()); @@ -794,20 +751,19 @@ set_to_accumulated(SPEraserContext *dc) } // Remove the eraser stroke itself: - sp_repr_unparent( dc->repr ); - dc->repr = 0; + sp_repr_unparent( this->repr ); + this->repr = 0; } } else { - if (dc->repr) { - sp_repr_unparent(dc->repr); - dc->repr = 0; + if (this->repr) { + sp_repr_unparent(this->repr); + this->repr = 0; } } if ( workDone ) { - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ERASER, - _("Draw eraser stroke")); + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ERASER, _("Draw eraser stroke")); } else { DocumentUndo::cancel(sp_desktop_document(desktop)); } @@ -824,6 +780,7 @@ add_cap(SPCurve *curve, Geom::Point v_in = from - pre; double mag_in = Geom::L2(v_in); + if ( mag_in > ERASER_EPSILON ) { v_in = mag * v_in / mag_in; } else { @@ -832,6 +789,7 @@ add_cap(SPCurve *curve, Geom::Point v_out = to - post; double mag_out = Geom::L2(v_out); + if ( mag_out > ERASER_EPSILON ) { v_out = mag * v_out / mag_out; } else { @@ -843,41 +801,40 @@ add_cap(SPCurve *curve, } } -static void -accumulate_eraser(SPEraserContext *dc) -{ - if ( !dc->cal1->is_empty() && !dc->cal2->is_empty() ) { - dc->accumulated->reset(); /* Is this required ?? */ - SPCurve *rev_cal2 = dc->cal2->create_reverse(); +void SPEraserContext::accumulate() { + if ( !this->cal1->is_empty() && !this->cal2->is_empty() ) { + this->accumulated->reset(); /* Is this required ?? */ + SPCurve *rev_cal2 = this->cal2->create_reverse(); - g_assert(dc->cal1->get_segment_count() > 0); + g_assert(this->cal1->get_segment_count() > 0); g_assert(rev_cal2->get_segment_count() > 0); - g_assert( ! dc->cal1->first_path()->closed() ); + g_assert( ! this->cal1->first_path()->closed() ); g_assert( ! rev_cal2->first_path()->closed() ); - Geom::CubicBezier const * dc_cal1_firstseg = dynamic_cast<Geom::CubicBezier const *>( dc->cal1->first_segment() ); + Geom::CubicBezier const * dc_cal1_firstseg = dynamic_cast<Geom::CubicBezier const *>( this->cal1->first_segment() ); Geom::CubicBezier const * rev_cal2_firstseg = dynamic_cast<Geom::CubicBezier const *>( rev_cal2->first_segment() ); - Geom::CubicBezier const * dc_cal1_lastseg = dynamic_cast<Geom::CubicBezier const *>( dc->cal1->last_segment() ); + Geom::CubicBezier const * dc_cal1_lastseg = dynamic_cast<Geom::CubicBezier const *>( this->cal1->last_segment() ); Geom::CubicBezier const * rev_cal2_lastseg = dynamic_cast<Geom::CubicBezier const *>( rev_cal2->last_segment() ); + g_assert( dc_cal1_firstseg ); g_assert( rev_cal2_firstseg ); g_assert( dc_cal1_lastseg ); g_assert( rev_cal2_lastseg ); - dc->accumulated->append(dc->cal1, FALSE); + this->accumulated->append(this->cal1, FALSE); - add_cap(dc->accumulated, (*dc_cal1_lastseg)[2], (*dc_cal1_lastseg)[3], (*rev_cal2_firstseg)[0], (*rev_cal2_firstseg)[1], dc->cap_rounding); + add_cap(this->accumulated, (*dc_cal1_lastseg)[2], (*dc_cal1_lastseg)[3], (*rev_cal2_firstseg)[0], (*rev_cal2_firstseg)[1], this->cap_rounding); - dc->accumulated->append(rev_cal2, TRUE); + this->accumulated->append(rev_cal2, TRUE); - add_cap(dc->accumulated, (*rev_cal2_lastseg)[2], (*rev_cal2_lastseg)[3], (*dc_cal1_firstseg)[0], (*dc_cal1_firstseg)[1], dc->cap_rounding); + add_cap(this->accumulated, (*rev_cal2_lastseg)[2], (*rev_cal2_lastseg)[3], (*dc_cal1_firstseg)[0], (*dc_cal1_firstseg)[1], this->cap_rounding); - dc->accumulated->closepath(); + this->accumulated->closepath(); rev_cal2->unref(); - dc->cal1->reset(); - dc->cal2->reset(); + this->cal1->reset(); + this->cal2->reset(); } } @@ -886,49 +843,43 @@ static double square(double const x) return x * x; } -static void -fit_and_split(SPEraserContext *dc, gboolean release) -{ - SPDesktop *desktop = SP_EVENT_CONTEXT(dc)->desktop; - +void SPEraserContext::fit_and_split(bool release) { double const tolerance_sq = square( desktop->w2d().descrim() * TOLERANCE_ERASER ); #ifdef ERASER_VERBOSE g_print("[F&S:R=%c]", release?'T':'F'); #endif - if (!( dc->npoints > 0 && dc->npoints < SAMPLING_SIZE )) + if (!( this->npoints > 0 && this->npoints < SAMPLING_SIZE )) return; // just clicked - if ( dc->npoints == SAMPLING_SIZE - 1 || release ) { + if ( this->npoints == SAMPLING_SIZE - 1 || release ) { #define BEZIER_SIZE 4 #define BEZIER_MAX_BEZIERS 8 #define BEZIER_MAX_LENGTH ( BEZIER_SIZE * BEZIER_MAX_BEZIERS ) #ifdef ERASER_VERBOSE - g_print("[F&S:#] dc->npoints:%d, release:%s\n", + g_print("[F&S:#] this->npoints:%d, release:%s\n", dc->npoints, release ? "TRUE" : "FALSE"); #endif /* Current eraser */ - if ( dc->cal1->is_empty() || dc->cal2->is_empty() ) { + if ( this->cal1->is_empty() || this->cal2->is_empty() ) { /* dc->npoints > 0 */ /* g_print("erasers(1|2) reset\n"); */ - dc->cal1->reset(); - dc->cal2->reset(); + this->cal1->reset(); + this->cal2->reset(); - dc->cal1->moveto(dc->point1[0]); - dc->cal2->moveto(dc->point2[0]); + this->cal1->moveto(this->point1[0]); + this->cal2->moveto(this->point2[0]); } Geom::Point b1[BEZIER_MAX_LENGTH]; - gint const nb1 = Geom::bezier_fit_cubic_r(b1, dc->point1, dc->npoints, - tolerance_sq, BEZIER_MAX_BEZIERS); + gint const nb1 = Geom::bezier_fit_cubic_r(b1, this->point1, this->npoints, tolerance_sq, BEZIER_MAX_BEZIERS); g_assert( nb1 * BEZIER_SIZE <= gint(G_N_ELEMENTS(b1)) ); Geom::Point b2[BEZIER_MAX_LENGTH]; - gint const nb2 = Geom::bezier_fit_cubic_r(b2, dc->point2, dc->npoints, - tolerance_sq, BEZIER_MAX_BEZIERS); + gint const nb2 = Geom::bezier_fit_cubic_r(b2, this->point2, this->npoints, tolerance_sq, BEZIER_MAX_BEZIERS); g_assert( nb2 * BEZIER_SIZE <= gint(G_N_ELEMENTS(b2)) ); if ( nb1 != -1 && nb2 != -1 ) { @@ -936,61 +887,66 @@ fit_and_split(SPEraserContext *dc, gboolean release) #ifdef ERASER_VERBOSE g_print("nb1:%d nb2:%d\n", nb1, nb2); #endif + /* CanvasShape */ if (! release) { - dc->currentcurve->reset(); - dc->currentcurve->moveto(b1[0]); + this->currentcurve->reset(); + this->currentcurve->moveto(b1[0]); + for (Geom::Point *bp1 = b1; bp1 < b1 + BEZIER_SIZE * nb1; bp1 += BEZIER_SIZE) { - dc->currentcurve->curveto(bp1[1], - bp1[2], bp1[3]); + this->currentcurve->curveto(bp1[1], bp1[2], bp1[3]); } - dc->currentcurve->lineto(b2[BEZIER_SIZE*(nb2-1) + 3]); + + this->currentcurve->lineto(b2[BEZIER_SIZE*(nb2-1) + 3]); + for (Geom::Point *bp2 = b2 + BEZIER_SIZE * ( nb2 - 1 ); bp2 >= b2; bp2 -= BEZIER_SIZE) { - dc->currentcurve->curveto(bp2[2], bp2[1], bp2[0]); + this->currentcurve->curveto(bp2[2], bp2[1], bp2[0]); } - // FIXME: dc->segments is always NULL at this point?? - if (!dc->segments) { // first segment - add_cap(dc->currentcurve, b2[1], b2[0], b1[0], b1[1], dc->cap_rounding); + + // FIXME: this->segments is always NULL at this point?? + if (!this->segments) { // first segment + add_cap(this->currentcurve, b2[1], b2[0], b1[0], b1[1], this->cap_rounding); } - dc->currentcurve->closepath(); - sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(dc->currentshape), dc->currentcurve); + + this->currentcurve->closepath(); + sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(this->currentshape), this->currentcurve); } /* Current eraser */ for (Geom::Point *bp1 = b1; bp1 < b1 + BEZIER_SIZE * nb1; bp1 += BEZIER_SIZE) { - dc->cal1->curveto(bp1[1], bp1[2], bp1[3]); + this->cal1->curveto(bp1[1], bp1[2], bp1[3]); } + for (Geom::Point *bp2 = b2; bp2 < b2 + BEZIER_SIZE * nb2; bp2 += BEZIER_SIZE) { - dc->cal2->curveto(bp2[1], bp2[2], bp2[3]); + this->cal2->curveto(bp2[1], bp2[2], bp2[3]); } } else { /* fixme: ??? */ #ifdef ERASER_VERBOSE g_print("[fit_and_split] failed to fit-cubic.\n"); #endif - draw_temporary_box(dc); + this->draw_temporary_box(); - for (gint i = 1; i < dc->npoints; i++) { - dc->cal1->lineto(dc->point1[i]); + for (gint i = 1; i < this->npoints; i++) { + this->cal1->lineto(this->point1[i]); } - for (gint i = 1; i < dc->npoints; i++) { - dc->cal2->lineto(dc->point2[i]); + + for (gint i = 1; i < this->npoints; i++) { + this->cal2->lineto(this->point2[i]); } } /* Fit and draw and copy last point */ #ifdef ERASER_VERBOSE - g_print("[%d]Yup\n", dc->npoints); + g_print("[%d]Yup\n", this->npoints); #endif if (!release) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0; - g_assert(!dc->currentcurve->is_empty()); + g_assert(!this->currentcurve->is_empty()); - SPCanvasItem *cbp = sp_canvas_item_new(sp_desktop_sketch(desktop), - SP_TYPE_CANVAS_BPATH, - NULL); - SPCurve *curve = dc->currentcurve->copy(); + SPCanvasItem *cbp = sp_canvas_item_new(sp_desktop_sketch(desktop), SP_TYPE_CANVAS_BPATH, NULL); + SPCurve *curve = this->currentcurve->copy(); sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH (cbp), curve); curve->unref(); @@ -1006,40 +962,41 @@ fit_and_split(SPEraserContext *dc, gboolean release) /* fixme: Cannot we cascade it to root more clearly? */ g_signal_connect(G_OBJECT(cbp), "event", G_CALLBACK(sp_desktop_root_handler), desktop); - dc->segments = g_slist_prepend(dc->segments, cbp); + this->segments = g_slist_prepend(this->segments, cbp); if ( !eraserMode ) { sp_canvas_item_hide(cbp); - sp_canvas_item_hide(dc->currentshape); + sp_canvas_item_hide(this->currentshape); } } - dc->point1[0] = dc->point1[dc->npoints - 1]; - dc->point2[0] = dc->point2[dc->npoints - 1]; - dc->npoints = 1; + this->point1[0] = this->point1[this->npoints - 1]; + this->point2[0] = this->point2[this->npoints - 1]; + this->npoints = 1; } else { - draw_temporary_box(dc); + this->draw_temporary_box(); } } -static void -draw_temporary_box(SPEraserContext *dc) -{ - dc->currentcurve->reset(); +void SPEraserContext::draw_temporary_box() { + this->currentcurve->reset(); - dc->currentcurve->moveto(dc->point1[dc->npoints-1]); - for (gint i = dc->npoints-2; i >= 0; i--) { - dc->currentcurve->lineto(dc->point1[i]); + this->currentcurve->moveto(this->point1[this->npoints-1]); + + for (gint i = this->npoints-2; i >= 0; i--) { + this->currentcurve->lineto(this->point1[i]); } - for (gint i = 0; i < dc->npoints; i++) { - dc->currentcurve->lineto(dc->point2[i]); + + for (gint i = 0; i < this->npoints; i++) { + this->currentcurve->lineto(this->point2[i]); } - if (dc->npoints >= 2) { - add_cap(dc->currentcurve, dc->point2[dc->npoints-2], dc->point2[dc->npoints-1], dc->point1[dc->npoints-1], dc->point1[dc->npoints-2], dc->cap_rounding); + + if (this->npoints >= 2) { + add_cap(this->currentcurve, this->point2[this->npoints-2], this->point2[this->npoints-1], this->point1[this->npoints-1], this->point1[this->npoints-2], this->cap_rounding); } - dc->currentcurve->closepath(); - sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(dc->currentshape), dc->currentcurve); + this->currentcurve->closepath(); + sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(this->currentshape), this->currentcurve); } /* diff --git a/src/eraser-context.h b/src/eraser-context.h index bc4268aef..7ff1cf712 100644 --- a/src/eraser-context.h +++ b/src/eraser-context.h @@ -21,14 +21,6 @@ #include "common-context.h" -G_BEGIN_DECLS - -#define SP_TYPE_ERASER_CONTEXT (sp_eraser_context_get_type()) -#define SP_ERASER_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_ERASER_CONTEXT, SPEraserContext)) -#define SP_ERASER_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_ERASER_CONTEXT, SPEraserContextClass)) -#define SP_IS_ERASER_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_ERASER_CONTEXT)) -#define SP_IS_ERASER_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_ERASER_CONTEXT)) - #define ERC_MIN_PRESSURE 0.0 #define ERC_MAX_PRESSURE 1.0 #define ERC_DEFAULT_PRESSURE 1.0 @@ -37,14 +29,30 @@ G_BEGIN_DECLS #define ERC_MAX_TILT 1.0 #define ERC_DEFAULT_TILT 0.0 -struct SPEraserContext : public SPCommonContext { -}; +class SPEraserContext : public SPCommonContext { +public: + SPEraserContext(); + virtual ~SPEraserContext(); -struct SPEraserContextClass : public SPEventContextClass{}; + static const std::string prefsPath; -GType sp_eraser_context_get_type(void); + virtual void setup(); + virtual bool root_handler(GdkEvent* event); -G_END_DECLS + virtual const std::string& getPrefsPath(); + +private: + void reset(Geom::Point p); + void extinput(GdkEvent *event); + bool apply(Geom::Point p); + void brush(); + void cancel(); + void clear_current(); + void set_to_accumulated(); + void accumulate(); + void fit_and_split(bool release); + void draw_temporary_box(); +}; #endif // SP_ERASER_CONTEXT_H_SEEN diff --git a/src/event-context.cpp b/src/event-context.cpp index 4bbb012e0..e5ea85818 100644 --- a/src/event-context.cpp +++ b/src/event-context.cpp @@ -58,14 +58,6 @@ #include "sp-guide.h" #include "color.h" -static void sp_event_context_dispose(GObject *object); - -static void sp_event_context_private_setup(SPEventContext *ec); -static gint sp_event_context_private_root_handler( - SPEventContext *event_context, GdkEvent *event); -static gint sp_event_context_private_item_handler( - SPEventContext *event_context, SPItem *item, GdkEvent *event); - static void set_event_location(SPDesktop * desktop, GdkEvent * event); // globals for temporary switching to selector by space @@ -76,82 +68,80 @@ static int switch_selector_to = 0; static bool dropper_toggled = FALSE; static int switch_dropper_to = 0; -static gint xp = 0, yp = 0; // where drag started -static gint tolerance = 0; -static bool within_tolerance = false; +//static gint xp = 0, yp = 0; // where drag started +//static gint tolerance = 0; +//static bool within_tolerance = false; // globals for keeping track of keyboard scroll events in order to accelerate static guint32 scroll_event_time = 0; static gdouble scroll_multiply = 1; static guint scroll_keyval = 0; -G_DEFINE_TYPE(SPEventContext, sp_event_context, G_TYPE_OBJECT); - -/** - * Callback to set up the SPEventContext vtable. - */ -static void sp_event_context_class_init(SPEventContextClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - object_class->dispose = sp_event_context_dispose; +void SPEventContext::set(const Inkscape::Preferences::Entry& val) { +} - klass->setup = sp_event_context_private_setup; - klass->root_handler = sp_event_context_private_root_handler; - klass->item_handler = sp_event_context_private_item_handler; +void SPEventContext::activate() { } -/** - * Clears all SPEventContext object members. - */ -static void sp_event_context_init(SPEventContext *event_context) { - event_context->desktop = NULL; - event_context->cursor = NULL; - event_context->_message_context = NULL; - event_context->_selcue = NULL; - event_context->_grdrag = NULL; - event_context->space_panning = false; - event_context->shape_editor = NULL; - event_context->_delayed_snap_event = NULL; - event_context->_dse_callback_in_process = false; - event_context->tool_url = NULL; +void SPEventContext::deactivate() { } -/** - * Callback to free and null member variables of SPEventContext object. - */ -static void sp_event_context_dispose(GObject *object) { - SPEventContext *ec; +void SPEventContext::finish() { + this->enableSelectionCue(false); +} - ec = SP_EVENT_CONTEXT(object); +SPEventContext::SPEventContext() { + this->hot_y = 0; + this->xp = 0; + this->cursor_shape = 0; + this->pref_observer = 0; + this->hot_x = 0; + this->yp = 0; + this->within_tolerance = false; + this->tolerance = 0; + //this->key = 0; + this->item_to_select = 0; + + this->desktop = NULL; + this->cursor = NULL; + this->message_context = NULL; + this->_selcue = NULL; + this->_grdrag = NULL; + this->space_panning = false; + this->shape_editor = NULL; + this->_delayed_snap_event = NULL; + this->_dse_callback_in_process = false; + //this->tool_url = NULL; +} - if (ec->_message_context) { - delete ec->_message_context; +SPEventContext::~SPEventContext() { + if (this->message_context) { + delete this->message_context; } - if (ec->cursor != NULL) { + if (this->cursor != NULL) { #if GTK_CHECK_VERSION(3,0,0) - g_object_unref(ec->cursor); + g_object_unref(this->cursor); #else - gdk_cursor_unref(ec->cursor); + gdk_cursor_unref(this->cursor); #endif - ec->cursor = NULL; + this->cursor = NULL; } - if (ec->desktop) { - ec->desktop = NULL; + if (this->desktop) { + this->desktop = NULL; } - if (ec->pref_observer) { - delete ec->pref_observer; + if (this->pref_observer) { + delete this->pref_observer; } - if (ec->_delayed_snap_event) { - delete ec->_delayed_snap_event; + if (this->_delayed_snap_event) { + delete this->_delayed_snap_event; } - - G_OBJECT_CLASS(sp_event_context_parent_class)->dispose(object); } + /** * Set the cursor to a standard GDK cursor */ @@ -176,68 +166,75 @@ static void sp_event_context_set_cursor(SPEventContext *event_context, GdkCursor /** * Recreates and draws cursor on desktop related to SPEventContext. */ -void sp_event_context_update_cursor(SPEventContext *ec) { - GtkWidget *w = GTK_WIDGET(sp_desktop_canvas(ec->desktop)); +void SPEventContext::sp_event_context_update_cursor() { + GtkWidget *w = GTK_WIDGET(sp_desktop_canvas(this->desktop)); if (gtk_widget_get_window (w)) { GtkStyle *style = gtk_widget_get_style(w); /* fixme: */ - if (ec->cursor_shape) { + if (this->cursor_shape) { GdkDisplay *display = gdk_display_get_default(); - if (ec->tool_url && gdk_display_supports_cursor_alpha(display) && gdk_display_supports_cursor_color(display)) { + if (gdk_display_supports_cursor_alpha(display) && gdk_display_supports_cursor_color(display)) { bool fillHasColor=false, strokeHasColor=false; - guint32 fillColor = sp_desktop_get_color_tool(ec->desktop, ec->tool_url, true, &fillHasColor); - guint32 strokeColor = sp_desktop_get_color_tool(ec->desktop, ec->tool_url, false, &strokeHasColor); - double fillOpacity = fillHasColor ? sp_desktop_get_opacity_tool(ec->desktop, ec->tool_url, true) : 0; - double strokeOpacity = strokeHasColor ? sp_desktop_get_opacity_tool(ec->desktop, ec->tool_url, false) : 0; + guint32 fillColor = sp_desktop_get_color_tool(this->desktop, this->getPrefsPath(), true, &fillHasColor); + guint32 strokeColor = sp_desktop_get_color_tool(this->desktop, this->getPrefsPath(), false, &strokeHasColor); + double fillOpacity = fillHasColor ? sp_desktop_get_opacity_tool(this->desktop, this->getPrefsPath(), true) : 0; + double strokeOpacity = strokeHasColor ? sp_desktop_get_opacity_tool(this->desktop, this->getPrefsPath(), false) : 0; GdkPixbuf *pixbuf = sp_cursor_pixbuf_from_xpm( - ec->cursor_shape, + this->cursor_shape, style->black, style->white, SP_RGBA32_U_COMPOSE(SP_RGBA32_R_U(fillColor),SP_RGBA32_G_U(fillColor),SP_RGBA32_B_U(fillColor),SP_COLOR_F_TO_U(fillOpacity)), SP_RGBA32_U_COMPOSE(SP_RGBA32_R_U(strokeColor),SP_RGBA32_G_U(strokeColor),SP_RGBA32_B_U(strokeColor),SP_COLOR_F_TO_U(strokeOpacity)) ); if (pixbuf != NULL) { - if (ec->cursor) { + if (this->cursor) { #if GTK_CHECK_VERSION(3,0,0) - g_object_unref(ec->cursor); + g_object_unref(this->cursor); #else - gdk_cursor_unref(ec->cursor); + gdk_cursor_unref(this->cursor); #endif } - ec->cursor = gdk_cursor_new_from_pixbuf(display, pixbuf, ec->hot_x, ec->hot_y); + this->cursor = gdk_cursor_new_from_pixbuf(display, pixbuf, this->hot_x, this->hot_y); g_object_unref(pixbuf); } } else { - GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data((const gchar **)ec->cursor_shape); + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data((const gchar **)this->cursor_shape); if (pixbuf) { - if (ec->cursor) { + if (this->cursor) { #if GTK_CHECK_VERSION(3,0,0) - g_object_unref(ec->cursor); + g_object_unref(this->cursor); #else - gdk_cursor_unref(ec->cursor); + gdk_cursor_unref(this->cursor); #endif } - ec->cursor = gdk_cursor_new_from_pixbuf(display, - pixbuf, ec->hot_x, ec->hot_y); + this->cursor = gdk_cursor_new_from_pixbuf(display, + pixbuf, this->hot_x, this->hot_y); g_object_unref(pixbuf); } } } - gdk_window_set_cursor(gtk_widget_get_window (w), ec->cursor); + gdk_window_set_cursor(gtk_widget_get_window (w), this->cursor); gdk_flush(); } - ec->desktop->waiting_cursor = false; + this->desktop->waiting_cursor = false; } /** * Callback that gets called on initialization of SPEventContext object. * Redraws mouse cursor, at the moment. */ -static void sp_event_context_private_setup(SPEventContext *ec) { - sp_event_context_update_cursor(ec); + +/** + * When you override it, call this method first. + */ +void SPEventContext::setup() { + this->pref_observer = new ToolPrefObserver(this->getPrefsPath(), this); + Inkscape::Preferences::get()->addObserver(*(this->pref_observer)); + + this->sp_event_context_update_cursor(); } /** @@ -358,14 +355,18 @@ static gdouble accelerate_scroll(GdkEvent *event, gdouble acceleration, /** * Main event dispatch, gets called from Gdk. */ -static gint sp_event_context_private_root_handler( - SPEventContext *event_context, GdkEvent *event) { +//static gint sp_event_context_private_root_handler( +// SPEventContext *event_context, GdkEvent *event) { +// +// return event_context->ceventcontext->root_handler(event); +//} + +bool SPEventContext::root_handler(GdkEvent* event) { static Geom::Point button_w; static unsigned int panning = 0; static unsigned int panning_cursor = 0; static unsigned int zoom_rb = 0; - SPDesktop *desktop = event_context->desktop; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); /// @todo REmove redundant /value in preference keys @@ -377,15 +378,14 @@ static gint sp_event_context_private_root_handler( case GDK_2BUTTON_PRESS: if (panning) { panning = 0; - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), - event->button.time); + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); ret = TRUE; } else { /* sp_desktop_dialog(); */ } break; - case GDK_BUTTON_PRESS: + case GDK_BUTTON_PRESS: // save drag origin xp = (gint) event->button.x; yp = (gint) event->button.y; @@ -395,54 +395,61 @@ static gint sp_event_context_private_root_handler( switch (event->button.button) { case 1: - if (event_context->space_panning) { - + if (this->space_panning) { // When starting panning, make sure there are no snap events pending because these might disable the panning again - sp_event_context_discard_delayed_snap_event(event_context); + sp_event_context_discard_delayed_snap_event(this); panning = 1; + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK, NULL, event->button.time - 1); + ret = TRUE; } break; + case 2: if (event->button.state & GDK_SHIFT_MASK) { zoom_rb = 2; } else { - // When starting panning, make sure there are no snap events pending because these might disable the panning again - sp_event_context_discard_delayed_snap_event(event_context); + sp_event_context_discard_delayed_snap_event(this); panning = 2; + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK, NULL, event->button.time - 1); } + ret = TRUE; break; + case 3: - if (event->button.state & GDK_SHIFT_MASK || event->button.state - & GDK_CONTROL_MASK) { + if ((event->button.state & GDK_SHIFT_MASK) || (event->button.state & GDK_CONTROL_MASK)) { // When starting panning, make sure there are no snap events pending because these might disable the panning again - sp_event_context_discard_delayed_snap_event(event_context); + sp_event_context_discard_delayed_snap_event(this); panning = 3; + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK, NULL, event->button.time); + ret = TRUE; } else { sp_event_root_menu_popup(desktop, NULL, event); } break; + default: break; } break; + case GDK_MOTION_NOTIFY: if (panning) { if (panning == 4 && !xp && !yp ) { @@ -456,16 +463,14 @@ static gint sp_event_context_private_root_handler( | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK, NULL, event->motion.time - 1); - - } + if ((panning == 2 && !(event->motion.state & GDK_BUTTON2_MASK)) || (panning == 1 && !(event->motion.state & GDK_BUTTON1_MASK)) || (panning == 3 && !(event->motion.state & GDK_BUTTON3_MASK))) { /* Gdk seems to lose button release for us sometimes :-( */ panning = 0; - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), - event->button.time); + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); ret = TRUE; } else { if (within_tolerance && (abs((gint) event->motion.x - xp) @@ -474,6 +479,7 @@ static gint sp_event_context_private_root_handler( // do not drag if we're within tolerance from origin break; } + // Once the user has moved farther than tolerance from // the original location (indicating they intend to move // the object, not click), then always process the motion @@ -487,12 +493,12 @@ static gint sp_event_context_private_root_handler( if (panning_cursor == 0) { panning_cursor = 1; - sp_event_context_set_cursor(event_context, GDK_FLEUR); + sp_event_context_set_cursor(this, GDK_FLEUR); } Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point const moved_w(motion_w - button_w); - event_context->desktop->scroll_world(moved_w, true); // we're still scrolling, do not redraw + this->desktop->scroll_world(moved_w, true); // we're still scrolling, do not redraw ret = TRUE; } } else if (zoom_rb) { @@ -504,6 +510,7 @@ static gint sp_event_context_private_root_handler( < tolerance)) { break; // do not drag if we're within tolerance from origin } + // Once the user has moved farther than tolerance from the original location // (indicating they intend to move the object, not click), then always process the // motion notify coordinates as given (no snapping back to origin) @@ -514,30 +521,40 @@ static gint sp_event_context_private_root_handler( } else { Inkscape::Rubberband::get(desktop)->start(desktop, motion_dt); } - if (zoom_rb == 2) + + if (zoom_rb == 2) { gobble_motion_events(GDK_BUTTON2_MASK); + } } break; + case GDK_BUTTON_RELEASE: xp = yp = 0; + if (panning_cursor == 1) { panning_cursor = 0; - GtkWidget *w = GTK_WIDGET(sp_desktop_canvas(event_context->desktop)); - gdk_window_set_cursor(gtk_widget_get_window (w), event_context->cursor); + GtkWidget *w = GTK_WIDGET(sp_desktop_canvas(this->desktop)); + gdk_window_set_cursor(gtk_widget_get_window (w), this->cursor); } + if (within_tolerance && (panning || zoom_rb)) { zoom_rb = 0; + if (panning) { panning = 0; sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); } + Geom::Point const event_w(event->button.x, event->button.y); Geom::Point const event_dt(desktop->w2d(event_w)); + double const zoom_inc = prefs->getDoubleLimited( "/options/zoomincrement/value", M_SQRT2, 1.01, 10); + desktop->zoom_relative_keep_point(event_dt, (event->button.state & GDK_SHIFT_MASK) ? 1 / zoom_inc : zoom_inc); + desktop->updateNow(); ret = TRUE; } else if (panning == event->button.button) { @@ -551,24 +568,28 @@ static gint sp_event_context_private_root_handler( // even if few intermediate steps were visible) Geom::Point const motion_w(event->button.x, event->button.y); Geom::Point const moved_w(motion_w - button_w); - event_context->desktop->scroll_world(moved_w); + + this->desktop->scroll_world(moved_w); desktop->updateNow(); ret = TRUE; } else if (zoom_rb == event->button.button) { zoom_rb = 0; - Geom::OptRect const b = - Inkscape::Rubberband::get(desktop)->getRectangle(); + + Geom::OptRect const b = Inkscape::Rubberband::get(desktop)->getRectangle(); Inkscape::Rubberband::get(desktop)->stop(); + if (b && !within_tolerance) { desktop->set_display_area(*b, 10); } + ret = TRUE; } - break; + case GDK_KEY_PRESS: { double const acceleration = prefs->getDoubleLimited( "/options/scrollingacceleration/value", 0, 0, 6); + int const key_scroll = prefs->getIntLimited("/options/keyscroll/value", 10, 0, 1000); @@ -581,12 +602,19 @@ static gint sp_event_context_private_root_handler( case GDK_KEY_ISO_Left_Tab: case GDK_KEY_F1: shortcut = get_group0_keyval(&event->key); - if (event->key.state & GDK_SHIFT_MASK) + + if (event->key.state & GDK_SHIFT_MASK) { shortcut |= SP_SHORTCUT_SHIFT_MASK; - if (event->key.state & GDK_CONTROL_MASK) + } + + if (event->key.state & GDK_CONTROL_MASK) { shortcut |= SP_SHORTCUT_CONTROL_MASK; - if (event->key.state & GDK_MOD1_MASK) + } + + if (event->key.state & GDK_MOD1_MASK) { shortcut |= SP_SHORTCUT_ALT_MASK; + } + ret = sp_shortcut_invoke(shortcut, desktop); break; @@ -600,6 +628,7 @@ static gint sp_event_context_private_root_handler( ret = TRUE; } break; + case GDK_KEY_W: case GDK_KEY_w: case GDK_KEY_F4: @@ -609,65 +638,78 @@ static gint sp_event_context_private_root_handler( ret = TRUE; } break; + case GDK_KEY_Left: // Ctrl Left case GDK_KEY_KP_Left: case GDK_KEY_KP_4: if (MOD__CTRL_ONLY(event)) { int i = (int) floor(key_scroll * accelerate_scroll(event, acceleration, sp_desktop_canvas(desktop))); + gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); - event_context->desktop->scroll_world(i, 0); + this->desktop->scroll_world(i, 0); ret = TRUE; } break; + case GDK_KEY_Up: // Ctrl Up case GDK_KEY_KP_Up: case GDK_KEY_KP_8: if (MOD__CTRL_ONLY(event)) { int i = (int) floor(key_scroll * accelerate_scroll(event, acceleration, sp_desktop_canvas(desktop))); + gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); - event_context->desktop->scroll_world(0, i); + this->desktop->scroll_world(0, i); ret = TRUE; } break; + case GDK_KEY_Right: // Ctrl Right case GDK_KEY_KP_Right: case GDK_KEY_KP_6: if (MOD__CTRL_ONLY(event)) { int i = (int) floor(key_scroll * accelerate_scroll(event, acceleration, sp_desktop_canvas(desktop))); + gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); - event_context->desktop->scroll_world(-i, 0); + this->desktop->scroll_world(-i, 0); ret = TRUE; } break; + case GDK_KEY_Down: // Ctrl Down case GDK_KEY_KP_Down: case GDK_KEY_KP_2: if (MOD__CTRL_ONLY(event)) { int i = (int) floor(key_scroll * accelerate_scroll(event, acceleration, sp_desktop_canvas(desktop))); + gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); - event_context->desktop->scroll_world(0, -i); + this->desktop->scroll_world(0, -i); ret = TRUE; } break; + case GDK_KEY_F10: if (MOD__SHIFT_ONLY(event)) { sp_event_root_menu_popup(desktop, NULL, event); ret = TRUE; } break; + case GDK_KEY_space: xp = yp = 0; within_tolerance = true; panning = 4; - event_context->space_panning = true; - event_context->_message_context->set(Inkscape::INFORMATION_MESSAGE, + + this->space_panning = true; + this->message_context->set(Inkscape::INFORMATION_MESSAGE, _("<b>Space+mouse move</b> to pan canvas")); + ret = TRUE; break; + case GDK_KEY_z: case GDK_KEY_Z: if (MOD__ALT_ONLY(event)) { @@ -675,31 +717,34 @@ static gint sp_event_context_private_root_handler( ret = TRUE; } break; + default: break; } } break; - case GDK_KEY_RELEASE: + case GDK_KEY_RELEASE: // Stop panning on any key release - if (event_context->space_panning) { - event_context->space_panning = false; - event_context->_message_context->clear(); + if (this->space_panning) { + this->space_panning = false; + this->message_context->clear(); } if (panning) { panning = 0; xp = yp = 0; + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->key.time); + desktop->updateNow(); } if (panning_cursor == 1) { panning_cursor = 0; - GtkWidget *w = GTK_WIDGET(sp_desktop_canvas(event_context->desktop)); - gdk_window_set_cursor(gtk_widget_get_window (w), event_context->cursor); + GtkWidget *w = GTK_WIDGET(sp_desktop_canvas(this->desktop)); + gdk_window_set_cursor(gtk_widget_get_window (w), this->cursor); } switch (get_group0_keyval(&event->key)) { @@ -709,8 +754,10 @@ static gint sp_event_context_private_root_handler( sp_toggle_selector(desktop); ret = TRUE; } + within_tolerance = false; break; + case GDK_KEY_Q: case GDK_KEY_q: if (desktop->quick_zoomed()) { @@ -718,13 +765,16 @@ static gint sp_event_context_private_root_handler( ret = TRUE; } break; + default: break; } break; + case GDK_SCROLL: { bool ctrl = (event->scroll.state & GDK_CONTROL_MASK); bool wheelzooms = prefs->getBool("/options/wheelzooms/value"); + int const wheel_scroll = prefs->getIntLimited( "/options/wheelscroll/value", 40, 0, 1000); @@ -740,9 +790,11 @@ static gint sp_event_context_private_root_handler( case GDK_SCROLL_UP: desktop->scroll_world(wheel_scroll, 0); break; + case GDK_SCROLL_DOWN: desktop->scroll_world(-wheel_scroll, 0); break; + default: break; } @@ -752,17 +804,21 @@ static gint sp_event_context_private_root_handler( double rel_zoom; double const zoom_inc = prefs->getDoubleLimited( "/options/zoomincrement/value", M_SQRT2, 1.01, 10); + switch (event->scroll.direction) { case GDK_SCROLL_UP: rel_zoom = zoom_inc; break; + case GDK_SCROLL_DOWN: rel_zoom = 1 / zoom_inc; break; + default: rel_zoom = 0.0; break; } + if (rel_zoom != 0.0) { Geom::Point const scroll_dt = desktop->point(); desktop->zoom_relative_keep_point(scroll_dt, rel_zoom); @@ -774,15 +830,19 @@ static gint sp_event_context_private_root_handler( case GDK_SCROLL_UP: desktop->scroll_world(0, wheel_scroll); break; + case GDK_SCROLL_DOWN: desktop->scroll_world(0, -wheel_scroll); break; + case GDK_SCROLL_LEFT: desktop->scroll_world(wheel_scroll, 0); break; + case GDK_SCROLL_RIGHT: desktop->scroll_world(-wheel_scroll, 0); break; + #if GTK_CHECK_VERSION(3,0,0) case GDK_SCROLL_SMOOTH: gdk_event_get_scroll_deltas(event, &delta_x, &delta_y); @@ -806,18 +866,23 @@ static gint sp_event_context_private_root_handler( * Only reacts to right mouse button at the moment. * \todo Fixme: do context sensitive popup menu on items. */ -gint sp_event_context_private_item_handler(SPEventContext *ec, SPItem *item, - GdkEvent *event) { +//gint sp_event_context_private_item_handler(SPEventContext *ec, SPItem *item, +// GdkEvent *event) { +// +// return ec->ceventcontext->item_handler(item, event); +//} + +bool SPEventContext::item_handler(SPItem* item, GdkEvent* event) { int ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: - if ((event->button.button == 3) && !(event->button.state - & GDK_SHIFT_MASK || event->button.state & GDK_CONTROL_MASK)) { - sp_event_root_menu_popup(ec->desktop, item, event); + if ((event->button.button == 3) && !((event->button.state & GDK_SHIFT_MASK) || (event->button.state & GDK_CONTROL_MASK))) { + sp_event_root_menu_popup(this->desktop, item, event); ret = TRUE; } break; + default: break; } @@ -838,70 +903,54 @@ bool sp_event_context_knot_mouseover(SPEventContext *ec) } /** - * An observer that relays pref changes to the derived classes. - */ -class ToolPrefObserver: public Inkscape::Preferences::Observer { -public: - ToolPrefObserver(Glib::ustring const &path, SPEventContext *ec) : - Inkscape::Preferences::Observer(path), _ec(ec) { - } - virtual void notify(Inkscape::Preferences::Entry const &val) { - if ((SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(_ec)))->set) { - (SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(_ec)))->set(_ec, - const_cast<Inkscape::Preferences::Entry*> (&val)); - } - } -private: - SPEventContext * const _ec; -}; - -/** * Creates new SPEventContext object and calls its virtual setup() function. * @todo This is bogus. pref_path should be a private property of the inheriting objects. */ -SPEventContext * -sp_event_context_new(GType type, SPDesktop *desktop, gchar const *pref_path, - unsigned int key) { - g_return_val_if_fail(g_type_is_a(type, SP_TYPE_EVENT_CONTEXT), NULL); - g_return_val_if_fail(desktop != NULL, NULL); - - SPEventContext * const ec = static_cast<SPEventContext*>(g_object_new(type, NULL)); - - ec->desktop = desktop; - ec->_message_context - = new Inkscape::MessageContext(desktop->messageStack()); - ec->key = key; - ec->pref_observer = NULL; - - if (pref_path) { - ec->pref_observer = new ToolPrefObserver(pref_path, ec); - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->addObserver(*(ec->pref_observer)); - } - - if ((SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->setup) - (SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->setup(ec); - - return ec; -} +//SPEventContext * +//sp_event_context_new(GType type, SPDesktop *desktop, gchar const *pref_path, +// unsigned int key) { +// g_return_val_if_fail(g_type_is_a(type, SP_TYPE_EVENT_CONTEXT), NULL); +// g_return_val_if_fail(desktop != NULL, NULL); +// +// SPEventContext * const ec = static_cast<SPEventContext*>(g_object_new(type, NULL)); +// +// ec->desktop = desktop; +// ec->_message_context +// = new Inkscape::MessageContext(desktop->messageStack()); +// ec->key = key; +// ec->pref_observer = NULL; +// +// if (pref_path) { +// ec->pref_observer = new ToolPrefObserver(pref_path, ec); +// +// Inkscape::Preferences *prefs = Inkscape::Preferences::get(); +// prefs->addObserver(*(ec->pref_observer)); +// } +// +//// if ((SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->setup) +//// (SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->setup(ec); +// ec->ceventcontext->setup(); +// +// return ec; +//} /** * Finishes SPEventContext. */ -void sp_event_context_finish(SPEventContext *ec) { - g_return_if_fail(ec != NULL); - g_return_if_fail(SP_IS_EVENT_CONTEXT(ec)); - - ec->enableSelectionCue(false); - - if (ec->next) { - g_warning("Finishing event context with active link\n"); - } - - if ((SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->finish) - (SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->finish(ec); -} +//void sp_event_context_finish(SPEventContext *ec) { +// g_return_if_fail(ec != NULL); +// g_return_if_fail(SP_IS_EVENT_CONTEXT(ec)); +// +// ec->enableSelectionCue(false); +// +//// if (ec->next) { +//// g_warning("Finishing event context with active link\n"); +//// } +// +//// if ((SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->finish) +//// (SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->finish(ec); +// ec->finish(); +//} //-------------------------------member functions @@ -956,12 +1005,16 @@ void sp_event_context_read(SPEventContext *ec, gchar const *key) { g_return_if_fail(SP_IS_EVENT_CONTEXT(ec)); g_return_if_fail(key != NULL); - if ((SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->set) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - Inkscape::Preferences::Entry val = prefs->getEntry( - ec->pref_observer->observed_path + '/' + key); - (SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->set(ec, &val); - } +// if ((SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->set) { +// Inkscape::Preferences *prefs = Inkscape::Preferences::get(); +// Inkscape::Preferences::Entry val = prefs->getEntry( +// ec->pref_observer->observed_path + '/' + key); +// (SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->set(ec, &val); +// } + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Inkscape::Preferences::Entry val = prefs->getEntry(ec->pref_observer->observed_path + '/' + key); + ec->set(val); } /** @@ -976,20 +1029,22 @@ void sp_event_context_activate(SPEventContext *ec) { // context should take care of this by itself. sp_event_context_discard_delayed_snap_event(ec); - if ((SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->activate) - (SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->activate(ec); +// if ((SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->activate) +// (SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->activate(ec); + ec->activate(); } /** * Calls virtual deactivate() function of SPEventContext. */ -void sp_event_context_deactivate(SPEventContext *ec) { - g_return_if_fail(ec != NULL); - g_return_if_fail(SP_IS_EVENT_CONTEXT(ec)); - - if ((SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->deactivate) - (SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->deactivate(ec); -} +//void sp_event_context_deactivate(SPEventContext *ec) { +// g_return_if_fail(ec != NULL); +// g_return_if_fail(SP_IS_EVENT_CONTEXT(ec)); +// +//// if ((SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->deactivate) +//// (SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ec)))->deactivate(ec); +// ec->deactivate(); +//} /** * Calls virtual root_handler(), the main event handling function. @@ -1029,7 +1084,9 @@ gint sp_event_context_virtual_root_handler(SPEventContext * event_context, GdkEv gint ret = false; if (event_context) { // If no event-context is available then do nothing, otherwise Inkscape would crash // (see the comment in SPDesktop::set_event_context, and bug LP #622350) - ret = (SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(event_context)))->root_handler(event_context, event); + //ret = (SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(event_context)))->root_handler(event_context, event); + ret = event_context->root_handler(event); + set_event_location(event_context->desktop, event); } return ret; @@ -1068,7 +1125,9 @@ gint sp_event_context_virtual_item_handler(SPEventContext * event_context, SPIte gint ret = false; if (event_context) { // If no event-context is available then do nothing, otherwise Inkscape would crash // (see the comment in SPDesktop::set_event_context, and bug LP #622350) - ret = (SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(event_context)))->item_handler(event_context, item, event); + //ret = (SP_EVENT_CONTEXT_CLASS(G_OBJECT_GET_CLASS(event_context)))->item_handler(event_context, item, event); + ret = event_context->item_handler(item, event); + if (!ret) { ret = sp_event_context_virtual_root_handler(event_context, event); } else { @@ -1159,10 +1218,12 @@ void sp_event_show_modifier_tip(Inkscape::MessageContext *message_context, */ guint get_group0_keyval(GdkEventKey *event) { guint keyval = 0; + gdk_keymap_translate_keyboard_state(gdk_keymap_get_for_display( gdk_display_get_default()), event->hardware_keycode, (GdkModifierType) event->state, 0 /*event->key.group*/, &keyval, NULL, NULL, NULL); + return keyval; } diff --git a/src/event-context.h b/src/event-context.h index e97a8ad8f..33bab5e3e 100644 --- a/src/event-context.h +++ b/src/event-context.h @@ -23,7 +23,7 @@ class GrDrag; class SPDesktop; class SPItem; class ShapeEditor; -struct SPEventContext; +class SPEventContext; namespace Inkscape { class MessageContext; @@ -33,13 +33,8 @@ namespace Inkscape { } } - -#define SP_TYPE_EVENT_CONTEXT (sp_event_context_get_type()) -#define SP_EVENT_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_EVENT_CONTEXT, SPEventContext)) -#define SP_EVENT_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_EVENT_CONTEXT, SPEventContextClass)) -#define SP_IS_EVENT_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_EVENT_CONTEXT)) - -GType sp_event_context_get_type(); +#define SP_EVENT_CONTEXT(obj) (dynamic_cast<SPEventContext*>((SPEventContext*)obj)) +#define SP_IS_EVENT_CONTEXT(obj) (dynamic_cast<const SPEventContext*>((const SPEventContext*)obj) != NULL) gboolean sp_event_context_snap_watchdog_callback(gpointer data); void sp_event_context_discard_delayed_snap_event(SPEventContext *ec); @@ -104,14 +99,15 @@ void sp_event_context_snap_delay_handler(SPEventContext *ec, gpointer const dse_ * plus few abstract base classes. Writing a new tool involves * subclassing SPEventContext. */ -struct SPEventContext : public GObject { +class SPEventContext { +public: void enableSelectionCue (bool enable=true); void enableGrDrag (bool enable=true); bool deleteSelectedDrag(bool just_one); - /// Desktop eventcontext stack - SPEventContext *next; - unsigned key; + SPEventContext(); + virtual ~SPEventContext(); + SPDesktop *desktop; Inkscape::Preferences::Observer *pref_observer; gchar const *const *cursor_shape; @@ -126,10 +122,10 @@ struct SPEventContext : public GObject { ///< be selected if this is a click not drag Inkscape::MessageContext *defaultMessageContext() { - return _message_context; + return message_context; } - Inkscape::MessageContext *_message_context; + Inkscape::MessageContext *message_context; Inkscape::SelCue *_selcue; @@ -143,20 +139,43 @@ struct SPEventContext : public GObject { DelayedSnapEvent *_delayed_snap_event; bool _dse_callback_in_process; - char const * tool_url; ///< the (preferences) url for the tool (if a subclass corresponding to a tool is used) -}; + virtual void setup(); + virtual void finish(); -/** - * The SPEvent vtable. - */ -struct SPEventContextClass : public GObjectClass { - void (* setup)(SPEventContext *ec); - void (* finish)(SPEventContext *ec); - void (* set)(SPEventContext *ec, Inkscape::Preferences::Entry *val); - void (* activate)(SPEventContext *ec); - void (* deactivate)(SPEventContext *ec); - gint (* root_handler)(SPEventContext *ec, GdkEvent *event); - gint (* item_handler)(SPEventContext *ec, SPItem *item, GdkEvent *event); + // Is called by our pref_observer if a preference has been changed. + virtual void set(const Inkscape::Preferences::Entry& val); + + virtual void activate(); + virtual void deactivate(); + + virtual bool root_handler(GdkEvent* event); + virtual bool item_handler(SPItem* item, GdkEvent* event); + + virtual const std::string& getPrefsPath() = 0; + + /** + * An observer that relays pref changes to the derived classes. + */ + class ToolPrefObserver: public Inkscape::Preferences::Observer { + public: + ToolPrefObserver(Glib::ustring const &path, SPEventContext *ec) : + Inkscape::Preferences::Observer(path), ec(ec) { + } + + virtual void notify(Inkscape::Preferences::Entry const &val) { + ec->set(val); + } + + private: + SPEventContext * const ec; + }; + +//protected: + void sp_event_context_update_cursor(); + +private: + SPEventContext(const SPEventContext&); + SPEventContext& operator=(const SPEventContext&); }; #define SP_EVENT_CONTEXT_DESKTOP(e) (SP_EVENT_CONTEXT(e)->desktop) @@ -164,11 +183,11 @@ struct SPEventContextClass : public GObjectClass { #define SP_EVENT_CONTEXT_STATIC 0 -SPEventContext *sp_event_context_new(GType type, SPDesktop *desktop, gchar const *pref_path, unsigned key); -void sp_event_context_finish(SPEventContext *ec); +//SPEventContext *sp_event_context_new(GType type, SPDesktop *desktop, gchar const *pref_path, unsigned key); +//void sp_event_context_finish(SPEventContext *ec); void sp_event_context_read(SPEventContext *ec, gchar const *key); void sp_event_context_activate(SPEventContext *ec); -void sp_event_context_deactivate(SPEventContext *ec); +//void sp_event_context_deactivate(SPEventContext *ec); gint sp_event_context_root_handler(SPEventContext *ec, GdkEvent *event); gint sp_event_context_virtual_root_handler(SPEventContext *ec, GdkEvent *event); @@ -180,7 +199,7 @@ void sp_event_root_menu_popup(SPDesktop *desktop, SPItem *item, GdkEvent *event) gint gobble_key_events(guint keyval, gint mask); gint gobble_motion_events(gint mask); -void sp_event_context_update_cursor(SPEventContext *ec); +//void sp_event_context_update_cursor(SPEventContext *ec); void sp_event_show_modifier_tip(Inkscape::MessageContext *message_context, GdkEvent *event, gchar const *ctrl_tip, gchar const *shift_tip, gchar const *alt_tip); @@ -192,14 +211,14 @@ SPItem *sp_event_context_over_item (SPDesktop *desktop, SPItem *item, Geom::Poin void sp_toggle_dropper(SPDesktop *dt); -ShapeEditor *sp_event_context_get_shape_editor (SPEventContext *ec); +//ShapeEditor *sp_event_context_get_shape_editor (SPEventContext *ec); bool sp_event_context_knot_mouseover(SPEventContext *ec); -void ec_shape_event_attr_changed(Inkscape::XML::Node *shape_repr, - gchar const *name, gchar const *old_value, gchar const *new_value, - bool const is_interactive, gpointer const data); - -void event_context_print_event_info(GdkEvent *event, bool print_return = true); +//void ec_shape_event_attr_changed(Inkscape::XML::Node *shape_repr, +// gchar const *name, gchar const *old_value, gchar const *new_value, +// bool const is_interactive, gpointer const data); +// +//void event_context_print_event_info(GdkEvent *event, bool print_return = true); #endif // SEEN_SP_EVENT_CONTEXT_H diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index a950fa177..4f9273cbb 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -1436,7 +1436,7 @@ CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle con return true; } -bool CairoRenderContext::renderImage(GdkPixbuf *pb, +bool CairoRenderContext::renderImage(Inkscape::Pixbuf *pb, Geom::Affine const &image_transform, SPStyle const * /*style*/) { g_assert( _is_valid ); @@ -1447,13 +1447,13 @@ bool CairoRenderContext::renderImage(GdkPixbuf *pb, _prepareRenderGraphic(); - int w = gdk_pixbuf_get_width (pb); - int h = gdk_pixbuf_get_height (pb); + int w = pb->width(); + int h = pb->height(); // TODO: reenable merge_opacity if useful float opacity = _state->opacity; - cairo_surface_t *image_surface = ink_cairo_surface_get_for_pixbuf(pb); + cairo_surface_t *image_surface = pb->getSurfaceRaw(); if (cairo_surface_status(image_surface)) { TRACE(("Image surface creation failed:\n%s\n", cairo_status_to_string(cairo_surface_status(image_surface)))); return false; diff --git a/src/extension/internal/cairo-render-context.h b/src/extension/internal/cairo-render-context.h index f8426aebe..8d3e63775 100644 --- a/src/extension/internal/cairo-render-context.h +++ b/src/extension/internal/cairo-render-context.h @@ -6,7 +6,7 @@ */ /* * Authors: - * Miklos Erdelyi <erdelyim@gmail.com> + * Miklos Erdelyi <erdelyim@gmail.com> * * Copyright (C) 2006 Miklos Erdelyi * @@ -29,9 +29,11 @@ #include <cairo.h> class SPClipPath; -struct SPMask; +class SPMask; namespace Inkscape { +class Pixbuf; + namespace Extension { namespace Internal { @@ -144,7 +146,7 @@ public: /* Rendering methods */ bool renderPathVector(Geom::PathVector const &pathv, SPStyle const *style, Geom::OptRect const &pbox); - bool renderImage(GdkPixbuf *pb, + bool renderImage(Inkscape::Pixbuf *pb, Geom::Affine const &image_transform, SPStyle const *style); bool renderGlyphtext(PangoFont *font, Geom::Affine const &font_matrix, std::vector<CairoGlyphInfo> const &glyphtext, SPStyle const *style); diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index 3463925b6..cace251cf 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -27,6 +27,7 @@ #include <signal.h> #include <errno.h> +#include <boost/scoped_ptr.hpp> #include "libnrtype/Layout-TNG.h" #include <2geom/transforms.h> @@ -347,8 +348,8 @@ static void sp_image_render(SPItem *item, CairoRenderContext *ctx) if (!image->pixbuf) return; if ((image->width.computed <= 0.0) || (image->height.computed <= 0.0)) return; - w = gdk_pixbuf_get_width (image->pixbuf); - h = gdk_pixbuf_get_height (image->pixbuf); + w = image->pixbuf->width(); + h = image->pixbuf->height(); double x = image->x.computed; double y = image->y.computed; @@ -497,22 +498,15 @@ static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx) GSList *items = NULL; items = g_slist_append(items, item); - GdkPixbuf *pb = sp_generate_internal_bitmap(document, NULL, - bbox->min()[Geom::X], bbox->min()[Geom::Y], bbox->max()[Geom::X], bbox->max()[Geom::Y], - width, height, res, res, (guint32) 0xffffff00, items ); + boost::scoped_ptr<Inkscape::Pixbuf> pb( + sp_generate_internal_bitmap(document, NULL, + bbox->min()[Geom::X], bbox->min()[Geom::Y], bbox->max()[Geom::X], bbox->max()[Geom::Y], + width, height, res, res, (guint32) 0xffffff00, items )); if (pb) { - TEST(gdk_pixbuf_save( pb, "bitmap.png", "png", NULL, NULL )); - - /* TODO: find a way to avoid a duplicate conversion between - * Cairo and GdkPixbuf pixel formats here. - * Internally, generate_internal_bitmap creates a Cairo surface, - * but then converts it to pixbuf format. In turn, renderImage() - * below converts back to Cairo format. - */ - ctx->renderImage(pb, t, item->style); - g_object_unref(pb); - pb = 0; + //TEST(gdk_pixbuf_save( pb, "bitmap.png", "png", NULL, NULL )); + + ctx->renderImage(pb.get(), t, item->style); } g_slist_free (items); } @@ -586,9 +580,9 @@ void CairoRenderer::renderItem(CairoRenderContext *ctx, SPItem *item) setStateForItem(ctx, item); CairoRenderState *state = ctx->getCurrentState(); - state->need_layer = ( state->mask || state->clip_path || state->opacity != 1.0 ); + state->need_layer = ( state->mask || state->opacity != 1.0 ); - // Draw item on a temporary surface so a mask, clip path, or opacity can be applied to it. + // Draw item on a temporary surface so a mask or opacity can be applied to it. if (state->need_layer) { state->merge_opacity = FALSE; ctx->pushLayer(); diff --git a/src/extension/internal/cairo-renderer.h b/src/extension/internal/cairo-renderer.h index 1ab8f1872..cfef6bdea 100644 --- a/src/extension/internal/cairo-renderer.h +++ b/src/extension/internal/cairo-renderer.h @@ -28,7 +28,7 @@ #include <cairo.h> class SPClipPath; -struct SPMask; +class SPMask; namespace Inkscape { namespace Extension { diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index 826a52ade..770257978 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -53,6 +53,7 @@ #include "sp-gradient.h" #include "sp-radial-gradient.h" #include "sp-linear-gradient.h" +#include "display/cairo-utils.h" #include "splivarot.h" // pieces for union on shapes #include "2geom/svg-path-parser.h" // to get from SVG text to Geom::Path @@ -333,7 +334,7 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) U_LOGBRUSH lb; uint32_t brush, fmode; MFDrawMode fill_mode; - GdkPixbuf *pixbuf; + Inkscape::Pixbuf *pixbuf; uint32_t brushStyle; int hatchType; U_COLORREF hatchColor; @@ -462,7 +463,7 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) int numCt; U_BITMAPINFOHEADER Bmih; PU_BITMAPINFO Bmi; - rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!! + rgba_px = (char *) pixbuf->pixels(); // Do NOT free this!!! colortype = U_BCBM_COLOR32; (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1); // Not sure why the next swap is needed because the preceding does it, and the code is identical @@ -528,7 +529,7 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) int linejoin = 0; uint32_t pen; uint32_t brushStyle; - GdkPixbuf *pixbuf; + Inkscape::Pixbuf *pixbuf; int hatchType; U_COLORREF hatchColor; U_COLORREF bkColor; @@ -565,7 +566,7 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) brush_classify(pat, 0, &pixbuf, &hatchType, &hatchColor, &bkColor); if (pixbuf) { brushStyle = U_BS_DIBPATTERN; - rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!! + rgba_px = (char *) pixbuf->pixels(); // Do NOT free this!!! colortype = U_BCBM_COLOR32; (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1); // Not sure why the next swap is needed because the preceding does it, and the code is identical diff --git a/src/extension/internal/gdkpixbuf-input.cpp b/src/extension/internal/gdkpixbuf-input.cpp index 117c2fe39..87cf8a9cc 100644 --- a/src/extension/internal/gdkpixbuf-input.cpp +++ b/src/extension/internal/gdkpixbuf-input.cpp @@ -1,6 +1,7 @@ #ifdef HAVE_CONFIG_H # include <config.h> #endif +#include <boost/scoped_ptr.hpp> #include <glib/gprintf.h> #include <glibmm/i18n.h> #include "document-private.h" @@ -14,15 +15,11 @@ #include "document-undo.h" #include "util/units.h" #include "image-resolution.h" +#include "display/cairo-utils.h" #include <set> namespace Inkscape { -namespace IO { -// this is defined in sp-image.cpp -GdkPixbuf* pixbuf_new_from_file(char const *filename, time_t &modTime, gchar*& pixPath); -} - namespace Extension { namespace Internal { @@ -47,9 +44,7 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) } SPDocument *doc = NULL; - gchar *pixpath = NULL; - time_t dummy; - GdkPixbuf *pb = Inkscape::IO::pixbuf_new_from_file(uri, dummy, pixpath); + boost::scoped_ptr<Inkscape::Pixbuf> pb(Inkscape::Pixbuf::create_from_file(uri)); // TODO: the pixbuf is created again from the base64-encoded attribute in SPImage. // Find a way to create the pixbuf only once. @@ -59,8 +54,8 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) bool saved = DocumentUndo::getUndoSensitive(doc); DocumentUndo::setUndoSensitive(doc, false); // no need to undo in this temporary document - double width = gdk_pixbuf_get_width(pb); - double height = gdk_pixbuf_get_height(pb); + double width = pb->width(); + double height = pb->height(); double defaultxdpi = prefs->getDouble("/dialogs/import/defaultxdpi/value", Inkscape::Util::Quantity::convert(1, "in", "px")); bool forcexdpi = prefs->getBool("/dialogs/import/forcexdpi"); ImageResolution *ir = 0; @@ -91,7 +86,7 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) sp_repr_set_svg_double(image_node, "height", height); if (embed) { - sp_embed_image(image_node, pb); + sp_embed_image(image_node, pb.get()); } else { // convert filename to uri gchar* _uri = g_filename_to_uri(uri, NULL, NULL); @@ -103,9 +98,6 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) } } - g_object_set_data(G_OBJECT(pb), "cairo_surface", NULL); - g_object_unref(pb); - // Add it to the current layer doc->getRoot()->appendChildRepr(image_node); Inkscape::GC::release(image_node); diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index 55d8d8352..7e6941232 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -417,7 +417,7 @@ Flowing in rectangle is possible, not in arb shape. } SPRect *frame = SP_RECT(frame_item); - Geom::Rect framebox = sp_rect_get_rect(frame) * transform(); + Geom::Rect framebox = frame->getRect() * transform(); // get position and alignment // Align on topleft corner. diff --git a/src/extension/internal/latex-text-renderer.h b/src/extension/internal/latex-text-renderer.h index 9aecf5ed9..77d12bc61 100644 --- a/src/extension/internal/latex-text-renderer.h +++ b/src/extension/internal/latex-text-renderer.h @@ -22,7 +22,7 @@ #include <stack> class SPItem; -struct SPRoot; +class SPRoot; namespace Inkscape { namespace Extension { diff --git a/src/extension/internal/metafile-print.cpp b/src/extension/internal/metafile-print.cpp index 9d080bd96..1e7735410 100644 --- a/src/extension/internal/metafile-print.cpp +++ b/src/extension/internal/metafile-print.cpp @@ -266,7 +266,7 @@ void PrintMetafile::hatch_classify(char *name, int *hatchType, U_COLORREF *hatch // otherwise hatchType is set to -1 and hatchColor is not defined. // -void PrintMetafile::brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor) +void PrintMetafile::brush_classify(SPObject *parent, int depth, Inkscape::Pixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor) { if (depth == 0) { *epixbuf = NULL; diff --git a/src/extension/internal/metafile-print.h b/src/extension/internal/metafile-print.h index e64ba92f3..cba4d564d 100644 --- a/src/extension/internal/metafile-print.h +++ b/src/extension/internal/metafile-print.h @@ -30,6 +30,8 @@ struct SPGradient; struct SPObject; namespace Inkscape { +class Pixbuf; + namespace Extension { namespace Internal { @@ -93,7 +95,7 @@ protected: U_COLORREF weight_colors(U_COLORREF c1, U_COLORREF c2, double t); void hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor); - void brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor); + void brush_classify(SPObject *parent, int depth, Inkscape::Pixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor); static void swapRBinRGBA(char *px, int pixels); int hold_gradient(void *gr, int mode); diff --git a/src/extension/internal/odf.cpp b/src/extension/internal/odf.cpp index 9f745cdea..a7c14387f 100644 --- a/src/extension/internal/odf.cpp +++ b/src/extension/internal/odf.cpp @@ -1484,7 +1484,7 @@ bool OdfOutput::processGradient(SPItem *item, for (SPStop *stop = grvec->getFirstStop(); stop ; stop = stop->getNextStop()) { - unsigned long rgba = sp_stop_get_rgba32(stop); + unsigned long rgba = stop->get_rgba32(); unsigned long rgb = (rgba >> 8) & 0xffffff; double opacity = (static_cast<double>(rgba & 0xff)) / 256.0; GradientStop gs(rgb, opacity); diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp index e5816073e..99262b109 100644 --- a/src/extension/internal/wmf-print.cpp +++ b/src/extension/internal/wmf-print.cpp @@ -56,6 +56,7 @@ #include "sp-gradient.h" #include "sp-radial-gradient.h" #include "sp-linear-gradient.h" +#include "display/cairo-utils.h" #include "splivarot.h" // pieces for union on shapes #include "2geom/svg-path-parser.h" // to get from SVG text to Geom::Path @@ -336,7 +337,7 @@ int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) U_WLOGBRUSH lb; uint32_t brush, fmode; MFDrawMode fill_mode; - GdkPixbuf *pixbuf; + Inkscape::Pixbuf *pixbuf; uint32_t brushStyle; int hatchType; U_COLORREF hatchColor; @@ -464,7 +465,7 @@ int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) int numCt; U_BITMAPINFOHEADER Bmih; PU_BITMAPINFO Bmi; - rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!! + rgba_px = (char *) pixbuf->pixels(); // Do NOT free this!!! colortype = U_BCBM_COLOR32; (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1); // Not sure why the next swap is needed because the preceding does it, and the code is identical @@ -1112,10 +1113,10 @@ unsigned int PrintWmf::image( g_error("Fatal programming error in PrintWmf::image at EMRHEADER"); } - x1 = atof(style->object->getAttribute("x")); - y1 = atof(style->object->getAttribute("y")); - dw = atof(style->object->getAttribute("width")); - dh = atof(style->object->getAttribute("height")); + x1 = g_ascii_strtod(style->object->getAttribute("x"), NULL); + y1 = g_ascii_strtod(style->object->getAttribute("y"), NULL); + dw = g_ascii_strtod(style->object->getAttribute("width"), NULL); + dh = g_ascii_strtod(style->object->getAttribute("height"), NULL); Geom::Point pLL(x1, y1); Geom::Point pLL2 = pLL * tf; //location of LL corner in Inkscape coordinates diff --git a/src/factory.h b/src/factory.h new file mode 100644 index 000000000..a1df55277 --- /dev/null +++ b/src/factory.h @@ -0,0 +1,116 @@ +/** @file + * Generic Factory + *//* + * Authors: + * Markus Engel + * + * Copyright (C) 2013 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef FACTORY_H_SEEN +#define FACTORY_H_SEEN + +#include <exception> +#include <map> +#include <string> +#include "xml/node.h" + +/** + * A simple singleton implementation. + */ +template <class T> +struct Singleton { + static T &instance() { + static T inst; + return inst; + } +}; + +namespace FactoryExceptions { +class TypeNotRegistered : public std::exception { +public: + TypeNotRegistered(std::string const &type) + : std::exception() + , _type_string(type) { + } + + virtual ~TypeNotRegistered() throw() { + } + + char const *what() const throw() { + return _type_string.c_str(); + } + +private: + std::string const _type_string; +}; +} // namespace FactoryExceptions + +/** + * A Factory for creating objects which can be identified by strings. + */ +template <class BaseObject> +class Factory { +public: + typedef BaseObject *CreateFunction(); + + bool registerObject(std::string const &id, CreateFunction *creator) { + return this->_object_map.insert(std::make_pair(id, creator)).second; + } + + BaseObject *createObject(std::string const &id) const { + typename std::map<std::string const, CreateFunction *>::const_iterator it = this->_object_map.find(id); + + if (it == this->_object_map.end()) { + throw FactoryExceptions::TypeNotRegistered(id); + } + + return it->second(); + } + +private: + std::map<std::string const, CreateFunction *> _object_map; +}; + + +struct NodeTraits { + static std::string get_type_string(Inkscape::XML::Node const &node) { + std::string name; + + switch (node.type()) { + case Inkscape::XML::TEXT_NODE: + name = "string"; + break; + + case Inkscape::XML::ELEMENT_NODE: { + gchar const *const sptype = node.attribute("sodipodi:type"); + + if (sptype) { + name = sptype; + } else { + name = node.name(); + } + break; + } + default: + name = ""; + break; + } + + return name; + } +}; + +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/filter-chemistry.cpp b/src/filter-chemistry.cpp index be030e12f..0f9138560 100644 --- a/src/filter-chemistry.cpp +++ b/src/filter-chemistry.cpp @@ -208,6 +208,15 @@ new_filter_gaussian_blur (SPDocument *document, gdouble radius, double expansion set_filter_area(repr, radius, expansion, expansionX, expansionY, width, height); + /* Inkscape now supports both sRGB and linear color-interpolation-filters. + * But, for the moment, keep sRGB as default value for new filters. + * historically set to sRGB and doesn't require conversion between + * filter cairo surfaces and other types of cairo surfaces. lp:1127103 */ + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property(css, "color-interpolation-filters", "sRGB"); + sp_repr_css_change(repr, css, "style"); + sp_repr_css_attr_unref(css); + //create feGaussianBlur node Inkscape::XML::Node *b_repr; b_repr = xml_doc->createElement("svg:feGaussianBlur"); @@ -260,6 +269,15 @@ new_filter_blend_gaussian_blur (SPDocument *document, const char *blendmode, gdo repr = xml_doc->createElement("svg:filter"); repr->setAttribute("inkscape:collect", "always"); + /* Inkscape now supports both sRGB and linear color-interpolation-filters. + * But, for the moment, keep sRGB as default value for new filters. + * historically set to sRGB and doesn't require conversion between + * filter cairo surfaces and other types of cairo surfaces. lp:1127103 */ + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property(css, "color-interpolation-filters", "sRGB"); + sp_repr_css_change(repr, css, "style"); + sp_repr_css_attr_unref(css); + // Append the new filter node to defs defs->appendChild(repr); Inkscape::GC::release(repr); diff --git a/src/filter-chemistry.h b/src/filter-chemistry.h index b00e33bcc..2ac3ebe8f 100644 --- a/src/filter-chemistry.h +++ b/src/filter-chemistry.h @@ -19,8 +19,8 @@ #include "display/nr-filter-types.h" class SPDocument; -struct SPFilter; -struct SPFilterPrimitive; +class SPFilter; +class SPFilterPrimitive; class SPItem; class SPObject; diff --git a/src/filters/blend.cpp b/src/filters/blend.cpp index a43927e81..219a099d1 100644 --- a/src/filters/blend.cpp +++ b/src/filters/blend.cpp @@ -30,35 +30,23 @@ #include "display/nr-filter-blend.h" #include "display/nr-filter-types.h" -/* FeBlend base class */ -static void sp_feBlend_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feBlend_release(SPObject *object); -static void sp_feBlend_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feBlend_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_feBlend_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_feBlend_build_renderer(SPFilterPrimitive *sp_prim, Inkscape::Filters::Filter *filter); - -G_DEFINE_TYPE(SPFeBlend, sp_feBlend, SP_TYPE_FILTER_PRIMITIVE); - -static void -sp_feBlend_class_init(SPFeBlendClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass; +#include "sp-factory.h" - sp_object_class->build = sp_feBlend_build; - sp_object_class->release = sp_feBlend_release; - sp_object_class->write = sp_feBlend_write; - sp_object_class->set = sp_feBlend_set; - sp_object_class->update = sp_feBlend_update; +namespace { + SPObject* createBlend() { + return new SPFeBlend(); + } - sp_primitive_class->build_renderer = sp_feBlend_build_renderer; + bool blendRegistered = SPFactory::instance().registerObject("svg:feBlend", createBlend); } -static void -sp_feBlend_init(SPFeBlend *feBlend) +SPFeBlend::SPFeBlend() + : SPFilterPrimitive(), blend_mode(Inkscape::Filters::BLEND_NORMAL), + in2(Inkscape::Filters::NR_FILTER_SLOT_NOT_SET) { - feBlend->in2 = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET; +} + +SPFeBlend::~SPFeBlend() { } /** @@ -66,43 +54,36 @@ sp_feBlend_init(SPFeBlend *feBlend) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_feBlend_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - SPFeBlend *blend = SP_FEBLEND(object); - - if (((SPObjectClass *) sp_feBlend_parent_class)->build) { - ((SPObjectClass *) sp_feBlend_parent_class)->build(object, document, repr); - } +void SPFeBlend::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive::build(document, repr); /*LOAD ATTRIBUTES FROM REPR HERE*/ - object->readAttr( "mode" ); - object->readAttr( "in2" ); + this->readAttr( "mode" ); + this->readAttr( "in2" ); /* Unlike normal in, in2 is required attribute. Make sure, we can call * it by some name. */ - if (blend->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET || - blend->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT) + if (this->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET || + this->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT) { - SPFilter *parent = SP_FILTER(object->parent); - blend->in2 = sp_filter_primitive_name_previous_out(blend); - repr->setAttribute("in2", sp_filter_name_for_image(parent, blend->in2)); + SPFilter *parent = SP_FILTER(this->parent); + this->in2 = sp_filter_primitive_name_previous_out(this); + repr->setAttribute("in2", sp_filter_name_for_image(parent, this->in2)); } } /** * Drops any allocated memory. */ -static void -sp_feBlend_release(SPObject *object) -{ - if (((SPObjectClass *) sp_feBlend_parent_class)->release) - ((SPObjectClass *) sp_feBlend_parent_class)->release(object); +void SPFeBlend::release() { + SPFilterPrimitive::release(); } -static Inkscape::Filters::FilterBlendMode sp_feBlend_readmode(gchar const *value) -{ - if (!value) return Inkscape::Filters::BLEND_NORMAL; +static Inkscape::Filters::FilterBlendMode sp_feBlend_readmode(gchar const *value) { + if (!value) { + return Inkscape::Filters::BLEND_NORMAL; + } + switch (value[0]) { case 'n': if (strncmp(value, "normal", 6) == 0) @@ -128,103 +109,97 @@ static Inkscape::Filters::FilterBlendMode sp_feBlend_readmode(gchar const *value // do nothing by default break; } + return Inkscape::Filters::BLEND_NORMAL; } /** * Sets a specific value in the SPFeBlend. */ -static void -sp_feBlend_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeBlend *feBlend = SP_FEBLEND(object); - (void)feBlend; - +void SPFeBlend::set(unsigned int key, gchar const *value) { Inkscape::Filters::FilterBlendMode mode; int input; + switch(key) { /*DEAL WITH SETTING ATTRIBUTES HERE*/ case SP_ATTR_MODE: mode = sp_feBlend_readmode(value); - if (mode != feBlend->blend_mode) { - feBlend->blend_mode = mode; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (mode != this->blend_mode) { + this->blend_mode = mode; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_IN2: - input = sp_filter_primitive_read_in(feBlend, value); - if (input != feBlend->in2) { - feBlend->in2 = input; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + input = sp_filter_primitive_read_in(this, value); + + if (input != this->in2) { + this->in2 = input; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; default: - if (((SPObjectClass *) sp_feBlend_parent_class)->set) - ((SPObjectClass *) sp_feBlend_parent_class)->set(object, key, value); + SPFilterPrimitive::set(key, value); break; } - } /** * Receives update notifications. */ -static void -sp_feBlend_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPFeBlend *blend = SP_FEBLEND(object); - +void SPFeBlend::update(SPCtx *ctx, guint flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { - object->readAttr( "mode" ); - object->readAttr( "in2" ); + this->readAttr( "mode" ); + this->readAttr( "in2" ); } /* Unlike normal in, in2 is required attribute. Make sure, we can call * it by some name. */ - if (blend->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET || - blend->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT) + if (this->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET || + this->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT) { - SPFilter *parent = SP_FILTER(object->parent); - blend->in2 = sp_filter_primitive_name_previous_out(blend); + SPFilter *parent = SP_FILTER(this->parent); + this->in2 = sp_filter_primitive_name_previous_out(this); - //XML Tree being used directly here while it shouldn't be. - object->getRepr()->setAttribute("in2", sp_filter_name_for_image(parent, blend->in2)); + // TODO: XML Tree being used directly here while it shouldn't be. + this->getRepr()->setAttribute("in2", sp_filter_name_for_image(parent, this->in2)); } - if (((SPObjectClass *) sp_feBlend_parent_class)->update) { - ((SPObjectClass *) sp_feBlend_parent_class)->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_feBlend_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ - SPFeBlend *blend = SP_FEBLEND(object); - SPFilter *parent = SP_FILTER(object->parent); +Inkscape::XML::Node* SPFeBlend::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { + SPFilter *parent = SP_FILTER(this->parent); if (!repr) { repr = doc->createElement("svg:feBlend"); } - gchar const *out_name = sp_filter_name_for_image(parent, blend->in2); + gchar const *out_name = sp_filter_name_for_image(parent, this->in2); + if (out_name) { repr->setAttribute("in2", out_name); } else { SPObject *i = parent->children; - while (i && i->next != object) i = i->next; + + while (i && i->next != this) { + i = i->next; + } + SPFilterPrimitive *i_prim = SP_FILTER_PRIMITIVE(i); out_name = sp_filter_name_for_image(parent, i_prim->image_out); repr->setAttribute("in2", out_name); + if (!out_name) { g_warning("Unable to set in2 for feBlend"); } } char const *mode; - switch(blend->blend_mode) { + switch(this->blend_mode) { case Inkscape::Filters::BLEND_NORMAL: mode = "normal"; break; case Inkscape::Filters::BLEND_MULTIPLY: @@ -238,30 +213,27 @@ sp_feBlend_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML:: default: mode = 0; } + repr->setAttribute("mode", mode); - if (((SPObjectClass *) sp_feBlend_parent_class)->write) { - ((SPObjectClass *) sp_feBlend_parent_class)->write(object, doc, repr, flags); - } + SPFilterPrimitive::write(doc, repr, flags); return repr; } -static void sp_feBlend_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - g_assert(primitive != NULL); +void SPFeBlend::build_renderer(Inkscape::Filters::Filter* filter) { + g_assert(this != NULL); g_assert(filter != NULL); - SPFeBlend *sp_blend = SP_FEBLEND(primitive); - int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_BLEND); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); Inkscape::Filters::FilterBlend *nr_blend = dynamic_cast<Inkscape::Filters::FilterBlend*>(nr_primitive); g_assert(nr_blend != NULL); - sp_filter_primitive_renderer_common(primitive, nr_primitive); + sp_filter_primitive_renderer_common(this, nr_primitive); - nr_blend->set_mode(sp_blend->blend_mode); - nr_blend->set_input(1, sp_blend->in2); + nr_blend->set_mode(this->blend_mode); + nr_blend->set_input(1, this->in2); } /* diff --git a/src/filters/blend.h b/src/filters/blend.h index 5d65c92fc..d5af9fe7d 100644 --- a/src/filters/blend.h +++ b/src/filters/blend.h @@ -16,23 +16,29 @@ #include "sp-filter-primitive.h" #include "display/nr-filter-blend.h" -#define SP_TYPE_FEBLEND (sp_feBlend_get_type()) -#define SP_FEBLEND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEBLEND, SPFeBlend)) -#define SP_FEBLEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEBLEND, SPFeBlendClass)) -#define SP_IS_FEBLEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEBLEND)) -#define SP_IS_FEBLEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEBLEND)) +#define SP_FEBLEND(obj) (dynamic_cast<SPFeBlend*>((SPObject*)obj)) +#define SP_IS_FEBLEND(obj) (dynamic_cast<const SPFeBlend*>((SPObject*)obj) != NULL) + +class SPFeBlend : public SPFilterPrimitive { +public: + SPFeBlend(); + virtual ~SPFeBlend(); -struct SPFeBlend : public SPFilterPrimitive { Inkscape::Filters::FilterBlendMode blend_mode; int in2; -}; -struct SPFeBlendClass { - SPFilterPrimitiveClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); -GType sp_feBlend_get_type(); + virtual void set(unsigned int key, const gchar* value); + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); +}; #endif /* !SP_FEBLEND_H_SEEN */ diff --git a/src/filters/colormatrix.cpp b/src/filters/colormatrix.cpp index aaf1c2986..58f601a65 100644 --- a/src/filters/colormatrix.cpp +++ b/src/filters/colormatrix.cpp @@ -29,64 +29,49 @@ #include "display/nr-filter.h" #include "display/nr-filter-colormatrix.h" -/* FeColorMatrix base class */ -static void sp_feColorMatrix_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feColorMatrix_release(SPObject *object); -static void sp_feColorMatrix_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feColorMatrix_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_feColorMatrix_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_feColorMatrix_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter); - -G_DEFINE_TYPE(SPFeColorMatrix, sp_feColorMatrix, SP_TYPE_FILTER_PRIMITIVE); - -static void -sp_feColorMatrix_class_init(SPFeColorMatrixClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass; - - sp_object_class->build = sp_feColorMatrix_build; - sp_object_class->release = sp_feColorMatrix_release; - sp_object_class->write = sp_feColorMatrix_write; - sp_object_class->set = sp_feColorMatrix_set; - sp_object_class->update = sp_feColorMatrix_update; - sp_primitive_class->build_renderer = sp_feColorMatrix_build_renderer; +#include "sp-factory.h" + +namespace { + SPObject* createColorMatrix() { + return new SPFeColorMatrix(); + } + + bool colorMatrixRegistered = SPFactory::instance().registerObject("svg:feColorMatrix", createColorMatrix); } -static void -sp_feColorMatrix_init(SPFeColorMatrix */*feColorMatrix*/) +SPFeColorMatrix::SPFeColorMatrix() + : SPFilterPrimitive(), type(Inkscape::Filters::COLORMATRIX_MATRIX), value(0) { } +SPFeColorMatrix::~SPFeColorMatrix() { +} + /** * Reads the Inkscape::XML::Node, and initializes SPFeColorMatrix variables. For this to get called, * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_feColorMatrix_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_feColorMatrix_parent_class)->build) { - ((SPObjectClass *) sp_feColorMatrix_parent_class)->build(object, document, repr); - } +void SPFeColorMatrix::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive::build(document, repr); - /*LOAD ATTRIBUTES FROM REPR HERE*/ - object->readAttr( "type" ); - object->readAttr( "values" ); + /*LOAD ATTRIBUTES FROM REPR HERE*/ + this->readAttr( "type" ); + this->readAttr( "values" ); } /** * Drops any allocated memory. */ -static void -sp_feColorMatrix_release(SPObject *object) -{ - if (((SPObjectClass *) sp_feColorMatrix_parent_class)->release) - ((SPObjectClass *) sp_feColorMatrix_parent_class)->release(object); +void SPFeColorMatrix::release() { + SPFilterPrimitive::release(); } static Inkscape::Filters::FilterColorMatrixType sp_feColorMatrix_read_type(gchar const *value){ - if (!value) return Inkscape::Filters::COLORMATRIX_MATRIX; //matrix is default + if (!value) { + return Inkscape::Filters::COLORMATRIX_MATRIX; //matrix is default + } + switch(value[0]){ case 'm': if (strcmp(value, "matrix") == 0) return Inkscape::Filters::COLORMATRIX_MATRIX; @@ -101,38 +86,35 @@ static Inkscape::Filters::FilterColorMatrixType sp_feColorMatrix_read_type(gchar if (strcmp(value, "luminanceToAlpha") == 0) return Inkscape::Filters::COLORMATRIX_LUMINANCETOALPHA; break; } + return Inkscape::Filters::COLORMATRIX_MATRIX; //matrix is default } /** * Sets a specific value in the SPFeColorMatrix. */ -static void -sp_feColorMatrix_set(SPObject *object, unsigned int key, gchar const *str) -{ - SPFeColorMatrix *feColorMatrix = SP_FECOLORMATRIX(object); - (void)feColorMatrix; - +void SPFeColorMatrix::set(unsigned int key, gchar const *str) { Inkscape::Filters::FilterColorMatrixType read_type; + /*DEAL WITH SETTING ATTRIBUTES HERE*/ switch(key) { case SP_ATTR_TYPE: read_type = sp_feColorMatrix_read_type(str); - if (feColorMatrix->type != read_type){ - feColorMatrix->type = read_type; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->type != read_type){ + this->type = read_type; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_VALUES: if (str){ - feColorMatrix->values = helperfns_read_vector(str); - feColorMatrix->value = helperfns_read_number(str, HELPERFNS_NO_WARNING); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->values = helperfns_read_vector(str); + this->value = helperfns_read_number(str, HELPERFNS_NO_WARNING); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; default: - if (((SPObjectClass *) sp_feColorMatrix_parent_class)->set) - ((SPObjectClass *) sp_feColorMatrix_parent_class)->set(object, key, str); + SPFilterPrimitive::set(key, str); break; } } @@ -140,9 +122,7 @@ sp_feColorMatrix_set(SPObject *object, unsigned int key, gchar const *str) /** * Receives update notifications. */ -static void -sp_feColorMatrix_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPFeColorMatrix::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { @@ -150,45 +130,37 @@ sp_feColorMatrix_update(SPObject *object, SPCtx *ctx, guint flags) } - if (((SPObjectClass *) sp_feColorMatrix_parent_class)->update) { - ((SPObjectClass *) sp_feColorMatrix_parent_class)->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_feColorMatrix_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPFeColorMatrix::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - if (((SPObjectClass *) sp_feColorMatrix_parent_class)->write) { - ((SPObjectClass *) sp_feColorMatrix_parent_class)->write(object, doc, repr, flags); - } + SPFilterPrimitive::write(doc, repr, flags); return repr; } -static void sp_feColorMatrix_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - g_assert(primitive != NULL); +void SPFeColorMatrix::build_renderer(Inkscape::Filters::Filter* filter) { + g_assert(this != NULL); g_assert(filter != NULL); - SPFeColorMatrix *sp_colormatrix = SP_FECOLORMATRIX(primitive); - int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_COLORMATRIX); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); Inkscape::Filters::FilterColorMatrix *nr_colormatrix = dynamic_cast<Inkscape::Filters::FilterColorMatrix*>(nr_primitive); g_assert(nr_colormatrix != NULL); - sp_filter_primitive_renderer_common(primitive, nr_primitive); - nr_colormatrix->set_type(sp_colormatrix->type); - nr_colormatrix->set_value(sp_colormatrix->value); - nr_colormatrix->set_values(sp_colormatrix->values); + sp_filter_primitive_renderer_common(this, nr_primitive); + nr_colormatrix->set_type(this->type); + nr_colormatrix->set_value(this->value); + nr_colormatrix->set_values(this->values); } /* diff --git a/src/filters/colormatrix.h b/src/filters/colormatrix.h index 558f01070..2a1c403f1 100644 --- a/src/filters/colormatrix.h +++ b/src/filters/colormatrix.h @@ -15,23 +15,30 @@ #include "sp-filter-primitive.h" #include "display/nr-filter-colormatrix.h" -#define SP_TYPE_FECOLORMATRIX (sp_feColorMatrix_get_type()) -#define SP_FECOLORMATRIX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FECOLORMATRIX, SPFeColorMatrix)) -#define SP_FECOLORMATRIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FECOLORMATRIX, SPFeColorMatrixClass)) -#define SP_IS_FECOLORMATRIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FECOLORMATRIX)) -#define SP_IS_FECOLORMATRIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FECOLORMATRIX)) +#define SP_FECOLORMATRIX(obj) (dynamic_cast<SPFeColorMatrix*>((SPObject*)obj)) +#define SP_IS_FECOLORMATRIX(obj) (dynamic_cast<const SPFeColorMatrix*>((SPObject*)obj) != NULL) + +class SPFeColorMatrix : public SPFilterPrimitive { +public: + SPFeColorMatrix(); + virtual ~SPFeColorMatrix(); -struct SPFeColorMatrix : public SPFilterPrimitive { Inkscape::Filters::FilterColorMatrixType type; gdouble value; std::vector<gdouble> values; -}; -struct SPFeColorMatrixClass { - SPFilterPrimitiveClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void set(unsigned int key, const gchar* value); -GType sp_feColorMatrix_get_type(); + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); +}; #endif /* !SP_FECOLORMATRIX_H_SEEN */ diff --git a/src/filters/componenttransfer-funcnode.cpp b/src/filters/componenttransfer-funcnode.cpp index 446009e1d..7c5191700 100644 --- a/src/filters/componenttransfer-funcnode.cpp +++ b/src/filters/componenttransfer-funcnode.cpp @@ -31,127 +31,12 @@ #include "macros.h" /* FeFuncNode class */ - -static void sp_fefuncnode_class_init(SPFeFuncNodeClass *klass); -static void sp_fefuncnode_init(SPFeFuncNode *fefuncnode); - -static void sp_fefuncnode_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_fefuncnode_release(SPObject *object); -static void sp_fefuncnode_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_fefuncnode_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_fefuncnode_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -static SPObjectClass *feFuncNode_parent_class; - -GType -sp_fefuncR_get_type() -{ - static GType fefuncnode_type = 0; - - if (!fefuncnode_type) { - GTypeInfo fefuncnode_info = { - sizeof(SPFeFuncNodeClass), - NULL, NULL, - (GClassInitFunc) sp_fefuncnode_class_init, - NULL, NULL, - sizeof(SPFeFuncNode), - 16, - (GInstanceInitFunc) sp_fefuncnode_init, - NULL, /* value_table */ - }; - fefuncnode_type = g_type_register_static(SP_TYPE_OBJECT, "SPFeFuncR", &fefuncnode_info, (GTypeFlags)0); - } - return fefuncnode_type; -} - -GType -sp_fefuncG_get_type() -{ - static GType fefuncnode_type = 0; - - if (!fefuncnode_type) { - GTypeInfo fefuncnode_info = { - sizeof(SPFeFuncNodeClass), - NULL, NULL, - (GClassInitFunc) sp_fefuncnode_class_init, - NULL, NULL, - sizeof(SPFeFuncNode), - 16, - (GInstanceInitFunc) sp_fefuncnode_init, - NULL, /* value_table */ - }; - fefuncnode_type = g_type_register_static(SP_TYPE_OBJECT, "SPFeFuncG", &fefuncnode_info, (GTypeFlags)0); - } - return fefuncnode_type; -} - -GType -sp_fefuncB_get_type() -{ - static GType fefuncnode_type = 0; - - if (!fefuncnode_type) { - GTypeInfo fefuncnode_info = { - sizeof(SPFeFuncNodeClass), - NULL, NULL, - (GClassInitFunc) sp_fefuncnode_class_init, - NULL, NULL, - sizeof(SPFeFuncNode), - 16, - (GInstanceInitFunc) sp_fefuncnode_init, - NULL, /* value_table */ - }; - fefuncnode_type = g_type_register_static(SP_TYPE_OBJECT, "SPFeFuncB", &fefuncnode_info, (GTypeFlags)0); - } - return fefuncnode_type; -} - -GType -sp_fefuncA_get_type() -{ - static GType fefuncnode_type = 0; - - if (!fefuncnode_type) { - GTypeInfo fefuncnode_info = { - sizeof(SPFeFuncNodeClass), - NULL, NULL, - (GClassInitFunc) sp_fefuncnode_class_init, - NULL, NULL, - sizeof(SPFeFuncNode), - 16, - (GInstanceInitFunc) sp_fefuncnode_init, - NULL, /* value_table */ - }; - fefuncnode_type = g_type_register_static(SP_TYPE_OBJECT, "SPFeFuncA", &fefuncnode_info, (GTypeFlags)0); - } - return fefuncnode_type; -} - -static void -sp_fefuncnode_class_init(SPFeFuncNodeClass *klass) -{ - - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - - feFuncNode_parent_class = (SPObjectClass*)g_type_class_peek_parent(klass); - - sp_object_class->build = sp_fefuncnode_build; - sp_object_class->release = sp_fefuncnode_release; - sp_object_class->write = sp_fefuncnode_write; - sp_object_class->set = sp_fefuncnode_set; - sp_object_class->update = sp_fefuncnode_update; +SPFeFuncNode::SPFeFuncNode() + : SPObject(), type(Inkscape::Filters::COMPONENTTRANSFER_TYPE_IDENTITY), + slope(1), intercept(0), amplitude(1), exponent(1), offset(0) { } -static void -sp_fefuncnode_init(SPFeFuncNode *fefuncnode) -{ - fefuncnode->type = Inkscape::Filters::COMPONENTTRANSFER_TYPE_IDENTITY; - //fefuncnode->tableValues = NULL; - fefuncnode->slope = 1; - fefuncnode->intercept = 0; - fefuncnode->amplitude = 1; - fefuncnode->exponent = 1; - fefuncnode->offset = 0; +SPFeFuncNode::~SPFeFuncNode() { } /** @@ -159,125 +44,135 @@ sp_fefuncnode_init(SPFeFuncNode *fefuncnode) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_fefuncnode_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) feFuncNode_parent_class)->build) { - ((SPObjectClass *) feFuncNode_parent_class)->build(object, document, repr); - } +void SPFeFuncNode::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPObject::build(document, repr); //Read values of key attributes from XML nodes into object. - object->readAttr( "type" ); - object->readAttr( "tableValues" ); - object->readAttr( "slope" ); - object->readAttr( "intercept" ); - object->readAttr( "amplitude" ); - object->readAttr( "exponent" ); - object->readAttr( "offset" ); + this->readAttr( "type" ); + this->readAttr( "tableValues" ); + this->readAttr( "slope" ); + this->readAttr( "intercept" ); + this->readAttr( "amplitude" ); + this->readAttr( "exponent" ); + this->readAttr( "offset" ); //is this necessary? - document->addResource("fefuncnode", object); //maybe feFuncR, fefuncG, feFuncB and fefuncA ? + document->addResource("fefuncnode", this); //maybe feFuncR, fefuncG, feFuncB and fefuncA ? } /** * Drops any allocated memory. */ -static void sp_fefuncnode_release(SPObject *object) -{ - //SPFeFuncNode *fefuncnode = SP_FEFUNCNODE(object); - - if ( object->document ) { +void SPFeFuncNode::release() { + if ( this->document ) { // Unregister ourselves - object->document->removeResource("fefuncnode", object); + this->document->removeResource("fefuncnode", this); } //TODO: release resources here } static Inkscape::Filters::FilterComponentTransferType sp_feComponenttransfer_read_type(gchar const *value){ - if (!value) return Inkscape::Filters::COMPONENTTRANSFER_TYPE_ERROR; //type attribute is REQUIRED. + if (!value) { + return Inkscape::Filters::COMPONENTTRANSFER_TYPE_ERROR; //type attribute is REQUIRED. + } + switch(value[0]){ case 'i': - if (strncmp(value, "identity", 8) == 0) return Inkscape::Filters::COMPONENTTRANSFER_TYPE_IDENTITY; + if (strncmp(value, "identity", 8) == 0) { + return Inkscape::Filters::COMPONENTTRANSFER_TYPE_IDENTITY; + } break; case 't': - if (strncmp(value, "table", 5) == 0) return Inkscape::Filters::COMPONENTTRANSFER_TYPE_TABLE; + if (strncmp(value, "table", 5) == 0) { + return Inkscape::Filters::COMPONENTTRANSFER_TYPE_TABLE; + } break; case 'd': - if (strncmp(value, "discrete", 8) == 0) return Inkscape::Filters::COMPONENTTRANSFER_TYPE_DISCRETE; + if (strncmp(value, "discrete", 8) == 0) { + return Inkscape::Filters::COMPONENTTRANSFER_TYPE_DISCRETE; + } break; case 'l': - if (strncmp(value, "linear", 6) == 0) return Inkscape::Filters::COMPONENTTRANSFER_TYPE_LINEAR; + if (strncmp(value, "linear", 6) == 0) { + return Inkscape::Filters::COMPONENTTRANSFER_TYPE_LINEAR; + } break; case 'g': - if (strncmp(value, "gamma", 5) == 0) return Inkscape::Filters::COMPONENTTRANSFER_TYPE_GAMMA; + if (strncmp(value, "gamma", 5) == 0) { + return Inkscape::Filters::COMPONENTTRANSFER_TYPE_GAMMA; + } break; } + return Inkscape::Filters::COMPONENTTRANSFER_TYPE_ERROR; //type attribute is REQUIRED. } /** * Sets a specific value in the SPFeFuncNode. */ -static void -sp_fefuncnode_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeFuncNode *feFuncNode = SP_FEFUNCNODE(object); +void SPFeFuncNode::set(unsigned int key, gchar const *value) { Inkscape::Filters::FilterComponentTransferType type; double read_num; + switch(key) { case SP_ATTR_TYPE: type = sp_feComponenttransfer_read_type(value); - if(type != feFuncNode->type) { - feFuncNode->type = type; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if(type != this->type) { + this->type = type; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_TABLEVALUES: if (value){ - feFuncNode->tableValues = helperfns_read_vector(value); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->tableValues = helperfns_read_vector(value); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_SLOPE: read_num = value ? helperfns_read_number(value) : 1; - if (read_num != feFuncNode->slope) { - feFuncNode->slope = read_num; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_num != this->slope) { + this->slope = read_num; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_INTERCEPT: read_num = value ? helperfns_read_number(value) : 0; - if (read_num != feFuncNode->intercept) { - feFuncNode->intercept = read_num; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_num != this->intercept) { + this->intercept = read_num; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_AMPLITUDE: read_num = value ? helperfns_read_number(value) : 1; - if (read_num != feFuncNode->amplitude) { - feFuncNode->amplitude = read_num; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_num != this->amplitude) { + this->amplitude = read_num; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_EXPONENT: read_num = value ? helperfns_read_number(value) : 1; - if (read_num != feFuncNode->exponent) { - feFuncNode->exponent = read_num; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_num != this->exponent) { + this->exponent = read_num; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_OFFSET: read_num = value ? helperfns_read_number(value) : 0; - if (read_num != feFuncNode->offset) { - feFuncNode->offset = read_num; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_num != this->offset) { + this->offset = read_num; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; default: - if (((SPObjectClass *) feFuncNode_parent_class)->set) - ((SPObjectClass *) feFuncNode_parent_class)->set(object, key, value); + SPObject::set(key, value); break; } } @@ -285,48 +180,34 @@ sp_fefuncnode_set(SPObject *object, unsigned int key, gchar const *value) /** * * Receives update notifications. * */ -static void -sp_fefuncnode_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPFeFuncNode *feFuncNode = SP_FEFUNCNODE(object); - (void)feFuncNode; - +void SPFeFuncNode::update(SPCtx *ctx, guint flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { /* do something to trigger redisplay, updates? */ //TODO - //object->readAttr( "azimuth" ); - //object->readAttr( "elevation" ); + //this->readAttr( "azimuth" ); + //this->readAttr( "elevation" ); } - if (((SPObjectClass *) feFuncNode_parent_class)->update) { - ((SPObjectClass *) feFuncNode_parent_class)->update(object, ctx, flags); - } + SPObject::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_fefuncnode_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ - SPFeFuncNode *fefuncnode = SP_FEFUNCNODE(object); - +Inkscape::XML::Node* SPFeFuncNode::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - (void)fefuncnode; /* -TODO: I'm not sure what to do here... + TODO: I'm not sure what to do here... if (fefuncnode->azimuth_set) sp_repr_set_css_double(repr, "azimuth", fefuncnode->azimuth); if (fefuncnode->elevation_set) sp_repr_set_css_double(repr, "elevation", fefuncnode->elevation);*/ - if (((SPObjectClass *) feFuncNode_parent_class)->write) { - ((SPObjectClass *) feFuncNode_parent_class)->write(object, doc, repr, flags); - } + SPObject::write(doc, repr, flags); return repr; } diff --git a/src/filters/componenttransfer-funcnode.h b/src/filters/componenttransfer-funcnode.h index ae1b2f8bb..a5f813e1e 100644 --- a/src/filters/componenttransfer-funcnode.h +++ b/src/filters/componenttransfer-funcnode.h @@ -18,23 +18,34 @@ #include "sp-object.h" #include "display/nr-filter-component-transfer.h" -#define SP_TYPE_FEFUNCR (sp_fefuncR_get_type()) -#define SP_TYPE_FEFUNCG (sp_fefuncG_get_type()) -#define SP_TYPE_FEFUNCB (sp_fefuncB_get_type()) -#define SP_TYPE_FEFUNCA (sp_fefuncA_get_type()) +//#define SP_TYPE_FEFUNCR (sp_fefuncR_get_type()) +//#define SP_TYPE_FEFUNCG (sp_fefuncG_get_type()) +//#define SP_TYPE_FEFUNCB (sp_fefuncB_get_type()) +//#define SP_TYPE_FEFUNCA (sp_fefuncA_get_type()) -#define SP_IS_FEFUNCR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEFUNCR)) -#define SP_IS_FEFUNCG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEFUNCG)) -#define SP_IS_FEFUNCB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEFUNCB)) -#define SP_IS_FEFUNCA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEFUNCA)) +// CPPIFY: Casting macros buggy, as these aren't classes. +//#define SP_IS_FEFUNCR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEFUNCR)) +//#define SP_IS_FEFUNCG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEFUNCG)) +//#define SP_IS_FEFUNCB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEFUNCB)) +//#define SP_IS_FEFUNCA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEFUNCA)) -#define SP_FEFUNCNODE(obj) (SP_IS_FEFUNCR(obj) ? G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEFUNCR, SPFeFuncNode) : (SP_IS_FEFUNCG(obj) ? G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEFUNCG, SPFeFuncNode) : (SP_IS_FEFUNCB(obj) ? G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEFUNCB, SPFeFuncNode):(SP_IS_FEFUNCA(obj) ? G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEFUNCA, SPFeFuncNode): NULL)))) +#define SP_FEFUNCNODE(obj) (dynamic_cast<SPFeFuncNode*>((SPObject*)obj)) -#define SP_FEFUNCNODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEFUNCNODE, SPFeFuncNodeClass)) +//#define SP_IS_FEFUNCR(obj) (obj != NULL && static_cast<const SPObject*>(obj)->typeHierarchy.count(typeid(SPFeFuncNode))) +//#define SP_IS_FEFUNCG(obj) (obj != NULL && static_cast<const SPObject*>(obj)->typeHierarchy.count(typeid(SPFeFuncNode))) +//#define SP_IS_FEFUNCB(obj) (obj != NULL && static_cast<const SPObject*>(obj)->typeHierarchy.count(typeid(SPFeFuncNode))) +//#define SP_IS_FEFUNCA(obj) (obj != NULL && static_cast<const SPObject*>(obj)->typeHierarchy.count(typeid(SPFeFuncNode))) -#define SP_IS_FEFUNCNODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEFUNCNODE)) +#define SP_IS_FEFUNCR(obj) (dynamic_cast<const SPFeFuncNode*>((SPObject*)obj) != NULL) +#define SP_IS_FEFUNCG(obj) (dynamic_cast<const SPFeFuncNode*>((SPObject*)obj) != NULL) +#define SP_IS_FEFUNCB(obj) (dynamic_cast<const SPFeFuncNode*>((SPObject*)obj) != NULL) +#define SP_IS_FEFUNCA(obj) (dynamic_cast<const SPFeFuncNode*>((SPObject*)obj) != NULL) + +class SPFeFuncNode : public SPObject { +public: + SPFeFuncNode(); + virtual ~SPFeFuncNode(); -struct SPFeFuncNode : public SPObject { Inkscape::Filters::FilterComponentTransferType type; std::vector<double> tableValues; double slope; @@ -42,17 +53,17 @@ struct SPFeFuncNode : public SPObject { double amplitude; double exponent; double offset; -}; -/* Component Transfer funcNode class */ -struct SPFeFuncNodeClass { - SPObjectClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); -GType sp_fefuncR_get_type(); -GType sp_fefuncG_get_type(); -GType sp_fefuncB_get_type(); -GType sp_fefuncA_get_type(); + virtual void set(unsigned int key, const gchar* value); + + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); +}; #endif /* !SP_FECOMPONENTTRANSFER_FUNCNODE_H_SEEN */ diff --git a/src/filters/componenttransfer.cpp b/src/filters/componenttransfer.cpp index 71e1ffe8e..96d1ea0bf 100644 --- a/src/filters/componenttransfer.cpp +++ b/src/filters/componenttransfer.cpp @@ -27,55 +27,36 @@ #include "display/nr-filter.h" #include "display/nr-filter-component-transfer.h" -/* FeComponentTransfer base class */ -static void sp_feComponentTransfer_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feComponentTransfer_release(SPObject *object); -static void sp_feComponentTransfer_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feComponentTransfer_update(SPObject *object, SPCtx *ctx, guint flags); -static void sp_feComponentTransfer_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter); -static void sp_feComponentTransfer_remove_child(SPObject *object, Inkscape::XML::Node *child); -static void sp_feComponentTransfer_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref); -static Inkscape::XML::Node *sp_feComponentTransfer_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -G_DEFINE_TYPE(SPFeComponentTransfer, sp_feComponentTransfer, SP_TYPE_FILTER_PRIMITIVE); - -static void -sp_feComponentTransfer_class_init(SPFeComponentTransferClass *klass) +#include "sp-factory.h" + +namespace { + SPObject* createComponentTransfer() { + return new SPFeComponentTransfer(); + } + + bool componentTransferRegistered = SPFactory::instance().registerObject("svg:feComponentTransfer", createComponentTransfer); +} + +SPFeComponentTransfer::SPFeComponentTransfer() + : SPFilterPrimitive(), renderer(NULL) { - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass; - - sp_object_class->build = sp_feComponentTransfer_build; - sp_object_class->release = sp_feComponentTransfer_release; - sp_object_class->write = sp_feComponentTransfer_write; - sp_object_class->set = sp_feComponentTransfer_set; - sp_object_class->update = sp_feComponentTransfer_update; - sp_object_class->child_added = sp_feComponentTransfer_child_added; - sp_object_class->remove_child = sp_feComponentTransfer_remove_child; - - sp_primitive_class->build_renderer = sp_feComponentTransfer_build_renderer; } -static void -sp_feComponentTransfer_init(SPFeComponentTransfer */*feComponentTransfer*/) -{} +SPFeComponentTransfer::~SPFeComponentTransfer() { +} /** * Reads the Inkscape::XML::Node, and initializes SPFeComponentTransfer variables. For this to get called, * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_feComponentTransfer_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_feComponentTransfer_parent_class)->build) { - ((SPObjectClass *) sp_feComponentTransfer_parent_class)->build(object, document, repr); - } +void SPFeComponentTransfer::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive::build(document, repr); - /*LOAD ATTRIBUTES FROM REPR HERE*/ + /*LOAD ATTRIBUTES FROM REPR HERE*/ - //do we need this? - //document->addResource("feComponentTransfer", object); + //do we need this? + //document->addResource("feComponentTransfer", object); } static void sp_feComponentTransfer_children_modified(SPFeComponentTransfer *sp_componenttransfer) @@ -114,58 +95,38 @@ static void sp_feComponentTransfer_children_modified(SPFeComponentTransfer *sp_c /** * Callback for child_added event. */ -static void -sp_feComponentTransfer_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) -{ - SPFeComponentTransfer *f = SP_FECOMPONENTTRANSFER(object); +void SPFeComponentTransfer::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { + SPFilterPrimitive::child_added(child, ref); - if (((SPObjectClass *) sp_feComponentTransfer_parent_class)->child_added) - (* ((SPObjectClass *) sp_feComponentTransfer_parent_class)->child_added)(object, child, ref); - - sp_feComponentTransfer_children_modified(f); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + sp_feComponentTransfer_children_modified(this); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } - /** * Callback for remove_child event. */ -static void -sp_feComponentTransfer_remove_child(SPObject *object, Inkscape::XML::Node *child) -{ - SPFeComponentTransfer *f = SP_FECOMPONENTTRANSFER(object); - - if (((SPObjectClass *) sp_feComponentTransfer_parent_class)->remove_child) - (* ((SPObjectClass *) sp_feComponentTransfer_parent_class)->remove_child)(object, child); +void SPFeComponentTransfer::remove_child(Inkscape::XML::Node *child) { + SPFilterPrimitive::remove_child(child); - sp_feComponentTransfer_children_modified(f); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + sp_feComponentTransfer_children_modified(this); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } /** * Drops any allocated memory. */ -static void -sp_feComponentTransfer_release(SPObject *object) -{ - if (((SPObjectClass *) sp_feComponentTransfer_parent_class)->release) - ((SPObjectClass *) sp_feComponentTransfer_parent_class)->release(object); +void SPFeComponentTransfer::release() { + SPFilterPrimitive::release(); } /** * Sets a specific value in the SPFeComponentTransfer. */ -static void -sp_feComponentTransfer_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeComponentTransfer *feComponentTransfer = SP_FECOMPONENTTRANSFER(object); - (void)feComponentTransfer; - +void SPFeComponentTransfer::set(unsigned int key, gchar const *value) { switch(key) { /*DEAL WITH SETTING ATTRIBUTES HERE*/ default: - if (((SPObjectClass *) sp_feComponentTransfer_parent_class)->set) - ((SPObjectClass *) sp_feComponentTransfer_parent_class)->set(object, key, value); + SPFilterPrimitive::set(key, value); break; } } @@ -173,9 +134,7 @@ sp_feComponentTransfer_set(SPObject *object, unsigned int key, gchar const *valu /** * Receives update notifications. */ -static void -sp_feComponentTransfer_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPFeComponentTransfer::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { @@ -183,46 +142,38 @@ sp_feComponentTransfer_update(SPObject *object, SPCtx *ctx, guint flags) } - if (((SPObjectClass *) sp_feComponentTransfer_parent_class)->update) { - ((SPObjectClass *) sp_feComponentTransfer_parent_class)->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_feComponentTransfer_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPFeComponentTransfer::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - if (((SPObjectClass *) sp_feComponentTransfer_parent_class)->write) { - ((SPObjectClass *) sp_feComponentTransfer_parent_class)->write(object, doc, repr, flags); - } + SPFilterPrimitive::write(doc, repr, flags); return repr; } -static void sp_feComponentTransfer_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - g_assert(primitive != NULL); +void SPFeComponentTransfer::build_renderer(Inkscape::Filters::Filter* filter) { + g_assert(this != NULL); g_assert(filter != NULL); - SPFeComponentTransfer *sp_componenttransfer = SP_FECOMPONENTTRANSFER(primitive); - int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_COMPONENTTRANSFER); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); Inkscape::Filters::FilterComponentTransfer *nr_componenttransfer = dynamic_cast<Inkscape::Filters::FilterComponentTransfer*>(nr_primitive); g_assert(nr_componenttransfer != NULL); - sp_componenttransfer->renderer = nr_componenttransfer; - sp_filter_primitive_renderer_common(primitive, nr_primitive); + this->renderer = nr_componenttransfer; + sp_filter_primitive_renderer_common(this, nr_primitive); - sp_feComponentTransfer_children_modified(sp_componenttransfer); //do we need it?! + sp_feComponentTransfer_children_modified(this); //do we need it?! } /* diff --git a/src/filters/componenttransfer.h b/src/filters/componenttransfer.h index deb6fb740..8dbe91db1 100644 --- a/src/filters/componenttransfer.h +++ b/src/filters/componenttransfer.h @@ -13,27 +13,36 @@ #include "sp-filter-primitive.h" -#define SP_TYPE_FECOMPONENTTRANSFER (sp_feComponentTransfer_get_type()) -#define SP_FECOMPONENTTRANSFER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FECOMPONENTTRANSFER, SPFeComponentTransfer)) -#define SP_FECOMPONENTTRANSFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FECOMPONENTTRANSFER, SPFeComponentTransferClass)) -#define SP_IS_FECOMPONENTTRANSFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FECOMPONENTTRANSFER)) -#define SP_IS_FECOMPONENTTRANSFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FECOMPONENTTRANSFER)) +#define SP_FECOMPONENTTRANSFER(obj) (dynamic_cast<SPFeComponentTransfer*>((SPObject*)obj)) +#define SP_IS_FECOMPONENTTRANSFER(obj) (dynamic_cast<const SPFeComponentTransfer*>((SPObject*)obj) != NULL) namespace Inkscape { namespace Filters { class FilterComponentTransfer; } } -struct SPFeComponentTransfer : public SPFilterPrimitive { +class SPFeComponentTransfer : public SPFilterPrimitive { +public: + SPFeComponentTransfer(); + virtual ~SPFeComponentTransfer(); + Inkscape::Filters::FilterComponentTransfer *renderer; -}; -struct SPFeComponentTransferClass { - SPFilterPrimitiveClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node* child); -GType sp_feComponentTransfer_get_type(); + virtual void set(unsigned int key, const gchar* value); + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); +}; #endif /* !SP_FECOMPONENTTRANSFER_H_SEEN */ diff --git a/src/filters/composite.cpp b/src/filters/composite.cpp index d490f336c..3c214a7a1 100644 --- a/src/filters/composite.cpp +++ b/src/filters/composite.cpp @@ -25,40 +25,23 @@ #include "display/nr-filter-composite.h" #include "sp-filter.h" -/* FeComposite base class */ -static void sp_feComposite_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feComposite_release(SPObject *object); -static void sp_feComposite_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feComposite_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_feComposite_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_feComposite_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter); - -G_DEFINE_TYPE(SPFeComposite, sp_feComposite, SP_TYPE_FILTER_PRIMITIVE); - -static void -sp_feComposite_class_init(SPFeCompositeClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass; +#include "sp-factory.h" - sp_object_class->build = sp_feComposite_build; - sp_object_class->release = sp_feComposite_release; - sp_object_class->write = sp_feComposite_write; - sp_object_class->set = sp_feComposite_set; - sp_object_class->update = sp_feComposite_update; +namespace { + SPObject* createComposite() { + return new SPFeComposite(); + } - sp_primitive_class->build_renderer = sp_feComposite_build_renderer; + bool compositeRegistered = SPFactory::instance().registerObject("svg:feComposite", createComposite); } -static void -sp_feComposite_init(SPFeComposite *feComposite) +SPFeComposite::SPFeComposite() + : SPFilterPrimitive(), composite_operator(COMPOSITE_DEFAULT), + k1(0), k2(0), k3(0), k4(0), in2(Inkscape::Filters::NR_FILTER_SLOT_NOT_SET) { - feComposite->composite_operator = COMPOSITE_DEFAULT; - feComposite->k1 = 0; - feComposite->k2 = 0; - feComposite->k3 = 0; - feComposite->k4 = 0; - feComposite->in2 = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET; +} + +SPFeComposite::~SPFeComposite() { } /** @@ -66,140 +49,133 @@ sp_feComposite_init(SPFeComposite *feComposite) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_feComposite_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_feComposite_parent_class)->build) { - ((SPObjectClass *) sp_feComposite_parent_class)->build(object, document, repr); - } - - SPFeComposite *comp = SP_FECOMPOSITE(object); - - object->readAttr( "operator" ); - if (comp->composite_operator == COMPOSITE_ARITHMETIC) { - object->readAttr( "k1" ); - object->readAttr( "k2" ); - object->readAttr( "k3" ); - object->readAttr( "k4" ); - } - object->readAttr( "in2" ); - - /* Unlike normal in, in2 is required attribute. Make sure, we can call - * it by some name. */ - if (comp->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET || - comp->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT) - { - SPFilter *parent = SP_FILTER(object->parent); - comp->in2 = sp_filter_primitive_name_previous_out(comp); - repr->setAttribute("in2", sp_filter_name_for_image(parent, comp->in2)); - } +void SPFeComposite::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive::build(document, repr); + + this->readAttr( "operator" ); + + if (this->composite_operator == COMPOSITE_ARITHMETIC) { + this->readAttr( "k1" ); + this->readAttr( "k2" ); + this->readAttr( "k3" ); + this->readAttr( "k4" ); + } + + this->readAttr( "in2" ); + + /* Unlike normal in, in2 is required attribute. Make sure, we can call + * it by some name. */ + if (this->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET || + this->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT) + { + SPFilter *parent = SP_FILTER(this->parent); + this->in2 = sp_filter_primitive_name_previous_out(this); + repr->setAttribute("in2", sp_filter_name_for_image(parent, this->in2)); + } } /** * Drops any allocated memory. */ -static void -sp_feComposite_release(SPObject *object) -{ - if (((SPObjectClass *) sp_feComposite_parent_class)->release) - ((SPObjectClass *) sp_feComposite_parent_class)->release(object); +void SPFeComposite::release() { + SPFilterPrimitive::release(); } static FeCompositeOperator sp_feComposite_read_operator(gchar const *value) { - if (!value) return COMPOSITE_DEFAULT; - - if (strcmp(value, "over") == 0) return COMPOSITE_OVER; - else if (strcmp(value, "in") == 0) return COMPOSITE_IN; - else if (strcmp(value, "out") == 0) return COMPOSITE_OUT; - else if (strcmp(value, "atop") == 0) return COMPOSITE_ATOP; - else if (strcmp(value, "xor") == 0) return COMPOSITE_XOR; - else if (strcmp(value, "arithmetic") == 0) return COMPOSITE_ARITHMETIC; + if (!value) { + return COMPOSITE_DEFAULT; + } + + if (strcmp(value, "over") == 0) { + return COMPOSITE_OVER; + } else if (strcmp(value, "in") == 0) { + return COMPOSITE_IN; + } else if (strcmp(value, "out") == 0) { + return COMPOSITE_OUT; + } else if (strcmp(value, "atop") == 0) { + return COMPOSITE_ATOP; + } else if (strcmp(value, "xor") == 0) { + return COMPOSITE_XOR; + } else if (strcmp(value, "arithmetic") == 0) { + return COMPOSITE_ARITHMETIC; + } + return COMPOSITE_DEFAULT; } /** * Sets a specific value in the SPFeComposite. */ -static void -sp_feComposite_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeComposite *feComposite = SP_FECOMPOSITE(object); - (void)feComposite; - +void SPFeComposite::set(unsigned int key, gchar const *value) { int input; FeCompositeOperator op; double k_n; + switch(key) { /*DEAL WITH SETTING ATTRIBUTES HERE*/ case SP_ATTR_OPERATOR: op = sp_feComposite_read_operator(value); - if (op != feComposite->composite_operator) { - feComposite->composite_operator = op; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (op != this->composite_operator) { + this->composite_operator = op; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_K1: k_n = value ? helperfns_read_number(value) : 0; - if (k_n != feComposite->k1) { - feComposite->k1 = k_n; - if (feComposite->composite_operator == COMPOSITE_ARITHMETIC) - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (k_n != this->k1) { + this->k1 = k_n; + if (this->composite_operator == COMPOSITE_ARITHMETIC) + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_K2: k_n = value ? helperfns_read_number(value) : 0; - if (k_n != feComposite->k2) { - feComposite->k2 = k_n; - if (feComposite->composite_operator == COMPOSITE_ARITHMETIC) - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (k_n != this->k2) { + this->k2 = k_n; + if (this->composite_operator == COMPOSITE_ARITHMETIC) + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_K3: k_n = value ? helperfns_read_number(value) : 0; - if (k_n != feComposite->k3) { - feComposite->k3 = k_n; - if (feComposite->composite_operator == COMPOSITE_ARITHMETIC) - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (k_n != this->k3) { + this->k3 = k_n; + if (this->composite_operator == COMPOSITE_ARITHMETIC) + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_K4: k_n = value ? helperfns_read_number(value) : 0; - if (k_n != feComposite->k4) { - feComposite->k4 = k_n; - if (feComposite->composite_operator == COMPOSITE_ARITHMETIC) - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (k_n != this->k4) { + this->k4 = k_n; + if (this->composite_operator == COMPOSITE_ARITHMETIC) + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_IN2: - input = sp_filter_primitive_read_in(feComposite, value); - if (input != feComposite->in2) { - feComposite->in2 = input; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + input = sp_filter_primitive_read_in(this, value); + if (input != this->in2) { + this->in2 = input; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; default: - if (((SPObjectClass *) sp_feComposite_parent_class)->set) - ((SPObjectClass *) sp_feComposite_parent_class)->set(object, key, value); + SPFilterPrimitive::set(key, value); break; } - } /** * Receives update notifications. */ -static void -sp_feComposite_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPFeComposite *comp = SP_FECOMPOSITE(object); - +void SPFeComposite::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { @@ -209,50 +185,52 @@ sp_feComposite_update(SPObject *object, SPCtx *ctx, guint flags) /* Unlike normal in, in2 is required attribute. Make sure, we can call * it by some name. */ - if (comp->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET || - comp->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT) + if (this->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET || + this->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT) { - SPFilter *parent = SP_FILTER(object->parent); - comp->in2 = sp_filter_primitive_name_previous_out(comp); + SPFilter *parent = SP_FILTER(this->parent); + this->in2 = sp_filter_primitive_name_previous_out(this); //XML Tree being used directly here while it shouldn't be. - object->getRepr()->setAttribute("in2", sp_filter_name_for_image(parent, comp->in2)); + this->getRepr()->setAttribute("in2", sp_filter_name_for_image(parent, this->in2)); } - if (((SPObjectClass *) sp_feComposite_parent_class)->update) { - ((SPObjectClass *) sp_feComposite_parent_class)->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_feComposite_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ - SPFeComposite *comp = SP_FECOMPOSITE(object); - SPFilter *parent = SP_FILTER(object->parent); +Inkscape::XML::Node* SPFeComposite::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { + SPFilter *parent = SP_FILTER(this->parent); if (!repr) { repr = doc->createElement("svg:feComposite"); } - gchar const *out_name = sp_filter_name_for_image(parent, comp->in2); + gchar const *out_name = sp_filter_name_for_image(parent, this->in2); + if (out_name) { repr->setAttribute("in2", out_name); } else { SPObject *i = parent->children; - while (i && i->next != object) i = i->next; + + while (i && i->next != this) { + i = i->next; + } + SPFilterPrimitive *i_prim = SP_FILTER_PRIMITIVE(i); out_name = sp_filter_name_for_image(parent, i_prim->image_out); repr->setAttribute("in2", out_name); + if (!out_name) { g_warning("Unable to set in2 for feComposite"); } } char const *comp_op; - switch (comp->composite_operator) { + + switch (this->composite_operator) { case COMPOSITE_OVER: comp_op = "over"; break; case COMPOSITE_IN: @@ -268,13 +246,14 @@ sp_feComposite_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::X default: comp_op = 0; } + repr->setAttribute("operator", comp_op); - if (comp->composite_operator == COMPOSITE_ARITHMETIC) { - sp_repr_set_svg_double(repr, "k1", comp->k1); - sp_repr_set_svg_double(repr, "k2", comp->k2); - sp_repr_set_svg_double(repr, "k3", comp->k3); - sp_repr_set_svg_double(repr, "k4", comp->k4); + if (this->composite_operator == COMPOSITE_ARITHMETIC) { + sp_repr_set_svg_double(repr, "k1", this->k1); + sp_repr_set_svg_double(repr, "k2", this->k2); + sp_repr_set_svg_double(repr, "k3", this->k3); + sp_repr_set_svg_double(repr, "k4", this->k4); } else { repr->setAttribute("k1", 0); repr->setAttribute("k2", 0); @@ -282,35 +261,31 @@ sp_feComposite_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::X repr->setAttribute("k4", 0); } - if (((SPObjectClass *) sp_feComposite_parent_class)->write) { - ((SPObjectClass *) sp_feComposite_parent_class)->write(object, doc, repr, flags); - } + SPFilterPrimitive::write(doc, repr, flags); return repr; } -static void sp_feComposite_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - g_assert(primitive != NULL); +void SPFeComposite::build_renderer(Inkscape::Filters::Filter* filter) { + g_assert(this != NULL); g_assert(filter != NULL); - SPFeComposite *sp_composite = SP_FECOMPOSITE(primitive); - int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_COMPOSITE); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); Inkscape::Filters::FilterComposite *nr_composite = dynamic_cast<Inkscape::Filters::FilterComposite*>(nr_primitive); g_assert(nr_composite != NULL); - sp_filter_primitive_renderer_common(primitive, nr_primitive); + sp_filter_primitive_renderer_common(this, nr_primitive); - nr_composite->set_operator(sp_composite->composite_operator); - nr_composite->set_input(1, sp_composite->in2); - if (sp_composite->composite_operator == COMPOSITE_ARITHMETIC) { - nr_composite->set_arithmetic(sp_composite->k1, sp_composite->k2, - sp_composite->k3, sp_composite->k4); + nr_composite->set_operator(this->composite_operator); + nr_composite->set_input(1, this->in2); + + if (this->composite_operator == COMPOSITE_ARITHMETIC) { + nr_composite->set_arithmetic(this->k1, this->k2, + this->k3, this->k4); } } - /* Local Variables: mode:c++ diff --git a/src/filters/composite.h b/src/filters/composite.h index 4f2d1ff69..b8c0178d1 100644 --- a/src/filters/composite.h +++ b/src/filters/composite.h @@ -13,11 +13,8 @@ #include "sp-filter-primitive.h" -#define SP_TYPE_FECOMPOSITE (sp_feComposite_get_type()) -#define SP_FECOMPOSITE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FECOMPOSITE, SPFeComposite)) -#define SP_FECOMPOSITE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FECOMPOSITE, SPFeCompositeClass)) -#define SP_IS_FECOMPOSITE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FECOMPOSITE)) -#define SP_IS_FECOMPOSITE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FECOMPOSITE)) +#define SP_FECOMPOSITE(obj) (dynamic_cast<SPFeComposite*>((SPObject*)obj)) +#define SP_IS_FECOMPOSITE(obj) (dynamic_cast<const SPFeComposite*>((SPObject*)obj) != NULL) enum FeCompositeOperator { // Default value is 'over', but let's distinquish specifying the @@ -32,17 +29,27 @@ enum FeCompositeOperator { COMPOSITE_ENDOPERATOR }; -struct SPFeComposite : public SPFilterPrimitive { +class SPFeComposite : public SPFilterPrimitive { +public: + SPFeComposite(); + virtual ~SPFeComposite(); + FeCompositeOperator composite_operator; double k1, k2, k3, k4; int in2; -}; -struct SPFeCompositeClass { - SPFilterPrimitiveClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void set(unsigned int key, const gchar* value); -GType sp_feComposite_get_type(); + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); +}; #endif /* !SP_FECOMPOSITE_H_SEEN */ diff --git a/src/filters/convolvematrix.cpp b/src/filters/convolvematrix.cpp index d002ef731..bd710b116 100644 --- a/src/filters/convolvematrix.cpp +++ b/src/filters/convolvematrix.cpp @@ -28,45 +28,35 @@ #include "display/nr-filter.h" #include "display/nr-filter-convolve-matrix.h" -/* FeConvolveMatrix base class */ -static void sp_feConvolveMatrix_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feConvolveMatrix_release(SPObject *object); -static void sp_feConvolveMatrix_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feConvolveMatrix_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_feConvolveMatrix_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_feConvolveMatrix_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter); +#include "sp-factory.h" -G_DEFINE_TYPE(SPFeConvolveMatrix, sp_feConvolveMatrix, SP_TYPE_FILTER_PRIMITIVE); +namespace { + SPObject* createConvolveMatrix() { + return new SPFeConvolveMatrix(); + } -static void -sp_feConvolveMatrix_class_init(SPFeConvolveMatrixClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass; - - sp_object_class->build = sp_feConvolveMatrix_build; - sp_object_class->release = sp_feConvolveMatrix_release; - sp_object_class->write = sp_feConvolveMatrix_write; - sp_object_class->set = sp_feConvolveMatrix_set; - sp_object_class->update = sp_feConvolveMatrix_update; - - sp_primitive_class->build_renderer = sp_feConvolveMatrix_build_renderer; + bool convolveMatrixRegistered = SPFactory::instance().registerObject("svg:feConvolveMatrix", createConvolveMatrix); } -static void -sp_feConvolveMatrix_init(SPFeConvolveMatrix *feConvolveMatrix) -{ +SPFeConvolveMatrix::SPFeConvolveMatrix() : SPFilterPrimitive() { + this->bias = 0; + this->divisorIsSet = 0; + this->divisor = 0; + //Setting default values: - feConvolveMatrix->order.set("3 3"); - feConvolveMatrix->targetX = 1; - feConvolveMatrix->targetY = 1; - feConvolveMatrix->edgeMode = Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_DUPLICATE; - feConvolveMatrix->preserveAlpha = false; + this->order.set("3 3"); + this->targetX = 1; + this->targetY = 1; + this->edgeMode = Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_DUPLICATE; + this->preserveAlpha = false; //some helper variables: - feConvolveMatrix->targetXIsSet = false; - feConvolveMatrix->targetYIsSet = false; - feConvolveMatrix->kernelMatrixIsSet = false; + this->targetXIsSet = false; + this->targetYIsSet = false; + this->kernelMatrixIsSet = false; +} + +SPFeConvolveMatrix::~SPFeConvolveMatrix() { } /** @@ -74,59 +64,58 @@ sp_feConvolveMatrix_init(SPFeConvolveMatrix *feConvolveMatrix) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_feConvolveMatrix_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_feConvolveMatrix_parent_class)->build) { - ((SPObjectClass *) sp_feConvolveMatrix_parent_class)->build(object, document, repr); - } +void SPFeConvolveMatrix::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive::build(document, repr); - /*LOAD ATTRIBUTES FROM REPR HERE*/ - object->readAttr( "order" ); - object->readAttr( "kernelMatrix" ); - object->readAttr( "divisor" ); - object->readAttr( "bias" ); - object->readAttr( "targetX" ); - object->readAttr( "targetY" ); - object->readAttr( "edgeMode" ); - object->readAttr( "kernelUnitLength" ); - object->readAttr( "preserveAlpha" ); + /*LOAD ATTRIBUTES FROM REPR HERE*/ + this->readAttr( "order" ); + this->readAttr( "kernelMatrix" ); + this->readAttr( "divisor" ); + this->readAttr( "bias" ); + this->readAttr( "targetX" ); + this->readAttr( "targetY" ); + this->readAttr( "edgeMode" ); + this->readAttr( "kernelUnitLength" ); + this->readAttr( "preserveAlpha" ); } /** * Drops any allocated memory. */ -static void -sp_feConvolveMatrix_release(SPObject *object) -{ - if (((SPObjectClass *) sp_feConvolveMatrix_parent_class)->release) - ((SPObjectClass *) sp_feConvolveMatrix_parent_class)->release(object); +void SPFeConvolveMatrix::release() { + SPFilterPrimitive::release(); } static Inkscape::Filters::FilterConvolveMatrixEdgeMode sp_feConvolveMatrix_read_edgeMode(gchar const *value){ - if (!value) return Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_DUPLICATE; //duplicate is default - switch(value[0]){ + if (!value) { + return Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_DUPLICATE; //duplicate is default + } + + switch (value[0]) { case 'd': - if (strncmp(value, "duplicate", 9) == 0) return Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_DUPLICATE; + if (strncmp(value, "duplicate", 9) == 0) { + return Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_DUPLICATE; + } break; case 'w': - if (strncmp(value, "wrap", 4) == 0) return Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_WRAP; + if (strncmp(value, "wrap", 4) == 0) { + return Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_WRAP; + } break; case 'n': - if (strncmp(value, "none", 4) == 0) return Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_NONE; + if (strncmp(value, "none", 4) == 0) { + return Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_NONE; + } break; } + return Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_DUPLICATE; //duplicate is default } /** * Sets a specific value in the SPFeConvolveMatrix. */ -static void -sp_feConvolveMatrix_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeConvolveMatrix *feConvolveMatrix = SP_FECONVOLVEMATRIX(object); - (void)feConvolveMatrix; +void SPFeConvolveMatrix::set(unsigned int key, gchar const *value) { double read_num; int read_int; bool read_bool; @@ -135,25 +124,41 @@ sp_feConvolveMatrix_set(SPObject *object, unsigned int key, gchar const *value) switch(key) { /*DEAL WITH SETTING ATTRIBUTES HERE*/ case SP_ATTR_ORDER: - feConvolveMatrix->order.set(value); + this->order.set(value); + //From SVG spec: If <orderY> is not provided, it defaults to <orderX>. - if (feConvolveMatrix->order.optNumIsSet() == false) - feConvolveMatrix->order.setOptNumber(feConvolveMatrix->order.getNumber()); - if (feConvolveMatrix->targetXIsSet == false) feConvolveMatrix->targetX = (int) floor(feConvolveMatrix->order.getNumber()/2); - if (feConvolveMatrix->targetYIsSet == false) feConvolveMatrix->targetY = (int) floor(feConvolveMatrix->order.getOptNumber()/2); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (this->order.optNumIsSet() == false) { + this->order.setOptNumber(this->order.getNumber()); + } + + if (this->targetXIsSet == false) { + this->targetX = (int) floor(this->order.getNumber()/2); + } + + if (this->targetYIsSet == false) { + this->targetY = (int) floor(this->order.getOptNumber()/2); + } + + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_KERNELMATRIX: if (value){ - feConvolveMatrix->kernelMatrixIsSet = true; - feConvolveMatrix->kernelMatrix = helperfns_read_vector(value); - if (! feConvolveMatrix->divisorIsSet) { - feConvolveMatrix->divisor = 0; - for (unsigned int i = 0; i< feConvolveMatrix->kernelMatrix.size(); i++) - feConvolveMatrix->divisor += feConvolveMatrix->kernelMatrix[i]; - if (feConvolveMatrix->divisor == 0) feConvolveMatrix->divisor = 1; + this->kernelMatrixIsSet = true; + this->kernelMatrix = helperfns_read_vector(value); + + if (! this->divisorIsSet) { + this->divisor = 0; + + for (unsigned int i = 0; i< this->kernelMatrix.size(); i++) { + this->divisor += this->kernelMatrix[i]; + } + + if (this->divisor == 0) { + this->divisor = 1; + } } - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } else { g_warning("For feConvolveMatrix you MUST pass a kernelMatrix parameter!"); } @@ -161,85 +166,104 @@ sp_feConvolveMatrix_set(SPObject *object, unsigned int key, gchar const *value) case SP_ATTR_DIVISOR: if (value) { read_num = helperfns_read_number(value); + if (read_num == 0) { // This should actually be an error, but given our UI it is more useful to simply set divisor to the default. - if (feConvolveMatrix->kernelMatrixIsSet) { - for (unsigned int i = 0; i< feConvolveMatrix->kernelMatrix.size(); i++) - read_num += feConvolveMatrix->kernelMatrix[i]; + if (this->kernelMatrixIsSet) { + for (unsigned int i = 0; i< this->kernelMatrix.size(); i++) { + read_num += this->kernelMatrix[i]; + } } - if (read_num == 0) read_num = 1; - if (feConvolveMatrix->divisorIsSet || feConvolveMatrix->divisor!=read_num) { - feConvolveMatrix->divisorIsSet = false; - feConvolveMatrix->divisor = read_num; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_num == 0) { + read_num = 1; } - } else if (!feConvolveMatrix->divisorIsSet || feConvolveMatrix->divisor!=read_num) { - feConvolveMatrix->divisorIsSet = true; - feConvolveMatrix->divisor = read_num; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->divisorIsSet || this->divisor!=read_num) { + this->divisorIsSet = false; + this->divisor = read_num; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + } + } else if (!this->divisorIsSet || this->divisor!=read_num) { + this->divisorIsSet = true; + this->divisor = read_num; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } } break; case SP_ATTR_BIAS: read_num = 0; - if (value) read_num = helperfns_read_number(value); - if (read_num != feConvolveMatrix->bias){ - feConvolveMatrix->bias = read_num; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (value) { + read_num = helperfns_read_number(value); + } + + if (read_num != this->bias){ + this->bias = read_num; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_TARGETX: if (value) { read_int = (int) helperfns_read_number(value); - if (read_int < 0 || read_int > feConvolveMatrix->order.getNumber()){ + + if (read_int < 0 || read_int > this->order.getNumber()){ g_warning("targetX must be a value between 0 and orderX! Assuming floor(orderX/2) as default value."); - read_int = (int) floor(feConvolveMatrix->order.getNumber()/2.0); + read_int = (int) floor(this->order.getNumber()/2.0); } - feConvolveMatrix->targetXIsSet = true; - if (read_int != feConvolveMatrix->targetX){ - feConvolveMatrix->targetX = read_int; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->targetXIsSet = true; + + if (read_int != this->targetX){ + this->targetX = read_int; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } } break; case SP_ATTR_TARGETY: if (value) { read_int = (int) helperfns_read_number(value); - if (read_int < 0 || read_int > feConvolveMatrix->order.getOptNumber()){ + + if (read_int < 0 || read_int > this->order.getOptNumber()){ g_warning("targetY must be a value between 0 and orderY! Assuming floor(orderY/2) as default value."); - read_int = (int) floor(feConvolveMatrix->order.getOptNumber()/2.0); + read_int = (int) floor(this->order.getOptNumber()/2.0); } - feConvolveMatrix->targetYIsSet = true; - if (read_int != feConvolveMatrix->targetY){ - feConvolveMatrix->targetY = read_int; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->targetYIsSet = true; + + if (read_int != this->targetY){ + this->targetY = read_int; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } } break; case SP_ATTR_EDGEMODE: read_mode = sp_feConvolveMatrix_read_edgeMode(value); - if (read_mode != feConvolveMatrix->edgeMode){ - feConvolveMatrix->edgeMode = read_mode; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_mode != this->edgeMode){ + this->edgeMode = read_mode; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_KERNELUNITLENGTH: - feConvolveMatrix->kernelUnitLength.set(value); + this->kernelUnitLength.set(value); + //From SVG spec: If the <dy> value is not specified, it defaults to the same value as <dx>. - if (feConvolveMatrix->kernelUnitLength.optNumIsSet() == false) - feConvolveMatrix->kernelUnitLength.setOptNumber(feConvolveMatrix->kernelUnitLength.getNumber()); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (this->kernelUnitLength.optNumIsSet() == false) { + this->kernelUnitLength.setOptNumber(this->kernelUnitLength.getNumber()); + } + + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_PRESERVEALPHA: read_bool = helperfns_read_bool(value, false); - if (read_bool != feConvolveMatrix->preserveAlpha){ - feConvolveMatrix->preserveAlpha = read_bool; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_bool != this->preserveAlpha){ + this->preserveAlpha = read_bool; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; default: - if (((SPObjectClass *) sp_feConvolveMatrix_parent_class)->set) - ((SPObjectClass *) sp_feConvolveMatrix_parent_class)->set(object, key, value); + SPFilterPrimitive::set(key, value); break; } @@ -248,9 +272,7 @@ sp_feConvolveMatrix_set(SPObject *object, unsigned int key, gchar const *value) /** * Receives update notifications. */ -static void -sp_feConvolveMatrix_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPFeConvolveMatrix::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { @@ -258,53 +280,44 @@ sp_feConvolveMatrix_update(SPObject *object, SPCtx *ctx, guint flags) } - if (((SPObjectClass *) sp_feConvolveMatrix_parent_class)->update) { - ((SPObjectClass *) sp_feConvolveMatrix_parent_class)->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_feConvolveMatrix_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPFeConvolveMatrix::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - if (((SPObjectClass *) sp_feConvolveMatrix_parent_class)->write) { - ((SPObjectClass *) sp_feConvolveMatrix_parent_class)->write(object, doc, repr, flags); - } + SPFilterPrimitive::write(doc, repr, flags); return repr; } -static void sp_feConvolveMatrix_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - g_assert(primitive != NULL); +void SPFeConvolveMatrix::build_renderer(Inkscape::Filters::Filter* filter) { + g_assert(this != NULL); g_assert(filter != NULL); - SPFeConvolveMatrix *sp_convolve = SP_FECONVOLVEMATRIX(primitive); - int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_CONVOLVEMATRIX); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); Inkscape::Filters::FilterConvolveMatrix *nr_convolve = dynamic_cast<Inkscape::Filters::FilterConvolveMatrix*>(nr_primitive); g_assert(nr_convolve != NULL); - sp_filter_primitive_renderer_common(primitive, nr_primitive); - - nr_convolve->set_targetX(sp_convolve->targetX); - nr_convolve->set_targetY(sp_convolve->targetY); - nr_convolve->set_orderX( (int)sp_convolve->order.getNumber() ); - nr_convolve->set_orderY( (int)sp_convolve->order.getOptNumber() ); - nr_convolve->set_kernelMatrix(sp_convolve->kernelMatrix); - nr_convolve->set_divisor(sp_convolve->divisor); - nr_convolve->set_bias(sp_convolve->bias); - nr_convolve->set_preserveAlpha(sp_convolve->preserveAlpha); + sp_filter_primitive_renderer_common(this, nr_primitive); + nr_convolve->set_targetX(this->targetX); + nr_convolve->set_targetY(this->targetY); + nr_convolve->set_orderX( (int)this->order.getNumber() ); + nr_convolve->set_orderY( (int)this->order.getOptNumber() ); + nr_convolve->set_kernelMatrix(this->kernelMatrix); + nr_convolve->set_divisor(this->divisor); + nr_convolve->set_bias(this->bias); + nr_convolve->set_preserveAlpha(this->preserveAlpha); } /* Local Variables: diff --git a/src/filters/convolvematrix.h b/src/filters/convolvematrix.h index cb2fbfb8d..9783eaa47 100644 --- a/src/filters/convolvematrix.h +++ b/src/filters/convolvematrix.h @@ -18,13 +18,14 @@ #include "number-opt-number.h" #include "display/nr-filter-convolve-matrix.h" -#define SP_TYPE_FECONVOLVEMATRIX (sp_feConvolveMatrix_get_type()) -#define SP_FECONVOLVEMATRIX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FECONVOLVEMATRIX, SPFeConvolveMatrix)) -#define SP_FECONVOLVEMATRIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FECONVOLVEMATRIX, SPFeConvolveMatrixClass)) -#define SP_IS_FECONVOLVEMATRIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FECONVOLVEMATRIX)) -#define SP_IS_FECONVOLVEMATRIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FECONVOLVEMATRIX)) +#define SP_FECONVOLVEMATRIX(obj) (dynamic_cast<SPFeConvolveMatrix*>((SPObject*)obj)) +#define SP_IS_FECONVOLVEMATRIX(obj) (dynamic_cast<const SPFeConvolveMatrix*>((SPObject*)obj) != NULL) + +class SPFeConvolveMatrix : public SPFilterPrimitive { +public: + SPFeConvolveMatrix(); + virtual ~SPFeConvolveMatrix(); -struct SPFeConvolveMatrix : public SPFilterPrimitive { NumberOptNumber order; std::vector<gdouble> kernelMatrix; double divisor, bias; @@ -37,13 +38,19 @@ struct SPFeConvolveMatrix : public SPFilterPrimitive { bool targetYIsSet; bool divisorIsSet; bool kernelMatrixIsSet; -}; -struct SPFeConvolveMatrixClass { - SPFilterPrimitiveClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void set(unsigned int key, const gchar* value); -GType sp_feConvolveMatrix_get_type(); + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); +}; #endif /* !SP_FECONVOLVEMATRIX_H_SEEN */ diff --git a/src/filters/diffuselighting.cpp b/src/filters/diffuselighting.cpp index 66dd825f6..09179a69d 100644 --- a/src/filters/diffuselighting.cpp +++ b/src/filters/diffuselighting.cpp @@ -34,57 +34,33 @@ #include "display/nr-filter-diffuselighting.h" /* FeDiffuseLighting base class */ -static void sp_feDiffuseLighting_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feDiffuseLighting_release(SPObject *object); -static void sp_feDiffuseLighting_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feDiffuseLighting_update(SPObject *object, SPCtx *ctx, guint flags); -//we assume that svg:feDiffuseLighting can have any number of children -//only the first one is considered as the light source of the filter -//TODO is that right? -//if not modify child_added and remove_child to raise errors -static void sp_feDiffuseLighting_child_added(SPObject *object, - Inkscape::XML::Node *child, - Inkscape::XML::Node *ref); -static void sp_feDiffuseLighting_remove_child(SPObject *object, Inkscape::XML::Node *child); -static void sp_feDiffuseLighting_order_changed(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref); -static Inkscape::XML::Node *sp_feDiffuseLighting_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_feDiffuseLighting_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter); static void sp_feDiffuseLighting_children_modified(SPFeDiffuseLighting *sp_diffuselighting); -G_DEFINE_TYPE(SPFeDiffuseLighting, sp_feDiffuseLighting, SP_TYPE_FILTER_PRIMITIVE); +#include "sp-factory.h" -static void -sp_feDiffuseLighting_class_init(SPFeDiffuseLightingClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass; - - sp_object_class->build = sp_feDiffuseLighting_build; - sp_object_class->release = sp_feDiffuseLighting_release; - sp_object_class->write = sp_feDiffuseLighting_write; - sp_object_class->set = sp_feDiffuseLighting_set; - sp_object_class->update = sp_feDiffuseLighting_update; - sp_object_class->child_added = sp_feDiffuseLighting_child_added; - sp_object_class->remove_child = sp_feDiffuseLighting_remove_child; - sp_object_class->order_changed = sp_feDiffuseLighting_order_changed; - - sp_primitive_class->build_renderer = sp_feDiffuseLighting_build_renderer; +namespace { + SPObject* createDiffuseLighting() { + return new SPFeDiffuseLighting(); + } + + bool diffuseLightingRegistered = SPFactory::instance().registerObject("svg:feDiffuseLighting", createDiffuseLighting); } -static void -sp_feDiffuseLighting_init(SPFeDiffuseLighting *feDiffuseLighting) -{ - feDiffuseLighting->surfaceScale = 1; - feDiffuseLighting->diffuseConstant = 1; - feDiffuseLighting->lighting_color = 0xffffffff; - feDiffuseLighting->icc = NULL; +SPFeDiffuseLighting::SPFeDiffuseLighting() : SPFilterPrimitive() { + this->surfaceScale = 1; + this->diffuseConstant = 1; + this->lighting_color = 0xffffffff; + this->icc = NULL; //TODO kernelUnit - feDiffuseLighting->renderer = NULL; + this->renderer = NULL; - feDiffuseLighting->surfaceScale_set = FALSE; - feDiffuseLighting->diffuseConstant_set = FALSE; - feDiffuseLighting->lighting_color_set = FALSE; + this->surfaceScale_set = FALSE; + this->diffuseConstant_set = FALSE; + this->lighting_color_set = FALSE; +} + +SPFeDiffuseLighting::~SPFeDiffuseLighting() { } /** @@ -92,175 +68,175 @@ sp_feDiffuseLighting_init(SPFeDiffuseLighting *feDiffuseLighting) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_feDiffuseLighting_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_feDiffuseLighting_parent_class)->build) { - ((SPObjectClass *) sp_feDiffuseLighting_parent_class)->build(object, document, repr); - } - - /*LOAD ATTRIBUTES FROM REPR HERE*/ - object->readAttr( "surfaceScale" ); - object->readAttr( "diffuseConstant" ); - object->readAttr( "kernelUnitLength" ); - object->readAttr( "lighting-color" ); - +void SPFeDiffuseLighting::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive::build(document, repr); + + /*LOAD ATTRIBUTES FROM REPR HERE*/ + this->readAttr( "surfaceScale" ); + this->readAttr( "diffuseConstant" ); + this->readAttr( "kernelUnitLength" ); + this->readAttr( "lighting-color" ); } /** * Drops any allocated memory. */ -static void -sp_feDiffuseLighting_release(SPObject *object) -{ - if (((SPObjectClass *) sp_feDiffuseLighting_parent_class)->release) - ((SPObjectClass *) sp_feDiffuseLighting_parent_class)->release(object); +void SPFeDiffuseLighting::release() { + SPFilterPrimitive::release(); } /** * Sets a specific value in the SPFeDiffuseLighting. */ -static void -sp_feDiffuseLighting_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeDiffuseLighting *feDiffuseLighting = SP_FEDIFFUSELIGHTING(object); +void SPFeDiffuseLighting::set(unsigned int key, gchar const *value) { gchar const *cend_ptr = NULL; gchar *end_ptr = NULL; switch(key) { /*DEAL WITH SETTING ATTRIBUTES HERE*/ -//TODO test forbidden values + //TODO test forbidden values case SP_ATTR_SURFACESCALE: end_ptr = NULL; + if (value) { - feDiffuseLighting->surfaceScale = g_ascii_strtod(value, &end_ptr); + this->surfaceScale = g_ascii_strtod(value, &end_ptr); + if (end_ptr) { - feDiffuseLighting->surfaceScale_set = TRUE; + this->surfaceScale_set = TRUE; } } + if (!value || !end_ptr) { - feDiffuseLighting->surfaceScale = 1; - feDiffuseLighting->surfaceScale_set = FALSE; + this->surfaceScale = 1; + this->surfaceScale_set = FALSE; } - if (feDiffuseLighting->renderer) { - feDiffuseLighting->renderer->surfaceScale = feDiffuseLighting->surfaceScale; + + if (this->renderer) { + this->renderer->surfaceScale = this->surfaceScale; } - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_DIFFUSECONSTANT: end_ptr = NULL; + if (value) { - feDiffuseLighting->diffuseConstant = g_ascii_strtod(value, &end_ptr); - if (end_ptr && feDiffuseLighting->diffuseConstant >= 0) { - feDiffuseLighting->diffuseConstant_set = TRUE; + this->diffuseConstant = g_ascii_strtod(value, &end_ptr); + + if (end_ptr && this->diffuseConstant >= 0) { + this->diffuseConstant_set = TRUE; } else { end_ptr = NULL; - g_warning("feDiffuseLighting: diffuseConstant should be a positive number ... defaulting to 1"); + g_warning("this: diffuseConstant should be a positive number ... defaulting to 1"); } } + if (!value || !end_ptr) { - feDiffuseLighting->diffuseConstant = 1; - feDiffuseLighting->diffuseConstant_set = FALSE; + this->diffuseConstant = 1; + this->diffuseConstant_set = FALSE; } - if (feDiffuseLighting->renderer) { - feDiffuseLighting->renderer->diffuseConstant = feDiffuseLighting->diffuseConstant; - } - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->renderer) { + this->renderer->diffuseConstant = this->diffuseConstant; + } + + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_KERNELUNITLENGTH: //TODO kernelUnit - //feDiffuseLighting->kernelUnitLength.set(value); + //this->kernelUnitLength.set(value); /*TODOif (feDiffuseLighting->renderer) { feDiffuseLighting->renderer->surfaceScale = feDiffuseLighting->renderer; } */ - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_PROP_LIGHTING_COLOR: cend_ptr = NULL; - feDiffuseLighting->lighting_color = sp_svg_read_color(value, &cend_ptr, 0xffffffff); + this->lighting_color = sp_svg_read_color(value, &cend_ptr, 0xffffffff); + //if a value was read if (cend_ptr) { while (g_ascii_isspace(*cend_ptr)) { ++cend_ptr; } + if (strneq(cend_ptr, "icc-color(", 10)) { - if (!feDiffuseLighting->icc) feDiffuseLighting->icc = new SVGICCColor(); - if ( ! sp_svg_read_icc_color( cend_ptr, feDiffuseLighting->icc ) ) { - delete feDiffuseLighting->icc; - feDiffuseLighting->icc = NULL; + if (!this->icc) { + this->icc = new SVGICCColor(); + } + + if ( ! sp_svg_read_icc_color( cend_ptr, this->icc ) ) { + delete this->icc; + this->icc = NULL; } } - feDiffuseLighting->lighting_color_set = TRUE; + + this->lighting_color_set = TRUE; } else { //lighting_color already contains the default value - feDiffuseLighting->lighting_color_set = FALSE; + this->lighting_color_set = FALSE; } - if (feDiffuseLighting->renderer) { - feDiffuseLighting->renderer->lighting_color = feDiffuseLighting->lighting_color; + + if (this->renderer) { + this->renderer->lighting_color = this->lighting_color; } - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); break; default: - if (((SPObjectClass *) sp_feDiffuseLighting_parent_class)->set) - ((SPObjectClass *) sp_feDiffuseLighting_parent_class)->set(object, key, value); + SPFilterPrimitive::set(key, value); break; } - } /** * Receives update notifications. */ -static void -sp_feDiffuseLighting_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPFeDiffuseLighting::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG)) { - object->readAttr( "surfaceScale" ); - object->readAttr( "diffuseConstant" ); - object->readAttr( "kernelUnit" ); - object->readAttr( "lighting-color" ); + this->readAttr( "surfaceScale" ); + this->readAttr( "diffuseConstant" ); + this->readAttr( "kernelUnit" ); + this->readAttr( "lighting-color" ); } - if (((SPObjectClass *) sp_feDiffuseLighting_parent_class)->update) { - ((SPObjectClass *) sp_feDiffuseLighting_parent_class)->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_feDiffuseLighting_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ - SPFeDiffuseLighting *fediffuselighting = SP_FEDIFFUSELIGHTING(object); - +Inkscape::XML::Node* SPFeDiffuseLighting::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { /* TODO: Don't just clone, but create a new repr node and write all * relevant values _and children_ into it */ if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); //repr = doc->createElement("svg:feDiffuseLighting"); } - if (fediffuselighting->surfaceScale_set) - sp_repr_set_css_double(repr, "surfaceScale", fediffuselighting->surfaceScale); - else + if (this->surfaceScale_set) { + sp_repr_set_css_double(repr, "surfaceScale", this->surfaceScale); + } else { repr->setAttribute("surfaceScale", NULL); - if (fediffuselighting->diffuseConstant_set) - sp_repr_set_css_double(repr, "diffuseConstant", fediffuselighting->diffuseConstant); - else + } + + if (this->diffuseConstant_set) { + sp_repr_set_css_double(repr, "diffuseConstant", this->diffuseConstant); + } else { repr->setAttribute("diffuseConstant", NULL); - /*TODO kernelUnits */ - if (fediffuselighting->lighting_color_set) { + } + + /*TODO kernelUnits */ + if (this->lighting_color_set) { gchar c[64]; - sp_svg_write_color(c, sizeof(c), fediffuselighting->lighting_color); + sp_svg_write_color(c, sizeof(c), this->lighting_color); repr->setAttribute("lighting-color", c); - } else + } else { repr->setAttribute("lighting-color", NULL); - - if (((SPObjectClass *) sp_feDiffuseLighting_parent_class)->write) { - ((SPObjectClass *) sp_feDiffuseLighting_parent_class)->write(object, doc, repr, flags); } + + SPFilterPrimitive::write(doc, repr, flags); return repr; } @@ -268,43 +244,28 @@ sp_feDiffuseLighting_write(SPObject *object, Inkscape::XML::Document *doc, Inksc /** * Callback for child_added event. */ -static void -sp_feDiffuseLighting_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) -{ - SPFeDiffuseLighting *f = SP_FEDIFFUSELIGHTING(object); - - if (((SPObjectClass *) sp_feDiffuseLighting_parent_class)->child_added) - (* ((SPObjectClass *) sp_feDiffuseLighting_parent_class)->child_added)(object, child, ref); +void SPFeDiffuseLighting::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { + SPFilterPrimitive::child_added(child, ref); - sp_feDiffuseLighting_children_modified(f); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + sp_feDiffuseLighting_children_modified(this); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } - /** * Callback for remove_child event. */ -static void -sp_feDiffuseLighting_remove_child(SPObject *object, Inkscape::XML::Node *child) -{ - SPFeDiffuseLighting *f = SP_FEDIFFUSELIGHTING(object); - - if (((SPObjectClass *) sp_feDiffuseLighting_parent_class)->remove_child) - (* ((SPObjectClass *) sp_feDiffuseLighting_parent_class)->remove_child)(object, child); +void SPFeDiffuseLighting::remove_child(Inkscape::XML::Node *child) { + SPFilterPrimitive::remove_child(child); - sp_feDiffuseLighting_children_modified(f); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + sp_feDiffuseLighting_children_modified(this); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } -static void -sp_feDiffuseLighting_order_changed (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref) -{ - SPFeDiffuseLighting *f = SP_FEDIFFUSELIGHTING(object); - if (((SPObjectClass *) (sp_feDiffuseLighting_parent_class))->order_changed) - (* ((SPObjectClass *) (sp_feDiffuseLighting_parent_class))->order_changed) (object, child, old_ref, new_ref); +void SPFeDiffuseLighting::order_changed(Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref) { + SPFilterPrimitive::order_changed(child, old_ref, new_ref); - sp_feDiffuseLighting_children_modified(f); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + sp_feDiffuseLighting_children_modified(this); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } static void sp_feDiffuseLighting_children_modified(SPFeDiffuseLighting *sp_diffuselighting) @@ -326,45 +287,45 @@ static void sp_feDiffuseLighting_children_modified(SPFeDiffuseLighting *sp_diffu } } -static void sp_feDiffuseLighting_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - g_assert(primitive != NULL); +void SPFeDiffuseLighting::build_renderer(Inkscape::Filters::Filter* filter) { + g_assert(this != NULL); g_assert(filter != NULL); - SPFeDiffuseLighting *sp_diffuselighting = SP_FEDIFFUSELIGHTING(primitive); - int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_DIFFUSELIGHTING); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); Inkscape::Filters::FilterDiffuseLighting *nr_diffuselighting = dynamic_cast<Inkscape::Filters::FilterDiffuseLighting*>(nr_primitive); g_assert(nr_diffuselighting != NULL); - sp_diffuselighting->renderer = nr_diffuselighting; - sp_filter_primitive_renderer_common(primitive, nr_primitive); + this->renderer = nr_diffuselighting; + sp_filter_primitive_renderer_common(this, nr_primitive); - nr_diffuselighting->diffuseConstant = sp_diffuselighting->diffuseConstant; - nr_diffuselighting->surfaceScale = sp_diffuselighting->surfaceScale; - nr_diffuselighting->lighting_color = sp_diffuselighting->lighting_color; - nr_diffuselighting->set_icc(sp_diffuselighting->icc); + nr_diffuselighting->diffuseConstant = this->diffuseConstant; + nr_diffuselighting->surfaceScale = this->surfaceScale; + nr_diffuselighting->lighting_color = this->lighting_color; + nr_diffuselighting->set_icc(this->icc); //We assume there is at most one child nr_diffuselighting->light_type = Inkscape::Filters::NO_LIGHT; - if (SP_IS_FEDISTANTLIGHT(primitive->children)) { + + if (SP_IS_FEDISTANTLIGHT(this->children)) { nr_diffuselighting->light_type = Inkscape::Filters::DISTANT_LIGHT; - nr_diffuselighting->light.distant = SP_FEDISTANTLIGHT(primitive->children); + nr_diffuselighting->light.distant = SP_FEDISTANTLIGHT(this->children); } - if (SP_IS_FEPOINTLIGHT(primitive->children)) { + + if (SP_IS_FEPOINTLIGHT(this->children)) { nr_diffuselighting->light_type = Inkscape::Filters::POINT_LIGHT; - nr_diffuselighting->light.point = SP_FEPOINTLIGHT(primitive->children); + nr_diffuselighting->light.point = SP_FEPOINTLIGHT(this->children); } - if (SP_IS_FESPOTLIGHT(primitive->children)) { + + if (SP_IS_FESPOTLIGHT(this->children)) { nr_diffuselighting->light_type = Inkscape::Filters::SPOT_LIGHT; - nr_diffuselighting->light.spot = SP_FESPOTLIGHT(primitive->children); + nr_diffuselighting->light.spot = SP_FESPOTLIGHT(this->children); } //nr_offset->set_dx(sp_offset->dx); //nr_offset->set_dy(sp_offset->dy); } - /* Local Variables: mode:c++ diff --git a/src/filters/diffuselighting.h b/src/filters/diffuselighting.h index 1572385b9..f41c6c056 100644 --- a/src/filters/diffuselighting.h +++ b/src/filters/diffuselighting.h @@ -15,11 +15,8 @@ #include "sp-filter-primitive.h" #include "number-opt-number.h" -#define SP_TYPE_FEDIFFUSELIGHTING (sp_feDiffuseLighting_get_type()) -#define SP_FEDIFFUSELIGHTING(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEDIFFUSELIGHTING, SPFeDiffuseLighting)) -#define SP_FEDIFFUSELIGHTING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEDIFFUSELIGHTING, SPFeDiffuseLightingClass)) -#define SP_IS_FEDIFFUSELIGHTING(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEDIFFUSELIGHTING)) -#define SP_IS_FEDIFFUSELIGHTING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEDIFFUSELIGHTING)) +#define SP_FEDIFFUSELIGHTING(obj) (dynamic_cast<SPFeDiffuseLighting*>((SPObject*)obj)) +#define SP_IS_FEDIFFUSELIGHTING(obj) (dynamic_cast<const SPFeDiffuseLighting*>((SPObject*)obj) != NULL) struct SVGICCColor; @@ -28,7 +25,11 @@ namespace Filters { class FilterDiffuseLighting; } } -struct SPFeDiffuseLighting : public SPFilterPrimitive { +class SPFeDiffuseLighting : public SPFilterPrimitive { +public: + SPFeDiffuseLighting(); + virtual ~SPFeDiffuseLighting(); + gfloat surfaceScale; guint surfaceScale_set : 1; gfloat diffuseConstant; @@ -38,13 +39,24 @@ struct SPFeDiffuseLighting : public SPFilterPrimitive { guint lighting_color_set : 1; Inkscape::Filters::FilterDiffuseLighting *renderer; SVGICCColor *icc; -}; -struct SPFeDiffuseLightingClass { - SPFilterPrimitiveClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node* child); + + virtual void order_changed(Inkscape::XML::Node* child, Inkscape::XML::Node* old_repr, Inkscape::XML::Node* new_repr); -GType sp_feDiffuseLighting_get_type(); + virtual void set(unsigned int key, const gchar* value); + + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); +}; #endif /* !SP_FEDIFFUSELIGHTING_H_SEEN */ diff --git a/src/filters/displacementmap.cpp b/src/filters/displacementmap.cpp index 408ffce9e..473e4913f 100644 --- a/src/filters/displacementmap.cpp +++ b/src/filters/displacementmap.cpp @@ -25,37 +25,24 @@ #include "display/nr-filter.h" #include "display/nr-filter-displacement-map.h" -/* FeDisplacementMap base class */ -static void sp_feDisplacementMap_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feDisplacementMap_release(SPObject *object); -static void sp_feDisplacementMap_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feDisplacementMap_update(SPObject *object, SPCtx *ctx, guint flags); -static void sp_feDisplacementMap_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter); -static Inkscape::XML::Node *sp_feDisplacementMap_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -G_DEFINE_TYPE(SPFeDisplacementMap, sp_feDisplacementMap, SP_TYPE_FILTER_PRIMITIVE); - -static void -sp_feDisplacementMap_class_init(SPFeDisplacementMapClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass; - - sp_object_class->build = sp_feDisplacementMap_build; - sp_object_class->release = sp_feDisplacementMap_release; - sp_object_class->write = sp_feDisplacementMap_write; - sp_object_class->set = sp_feDisplacementMap_set; - sp_object_class->update = sp_feDisplacementMap_update; - sp_primitive_class->build_renderer = sp_feDisplacementMap_build_renderer; +#include "sp-factory.h" + +namespace { + SPObject* createDisplacementMap() { + return new SPFeDisplacementMap(); + } + + bool displacementMapRegistered = SPFactory::instance().registerObject("svg:feDisplacementMap", createDisplacementMap); } -static void -sp_feDisplacementMap_init(SPFeDisplacementMap *feDisplacementMap) -{ - feDisplacementMap->scale=0; - feDisplacementMap->xChannelSelector = DISPLACEMENTMAP_CHANNEL_ALPHA; - feDisplacementMap->yChannelSelector = DISPLACEMENTMAP_CHANNEL_ALPHA; - feDisplacementMap->in2 = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET; +SPFeDisplacementMap::SPFeDisplacementMap() : SPFilterPrimitive() { + this->scale=0; + this->xChannelSelector = DISPLACEMENTMAP_CHANNEL_ALPHA; + this->yChannelSelector = DISPLACEMENTMAP_CHANNEL_ALPHA; + this->in2 = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET; +} + +SPFeDisplacementMap::~SPFeDisplacementMap() { } /** @@ -63,44 +50,37 @@ sp_feDisplacementMap_init(SPFeDisplacementMap *feDisplacementMap) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_feDisplacementMap_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_feDisplacementMap_parent_class)->build) { - ((SPObjectClass *) sp_feDisplacementMap_parent_class)->build(object, document, repr); - } - - /*LOAD ATTRIBUTES FROM REPR HERE*/ - object->readAttr( "scale" ); - object->readAttr( "in2" ); - object->readAttr( "xChannelSelector" ); - object->readAttr( "yChannelSelector" ); - - /* Unlike normal in, in2 is required attribute. Make sure, we can call - * it by some name. */ - SPFeDisplacementMap *disp = SP_FEDISPLACEMENTMAP(object); - if (disp->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET || - disp->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT) - { - SPFilter *parent = SP_FILTER(object->parent); - disp->in2 = sp_filter_primitive_name_previous_out(disp); - repr->setAttribute("in2", sp_filter_name_for_image(parent, disp->in2)); - } +void SPFeDisplacementMap::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive::build(document, repr); + + /*LOAD ATTRIBUTES FROM REPR HERE*/ + this->readAttr( "scale" ); + this->readAttr( "in2" ); + this->readAttr( "xChannelSelector" ); + this->readAttr( "yChannelSelector" ); + + /* Unlike normal in, in2 is required attribute. Make sure, we can call + * it by some name. */ + if (this->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET || + this->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT) + { + SPFilter *parent = SP_FILTER(this->parent); + this->in2 = sp_filter_primitive_name_previous_out(this); + repr->setAttribute("in2", sp_filter_name_for_image(parent, this->in2)); + } } /** * Drops any allocated memory. */ -static void -sp_feDisplacementMap_release(SPObject *object) -{ - if (((SPObjectClass *) sp_feDisplacementMap_parent_class)->release) - ((SPObjectClass *) sp_feDisplacementMap_parent_class)->release(object); +void SPFeDisplacementMap::release() { + SPFilterPrimitive::release(); } static FilterDisplacementMapChannelSelector sp_feDisplacementMap_readChannelSelector(gchar const *value) { if (!value) return DISPLACEMENTMAP_CHANNEL_ALPHA; + switch (value[0]) { case 'R': return DISPLACEMENTMAP_CHANNEL_RED; @@ -119,64 +99,62 @@ static FilterDisplacementMapChannelSelector sp_feDisplacementMap_readChannelSele g_warning("Invalid attribute for Channel Selector. Valid modes are 'R', 'G', 'B' or 'A'"); break; } + return DISPLACEMENTMAP_CHANNEL_ALPHA; //default is Alpha Channel } /** * Sets a specific value in the SPFeDisplacementMap. */ -static void -sp_feDisplacementMap_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeDisplacementMap *feDisplacementMap = SP_FEDISPLACEMENTMAP(object); - (void)feDisplacementMap; +void SPFeDisplacementMap::set(unsigned int key, gchar const *value) { int input; double read_num; FilterDisplacementMapChannelSelector read_selector; + switch(key) { /*DEAL WITH SETTING ATTRIBUTES HERE*/ case SP_ATTR_XCHANNELSELECTOR: read_selector = sp_feDisplacementMap_readChannelSelector(value); - if (read_selector != feDisplacementMap->xChannelSelector){ - feDisplacementMap->xChannelSelector = read_selector; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_selector != this->xChannelSelector){ + this->xChannelSelector = read_selector; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_YCHANNELSELECTOR: read_selector = sp_feDisplacementMap_readChannelSelector(value); - if (read_selector != feDisplacementMap->yChannelSelector){ - feDisplacementMap->yChannelSelector = read_selector; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_selector != this->yChannelSelector){ + this->yChannelSelector = read_selector; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_SCALE: read_num = value ? helperfns_read_number(value) : 0; - if (read_num != feDisplacementMap->scale) { - feDisplacementMap->scale = read_num; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_num != this->scale) { + this->scale = read_num; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_IN2: - input = sp_filter_primitive_read_in(feDisplacementMap, value); - if (input != feDisplacementMap->in2) { - feDisplacementMap->in2 = input; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + input = sp_filter_primitive_read_in(this, value); + + if (input != this->in2) { + this->in2 = input; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; default: - if (((SPObjectClass *) sp_feDisplacementMap_parent_class)->set) - ((SPObjectClass *) sp_feDisplacementMap_parent_class)->set(object, key, value); + SPFilterPrimitive::set(key, value); break; } - } /** * Receives update notifications. */ -static void -sp_feDisplacementMap_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPFeDisplacementMap::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { @@ -186,20 +164,17 @@ sp_feDisplacementMap_update(SPObject *object, SPCtx *ctx, guint flags) /* Unlike normal in, in2 is required attribute. Make sure, we can call * it by some name. */ - SPFeDisplacementMap *disp = SP_FEDISPLACEMENTMAP(object); - if (disp->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET || - disp->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT) + if (this->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET || + this->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT) { - SPFilter *parent = SP_FILTER(object->parent); - disp->in2 = sp_filter_primitive_name_previous_out(disp); + SPFilter *parent = SP_FILTER(this->parent); + this->in2 = sp_filter_primitive_name_previous_out(this); //XML Tree being used directly here while it shouldn't be. - object->getRepr()->setAttribute("in2", sp_filter_name_for_image(parent, disp->in2)); + this->getRepr()->setAttribute("in2", sp_filter_name_for_image(parent, this->in2)); } - if (((SPObjectClass *) sp_feDisplacementMap_parent_class)->update) { - ((SPObjectClass *) sp_feDisplacementMap_parent_class)->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } static char const * get_channelselector_name(FilterDisplacementMapChannelSelector selector) { @@ -220,63 +195,60 @@ static char const * get_channelselector_name(FilterDisplacementMapChannelSelecto /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_feDisplacementMap_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ - SPFeDisplacementMap *disp = SP_FEDISPLACEMENTMAP(object); - SPFilter *parent = SP_FILTER(object->parent); +Inkscape::XML::Node* SPFeDisplacementMap::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { + SPFilter *parent = SP_FILTER(this->parent); if (!repr) { repr = doc->createElement("svg:feDisplacementMap"); } - gchar const *out_name = sp_filter_name_for_image(parent, disp->in2); + gchar const *out_name = sp_filter_name_for_image(parent, this->in2); if (out_name) { repr->setAttribute("in2", out_name); } else { SPObject *i = parent->children; - while (i && i->next != object) i = i->next; + + while (i && i->next != this) { + i = i->next; + } + SPFilterPrimitive *i_prim = SP_FILTER_PRIMITIVE(i); out_name = sp_filter_name_for_image(parent, i_prim->image_out); repr->setAttribute("in2", out_name); + if (!out_name) { g_warning("Unable to set in2 for feDisplacementMap"); } } - sp_repr_set_svg_double(repr, "scale", disp->scale); + sp_repr_set_svg_double(repr, "scale", this->scale); repr->setAttribute("xChannelSelector", - get_channelselector_name(disp->xChannelSelector)); + get_channelselector_name(this->xChannelSelector)); repr->setAttribute("yChannelSelector", - get_channelselector_name(disp->yChannelSelector)); + get_channelselector_name(this->yChannelSelector)); - if (((SPObjectClass *) sp_feDisplacementMap_parent_class)->write) { - ((SPObjectClass *) sp_feDisplacementMap_parent_class)->write(object, doc, repr, flags); - } + SPFilterPrimitive::write(doc, repr, flags); return repr; } -static void sp_feDisplacementMap_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - g_assert(primitive != NULL); +void SPFeDisplacementMap::build_renderer(Inkscape::Filters::Filter* filter) { + g_assert(this != NULL); g_assert(filter != NULL); - SPFeDisplacementMap *sp_displacement_map = SP_FEDISPLACEMENTMAP(primitive); - int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_DISPLACEMENTMAP); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); Inkscape::Filters::FilterDisplacementMap *nr_displacement_map = dynamic_cast<Inkscape::Filters::FilterDisplacementMap*>(nr_primitive); g_assert(nr_displacement_map != NULL); - sp_filter_primitive_renderer_common(primitive, nr_primitive); + sp_filter_primitive_renderer_common(this, nr_primitive); - nr_displacement_map->set_input(1, sp_displacement_map->in2); - nr_displacement_map->set_scale(sp_displacement_map->scale); - nr_displacement_map->set_channel_selector(0, sp_displacement_map->xChannelSelector); - nr_displacement_map->set_channel_selector(1, sp_displacement_map->yChannelSelector); + nr_displacement_map->set_input(1, this->in2); + nr_displacement_map->set_scale(this->scale); + nr_displacement_map->set_channel_selector(0, this->xChannelSelector); + nr_displacement_map->set_channel_selector(1, this->yChannelSelector); } - /* Local Variables: mode:c++ diff --git a/src/filters/displacementmap.h b/src/filters/displacementmap.h index 93dc86d27..85a6beaaa 100644 --- a/src/filters/displacementmap.h +++ b/src/filters/displacementmap.h @@ -14,11 +14,8 @@ #include "sp-filter-primitive.h" -#define SP_TYPE_FEDISPLACEMENTMAP (sp_feDisplacementMap_get_type()) -#define SP_FEDISPLACEMENTMAP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEDISPLACEMENTMAP, SPFeDisplacementMap)) -#define SP_FEDISPLACEMENTMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEDISPLACEMENTMAP, SPFeDisplacementMapClass)) -#define SP_IS_FEDISPLACEMENTMAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEDISPLACEMENTMAP)) -#define SP_IS_FEDISPLACEMENTMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEDISPLACEMENTMAP)) +#define SP_FEDISPLACEMENTMAP(obj) (dynamic_cast<SPFeDisplacementMap*>((SPObject*)obj)) +#define SP_IS_FEDISPLACEMENTMAP(obj) (dynamic_cast<const SPFeDisplacementMap*>((SPObject*)obj) != NULL) enum FilterDisplacementMapChannelSelector { DISPLACEMENTMAP_CHANNEL_RED, @@ -28,18 +25,28 @@ enum FilterDisplacementMapChannelSelector { DISPLACEMENTMAP_CHANNEL_ENDTYPE }; -struct SPFeDisplacementMap : public SPFilterPrimitive { +class SPFeDisplacementMap : public SPFilterPrimitive { +public: + SPFeDisplacementMap(); + virtual ~SPFeDisplacementMap(); + int in2; double scale; FilterDisplacementMapChannelSelector xChannelSelector; FilterDisplacementMapChannelSelector yChannelSelector; -}; -struct SPFeDisplacementMapClass { - SPFilterPrimitiveClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void set(unsigned int key, const gchar* value); -GType sp_feDisplacementMap_get_type(); + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); +}; #endif /* !SP_FEDISPLACEMENTMAP_H_SEEN */ diff --git a/src/filters/distantlight.cpp b/src/filters/distantlight.cpp index 5e1c35a95..8b6ef023b 100644 --- a/src/filters/distantlight.cpp +++ b/src/filters/distantlight.cpp @@ -29,34 +29,11 @@ #define SP_MACROS_SILENT #include "macros.h" -/* FeDistantLight class */ -static void sp_fedistantlight_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_fedistantlight_release(SPObject *object); -static void sp_fedistantlight_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_fedistantlight_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_fedistantlight_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -G_DEFINE_TYPE(SPFeDistantLight, sp_fedistantlight, SP_TYPE_OBJECT); - -static void -sp_fedistantlight_class_init(SPFeDistantLightClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - - sp_object_class->build = sp_fedistantlight_build; - sp_object_class->release = sp_fedistantlight_release; - sp_object_class->write = sp_fedistantlight_write; - sp_object_class->set = sp_fedistantlight_set; - sp_object_class->update = sp_fedistantlight_update; +SPFeDistantLight::SPFeDistantLight() + : SPObject(), azimuth(0), azimuth_set(FALSE), elevation(0), elevation_set(FALSE) { } -static void -sp_fedistantlight_init(SPFeDistantLight *fedistantlight) -{ - fedistantlight->azimuth = 0; - fedistantlight->elevation = 0; - fedistantlight->azimuth_set = FALSE; - fedistantlight->elevation_set = FALSE; +SPFeDistantLight::~SPFeDistantLight() { } /** @@ -64,32 +41,24 @@ sp_fedistantlight_init(SPFeDistantLight *fedistantlight) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_fedistantlight_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_fedistantlight_parent_class)->build) { - ((SPObjectClass *) sp_fedistantlight_parent_class)->build(object, document, repr); - } +void SPFeDistantLight::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPObject::build(document, repr); //Read values of key attributes from XML nodes into object. - object->readAttr( "azimuth" ); - object->readAttr( "elevation" ); + this->readAttr( "azimuth" ); + this->readAttr( "elevation" ); //is this necessary? - document->addResource("fedistantlight", object); + document->addResource("fedistantlight", this); } /** * Drops any allocated memory. */ -static void -sp_fedistantlight_release(SPObject *object) -{ - //SPFeDistantLight *fedistantlight = SP_FEDISTANTLIGHT(object); - - if ( object->document ) { +void SPFeDistantLight::release() { + if ( this->document ) { // Unregister ourselves - object->document->removeResource("fedistantlight", object); + this->document->removeResource("fedistantlight", this); } //TODO: release resources here @@ -98,53 +67,57 @@ sp_fedistantlight_release(SPObject *object) /** * Sets a specific value in the SPFeDistantLight. */ -static void -sp_fedistantlight_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeDistantLight *fedistantlight = SP_FEDISTANTLIGHT(object); +void SPFeDistantLight::set(unsigned int key, gchar const *value) { gchar *end_ptr; + switch (key) { case SP_ATTR_AZIMUTH: end_ptr =NULL; + if (value) { - fedistantlight->azimuth = g_ascii_strtod(value, &end_ptr); + this->azimuth = g_ascii_strtod(value, &end_ptr); + if (end_ptr) { - fedistantlight->azimuth_set = TRUE; + this->azimuth_set = TRUE; } } + if (!value || !end_ptr) { - fedistantlight->azimuth_set = FALSE; - fedistantlight->azimuth = 0; + this->azimuth_set = FALSE; + this->azimuth = 0; } - if (object->parent && - (SP_IS_FEDIFFUSELIGHTING(object->parent) || - SP_IS_FESPECULARLIGHTING(object->parent))) { - object->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->parent && + (SP_IS_FEDIFFUSELIGHTING(this->parent) || + SP_IS_FESPECULARLIGHTING(this->parent))) { + this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_ELEVATION: end_ptr =NULL; + if (value) { - fedistantlight->elevation = g_ascii_strtod(value, &end_ptr); + this->elevation = g_ascii_strtod(value, &end_ptr); + if (end_ptr) { - fedistantlight->elevation_set = TRUE; + this->elevation_set = TRUE; } } + if (!value || !end_ptr) { - fedistantlight->elevation_set = FALSE; - fedistantlight->elevation = 0; + this->elevation_set = FALSE; + this->elevation = 0; } - if (object->parent && - (SP_IS_FEDIFFUSELIGHTING(object->parent) || - SP_IS_FESPECULARLIGHTING(object->parent))) { - object->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->parent && + (SP_IS_FEDIFFUSELIGHTING(this->parent) || + SP_IS_FESPECULARLIGHTING(this->parent))) { + this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; default: // See if any parents need this value. - if (((SPObjectClass *) sp_fedistantlight_parent_class)->set) { - ((SPObjectClass *) sp_fedistantlight_parent_class)->set(object, key, value); - } + SPObject::set(key, value); break; } } @@ -152,44 +125,34 @@ sp_fedistantlight_set(SPObject *object, unsigned int key, gchar const *value) /** * * Receives update notifications. * */ -static void -sp_fedistantlight_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPFeDistantLight *feDistantLight = SP_FEDISTANTLIGHT(object); - (void)feDistantLight; - +void SPFeDistantLight::update(SPCtx *ctx, guint flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { /* do something to trigger redisplay, updates? */ - object->readAttr( "azimuth" ); - object->readAttr( "elevation" ); + this->readAttr( "azimuth" ); + this->readAttr( "elevation" ); } - if (((SPObjectClass *) sp_fedistantlight_parent_class)->update) { - ((SPObjectClass *) sp_fedistantlight_parent_class)->update(object, ctx, flags); - } + SPObject::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_fedistantlight_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ - SPFeDistantLight *fedistantlight = SP_FEDISTANTLIGHT(object); - +Inkscape::XML::Node* SPFeDistantLight::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - if (fedistantlight->azimuth_set) - sp_repr_set_css_double(repr, "azimuth", fedistantlight->azimuth); - if (fedistantlight->elevation_set) - sp_repr_set_css_double(repr, "elevation", fedistantlight->elevation); + if (this->azimuth_set) { + sp_repr_set_css_double(repr, "azimuth", this->azimuth); + } - if (((SPObjectClass *) sp_fedistantlight_parent_class)->write) { - ((SPObjectClass *) sp_fedistantlight_parent_class)->write(object, doc, repr, flags); + if (this->elevation_set) { + sp_repr_set_css_double(repr, "elevation", this->elevation); } + SPObject::write(doc, repr, flags); + return repr; } diff --git a/src/filters/distantlight.h b/src/filters/distantlight.h index b1febf5d3..0eebf768f 100644 --- a/src/filters/distantlight.h +++ b/src/filters/distantlight.h @@ -17,15 +17,14 @@ #include "sp-object.h" -#define SP_TYPE_FEDISTANTLIGHT (sp_fedistantlight_get_type()) -#define SP_FEDISTANTLIGHT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEDISTANTLIGHT, SPFeDistantLight)) -#define SP_FEDISTANTLIGHT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEDISTANTLIGHT, SPFeDistantLightClass)) -#define SP_IS_FEDISTANTLIGHT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEDISTANTLIGHT)) -#define SP_IS_FEDISTANTLIGHT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEDISTANTLIGHT)) +#define SP_FEDISTANTLIGHT(obj) (dynamic_cast<SPFeDistantLight*>((SPObject*)obj)) +#define SP_IS_FEDISTANTLIGHT(obj) (dynamic_cast<const SPFeDistantLight*>((SPObject*)obj) != NULL) /* Distant light class */ - -struct SPFeDistantLight : public SPObject { +class SPFeDistantLight : public SPObject { +public: + SPFeDistantLight(); + virtual ~SPFeDistantLight(); /** azimuth attribute */ gfloat azimuth; @@ -33,14 +32,18 @@ struct SPFeDistantLight : public SPObject { /** elevation attribute */ gfloat elevation; guint elevation_set : 1; -}; -struct SPFeDistantLightClass { - SPObjectClass parent_class; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void set(unsigned int key, const gchar* value); + + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); }; -GType -sp_fedistantlight_get_type(); #endif /* !SP_FEDISTANTLIGHT_H_SEEN */ /* diff --git a/src/filters/flood.cpp b/src/filters/flood.cpp index 51b139b34..134492d34 100644 --- a/src/filters/flood.cpp +++ b/src/filters/flood.cpp @@ -27,34 +27,24 @@ #include "display/nr-filter.h" #include "display/nr-filter-flood.h" -/* FeFlood base class */ - -static void sp_feFlood_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feFlood_release(SPObject *object); -static void sp_feFlood_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feFlood_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_feFlood_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_feFlood_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter); - -G_DEFINE_TYPE(SPFeFlood, sp_feFlood, SP_TYPE_FILTER_PRIMITIVE); - -static void sp_feFlood_class_init(SPFeFloodClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass; - - sp_object_class->build = sp_feFlood_build; - sp_object_class->release = sp_feFlood_release; - sp_object_class->write = sp_feFlood_write; - sp_object_class->set = sp_feFlood_set; - sp_object_class->update = sp_feFlood_update; - sp_primitive_class->build_renderer = sp_feFlood_build_renderer; +#include "sp-factory.h" + +namespace { + SPObject* createFlood() { + return new SPFeFlood(); + } + + bool floodRegistered = SPFactory::instance().registerObject("svg:feFlood", createFlood); +} + +SPFeFlood::SPFeFlood() : SPFilterPrimitive() { + this->color = 0; + + this->opacity = 1; + this->icc = NULL; } -static void sp_feFlood_init(SPFeFlood *feFlood) -{ - feFlood->opacity = 1; - feFlood->icc = NULL; +SPFeFlood::~SPFeFlood() { } /** @@ -62,35 +52,25 @@ static void sp_feFlood_init(SPFeFlood *feFlood) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_feFlood_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if ((SP_OBJECT_CLASS(sp_feFlood_parent_class))->build) { - (SP_OBJECT_CLASS(sp_feFlood_parent_class))->build(object, document, repr); - } +void SPFeFlood::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive::build(document, repr); - /*LOAD ATTRIBUTES FROM REPR HERE*/ - object->readAttr( "flood-opacity" ); - object->readAttr( "flood-color" ); + /*LOAD ATTRIBUTES FROM REPR HERE*/ + this->readAttr( "flood-opacity" ); + this->readAttr( "flood-color" ); } /** * Drops any allocated memory. */ -static void sp_feFlood_release(SPObject *object) -{ - if ((SP_OBJECT_CLASS(sp_feFlood_parent_class))->release) - (SP_OBJECT_CLASS(sp_feFlood_parent_class))->release(object); +void SPFeFlood::release() { + SPFilterPrimitive::release(); } /** * Sets a specific value in the SPFeFlood. */ -static void -sp_feFlood_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeFlood *feFlood = SP_FEFLOOD(object); - (void)feFlood; +void SPFeFlood::set(unsigned int key, gchar const *value) { gchar const *cend_ptr = NULL; gchar *end_ptr = NULL; guint32 read_color; @@ -103,8 +83,8 @@ sp_feFlood_set(SPObject *object, unsigned int key, gchar const *value) cend_ptr = NULL; read_color = sp_svg_read_color(value, &cend_ptr, 0xffffffff); - if (cend_ptr && read_color != feFlood->color){ - feFlood->color = read_color; + if (cend_ptr && read_color != this->color){ + this->color = read_color; dirty=true; } @@ -112,52 +92,54 @@ sp_feFlood_set(SPObject *object, unsigned int key, gchar const *value) while (g_ascii_isspace(*cend_ptr)) { ++cend_ptr; } + if (strneq(cend_ptr, "icc-color(", 10)) { - if (!feFlood->icc) feFlood->icc = new SVGICCColor(); - if ( ! sp_svg_read_icc_color( cend_ptr, feFlood->icc ) ) { - delete feFlood->icc; - feFlood->icc = NULL; + if (!this->icc) { + this->icc = new SVGICCColor(); } + + if ( ! sp_svg_read_icc_color( cend_ptr, this->icc ) ) { + delete this->icc; + this->icc = NULL; + } + dirty = true; } } - if (dirty) - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (dirty) { + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + } break; case SP_PROP_FLOOD_OPACITY: if (value) { read_num = g_ascii_strtod(value, &end_ptr); - if (end_ptr != NULL) - { - if (*end_ptr) - { + + if (end_ptr != NULL) { + if (*end_ptr) { g_warning("Unable to convert \"%s\" to number", value); read_num = 1; } } - } - else { + } else { read_num = 1; } - if (read_num != feFlood->opacity){ - feFlood->opacity = read_num; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_num != this->opacity) { + this->opacity = read_num; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; default: - if ((SP_OBJECT_CLASS(sp_feFlood_parent_class))->set) - (SP_OBJECT_CLASS(sp_feFlood_parent_class))->set(object, key, value); + SPFilterPrimitive::set(key, value); break; } - } /** * Receives update notifications. */ -static void -sp_feFlood_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPFeFlood::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { @@ -165,50 +147,40 @@ sp_feFlood_update(SPObject *object, SPCtx *ctx, guint flags) } - if ((SP_OBJECT_CLASS(sp_feFlood_parent_class))->update) { - (SP_OBJECT_CLASS(sp_feFlood_parent_class))->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_feFlood_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPFeFlood::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - if ((SP_OBJECT_CLASS(sp_feFlood_parent_class))->write) { - (SP_OBJECT_CLASS(sp_feFlood_parent_class))->write(object, doc, repr, flags); - } + SPFilterPrimitive::write(doc, repr, flags); return repr; } -static void sp_feFlood_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - g_assert(primitive != NULL); +void SPFeFlood::build_renderer(Inkscape::Filters::Filter* filter) { + g_assert(this != NULL); g_assert(filter != NULL); - SPFeFlood *sp_flood = SP_FEFLOOD(primitive); - (void)sp_flood; - int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_FLOOD); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); Inkscape::Filters::FilterFlood *nr_flood = dynamic_cast<Inkscape::Filters::FilterFlood*>(nr_primitive); g_assert(nr_flood != NULL); - sp_filter_primitive_renderer_common(primitive, nr_primitive); + sp_filter_primitive_renderer_common(this, nr_primitive); - nr_flood->set_opacity(sp_flood->opacity); - nr_flood->set_color(sp_flood->color); - nr_flood->set_icc(sp_flood->icc); + nr_flood->set_opacity(this->opacity); + nr_flood->set_color(this->color); + nr_flood->set_icc(this->icc); } - /* Local Variables: mode:c++ diff --git a/src/filters/flood.h b/src/filters/flood.h index ab9f061d6..75e332b73 100644 --- a/src/filters/flood.h +++ b/src/filters/flood.h @@ -15,27 +15,31 @@ #include "sp-filter-primitive.h" #include "svg/svg-icc-color.h" -G_BEGIN_DECLS +#define SP_FEFLOOD(obj) (dynamic_cast<SPFeFlood*>((SPObject*)obj)) +#define SP_IS_FEFLOOD(obj) (dynamic_cast<const SPFeFlood*>((SPObject*)obj) != NULL) -#define SP_TYPE_FEFLOOD (sp_feFlood_get_type()) -#define SP_FEFLOOD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEFLOOD, SPFeFlood)) -#define SP_FEFLOOD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEFLOOD, SPFeFloodClass)) -#define SP_IS_FEFLOOD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEFLOOD)) -#define SP_IS_FEFLOOD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEFLOOD)) +class SPFeFlood : public SPFilterPrimitive { +public: + SPFeFlood(); + virtual ~SPFeFlood(); -struct SPFeFlood : public SPFilterPrimitive { guint32 color; SVGICCColor *icc; double opacity; -}; -struct SPFeFloodClass { - SPFilterPrimitiveClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void set(unsigned int key, const gchar* value); -GType sp_feFlood_get_type() G_GNUC_CONST; + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); +}; -G_END_DECLS #endif /* !SP_FEFLOOD_H_SEEN */ /* diff --git a/src/filters/gaussian-blur.cpp b/src/filters/gaussian-blur.cpp index ca93cf6d8..fc1e65925 100644 --- a/src/filters/gaussian-blur.cpp +++ b/src/filters/gaussian-blur.cpp @@ -30,34 +30,20 @@ //#define SP_MACROS_SILENT //#include "macros.h" -/* GaussianBlur base class */ -static void sp_gaussianBlur_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_gaussianBlur_release(SPObject *object); -static void sp_gaussianBlur_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_gaussianBlur_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_gaussianBlur_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_gaussianBlur_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter); - -G_DEFINE_TYPE(SPGaussianBlur, sp_gaussianBlur, SP_TYPE_FILTER_PRIMITIVE); - -static void -sp_gaussianBlur_class_init(SPGaussianBlurClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass; +#include "sp-factory.h" - sp_object_class->build = sp_gaussianBlur_build; - sp_object_class->release = sp_gaussianBlur_release; - sp_object_class->write = sp_gaussianBlur_write; - sp_object_class->set = sp_gaussianBlur_set; - sp_object_class->update = sp_gaussianBlur_update; +namespace { + SPObject* createGaussianBlur() { + return new SPGaussianBlur(); + } - sp_primitive_class->build_renderer = sp_gaussianBlur_build_renderer; + bool gaussianBlurRegistered = SPFactory::instance().registerObject("svg:feGaussianBlur", createGaussianBlur); } -static void -sp_gaussianBlur_init(SPGaussianBlur */*gaussianBlur*/) -{ +SPGaussianBlur::SPGaussianBlur() : SPFilterPrimitive() { +} + +SPGaussianBlur::~SPGaussianBlur() { } /** @@ -65,110 +51,88 @@ sp_gaussianBlur_init(SPGaussianBlur */*gaussianBlur*/) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_gaussianBlur_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_gaussianBlur_parent_class)->build) { - ((SPObjectClass *) sp_gaussianBlur_parent_class)->build(object, document, repr); - } - - object->readAttr( "stdDeviation" ); +void SPGaussianBlur::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive::build(document, repr); + this->readAttr( "stdDeviation" ); } /** * Drops any allocated memory. */ -static void -sp_gaussianBlur_release(SPObject *object) -{ - - if (((SPObjectClass *) sp_gaussianBlur_parent_class)->release) - ((SPObjectClass *) sp_gaussianBlur_parent_class)->release(object); +void SPGaussianBlur::release() { + SPFilterPrimitive::release(); } /** * Sets a specific value in the SPGaussianBlur. */ -static void -sp_gaussianBlur_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPGaussianBlur *gaussianBlur = SP_GAUSSIANBLUR(object); - +void SPGaussianBlur::set(unsigned int key, gchar const *value) { switch(key) { case SP_ATTR_STDDEVIATION: - gaussianBlur->stdDeviation.set(value); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->stdDeviation.set(value); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); break; default: - if (((SPObjectClass *) sp_gaussianBlur_parent_class)->set) - ((SPObjectClass *) sp_gaussianBlur_parent_class)->set(object, key, value); + SPFilterPrimitive::set(key, value); break; } - } /** * Receives update notifications. */ -static void -sp_gaussianBlur_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPGaussianBlur::update(SPCtx *ctx, guint flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { - object->readAttr( "stdDeviation" ); + this->readAttr( "stdDeviation" ); } - if (((SPObjectClass *) sp_gaussianBlur_parent_class)->update) { - ((SPObjectClass *) sp_gaussianBlur_parent_class)->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_gaussianBlur_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPGaussianBlur::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - if (((SPObjectClass *) sp_gaussianBlur_parent_class)->write) { - ((SPObjectClass *) sp_gaussianBlur_parent_class)->write(object, doc, repr, flags); - } + SPFilterPrimitive::write(doc, repr, flags); return repr; } - void sp_gaussianBlur_setDeviation(SPGaussianBlur *blur, float num) { blur->stdDeviation.setNumber(num); } + void sp_gaussianBlur_setDeviation(SPGaussianBlur *blur, float num, float optnum) { blur->stdDeviation.setNumber(num); blur->stdDeviation.setOptNumber(optnum); } -static void sp_gaussianBlur_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - SPGaussianBlur *sp_blur = SP_GAUSSIANBLUR(primitive); - +void SPGaussianBlur::build_renderer(Inkscape::Filters::Filter* filter) { int handle = filter->add_primitive(Inkscape::Filters::NR_FILTER_GAUSSIANBLUR); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(handle); Inkscape::Filters::FilterGaussian *nr_blur = dynamic_cast<Inkscape::Filters::FilterGaussian*>(nr_primitive); - sp_filter_primitive_renderer_common(primitive, nr_primitive); + sp_filter_primitive_renderer_common(this, nr_primitive); + + gfloat num = this->stdDeviation.getNumber(); - gfloat num = sp_blur->stdDeviation.getNumber(); if (num >= 0.0) { - gfloat optnum = sp_blur->stdDeviation.getOptNumber(); - if(optnum >= 0.0) + gfloat optnum = this->stdDeviation.getOptNumber(); + + if(optnum >= 0.0) { nr_blur->set_deviation((double) num, (double) optnum); - else + } else { nr_blur->set_deviation((double) num); + } } } diff --git a/src/filters/gaussian-blur.h b/src/filters/gaussian-blur.h index 8929627ba..00de8a95f 100644 --- a/src/filters/gaussian-blur.h +++ b/src/filters/gaussian-blur.h @@ -15,23 +15,30 @@ #include "sp-filter-primitive.h" #include "number-opt-number.h" -#define SP_TYPE_GAUSSIANBLUR (sp_gaussianBlur_get_type()) -#define SP_GAUSSIANBLUR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_GAUSSIANBLUR, SPGaussianBlur)) -#define SP_GAUSSIANBLUR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_GAUSSIANBLUR, SPGaussianBlurClass)) -#define SP_IS_GAUSSIANBLUR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_GAUSSIANBLUR)) -#define SP_IS_GAUSSIANBLUR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_GAUSSIANBLUR)) +#define SP_GAUSSIANBLUR(obj) (dynamic_cast<SPGaussianBlur*>((SPObject*)obj)) +#define SP_IS_GAUSSIANBLUR(obj) (dynamic_cast<const SPGaussianBlur*>((SPObject*)obj) != NULL) + +class SPGaussianBlur : public SPFilterPrimitive { +public: + SPGaussianBlur(); + virtual ~SPGaussianBlur(); -struct SPGaussianBlur : public SPFilterPrimitive { /** stdDeviation attribute */ NumberOptNumber stdDeviation; -}; -/* GaussianBlur base class */ -struct SPGaussianBlurClass { - SPFilterPrimitiveClass parent_class; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void set(unsigned int key, const gchar* value); + + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); }; -GType sp_gaussianBlur_get_type(); void sp_gaussianBlur_setDeviation(SPGaussianBlur *blur, float num); void sp_gaussianBlur_setDeviation(SPGaussianBlur *blur, float num, float optnum); diff --git a/src/filters/image.cpp b/src/filters/image.cpp index 0f15e9d0f..9a1b85911 100644 --- a/src/filters/image.cpp +++ b/src/filters/image.cpp @@ -17,6 +17,8 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif + +#include <sigc++/bind.h> #include "display/nr-filter-image.h" #include "uri.h" #include "uri-references.h" @@ -29,34 +31,28 @@ #include "display/nr-filter.h" -/* FeImage base class */ -static void sp_feImage_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feImage_release(SPObject *object); -static void sp_feImage_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feImage_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_feImage_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_feImage_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter); +#include "sp-factory.h" -G_DEFINE_TYPE(SPFeImage, sp_feImage, SP_TYPE_FILTER_PRIMITIVE); +namespace { + SPObject* createImage() { + return new SPFeImage(); + } -static void sp_feImage_class_init(SPFeImageClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass * sp_primitive_class = (SPFilterPrimitiveClass *)klass; + bool imageRegistered = SPFactory::instance().registerObject("svg:feImage", createImage); +} - sp_object_class->build = sp_feImage_build; - sp_object_class->release = sp_feImage_release; - sp_object_class->write = sp_feImage_write; - sp_object_class->set = sp_feImage_set; - sp_object_class->update = sp_feImage_update; +SPFeImage::SPFeImage() : SPFilterPrimitive() { + this->document = NULL; + this->href = NULL; + this->from_element = 0; + this->SVGElemRef = NULL; + this->SVGElem = NULL; - sp_primitive_class->build_renderer = sp_feImage_build_renderer; + this->aspect_align = SP_ASPECT_XMID_YMID; // Default + this->aspect_clip = SP_ASPECT_MEET; // Default } -static void sp_feImage_init(SPFeImage *feImage) -{ - feImage->aspect_align = SP_ASPECT_XMID_YMID; // Default - feImage->aspect_clip = SP_ASPECT_MEET; // Default +SPFeImage::~SPFeImage() { } /** @@ -64,35 +60,30 @@ static void sp_feImage_init(SPFeImage *feImage) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void sp_feImage_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ +void SPFeImage::build(SPDocument *document, Inkscape::XML::Node *repr) { // Save document reference so we can load images with relative paths. - SPFeImage *feImage = SP_FEIMAGE(object); - feImage->document = document; + this->document = document; - if (((SPObjectClass *) sp_feImage_parent_class)->build) { - ((SPObjectClass *) sp_feImage_parent_class)->build(object, document, repr); - } + SPFilterPrimitive::build(document, repr); /*LOAD ATTRIBUTES FROM REPR HERE*/ - object->readAttr( "preserveAspectRatio" ); - object->readAttr( "xlink:href" ); - + this->readAttr( "preserveAspectRatio" ); + this->readAttr( "xlink:href" ); } /** * Drops any allocated memory. */ -static void sp_feImage_release(SPObject *object) -{ - SPFeImage *feImage = SP_FEIMAGE(object); - feImage->_image_modified_connection.disconnect(); - feImage->_href_modified_connection.disconnect(); - if (feImage->SVGElemRef) delete feImage->SVGElemRef; +void SPFeImage::release() { + this->_image_modified_connection.disconnect(); + this->_href_modified_connection.disconnect(); - if (((SPObjectClass *) sp_feImage_parent_class)->release) - ((SPObjectClass *) sp_feImage_parent_class)->release(object); + if (this->SVGElemRef) { + delete this->SVGElemRef; + } + + SPFilterPrimitive::release(); } static void sp_feImage_elem_modified(SPObject* /*href*/, guint /*flags*/, SPObject* obj) @@ -117,42 +108,39 @@ static void sp_feImage_href_modified(SPObject* /*old_elem*/, SPObject* new_elem, /** * Sets a specific value in the SPFeImage. */ -static void sp_feImage_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeImage *feImage = SP_FEIMAGE(object); - (void)feImage; +void SPFeImage::set(unsigned int key, gchar const *value) { switch(key) { /*DEAL WITH SETTING ATTRIBUTES HERE*/ case SP_ATTR_XLINK_HREF: - if (feImage->href) { - g_free(feImage->href); + if (this->href) { + g_free(this->href); } - feImage->href = (value) ? g_strdup (value) : NULL; - if (!feImage->href) return; - delete feImage->SVGElemRef; - feImage->SVGElemRef = 0; - feImage->SVGElem = 0; - feImage->_image_modified_connection.disconnect(); - feImage->_href_modified_connection.disconnect(); + this->href = (value) ? g_strdup (value) : NULL; + if (!this->href) return; + delete this->SVGElemRef; + this->SVGElemRef = 0; + this->SVGElem = 0; + this->_image_modified_connection.disconnect(); + this->_href_modified_connection.disconnect(); try{ - Inkscape::URI SVGElem_uri(feImage->href); - feImage->SVGElemRef = new Inkscape::URIReference(feImage->document); - feImage->SVGElemRef->attach(SVGElem_uri); - feImage->from_element = true; - feImage->_href_modified_connection = feImage->SVGElemRef->changedSignal().connect(sigc::bind(sigc::ptr_fun(&sp_feImage_href_modified), object)); - if (SPObject *elemref = feImage->SVGElemRef->getObject()) { - feImage->SVGElem = SP_ITEM(elemref); - feImage->_image_modified_connection = ((SPObject*) feImage->SVGElem)->connectModified(sigc::bind(sigc::ptr_fun(&sp_feImage_elem_modified), object)); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + Inkscape::URI SVGElem_uri(this->href); + this->SVGElemRef = new Inkscape::URIReference(this->document); + this->SVGElemRef->attach(SVGElem_uri); + this->from_element = true; + this->_href_modified_connection = this->SVGElemRef->changedSignal().connect(sigc::bind(sigc::ptr_fun(&sp_feImage_href_modified), this)); + if (SPObject *elemref = this->SVGElemRef->getObject()) { + this->SVGElem = SP_ITEM(elemref); + this->_image_modified_connection = ((SPObject*) this->SVGElem)->connectModified(sigc::bind(sigc::ptr_fun(&sp_feImage_elem_modified), this)); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } else { - g_warning("SVG element URI was not found in the document while loading feImage"); + g_warning("SVG element URI was not found in the document while loading this"); } } // catches either MalformedURIException or UnsupportedURIException catch(const Inkscape::BadURIException & e) { - feImage->from_element = false; + this->from_element = false; /* This occurs when using external image as the source */ //g_warning("caught Inkscape::BadURIException in sp_feImage_set"); break; @@ -162,9 +150,9 @@ static void sp_feImage_set(SPObject *object, unsigned int key, gchar const *valu case SP_ATTR_PRESERVEASPECTRATIO: /* Copied from sp-image.cpp */ /* Do setup before, so we can use break to escape */ - feImage->aspect_align = SP_ASPECT_XMID_YMID; // Default - feImage->aspect_clip = SP_ASPECT_MEET; // Default - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + this->aspect_align = SP_ASPECT_XMID_YMID; // Default + this->aspect_clip = SP_ASPECT_MEET; // Default + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); if (value) { int len; gchar c[256]; @@ -215,73 +203,62 @@ static void sp_feImage_set(SPObject *object, unsigned int key, gchar const *valu break; } } - feImage->aspect_align = align; - feImage->aspect_clip = clip; + this->aspect_align = align; + this->aspect_clip = clip; } break; default: - if (((SPObjectClass *) sp_feImage_parent_class)->set) - ((SPObjectClass *) sp_feImage_parent_class)->set(object, key, value); + SPFilterPrimitive::set(key, value); break; } - } /** * Receives update notifications. */ -static void sp_feImage_update(SPObject *object, SPCtx *ctx, guint flags) -{ - +void SPFeImage::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { /* do something to trigger redisplay, updates? */ } - if (((SPObjectClass *) sp_feImage_parent_class)->update) { - ((SPObjectClass *) sp_feImage_parent_class)->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * sp_feImage_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPFeImage::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - if (((SPObjectClass *) sp_feImage_parent_class)->write) { - ((SPObjectClass *) sp_feImage_parent_class)->write(object, doc, repr, flags); - } + SPFilterPrimitive::write(doc, repr, flags); return repr; } -static void sp_feImage_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - g_assert(primitive != NULL); +void SPFeImage::build_renderer(Inkscape::Filters::Filter* filter) { + g_assert(this != NULL); g_assert(filter != NULL); - SPFeImage *sp_image = SP_FEIMAGE(primitive); - int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_IMAGE); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); Inkscape::Filters::FilterImage *nr_image = dynamic_cast<Inkscape::Filters::FilterImage*>(nr_primitive); g_assert(nr_image != NULL); - sp_filter_primitive_renderer_common(primitive, nr_primitive); + sp_filter_primitive_renderer_common(this, nr_primitive); - nr_image->from_element = sp_image->from_element; - nr_image->SVGElem = sp_image->SVGElem; - nr_image->set_align( sp_image->aspect_align ); - nr_image->set_clip( sp_image->aspect_clip ); - nr_image->set_href(sp_image->href); - nr_image->set_document(sp_image->document); + nr_image->from_element = this->from_element; + nr_image->SVGElem = this->SVGElem; + nr_image->set_align( this->aspect_align ); + nr_image->set_clip( this->aspect_clip ); + nr_image->set_href(this->href); + nr_image->set_document(this->document); } /* diff --git a/src/filters/image.h b/src/filters/image.h index a96e650b7..452e08134 100644 --- a/src/filters/image.h +++ b/src/filters/image.h @@ -18,13 +18,14 @@ #include "sp-item.h" #include "uri-references.h" -#define SP_TYPE_FEIMAGE (sp_feImage_get_type()) -#define SP_FEIMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEIMAGE, SPFeImage)) -#define SP_FEIMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEIMAGE, SPFeImageClass)) -#define SP_IS_FEIMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEIMAGE)) -#define SP_IS_FEIMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEIMAGE)) +#define SP_FEIMAGE(obj) (dynamic_cast<SPFeImage*>((SPObject*)obj)) +#define SP_IS_FEIMAGE(obj) (dynamic_cast<const SPFeImage*>((SPObject*)obj) != NULL) + +class SPFeImage : public SPFilterPrimitive { +public: + SPFeImage(); + virtual ~SPFeImage(); -struct SPFeImage : public SPFilterPrimitive { gchar *href; /* preserveAspectRatio */ @@ -37,13 +38,19 @@ struct SPFeImage : public SPFilterPrimitive { Inkscape::URIReference* SVGElemRef; sigc::connection _image_modified_connection; sigc::connection _href_modified_connection; -}; -struct SPFeImageClass { - SPFilterPrimitiveClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void set(unsigned int key, const gchar* value); -GType sp_feImage_get_type(); + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); +}; #endif /* !SP_FEIMAGE_H_SEEN */ diff --git a/src/filters/merge.cpp b/src/filters/merge.cpp index 7346a0892..882ab36dd 100644 --- a/src/filters/merge.cpp +++ b/src/filters/merge.cpp @@ -24,34 +24,20 @@ #include "display/nr-filter.h" #include "display/nr-filter-merge.h" -/* FeMerge base class */ -static void sp_feMerge_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feMerge_release(SPObject *object); -static void sp_feMerge_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feMerge_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_feMerge_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_feMerge_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter); - -G_DEFINE_TYPE(SPFeMerge, sp_feMerge, SP_TYPE_FILTER_PRIMITIVE); - -static void -sp_feMerge_class_init(SPFeMergeClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass; - - sp_object_class->build = sp_feMerge_build; - sp_object_class->release = sp_feMerge_release; - sp_object_class->write = sp_feMerge_write; - sp_object_class->set = sp_feMerge_set; - sp_object_class->update = sp_feMerge_update; - - sp_primitive_class->build_renderer = sp_feMerge_build_renderer; +#include "sp-factory.h" + +namespace { + SPObject* createMerge() { + return new SPFeMerge(); + } + + bool mergeRegistered = SPFactory::instance().registerObject("svg:feMerge", createMerge); +} + +SPFeMerge::SPFeMerge() : SPFilterPrimitive() { } -static void -sp_feMerge_init(SPFeMerge */*feMerge*/) -{ +SPFeMerge::~SPFeMerge() { } /** @@ -59,102 +45,77 @@ sp_feMerge_init(SPFeMerge */*feMerge*/) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_feMerge_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_feMerge_parent_class)->build) { - ((SPObjectClass *) sp_feMerge_parent_class)->build(object, document, repr); - } - - /*LOAD ATTRIBUTES FROM REPR HERE*/ +void SPFeMerge::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive::build(document, repr); } /** * Drops any allocated memory. */ -static void -sp_feMerge_release(SPObject *object) -{ - if (((SPObjectClass *) sp_feMerge_parent_class)->release) - ((SPObjectClass *) sp_feMerge_parent_class)->release(object); +void SPFeMerge::release() { + SPFilterPrimitive::release(); } /** * Sets a specific value in the SPFeMerge. */ -static void -sp_feMerge_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeMerge *feMerge = SP_FEMERGE(object); - (void)feMerge; - +void SPFeMerge::set(unsigned int key, gchar const *value) { switch(key) { /*DEAL WITH SETTING ATTRIBUTES HERE*/ default: - if (((SPObjectClass *) sp_feMerge_parent_class)->set) - ((SPObjectClass *) sp_feMerge_parent_class)->set(object, key, value); + SPFilterPrimitive::set(key, value); break; } - } /** * Receives update notifications. */ -static void -sp_feMerge_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPFeMerge::update(SPCtx *ctx, guint flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } - if (((SPObjectClass *) sp_feMerge_parent_class)->update) { - ((SPObjectClass *) sp_feMerge_parent_class)->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_feMerge_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPFeMerge::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it. And child nodes, too! */ if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - if (((SPObjectClass *) sp_feMerge_parent_class)->write) { - ((SPObjectClass *) sp_feMerge_parent_class)->write(object, doc, repr, flags); - } + SPFilterPrimitive::write(doc, repr, flags); return repr; } -static void sp_feMerge_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - g_assert(primitive != NULL); +void SPFeMerge::build_renderer(Inkscape::Filters::Filter* filter) { + g_assert(this != NULL); g_assert(filter != NULL); - SPFeMerge *sp_merge = SP_FEMERGE(primitive); - (void)sp_merge; - int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_MERGE); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); Inkscape::Filters::FilterMerge *nr_merge = dynamic_cast<Inkscape::Filters::FilterMerge*>(nr_primitive); g_assert(nr_merge != NULL); - sp_filter_primitive_renderer_common(primitive, nr_primitive); + sp_filter_primitive_renderer_common(this, nr_primitive); - SPObject *input = primitive->children; + SPObject *input = this->children; int in_nr = 0; + while (input) { if (SP_IS_FEMERGENODE(input)) { SPFeMergeNode *node = SP_FEMERGENODE(input); nr_merge->set_input(in_nr, node->input); in_nr++; } + input = input->next; } } diff --git a/src/filters/merge.h b/src/filters/merge.h index 40a9bb848..68257c38e 100644 --- a/src/filters/merge.h +++ b/src/filters/merge.h @@ -12,22 +12,26 @@ #include "sp-filter-primitive.h" -#define SP_TYPE_FEMERGE (sp_feMerge_get_type()) -#define SP_FEMERGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEMERGE, SPFeMerge)) -#define SP_FEMERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEMERGE, SPFeMergeClass)) -#define SP_IS_FEMERGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEMERGE)) -#define SP_IS_FEMERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEMERGE)) - -struct SPFeMerge : public SPFilterPrimitive { - -}; +#define SP_FEMERGE(obj) (dynamic_cast<SPFeMerge*>((SPObject*)obj)) +#define SP_IS_FEMERGE(obj) (dynamic_cast<const SPFeMerge*>((SPObject*)obj) != NULL) -struct SPFeMergeClass { - SPFilterPrimitiveClass parent_class; -}; +class SPFeMerge : public SPFilterPrimitive { +public: + SPFeMerge(); + virtual ~SPFeMerge(); + +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); -GType sp_feMerge_get_type(); + virtual void set(unsigned int key, const gchar* value); + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); +}; #endif /* !SP_FEMERGE_H_SEEN */ diff --git a/src/filters/mergenode.cpp b/src/filters/mergenode.cpp index fa193ad77..1b06db706 100644 --- a/src/filters/mergenode.cpp +++ b/src/filters/mergenode.cpp @@ -23,30 +23,21 @@ #include "filters/merge.h" #include "display/nr-filter-types.h" -static void sp_feMergeNode_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feMergeNode_release(SPObject *object); -static void sp_feMergeNode_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feMergeNode_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_feMergeNode_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -G_DEFINE_TYPE(SPFeMergeNode, sp_feMergeNode, SP_TYPE_OBJECT); - -static void -sp_feMergeNode_class_init(SPFeMergeNodeClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - - sp_object_class->build = sp_feMergeNode_build; - sp_object_class->release = sp_feMergeNode_release; - sp_object_class->write = sp_feMergeNode_write; - sp_object_class->set = sp_feMergeNode_set; - sp_object_class->update = sp_feMergeNode_update; +#include "sp-factory.h" + +namespace { + SPObject* createMergeNode() { + return new SPFeMergeNode(); + } + + bool mergeNodeRegistered = SPFactory::instance().registerObject("svg:feMergeNode", createMergeNode); } -static void -sp_feMergeNode_init(SPFeMergeNode *feMergeNode) -{ - feMergeNode->input = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET; +SPFeMergeNode::SPFeMergeNode() + : SPObject(), input(Inkscape::Filters::NR_FILTER_SLOT_NOT_SET) { +} + +SPFeMergeNode::~SPFeMergeNode() { } /** @@ -54,85 +45,61 @@ sp_feMergeNode_init(SPFeMergeNode *feMergeNode) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_feMergeNode_build(SPObject *object, SPDocument */*document*/, Inkscape::XML::Node */*repr*/) -{ - object->readAttr( "in" ); +void SPFeMergeNode::build(SPDocument *document, Inkscape::XML::Node *repr) { + this->readAttr( "in" ); } /** * Drops any allocated memory. */ -static void -sp_feMergeNode_release(SPObject *object) -{ - /* deal with our children and our selves here */ - - if (((SPObjectClass *) sp_feMergeNode_parent_class)->release) - ((SPObjectClass *) sp_feMergeNode_parent_class)->release(object); +void SPFeMergeNode::release() { + SPObject::release(); } /** * Sets a specific value in the SPFeMergeNode. */ -static void -sp_feMergeNode_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeMergeNode *feMergeNode = SP_FEMERGENODE(object); - SPFeMerge *parent = SP_FEMERGE(object->parent); +void SPFeMergeNode::set(unsigned int key, gchar const *value) { + SPFeMerge *parent = SP_FEMERGE(this->parent); if (key == SP_ATTR_IN) { int input = sp_filter_primitive_read_in(parent, value); - if (input != feMergeNode->input) { - feMergeNode->input = input; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (input != this->input) { + this->input = input; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } } /* See if any parents need this value. */ - if (((SPObjectClass *) sp_feMergeNode_parent_class)->set) { - ((SPObjectClass *) sp_feMergeNode_parent_class)->set(object, key, value); - } + SPObject::set(key, value); } /** * Receives update notifications. */ -static void -sp_feMergeNode_update(SPObject *object, SPCtx *ctx, guint flags) -{ - //SPFeMergeNode *feMergeNode = SP_FEMERGENODE(object); - +void SPFeMergeNode::update(SPCtx *ctx, guint flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } - if (((SPObjectClass *) sp_feMergeNode_parent_class)->update) { - ((SPObjectClass *) sp_feMergeNode_parent_class)->update(object, ctx, flags); - } + SPObject::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_feMergeNode_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ - //SPFeMergeNode *feMergeNode = SP_FEMERGENODE(object); - - // Inkscape-only object, not copied during an "plain SVG" dump: +Inkscape::XML::Node* SPFeMergeNode::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { + // Inkscape-only this, not copied during an "plain SVG" dump: if (flags & SP_OBJECT_WRITE_EXT) { if (repr) { // is this sane? //repr->mergeFrom(object->getRepr(), "id"); } else { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } } - if (((SPObjectClass *) sp_feMergeNode_parent_class)->write) { - ((SPObjectClass *) sp_feMergeNode_parent_class)->write(object, doc, repr, flags); - } + SPObject::write(doc, repr, flags); return repr; } diff --git a/src/filters/mergenode.h b/src/filters/mergenode.h index edb35faec..408b3bbb8 100644 --- a/src/filters/mergenode.h +++ b/src/filters/mergenode.h @@ -17,20 +17,26 @@ #include "sp-object.h" -#define SP_TYPE_FEMERGENODE (sp_feMergeNode_get_type()) -#define SP_FEMERGENODE(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_FEMERGENODE, SPFeMergeNode)) -#define SP_IS_FEMERGENODE(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_FEMERGENODE)) +#define SP_FEMERGENODE(obj) (dynamic_cast<SPFeMergeNode*>((SPObject*)obj)) +#define SP_IS_FEMERGENODE(obj) (dynamic_cast<const SPFeMergeNode*>((SPObject*)obj) != NULL) + +class SPFeMergeNode : public SPObject { +public: + SPFeMergeNode(); + virtual ~SPFeMergeNode(); -struct SPFeMergeNode : public SPObject { int input; -}; -struct SPFeMergeNodeClass { - SPObjectClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); -GType sp_feMergeNode_get_type(); + virtual void set(unsigned int key, const gchar* value); + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); +}; #endif /* !SP_FEMERGENODE_H_SEEN */ diff --git a/src/filters/morphology.cpp b/src/filters/morphology.cpp index 886a10311..d3611b081 100644 --- a/src/filters/morphology.cpp +++ b/src/filters/morphology.cpp @@ -26,35 +26,24 @@ #include "display/nr-filter.h" #include "display/nr-filter-morphology.h" -/* FeMorphology base class */ -static void sp_feMorphology_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feMorphology_release(SPObject *object); -static void sp_feMorphology_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feMorphology_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_feMorphology_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_feMorphology_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter); - -G_DEFINE_TYPE(SPFeMorphology, sp_feMorphology, SP_TYPE_FILTER_PRIMITIVE); - -static void -sp_feMorphology_class_init(SPFeMorphologyClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass; - - sp_object_class->build = sp_feMorphology_build; - sp_object_class->release = sp_feMorphology_release; - sp_object_class->write = sp_feMorphology_write; - sp_object_class->set = sp_feMorphology_set; - sp_object_class->update = sp_feMorphology_update; - sp_primitive_class->build_renderer = sp_feMorphology_build_renderer; +#include "sp-factory.h" + +namespace { + SPObject* createMorphology() { + return new SPFeMorphology(); + } + + bool morphologyRegistered = SPFactory::instance().registerObject("svg:feMorphology", createMorphology); } -static void -sp_feMorphology_init(SPFeMorphology *feMorphology) -{ +SPFeMorphology::SPFeMorphology() : SPFilterPrimitive() { + this->Operator = Inkscape::Filters::MORPHOLOGY_OPERATOR_ERODE; + //Setting default values: - feMorphology->radius.set("0"); + this->radius.set("0"); +} + +SPFeMorphology::~SPFeMorphology() { } /** @@ -62,70 +51,70 @@ sp_feMorphology_init(SPFeMorphology *feMorphology) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_feMorphology_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_feMorphology_parent_class)->build) { - ((SPObjectClass *) sp_feMorphology_parent_class)->build(object, document, repr); - } +void SPFeMorphology::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive::build(document, repr); - /*LOAD ATTRIBUTES FROM REPR HERE*/ - object->readAttr( "operator" ); - object->readAttr( "radius" ); + /*LOAD ATTRIBUTES FROM REPR HERE*/ + this->readAttr( "operator" ); + this->readAttr( "radius" ); } /** * Drops any allocated memory. */ -static void -sp_feMorphology_release(SPObject *object) -{ - if (((SPObjectClass *) sp_feMorphology_parent_class)->release) - ((SPObjectClass *) sp_feMorphology_parent_class)->release(object); +void SPFeMorphology::release() { + SPFilterPrimitive::release(); } static Inkscape::Filters::FilterMorphologyOperator sp_feMorphology_read_operator(gchar const *value){ - if (!value) return Inkscape::Filters::MORPHOLOGY_OPERATOR_ERODE; //erode is default + if (!value) { + return Inkscape::Filters::MORPHOLOGY_OPERATOR_ERODE; //erode is default + } + switch(value[0]){ case 'e': - if (strncmp(value, "erode", 5) == 0) return Inkscape::Filters::MORPHOLOGY_OPERATOR_ERODE; + if (strncmp(value, "erode", 5) == 0) { + return Inkscape::Filters::MORPHOLOGY_OPERATOR_ERODE; + } break; case 'd': - if (strncmp(value, "dilate", 6) == 0) return Inkscape::Filters::MORPHOLOGY_OPERATOR_DILATE; + if (strncmp(value, "dilate", 6) == 0) { + return Inkscape::Filters::MORPHOLOGY_OPERATOR_DILATE; + } break; } + return Inkscape::Filters::MORPHOLOGY_OPERATOR_ERODE; //erode is default } /** * Sets a specific value in the SPFeMorphology. */ -static void -sp_feMorphology_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeMorphology *feMorphology = SP_FEMORPHOLOGY(object); - (void)feMorphology; - +void SPFeMorphology::set(unsigned int key, gchar const *value) { Inkscape::Filters::FilterMorphologyOperator read_operator; + switch(key) { /*DEAL WITH SETTING ATTRIBUTES HERE*/ case SP_ATTR_OPERATOR: read_operator = sp_feMorphology_read_operator(value); - if (read_operator != feMorphology->Operator){ - feMorphology->Operator = read_operator; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_operator != this->Operator){ + this->Operator = read_operator; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_RADIUS: - feMorphology->radius.set(value); + this->radius.set(value); + //From SVG spec: If <y-radius> is not provided, it defaults to <x-radius>. - if (feMorphology->radius.optNumIsSet() == false) - feMorphology->radius.setOptNumber(feMorphology->radius.getNumber()); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (this->radius.optNumIsSet() == false) { + this->radius.setOptNumber(this->radius.getNumber()); + } + + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); break; default: - if (((SPObjectClass *) sp_feMorphology_parent_class)->set) - ((SPObjectClass *) sp_feMorphology_parent_class)->set(object, key, value); + SPFilterPrimitive::set(key, value); break; } @@ -134,9 +123,7 @@ sp_feMorphology_set(SPObject *object, unsigned int key, gchar const *value) /** * Receives update notifications. */ -static void -sp_feMorphology_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPFeMorphology::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { @@ -144,46 +131,38 @@ sp_feMorphology_update(SPObject *object, SPCtx *ctx, guint flags) } - if (((SPObjectClass *) sp_feMorphology_parent_class)->update) { - ((SPObjectClass *) sp_feMorphology_parent_class)->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_feMorphology_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ - /* TODO: Don't just clone, but create a new repr node and write all +Inkscape::XML::Node* SPFeMorphology::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { + /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - if (((SPObjectClass *) sp_feMorphology_parent_class)->write) { - ((SPObjectClass *) sp_feMorphology_parent_class)->write(object, doc, repr, flags); - } + SPFilterPrimitive::write(doc, repr, flags); return repr; } -static void sp_feMorphology_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - g_assert(primitive != NULL); +void SPFeMorphology::build_renderer(Inkscape::Filters::Filter* filter) { + g_assert(this != NULL); g_assert(filter != NULL); - SPFeMorphology *sp_morphology = SP_FEMORPHOLOGY(primitive); - int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_MORPHOLOGY); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); Inkscape::Filters::FilterMorphology *nr_morphology = dynamic_cast<Inkscape::Filters::FilterMorphology*>(nr_primitive); g_assert(nr_morphology != NULL); - sp_filter_primitive_renderer_common(primitive, nr_primitive); + sp_filter_primitive_renderer_common(this, nr_primitive); - nr_morphology->set_operator(sp_morphology->Operator); - nr_morphology->set_xradius( sp_morphology->radius.getNumber() ); - nr_morphology->set_yradius( sp_morphology->radius.getOptNumber() ); + nr_morphology->set_operator(this->Operator); + nr_morphology->set_xradius( this->radius.getNumber() ); + nr_morphology->set_yradius( this->radius.getOptNumber() ); } /* diff --git a/src/filters/morphology.h b/src/filters/morphology.h index 9084d1b94..f84a7271e 100644 --- a/src/filters/morphology.h +++ b/src/filters/morphology.h @@ -16,23 +16,29 @@ #include "number-opt-number.h" #include "display/nr-filter-morphology.h" -#define SP_TYPE_FEMORPHOLOGY (sp_feMorphology_get_type()) -#define SP_FEMORPHOLOGY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEMORPHOLOGY, SPFeMorphology)) -#define SP_FEMORPHOLOGY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEMORPHOLOGY, SPFeMorphologyClass)) -#define SP_IS_FEMORPHOLOGY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEMORPHOLOGY)) -#define SP_IS_FEMORPHOLOGY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEMORPHOLOGY)) +#define SP_FEMORPHOLOGY(obj) (dynamic_cast<SPFeMorphology*>((SPObject*)obj)) +#define SP_IS_FEMORPHOLOGY(obj) (dynamic_cast<const SPFeMorphology*>((SPObject*)obj) != NULL) + +class SPFeMorphology : public SPFilterPrimitive { +public: + SPFeMorphology(); + virtual ~SPFeMorphology(); -struct SPFeMorphology : public SPFilterPrimitive { Inkscape::Filters::FilterMorphologyOperator Operator; NumberOptNumber radius; -}; -struct SPFeMorphologyClass { - SPFilterPrimitiveClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); -GType sp_feMorphology_get_type(); + virtual void set(unsigned int key, const gchar* value); + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); +}; #endif /* !SP_FEMORPHOLOGY_H_SEEN */ diff --git a/src/filters/offset.cpp b/src/filters/offset.cpp index 2851f4f7d..234a1a964 100644 --- a/src/filters/offset.cpp +++ b/src/filters/offset.cpp @@ -25,36 +25,22 @@ #include "display/nr-filter.h" #include "display/nr-filter-offset.h" -/* FeOffset base class */ -static void sp_feOffset_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feOffset_release(SPObject *object); -static void sp_feOffset_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feOffset_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_feOffset_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_feOffset_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter); - -G_DEFINE_TYPE(SPFeOffset, sp_feOffset, SP_TYPE_FILTER_PRIMITIVE); - -static void -sp_feOffset_class_init(SPFeOffsetClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass; - - sp_object_class->build = sp_feOffset_build; - sp_object_class->release = sp_feOffset_release; - sp_object_class->write = sp_feOffset_write; - sp_object_class->set = sp_feOffset_set; - sp_object_class->update = sp_feOffset_update; - - sp_primitive_class->build_renderer = sp_feOffset_build_renderer; +#include "sp-factory.h" + +namespace { + SPObject* createOffset() { + return new SPFeOffset(); + } + + bool offsetRegistered = SPFactory::instance().registerObject("svg:feOffset", createOffset); +} + +SPFeOffset::SPFeOffset() : SPFilterPrimitive() { + this->dx = 0; + this->dy = 0; } -static void -sp_feOffset_init(SPFeOffset *feOffset) -{ - feOffset->dx = 0; - feOffset->dy = 0; +SPFeOffset::~SPFeOffset() { } /** @@ -62,111 +48,91 @@ sp_feOffset_init(SPFeOffset *feOffset) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_feOffset_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_feOffset_parent_class)->build) { - ((SPObjectClass *) sp_feOffset_parent_class)->build(object, document, repr); - } +void SPFeOffset::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive::build(document, repr); - object->readAttr( "dx" ); - object->readAttr( "dy" ); + this->readAttr( "dx" ); + this->readAttr( "dy" ); } /** * Drops any allocated memory. */ -static void -sp_feOffset_release(SPObject *object) -{ - if (((SPObjectClass *) sp_feOffset_parent_class)->release) - ((SPObjectClass *) sp_feOffset_parent_class)->release(object); +void SPFeOffset::release() { + SPFilterPrimitive::release(); } /** * Sets a specific value in the SPFeOffset. */ -static void -sp_feOffset_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeOffset *feOffset = SP_FEOFFSET(object); - +void SPFeOffset::set(unsigned int key, gchar const *value) { double read_num; + switch(key) { case SP_ATTR_DX: read_num = value ? helperfns_read_number(value) : 0; - if (read_num != feOffset->dx) { - feOffset->dx = read_num; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_num != this->dx) { + this->dx = read_num; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_DY: read_num = value ? helperfns_read_number(value) : 0; - if (read_num != feOffset->dy) { - feOffset->dy = read_num; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_num != this->dy) { + this->dy = read_num; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; /*DEAL WITH SETTING ATTRIBUTES HERE*/ default: - if (((SPObjectClass *) sp_feOffset_parent_class)->set) - ((SPObjectClass *) sp_feOffset_parent_class)->set(object, key, value); + SPFilterPrimitive::set(key, value); break; } - } /** * Receives update notifications. */ -static void -sp_feOffset_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPFeOffset::update(SPCtx *ctx, guint flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { - object->readAttr( "dx" ); - object->readAttr( "dy" ); + this->readAttr( "dx" ); + this->readAttr( "dy" ); } - if (((SPObjectClass *) sp_feOffset_parent_class)->update) { - ((SPObjectClass *) sp_feOffset_parent_class)->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_feOffset_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPFeOffset::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - if (((SPObjectClass *) sp_feOffset_parent_class)->write) { - ((SPObjectClass *) sp_feOffset_parent_class)->write(object, doc, repr, flags); - } + SPFilterPrimitive::write(doc, repr, flags); return repr; } -static void sp_feOffset_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - g_assert(primitive != NULL); +void SPFeOffset::build_renderer(Inkscape::Filters::Filter* filter) { + g_assert(this != NULL); g_assert(filter != NULL); - SPFeOffset *sp_offset = SP_FEOFFSET(primitive); - int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_OFFSET); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); Inkscape::Filters::FilterOffset *nr_offset = dynamic_cast<Inkscape::Filters::FilterOffset*>(nr_primitive); g_assert(nr_offset != NULL); - sp_filter_primitive_renderer_common(primitive, nr_primitive); + sp_filter_primitive_renderer_common(this, nr_primitive); - nr_offset->set_dx(sp_offset->dx); - nr_offset->set_dy(sp_offset->dy); + nr_offset->set_dx(this->dx); + nr_offset->set_dy(this->dy); } diff --git a/src/filters/offset.h b/src/filters/offset.h index 08954a8e4..0d26f6f90 100644 --- a/src/filters/offset.h +++ b/src/filters/offset.h @@ -14,22 +14,28 @@ #include "sp-filter-primitive.h" -#define SP_TYPE_FEOFFSET (sp_feOffset_get_type()) -#define SP_FEOFFSET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEOFFSET, SPFeOffset)) -#define SP_FEOFFSET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEOFFSET, SPFeOffsetClass)) -#define SP_IS_FEOFFSET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEOFFSET)) -#define SP_IS_FEOFFSET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEOFFSET)) +#define SP_FEOFFSET(obj) (dynamic_cast<SPFeOffset*>((SPObject*)obj)) +#define SP_IS_FEOFFSET(obj) (dynamic_cast<const SPFeOffset*>((SPObject*)obj) != NULL) + +class SPFeOffset : public SPFilterPrimitive { +public: + SPFeOffset(); + virtual ~SPFeOffset(); -struct SPFeOffset : public SPFilterPrimitive { double dx, dy; -}; -struct SPFeOffsetClass { - SPFilterPrimitiveClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); -GType sp_feOffset_get_type(); + virtual void set(unsigned int key, const gchar* value); + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); +}; #endif /* !SP_FEOFFSET_H_SEEN */ diff --git a/src/filters/pointlight.cpp b/src/filters/pointlight.cpp index a512172d1..1c7532b4e 100644 --- a/src/filters/pointlight.cpp +++ b/src/filters/pointlight.cpp @@ -29,71 +29,48 @@ #define SP_MACROS_SILENT #include "macros.h" -/* FePointLight class */ -static void sp_fepointlight_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_fepointlight_release(SPObject *object); -static void sp_fepointlight_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_fepointlight_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_fepointlight_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -G_DEFINE_TYPE(SPFePointLight, sp_fepointlight, SP_TYPE_OBJECT); - -static void -sp_fepointlight_class_init(SPFePointLightClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - - sp_object_class->build = sp_fepointlight_build; - sp_object_class->release = sp_fepointlight_release; - sp_object_class->write = sp_fepointlight_write; - sp_object_class->set = sp_fepointlight_set; - sp_object_class->update = sp_fepointlight_update; +#include "sp-factory.h" + +namespace { + SPObject* createPointLight() { + return new SPFePointLight(); + } + + bool pointLightRegistered = SPFactory::instance().registerObject("svg:fePointLight", createPointLight); } -static void -sp_fepointlight_init(SPFePointLight *fepointlight) -{ - fepointlight->x = 0; - fepointlight->y = 0; - fepointlight->z = 0; +SPFePointLight::SPFePointLight() + : SPObject(), x(0), x_set(FALSE), y(0), y_set(FALSE), z(0), z_set(FALSE) { +} - fepointlight->x_set = FALSE; - fepointlight->y_set = FALSE; - fepointlight->z_set = FALSE; +SPFePointLight::~SPFePointLight() { } + /** * Reads the Inkscape::XML::Node, and initializes SPPointLight variables. For this to get called, * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_fepointlight_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_fepointlight_parent_class)->build) { - ((SPObjectClass *) sp_fepointlight_parent_class)->build(object, document, repr); - } +void SPFePointLight::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPObject::build(document, repr); //Read values of key attributes from XML nodes into object. - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "z" ); + this->readAttr( "x" ); + this->readAttr( "y" ); + this->readAttr( "z" ); //is this necessary? - document->addResource("fepointlight", object); + document->addResource("fepointlight", this); } /** * Drops any allocated memory. */ -static void -sp_fepointlight_release(SPObject *object) -{ - //SPFePointLight *fepointlight = SP_FEPOINTLIGHT(object); - - if ( object->document ) { +void SPFePointLight::release() { + if ( this->document ) { // Unregister ourselves - object->document->removeResource("fepointlight", object); + this->document->removeResource("fepointlight", this); } //TODO: release resources here @@ -102,71 +79,79 @@ sp_fepointlight_release(SPObject *object) /** * Sets a specific value in the SPFePointLight. */ -static void -sp_fepointlight_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFePointLight *fepointlight = SP_FEPOINTLIGHT(object); +void SPFePointLight::set(unsigned int key, gchar const *value) { gchar *end_ptr; + switch (key) { case SP_ATTR_X: end_ptr = NULL; + if (value) { - fepointlight->x = g_ascii_strtod(value, &end_ptr); + this->x = g_ascii_strtod(value, &end_ptr); + if (end_ptr) { - fepointlight->x_set = TRUE; + this->x_set = TRUE; } } + if (!value || !end_ptr) { - fepointlight->x = 0; - fepointlight->x_set = FALSE; + this->x = 0; + this->x_set = FALSE; } - if (object->parent && - (SP_IS_FEDIFFUSELIGHTING(object->parent) || - SP_IS_FESPECULARLIGHTING(object->parent))) { - object->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->parent && + (SP_IS_FEDIFFUSELIGHTING(this->parent) || + SP_IS_FESPECULARLIGHTING(this->parent))) { + this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_Y: end_ptr = NULL; + if (value) { - fepointlight->y = g_ascii_strtod(value, &end_ptr); + this->y = g_ascii_strtod(value, &end_ptr); + if (end_ptr) { - fepointlight->y_set = TRUE; + this->y_set = TRUE; } } + if (!value || !end_ptr) { - fepointlight->y = 0; - fepointlight->y_set = FALSE; + this->y = 0; + this->y_set = FALSE; } - if (object->parent && - (SP_IS_FEDIFFUSELIGHTING(object->parent) || - SP_IS_FESPECULARLIGHTING(object->parent))) { - object->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->parent && + (SP_IS_FEDIFFUSELIGHTING(this->parent) || + SP_IS_FESPECULARLIGHTING(this->parent))) { + this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_Z: end_ptr = NULL; + if (value) { - fepointlight->z = g_ascii_strtod(value, &end_ptr); + this->z = g_ascii_strtod(value, &end_ptr); + if (end_ptr) { - fepointlight->z_set = TRUE; + this->z_set = TRUE; } } + if (!value || !end_ptr) { - fepointlight->z = 0; - fepointlight->z_set = FALSE; + this->z = 0; + this->z_set = FALSE; } - if (object->parent && - (SP_IS_FEDIFFUSELIGHTING(object->parent) || - SP_IS_FESPECULARLIGHTING(object->parent))) { - object->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->parent && + (SP_IS_FEDIFFUSELIGHTING(this->parent) || + SP_IS_FESPECULARLIGHTING(this->parent))) { + this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; default: // See if any parents need this value. - if (((SPObjectClass *) sp_fepointlight_parent_class)->set) { - ((SPObjectClass *) sp_fepointlight_parent_class)->set(object, key, value); - } + SPObject::set(key, value); break; } } @@ -174,46 +159,33 @@ sp_fepointlight_set(SPObject *object, unsigned int key, gchar const *value) /** * * Receives update notifications. * */ -static void -sp_fepointlight_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPFePointLight *fePointLight = SP_FEPOINTLIGHT(object); - (void)fePointLight; - +void SPFePointLight::update(SPCtx *ctx, guint flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { /* do something to trigger redisplay, updates? */ - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "z" ); + this->readAttr( "x" ); + this->readAttr( "y" ); + this->readAttr( "z" ); } - if (((SPObjectClass *) sp_fepointlight_parent_class)->update) { - ((SPObjectClass *) sp_fepointlight_parent_class)->update(object, ctx, flags); - } + SPObject::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_fepointlight_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ - SPFePointLight *fepointlight = SP_FEPOINTLIGHT(object); - +Inkscape::XML::Node* SPFePointLight::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - if (fepointlight->x_set) - sp_repr_set_css_double(repr, "x", fepointlight->x); - if (fepointlight->y_set) - sp_repr_set_css_double(repr, "y", fepointlight->y); - if (fepointlight->z_set) - sp_repr_set_css_double(repr, "z", fepointlight->z); + if (this->x_set) + sp_repr_set_css_double(repr, "x", this->x); + if (this->y_set) + sp_repr_set_css_double(repr, "y", this->y); + if (this->z_set) + sp_repr_set_css_double(repr, "z", this->z); - if (((SPObjectClass *) sp_fepointlight_parent_class)->write) { - ((SPObjectClass *) sp_fepointlight_parent_class)->write(object, doc, repr, flags); - } + SPObject::write(doc, repr, flags); return repr; } diff --git a/src/filters/pointlight.h b/src/filters/pointlight.h index 3ec5d5791..3819d8ff5 100644 --- a/src/filters/pointlight.h +++ b/src/filters/pointlight.h @@ -17,13 +17,13 @@ #include "sp-object.h" -#define SP_TYPE_FEPOINTLIGHT (sp_fepointlight_get_type()) -#define SP_FEPOINTLIGHT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FEPOINTLIGHT, SPFePointLight)) -#define SP_FEPOINTLIGHT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FEPOINTLIGHT, SPFePointLightClass)) -#define SP_IS_FEPOINTLIGHT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FEPOINTLIGHT)) -#define SP_IS_FEPOINTLIGHT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FEPOINTLIGHT)) +#define SP_FEPOINTLIGHT(obj) (dynamic_cast<SPFePointLight*>((SPObject*)obj)) +#define SP_IS_FEPOINTLIGHT(obj) (dynamic_cast<const SPFePointLight*>((SPObject*)obj) != NULL) -struct SPFePointLight : public SPObject { +class SPFePointLight : public SPObject { +public: + SPFePointLight(); + virtual ~SPFePointLight(); /** x coordinate of the light source */ gfloat x; @@ -35,15 +35,17 @@ struct SPFePointLight : public SPObject { gfloat z; guint z_set : 1; - //other fields -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void set(unsigned int key, const gchar* value); + + virtual void update(SPCtx* ctx, unsigned int flags); -struct SPFePointLightClass { - SPObjectClass parent_class; + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); }; -GType -sp_fepointlight_get_type(); #endif /* !SP_FEPOINTLIGHT_H_SEEN */ /* diff --git a/src/filters/specularlighting.cpp b/src/filters/specularlighting.cpp index a7a19e11d..6cdd5d9ba 100644 --- a/src/filters/specularlighting.cpp +++ b/src/filters/specularlighting.cpp @@ -34,59 +34,35 @@ #include "display/nr-filter-specularlighting.h" /* FeSpecularLighting base class */ -static void sp_feSpecularLighting_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feSpecularLighting_release(SPObject *object); -static void sp_feSpecularLighting_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feSpecularLighting_update(SPObject *object, SPCtx *ctx, guint flags); -//we assume that svg:feSpecularLighting can have any number of children -//only the first one is considered as the light source of the filter -//TODO is that right? -//if not modify child_added and remove_child to raise errors -static void sp_feSpecularLighting_child_added(SPObject *object, - Inkscape::XML::Node *child, - Inkscape::XML::Node *ref); -static void sp_feSpecularLighting_remove_child(SPObject *object, Inkscape::XML::Node *child); -static void sp_feSpecularLighting_order_changed(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref); -static Inkscape::XML::Node *sp_feSpecularLighting_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_feSpecularLighting_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter); static void sp_feSpecularLighting_children_modified(SPFeSpecularLighting *sp_specularlighting); -G_DEFINE_TYPE(SPFeSpecularLighting, sp_feSpecularLighting, SP_TYPE_FILTER_PRIMITIVE); +#include "sp-factory.h" -static void -sp_feSpecularLighting_class_init(SPFeSpecularLightingClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass; +namespace { + SPObject* createSpecularLighting() { + return new SPFeSpecularLighting(); + } - sp_object_class->build = sp_feSpecularLighting_build; - sp_object_class->release = sp_feSpecularLighting_release; - sp_object_class->write = sp_feSpecularLighting_write; - sp_object_class->set = sp_feSpecularLighting_set; - sp_object_class->update = sp_feSpecularLighting_update; - sp_object_class->child_added = sp_feSpecularLighting_child_added; - sp_object_class->remove_child = sp_feSpecularLighting_remove_child; - sp_object_class->order_changed = sp_feSpecularLighting_order_changed; - - sp_primitive_class->build_renderer = sp_feSpecularLighting_build_renderer; + bool specularLightingRegistered = SPFactory::instance().registerObject("svg:feSpecularLighting", createSpecularLighting); } -static void -sp_feSpecularLighting_init(SPFeSpecularLighting *feSpecularLighting) -{ - feSpecularLighting->surfaceScale = 1; - feSpecularLighting->specularConstant = 1; - feSpecularLighting->specularExponent = 1; - feSpecularLighting->lighting_color = 0xffffffff; - feSpecularLighting->icc = NULL; +SPFeSpecularLighting::SPFeSpecularLighting() : SPFilterPrimitive() { + this->surfaceScale = 1; + this->specularConstant = 1; + this->specularExponent = 1; + this->lighting_color = 0xffffffff; + this->icc = NULL; //TODO kernelUnit - feSpecularLighting->renderer = NULL; + this->renderer = NULL; - feSpecularLighting->surfaceScale_set = FALSE; - feSpecularLighting->specularConstant_set = FALSE; - feSpecularLighting->specularExponent_set = FALSE; - feSpecularLighting->lighting_color_set = FALSE; + this->surfaceScale_set = FALSE; + this->specularConstant_set = FALSE; + this->specularExponent_set = FALSE; + this->lighting_color_set = FALSE; +} + +SPFeSpecularLighting::~SPFeSpecularLighting() { } /** @@ -94,196 +70,181 @@ sp_feSpecularLighting_init(SPFeSpecularLighting *feSpecularLighting) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_feSpecularLighting_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_feSpecularLighting_parent_class)->build) { - ((SPObjectClass *) sp_feSpecularLighting_parent_class)->build(object, document, repr); - } - - /*LOAD ATTRIBUTES FROM REPR HERE*/ - object->readAttr( "surfaceScale" ); - object->readAttr( "specularConstant" ); - object->readAttr( "specularExponent" ); - object->readAttr( "kernelUnitLength" ); - object->readAttr( "lighting-color" ); - +void SPFeSpecularLighting::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive::build(document, repr); + + /*LOAD ATTRIBUTES FROM REPR HERE*/ + this->readAttr( "surfaceScale" ); + this->readAttr( "specularConstant" ); + this->readAttr( "specularExponent" ); + this->readAttr( "kernelUnitLength" ); + this->readAttr( "lighting-color" ); } /** * Drops any allocated memory. */ -static void -sp_feSpecularLighting_release(SPObject *object) -{ - if (((SPObjectClass *) sp_feSpecularLighting_parent_class)->release) - ((SPObjectClass *) sp_feSpecularLighting_parent_class)->release(object); +void SPFeSpecularLighting::release() { + SPFilterPrimitive::release(); } /** * Sets a specific value in the SPFeSpecularLighting. */ -static void -sp_feSpecularLighting_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeSpecularLighting *feSpecularLighting = SP_FESPECULARLIGHTING(object); +void SPFeSpecularLighting::set(unsigned int key, gchar const *value) { gchar const *cend_ptr = NULL; gchar *end_ptr = NULL; + switch(key) { /*DEAL WITH SETTING ATTRIBUTES HERE*/ //TODO test forbidden values case SP_ATTR_SURFACESCALE: end_ptr = NULL; if (value) { - feSpecularLighting->surfaceScale = g_ascii_strtod(value, &end_ptr); + this->surfaceScale = g_ascii_strtod(value, &end_ptr); if (end_ptr) { - feSpecularLighting->surfaceScale_set = TRUE; + this->surfaceScale_set = TRUE; } else { - g_warning("feSpecularLighting: surfaceScale should be a number ... defaulting to 1"); + g_warning("this: surfaceScale should be a number ... defaulting to 1"); } } //if the attribute is not set or has an unreadable value if (!value || !end_ptr) { - feSpecularLighting->surfaceScale = 1; - feSpecularLighting->surfaceScale_set = FALSE; + this->surfaceScale = 1; + this->surfaceScale_set = FALSE; } - if (feSpecularLighting->renderer) { - feSpecularLighting->renderer->surfaceScale = feSpecularLighting->surfaceScale; + if (this->renderer) { + this->renderer->surfaceScale = this->surfaceScale; } - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SPECULARCONSTANT: end_ptr = NULL; if (value) { - feSpecularLighting->specularConstant = g_ascii_strtod(value, &end_ptr); - if (end_ptr && feSpecularLighting->specularConstant >= 0) { - feSpecularLighting->specularConstant_set = TRUE; + this->specularConstant = g_ascii_strtod(value, &end_ptr); + if (end_ptr && this->specularConstant >= 0) { + this->specularConstant_set = TRUE; } else { end_ptr = NULL; - g_warning("feSpecularLighting: specularConstant should be a positive number ... defaulting to 1"); + g_warning("this: specularConstant should be a positive number ... defaulting to 1"); } } if (!value || !end_ptr) { - feSpecularLighting->specularConstant = 1; - feSpecularLighting->specularConstant_set = FALSE; + this->specularConstant = 1; + this->specularConstant_set = FALSE; } - if (feSpecularLighting->renderer) { - feSpecularLighting->renderer->specularConstant = feSpecularLighting->specularConstant; + if (this->renderer) { + this->renderer->specularConstant = this->specularConstant; } - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SPECULAREXPONENT: end_ptr = NULL; if (value) { - feSpecularLighting->specularExponent = g_ascii_strtod(value, &end_ptr); - if (feSpecularLighting->specularExponent >= 1 && feSpecularLighting->specularExponent <= 128) { - feSpecularLighting->specularExponent_set = TRUE; + this->specularExponent = g_ascii_strtod(value, &end_ptr); + if (this->specularExponent >= 1 && this->specularExponent <= 128) { + this->specularExponent_set = TRUE; } else { end_ptr = NULL; - g_warning("feSpecularLighting: specularExponent should be a number in range [1, 128] ... defaulting to 1"); + g_warning("this: specularExponent should be a number in range [1, 128] ... defaulting to 1"); } } if (!value || !end_ptr) { - feSpecularLighting->specularExponent = 1; - feSpecularLighting->specularExponent_set = FALSE; + this->specularExponent = 1; + this->specularExponent_set = FALSE; } - if (feSpecularLighting->renderer) { - feSpecularLighting->renderer->specularExponent = feSpecularLighting->specularExponent; + if (this->renderer) { + this->renderer->specularExponent = this->specularExponent; } - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_KERNELUNITLENGTH: //TODO kernelUnit - //feSpecularLighting->kernelUnitLength.set(value); + //this->kernelUnitLength.set(value); /*TODOif (feSpecularLighting->renderer) { feSpecularLighting->renderer->surfaceScale = feSpecularLighting->renderer; } */ - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_PROP_LIGHTING_COLOR: cend_ptr = NULL; - feSpecularLighting->lighting_color = sp_svg_read_color(value, &cend_ptr, 0xffffffff); + this->lighting_color = sp_svg_read_color(value, &cend_ptr, 0xffffffff); //if a value was read if (cend_ptr) { while (g_ascii_isspace(*cend_ptr)) { ++cend_ptr; } if (strneq(cend_ptr, "icc-color(", 10)) { - if (!feSpecularLighting->icc) feSpecularLighting->icc = new SVGICCColor(); - if ( ! sp_svg_read_icc_color( cend_ptr, feSpecularLighting->icc ) ) { - delete feSpecularLighting->icc; - feSpecularLighting->icc = NULL; + if (!this->icc) this->icc = new SVGICCColor(); + if ( ! sp_svg_read_icc_color( cend_ptr, this->icc ) ) { + delete this->icc; + this->icc = NULL; } } - feSpecularLighting->lighting_color_set = TRUE; + this->lighting_color_set = TRUE; } else { //lighting_color already contains the default value - feSpecularLighting->lighting_color_set = FALSE; + this->lighting_color_set = FALSE; } - if (feSpecularLighting->renderer) { - feSpecularLighting->renderer->lighting_color = feSpecularLighting->lighting_color; + if (this->renderer) { + this->renderer->lighting_color = this->lighting_color; } - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); break; default: - if (((SPObjectClass *) sp_feSpecularLighting_parent_class)->set) - ((SPObjectClass *) sp_feSpecularLighting_parent_class)->set(object, key, value); + SPFilterPrimitive::set(key, value); break; } - } /** * Receives update notifications. */ -static void -sp_feSpecularLighting_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPFeSpecularLighting::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG)) { - object->readAttr( "surfaceScale" ); - object->readAttr( "specularConstant" ); - object->readAttr( "specularExponent" ); - object->readAttr( "kernelUnitLength" ); - object->readAttr( "lighting-color" ); + this->readAttr( "surfaceScale" ); + this->readAttr( "specularConstant" ); + this->readAttr( "specularExponent" ); + this->readAttr( "kernelUnitLength" ); + this->readAttr( "lighting-color" ); } - if (((SPObjectClass *) sp_feSpecularLighting_parent_class)->update) { - ((SPObjectClass *) sp_feSpecularLighting_parent_class)->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_feSpecularLighting_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ - SPFeSpecularLighting *fespecularlighting = SP_FESPECULARLIGHTING(object); - +Inkscape::XML::Node* SPFeSpecularLighting::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { /* TODO: Don't just clone, but create a new repr node and write all * relevant values _and children_ into it */ if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); //repr = doc->createElement("svg:feSpecularLighting"); } - if (fespecularlighting->surfaceScale_set) - sp_repr_set_css_double(repr, "surfaceScale", fespecularlighting->surfaceScale); - if (fespecularlighting->specularConstant_set) - sp_repr_set_css_double(repr, "specularConstant", fespecularlighting->specularConstant); - if (fespecularlighting->specularExponent_set) - sp_repr_set_css_double(repr, "specularExponent", fespecularlighting->specularExponent); - /*TODO kernelUnits */ - if (fespecularlighting->lighting_color_set) { + if (this->surfaceScale_set) { + sp_repr_set_css_double(repr, "surfaceScale", this->surfaceScale); + } + + if (this->specularConstant_set) { + sp_repr_set_css_double(repr, "specularConstant", this->specularConstant); + } + + if (this->specularExponent_set) { + sp_repr_set_css_double(repr, "specularExponent", this->specularExponent); + } + + /*TODO kernelUnits */ + if (this->lighting_color_set) { gchar c[64]; - sp_svg_write_color(c, sizeof(c), fespecularlighting->lighting_color); + sp_svg_write_color(c, sizeof(c), this->lighting_color); repr->setAttribute("lighting-color", c); } - if (((SPObjectClass *) sp_feSpecularLighting_parent_class)->write) { - ((SPObjectClass *) sp_feSpecularLighting_parent_class)->write(object, doc, repr, flags); - } + + SPFilterPrimitive::write(doc, repr, flags); return repr; } @@ -291,97 +252,85 @@ sp_feSpecularLighting_write(SPObject *object, Inkscape::XML::Document *doc, Inks /** * Callback for child_added event. */ -static void -sp_feSpecularLighting_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) -{ - SPFeSpecularLighting *f = SP_FESPECULARLIGHTING(object); +void SPFeSpecularLighting::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { + SPFilterPrimitive::child_added(child, ref); - if (((SPObjectClass *) sp_feSpecularLighting_parent_class)->child_added) - (* ((SPObjectClass *) sp_feSpecularLighting_parent_class)->child_added)(object, child, ref); - - sp_feSpecularLighting_children_modified(f); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + sp_feSpecularLighting_children_modified(this); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } - /** * Callback for remove_child event. */ -static void -sp_feSpecularLighting_remove_child(SPObject *object, Inkscape::XML::Node *child) -{ - SPFeSpecularLighting *f = SP_FESPECULARLIGHTING(object); - - if (((SPObjectClass *) sp_feSpecularLighting_parent_class)->remove_child) - (* ((SPObjectClass *) sp_feSpecularLighting_parent_class)->remove_child)(object, child); +void SPFeSpecularLighting::remove_child(Inkscape::XML::Node *child) { + SPFilterPrimitive::remove_child(child); - sp_feSpecularLighting_children_modified(f); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + sp_feSpecularLighting_children_modified(this); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } -static void -sp_feSpecularLighting_order_changed (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref) -{ - SPFeSpecularLighting *f = SP_FESPECULARLIGHTING(object); - if (((SPObjectClass *) (sp_feSpecularLighting_parent_class))->order_changed) - (* ((SPObjectClass *) (sp_feSpecularLighting_parent_class))->order_changed) (object, child, old_ref, new_ref); +void SPFeSpecularLighting::order_changed(Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref) { + SPFilterPrimitive::order_changed(child, old_ref, new_ref); - sp_feSpecularLighting_children_modified(f); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + sp_feSpecularLighting_children_modified(this); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } -static void sp_feSpecularLighting_children_modified(SPFeSpecularLighting *sp_specularlighting) -{ - if (sp_specularlighting->renderer) { +static void sp_feSpecularLighting_children_modified(SPFeSpecularLighting *sp_specularlighting) { + if (sp_specularlighting->renderer) { sp_specularlighting->renderer->light_type = Inkscape::Filters::NO_LIGHT; + if (SP_IS_FEDISTANTLIGHT(sp_specularlighting->children)) { sp_specularlighting->renderer->light_type = Inkscape::Filters::DISTANT_LIGHT; sp_specularlighting->renderer->light.distant = SP_FEDISTANTLIGHT(sp_specularlighting->children); } + if (SP_IS_FEPOINTLIGHT(sp_specularlighting->children)) { sp_specularlighting->renderer->light_type = Inkscape::Filters::POINT_LIGHT; sp_specularlighting->renderer->light.point = SP_FEPOINTLIGHT(sp_specularlighting->children); } + if (SP_IS_FESPOTLIGHT(sp_specularlighting->children)) { sp_specularlighting->renderer->light_type = Inkscape::Filters::SPOT_LIGHT; sp_specularlighting->renderer->light.spot = SP_FESPOTLIGHT(sp_specularlighting->children); } - } + } } -static void sp_feSpecularLighting_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - g_assert(primitive != NULL); +void SPFeSpecularLighting::build_renderer(Inkscape::Filters::Filter* filter) { + g_assert(this != NULL); g_assert(filter != NULL); - SPFeSpecularLighting *sp_specularlighting = SP_FESPECULARLIGHTING(primitive); - int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_SPECULARLIGHTING); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); Inkscape::Filters::FilterSpecularLighting *nr_specularlighting = dynamic_cast<Inkscape::Filters::FilterSpecularLighting*>(nr_primitive); g_assert(nr_specularlighting != NULL); - sp_specularlighting->renderer = nr_specularlighting; - sp_filter_primitive_renderer_common(primitive, nr_primitive); + this->renderer = nr_specularlighting; + sp_filter_primitive_renderer_common(this, nr_primitive); - nr_specularlighting->specularConstant = sp_specularlighting->specularConstant; - nr_specularlighting->specularExponent = sp_specularlighting->specularExponent; - nr_specularlighting->surfaceScale = sp_specularlighting->surfaceScale; - nr_specularlighting->lighting_color = sp_specularlighting->lighting_color; - nr_specularlighting->set_icc(sp_specularlighting->icc); + nr_specularlighting->specularConstant = this->specularConstant; + nr_specularlighting->specularExponent = this->specularExponent; + nr_specularlighting->surfaceScale = this->surfaceScale; + nr_specularlighting->lighting_color = this->lighting_color; + nr_specularlighting->set_icc(this->icc); //We assume there is at most one child nr_specularlighting->light_type = Inkscape::Filters::NO_LIGHT; - if (SP_IS_FEDISTANTLIGHT(primitive->children)) { + + if (SP_IS_FEDISTANTLIGHT(this->children)) { nr_specularlighting->light_type = Inkscape::Filters::DISTANT_LIGHT; - nr_specularlighting->light.distant = SP_FEDISTANTLIGHT(primitive->children); + nr_specularlighting->light.distant = SP_FEDISTANTLIGHT(this->children); } - if (SP_IS_FEPOINTLIGHT(primitive->children)) { + + if (SP_IS_FEPOINTLIGHT(this->children)) { nr_specularlighting->light_type = Inkscape::Filters::POINT_LIGHT; - nr_specularlighting->light.point = SP_FEPOINTLIGHT(primitive->children); + nr_specularlighting->light.point = SP_FEPOINTLIGHT(this->children); } - if (SP_IS_FESPOTLIGHT(primitive->children)) { + + if (SP_IS_FESPOTLIGHT(this->children)) { nr_specularlighting->light_type = Inkscape::Filters::SPOT_LIGHT; - nr_specularlighting->light.spot = SP_FESPOTLIGHT(primitive->children); + nr_specularlighting->light.spot = SP_FESPOTLIGHT(this->children); } //nr_offset->set_dx(sp_offset->dx); diff --git a/src/filters/specularlighting.h b/src/filters/specularlighting.h index 4b31eb4c4..1de32ec58 100644 --- a/src/filters/specularlighting.h +++ b/src/filters/specularlighting.h @@ -17,11 +17,8 @@ #include "sp-filter-primitive.h" #include "number-opt-number.h" -#define SP_TYPE_FESPECULARLIGHTING (sp_feSpecularLighting_get_type()) -#define SP_FESPECULARLIGHTING(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FESPECULARLIGHTING, SPFeSpecularLighting)) -#define SP_FESPECULARLIGHTING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FESPECULARLIGHTING, SPFeSpecularLightingClass)) -#define SP_IS_FESPECULARLIGHTING(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FESPECULARLIGHTING)) -#define SP_IS_FESPECULARLIGHTING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FESPECULARLIGHTING)) +#define SP_FESPECULARLIGHTING(obj) (dynamic_cast<SPFeSpecularLighting*>((SPObject*)obj)) +#define SP_IS_FESPECULARLIGHTING(obj) (dynamic_cast<const SPFeSpecularLighting*>((SPObject*)obj) != NULL) struct SVGICCColor; @@ -31,7 +28,11 @@ class FilterSpecularLighting; } } -struct SPFeSpecularLighting : public SPFilterPrimitive { +class SPFeSpecularLighting : public SPFilterPrimitive { +public: + SPFeSpecularLighting(); + virtual ~SPFeSpecularLighting(); + gfloat surfaceScale; guint surfaceScale_set : 1; gfloat specularConstant; @@ -44,14 +45,24 @@ struct SPFeSpecularLighting : public SPFilterPrimitive { SVGICCColor *icc; Inkscape::Filters::FilterSpecularLighting *renderer; -}; -struct SPFeSpecularLightingClass { - SPFilterPrimitiveClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node* child); -GType sp_feSpecularLighting_get_type(); + virtual void order_changed(Inkscape::XML::Node* child, Inkscape::XML::Node* old_repr, Inkscape::XML::Node* new_repr); + virtual void set(unsigned int key, const gchar* value); + + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); +}; #endif /* !SP_FESPECULARLIGHTING_H_SEEN */ diff --git a/src/filters/spotlight.cpp b/src/filters/spotlight.cpp index 181e39990..c0344067c 100644 --- a/src/filters/spotlight.cpp +++ b/src/filters/spotlight.cpp @@ -29,86 +29,57 @@ #define SP_MACROS_SILENT #include "macros.h" -/* FeSpotLight class */ -static void sp_fespotlight_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_fespotlight_release(SPObject *object); -static void sp_fespotlight_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_fespotlight_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_fespotlight_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); +#include "sp-factory.h" -G_DEFINE_TYPE(SPFeSpotLight, sp_fespotlight, SP_TYPE_OBJECT); +namespace { + SPObject* createSpotLight() { + return new SPFeSpotLight(); + } -static void -sp_fespotlight_class_init(SPFeSpotLightClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - - sp_object_class->build = sp_fespotlight_build; - sp_object_class->release = sp_fespotlight_release; - sp_object_class->write = sp_fespotlight_write; - sp_object_class->set = sp_fespotlight_set; - sp_object_class->update = sp_fespotlight_update; + bool spotLightRegistered = SPFactory::instance().registerObject("svg:feSpotLight", createSpotLight); } -static void -sp_fespotlight_init(SPFeSpotLight *fespotlight) +SPFeSpotLight::SPFeSpotLight() + : SPObject(), x(0), x_set(FALSE), y(0), y_set(FALSE), z(0), z_set(FALSE), pointsAtX(0), pointsAtX_set(FALSE), + pointsAtY(0), pointsAtY_set(FALSE), pointsAtZ(0), pointsAtZ_set(FALSE), + specularExponent(1), specularExponent_set(FALSE), limitingConeAngle(90), + limitingConeAngle_set(FALSE) { - fespotlight->x = 0; - fespotlight->y = 0; - fespotlight->z = 0; - fespotlight->pointsAtX = 0; - fespotlight->pointsAtY = 0; - fespotlight->pointsAtZ = 0; - fespotlight->specularExponent = 1; - fespotlight->limitingConeAngle = 90; +} - fespotlight->x_set = FALSE; - fespotlight->y_set = FALSE; - fespotlight->z_set = FALSE; - fespotlight->pointsAtX_set = FALSE; - fespotlight->pointsAtY_set = FALSE; - fespotlight->pointsAtZ_set = FALSE; - fespotlight->specularExponent_set = FALSE; - fespotlight->limitingConeAngle_set = FALSE; +SPFeSpotLight::~SPFeSpotLight() { } + /** * Reads the Inkscape::XML::Node, and initializes SPPointLight variables. For this to get called, * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_fespotlight_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_fespotlight_parent_class)->build) { - ((SPObjectClass *) sp_fespotlight_parent_class)->build(object, document, repr); - } +void SPFeSpotLight::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPObject::build(document, repr); //Read values of key attributes from XML nodes into object. - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "z" ); - object->readAttr( "pointsAtX" ); - object->readAttr( "pointsAtY" ); - object->readAttr( "pointsAtZ" ); - object->readAttr( "specularExponent" ); - object->readAttr( "limitingConeAngle" ); + this->readAttr( "x" ); + this->readAttr( "y" ); + this->readAttr( "z" ); + this->readAttr( "pointsAtX" ); + this->readAttr( "pointsAtY" ); + this->readAttr( "pointsAtZ" ); + this->readAttr( "specularExponent" ); + this->readAttr( "limitingConeAngle" ); //is this necessary? - document->addResource("fespotlight", object); + document->addResource("fespotlight", this); } /** * Drops any allocated memory. */ -static void -sp_fespotlight_release(SPObject *object) -{ - //SPFeSpotLight *fespotlight = SP_FESPOTLIGHT(object); - - if ( object->document ) { +void SPFeSpotLight::release() { + if ( this->document ) { // Unregister ourselves - object->document->removeResource("fespotlight", object); + this->document->removeResource("fespotlight", this); } //TODO: release resources here @@ -117,154 +88,189 @@ sp_fespotlight_release(SPObject *object) /** * Sets a specific value in the SPFeSpotLight. */ -static void -sp_fespotlight_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeSpotLight *fespotlight = SP_FESPOTLIGHT(object); +void SPFeSpotLight::set(unsigned int key, gchar const *value) { gchar *end_ptr; switch (key) { case SP_ATTR_X: end_ptr = NULL; + if (value) { - fespotlight->x = g_ascii_strtod(value, &end_ptr); - if (end_ptr) - fespotlight->x_set = TRUE; + this->x = g_ascii_strtod(value, &end_ptr); + + if (end_ptr) { + this->x_set = TRUE; + } } + if(!value || !end_ptr) { - fespotlight->x = 0; - fespotlight->x_set = FALSE; + this->x = 0; + this->x_set = FALSE; } - if (object->parent && - (SP_IS_FEDIFFUSELIGHTING(object->parent) || - SP_IS_FESPECULARLIGHTING(object->parent))) { - object->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->parent && + (SP_IS_FEDIFFUSELIGHTING(this->parent) || + SP_IS_FESPECULARLIGHTING(this->parent))) { + this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_Y: end_ptr = NULL; + if (value) { - fespotlight->y = g_ascii_strtod(value, &end_ptr); - if (end_ptr) - fespotlight->y_set = TRUE; + this->y = g_ascii_strtod(value, &end_ptr); + + if (end_ptr) { + this->y_set = TRUE; + } } + if(!value || !end_ptr) { - fespotlight->y = 0; - fespotlight->y_set = FALSE; + this->y = 0; + this->y_set = FALSE; } - if (object->parent && - (SP_IS_FEDIFFUSELIGHTING(object->parent) || - SP_IS_FESPECULARLIGHTING(object->parent))) { - object->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->parent && + (SP_IS_FEDIFFUSELIGHTING(this->parent) || + SP_IS_FESPECULARLIGHTING(this->parent))) { + this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_Z: end_ptr = NULL; + if (value) { - fespotlight->z = g_ascii_strtod(value, &end_ptr); - if (end_ptr) - fespotlight->z_set = TRUE; + this->z = g_ascii_strtod(value, &end_ptr); + + if (end_ptr) { + this->z_set = TRUE; + } } + if(!value || !end_ptr) { - fespotlight->z = 0; - fespotlight->z_set = FALSE; + this->z = 0; + this->z_set = FALSE; } - if (object->parent && - (SP_IS_FEDIFFUSELIGHTING(object->parent) || - SP_IS_FESPECULARLIGHTING(object->parent))) { - object->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->parent && + (SP_IS_FEDIFFUSELIGHTING(this->parent) || + SP_IS_FESPECULARLIGHTING(this->parent))) { + this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_POINTSATX: end_ptr = NULL; + if (value) { - fespotlight->pointsAtX = g_ascii_strtod(value, &end_ptr); - if (end_ptr) - fespotlight->pointsAtX_set = TRUE; + this->pointsAtX = g_ascii_strtod(value, &end_ptr); + + if (end_ptr) { + this->pointsAtX_set = TRUE; + } } + if(!value || !end_ptr) { - fespotlight->pointsAtX = 0; - fespotlight->pointsAtX_set = FALSE; + this->pointsAtX = 0; + this->pointsAtX_set = FALSE; } - if (object->parent && - (SP_IS_FEDIFFUSELIGHTING(object->parent) || - SP_IS_FESPECULARLIGHTING(object->parent))) { - object->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->parent && + (SP_IS_FEDIFFUSELIGHTING(this->parent) || + SP_IS_FESPECULARLIGHTING(this->parent))) { + this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_POINTSATY: end_ptr = NULL; + if (value) { - fespotlight->pointsAtY = g_ascii_strtod(value, &end_ptr); - if (end_ptr) - fespotlight->pointsAtY_set = TRUE; + this->pointsAtY = g_ascii_strtod(value, &end_ptr); + + if (end_ptr) { + this->pointsAtY_set = TRUE; + } } + if(!value || !end_ptr) { - fespotlight->pointsAtY = 0; - fespotlight->pointsAtY_set = FALSE; + this->pointsAtY = 0; + this->pointsAtY_set = FALSE; } - if (object->parent && - (SP_IS_FEDIFFUSELIGHTING(object->parent) || - SP_IS_FESPECULARLIGHTING(object->parent))) { - object->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->parent && + (SP_IS_FEDIFFUSELIGHTING(this->parent) || + SP_IS_FESPECULARLIGHTING(this->parent))) { + this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_POINTSATZ: end_ptr = NULL; + if (value) { - fespotlight->pointsAtZ = g_ascii_strtod(value, &end_ptr); - if (end_ptr) - fespotlight->pointsAtZ_set = TRUE; + this->pointsAtZ = g_ascii_strtod(value, &end_ptr); + + if (end_ptr) { + this->pointsAtZ_set = TRUE; + } } + if(!value || !end_ptr) { - fespotlight->pointsAtZ = 0; - fespotlight->pointsAtZ_set = FALSE; + this->pointsAtZ = 0; + this->pointsAtZ_set = FALSE; } - if (object->parent && - (SP_IS_FEDIFFUSELIGHTING(object->parent) || - SP_IS_FESPECULARLIGHTING(object->parent))) { - object->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->parent && + (SP_IS_FEDIFFUSELIGHTING(this->parent) || + SP_IS_FESPECULARLIGHTING(this->parent))) { + this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_SPECULAREXPONENT: end_ptr = NULL; + if (value) { - fespotlight->specularExponent = g_ascii_strtod(value, &end_ptr); - if (end_ptr) - fespotlight->specularExponent_set = TRUE; + this->specularExponent = g_ascii_strtod(value, &end_ptr); + + if (end_ptr) { + this->specularExponent_set = TRUE; + } } + if(!value || !end_ptr) { - fespotlight->specularExponent = 1; - fespotlight->specularExponent_set = FALSE; + this->specularExponent = 1; + this->specularExponent_set = FALSE; } - if (object->parent && - (SP_IS_FEDIFFUSELIGHTING(object->parent) || - SP_IS_FESPECULARLIGHTING(object->parent))) { - object->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->parent && + (SP_IS_FEDIFFUSELIGHTING(this->parent) || + SP_IS_FESPECULARLIGHTING(this->parent))) { + this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_LIMITINGCONEANGLE: end_ptr = NULL; + if (value) { - fespotlight->limitingConeAngle = g_ascii_strtod(value, &end_ptr); - if (end_ptr) - fespotlight->limitingConeAngle_set = TRUE; + this->limitingConeAngle = g_ascii_strtod(value, &end_ptr); + + if (end_ptr) { + this->limitingConeAngle_set = TRUE; + } } + if(!value || !end_ptr) { - fespotlight->limitingConeAngle = 90; - fespotlight->limitingConeAngle_set = FALSE; + this->limitingConeAngle = 90; + this->limitingConeAngle_set = FALSE; } - if (object->parent && - (SP_IS_FEDIFFUSELIGHTING(object->parent) || - SP_IS_FESPECULARLIGHTING(object->parent))) { - object->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->parent && + (SP_IS_FEDIFFUSELIGHTING(this->parent) || + SP_IS_FESPECULARLIGHTING(this->parent))) { + this->parent->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; default: // See if any parents need this value. - if (((SPObjectClass *) sp_fespotlight_parent_class)->set) { - ((SPObjectClass *) sp_fespotlight_parent_class)->set(object, key, value); - } + SPObject::set(key, value); break; } } @@ -272,61 +278,48 @@ sp_fespotlight_set(SPObject *object, unsigned int key, gchar const *value) /** * * Receives update notifications. * */ -static void -sp_fespotlight_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPFeSpotLight *feSpotLight = SP_FESPOTLIGHT(object); - (void)feSpotLight; - +void SPFeSpotLight::update(SPCtx *ctx, guint flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { /* do something to trigger redisplay, updates? */ - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "z" ); - object->readAttr( "pointsAtX" ); - object->readAttr( "pointsAtY" ); - object->readAttr( "pointsAtZ" ); - object->readAttr( "specularExponent" ); - object->readAttr( "limitingConeAngle" ); + this->readAttr( "x" ); + this->readAttr( "y" ); + this->readAttr( "z" ); + this->readAttr( "pointsAtX" ); + this->readAttr( "pointsAtY" ); + this->readAttr( "pointsAtZ" ); + this->readAttr( "specularExponent" ); + this->readAttr( "limitingConeAngle" ); } - if (((SPObjectClass *) sp_fespotlight_parent_class)->update) { - ((SPObjectClass *) sp_fespotlight_parent_class)->update(object, ctx, flags); - } + SPObject::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_fespotlight_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ - SPFeSpotLight *fespotlight = SP_FESPOTLIGHT(object); - +Inkscape::XML::Node* SPFeSpotLight::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - if (fespotlight->x_set) - sp_repr_set_css_double(repr, "x", fespotlight->x); - if (fespotlight->y_set) - sp_repr_set_css_double(repr, "y", fespotlight->y); - if (fespotlight->z_set) - sp_repr_set_css_double(repr, "z", fespotlight->z); - if (fespotlight->pointsAtX_set) - sp_repr_set_css_double(repr, "pointsAtX", fespotlight->pointsAtX); - if (fespotlight->pointsAtY_set) - sp_repr_set_css_double(repr, "pointsAtY", fespotlight->pointsAtY); - if (fespotlight->pointsAtZ_set) - sp_repr_set_css_double(repr, "pointsAtZ", fespotlight->pointsAtZ); - if (fespotlight->specularExponent_set) - sp_repr_set_css_double(repr, "specularExponent", fespotlight->specularExponent); - if (fespotlight->limitingConeAngle_set) - sp_repr_set_css_double(repr, "limitingConeAngle", fespotlight->limitingConeAngle); + if (this->x_set) + sp_repr_set_css_double(repr, "x", this->x); + if (this->y_set) + sp_repr_set_css_double(repr, "y", this->y); + if (this->z_set) + sp_repr_set_css_double(repr, "z", this->z); + if (this->pointsAtX_set) + sp_repr_set_css_double(repr, "pointsAtX", this->pointsAtX); + if (this->pointsAtY_set) + sp_repr_set_css_double(repr, "pointsAtY", this->pointsAtY); + if (this->pointsAtZ_set) + sp_repr_set_css_double(repr, "pointsAtZ", this->pointsAtZ); + if (this->specularExponent_set) + sp_repr_set_css_double(repr, "specularExponent", this->specularExponent); + if (this->limitingConeAngle_set) + sp_repr_set_css_double(repr, "limitingConeAngle", this->limitingConeAngle); - if (((SPObjectClass *) sp_fespotlight_parent_class)->write) { - ((SPObjectClass *) sp_fespotlight_parent_class)->write(object, doc, repr, flags); - } + SPObject::write(doc, repr, flags); return repr; } diff --git a/src/filters/spotlight.h b/src/filters/spotlight.h index 1750ca95b..8caf12858 100644 --- a/src/filters/spotlight.h +++ b/src/filters/spotlight.h @@ -17,13 +17,13 @@ #include "sp-object.h" -#define SP_TYPE_FESPOTLIGHT (sp_fespotlight_get_type()) -#define SP_FESPOTLIGHT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FESPOTLIGHT, SPFeSpotLight)) -#define SP_FESPOTLIGHT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FESPOTLIGHT, SPFeSpotLightClass)) -#define SP_IS_FESPOTLIGHT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FESPOTLIGHT)) -#define SP_IS_FESPOTLIGHT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FESPOTLIGHT)) +#define SP_FESPOTLIGHT(obj) (dynamic_cast<SPFeSpotLight*>((SPObject*)obj)) +#define SP_IS_FESPOTLIGHT(obj) (dynamic_cast<const SPFeSpotLight*>((SPObject*)obj) != NULL) -struct SPFeSpotLight : public SPObject { +class SPFeSpotLight : public SPObject { +public: + SPFeSpotLight(); + virtual ~SPFeSpotLight(); /** x coordinate of the light source */ gfloat x; @@ -50,14 +50,18 @@ struct SPFeSpotLight : public SPObject { gfloat limitingConeAngle; guint limitingConeAngle_set : 1; //other fields -}; -struct SPFeSpotLightClass { - SPObjectClass parent_class; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void set(unsigned int key, const gchar* value); + + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); }; -GType -sp_fespotlight_get_type(); #endif /* !SP_FESPOTLIGHT_H_SEEN */ /* diff --git a/src/filters/tile.cpp b/src/filters/tile.cpp index d2725f50c..19e96f47d 100644 --- a/src/filters/tile.cpp +++ b/src/filters/tile.cpp @@ -22,33 +22,20 @@ #include "display/nr-filter.h" #include "display/nr-filter-tile.h" -/* FeTile base class */ -static void sp_feTile_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feTile_release(SPObject *object); -static void sp_feTile_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feTile_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_feTile_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_feTile_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter); - -G_DEFINE_TYPE(SPFeTile, sp_feTile, SP_TYPE_FILTER_PRIMITIVE); - -static void -sp_feTile_class_init(SPFeTileClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass; - - sp_object_class->build = sp_feTile_build; - sp_object_class->release = sp_feTile_release; - sp_object_class->write = sp_feTile_write; - sp_object_class->set = sp_feTile_set; - sp_object_class->update = sp_feTile_update; - sp_primitive_class->build_renderer = sp_feTile_build_renderer; +#include "sp-factory.h" + +namespace { + SPObject* createTile() { + return new SPFeTile(); + } + + bool tileRegistered = SPFactory::instance().registerObject("svg:feTile", createTile); +} + +SPFeTile::SPFeTile() : SPFilterPrimitive() { } -static void -sp_feTile_init(SPFeTile */*feTile*/) -{ +SPFeTile::~SPFeTile() { } /** @@ -56,51 +43,33 @@ sp_feTile_init(SPFeTile */*feTile*/) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_feTile_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_feTile_parent_class)->build) { - ((SPObjectClass *) sp_feTile_parent_class)->build(object, document, repr); - } - - /*LOAD ATTRIBUTES FROM REPR HERE*/ +void SPFeTile::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive::build(document, repr); } /** * Drops any allocated memory. */ -static void -sp_feTile_release(SPObject *object) -{ - if (((SPObjectClass *) sp_feTile_parent_class)->release) - ((SPObjectClass *) sp_feTile_parent_class)->release(object); +void SPFeTile::release() { + SPFilterPrimitive::release(); } /** * Sets a specific value in the SPFeTile. */ -static void -sp_feTile_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeTile *feTile = SP_FETILE(object); - (void)feTile; - +void SPFeTile::set(unsigned int key, gchar const *value) { switch(key) { /*DEAL WITH SETTING ATTRIBUTES HERE*/ default: - if (((SPObjectClass *) sp_feTile_parent_class)->set) - ((SPObjectClass *) sp_feTile_parent_class)->set(object, key, value); + SPFilterPrimitive::set(key, value); break; } - } /** * Receives update notifications. */ -static void -sp_feTile_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPFeTile::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { @@ -108,43 +77,34 @@ sp_feTile_update(SPObject *object, SPCtx *ctx, guint flags) } - if (((SPObjectClass *) sp_feTile_parent_class)->update) { - ((SPObjectClass *) sp_feTile_parent_class)->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_feTile_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPFeTile::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - if (((SPObjectClass *) sp_feTile_parent_class)->write) { - ((SPObjectClass *) sp_feTile_parent_class)->write(object, doc, repr, flags); - } + SPFilterPrimitive::write(doc, repr, flags); return repr; } -static void sp_feTile_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - g_assert(primitive != NULL); +void SPFeTile::build_renderer(Inkscape::Filters::Filter* filter) { + g_assert(this != NULL); g_assert(filter != NULL); - SPFeTile *sp_tile = SP_FETILE(primitive); - (void)sp_tile; - int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_TILE); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); Inkscape::Filters::FilterTile *nr_tile = dynamic_cast<Inkscape::Filters::FilterTile*>(nr_primitive); g_assert(nr_tile != NULL); - sp_filter_primitive_renderer_common(primitive, nr_primitive); + sp_filter_primitive_renderer_common(this, nr_primitive); } /* diff --git a/src/filters/tile.h b/src/filters/tile.h index 48a552fc8..cc1a006dd 100644 --- a/src/filters/tile.h +++ b/src/filters/tile.h @@ -14,22 +14,27 @@ #include "sp-filter-primitive.h" -#define SP_TYPE_FETILE (sp_feTile_get_type()) -#define SP_FETILE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FETILE, SPFeTile)) -#define SP_FETILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FETILE, SPFeTileClass)) -#define SP_IS_FETILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FETILE)) -#define SP_IS_FETILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FETILE)) +#define SP_FETILE(obj) (dynamic_cast<SPFeTile*>((SPObject*)obj)) +#define SP_IS_FETILE(obj) (dynamic_cast<const SPFeTile*>((SPObject*)obj) != NULL) /* FeTile base class */ -struct SPFeTile : public SPFilterPrimitive { - -}; +class SPFeTile : public SPFilterPrimitive { +public: + SPFeTile(); + virtual ~SPFeTile(); -struct SPFeTileClass { - SPFilterPrimitiveClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void set(unsigned int key, const gchar* value); -GType sp_feTile_get_type(); + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); +}; #endif /* !SP_FETILE_H_SEEN */ diff --git a/src/filters/turbulence.cpp b/src/filters/turbulence.cpp index c4d4ca4ae..d33667a8c 100644 --- a/src/filters/turbulence.cpp +++ b/src/filters/turbulence.cpp @@ -28,35 +28,26 @@ #include "display/nr-filter.h" #include "display/nr-filter-turbulence.h" -/* FeTurbulence base class */ -static void sp_feTurbulence_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_feTurbulence_release(SPObject *object); -static void sp_feTurbulence_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_feTurbulence_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_feTurbulence_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_feTurbulence_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter); - -G_DEFINE_TYPE(SPFeTurbulence, sp_feTurbulence, SP_TYPE_FILTER_PRIMITIVE); - -static void -sp_feTurbulence_class_init(SPFeTurbulenceClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - SPFilterPrimitiveClass * sp_primitive_class = (SPFilterPrimitiveClass *)klass; - - sp_object_class->build = sp_feTurbulence_build; - sp_object_class->release = sp_feTurbulence_release; - sp_object_class->write = sp_feTurbulence_write; - sp_object_class->set = sp_feTurbulence_set; - sp_object_class->update = sp_feTurbulence_update; - - sp_primitive_class->build_renderer = sp_feTurbulence_build_renderer; +#include "sp-factory.h" + +namespace { + SPObject* createTurbulence() { + return new SPFeTurbulence(); + } + + bool turbulenceRegistered = SPFactory::instance().registerObject("svg:feTurbulence", createTurbulence); +} + +SPFeTurbulence::SPFeTurbulence() : SPFilterPrimitive() { + this->stitchTiles = 0; + this->seed = 0; + this->numOctaves = 0; + this->type = Inkscape::Filters::TURBULENCE_FRACTALNOISE; + + this->updated=false; } -static void -sp_feTurbulence_init(SPFeTurbulence *feTurbulence) -{ - feTurbulence->updated=false; +SPFeTurbulence::~SPFeTurbulence() { } /** @@ -64,66 +55,70 @@ sp_feTurbulence_init(SPFeTurbulence *feTurbulence) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_feTurbulence_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_feTurbulence_parent_class)->build) { - ((SPObjectClass *) sp_feTurbulence_parent_class)->build(object, document, repr); - } - - /*LOAD ATTRIBUTES FROM REPR HERE*/ - object->readAttr( "baseFrequency" ); - object->readAttr( "numOctaves" ); - object->readAttr( "seed" ); - object->readAttr( "stitchTiles" ); - object->readAttr( "type" ); +void SPFeTurbulence::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive::build(document, repr); + + /*LOAD ATTRIBUTES FROM REPR HERE*/ + this->readAttr( "baseFrequency" ); + this->readAttr( "numOctaves" ); + this->readAttr( "seed" ); + this->readAttr( "stitchTiles" ); + this->readAttr( "type" ); } /** * Drops any allocated memory. */ -static void -sp_feTurbulence_release(SPObject *object) -{ - if (((SPObjectClass *) sp_feTurbulence_parent_class)->release) - ((SPObjectClass *) sp_feTurbulence_parent_class)->release(object); +void SPFeTurbulence::release() { + SPFilterPrimitive::release(); } static bool sp_feTurbulence_read_stitchTiles(gchar const *value){ - if (!value) return false; // 'noStitch' is default + if (!value) { + return false; // 'noStitch' is default + } + switch(value[0]){ case 's': - if (strncmp(value, "stitch", 6) == 0) return true; + if (strncmp(value, "stitch", 6) == 0) { + return true; + } break; case 'n': - if (strncmp(value, "noStitch", 8) == 0) return false; + if (strncmp(value, "noStitch", 8) == 0) { + return false; + } break; } + return false; // 'noStitch' is default } static Inkscape::Filters::FilterTurbulenceType sp_feTurbulence_read_type(gchar const *value){ - if (!value) return Inkscape::Filters::TURBULENCE_TURBULENCE; // 'turbulence' is default + if (!value) { + return Inkscape::Filters::TURBULENCE_TURBULENCE; // 'turbulence' is default + } + switch(value[0]){ case 'f': - if (strncmp(value, "fractalNoise", 12) == 0) return Inkscape::Filters::TURBULENCE_FRACTALNOISE; + if (strncmp(value, "fractalNoise", 12) == 0) { + return Inkscape::Filters::TURBULENCE_FRACTALNOISE; + } break; case 't': - if (strncmp(value, "turbulence", 10) == 0) return Inkscape::Filters::TURBULENCE_TURBULENCE; + if (strncmp(value, "turbulence", 10) == 0) { + return Inkscape::Filters::TURBULENCE_TURBULENCE; + } break; } + return Inkscape::Filters::TURBULENCE_TURBULENCE; // 'turbulence' is default } /** * Sets a specific value in the SPFeTurbulence. */ -static void -sp_feTurbulence_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFeTurbulence *feTurbulence = SP_FETURBULENCE(object); - (void)feTurbulence; - +void SPFeTurbulence::set(unsigned int key, gchar const *value) { int read_int; double read_num; bool read_bool; @@ -131,61 +126,66 @@ sp_feTurbulence_set(SPObject *object, unsigned int key, gchar const *value) switch(key) { /*DEAL WITH SETTING ATTRIBUTES HERE*/ - case SP_ATTR_BASEFREQUENCY: - feTurbulence->baseFrequency.set(value); - //From SVG spec: If two <number>s are provided, the first number represents a base frequency in the X direction and the second value represents a base frequency in the Y direction. If one number is provided, then that value is used for both X and Y. - if (feTurbulence->baseFrequency.optNumIsSet() == false) - feTurbulence->baseFrequency.setOptNumber(feTurbulence->baseFrequency.getNumber()); - feTurbulence->updated = false; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->baseFrequency.set(value); + + // From SVG spec: If two <number>s are provided, the first number represents + // a base frequency in the X direction and the second value represents a base + // frequency in the Y direction. If one number is provided, then that value is + // used for both X and Y. + if (this->baseFrequency.optNumIsSet() == false) { + this->baseFrequency.setOptNumber(this->baseFrequency.getNumber()); + } + + this->updated = false; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_NUMOCTAVES: read_int = value ? (int)floor(helperfns_read_number(value)) : 1; - if (read_int != feTurbulence->numOctaves){ - feTurbulence->numOctaves = read_int; - feTurbulence->updated = false; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_int != this->numOctaves){ + this->numOctaves = read_int; + this->updated = false; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_SEED: read_num = value ? helperfns_read_number(value) : 0; - if (read_num != feTurbulence->seed){ - feTurbulence->seed = read_num; - feTurbulence->updated = false; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_num != this->seed){ + this->seed = read_num; + this->updated = false; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_STITCHTILES: read_bool = sp_feTurbulence_read_stitchTiles(value); - if (read_bool != feTurbulence->stitchTiles){ - feTurbulence->stitchTiles = read_bool; - feTurbulence->updated = false; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_bool != this->stitchTiles){ + this->stitchTiles = read_bool; + this->updated = false; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case SP_ATTR_TYPE: read_type = sp_feTurbulence_read_type(value); - if (read_type != feTurbulence->type){ - feTurbulence->type = read_type; - feTurbulence->updated = false; - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (read_type != this->type){ + this->type = read_type; + this->updated = false; + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; default: - if (((SPObjectClass *) sp_feTurbulence_parent_class)->set) - ((SPObjectClass *) sp_feTurbulence_parent_class)->set(object, key, value); + SPFilterPrimitive::set(key, value); break; } - } /** * Receives update notifications. */ -static void -sp_feTurbulence_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPFeTurbulence::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { @@ -193,26 +193,20 @@ sp_feTurbulence_update(SPObject *object, SPCtx *ctx, guint flags) } - if (((SPObjectClass *) sp_feTurbulence_parent_class)->update) { - ((SPObjectClass *) sp_feTurbulence_parent_class)->update(object, ctx, flags); - } + SPFilterPrimitive::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_feTurbulence_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPFeTurbulence::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - if (((SPObjectClass *) sp_feTurbulence_parent_class)->write) { - ((SPObjectClass *) sp_feTurbulence_parent_class)->write(object, doc, repr, flags); - } + SPFilterPrimitive::write(doc, repr, flags); /* turbulence doesn't take input */ repr->setAttribute("in", 0); @@ -220,26 +214,24 @@ sp_feTurbulence_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape:: return repr; } -static void sp_feTurbulence_build_renderer(SPFilterPrimitive *primitive, Inkscape::Filters::Filter *filter) { - g_assert(primitive != NULL); +void SPFeTurbulence::build_renderer(Inkscape::Filters::Filter* filter) { + g_assert(this != NULL); g_assert(filter != NULL); - SPFeTurbulence *sp_turbulence = SP_FETURBULENCE(primitive); - int primitive_n = filter->add_primitive(Inkscape::Filters::NR_FILTER_TURBULENCE); Inkscape::Filters::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); Inkscape::Filters::FilterTurbulence *nr_turbulence = dynamic_cast<Inkscape::Filters::FilterTurbulence*>(nr_primitive); g_assert(nr_turbulence != NULL); - sp_filter_primitive_renderer_common(primitive, nr_primitive); + sp_filter_primitive_renderer_common(this, nr_primitive); - nr_turbulence->set_baseFrequency(0, sp_turbulence->baseFrequency.getNumber()); - nr_turbulence->set_baseFrequency(1, sp_turbulence->baseFrequency.getOptNumber()); - nr_turbulence->set_numOctaves(sp_turbulence->numOctaves); - nr_turbulence->set_seed(sp_turbulence->seed); - nr_turbulence->set_stitchTiles(sp_turbulence->stitchTiles); - nr_turbulence->set_type(sp_turbulence->type); - nr_turbulence->set_updated(sp_turbulence->updated); + nr_turbulence->set_baseFrequency(0, this->baseFrequency.getNumber()); + nr_turbulence->set_baseFrequency(1, this->baseFrequency.getOptNumber()); + nr_turbulence->set_numOctaves(this->numOctaves); + nr_turbulence->set_seed(this->seed); + nr_turbulence->set_stitchTiles(this->stitchTiles); + nr_turbulence->set_type(this->type); + nr_turbulence->set_updated(this->updated); } /* diff --git a/src/filters/turbulence.h b/src/filters/turbulence.h index bad8315c1..89e6d4a19 100644 --- a/src/filters/turbulence.h +++ b/src/filters/turbulence.h @@ -17,15 +17,16 @@ #include "number-opt-number.h" #include "display/nr-filter-turbulence.h" -#define SP_TYPE_FETURBULENCE (sp_feTurbulence_get_type()) -#define SP_FETURBULENCE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FETURBULENCE, SPFeTurbulence)) -#define SP_FETURBULENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FETURBULENCE, SPFeTurbulenceClass)) -#define SP_IS_FETURBULENCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FETURBULENCE)) -#define SP_IS_FETURBULENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FETURBULENCE)) +#define SP_FETURBULENCE(obj) (dynamic_cast<SPFeTurbulence*>((SPObject*)obj)) +#define SP_IS_FETURBULENCE(obj) (dynamic_cast<const SPFeTurbulence*>((SPObject*)obj) != NULL) /* FeTurbulence base class */ -struct SPFeTurbulence : public SPFilterPrimitive { +class SPFeTurbulence : public SPFilterPrimitive { +public: + SPFeTurbulence(); + virtual ~SPFeTurbulence(); + /** TURBULENCE ATTRIBUTES HERE */ NumberOptNumber baseFrequency; int numOctaves; @@ -34,14 +35,19 @@ struct SPFeTurbulence : public SPFilterPrimitive { Inkscape::Filters::FilterTurbulenceType type; SVGLength x, y, height, width; bool updated; -}; -struct SPFeTurbulenceClass { - SPFilterPrimitiveClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); -GType sp_feTurbulence_get_type(); + virtual void set(unsigned int key, const gchar* value); + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual void build_renderer(Inkscape::Filters::Filter* filter); +}; #endif /* !SP_FETURBULENCE_H_SEEN */ diff --git a/src/flood-context.cpp b/src/flood-context.cpp index a719f1202..1f2a240ca 100644 --- a/src/flood-context.cpp +++ b/src/flood-context.cpp @@ -74,112 +74,79 @@ using Inkscape::Display::ExtractARGB32; using Inkscape::Display::ExtractRGB32; using Inkscape::Display::AssembleARGB32; -static void sp_flood_context_dispose(GObject *object); +#include "tool-factory.h" -static void sp_flood_context_setup(SPEventContext *ec); +namespace { + SPEventContext* createPaintbucketContext() { + return new SPFloodContext(); + } -static gint sp_flood_context_root_handler(SPEventContext *event_context, GdkEvent *event); -static gint sp_flood_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event); - -static void sp_flood_finish(SPFloodContext *rc); - -G_DEFINE_TYPE(SPFloodContext, sp_flood_context, SP_TYPE_EVENT_CONTEXT); - -static void sp_flood_context_class_init(SPFloodContextClass *klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - SPEventContextClass *event_context_class = (SPEventContextClass *) klass; - - object_class->dispose = sp_flood_context_dispose; - - event_context_class->setup = sp_flood_context_setup; - event_context_class->root_handler = sp_flood_context_root_handler; - event_context_class->item_handler = sp_flood_context_item_handler; + bool paintbucketContextRegistered = ToolFactory::instance().registerObject("/tools/paintbucket", createPaintbucketContext); } -static void sp_flood_context_init(SPFloodContext *flood_context) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(flood_context); +const std::string& SPFloodContext::getPrefsPath() { + return SPFloodContext::prefsPath; +} - event_context->cursor_shape = cursor_paintbucket_xpm; - event_context->hot_x = 11; - event_context->hot_y = 30; - event_context->xp = 0; - event_context->yp = 0; - event_context->tolerance = 4; - event_context->within_tolerance = false; - event_context->item_to_select = NULL; +const std::string SPFloodContext::prefsPath = "/tools/paintbucket"; - flood_context->item = NULL; +SPFloodContext::SPFloodContext() : SPEventContext() { + this->cursor_shape = cursor_paintbucket_xpm; + this->hot_x = 11; + this->hot_y = 30; + this->xp = 0; + this->yp = 0; + this->tolerance = 4; + this->within_tolerance = false; + this->item_to_select = NULL; - new (&flood_context->sel_changed_connection) sigc::connection(); + this->item = NULL; } -static void sp_flood_context_dispose(GObject *object) -{ - SPFloodContext *rc = SP_FLOOD_CONTEXT(object); - SPEventContext *ec = SP_EVENT_CONTEXT(object); +SPFloodContext::~SPFloodContext() { + this->sel_changed_connection.disconnect(); - rc->sel_changed_connection.disconnect(); - rc->sel_changed_connection.~connection(); - - delete ec->shape_editor; - ec->shape_editor = NULL; + delete this->shape_editor; + this->shape_editor = NULL; /* fixme: This is necessary because we do not grab */ - if (rc->item) { - sp_flood_finish(rc); + if (this->item) { + this->finishItem(); } - - if (rc->_message_context) { - delete rc->_message_context; - } - - G_OBJECT_CLASS(sp_flood_context_parent_class)->dispose(object); } /** * Callback that processes the "changed" signal on the selection; * destroys old and creates new knotholder. */ -static void sp_flood_context_selection_changed(Inkscape::Selection *selection, gpointer data) -{ - SPFloodContext *rc = SP_FLOOD_CONTEXT(data); - SPEventContext *ec = SP_EVENT_CONTEXT(rc); - - ec->shape_editor->unset_item(SH_KNOTHOLDER); - SPItem *item = selection->singleItem(); - ec->shape_editor->set_item(item, SH_KNOTHOLDER); +void SPFloodContext::selection_changed(Inkscape::Selection* selection) { + this->shape_editor->unset_item(SH_KNOTHOLDER); + this->shape_editor->set_item(selection->singleItem(), SH_KNOTHOLDER); } -static void sp_flood_context_setup(SPEventContext *ec) -{ - SPFloodContext *rc = SP_FLOOD_CONTEXT(ec); - - if (((SPEventContextClass *) sp_flood_context_parent_class)->setup) { - ((SPEventContextClass *) sp_flood_context_parent_class)->setup(ec); - } +void SPFloodContext::setup() { + SPEventContext::setup(); - ec->shape_editor = new ShapeEditor(ec->desktop); + this->shape_editor = new ShapeEditor(this->desktop); - SPItem *item = sp_desktop_selection(ec->desktop)->singleItem(); + SPItem *item = sp_desktop_selection(this->desktop)->singleItem(); if (item) { - ec->shape_editor->set_item(item, SH_KNOTHOLDER); + this->shape_editor->set_item(item, SH_KNOTHOLDER); } - rc->sel_changed_connection.disconnect(); - rc->sel_changed_connection = sp_desktop_selection(ec->desktop)->connectChanged( - sigc::bind(sigc::ptr_fun(&sp_flood_context_selection_changed), (gpointer)rc) + this->sel_changed_connection.disconnect(); + this->sel_changed_connection = sp_desktop_selection(this->desktop)->connectChanged( + sigc::mem_fun(this, &SPFloodContext::selection_changed) ); - rc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack()); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/tools/paintbucket/selcue")) { - rc->enableSelectionCue(); + this->enableSelectionCue(); } } + // Changes from 0.48 -> 0.49 (Cairo) // 0.49: Ignores alpha in background // 0.48: RGBA, 0.49 ARGB @@ -1117,56 +1084,54 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even DocumentUndo::done(document, SP_VERB_CONTEXT_PAINTBUCKET, _("Fill bounded area")); } -static gint sp_flood_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event) -{ +bool SPFloodContext::item_handler(SPItem* item, GdkEvent* event) { gint ret = FALSE; - SPDesktop *desktop = event_context->desktop; - switch (event->type) { case GDK_BUTTON_PRESS: - if ((event->button.state & GDK_CONTROL_MASK) && event->button.button == 1 && !event_context->space_panning) { - Geom::Point const button_w(event->button.x, - event->button.y); + if ((event->button.state & GDK_CONTROL_MASK) && event->button.button == 1 && !this->space_panning) { + Geom::Point const button_w(event->button.x, event->button.y); SPItem *item = sp_event_context_find_item (desktop, button_w, TRUE, TRUE); // Set style desktop->applyCurrentOrToolStyle(item, "/tools/paintbucket", false); + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_PAINTBUCKET, _("Set style on object")); + ret = TRUE; } break; + default: break; } - if (((SPEventContextClass *) sp_flood_context_parent_class)->item_handler) { - ret = ((SPEventContextClass *) sp_flood_context_parent_class)->item_handler(event_context, item, event); - } +// if (((SPEventContextClass *) sp_flood_context_parent_class)->item_handler) { +// ret = ((SPEventContextClass *) sp_flood_context_parent_class)->item_handler(event_context, item, event); +// } + // CPPIFY: ret is overwritten... + ret = SPEventContext::item_handler(item, event); return ret; } -static gint sp_flood_context_root_handler(SPEventContext *event_context, GdkEvent *event) -{ +bool SPFloodContext::root_handler(GdkEvent* event) { static bool dragging; gint ret = FALSE; - SPDesktop *desktop = event_context->desktop; switch (event->type) { case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { + if (event->button.button == 1 && !this->space_panning) { if (!(event->button.state & GDK_CONTROL_MASK)) { - Geom::Point const button_w(event->button.x, - event->button.y); + Geom::Point const button_w(event->button.x, event->button.y); - if (Inkscape::have_viable_layer(desktop, event_context->defaultMessageContext())) { + if (Inkscape::have_viable_layer(desktop, this->defaultMessageContext())) { // save drag origin - event_context->xp = (gint) button_w[Geom::X]; - event_context->yp = (gint) button_w[Geom::Y]; - event_context->within_tolerance = true; + this->xp = (gint) button_w[Geom::X]; + this->yp = (gint) button_w[Geom::Y]; + this->within_tolerance = true; dragging = true; @@ -1176,44 +1141,45 @@ static gint sp_flood_context_root_handler(SPEventContext *event_context, GdkEven } } } + case GDK_MOTION_NOTIFY: - if ( dragging - && ( event->motion.state & GDK_BUTTON1_MASK ) && !event_context->space_panning) - { - if ( event_context->within_tolerance - && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance ) - && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) { + if ( dragging && ( event->motion.state & GDK_BUTTON1_MASK ) && !this->space_panning) { + if ( this->within_tolerance + && ( abs( (gint) event->motion.x - this->xp ) < this->tolerance ) + && ( abs( (gint) event->motion.y - this->yp ) < this->tolerance ) ) { break; // do not drag if we're within tolerance from origin } - event_context->within_tolerance = false; + this->within_tolerance = false; Geom::Point const motion_pt(event->motion.x, event->motion.y); Geom::Point const p(desktop->w2d(motion_pt)); + if (Inkscape::Rubberband::get(desktop)->is_started()) { Inkscape::Rubberband::get(desktop)->move(p); - event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw over</b> areas to add to fill, hold <b>Alt</b> for touch fill")); + this->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw over</b> areas to add to fill, hold <b>Alt</b> for touch fill")); gobble_motion_events(GDK_BUTTON1_MASK); } } break; case GDK_BUTTON_RELEASE: - if (event->button.button == 1 && !event_context->space_panning) { + if (event->button.button == 1 && !this->space_panning) { Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop); + if (r->is_started()) { // set "busy" cursor desktop->setWaitingCursor(); - if (SP_IS_EVENT_CONTEXT(event_context)) { + if (SP_IS_EVENT_CONTEXT(this)) { // Since setWaitingCursor runs main loop iterations, we may have already left this tool! // So check if the tool is valid before doing anything dragging = false; - bool is_point_fill = event_context->within_tolerance; + bool is_point_fill = this->within_tolerance; bool is_touch_fill = event->button.state & GDK_MOD1_MASK; - sp_flood_do_flood_fill(event_context, event, event->button.state & GDK_SHIFT_MASK, is_point_fill, is_touch_fill); + sp_flood_do_flood_fill(this, event, event->button.state & GDK_SHIFT_MASK, is_point_fill, is_touch_fill); desktop->clearWaitingCursor(); // restore cursor when done; note that it may already be different if e.g. user @@ -1224,9 +1190,9 @@ static gint sp_flood_context_root_handler(SPEventContext *event_context, GdkEven r->stop(); - if (SP_IS_EVENT_CONTEXT(event_context)) { - event_context->defaultMessageContext()->clear(); - } + //if (SP_IS_EVENT_CONTEXT(this)) { + this->defaultMessageContext()->clear(); + //} } } break; @@ -1244,43 +1210,35 @@ static gint sp_flood_context_root_handler(SPEventContext *event_context, GdkEven break; } break; + default: break; } if (!ret) { - if (((SPEventContextClass *) sp_flood_context_parent_class)->root_handler) { - ret = ((SPEventContextClass *) sp_flood_context_parent_class)->root_handler(event_context, event); - } + ret = SPEventContext::root_handler(event); } return ret; } +void SPFloodContext::finishItem() { + this->message_context->clear(); -static void sp_flood_finish(SPFloodContext *rc) -{ - rc->_message_context->clear(); - - if ( rc->item != NULL ) { - SPDesktop * desktop; - - desktop = SP_EVENT_CONTEXT_DESKTOP(rc); - - SP_OBJECT(rc->item)->updateRepr(); + if (this->item != NULL) { + this->item->updateRepr(); desktop->canvas->endForcedFullRedraws(); - sp_desktop_selection(desktop)->set(rc->item); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_PAINTBUCKET, - _("Fill bounded area")); + sp_desktop_selection(desktop)->set(this->item); - rc->item = NULL; + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_PAINTBUCKET, _("Fill bounded area")); + + this->item = NULL; } } -void flood_channels_set_channels( gint channels ) -{ +void SPFloodContext::set_channels(gint channels) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setInt("/tools/paintbucket/channels", channels); } diff --git a/src/flood-context.h b/src/flood-context.h index 810a3b48f..48bf36f85 100644 --- a/src/flood-context.h +++ b/src/flood-context.h @@ -16,36 +16,41 @@ #include <gtk/gtk.h> #include "event-context.h" -#define SP_TYPE_FLOOD_CONTEXT (sp_flood_context_get_type ()) -#define SP_FLOOD_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_FLOOD_CONTEXT, SPFloodContext)) -#define SP_FLOOD_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_FLOOD_CONTEXT, SPFloodContextClass)) -#define SP_IS_FLOOD_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_FLOOD_CONTEXT)) -#define SP_IS_FLOOD_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_FLOOD_CONTEXT)) +#define SP_FLOOD_CONTEXT(obj) (dynamic_cast<SPFloodContext*>((SPEventContext*)obj)) +#define SP_IS_FLOOD_CONTEXT(obj) (dynamic_cast<const SPFloodContext*>((const SPEventContext*)obj) != NULL) + #define FLOOD_COLOR_CHANNEL_R 1 #define FLOOD_COLOR_CHANNEL_G 2 #define FLOOD_COLOR_CHANNEL_B 4 #define FLOOD_COLOR_CHANNEL_A 8 -struct SPFloodContext : public SPEventContext { +class SPFloodContext : public SPEventContext { +public: + SPFloodContext(); + virtual ~SPFloodContext(); + SPItem *item; sigc::connection sel_changed_connection; - Inkscape::MessageContext *_message_context; -}; + static const std::string prefsPath; -struct SPFloodContextClass { - SPEventContextClass parent_class; -}; + virtual void setup(); + virtual bool root_handler(GdkEvent* event); + virtual bool item_handler(SPItem* item, GdkEvent* event); + + virtual const std::string& getPrefsPath(); -/* Standard Gtk function */ + static void set_channels(gint channels); -GType sp_flood_context_get_type (void); +private: + void selection_changed(Inkscape::Selection* selection); + void finishItem(); +}; GList* flood_channels_dropdown_items_list (void); GList* flood_autogap_dropdown_items_list (void); -void flood_channels_set_channels( gint channels ); enum PaintBucketChannels { FLOOD_CHANNELS_RGB, diff --git a/src/gradient-chemistry.cpp b/src/gradient-chemistry.cpp index a0c20c609..40260ea66 100644 --- a/src/gradient-chemistry.cpp +++ b/src/gradient-chemistry.cpp @@ -648,8 +648,8 @@ SPStop *sp_vector_add_stop(SPGradient *vector, SPStop* prev_stop, SPStop* next_s SPStop *newstop = reinterpret_cast<SPStop *>(vector->document->getObjectByRepr(new_stop_repr)); newstop->offset = offset; sp_repr_set_css_double( newstop->getRepr(), "offset", (double)offset); - guint32 const c1 = sp_stop_get_rgba32(prev_stop); - guint32 const c2 = sp_stop_get_rgba32(next_stop); + guint32 const c1 = prev_stop->get_rgba32(); + guint32 const c2 = next_stop->get_rgba32(); guint32 cnew = average_color (c1, c2, (offset - prev_stop->offset) / (next_stop->offset - prev_stop->offset)); Inkscape::CSSOStringStream os; gchar c[64]; @@ -726,7 +726,7 @@ guint32 sp_item_gradient_stop_query_style(SPItem *item, GrPointType point_type, { SPStop *first = vector->getFirstStop(); if (first) { - return sp_stop_get_rgba32(first); + return first->get_rgba32(); } } break; @@ -737,7 +737,7 @@ guint32 sp_item_gradient_stop_query_style(SPItem *item, GrPointType point_type, { SPStop *last = sp_last_stop (vector); if (last) { - return sp_stop_get_rgba32(last); + return last->get_rgba32(); } } break; @@ -748,7 +748,7 @@ guint32 sp_item_gradient_stop_query_style(SPItem *item, GrPointType point_type, { SPStop *stopi = sp_get_stop_i (vector, point_i); if (stopi) { - return sp_stop_get_rgba32(stopi); + return stopi->get_rgba32(); } } break; @@ -982,7 +982,7 @@ void sp_item_gradient_invert_vector_color(SPItem *item, Inkscape::PaintTarget fi for ( SPObject *child = vector->firstChild(); child; child = child->getNext()) { if (SP_IS_STOP(child)) { - guint32 color = sp_stop_get_rgba32(SP_STOP(child)); + guint32 color = SP_STOP(child)->get_rgba32(); //g_message("Stop color %d", color); gchar c[64]; sp_svg_write_color (c, sizeof(c), @@ -1571,7 +1571,7 @@ void sp_gradient_invert_selected_gradients(SPDesktop *desktop, Inkscape::PaintTa void sp_gradient_reverse_selected_gradients(SPDesktop *desktop) { Inkscape::Selection *selection = sp_desktop_selection(desktop); - SPEventContext *ev = sp_desktop_event_context(desktop); + SPEventContext *ev = desktop->getEventContext(); if (!ev) { return; diff --git a/src/gradient-context.cpp b/src/gradient-context.cpp index d2822fbe1..3456f33c3 100644 --- a/src/gradient-context.cpp +++ b/src/gradient-context.cpp @@ -51,59 +51,50 @@ using Inkscape::DocumentUndo; -static void sp_gradient_context_dispose(GObject *object); - -static void sp_gradient_context_setup(SPEventContext *ec); - -static gint sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event); - static void sp_gradient_drag(SPGradientContext &rc, Geom::Point const pt, guint state, guint32 etime); -G_DEFINE_TYPE(SPGradientContext, sp_gradient_context, SP_TYPE_EVENT_CONTEXT); -static void sp_gradient_context_class_init(SPGradientContextClass *klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - SPEventContextClass *event_context_class = (SPEventContextClass *) klass; +#include "tool-factory.h" - object_class->dispose = sp_gradient_context_dispose; +namespace { + SPEventContext* createGradientContext() { + return new SPGradientContext(); + } - event_context_class->setup = sp_gradient_context_setup; - event_context_class->root_handler = sp_gradient_context_root_handler; + bool gradientContextRegistered = ToolFactory::instance().registerObject("/tools/gradient", createGradientContext); } -static void sp_gradient_context_init(SPGradientContext *gr_context) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(gr_context); - - gr_context->cursor_addnode = false; - event_context->cursor_shape = cursor_gradient_xpm; - event_context->hot_x = 4; - event_context->hot_y = 4; - event_context->xp = 0; - event_context->yp = 0; - event_context->tolerance = 6; - event_context->within_tolerance = false; - event_context->item_to_select = NULL; +const std::string& SPGradientContext::getPrefsPath() { + return SPGradientContext::prefsPath; } -static void sp_gradient_context_dispose(GObject *object) -{ - SPGradientContext *rc = SP_GRADIENT_CONTEXT(object); - SPEventContext *ec = SP_EVENT_CONTEXT(object); +const std::string SPGradientContext::prefsPath = "/tools/gradient"; - ec->enableGrDrag(false); - if (rc->_message_context) { - delete rc->_message_context; - } +SPGradientContext::SPGradientContext() : SPEventContext() { + this->node_added = false; + this->subselcon = 0; + this->selcon = 0; + + this->cursor_addnode = false; + this->cursor_shape = cursor_gradient_xpm; + this->hot_x = 4; + this->hot_y = 4; + this->xp = 0; + this->yp = 0; + this->tolerance = 6; + this->within_tolerance = false; + this->item_to_select = NULL; +} + +SPGradientContext::~SPGradientContext() { + this->enableGrDrag(false); - rc->selcon->disconnect(); - delete rc->selcon; - rc->subselcon->disconnect(); - delete rc->subselcon; + this->selcon->disconnect(); + delete this->selcon; - G_OBJECT_CLASS(sp_gradient_context_parent_class)->dispose(object); + this->subselcon->disconnect(); + delete this->subselcon; } const gchar *gr_handle_descr [] = { @@ -118,10 +109,8 @@ const gchar *gr_handle_descr [] = { N_("Radial gradient <b>mid stop</b>") }; -static void -gradient_selection_changed (Inkscape::Selection *, gpointer data) -{ - SPGradientContext *rc = (SPGradientContext *) data; +void SPGradientContext::selection_changed(Inkscape::Selection*) { + SPGradientContext *rc = (SPGradientContext *) this; GrDrag *drag = rc->_grdrag; Inkscape::Selection *selection = sp_desktop_selection(SP_EVENT_CONTEXT(rc)->desktop); @@ -144,7 +133,7 @@ gradient_selection_changed (Inkscape::Selection *, gpointer data) //TRANSLATORS: Mind the space in front. This is part of a compound message ngettext(" out of %d gradient handle"," out of %d gradient handles",n_tot), ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL); - rc->_message_context->setF(Inkscape::NORMAL_MESSAGE, + rc->message_context->setF(Inkscape::NORMAL_MESSAGE, message,_(gr_handle_descr[drag->singleSelectedDraggerSingleDraggableType()]), n_tot, n_obj); } else { gchar * message = g_strconcat( @@ -153,50 +142,46 @@ gradient_selection_changed (Inkscape::Selection *, gpointer data) "One handle merging %d stops (drag with <b>Shift</b> to separate) selected",drag->singleSelectedDraggerNumDraggables()), ngettext(" out of %d gradient handle"," out of %d gradient handles",n_tot), ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL); - rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,message,drag->singleSelectedDraggerNumDraggables(), n_tot, n_obj); + rc->message_context->setF(Inkscape::NORMAL_MESSAGE,message,drag->singleSelectedDraggerNumDraggables(), n_tot, n_obj); } } else if (n_sel > 1) { //TRANSLATORS: The plural refers to number of selected gradient handles. This is part of a compound message (part two indicates selected object count) gchar * message = g_strconcat(ngettext("<b>%d</b> gradient handle selected out of %d","<b>%d</b> gradient handles selected out of %d",n_sel), //TRANSLATORS: Mind the space in front. (Refers to gradient handles selected). This is part of a compound message ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL); - rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,message, n_sel, n_tot, n_obj); + rc->message_context->setF(Inkscape::NORMAL_MESSAGE,message, n_sel, n_tot, n_obj); } else if (n_sel == 0) { - rc->_message_context->setF(Inkscape::NORMAL_MESSAGE, + rc->message_context->setF(Inkscape::NORMAL_MESSAGE, //TRANSLATORS: The plural refers to number of selected objects ngettext("<b>No</b> gradient handles selected out of %d on %d selected object", "<b>No</b> gradient handles selected out of %d on %d selected objects",n_obj), n_tot, n_obj); } } -static void -gradient_subselection_changed (gpointer, gpointer data) -{ - gradient_selection_changed (NULL, data); -} - - -static void sp_gradient_context_setup(SPEventContext *ec) -{ - SPGradientContext *rc = SP_GRADIENT_CONTEXT(ec); - - if (((SPEventContextClass *) sp_gradient_context_parent_class)->setup) { - ((SPEventContextClass *) sp_gradient_context_parent_class)->setup(ec); - } +void SPGradientContext::setup() { + SPEventContext::setup(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/tools/gradient/selcue", true)) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } - ec->enableGrDrag(); - Inkscape::Selection *selection = sp_desktop_selection(ec->desktop); + this->enableGrDrag(); + Inkscape::Selection *selection = sp_desktop_selection(this->desktop); - rc->_message_context = new Inkscape::MessageContext(sp_desktop_message_stack(ec->desktop)); + this->selcon = new sigc::connection(selection->connectChanged( + sigc::mem_fun(this, &SPGradientContext::selection_changed) + )); - rc->selcon = new sigc::connection (selection->connectChanged( sigc::bind (sigc::ptr_fun(&gradient_selection_changed), rc))); - rc->subselcon = new sigc::connection (ec->desktop->connectToolSubselectionChanged(sigc::bind (sigc::ptr_fun(&gradient_subselection_changed), rc))); - gradient_selection_changed(selection, rc); + this->subselcon = new sigc::connection(this->desktop->connectToolSubselectionChanged( + sigc::hide(sigc::bind( + sigc::mem_fun(this, &SPGradientContext::selection_changed), + (Inkscape::Selection*)NULL + )) + )); + + this->selection_changed(selection); } void @@ -425,9 +410,9 @@ sp_gradient_simplify(SPGradientContext *rc, double tolerance) if (g_slist_find(todel, stop0) || g_slist_find(todel, stop2)) continue; - guint32 const c0 = sp_stop_get_rgba32(stop0); - guint32 const c2 = sp_stop_get_rgba32(stop2); - guint32 const c1r = sp_stop_get_rgba32(stop1); + guint32 const c0 = stop0->get_rgba32(); + guint32 const c2 = stop2->get_rgba32(); + guint32 const c1r = stop1->get_rgba32(); guint32 c1 = average_color (c0, c2, (stop1->offset - stop0->offset) / (stop2->offset - stop0->offset)); @@ -483,40 +468,37 @@ sp_gradient_context_add_stop_near_point (SPGradientContext *rc, SPItem *item, G ec->get_drag()->selectByStop(newstop); } - -static gint -sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) -{ +bool SPGradientContext::root_handler(GdkEvent* event) { static bool dragging; - SPDesktop *desktop = event_context->desktop; Inkscape::Selection *selection = sp_desktop_selection (desktop); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - SPGradientContext *rc = SP_GRADIENT_CONTEXT(event_context); - - event_context->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); + this->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); double const nudge = prefs->getDoubleLimited("/options/nudgedistance/value", 2, 0, 1000, "px"); // in px - GrDrag *drag = event_context->_grdrag; + GrDrag *drag = this->_grdrag; g_assert (drag); gint ret = FALSE; + switch (event->type) { case GDK_2BUTTON_PRESS: if ( event->button.button == 1 ) { bool over_line = false; SPCtrlLine *line = NULL; + if (drag->lines) { for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) { line = (SPCtrlLine*) l->data; - over_line |= sp_gradient_context_is_over_line (rc, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y)); + over_line |= sp_gradient_context_is_over_line (this, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y)); } } + if (over_line) { // we take the first item in selection, because with doubleclick, the first click // always resets selection to the single object under cursor - sp_gradient_context_add_stop_near_point(rc, SP_ITEM(selection->itemList()->data), rc->mousepoint_doc, event->button.time); + sp_gradient_context_add_stop_near_point(this, SP_ITEM(selection->itemList()->data), this->mousepoint_doc, event->button.time); } else { for (GSList const* i = selection->itemList(); i != NULL; i = i->next) { SPItem *item = SP_ITEM(i->data); @@ -535,14 +517,15 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) ret = TRUE; } break; + case GDK_BUTTON_PRESS: - if ( event->button.button == 1 && !event_context->space_panning ) { + if ( event->button.button == 1 && !this->space_panning ) { Geom::Point button_w(event->button.x, event->button.y); // save drag origin - event_context->xp = (gint) button_w[Geom::X]; - event_context->yp = (gint) button_w[Geom::Y]; - event_context->within_tolerance = true; + this->xp = (gint) button_w[Geom::X]; + this->yp = (gint) button_w[Geom::Y]; + this->within_tolerance = true; dragging = true; @@ -552,8 +535,9 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) } else { // remember clicked item, disregarding groups, honoring Alt; do nothing with Crtl to // enable Ctrl+doubleclick of exactly the selected item(s) - if (!(event->button.state & GDK_CONTROL_MASK)) - event_context->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE); + if (!(event->button.state & GDK_CONTROL_MASK)) { + this->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE); + } if (!selection->isEmpty()) { SnapManager &m = desktop->namedview->snap_manager; @@ -561,36 +545,37 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) m.freeSnapReturnByRef(button_dt, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); } - rc->origin = button_dt; + + this->origin = button_dt; } ret = TRUE; } break; + case GDK_MOTION_NOTIFY: - if ( dragging - && ( event->motion.state & GDK_BUTTON1_MASK ) && !event_context->space_panning ) - { - if ( event_context->within_tolerance - && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance ) - && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) { + if (dragging && ( event->motion.state & GDK_BUTTON1_MASK ) && !this->space_panning) { + if ( this->within_tolerance + && ( abs( (gint) event->motion.x - this->xp ) < this->tolerance ) + && ( abs( (gint) event->motion.y - this->yp ) < this->tolerance ) ) { break; // do not drag if we're within tolerance from origin } // Once the user has moved farther than tolerance from the original location // (indicating they intend to draw, not click), then always process the // motion notify coordinates as given (no snapping back to origin) - event_context->within_tolerance = false; + this->within_tolerance = false; Geom::Point const motion_w(event->motion.x, event->motion.y); - Geom::Point const motion_dt = event_context->desktop->w2d(motion_w); + Geom::Point const motion_dt = this->desktop->w2d(motion_w); if (Inkscape::Rubberband::get(desktop)->is_started()) { Inkscape::Rubberband::get(desktop)->move(motion_dt); - event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw around</b> handles to select them")); + this->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw around</b> handles to select them")); } else { - sp_gradient_drag(*rc, motion_dt, event->motion.state, event->motion.time); + sp_gradient_drag(*this, motion_dt, event->motion.state, event->motion.time); } + gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; @@ -600,46 +585,51 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) m.setup(desktop); Geom::Point const motion_w(event->motion.x, event->motion.y); - Geom::Point const motion_dt = event_context->desktop->w2d(motion_w); + Geom::Point const motion_dt = this->desktop->w2d(motion_w); m.preSnap(Inkscape::SnapCandidatePoint(motion_dt, Inkscape::SNAPSOURCE_OTHER_HANDLE)); m.unSetup(); } bool over_line = false; + if (drag->lines) { for (GSList *l = drag->lines; l != NULL; l = l->next) { - over_line |= sp_gradient_context_is_over_line (rc, (SPItem*) l->data, Geom::Point(event->motion.x, event->motion.y)); + over_line |= sp_gradient_context_is_over_line (this, (SPItem*) l->data, Geom::Point(event->motion.x, event->motion.y)); } } - if (rc->cursor_addnode && !over_line) { - event_context->cursor_shape = cursor_gradient_xpm; - sp_event_context_update_cursor(event_context); - rc->cursor_addnode = false; - } else if (!rc->cursor_addnode && over_line) { - event_context->cursor_shape = cursor_gradient_add_xpm; - sp_event_context_update_cursor(event_context); - rc->cursor_addnode = true; + if (this->cursor_addnode && !over_line) { + this->cursor_shape = cursor_gradient_xpm; + this->sp_event_context_update_cursor(); + this->cursor_addnode = false; + } else if (!this->cursor_addnode && over_line) { + this->cursor_shape = cursor_gradient_add_xpm; + this->sp_event_context_update_cursor(); + this->cursor_addnode = true; } } break; + case GDK_BUTTON_RELEASE: - event_context->xp = event_context->yp = 0; - if ( event->button.button == 1 && !event_context->space_panning ) { + this->xp = this->yp = 0; + + if ( event->button.button == 1 && !this->space_panning ) { bool over_line = false; SPCtrlLine *line = NULL; + if (drag->lines) { for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) { line = (SPCtrlLine*) l->data; - over_line = sp_gradient_context_is_over_line (rc, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y)); + over_line = sp_gradient_context_is_over_line (this, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y)); if (over_line) break; } } + if ( (event->button.state & GDK_CONTROL_MASK) && (event->button.state & GDK_MOD1_MASK ) ) { if (over_line && line) { - sp_gradient_context_add_stop_near_point(rc, line->item, rc->mousepoint_doc, 0); + sp_gradient_context_add_stop_near_point(this, line->item, this->mousepoint_doc, 0); ret = TRUE; } } else { @@ -651,30 +641,29 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) break; } - if (!event_context->within_tolerance) { + if (!this->within_tolerance) { // we've been dragging, either do nothing (grdrag handles that), // or rubberband-select if we have rubberband Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop); - if (r->is_started() && !event_context->within_tolerance) { + + if (r->is_started() && !this->within_tolerance) { // this was a rubberband drag if (r->getMode() == RUBBERBAND_MODE_RECT) { Geom::OptRect const b = r->getRectangle(); drag->selectRect(*b); } } - - } else if (event_context->item_to_select) { + } else if (this->item_to_select) { if (over_line && line) { // Clicked on an existing gradient line, dont change selection. This stops // possible change in selection during a double click with overlapping objects - } - else { + } else { // no dragging, select clicked item if any if (event->button.state & GDK_SHIFT_MASK) { - selection->toggle(event_context->item_to_select); + selection->toggle(this->item_to_select); } else { drag->deselectAll(); - selection->set(event_context->item_to_select); + selection->set(this->item_to_select); } } } else { @@ -686,12 +675,14 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) } } - event_context->item_to_select = NULL; + this->item_to_select = NULL; ret = TRUE; } + Inkscape::Rubberband::get(desktop)->stop(); } break; + case GDK_KEY_PRESS: switch (get_group0_keyval (&event->key)) { case GDK_KEY_Alt_L: @@ -702,7 +693,7 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_Shift_R: case GDK_KEY_Meta_L: // Meta is when you press Shift+Alt (at least on my machine) case GDK_KEY_Meta_R: - sp_event_show_modifier_tip (event_context->defaultMessageContext(), event, + sp_event_show_modifier_tip (this->defaultMessageContext(), event, _("<b>Ctrl</b>: snap gradient angle"), _("<b>Shift</b>: draw gradient around the starting point"), NULL); @@ -727,7 +718,7 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_L: case GDK_KEY_l: if (MOD__CTRL_ONLY(event) && drag->isNonEmpty() && drag->hasSelection()) { - sp_gradient_simplify(rc, 1e-4); + sp_gradient_simplify(this, 1e-4); ret = TRUE; } break; @@ -749,16 +740,22 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__ALT(event)) { // alt - if (MOD__SHIFT(event)) drag->selected_move_screen(mul*-10, 0); // shift - else drag->selected_move_screen(mul*-1, 0); // no shift - } - else { // no alt - if (MOD__SHIFT(event)) drag->selected_move(mul*-10*nudge, 0); // shift - else drag->selected_move(mul*-nudge, 0); // no shift + if (MOD__SHIFT(event)) { + drag->selected_move_screen(mul*-10, 0); // shift + } else { + drag->selected_move_screen(mul*-1, 0); // no shift + } + } else { // no alt + if (MOD__SHIFT(event)) { + drag->selected_move(mul*-10*nudge, 0); // shift + } else { + drag->selected_move(mul*-nudge, 0); // no shift + } } ret = TRUE; } break; + case GDK_KEY_Up: // move handle up case GDK_KEY_KP_Up: case GDK_KEY_KP_8: @@ -766,50 +763,73 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__ALT(event)) { // alt - if (MOD__SHIFT(event)) drag->selected_move_screen(0, mul*10); // shift - else drag->selected_move_screen(0, mul*1); // no shift - } - else { // no alt - if (MOD__SHIFT(event)) drag->selected_move(0, mul*10*nudge); // shift - else drag->selected_move(0, mul*nudge); // no shift + if (MOD__SHIFT(event)) { + drag->selected_move_screen(0, mul*10); // shift + } else { + drag->selected_move_screen(0, mul*1); // no shift + } + } else { // no alt + if (MOD__SHIFT(event)) { + drag->selected_move(0, mul*10*nudge); // shift + } else { + drag->selected_move(0, mul*nudge); // no shift + } } + ret = TRUE; } break; + case GDK_KEY_Right: // move handle right case GDK_KEY_KP_Right: case GDK_KEY_KP_6: if (!MOD__CTRL(event)) { // not ctrl gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask + if (MOD__ALT(event)) { // alt - if (MOD__SHIFT(event)) drag->selected_move_screen(mul*10, 0); // shift - else drag->selected_move_screen(mul*1, 0); // no shift - } - else { // no alt - if (MOD__SHIFT(event)) drag->selected_move(mul*10*nudge, 0); // shift - else drag->selected_move(mul*nudge, 0); // no shift + if (MOD__SHIFT(event)) { + drag->selected_move_screen(mul*10, 0); // shift + } else { + drag->selected_move_screen(mul*1, 0); // no shift + } + } else { // no alt + if (MOD__SHIFT(event)) { + drag->selected_move(mul*10*nudge, 0); // shift + } else { + drag->selected_move(mul*nudge, 0); // no shift + } } + ret = TRUE; } break; + case GDK_KEY_Down: // move handle down case GDK_KEY_KP_Down: case GDK_KEY_KP_2: if (!MOD__CTRL(event)) { // not ctrl gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask + if (MOD__ALT(event)) { // alt - if (MOD__SHIFT(event)) drag->selected_move_screen(0, mul*-10); // shift - else drag->selected_move_screen(0, mul*-1); // no shift - } - else { // no alt - if (MOD__SHIFT(event)) drag->selected_move(0, mul*-10*nudge); // shift - else drag->selected_move(0, mul*-nudge); // no shift + if (MOD__SHIFT(event)) { + drag->selected_move_screen(0, mul*-10); // shift + } else { + drag->selected_move_screen(0, mul*-1); // no shift + } + } else { // no alt + if (MOD__SHIFT(event)) { + drag->selected_move(0, mul*-10*nudge); // shift + } else { + drag->selected_move(0, mul*-nudge); // no shift + } } + ret = TRUE; } break; + case GDK_KEY_r: case GDK_KEY_R: if (MOD__SHIFT_ONLY(event)) { @@ -821,19 +841,21 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_Insert: case GDK_KEY_KP_Insert: // with any modifiers: - sp_gradient_context_add_stops_between_selected_stops (rc); + sp_gradient_context_add_stops_between_selected_stops (this); ret = TRUE; break; case GDK_KEY_Delete: case GDK_KEY_KP_Delete: case GDK_KEY_BackSpace: - ret = event_context->deleteSelectedDrag(MOD__CTRL_ONLY(event)); + ret = this->deleteSelectedDrag(MOD__CTRL_ONLY(event)); break; + default: break; } break; + case GDK_KEY_RELEASE: switch (get_group0_keyval (&event->key)) { case GDK_KEY_Alt_L: @@ -844,20 +866,20 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_Shift_R: case GDK_KEY_Meta_L: // Meta is when you press Shift+Alt case GDK_KEY_Meta_R: - event_context->defaultMessageContext()->clear(); + this->defaultMessageContext()->clear(); break; + default: break; } break; + default: break; } if (!ret) { - if (((SPEventContextClass *) sp_gradient_context_parent_class)->root_handler) { - ret = ((SPEventContextClass *) sp_gradient_context_parent_class)->root_handler(event_context, event); - } + ret = SPEventContext::root_handler(event); } return ret; @@ -926,7 +948,7 @@ static void sp_gradient_drag(SPGradientContext &rc, Geom::Point const pt, guint // status text; we do not track coords because this branch is run once, not all the time // during drag int n_objects = g_slist_length((GSList *) selection->itemList()); - rc._message_context->setF(Inkscape::NORMAL_MESSAGE, + rc.message_context->setF(Inkscape::NORMAL_MESSAGE, ngettext("<b>Gradient</b> for %d object; with <b>Ctrl</b> to snap angle", "<b>Gradient</b> for %d objects; with <b>Ctrl</b> to snap angle", n_objects), n_objects); diff --git a/src/gradient-context.h b/src/gradient-context.h index 464b95ad4..7a2918f3d 100644 --- a/src/gradient-context.h +++ b/src/gradient-context.h @@ -19,13 +19,13 @@ #include <sigc++/sigc++.h> #include "event-context.h" -#define SP_TYPE_GRADIENT_CONTEXT (sp_gradient_context_get_type()) -#define SP_GRADIENT_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_GRADIENT_CONTEXT, SPGradientContext)) -#define SP_GRADIENT_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_GRADIENT_CONTEXT, SPGradientContextClass)) -#define SP_IS_GRADIENT_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_GRADIENT_CONTEXT)) -#define SP_IS_GRADIENT_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_GRADIENT_CONTEXT)) +#define SP_GRADIENT_CONTEXT(obj) (dynamic_cast<SPGradientContext*>((SPEventContext*)obj)) +#define SP_IS_GRADIENT_CONTEXT(obj) (dynamic_cast<const SPGradientContext*>((const SPEventContext*)obj) != NULL) -struct SPGradientContext : public SPEventContext { +class SPGradientContext : public SPEventContext { +public: + SPGradientContext(); + virtual ~SPGradientContext(); Geom::Point origin; @@ -35,18 +35,19 @@ struct SPGradientContext : public SPEventContext { Geom::Point mousepoint_doc; // stores mousepoint when over_line in doc coords - Inkscape::MessageContext *_message_context; - sigc::connection *selcon; sigc::connection *subselcon; -}; -struct SPGradientContextClass { - SPEventContextClass parent_class; -}; + static const std::string prefsPath; -/* Standard Gtk function */ -GType sp_gradient_context_get_type(); + virtual void setup(); + virtual bool root_handler(GdkEvent* event); + + virtual const std::string& getPrefsPath(); + +private: + void selection_changed(Inkscape::Selection*); +}; void sp_gradient_context_select_next (SPEventContext *event_context); void sp_gradient_context_select_prev (SPEventContext *event_context); diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp index 65b26937b..fb58aa508 100644 --- a/src/gradient-drag.cpp +++ b/src/gradient-drag.cpp @@ -709,12 +709,14 @@ GrDraggable::GrDraggable(SPItem *item, GrPointType point_type, guint point_i, In point_i(point_i), fill_or_stroke(fill_or_stroke) { - g_object_ref(G_OBJECT(item)); + //g_object_ref(G_OBJECT(item)); + sp_object_ref(item); } GrDraggable::~GrDraggable() { - g_object_unref (G_OBJECT (this->item)); + //g_object_unref (G_OBJECT (this->item)); + sp_object_unref(this->item); } @@ -1415,7 +1417,7 @@ void GrDragger::updateTip() if (g_slist_length (this->draggables) == 1) { GrDraggable *draggable = (GrDraggable *) this->draggables->data; - char *item_desc = draggable->item->description(); + char *item_desc = draggable->item->getDetailedDescription(); switch (draggable->point_type) { case POINT_LG_MID: case POINT_RG_MID1: diff --git a/src/gradient-drag.h b/src/gradient-drag.h index 2a2465590..c92a5c22f 100644 --- a/src/gradient-drag.h +++ b/src/gradient-drag.h @@ -33,12 +33,12 @@ struct SPKnot; class SPDesktop; class SPCSSAttr; -struct SPLinearGradient; -struct SPMeshGradient; +class SPLinearGradient; +class SPMeshGradient; class SPItem; class SPObject; -struct SPRadialGradient; -struct SPStop; +class SPRadialGradient; +class SPStop; namespace Inkscape { class Selection; diff --git a/src/guide-snapper.h b/src/guide-snapper.h index aa0c45320..7aea2988b 100644 --- a/src/guide-snapper.h +++ b/src/guide-snapper.h @@ -13,7 +13,7 @@ #include "line-snapper.h" -struct SPNamedView; +class SPNamedView; namespace Inkscape { diff --git a/src/helper/pixbuf-ops.cpp b/src/helper/pixbuf-ops.cpp index a51a62f42..8e611d197 100644 --- a/src/helper/pixbuf-ops.cpp +++ b/src/helper/pixbuf-ops.cpp @@ -16,6 +16,7 @@ #endif #include <png.h> +#include <boost/scoped_ptr.hpp> #include <2geom/transforms.h> #include "interface.h" @@ -67,16 +68,14 @@ bool sp_export_jpg_file(SPDocument *doc, gchar const *filename, unsigned width, unsigned height, double xdpi, double ydpi, unsigned long bgcolor, double quality,GSList *items) { - GdkPixbuf* pixbuf = 0; - pixbuf = sp_generate_internal_bitmap(doc, filename, x0, y0, x1, y1, - width, height, xdpi, ydpi, - bgcolor, items ); + boost::scoped_ptr<Inkscape::Pixbuf> pixbuf( + sp_generate_internal_bitmap(doc, filename, x0, y0, x1, y1, + width, height, xdpi, ydpi, bgcolor, items)); gchar c[32]; g_snprintf(c, 32, "%f", quality); - gboolean saved = gdk_pixbuf_save (pixbuf, filename, "jpeg", NULL, "quality", c, NULL); + gboolean saved = gdk_pixbuf_save(pixbuf->getPixbufRaw(), filename, "jpeg", NULL, "quality", c, NULL); g_free(c); - g_object_unref (pixbuf); return saved; } @@ -94,7 +93,7 @@ bool sp_export_jpg_file(SPDocument *doc, gchar const *filename, @param ydpi @return the created GdkPixbuf structure or NULL if no memory is allocable */ -GdkPixbuf *sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/, +Inkscape::Pixbuf *sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/, double x0, double y0, double x1, double y1, unsigned width, unsigned height, double xdpi, double ydpi, unsigned long /*bgcolor*/, @@ -103,7 +102,7 @@ GdkPixbuf *sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename* { if (width == 0 || height == 0) return NULL; - GdkPixbuf* pixbuf = NULL; + Inkscape::Pixbuf *inkpb = NULL; /* Create new drawing for offscreen rendering*/ Inkscape::Drawing drawing; drawing.setExact(true); @@ -146,7 +145,7 @@ GdkPixbuf *sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename* // render items drawing.render(ct, final_bbox, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); - pixbuf = ink_pixbuf_create_from_cairo_surface(surface); + inkpb = new Inkscape::Pixbuf(surface); } else { @@ -158,7 +157,7 @@ GdkPixbuf *sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename* // gdk_pixbuf_save (pixbuf, "C:\\temp\\internal.jpg", "jpeg", NULL, "quality","100", NULL); - return pixbuf; + return inkpb; } /* diff --git a/src/helper/pixbuf-ops.h b/src/helper/pixbuf-ops.h index 44851d388..61a879f9b 100644 --- a/src/helper/pixbuf-ops.h +++ b/src/helper/pixbuf-ops.h @@ -15,11 +15,12 @@ #include <glib.h> class SPDocument; +namespace Inkscape { class Pixbuf; } bool sp_export_jpg_file (SPDocument *doc, gchar const *filename, double x0, double y0, double x1, double y1, unsigned int width, unsigned int height, double xdpi, double ydpi, unsigned long bgcolor, double quality, GSList *items_only = NULL); -GdkPixbuf* sp_generate_internal_bitmap(SPDocument *doc, gchar const *filename, +Inkscape::Pixbuf *sp_generate_internal_bitmap(SPDocument *doc, gchar const *filename, double x0, double y0, double x1, double y1, unsigned width, unsigned height, double xdpi, double ydpi, unsigned long bgcolor, GSList *items_only = NULL); diff --git a/src/inkscape.cpp b/src/inkscape.cpp index a24bd2b8a..e1cabd2d5 100644 --- a/src/inkscape.cpp +++ b/src/inkscape.cpp @@ -1013,7 +1013,7 @@ inkscape_add_desktop (SPDesktop * desktop) inkscape->desktops = g_slist_prepend (inkscape->desktops, desktop); g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop); - g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (desktop)); + g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, desktop->getEventContext()); g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (desktop)); g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (desktop)); } @@ -1035,7 +1035,7 @@ inkscape_remove_desktop (SPDesktop * desktop) inkscape->desktops = g_slist_remove (inkscape->desktops, new_desktop); inkscape->desktops = g_slist_prepend (inkscape->desktops, new_desktop); g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, new_desktop); - g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (new_desktop)); + g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, new_desktop->getEventContext()); g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (new_desktop)); g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (new_desktop)); } else { @@ -1075,7 +1075,7 @@ inkscape_activate_desktop (SPDesktop * desktop) inkscape->desktops = g_slist_prepend (inkscape->desktops, desktop); g_signal_emit (G_OBJECT (inkscape), inkscape_signals[ACTIVATE_DESKTOP], 0, desktop); - g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, sp_desktop_event_context (desktop)); + g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_EVENTCONTEXT], 0, desktop->getEventContext()); g_signal_emit (G_OBJECT (inkscape), inkscape_signals[SET_SELECTION], 0, sp_desktop_selection (desktop)); g_signal_emit (G_OBJECT (inkscape), inkscape_signals[CHANGE_SELECTION], 0, sp_desktop_selection (desktop)); } @@ -1342,7 +1342,7 @@ SPEventContext * inkscape_active_event_context (void) { if (SP_ACTIVE_DESKTOP) { - return sp_desktop_event_context (SP_ACTIVE_DESKTOP); + return SP_ACTIVE_DESKTOP->getEventContext(); } return NULL; diff --git a/src/inkscape.h b/src/inkscape.h index 234b98d2c..0effc3c38 100644 --- a/src/inkscape.h +++ b/src/inkscape.h @@ -17,7 +17,7 @@ class SPDesktop; class SPDocument; -struct SPEventContext; +class SPEventContext; namespace Inkscape { class ActionContext; diff --git a/src/interface.cpp b/src/interface.cpp index 026890c67..ea5eaf16a 100644 --- a/src/interface.cpp +++ b/src/interface.cpp @@ -47,7 +47,6 @@ #include "widgets/desktop-widget.h" #include "sp-item-group.h" #include "sp-text.h" -#include "sp-gradient-fns.h" #include "sp-gradient.h" #include "sp-flowtext.h" #include "sp-namedview.h" @@ -1607,32 +1606,56 @@ void ContextMenu::AppendItemFromVerb(Inkscape::Verb *verb)//, SPDesktop *view)// void ContextMenu::MakeObjectMenu(void) { - GObjectClass *klass = G_OBJECT_GET_CLASS(_object); //to deduce the object's type from its class - - if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_ITEM)) - { - MakeItemMenu (); - } - if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_GROUP)) - { - MakeGroupMenu(); - } - if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_ANCHOR)) - { - MakeAnchorMenu(); - } - if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_IMAGE)) - { - MakeImageMenu(); - } - if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_SHAPE)) - { - MakeShapeMenu(); - } - if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_TEXT)) - { - MakeTextMenu(); - } +// GObjectClass *klass = G_OBJECT_GET_CLASS(_object); //to deduce the object's type from its class +// +// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_ITEM)) +// { +// MakeItemMenu (); +// } +// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_GROUP)) +// { +// MakeGroupMenu(); +// } +// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_ANCHOR)) +// { +// MakeAnchorMenu(); +// } +// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_IMAGE)) +// { +// MakeImageMenu(); +// } +// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_SHAPE)) +// { +// MakeShapeMenu(); +// } +// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_TEXT)) +// { +// MakeTextMenu(); +// } + + if (SP_IS_ITEM(_object)) { + MakeItemMenu(); + } + + if (SP_IS_GROUP(_object)) { + MakeGroupMenu(); + } + + if (SP_IS_ANCHOR(_object)) { + MakeAnchorMenu(); + } + + if (SP_IS_IMAGE(_object)) { + MakeImageMenu(); + } + + if (SP_IS_SHAPE(_object)) { + MakeShapeMenu(); + } + + if (SP_IS_TEXT(_object)) { + MakeTextMenu(); + } } void ContextMenu::MakeItemMenu (void) @@ -1986,6 +2009,15 @@ void ContextMenu::MakeImageMenu (void) mi->set_sensitive(FALSE); } + /* Trace Pixel Art */ + mi = manage(new Gtk::MenuItem(_("Trace Pixel Art"),1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageTracePixelArt)); + mi->show(); + insert(*mi,positionOfLastDialog++); + if (_desktop->selection->isEmpty()) { + mi->set_sensitive(FALSE); + } + /* Embed image */ if (Inkscape::Verb::getbyid( "org.ekips.filter.embedselectedimages" )) { mi = manage(new Gtk::MenuItem(C_("Context menu", "Embed Image"))); @@ -2103,6 +2135,12 @@ void ContextMenu::ImageTraceBitmap(void) _desktop->_dlg_mgr->showDialog("Trace"); } +void ContextMenu::ImageTracePixelArt(void) +{ + inkscape_dialogs_unhide(); + _desktop->_dlg_mgr->showDialog("PixelArt"); +} + void ContextMenu::ImageEmbed(void) { if (_desktop->selection->isEmpty()) { diff --git a/src/interface.h b/src/interface.h index 13fbaf9ac..215a3bfc9 100644 --- a/src/interface.h +++ b/src/interface.h @@ -239,6 +239,11 @@ class ContextMenu : public Gtk::Menu void ImageTraceBitmap(void); /** + * callback, is executed on clicking the "Trace Pixel Art" menu entry + */ + void ImageTracePixelArt(void); + + /** * callback, is executed on clicking the "Extract Image" menu entry */ void ImageExtract(void); diff --git a/src/io/CMakeLists.txt b/src/io/CMakeLists.txt index 8f8355c03..ef577b014 100644 --- a/src/io/CMakeLists.txt +++ b/src/io/CMakeLists.txt @@ -2,7 +2,6 @@ set(io_SRC base64stream.cpp bufferstream.cpp - ftos.cpp gzipstream.cpp inkjar.cpp inkscapestream.cpp @@ -16,7 +15,6 @@ set(io_SRC # Headers base64stream.h bufferstream.h - ftos.h gzipstream.h inkjar.h inkscapestream.h diff --git a/src/io/Makefile_insert b/src/io/Makefile_insert index 804c9575a..35119ec7b 100644 --- a/src/io/Makefile_insert +++ b/src/io/Makefile_insert @@ -5,8 +5,6 @@ ink_common_sources += \ io/base64stream.cpp \ io/bufferstream.cpp \ io/bufferstream.h \ - io/ftos.cpp \ - io/ftos.h \ io/gzipstream.cpp \ io/gzipstream.h \ io/inkjar.cpp \ diff --git a/src/io/ftos.cpp b/src/io/ftos.cpp deleted file mode 100644 index d0764d86c..000000000 --- a/src/io/ftos.cpp +++ /dev/null @@ -1,484 +0,0 @@ -/* ////////////////////////////////////////////////////////////////////// -// ftos.cc -// -// Copyright (c) 1996-2003 Bryce W. Harrington [bryce at osdl dot org] -// -//----------------------------------------------------------------------- -// License: This code may be used by anyone for any purpose -// so long as the copyright notices and this license -// statement remains attached. -//----------------------------------------------------------------------- -// -// string ftos(double val[, char mode[, int sigfig[, int precision[, int options]]]]) -// -// DESCRIPTION -// This routine is intended to replace the typical use of sprintf for -// converting floating point numbers into strings. -// -// To one-up sprintf, an additional mode was created - 'h' mode - -// which produces numbers in 'engineering notation' - exponents are -// always shown in multiples of 3. To non-engineers this mode is -// probably irrelevant, but for engineers (and scientists) it is SOP. -// -// One other new feature is an option to use 'x10^' instead of the -// conventional 'E' for exponental notation. This is entirely for -// aesthetics since numbers in the 'x10^' form cannot be used as -// inputs for most programs. -// -// For most cases, the routine can simply be used with the defaults -// and acceptable results will be produced. No fill zeros or trailing -// zeros are shown, and exponential notation is only used for numbers -// greater than 1e6 or less than 1e-3. -// -// The one area where sprintf may surpass this routine is in width control. -// No provisions are made in this routine to restrict a number to a -// certain number of digits (thus allowing the number to be constrained -// to an 8 space column, for instance.) Along with this, it does not -// support pre-padding a number with zeros (e.g., '5' -> '0005') and will -// not post-pad a number with spaces (i.e., allow left-justification.) -// -// If width control is this important, then the user will probably want to -// use the stdio routines, which really is well suited for outputting -// columns of data with a brief amount of code. -// -// PARAMETERS -// val - number to be converted -// mode - can be one of four possible values. Default is 'g' -// -// e: Produces numbers in scientific notation. One digit -// is shown on the left side of the decimal, the rest -// on the right, and the exponential is always shown. -// EXAMPLE: 1.04e-4 -// -// f: Produces numbers with fixed format. Number is shown -// exact, with no exponent. -// EXAMPLE: 0.000104 -// -// g: If val is greater than 1e6 or less than 1e-3 it will -// be shown in 'e' format, otherwise 'f' format will be -// used. -// -// h: Produces numbers in engineering format. Result is -// identical to 'f' format for numbers between 1 and -// 1e3, otherwise, the number is shown such that it -// always begins with a nonzero digit on the left side -// (unless number equals zero), and the exponential is -// a multiple of 3. -// EXAMPLE: 104e-6 -// -// If the mode is expressed as a capital letter (e.g., 'F') -// then the exponential part of the number will also be -// capitalized (e.g., '1E6' or '1X10^6'.) -// -// sigfig - the number of significant figures. These are the digits -// that are "retained". For example, the following numbers -// all have four sigfigs: -// 1234 12.34 0.0001234 1.234e-10 -// the last digit shown will be rounded in the standard -// manner (down if the next digit is less than 5, up otherwise.) -// -// precision - the number of digits to show to the right of the decimal. -// For example, all of the following numbers have precisions -// of 2: -// 1234.00 12.34 0.00 1.23e-10 123.40e-12 -// -// options - several options are allowed to control the look of the -// output. -// -// FORCE_DECIMAL - require the decimal point to be shown for -// numbers that do not have any fractional digits (or that -// have a precision set to zero) -// EXAMPLE: 1.e6 -// FORCE_EXP_ZERO - pad the 10's zero in exponent if necessary -// EXAMPLE: 1e06 -// FORCE_HUNDRED_EXP_ZERO - pad the 100's zero in exponent if -// necessary. Also pads 10's zero in exponent if necessary. -// EXAMPLE: 1e006 -// FORCE_EXP_PLUS - show the '+' in the exponent if exponent -// is used. -// EXAMPLE: 1e+6 -// FORCE_EXP - force the output to display the exponent -// EXAMPLE: 0e0 -// FORCE_X10 - use x10^ instead of E -// EXAMPLE: 1x10^6 -// FORCE_PLUS - force output of the '+' for positive numbers -// EXAMPLE: +1e6 -// -// Options can be combined using the usual OR method. For -// example, -// -// ftos(123.456, 'f', -1, -1, FORCE_PLUS | FORCE_X10 | FORCE_EXP) -// -// gives "+123.456x10^0" -// -// RETURN VALUE -// The string representation of the number is returned from the routine. -// The ANSI C++ Standard "string" class was used for several important -// reasons. First, because the string class manages it's own space, the -// ftos routine does not need to concern itself with writing to unallocated -// areas of memory or with handling memory reallocation internally. Second, -// it allows return of an object, not a pointer to an object; this may not -// be as efficient, but it is cleaner and safer than the alternative. Third, -// the routine's return value can be directly assigned to a variable, i.e. -// string var = ftos(3.1415); -// which makes code much easier to comprehend and modify. -// -// Internally, the ftos routine uses fairly typical string operators (=, +=, -// +, etc.) which pretty much any other flavor of string class will define as -// well. Thus if one does not have access to the ANSI C++ Standard string -// class, the user can substitute another with little difficulty. (If the -// alternate class is not named "string" then redefine "string" to whatever -// you wish to use. For example, -// #define string CString -// -// November 1996 - Bryce Harrington -// Created ftoa and ftos -// -// December 1996 - Bryce Harrington -// Added engineering notation mode, added sigfig capability, added -// significant debug code, added options, thoroughly debugged and -// tested the code. -// -// -// June 1999 - Bryce Harrington -// Modified to run on Linux for WorldForge -// -// March 2003 - Bryce Harrington -// Removed DTAG() macros - use of fprintf(stderr,...) instead -// Broke out round/itos/ftos into separate files -// Removed curses bits -// -/////////////////////////////////////////////////////////////////////// */ - - -// This is the routine used for converting a floating point into a string -// This may be included in stdlib.h on some systems and may conflict. -// Let me know your system & etc. so I can properly #ifdef this, but -// try commenting the following four lines out if you run into conflicts. -// extern "C" { -// char* -// ecvt (double val, size_t ndigit, int *decpt, int *sign); -// } - -using namespace std; - -#ifndef HAS_ECVT -#include <glib.h> -#endif - - -#include "ftos.h" - - -// This routine counts from the end of a string like '10229000' to find the index -// of the first non-'0' character (5 would be returned for the above number.) -static int countDigs(char *p) -{ - int length =0; - while (*(p+length)!='\0') length++; // Count total length - while (length>0 && *(p+length-1)=='0') length--; // Scan backwards for a non-'0' - return length; -} - -// This routine determines how many digits make up the left hand -// side of the number if the abs value of the number is greater than 1, or the -// digits that make up the right hand side if the abs value of the number -// is between 0 and 1. Returns 1 if v==0. Return value is positive for numbers -// greater than or equal to 1, negative for numbers less than 0.1, and zero for -// numbers between 0.1 and 1. -static int countLhsDigits(double v) -{ - if (v<0) v = -v; // Take abs value - else if (v==0) return 1; // Special case if v==0 - - int n=0; - for (; v<0.1; v*=10) // Count digits on right hand side (l.t. 0.1) - { n--; } - for (; v>=1; v/=10) // Count digits on left hand side (g.e. 1.0) - { n++; } - return n; -} - -// This is the routine that does the work of converting the number into a string. -string ftos(double val, char mode, int sigfig, int precision, int options) -{ - // Parse the options to a more usable form - // These options allow the user to control some of the ornaments on the - // number that is output. By default they are all false. Turning them - // on helps to "fix" the format of the number so it lines up in columns - // better. - // - require the decimal point to be shown for numbers that do not have - // any fractional digits (or that have a precision set to zero - bool forceDecimal = (options & FORCE_DECIMAL); - // - show the 10's and 100's zero in exponent - bool forceExpZero = (options & FORCE_EXP_ZERO); - bool forceHundredExpZero = (options & FORCE_HUNDRED_EXP_ZERO); - // - show the '+' in the exponent if exponent is used - bool forceExpPlus = (options & FORCE_EXP_PLUS); - // - force the output to display the exponent - bool forceExponent = (options & FORCE_EXP); - // - use x10^ instead of E - bool forcex10 = (options & FORCE_X10); - // - force output of the '+' for positive numbers - bool forcePlus = (options & FORCE_PLUS); - -#ifdef DEBUG - fprintf(stderr, "Options: "); - fprintf(stderr, " %4s = %s ", "x10", (forcex10 ? "on" : "off" )); - fprintf(stderr, " %4s = %s ", ".", (forceDecimal ? "on" : "off" )); - fprintf(stderr, " %4s = %s ", "e0", (forceExpZero ? "on" : "off" )); - fprintf(stderr, " %4s = %s ", "e00", (forceHundredExpZero ? "on" : "off" )); - fprintf(stderr, " %4s = %s ", "e+", (forceExpPlus ? "on" : "off" )); - fprintf(stderr, " %4s = %s ", "e", (forceExponent ? "on" : "off" )); - fprintf(stderr, " %4s = %s \n", "+#", (forcePlus ? "on" : "off" )); -#endif - - // - exponent usage - bool useExponent = false; - - // Determine the case for the 'e' (if used) - char E = (forcex10)? 'x' : 'e'; - if (g_ascii_isupper(mode)) { - E = g_ascii_toupper(E); - mode = g_ascii_tolower(mode); - } - - // Determine how many decimals we're interested in - int L = countLhsDigits(val); - -#ifdef DEBUG - fprintf(stderr, "*** L is %s\n", itos(L).c_str()); -#endif - - int count = 0; - if (sigfig==0) // bad input - don't want any sigfigs??!! - return ""; - else if (precision>=0) { // Use fixed number of decimal places - count = precision; - if (mode == 'e') count += 1; - else if (mode == 'f') count += L; - else if (mode == 'g') count += (L>6 || L<-3)? 1 : L; - else if (mode == 'h') count += (L>0)? ((L-1)%3+1) : (L%3+3); - if (sigfig>0) count = (sigfig > count)? count : sigfig; // Use sigfig # if it means more decimal places - } - else if (sigfig>0) // Just use sigfigs - count = sigfig; - else // prec < 0 and sigfig < 0 - count = 10; -#ifdef DEBUG - fprintf(stderr, "*** count is %s\n", itos(count).c_str()); -#endif - - // Get number's string rep, sign, and exponent - int sign = 0; - int decimal=0; - -#ifdef HAS_ECVT - char *p = ecvt(val, count, &decimal, &sign); -#else - char *p = (char *) g_strdup_printf("%.0f", val); - // asprintf(&p, "%.0f", val); -#endif - -#ifdef DEBUG - fprintf(stderr, "*** string rep is %s\n", p); - fprintf(stderr, "*** decimal is %s\n", itos(decimal).c_str()); - fprintf(stderr, "*** sign is %s\n", itos(sign).c_str()); -#endif - - // Count the number of relevant digits in the resultant number - int dig = countDigs(p); - if (dig < sigfig) dig = sigfig; - -#ifdef DEBUG - fprintf(stderr, "*** digs is %s\n", itos(dig).c_str()); -#endif - - // Determine number of digits to put on left side of the decimal point - int lhs=0; - // For 'g' mode, decide whether to use 'e' or 'f' format. - if (mode=='g') mode = (decimal>6 || decimal<-3)? 'e' : 'f'; - switch (mode) { - case 'e': - lhs = 1; // only need one char on left side - useExponent = true; // force exponent use - break; - - case 'f': - lhs = (decimal<1)? 1 : decimal; - // use one char on left for num < 1, - // otherwise, use the number of decimal places. - useExponent = false; // don't want exponent for 'f' format - break; - - case 'h': - if (val==0.0) // special case for if value is zero exactly. - lhs = 0; // this prevents code from returning '000.0' - else - lhs = (decimal<=0)? (decimal)%3 + 3 : (decimal-1)%3+1; - useExponent = !(lhs==decimal); // only use exponent if we really need it - break; - - default: - g_free(p); - return "**bad mode**"; - } - -#ifdef DEBUG - fprintf(stderr, "*** lhs is %s\n", itos(lhs).c_str()); -#endif - - // Figure out the number of digits to show in the right hand side - int rhs=0; - if (precision>=0) - rhs = precision; - else if (val == 0.0) - rhs = 0; - else if (useExponent || decimal>0) - rhs = dig-lhs; - else - rhs = dig-decimal; - - // can't use a negative rhs value, so turn it to zero if that is the case - if (rhs<0) rhs = 0; - -#ifdef DEBUG - fprintf(stderr, "*** rhs is %s\n", itos(rhs).c_str()); -#endif - - // Determine the exponent - int exponent = decimal - lhs; - if (val==0.0) exponent=0; // prevent zero from getting an exponent -#ifdef DEBUG - fprintf(stderr, "*** exponent is %s\n", itos(exponent).c_str()); -#endif - - string ascii; - - // output the sign - if (sign) ascii += "-"; - else if (forcePlus) ascii += "+"; - - // output the left hand side - if (!useExponent && decimal<=0) // if fraction, put the 0 out front - ascii += '0'; - else // is either exponential or >= 1, so write the lhs - for (; lhs>0; lhs--) - ascii += (*p)? *p++ : int('0'); // now fill in the numbers before decimal - -#ifdef DEBUG - fprintf(stderr, "*** ascii + sign + lhs is %s\n", ascii.c_str()); -#endif - - // output the decimal point - if (forceDecimal || rhs>0) - ascii += '.'; - - // output the right hand side - if (!useExponent && rhs>0) // first fill in zeros after dp and before numbers - while (decimal++ <0 && rhs-->0) - ascii += '0'; - for (; rhs>0 ; rhs--) // now fill in the numbers after decimal - ascii += (*p)? *p++ : int('0'); - -#ifdef DEBUG - fprintf(stderr, "*** ascii + . + rhs is %s\n", ascii.c_str()); -#endif - - if (forceExponent || useExponent) // output the entire exponent if required - { - ascii += E; // output the E or X - if (forcex10) ascii += "10^"; // if using 'x10^' format, output the '10^' part - - // output the exponent's sign - if (exponent < 0) { // Negative exponent - exponent = -exponent; // make exponent positive if needed - ascii += '-'; // output negative sign - } - else if (forceExpPlus) // We only want the '+' if it is asked for explicitly - ascii += '+'; - - // output the exponent - if (forceHundredExpZero || exponent >= 100) - ascii += ( (exponent/100) % 10 + '0' ); - if (forceHundredExpZero || forceExpZero || exponent >= 10) - ascii += ( (exponent/10) % 10 + '0' ); - ascii += ( exponent % 10 + '0' ); - -#ifdef DEBUG - fprintf(stderr, "*** ascii + exp is %s\n", ascii.c_str()); -#endif - } - -#ifdef DEBUG - fprintf(stderr, "*** End of ftos with ascii = %s\n", ascii.c_str()); -#endif - /* finally, we can return */ - g_free(p); - return ascii; -} - -#ifdef TESTFTOS - -int main() -{ - cout << "Normal (g): " << endl; - cout << "1.0 = " << ftos(1.0) << endl; - cout << "42 = " << ftos(42) << endl; - cout << "3.141 = " << ftos(3.141) << endl; - cout << "0.01 = " << ftos(0.01) << endl; - cout << "1.0e7 = " << ftos(1.0e7) << endl; - cout << endl; - - cout << "Scientific (e): " << endl; - cout << "1.0 = " << ftos(1.0, 'e') << endl; - cout << "42 = " << ftos(42, 'e') << endl; - cout << "3.141 = " << ftos(3.141, 'e') << endl; - cout << "0.01 = " << ftos(0.01, 'e') << endl; - cout << "1.0e7 = " << ftos(1.0e7, 'e') << endl; - cout << endl; - - cout << "Fixed (f): " << endl; - cout << "1.0 = " << ftos(1.0, 'f') << endl; - cout << "42 = " << ftos(42, 'f') << endl; - cout << "3.141 = " << ftos(3.141, 'f') << endl; - cout << "0.01 = " << ftos(0.01, 'f') << endl; - cout << "1.0e7 = " << ftos(1.0e7, 'f') << endl; - cout << endl; - - cout << "Engineering (h): " << endl; - cout << "1.0 = " << ftos(1.0, 'h') << endl; - cout << "42 = " << ftos(42, 'h') << endl; - cout << "3.141 = " << ftos(3.141, 'h') << endl; - cout << "0.01 = " << ftos(0.01, 'h') << endl; - cout << "1.0e7 = " << ftos(1.0e7, 'h') << endl; - cout << endl; - - cout << "Sigfigs: " << endl; - cout << "2 sf = " << ftos(1234, 'g', 2) << " " - << ftos(12.34, 'g', 2) << " " - << ftos(0, 'g', 2) << " " - << ftos(123.4e-11, 'g', 2) << endl; - cout << "4 sf = " << ftos(1234, 'g', 4) << " " - << ftos(12.34, 'g', 4) << " " - << ftos(0, 'g', 4) << " " - << ftos(123.4e-11, 'g', 4) << endl; - cout << "8 sf = " << ftos(1234, 'g', 8) << " " - << ftos(12.34, 'g', 8) << " " - << ftos(0, 'g', 8) << " " - << ftos(123.4e-11, 'g', 8) << endl; - cout << endl; - - cout << "x10 mode: " << endl; - cout << "1234 = " << ftos(1234, 'e', 4, -1, FORCE_X10 | FORCE_EXP) << endl; - cout << "1.01e10 = " << ftos(1.01e10, 'h', -1, -1, FORCE_X10 | FORCE_EXP) << endl; - cout << endl; - - cout << "itos tests..." << endl; - cout << "42 = " << itos(42) << endl; - cout << endl; - - return 0; -} - -#endif // TESTFTOS diff --git a/src/io/ftos.h b/src/io/ftos.h deleted file mode 100644 index 888def639..000000000 --- a/src/io/ftos.h +++ /dev/null @@ -1,54 +0,0 @@ -///////////////////////////////////////////////////////////////////////// -// ftos.h -// -// Copyright (c) 1996 Bryce W. Harrington - bryce@neptune.net -// -//----------------------------------------------------------------------- -// License: This code may be used by anyone for any purpose -// so long as the copyright notices and this license -// statement remains attached. -//----------------------------------------------------------------------- -// Description of file contents -// 1993 - Bryce Harrington -// Created initial ftoa routine -// -// October 1996 - Bryce Harrington -// Created itos from code taken from Kernighan & Ritchie -// _The C Programming Language_ 2nd edition -// -// November 1996 - Bryce Harrington -// Created new ftoa and ftos -// -// July 1999 - Bryce Harrington -// Ported to Linux for use in WorldForge -// -// January 2000 - Karsten Laux klaux@rhrk.uni-kl.de -// added ultos - convering ulong to string -// -///////////////////////////////////////////////////////////////////////// -#ifndef ftos_h -#define ftos_h - -#include <string> - -// ftos routine -const int FORCE_X10 = (1 << 0); -const int FORCE_DECIMAL = (1 << 1); -const int FORCE_EXP_ZERO = (1 << 2); -const int FORCE_HUNDRED_EXP_ZERO = (1 << 3); -const int FORCE_EXP_PLUS = (1 << 4); -const int FORCE_EXP = (1 << 5); -const int FORCE_PLUS = (1 << 6); - -/// -std::string ftos(double val, char mode='g', int sigfig=-1, int precision=-1, int options=0); -/// -std::string itos(int n); -/// -std::string ultos(unsigned long n); -/// -double rround(double x); // use rounding rule -> x to nearest int. -/// -double rround(double x, int k); // round to the kth place - -#endif // ftos_h diff --git a/src/knotholder.cpp b/src/knotholder.cpp index a1ee3082b..32ba9075b 100644 --- a/src/knotholder.cpp +++ b/src/knotholder.cpp @@ -63,13 +63,16 @@ KnotHolder::KnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFun g_print ("Error! Throw an exception, please!\n"); } - g_object_ref(G_OBJECT(item)); // TODO: is this still needed after C++-ification? + //g_object_ref(G_OBJECT(item)); // TODO: is this still needed after C++-ification? + sp_object_ref(item); sizeUpdatedConn = ControlManager::getManager().connectCtrlSizeChanged(sigc::mem_fun(*this, &KnotHolder::updateControlSizes)); } KnotHolder::~KnotHolder() { - g_object_unref(G_OBJECT(item)); + //g_object_unref(G_OBJECT(item)); + sp_object_unref(item); + for (std::list<KnotHolderEntity *>::iterator i = entity.begin(); i != entity.end(); ++i) { delete (*i); @@ -128,7 +131,7 @@ KnotHolder::knot_clicked_handler(SPKnot *knot, guint state) } if (SP_IS_SHAPE(saved_item)) { - SP_SHAPE(saved_item)->setShape(); + SP_SHAPE(saved_item)->set_shape(); } knot_holder->update_knots(); @@ -177,7 +180,7 @@ KnotHolder::knot_moved_handler(SPKnot *knot, Geom::Point const &p, guint state) } if (SP_IS_SHAPE (item)) { - SP_SHAPE (item)->setShape(); + SP_SHAPE (item)->set_shape(); } this->update_knots(); diff --git a/src/libdepixelize/CMakeLists.txt b/src/libdepixelize/CMakeLists.txt new file mode 100644 index 000000000..e05849e29 --- /dev/null +++ b/src/libdepixelize/CMakeLists.txt @@ -0,0 +1,20 @@ + +set(libdepixelize_SRC + kopftracer2011.cpp + + # ------- + # Headers + kopftracer2011.h + splines.h + + priv/branchless.h + priv/colorspace.h + priv/homogeneoussplines.h + priv/iterator.h + priv/pixelgraph.h + priv/point.h + priv/simplifiedvoronoi.h + priv/splines.h +) + +add_inkscape_lib(depixelize_LIB "${libdepixelize_SRC}") diff --git a/src/libdepixelize/Makefile_insert b/src/libdepixelize/Makefile_insert new file mode 100644 index 000000000..75b19bf5c --- /dev/null +++ b/src/libdepixelize/Makefile_insert @@ -0,0 +1,11 @@ +## Makefile.am fragment sourced by src/Makefile.am. + +libdepixelize/all: libdepixelize/libdepixelize.a + +libdepixelize/clean: + rm -f libdepixelize/libdepixelize.a $(libdepixelize_libdepixelize_a_OBJECTS) + +libdepixelize_libdepixelize_a_SOURCES = \ + libdepixelize/kopftracer2011.cpp \ + libdepixelize/kopftracer2011.h \ + libdepixelize/splines.h diff --git a/src/libdepixelize/kopftracer2011.cpp b/src/libdepixelize/kopftracer2011.cpp new file mode 100644 index 000000000..26ad8863b --- /dev/null +++ b/src/libdepixelize/kopftracer2011.cpp @@ -0,0 +1,470 @@ +/* This file is part of the libdepixelize project + Copyright (C) 2013 VinÃcius dos Santos Oliveira <vini.ipsmaker@gmail.com> + + GNU Lesser General Public License Usage + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + You should have received a copy of the GNU Lesser General Public License + along with this library. If not, see <http://www.gnu.org/licenses/>. + + GNU General Public License Usage + Alternatively, this library may be used under the terms of the GNU General + Public License as published by the Free Software Foundation, either version + 2 of the License, or (at your option) any later version. + You should have received a copy of the GNU General Public License along with + this library. If not, see <http://www.gnu.org/licenses/>. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. +*/ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +// Build fix under Inkscape build tree +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif + +#include <utility> +#include <algorithm> +#include "kopftracer2011.h" +#include "priv/colorspace.h" +#include "priv/homogeneoussplines.h" +#include "priv/branchless.h" +#include "priv/splines.h" +#include "priv/iterator.h" + +namespace Tracer { +namespace Heuristics { + +int curves(const PixelGraph &graph, PixelGraph::const_iterator a, + PixelGraph::const_iterator b); +bool islands(PixelGraph::const_iterator a, PixelGraph::const_iterator b); + +struct SparsePixels +{ + enum Diagonal { + /** + * From (first) the top left corner to (second) the bottom right. + */ + MAIN_DIAGONAL = 0, + /** + * From (first) the top right to (second) the bottom left. + */ + SECONDARY_DIAGONAL = 1 + }; + + typedef std::pair<PixelGraph::const_iterator, PixelGraph::const_iterator> + Edge; + typedef std::pair<Edge, int> EdgeWeight; + + void operator()(const PixelGraph &graph, unsigned radius); + + static bool similar_colors(PixelGraph::const_iterator n, + const guint8 (&a)[4], const guint8 (&b)[4]); + + /* + * Precondition: Must be filled according to Diagonal enum. + */ + EdgeWeight diagonals[2]; +}; + +} // namespace Heuristics + +Splines Kopf2011::to_voronoi(const std::string &filename, + const Options &options) +{ + return to_voronoi(Gdk::Pixbuf::create_from_file(filename), options); +} + +Splines Kopf2011::to_voronoi(const Glib::RefPtr<Gdk::Pixbuf const> &buf, + const Options &options) +{ + return Splines(_voronoi<Precision>(buf, options)); +} + +Splines Kopf2011::to_splines(const std::string &filename, + const Options &options) +{ + return to_splines(Gdk::Pixbuf::create_from_file(filename), options); +} + +Splines Kopf2011::to_splines(const Glib::RefPtr<Gdk::Pixbuf const> &buf, + const Options &options) +{ + HomogeneousSplines<Precision> splines(_voronoi<Precision>(buf, options)); + return Splines(splines, options.optimize, options.nthreads); +} + +template<class T> +SimplifiedVoronoi<T> Kopf2011::_voronoi(const Glib::RefPtr<Gdk::Pixbuf const> &buf, + const Options &options) +{ + PixelGraph graph(buf); + + /*if ( !graph.width() || !graph.height() ) + return;*/ + +#ifndef NDEBUG + graph.checkConsistency(); +#endif + + // This step could be part of the initialization of PixelGraph + // and decrease the necessary number of passes + graph.connectAllNeighbors(); + +#ifndef NDEBUG + graph.checkConsistency(); +#endif + + // This step can't be part of PixelGraph initilization without adding some + // cache misses due to random access patterns that might be injected + _disconnect_neighbors_with_dissimilar_colors(graph); + +#ifndef NDEBUG + graph.checkConsistency(); +#endif + + // This and below steps must be executed in separate. + // Otherwise, there will be colateral effects due to misassumption about the + // data being read. + _remove_crossing_edges_safe(graph); + +#ifndef NDEBUG + graph.checkConsistency(); +#endif + + _remove_crossing_edges_unsafe(graph, options); + +#ifndef NDEBUG + graph.checkConsistency(); +#endif + + return SimplifiedVoronoi<T>(graph); +} + +// TODO: move this function (plus connectAllNeighbors) to PixelGraph constructor +inline void +Kopf2011::_disconnect_neighbors_with_dissimilar_colors(PixelGraph &graph) +{ + using colorspace::similar_colors; + for ( PixelGraph::iterator it = graph.begin(), end = graph.end() ; it != end + ; ++it ) { + if ( it->adj.top ) + it->adj.top = similar_colors(it->rgba, (it - graph.width())->rgba); + if ( it->adj.topright ) { + it->adj.topright + = similar_colors(it->rgba, (it - graph.width() + 1)->rgba); + } + if ( it->adj.right ) + it->adj.right = similar_colors(it->rgba, (it + 1)->rgba); + if ( it->adj.bottomright ) { + it->adj.bottomright + = similar_colors(it->rgba, (it + graph.width() + 1)->rgba); + } + if ( it->adj.bottom ) { + it->adj.bottom + = similar_colors(it->rgba, (it + graph.width())->rgba); + } + if ( it->adj.bottomleft ) { + it->adj.bottomleft + = similar_colors(it->rgba, (it + graph.width() - 1)->rgba); + } + if ( it->adj.left ) + it->adj.left = similar_colors(it->rgba, (it - 1)->rgba); + if ( it->adj.topleft ) { + it->adj.topleft = similar_colors(it->rgba, + (it - graph.width() - 1)->rgba); + } + } +} + +/** + * This method removes crossing edges if the 2x2 block is fully connected. + * + * In this case the two diagonal connections can be safely removed without + * affecting the final result. + * + * \TODO: It should remember/cache who are the unsafe crossing edges? + */ +inline void Kopf2011::_remove_crossing_edges_safe(PixelGraph &graph) +{ + if ( graph.width() < 2 || graph.height() < 2 ) + return; + + PixelGraph::iterator it = graph.begin(); + for ( int i = 0 ; i != graph.height() - 1 ; ++i, ++it ) { + for ( int j = 0 ; j != graph.width() - 1 ; ++j, ++it ) { + // this <-> right + if ( !it->adj.right ) + continue; + + // this <-> down + if ( !it->adj.bottom ) + continue; + + PixelGraph::iterator down_right = it + graph.width() + 1; + + // down_right <-> right + if ( !down_right->adj.top ) + continue; + + // down_right <-> down + if ( !down_right->adj.left ) + continue; + + // main diagonal + // this <-> down_right + it->adj.bottomright = 0; + down_right->adj.topleft = 0; + + // secondary diagonal + // right <-> down + (it + 1)->adj.bottomleft = 0; + (it + graph.width())->adj.topright = 0; + } + } +} + +/** + * This method removes crossing edges using the heuristics. + */ +inline +void Kopf2011::_remove_crossing_edges_unsafe(PixelGraph &graph, + const Options &options) +{ + if ( graph.width() < 2 || graph.height() < 2 ) + return; + + // Iterate over the graph, 2x2 blocks at time + PixelGraph::iterator it = graph.begin(); + for (int i = 0 ; i != graph.height() - 1 ; ++i, ++it ) { + for ( int j = 0 ; j != graph.width() - 1 ; ++j, ++it ) { + using std::pair; + using std::make_pair; + + typedef pair<PixelGraph::iterator, PixelGraph::iterator> Edge; + typedef pair<Edge, int> EdgeWeight; + + EdgeWeight diagonals[2] = { + make_pair(make_pair(it, graph.nodeBottomRight(it)), 0), + make_pair(make_pair(graph.nodeRight(it), graph.nodeBottom(it)), + 0) + }; + + // Check if there are crossing edges + if ( !diagonals[0].first.first->adj.bottomright + || !diagonals[1].first.first->adj.bottomleft ) { + continue; + } + + // Compute weights + for ( int i = 0 ; i != 2 ; ++i ) { + // Curves and islands heuristics + PixelGraph::const_iterator a = diagonals[i].first.first; + PixelGraph::const_iterator b = diagonals[i].first.second; + + diagonals[i].second += Heuristics::curves(graph, a, b) + * options.curvesMultiplier; + + diagonals[i].second += Heuristics::islands(a, b) + * options.islandsWeight; + } + + { + // Sparse pixels heuristic + Heuristics::SparsePixels sparse_pixels; + + for ( int i = 0 ; i != 2 ; ++i ) + sparse_pixels.diagonals[i] = diagonals[i]; + + sparse_pixels(graph, options.sparsePixelsRadius); + + for ( int i = 0 ; i != 2 ; ++i ) { + diagonals[i].second += sparse_pixels.diagonals[i].second + * options.sparsePixelsMultiplier; + } + } + + // Remove edges with lower weight + if ( diagonals[0].second > diagonals[1].second ) { + diagonals[1].first.first->adj.bottomleft = 0; + diagonals[1].first.second->adj.topright = 0; + } else if ( diagonals[0].second < diagonals[1].second ) { + diagonals[0].first.first->adj.bottomright = 0; + diagonals[0].first.second->adj.topleft = 0; + } else { + diagonals[0].first.first->adj.bottomright = 0; + diagonals[0].first.second->adj.topleft = 0; + diagonals[1].first.first->adj.bottomleft = 0; + diagonals[1].first.second->adj.topright = 0; + } + } + } +} + +inline int Heuristics::curves(const PixelGraph &graph, + PixelGraph::const_iterator a, + PixelGraph::const_iterator b) +{ + int count = 1; + ToPtr<PixelGraph::Node> to_ptr; + ToIter<PixelGraph::Node> to_iter(graph.begin()); + + // b -> a + // and then a -> b + for ( int i = 0 ; i != 2 ; ++i ) { + PixelGraph::const_iterator it = i ? a : b; + PixelGraph::const_iterator prev = i ? b : a; + int local_count = 0; + + // Used to avoid inifinite loops in circular-like edges + const PixelGraph::const_iterator initial = it; + + while ( it->adjsize() == 2 ) { + ++local_count; + + // Iterate to next + { + // There are only two values that won't be zero'ed + // and one of them has the same value of prev + guintptr aux = guintptr(to_ptr(it)); + aux = (it->adj.top + * guintptr(to_ptr(graph.nodeTop(it)))) + + (it->adj.topright + * guintptr(to_ptr(graph.nodeTopRight(it)))) + + (it->adj.right + * guintptr(to_ptr(graph.nodeRight(it)))) + + (it->adj.bottomright + * guintptr(to_ptr(graph.nodeBottomRight(it)))) + + (it->adj.bottom + * guintptr(to_ptr(graph.nodeBottom(it)))) + + (it->adj.bottomleft + * guintptr(to_ptr(graph.nodeBottomLeft(it)))) + + (it->adj.left + * guintptr(to_ptr(graph.nodeLeft(it)))) + + (it->adj.topleft + * guintptr(to_ptr(graph.nodeTopLeft(it)))) + - guintptr(to_ptr(prev)); + prev = it; + it = to_iter(reinterpret_cast<PixelGraph::Node const*>(aux)); + } + + // Break infinite loops + if ( it == initial ) + return local_count; + } + count += local_count; + } + + return count; +} + +inline void Heuristics::SparsePixels::operator ()(const PixelGraph &graph, + unsigned radius) +{ + if ( !graph.width() || !graph.height() ) + return; + + // Clear weights + for ( int i = 0 ; i != 2 ; ++i ) + diagonals[i].second = 0; + + if ( !radius ) + return; + + // Fix radius/bounds + { + unsigned x = graph.toX(diagonals[MAIN_DIAGONAL].first.first); + unsigned y = graph.toY(diagonals[MAIN_DIAGONAL].first.first); + unsigned minor = std::min(x, y); + unsigned displace = radius - 1; + + if ( displace > minor ) { + displace = minor; + radius = displace + 1; + } + + displace = radius; + + if ( x + displace >= graph.width() ) { + displace = unsigned(graph.width()) - x - 1; + radius = displace; + } + + if ( y + displace >= graph.height() ) { + displace = unsigned(graph.height()) - y - 1; + radius = displace; + } + } + + if ( !radius ) + return; + + // Iterate over nodes and count them + { + PixelGraph::const_iterator it = diagonals[MAIN_DIAGONAL].first.first; + for ( unsigned i = radius - 1 ; i ; --i ) + it = graph.nodeTopLeft(it); + + bool invert = false; + for ( unsigned i = 0 ; i != 2 * radius ; ++i ) { + for ( unsigned j = 0 ; j != 2 * radius ; ++j ) { + for ( int k = 0 ; k != 2 ; ++k ) { + diagonals[k].second + += similar_colors(it, diagonals[k].first.first->rgba, + diagonals[k].first.second->rgba); + } + it = (invert ? graph.nodeLeft(it) : graph.nodeRight(it)); + } + it = (invert ? graph.nodeRight(it) : graph.nodeLeft(it)); + + + invert = !invert; + it = graph.nodeBottom(it); + } + } + + int minor = std::min(diagonals[0].second, diagonals[1].second); + for ( int i = 0 ; i != 2 ; ++i ) + diagonals[i].second -= minor; + + std::swap(diagonals[0].second, diagonals[1].second); +} + +inline bool +Heuristics::SparsePixels::similar_colors(PixelGraph::const_iterator n, + const guint8 (&a)[4], + const guint8 (&b)[4]) +{ + using colorspace::similar_colors; + return similar_colors(n->rgba, a) || similar_colors(n->rgba, b); +} + +inline bool Heuristics::islands(PixelGraph::const_iterator a, + PixelGraph::const_iterator b) +{ + if ( a->adjsize() == 1 || b->adjsize() == 1 ) + return true; + + return false; +} + +} // namespace Tracer + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/libdepixelize/kopftracer2011.h b/src/libdepixelize/kopftracer2011.h new file mode 100644 index 000000000..73f3b7274 --- /dev/null +++ b/src/libdepixelize/kopftracer2011.h @@ -0,0 +1,123 @@ +/* This file is part of the libdepixelize project + Copyright (C) 2013 VinÃcius dos Santos Oliveira <vini.ipsmaker@gmail.com> + + GNU Lesser General Public License Usage + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + You should have received a copy of the GNU Lesser General Public License + along with this library. If not, see <http://www.gnu.org/licenses/>. + + GNU General Public License Usage + Alternatively, this library may be used under the terms of the GNU General + Public License as published by the Free Software Foundation, either version + 2 of the License, or (at your option) any later version. + You should have received a copy of the GNU General Public License along with + this library. If not, see <http://www.gnu.org/licenses/>. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. +*/ + +#ifndef LIBDEPIXELIZE_TRACER_KOPFTRACER2011_H +#define LIBDEPIXELIZE_TRACER_KOPFTRACER2011_H + +#include <string> + +// Contains exception definitions +#include <glibmm/fileutils.h> +#include <gdkmm/pixbuf.h> +#include "splines.h" + +namespace Tracer { + +class PixelGraph; +template<typename T> class SimplifiedVoronoi; +template<typename T> class HomogeneousSplines; + +class Kopf2011 +{ +public: + struct Options + { + enum Defaults { + CURVES_MULTIPLIER = 1, + ISLANDS_WEIGHT = 5, + SPARSE_PIXELS_MULTIPLIER = 1, + SPARSE_PIXELS_RADIUS = 4 + }; + + Options() : + curvesMultiplier(CURVES_MULTIPLIER), + islandsWeight(ISLANDS_WEIGHT), + sparsePixelsMultiplier(SPARSE_PIXELS_MULTIPLIER), + sparsePixelsRadius(SPARSE_PIXELS_RADIUS), + optimize(true), + nthreads(1) + {} + + // Heuristics + double curvesMultiplier; + int islandsWeight; + double sparsePixelsMultiplier; + unsigned sparsePixelsRadius; + + // Other options + bool optimize; + int nthreads; + }; + + /** + * # Exceptions + * + * Glib::FileError + * Gdk::PixbufError + */ + static Splines to_voronoi(const std::string &filename, + const Options &options = Options()); + + static Splines to_voronoi(const Glib::RefPtr<Gdk::Pixbuf const> &buf, + const Options &options = Options()); + + /** + * # Exceptions + * + * Glib::FileError + * Gdk::PixbufError + */ + static Splines to_splines(const std::string &filename, + const Options &options = Options()); + + static Splines to_splines(const Glib::RefPtr<Gdk::Pixbuf const> &buf, + const Options &options = Options()); + +private: + typedef double Precision; + + template<class T> + static SimplifiedVoronoi<T> _voronoi(const Glib::RefPtr<Gdk::Pixbuf const> &buf, + const Options &options); + + static void _disconnect_neighbors_with_dissimilar_colors(PixelGraph &graph); + static void _remove_crossing_edges_safe(PixelGraph &graph); + static void _remove_crossing_edges_unsafe(PixelGraph &graph, + const Options &options); +}; + +} // namespace Tracer + +#endif // LIBDEPIXELIZE_TRACER_KOPFTRACER2011_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/libdepixelize/makefile.in b/src/libdepixelize/makefile.in new file mode 100644 index 000000000..51d020db1 --- /dev/null +++ b/src/libdepixelize/makefile.in @@ -0,0 +1,17 @@ +# Convenience stub makefile to call the real Makefile. + +@SET_MAKE@ + +OBJEXT = @OBJEXT@ + +# Explicit so that it's the default rule. +all: + cd .. && $(MAKE) libdepixelize/all + +clean %.a %.$(OBJEXT): + cd .. && $(MAKE) libdepixelize/$@ + +.PHONY: all clean + +.SUFFIXES: +.SUFFIXES: .a .$(OBJEXT) diff --git a/src/libdepixelize/priv/branchless.h b/src/libdepixelize/priv/branchless.h new file mode 100644 index 000000000..487a9688d --- /dev/null +++ b/src/libdepixelize/priv/branchless.h @@ -0,0 +1,58 @@ +/* This file is part of the libdepixelize project + Copyright (C) 2013 VinÃcius dos Santos Oliveira <vini.ipsmaker@gmail.com> + + GNU Lesser General Public License Usage + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + You should have received a copy of the GNU Lesser General Public License + along with this library. If not, see <http://www.gnu.org/licenses/>. + + GNU General Public License Usage + Alternatively, this library may be used under the terms of the GNU General + Public License as published by the Free Software Foundation, either version + 2 of the License, or (at your option) any later version. + You should have received a copy of the GNU General Public License along with + this library. If not, see <http://www.gnu.org/licenses/>. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. +*/ + +#ifndef LIBDEPIXELIZE_TRACER_BRANCHLESS_H +#define LIBDEPIXELIZE_TRACER_BRANCHLESS_H + +namespace Tracer { + +/** + * Branch misprediction proof operations + */ +namespace branchless { + +/* + * All modern processors optimize the branch to a conditional move + */ +template<class T> +T first_if(T first, T second, bool cond) +{ + return cond ? first : second; +} + +} // namespace branchless +} // namespace Tracer { + +#endif // LIBDEPIXELIZE_TRACER_BRANCHLESS_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/libdepixelize/priv/colorspace.h b/src/libdepixelize/priv/colorspace.h new file mode 100644 index 000000000..4982630ad --- /dev/null +++ b/src/libdepixelize/priv/colorspace.h @@ -0,0 +1,111 @@ +/* This file is part of the libdepixelize project + Copyright (C) 2013 VinÃcius dos Santos Oliveira <vini.ipsmaker@gmail.com> + + GNU Lesser General Public License Usage + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + You should have received a copy of the GNU Lesser General Public License + along with this library. If not, see <http://www.gnu.org/licenses/>. + + GNU General Public License Usage + Alternatively, this library may be used under the terms of the GNU General + Public License as published by the Free Software Foundation, either version + 2 of the License, or (at your option) any later version. + You should have received a copy of the GNU General Public License along with + this library. If not, see <http://www.gnu.org/licenses/>. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. +*/ + +#ifndef LIBDEPIXELIZE_TRACER_YUV_H +#define LIBDEPIXELIZE_TRACER_YUV_H + +#include <glib.h> + +namespace Tracer { +namespace colorspace { + +/** + * The same algorithm used in hqx filter + */ +inline void rgb2yuv(guint8 r, guint8 g, guint8 b, + guint8 &y, guint8 &u, guint8 &v) +{ + y = 0.299 * r + 0.587 * g + 0.114 * b; + u = guint16(-0.169 * r - 0.331 * g + 0.5 * b) + 128; + v = guint16(0.5 * r - 0.419 * g - 0.081 * b) + 128; +} + +inline void rgb2yuv(const guint8 rgb[], guint8 yuv[]) +{ + rgb2yuv(rgb[0], rgb[1], rgb[2], yuv[0], yuv[1], yuv[2]); +} + +inline bool same_color(const guint8 (&a)[4], const guint8 (&b)[4]) +{ + return (a[0] == b[0] + && a[1] == b[1] + && a[2] == b[2] + && a[3] == b[3]); +} + +inline bool dissimilar_colors(const guint8 a[], const guint8 b[]) +{ + // C uses row-major order, so + // A[2][3] = { {1, 2, 3}, {4, 5, 6} } = {1, 2, 3, 4, 5, 6} + guint8 yuv[2][3]; + rgb2yuv(a, yuv[0]); + rgb2yuv(b, yuv[1]); + + // Magic numbers taken from hqx algorithm + // Only used to describe the level of tolerance + return abs(yuv[0][0] - yuv[1][0]) > 0x30 + || abs(yuv[0][1] - yuv[1][1]) > 7 + || abs(yuv[0][2] - yuv[1][2]) > 6; +} + +inline bool similar_colors(const guint8 a[], const guint8 b[]) +{ + return !dissimilar_colors(a, b); +} + +inline bool shading_edge(const guint8 a[], const guint8 b[]) +{ + // C uses row-major order, so + // A[2][3] = { {1, 2, 3}, {4, 5, 6} } = {1, 2, 3, 4, 5, 6} + guint8 yuv[2][3]; + rgb2yuv(a, yuv[0]); + rgb2yuv(b, yuv[1]); + + // Magic numbers taken from Kopf-Lischinski algorithm + // Only used to describe the level of tolerance + return abs(yuv[0][0] - yuv[1][0]) <= 100 + && abs(yuv[0][1] - yuv[1][1]) <= 100 + && abs(yuv[0][2] - yuv[1][2]) <= 100; +} + +inline bool contour_edge(const guint8 a[], const guint8 b[]) +{ + return !shading_edge(a, b); +} + +} // namespace colorspace +} // namespace Tracer + +#endif // LIBDEPIXELIZE_TRACER_YUV_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/libdepixelize/priv/homogeneoussplines.h b/src/libdepixelize/priv/homogeneoussplines.h new file mode 100644 index 000000000..57c77a163 --- /dev/null +++ b/src/libdepixelize/priv/homogeneoussplines.h @@ -0,0 +1,465 @@ +/* This file is part of the libdepixelize project + Copyright (C) 2013 VinÃcius dos Santos Oliveira <vini.ipsmaker@gmail.com> + + GNU Lesser General Public License Usage + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + You should have received a copy of the GNU Lesser General Public License + along with this library. If not, see <http://www.gnu.org/licenses/>. + + GNU General Public License Usage + Alternatively, this library may be used under the terms of the GNU General + Public License as published by the Free Software Foundation, either version + 2 of the License, or (at your option) any later version. + You should have received a copy of the GNU General Public License along with + this library. If not, see <http://www.gnu.org/licenses/>. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. +*/ + +#ifndef LIBDEPIXELIZE_TRACER_HOMOGENEOUSSPLINES_H +#define LIBDEPIXELIZE_TRACER_HOMOGENEOUSSPLINES_H + +#include "simplifiedvoronoi.h" +#include "point.h" +#include <algorithm> +#include <utility> + +namespace Tracer { + +template<typename T> +class HomogeneousSplines +{ +public: + struct Polygon + { + Polygon() {} + Polygon(const guint8 (&rgba)[4]) + { + for ( int i = 0 ; i != 4 ; ++i ) + this->rgba[i] = rgba[i]; + } + + std::vector< Point<T> > vertices; + + /** + * It may be benefited from C++11 move references. + */ + std::vector< std::vector< Point<T> > > holes; + + guint8 rgba[4]; + }; + + typedef typename std::vector<Polygon>::iterator iterator; + typedef typename std::vector<Polygon>::const_iterator const_iterator; + typedef typename std::vector<Polygon>::size_type size_type; + + HomogeneousSplines(const SimplifiedVoronoi<T> &voronoi); + + // Iterators + iterator begin() + { + return _polygons.begin(); + } + + const_iterator begin() const + { + return _polygons.begin(); + } + + iterator end() + { + return _polygons.end(); + } + + const_iterator end() const + { + return _polygons.end(); + } + + size_type size() const + { + return _polygons.size(); + } + + int width() const + { + return _width; + } + + int height() const + { + return _height; + } + +private: + typedef typename SimplifiedVoronoi<T>::Cell Cell; + typedef std::vector< Point<T> > Points; + + typedef typename SimplifiedVoronoi<T>::iterator voronoi_iter; + typedef typename SimplifiedVoronoi<T>::const_iterator voronoi_citer; + + typedef typename Points::iterator points_iter; + typedef typename Points::const_iterator points_citer; + typedef typename Points::reverse_iterator points_riter; + typedef typename Points::const_reverse_iterator points_criter; + + typedef std::pair<points_iter, points_iter> points_range; + typedef std::pair<points_citer, points_citer> points_crange; + + struct CommonEdge + { + bool ok; //< share an edge + Points *dst; + const Points *src; + + // the interval is closed on both ends + // different from [begin, end) STL style + points_iter dst_begin, dst_end; + points_citer src_begin, src_end; + }; + + struct SelfCommonEdge + { + bool ok; //< share an edge + + // Greater range. The one that should be erased from the vector. + points_riter grt_begin, grt_end; + + // Smaller range. The one that should be used to create a new vector. + points_riter sml_begin, sml_end; + }; + + /** + * Return ok == true if they share an edge (more than one point). + */ + CommonEdge _common_edge(Points &dst, const Points &src); + + /** + * Return ok == true if they share an edge (more than one point). + * + * - [dst_begin, dst_end) will contain the hole polygon + * - [src_begin, src_end) will contain the range to be erased + * + * It's required to do the search in backward order. + */ + SelfCommonEdge _common_edge(Points &points, points_riter it); + + /*! + * Add polygon represented by \p common_edge.src to \p common_edge.dst. + */ + void _polygon_union(CommonEdge common_edge); + + /** + * Weird recursive function created to solve the complex problem to fill + * polygons holes without the need to store temporaries on the heap nor + * changing requirements to some data type that don't invalidate iterators + * that point before the current element (maybe I'll write some poetry about + * the problem someday). + */ + void _fill_holes(std::vector<Points> &holes, points_iter region_begin, + points_iter region_end); + + std::vector<Polygon> _polygons; + int _width; + int _height; +}; + +template<class T> +HomogeneousSplines<T>::HomogeneousSplines(const SimplifiedVoronoi<T> &voronoi) : + _width(voronoi.width()), + _height(voronoi.height()) +{ + //if (!voronoi.size()) + // return; + using colorspace::same_color; + + // Identify visible edges (group polygons with the same color) + for ( voronoi_citer cell_it = voronoi.begin(), cell_end = voronoi.end() + ; cell_it != cell_end ; ++cell_it ) { + bool found = false; + for ( iterator polygon_it = _polygons.begin(), + polygon_end = _polygons.end() + ; polygon_it != polygon_end ; ++polygon_it ) { + if ( same_color(polygon_it->rgba, cell_it->rgba) ) { + CommonEdge common_edge = _common_edge(polygon_it->vertices, + cell_it->vertices); + if ( common_edge.ok ) { + _polygon_union(common_edge); + found = true; + + for ( iterator polygon2_it = polygon_it + 1 + ; polygon2_it != polygon_end ; ++polygon2_it ) { + if ( same_color(polygon_it->rgba, polygon2_it->rgba) ) { + CommonEdge common_edge2 + = _common_edge(polygon_it->vertices, + polygon2_it->vertices); + if ( common_edge2.ok ) { + _polygon_union(common_edge2); + _polygons.erase(polygon2_it); + break; + } + } + } + + break; + } + } + } + if ( !found ) { + Polygon polygon(cell_it->rgba); + polygon.vertices = cell_it->vertices; + _polygons.insert(_polygons.end(), polygon); + } + } + + // Find polygons with holes and fix them + // This iteration runs such complex time-consuming algorithm, but each + // polygon has an independent result. They wouldn't even need to share/sync + // results and the only waste would be a join at the end of the for. + for ( typename std::vector<Polygon>::iterator it = _polygons.begin(), + end = _polygons.end() ; it != end ; ++it ) { + SelfCommonEdge ce = _common_edge(it->vertices, it->vertices.rbegin()); + while ( ce.ok ) { + _fill_holes(it->holes, ce.sml_end.base(), ce.sml_begin.base()); + it->vertices.erase(ce.grt_end.base() + 1, ce.grt_begin.base()); + ce = _common_edge(it->vertices, ce.grt_end); + } + } +} + +// it can infinite loop if points of both entities are equal, +// but this shouldn't happen if user has only access to Kopf2011 interface +template<class T> +typename HomogeneousSplines<T>::CommonEdge +HomogeneousSplines<T>::_common_edge(Points &dst, const Points &src) +{ + // It's an edge, then the points are closer together. After we find the + // first point, there is no need for check against all points of the src + // a second time + + const points_iter dst_begin = dst.begin(); + const points_iter dst_end = dst.end(); + + const points_citer src_begin = src.begin(); + const points_citer src_end = src.end(); + + for ( points_iter it = dst_begin ; it != dst_end ; ++it ) { + points_citer src_it = std::find(src_begin, src_end, *it); + + if ( src_it == src_end ) + continue; + + points_iter dst_common_edge_begin = it; + points_citer src_common_edge_end = src_it; + + // iterate until find the beginning of the common edge range + while ( *dst_common_edge_begin == *src_common_edge_end ) { + if ( dst_common_edge_begin == dst_begin ) + dst_common_edge_begin = dst_end - 1; + else + --dst_common_edge_begin; + + ++src_common_edge_end; + if ( src_common_edge_end == src_end ) + src_common_edge_end = src_begin; + } + + // fix {dst_begin, src_end} range + ++dst_common_edge_begin; + if ( dst_common_edge_begin == dst_end ) + dst_common_edge_begin = dst_begin; + + if ( src_common_edge_end == src_begin ) + src_common_edge_end = src_end - 1; + else + --src_common_edge_end; + + points_iter dst_common_edge_end = it; + points_citer src_common_edge_begin = src_it; + + // find the end of the common edge range + while ( *dst_common_edge_end == *src_common_edge_begin ) { + ++dst_common_edge_end; + if ( dst_common_edge_end == dst_end ) + dst_common_edge_end = dst_begin; + + if ( src_common_edge_begin == src_begin ) + src_common_edge_begin = src_end - 1; + else + --src_common_edge_begin; + } + + // fix {dst_end, src_begin} range + if ( dst_common_edge_end == dst_begin ) + dst_common_edge_end = dst_end - 1; + else + --dst_common_edge_end; + + ++src_common_edge_begin; + if ( src_common_edge_begin == src_end ) + src_common_edge_begin = src_begin; + + CommonEdge ret; + + // if only one point in common + if ( dst_common_edge_begin == dst_common_edge_end ) + continue; + + ret.ok = true; + + ret.dst = &dst; + ret.dst_begin = dst_common_edge_begin; + ret.dst_end = dst_common_edge_end; + + ret.src = &src; + ret.src_begin = src_common_edge_begin; + ret.src_end = src_common_edge_end; + + return ret; + } + + CommonEdge ret; + ret.ok = false; + return ret; +} + +template<class T> +typename HomogeneousSplines<T>::SelfCommonEdge +HomogeneousSplines<T>::_common_edge(Points &points, points_riter it) +{ + SelfCommonEdge ret; + + ret.grt_end = points.rend(); + + for ( ; it != ret.grt_end ; ++it ) { + ret.sml_end = std::find(it + 1, ret.grt_end, *it); + + if ( ret.sml_end == ret.grt_end ) + continue; + + ret.grt_begin = it; + ret.grt_end = ret.sml_end + 1; + + ret.sml_begin = it; + + while ( *ret.sml_begin == *ret.sml_end ) { + ++ret.sml_begin; + --ret.sml_end; + } + + --ret.sml_begin; + ++ret.sml_end; + ++ret.sml_end; + + ret.ok = true; + return ret; + } + + ret.ok = false; + return ret; +} + +template<class T> +void HomogeneousSplines<T>::_polygon_union(CommonEdge common_edge) +{ + Points &dst = *common_edge.dst; + const Points &src = *common_edge.src; + + // the rotated cell must be inserted before (dst.begin() + index) + typename Points::difference_type index; + + // first, we remove the common edge in dst + if ( common_edge.dst_begin < common_edge.dst_end ) { + // common edge is in the middle of dst + + index = dst.erase(common_edge.dst_begin, + common_edge.dst_end + 1) - dst.begin(); + } else { + // common edge cross the end of dst + + dst.erase(common_edge.dst_begin, dst.end()); + dst.erase(dst.begin(), common_edge.dst_end); + index = dst.end() - dst.begin(); + } + + // second, we copy src points to polygon + if ( common_edge.src_begin < common_edge.src_end ) { + // common edge is in the middle of src + + const typename Points::difference_type nfirstinserted + = src.end() - common_edge.src_end; + const typename Points::difference_type nsecondinserted + = 1 + (common_edge.src_begin - src.begin()); + + dst.reserve(dst.size() + nfirstinserted + nsecondinserted); + + dst.insert(dst.begin() + index, common_edge.src_end, src.end()); + + dst.insert(dst.begin() + index + nfirstinserted, + src.begin(), common_edge.src_begin + 1); + } else { + // common edge cross the end of src + + dst.reserve(dst.size() + 1 + + (common_edge.src_begin - common_edge.src_end)); + + dst.insert(dst.begin() + index, + common_edge.src_end, common_edge.src_begin + 1); + } +} + +// The following piece of code is so evil that you could end up invoking an +// ancient beast if you proceed to read it, but I'll be able to explain it in +// the form of some video (text is not so representative as an image). +template<class T> +void HomogeneousSplines<T>::_fill_holes(std::vector<Points> &holes, + points_iter region_begin, + points_iter region_end) +{ + // the exact location might not always be back and iterators will be + // invalidated after some insertions, then the index is required + const typename std::vector<Points>::size_type hole_index = holes.size(); + holes.resize(hole_index + 1); + + for ( points_iter it = region_begin + 1 ; it != region_end ; ++it ) { + points_iter res = std::find(it + 1, region_end, *it); + if ( res == region_end ) + continue; + + holes[hole_index].insert(holes[hole_index].end(), region_begin, + it); + region_begin = res; + + do { + ++it; + --res; + } while ( *it == *res ); + _fill_holes(holes, it - 1, res + 2); + + it = region_begin; + } + + holes[hole_index].insert(holes[hole_index].end(), region_begin, + region_end - 1); +} + +} // namespace Tracer + +#endif // LIBDEPIXELIZE_TRACER_HOMOGENEOUSSPLINES_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/libdepixelize/priv/iterator.h b/src/libdepixelize/priv/iterator.h new file mode 100644 index 000000000..7caa9bfa9 --- /dev/null +++ b/src/libdepixelize/priv/iterator.h @@ -0,0 +1,123 @@ +/* This file is part of the libdepixelize project + Copyright (C) 2013 VinÃcius dos Santos Oliveira <vini.ipsmaker@gmail.com> + + GNU Lesser General Public License Usage + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + You should have received a copy of the GNU Lesser General Public License + along with this library. If not, see <http://www.gnu.org/licenses/>. + + GNU General Public License Usage + Alternatively, this library may be used under the terms of the GNU General + Public License as published by the Free Software Foundation, either version + 2 of the License, or (at your option) any later version. + You should have received a copy of the GNU General Public License along with + this library. If not, see <http://www.gnu.org/licenses/>. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. +*/ + +#ifndef LIBDEPIXELIZE_TRACER_ITERATOR_H +#define LIBDEPIXELIZE_TRACER_ITERATOR_H + +#include <vector> +#include <iterator> + +namespace Tracer { + +template<typename T> +const T *to_ptr(typename std::vector<T>::const_iterator it) +{ + return &*it; +} + +template<typename T> +T *to_ptr(typename std::vector<T>::iterator it) +{ + return &*it; +} + +template<typename T> +typename std::vector<T>::const_iterator to_iterator(T const *ptr, + typename std::vector<T> + ::const_iterator begin) +{ + typedef typename std::vector<T>::const_iterator It; + typedef typename std::iterator_traits<It>::difference_type difference_type; + difference_type idx = ptr - to_ptr<T>(begin); + return begin + idx; +} + +template<typename T> +typename std::vector<T>::iterator to_iterator(T *ptr, + typename std::vector<T>::iterator + begin) +{ + typedef typename std::vector<T>::iterator It; + typedef typename std::iterator_traits<It>::difference_type difference_type; + difference_type idx = ptr - to_ptr<T>(begin); + return begin + idx; +} + +template<typename T> +class ToIter +{ +public: + typedef typename std::vector<T>::const_iterator const_iterator; + typedef typename std::vector<T>::iterator iterator; + + ToIter(const_iterator begin) : + begin(begin) + {} + + const_iterator operator()(T const *ptr) const + { + return to_iterator<T>(ptr, begin); + } + + iterator operator()(T *ptr) const + { + return to_iterator<T>(ptr, begin); + } + +private: + typename std::vector<T>::const_iterator begin; +}; + +template<typename T> +class ToPtr +{ +public: + typedef typename std::vector<T>::const_iterator const_iterator; + typedef typename std::vector<T>::iterator iterator; + + const T *operator()(const_iterator it) const + { + return to_ptr<T>(it); + } + + T *operator()(iterator it) const + { + return to_ptr<T>(it); + } +}; + +} // namespace Tracer + +#endif // LIBDEPIXELIZE_TRACER_ITERATOR_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/libdepixelize/priv/pixelgraph.h b/src/libdepixelize/priv/pixelgraph.h new file mode 100644 index 000000000..32523d8ee --- /dev/null +++ b/src/libdepixelize/priv/pixelgraph.h @@ -0,0 +1,490 @@ +/* This file is part of the libdepixelize project + Copyright (C) 2013 VinÃcius dos Santos Oliveira <vini.ipsmaker@gmail.com> + + GNU Lesser General Public License Usage + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + You should have received a copy of the GNU Lesser General Public License + along with this library. If not, see <http://www.gnu.org/licenses/>. + + GNU General Public License Usage + Alternatively, this library may be used under the terms of the GNU General + Public License as published by the Free Software Foundation, either version + 2 of the License, or (at your option) any later version. + You should have received a copy of the GNU General Public License along with + this library. If not, see <http://www.gnu.org/licenses/>. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. +*/ + +#ifndef LIBDEPIXELIZE_TRACER_PIXELGRAPH_H +#define LIBDEPIXELIZE_TRACER_PIXELGRAPH_H + +#include <gdkmm/pixbuf.h> +#include <vector> +#include <cassert> + +namespace Tracer { + +class PixelGraph +{ +public: + class Node + { + public: + /* + * Hamming weight of \p adj + */ + unsigned adjsize() const + { + unsigned all[8] = { + adj.top, + adj.topright, + adj.right, + adj.bottomright, + adj.bottom, + adj.bottomleft, + adj.left, + adj.topleft + }; + return all[0] + all[1] + all[2] + all[3] + + all[4] + all[5] + all[6] + all[7]; + } + + guint8 rgba[4]; + // Nodes pointing from this + struct Adj + { + unsigned top: 1; + unsigned topright: 1; + unsigned right: 1; + unsigned bottomright: 1; + unsigned bottom: 1; + unsigned bottomleft: 1; + unsigned left: 1; + unsigned topleft: 1; + } adj; + }; + + typedef std::vector<Node>::iterator iterator; + typedef std::vector<Node>::const_iterator const_iterator; + typedef std::vector<Node>::reverse_iterator reverse_iterator; + typedef std::vector<Node>::const_reverse_iterator const_reverse_iterator; + + class ColumnView + { + public: + ColumnView(std::vector<Node> &nodes, int width, int column) : + _nodes(nodes), _width(width), _column(column) + {} + + Node &operator[](int line); + + private: + std::vector<Node> &_nodes; + const int _width; + const int _column; + }; + + PixelGraph(Glib::RefPtr<Gdk::Pixbuf const> pixbuf); + + void checkConsistency(); + + /** + * It'll let you access the nodes using the syntax: + * + * graph[x][y] + * + * Where x is the column and y is the line. + */ + ColumnView operator[](int column); + + // Iterators + iterator begin() + { + return _nodes.begin(); + } + + const_iterator begin() const + { + return _nodes.begin(); + } + + iterator end() + { + return _nodes.end(); + } + + const_iterator end() const + { + return _nodes.end(); + } + + reverse_iterator rbegin() + { + return _nodes.rbegin(); + } + + const_reverse_iterator rbegin() const + { + return _nodes.rbegin(); + } + + reverse_iterator rend() + { + return _nodes.rend(); + } + + const_reverse_iterator rend() const + { + return _nodes.rend(); + } + + size_t size() const + { + return _nodes.size(); + } + + int width() const + { + return _width; + } + + int height() const + { + return _height; + } + + // Algorithms + void connectAllNeighbors(); + + int toX(const_iterator n) const + { + return (&*n - &_nodes[0]) % _width; + } + + int toY(const_iterator n) const + { + return (&*n - &_nodes[0]) / _width; + } + + iterator nodeTop(iterator n) + { + return n - _width; + } + + iterator nodeBottom(iterator n) + { + return n + _width; + } + + iterator nodeLeft(iterator n) + { + return n - 1; + } + + iterator nodeRight(iterator n) + { + return n + 1; + } + + iterator nodeTopLeft(iterator n) + { + return n - _width - 1; + } + + iterator nodeTopRight(iterator n) + { + return n - _width + 1; + } + + iterator nodeBottomLeft(iterator n) + { + return n + _width - 1; + } + + iterator nodeBottomRight(iterator n) + { + return n + _width + 1; + } + + const_iterator nodeTop(const_iterator n) const + { + return n - _width; + } + + const_iterator nodeBottom(const_iterator n) const + { + return n + _width; + } + + const_iterator nodeLeft(const_iterator n) const + { + return n - 1; + } + + const_iterator nodeRight(const_iterator n) const + { + return n + 1; + } + + const_iterator nodeTopLeft(const_iterator n) const + { + return n - _width - 1; + } + + const_iterator nodeTopRight(const_iterator n) const + { + return n - _width + 1; + } + + const_iterator nodeBottomLeft(const_iterator n) const + { + return n + _width - 1; + } + + const_iterator nodeBottomRight(const_iterator n) const + { + return n + _width + 1; + } + +private: + PixelGraph(const PixelGraph&); + + int _width; + int _height; + + // The data representation follows the image data pattern from gdk-pixbuf. + // + // Quoting: + // "Image data in a pixbuf is stored in memory in uncompressed, packed + // format. Rows in the image are stored top to bottom, and in each row + // pixels are stored from left to right. There may be padding at the end of + // a row." + // + // Differently, _nodes don't put padding among rows. + std::vector<Node> _nodes; +}; + +inline PixelGraph::PixelGraph(Glib::RefPtr<Gdk::Pixbuf const> pixbuf) : + _width(pixbuf->get_width()), + _height(pixbuf->get_height()), + _nodes(size_t(_width) * _height) +{ + if ( !_width || !_height ) + return; + + // Initialize the graph using the pixels' color data + guint8 *pixels = pixbuf->get_pixels(); + Node *dest = &_nodes[0]; + const int n_channels = pixbuf->get_n_channels(); + const int rowpadding = pixbuf->get_rowstride() - _width * n_channels; + + if ( n_channels == 4 ) { + for ( int i = 0 ; i != _height ; ++i ) { + for ( int j = 0 ; j != _width ; ++j ) { + for ( int k = 0 ; k != 4 ; ++k ) + dest->rgba[k] = pixels[k]; + { + dest->adj.top = 0; + dest->adj.topright = 0; + dest->adj.right = 0; + dest->adj.bottomright = 0; + dest->adj.bottom = 0; + dest->adj.bottomleft = 0; + dest->adj.left = 0; + dest->adj.topleft = 0; + } + pixels += n_channels; + ++dest; + } + pixels += rowpadding; + } + } else { + assert(n_channels == 3); + for ( int i = 0 ; i != _height ; ++i ) { + for ( int j = 0 ; j != _width ; ++j ) { + for ( int k = 0 ; k != 3 ; ++k ) + dest->rgba[k] = pixels[k]; + dest->rgba[3] = '\xFF'; + { + dest->adj.top = 0; + dest->adj.topright = 0; + dest->adj.right = 0; + dest->adj.bottomright = 0; + dest->adj.bottom = 0; + dest->adj.bottomleft = 0; + dest->adj.left = 0; + dest->adj.topleft = 0; + } + pixels += n_channels; + ++dest; + } + pixels += rowpadding; + } + } +} + +inline void PixelGraph::checkConsistency() +{ + PixelGraph::Node *it = &_nodes.front(); + for ( int i = 0 ; i != _height ; ++i ) { + for ( int j = 0 ; j != _width ; ++j, ++it ) { + if ( it->adj.top ) + assert((it - _width)->adj.bottom); + if ( it->adj.topright ) + assert((it - _width + 1)->adj.bottomleft); + if ( it->adj.right ) + assert((it + 1)->adj.left); + if ( it->adj.bottomright ) + assert((it + _width + 1)->adj.topleft); + if ( it->adj.bottom ) + assert((it + _width)->adj.top); + if ( it->adj.bottomleft ) + assert((it + _width - 1)->adj.topright); + if ( it->adj.left ) + assert((it - 1)->adj.right); + if ( it->adj.topleft ) + assert((it - _width - 1)->adj.bottomright); + } + } +} + +inline PixelGraph::ColumnView PixelGraph::operator[](int column) +{ + return ColumnView(_nodes, _width, column); +} + +inline void PixelGraph::connectAllNeighbors() +{ + // ...the "center" nodes first... + if ( _width > 2 && _height > 2 ) { + iterator it = nodeBottomRight(begin()); // [1][1] + for ( int i = 1 ; i != _height - 1 ; ++i ) { + for ( int j = 1 ; j != _width - 1 ; ++j ) { + it->adj.top = 1; + it->adj.topright = 1; + it->adj.right = 1; + it->adj.bottomright = 1; + it->adj.bottom = 1; + it->adj.bottomleft = 1; + it->adj.left = 1; + it->adj.topleft = 1; + + it = nodeRight(it); + } + // After the previous loop, 'it' is poiting to the last node from + // the row. + // Go south, then first node in the row (increment 'it' by 1) + // Go to the second node in the line (increment 'it' by 1) + it += 2; + } + } + + // ...then the "top" nodes... + if ( _width > 2 ) { + Node *it = &_nodes[1]; + for ( int i = 1 ; i != _width - 1 ; ++i ) { + it->adj.right = 1; + it->adj.bottomright = 1; + it->adj.bottom = 1; + it->adj.bottomleft = 1; + it->adj.left = 1; + + ++it; + } + } + + // ...then the "bottom" nodes... + if ( _width > 2 && _height > 1 ) { + Node *it = &((*this)[1][_height - 1]); + for ( int i = 1 ; i != _width - 1 ; ++i ) { + it->adj.left = 1; + it->adj.topleft = 1; + it->adj.top = 1; + it->adj.topright = 1; + it->adj.right = 1; + + ++it; + } + } + + // ...then the "left" nodes... + if ( _height > 2 ) { + iterator it = nodeBottom(begin()); // [0][1] + for ( int i = 1 ; i != _height - 1 ; ++i ) { + it->adj.top = 1; + it->adj.topright = 1; + it->adj.right = 1; + it->adj.bottomright = 1; + it->adj.bottom = 1; + + it = nodeBottom(it); + } + } + + // ...then the "right" nodes... + if ( _height > 2 && _width > 1 ) { + iterator it = nodeBottom(begin() + _width - 1);// [_width - 1][1] + for ( int i = 1 ; i != _height - 1 ; ++i ) { + it->adj.bottom = 1; + it->adj.bottomleft = 1; + it->adj.left = 1; + it->adj.topleft = 1; + it->adj.top = 1; + + it = nodeBottom(it); + } + } + + // ...and the 4 corner nodes + { + Node *const top_left = &(*this)[0][0]; + top_left->adj.right = 1; + top_left->adj.bottomright = 1; + top_left->adj.bottom = 1; + } + if ( _width > 1 ) { + Node *const top_right = &(*this)[_width - 1][0]; + top_right->adj.bottom = 1; + top_right->adj.bottomleft = 1; + top_right->adj.left = 1; + } + if ( _height > 1 ) { + Node *const down_left = &(*this)[0][_height - 1]; + down_left->adj.top = 1; + down_left->adj.topright = 1; + down_left->adj.right = 1; + } + if ( _width > 1 && _height > 1 ) { + Node *const down_right = &(*this)[_width - 1][_height - 1]; + down_right->adj.left = 1; + down_right->adj.topleft = 1; + down_right->adj.top = 1; + } +} + +inline PixelGraph::Node &PixelGraph::ColumnView::operator[](int line) +{ + return _nodes[line * _width + _column]; +} + +} // namespace Tracer + +#endif // LIBDEPIXELIZE_TRACER_PIXELGRAPH_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/libdepixelize/priv/point.h b/src/libdepixelize/priv/point.h new file mode 100644 index 000000000..6bea752ed --- /dev/null +++ b/src/libdepixelize/priv/point.h @@ -0,0 +1,75 @@ +/* This file is part of the libdepixelize project + Copyright (C) 2013 VinÃcius dos Santos Oliveira <vini.ipsmaker@gmail.com> + + GNU Lesser General Public License Usage + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + You should have received a copy of the GNU Lesser General Public License + along with this library. If not, see <http://www.gnu.org/licenses/>. + + GNU General Public License Usage + Alternatively, this library may be used under the terms of the GNU General + Public License as published by the Free Software Foundation, either version + 2 of the License, or (at your option) any later version. + You should have received a copy of the GNU General Public License along with + this library. If not, see <http://www.gnu.org/licenses/>. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. +*/ + +#ifndef LIBDEPIXELIZE_TRACER_POINT_H +#define LIBDEPIXELIZE_TRACER_POINT_H + +namespace Tracer { + +template<class T> +struct Point +{ + Point() {} + Point(T x, T y) : x(x), y(y) {} + Point(T x, T y, bool smooth) : smooth(smooth), x(x), y(y) {} + + Point operator+(const Point &rhs) const + { + return Point(x + rhs.x, y + rhs.y); + } + + Point operator/(T foo) const + { + return Point(x / foo, y / foo); + } + + bool smooth; + + T x, y; +}; + +template<class T> +inline bool operator==(const Point<T> &lhs, const Point<T> &rhs) +{ + return +#ifndef LIBDEPIXELIZE_IS_VERY_WELL_TESTED + lhs.smooth == rhs.smooth && +#endif // LIBDEPIXELIZE_IS_VERY_WELL_TESTED + lhs.x == rhs.x && lhs.y == rhs.y; +} + +} // namespace Tracer + +#endif // LIBDEPIXELIZE_TRACER_POINT_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/libdepixelize/priv/simplifiedvoronoi.h b/src/libdepixelize/priv/simplifiedvoronoi.h new file mode 100644 index 000000000..a33695ff7 --- /dev/null +++ b/src/libdepixelize/priv/simplifiedvoronoi.h @@ -0,0 +1,1324 @@ +/* This file is part of the libdepixelize project + Copyright (C) 2013 VinÃcius dos Santos Oliveira <vini.ipsmaker@gmail.com> + + GNU Lesser General Public License Usage + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + You should have received a copy of the GNU Lesser General Public License + along with this library. If not, see <http://www.gnu.org/licenses/>. + + GNU General Public License Usage + Alternatively, this library may be used under the terms of the GNU General + Public License as published by the Free Software Foundation, either version + 2 of the License, or (at your option) any later version. + You should have received a copy of the GNU General Public License along with + this library. If not, see <http://www.gnu.org/licenses/>. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. +*/ + +#ifndef LIBDEPIXELIZE_TRACER_SIMPLIFIEDVORONOI_H +#define LIBDEPIXELIZE_TRACER_SIMPLIFIEDVORONOI_H + +#include "pixelgraph.h" +#include "colorspace.h" +#include "point.h" +#include "branchless.h" + +namespace Tracer { + +template<typename T> +class SimplifiedVoronoi +{ +public: + /** + * The "smooth" attribute of each vertex is only accurate if edge is + * visible. This decision was made because invisible edges will disappear + * during polygon-union, the next phase of Kopf-Lischinski. + */ + struct Cell + { + // There may not exist more than 8 vertices per cell and a + // "small vector optimization" could improve the performance + // by avoiding memory fragmentation. Serious testing is needed. + + // The vertices are filled in clockwise order + std::vector< Point<T> > vertices; + guint8 rgba[4]; + }; + + typedef typename std::vector<Cell>::iterator iterator; + typedef typename std::vector<Cell>::const_iterator const_iterator; + typedef typename std::vector<Cell>::reverse_iterator reverse_iterator; + + typedef typename std::vector<Cell>::const_reverse_iterator + const_reverse_iterator; + + /* + It will work correctly if no crossing-edges are present. + */ + SimplifiedVoronoi(const PixelGraph &graph); + + // Iterators + iterator begin() + { + return _cells.begin(); + } + + const_iterator begin() const + { + return _cells.begin(); + } + + iterator end() + { + return _cells.end(); + } + + const_iterator end() const + { + return _cells.end(); + } + + reverse_iterator rbegin() + { + return _cells.rbegin(); + } + + const_reverse_iterator rbegin() const + { + return _cells.rbegin(); + } + + reverse_iterator rend() + { + return _cells.rend(); + } + + const_reverse_iterator rend() const + { + return _cells.rend(); + } + + size_t size() const + { + return _cells.size(); + } + + int width() const + { + return _width; + } + + int height() const + { + return _height; + } + +private: + typedef void (*PointTransform)(Point<T> &p, T dx, T dy); + typedef bool (*NodeTransform)(PixelGraph::const_iterator); + + static Point<T> _midpoint(const Point<T> &p1, const Point<T> p2) + { + return Point<T>((p1.x + p2.x) / 2, (p1.y + p2.y) / 2); + } + + /** + * Output is translated by -.5 in each axis. This function fixes this error. + */ + static Point<T> _adjust(Point<T> p) + { + return Point<T>(p.x + .5, p.y + .5); + } + + /** + * Output is translated by -.5 in each axis. This function fixes this error. + */ + static Point<T> _adjust(Point<T> p, bool smooth) + { + return Point<T>(p.x + .5, p.y + .5, smooth); + } + + void _complexTopLeft(const PixelGraph &graph, + PixelGraph::const_iterator graph_it, + Cell *const cells_it, int x, int y); + void _complexTopRight(const PixelGraph &graph, + PixelGraph::const_iterator graph_it, + Cell *const cells_it, int x, int y); + void _complexBottomRight(const PixelGraph &graph, + PixelGraph::const_iterator graph_it, + Cell *const cells_it, int x, int y); + void _complexBottomLeft(const PixelGraph &graph, + PixelGraph::const_iterator graph_it, + Cell *const cells_it, int x, int y); + + static void _complexTopLeftTransform(Point<T> &p, T dx, T dy); + static void _complexTopRightTransform(Point<T> &p, T dx, T dy); + static void _complexBottomRightTransform(Point<T> &p, T dx, T dy); + static void _complexBottomLeftTransform(Point<T> &p, T dx, T dy); + + static bool _complexTopLeftTransformTop(PixelGraph::const_iterator graph_it); + static bool _complexTopLeftTransformTopRight(PixelGraph::const_iterator graph_it); + static bool _complexTopLeftTransformRight(PixelGraph::const_iterator graph_it); + static bool _complexTopLeftTransformBottomRight(PixelGraph::const_iterator graph_it); + static bool _complexTopLeftTransformBottom(PixelGraph::const_iterator graph_it); + static bool _complexTopLeftTransformBottomLeft(PixelGraph::const_iterator graph_it); + static bool _complexTopLeftTransformLeft(PixelGraph::const_iterator graph_it); + static bool _complexTopLeftTransformTopLeft(PixelGraph::const_iterator graph_it); + + static bool _complexTopRightTransformTop(PixelGraph::const_iterator graph_it); + static bool _complexTopRightTransformTopRight(PixelGraph::const_iterator graph_it); + static bool _complexTopRightTransformRight(PixelGraph::const_iterator graph_it); + static bool _complexTopRightTransformBottomRight(PixelGraph::const_iterator graph_it); + static bool _complexTopRightTransformBottom(PixelGraph::const_iterator graph_it); + static bool _complexTopRightTransformBottomLeft(PixelGraph::const_iterator graph_it); + static bool _complexTopRightTransformLeft(PixelGraph::const_iterator graph_it); + static bool _complexTopRightTransformTopLeft(PixelGraph::const_iterator graph_it); + + static bool _complexBottomRightTransformTop(PixelGraph::const_iterator graph_it); + static bool _complexBottomRightTransformTopRight(PixelGraph::const_iterator graph_it); + static bool _complexBottomRightTransformRight(PixelGraph::const_iterator graph_it); + static bool _complexBottomRightTransformBottomRight(PixelGraph::const_iterator graph_it); + static bool _complexBottomRightTransformBottom(PixelGraph::const_iterator graph_it); + static bool _complexBottomRightTransformBottomLeft(PixelGraph::const_iterator graph_it); + static bool _complexBottomRightTransformLeft(PixelGraph::const_iterator graph_it); + static bool _complexBottomRightTransformTopLeft(PixelGraph::const_iterator graph_it); + + static bool _complexBottomLeftTransformTop(PixelGraph::const_iterator graph_it); + static bool _complexBottomLeftTransformTopRight(PixelGraph::const_iterator graph_it); + static bool _complexBottomLeftTransformRight(PixelGraph::const_iterator graph_it); + static bool _complexBottomLeftTransformBottomRight(PixelGraph::const_iterator graph_it); + static bool _complexBottomLeftTransformBottom(PixelGraph::const_iterator graph_it); + static bool _complexBottomLeftTransformBottomLeft(PixelGraph::const_iterator graph_it); + static bool _complexBottomLeftTransformLeft(PixelGraph::const_iterator graph_it); + static bool _complexBottomLeftTransformTopLeft(PixelGraph::const_iterator graph_it); + + /* + * The memory layout assumed goes like this (with a_it being the current + * iterated element): + * + * (a_it) | (b_it) + * -------+------- + * (c_it) | (d_it) + * + * If you want to use it with another directions (topleft, topright, ...) + * **DO NOT** invert x or y axis, because the insertion order will go mad. + * + * The idea behind this abstraction is to rotate the iterators, then the + * insertion order will be preserved. + * + * The initial value of all nodes that will be inserted is {x, y}. All + * changes to this node **MUST** occur through \p transform or _adjust. + * + * Some maintainers may like this function because they will handle a + * code base 4 times smaller and bugs will be MUCH MUCH difficult to hide. + * + * Some maintainers may go mad because the level extra level of + * abstracation. + * + * "All problems in computer science can be solved by another level of + * indirection, except for the problem of too many layers of indirection." + * -- David J. Wheeler + */ + void _genericComplexBottomRight(PixelGraph::const_iterator a_it, + PixelGraph::const_iterator b_it, + PixelGraph::const_iterator c_it, + PixelGraph::const_iterator d_it, + Cell *const cells_it, int x, int y, + PointTransform transform, + NodeTransform top, + NodeTransform topright, + NodeTransform right, + NodeTransform bottomright, + NodeTransform bottom, + NodeTransform bottomleft, + NodeTransform left, + NodeTransform topleft); + + int _width; + int _height; + std::vector<Cell> _cells; +}; + +template<class T> +SimplifiedVoronoi<T>::SimplifiedVoronoi(const PixelGraph &graph) : + _width(graph.width()), + _height(graph.height()), + _cells(graph.size()) +{ + if (!graph.size()) + return; + + // ...the "center" cells first... + if ( _width > 2 && _height > 2 ) { + PixelGraph::const_iterator graph_it = graph.begin() + _width + 1; + Cell *cells_it = &_cells.front() + _width + 1; + + for ( int i = 1 ; i != _height - 1 ; ++i ) { + for ( int j = 1 ; j != _width - 1 ; ++j, ++graph_it, ++cells_it ) { + for ( int k = 0 ; k != 4 ; ++k ) + cells_it->rgba[k] = graph_it->rgba[k]; + // Top-left + _complexTopLeft(graph, graph_it, cells_it, j, i); + + // Top-right + _complexTopRight(graph, graph_it, cells_it, j, i); + + // Bottom-right + _complexBottomRight(graph, graph_it, cells_it, j, i); + + // Bottom-left + _complexBottomLeft(graph, graph_it, cells_it, j, i); + } + // After the previous loop, 'it' is poiting to the last cell from + // the row. + // Go south, then first node in the row (increment 'it' by 1) + // Go to the second node in the line (increment 'it' by 1) + graph_it += 2; + cells_it += 2; + } + } + + // ...then the "top" cells... + if ( _width > 2 ) { + PixelGraph::const_iterator graph_it = graph.begin() + 1; + Cell *cells_it = &_cells.front() + 1; + + for ( int i = 1 ; i != _width - 1 ; ++i, ++graph_it, ++cells_it ) { + for ( int j = 0 ; j != 4 ; ++j ) + cells_it->rgba[j] = graph_it->rgba[j]; + + // Top-left + cells_it->vertices.push_back(Point<T>(i, 0, false)); + + // Top-right + cells_it->vertices.push_back(Point<T>(i + 1, 0, false)); + + // Bottom-right + _complexBottomRight(graph, graph_it, cells_it, i, 0); + + // Bottom-left + _complexBottomLeft(graph, graph_it, cells_it, i, 0); + } + } + + // ...then the "bottom" cells... + if ( _width > 2 && _height > 1 ) { + // Node *it = &((*this)[1][_height - 1]); + PixelGraph::const_iterator graph_it + = graph.begin() + (_height - 1) * _width + 1; + Cell *cells_it = &_cells.front() + (_height - 1) * _width + 1; + + for ( int i = 1 ; i != _width - 1 ; ++i, ++graph_it, ++cells_it ) { + for ( int j = 0 ; j != 4 ; ++j ) + cells_it->rgba[j] = graph_it->rgba[j]; + + // Top-left + _complexTopLeft(graph, graph_it, cells_it, i, _height - 1); + + // Top-right + _complexTopRight(graph, graph_it, cells_it, i, _height - 1); + + // Bottom-right + cells_it->vertices.push_back(Point<T>(i + 1, _height, false)); + + // Bottom-left + cells_it->vertices.push_back(Point<T>(i, _height, false)); + } + } + + // ...then the "left" cells... + if ( _height > 2 ) { + PixelGraph::const_iterator graph_it = graph.begin() + _width; + Cell *cells_it = &_cells.front() + _width; + + for ( int i = 1 ; i != _height - 1 ; ++i) { + for ( int j = 0 ; j != 4 ; ++j ) + cells_it->rgba[j] = graph_it->rgba[j]; + + // Top-left + cells_it->vertices.push_back(Point<T>(0, i, false)); + + // Top-right + _complexTopRight(graph, graph_it, cells_it, 0, i); + + // Bottom-right + _complexBottomRight(graph, graph_it, cells_it, 0, i); + + // Bottom-left + cells_it->vertices.push_back(Point<T>(0, i + 1, false)); + + graph_it += _width; + cells_it += _width; + } + } + + // ...then the "right" cells... + if ( _height > 2 && _width > 1 ) { + PixelGraph::const_iterator graph_it = graph.begin() + 2 * _width - 1; + Cell *cells_it = &_cells.front() + 2 * _width - 1; + + for ( int i = 1 ; i != _height - 1 ; ++i ) { + for ( int j = 0 ; j != 4 ; ++j ) + cells_it->rgba[j] = graph_it->rgba[j]; + + // Top-left + _complexTopLeft(graph, graph_it, cells_it, _width - 1, i); + + // Top-right + cells_it->vertices.push_back(Point<T>(_width, i, false)); + + // Bottom-right + cells_it->vertices.push_back(Point<T>(_width, i + 1, false)); + + // Bottom-left + _complexBottomLeft(graph, graph_it, cells_it, _width - 1, i); + + graph_it += _width; + cells_it += _width; + } + } + + // ...and the 4 corner nodes + // top-left + { + PixelGraph::const_iterator graph_it = graph.begin(); + Cell *cells_it = &_cells.front(); + + for ( int i = 0 ; i != 4 ; ++i ) + cells_it->rgba[i] = graph_it->rgba[i]; + + // Top-left + cells_it->vertices.push_back(Point<T>(0, 0, false)); + + // Top-right + cells_it->vertices.push_back(Point<T>(1, 0, false)); + + // Bottom-right + if ( _width > 1 && _height > 1 ) + _complexBottomRight(graph, graph_it, cells_it, 0, 0); + else + cells_it->vertices.push_back(Point<T>(1, 1, false)); + + // Bottom-left + cells_it->vertices.push_back(Point<T>(0, 1, false)); + } + + // top-right + if ( _width > 1 ) { + PixelGraph::const_iterator graph_it = graph.begin() + _width - 1; + Cell *cells_it = &_cells.front() + _width - 1; + + for ( int i = 0 ; i != 4 ; ++i ) + cells_it->rgba[i] = graph_it->rgba[i]; + + // Top-left + cells_it->vertices.push_back(Point<T>(_width - 1, 0, false)); + + // Top-right + cells_it->vertices.push_back(Point<T>(_width, 0, false)); + + // Bottom-right + cells_it->vertices.push_back(Point<T>(_width, 1, false)); + + // Bottom-left + if ( _height > 1 ) + _complexBottomLeft(graph, graph_it, cells_it, _width - 1, 0); + else + cells_it->vertices.push_back(Point<T>(_width - 1, 1, false)); + } + + // bottom-left + if ( _height > 1 ) { + PixelGraph::const_iterator graph_it + = graph.begin() + (_height - 1) * _width; + Cell *cells_it = &_cells.front() + (_height - 1) * _width; + + for ( int i = 0 ; i != 4 ; ++i ) + cells_it->rgba[i] = graph_it->rgba[i]; + + // Top-left + cells_it->vertices.push_back(Point<T>(0, _height - 1, false)); + + // Top-right + if ( _width > 1) + _complexTopRight(graph, graph_it, cells_it, 0, _height - 1); + else + cells_it->vertices.push_back(Point<T>(1, _height - 1, false)); + + // Bottom-right + cells_it->vertices.push_back(Point<T>(1, _height, false)); + + // Bottom-left + cells_it->vertices.push_back(Point<T>(0, _height, false)); + } + + // bottom-right + if ( _width > 1 && _height > 1 ) { + PixelGraph::const_iterator graph_it = --graph.end(); + Cell *cells_it = &_cells.back(); + + for ( int i = 0 ; i != 4 ; ++i ) + cells_it->rgba[i] = graph_it->rgba[i]; + + // Top-left + _complexTopLeft(graph, graph_it, cells_it, _width - 1, _height - 1); + + // Top-right + cells_it->vertices.push_back(Point<T>(_width, _height - 1, false)); + + // Bottom-right + cells_it->vertices.push_back(Point<T>(_width, _height, false)); + + // Bottom-left + cells_it->vertices.push_back(Point<T>(_width - 1, _height, false)); + } +} + +template<class T> void +SimplifiedVoronoi<T>::_complexTopLeft(const PixelGraph &graph, + PixelGraph::const_iterator graph_it, + Cell *const cells_it, int x, int y) +{ + _genericComplexBottomRight(graph_it, + graph.nodeLeft(graph_it), + graph.nodeTop(graph_it), + graph.nodeTopLeft(graph_it), + cells_it, x, y, + &SimplifiedVoronoi::_complexTopLeftTransform, + &SimplifiedVoronoi::_complexTopLeftTransformTop, + &SimplifiedVoronoi::_complexTopLeftTransformTopRight, + &SimplifiedVoronoi::_complexTopLeftTransformRight, + &SimplifiedVoronoi::_complexTopLeftTransformBottomRight, + &SimplifiedVoronoi::_complexTopLeftTransformBottom, + &SimplifiedVoronoi::_complexTopLeftTransformBottomLeft, + &SimplifiedVoronoi::_complexTopLeftTransformLeft, + &SimplifiedVoronoi::_complexTopLeftTransformTopLeft); +} + +template<class T> void +SimplifiedVoronoi<T>::_complexTopRight(const PixelGraph &graph, + PixelGraph::const_iterator graph_it, + Cell *const cells_it, int x, int y) +{ + _genericComplexBottomRight(graph_it, + graph.nodeTop(graph_it), + graph.nodeRight(graph_it), + graph.nodeTopRight(graph_it), + cells_it, x, y, + &SimplifiedVoronoi::_complexTopRightTransform, + &SimplifiedVoronoi::_complexTopRightTransformTop, + &SimplifiedVoronoi::_complexTopRightTransformTopRight, + &SimplifiedVoronoi::_complexTopRightTransformRight, + &SimplifiedVoronoi::_complexTopRightTransformBottomRight, + &SimplifiedVoronoi::_complexTopRightTransformBottom, + &SimplifiedVoronoi::_complexTopRightTransformBottomLeft, + &SimplifiedVoronoi::_complexTopRightTransformLeft, + &SimplifiedVoronoi::_complexTopRightTransformTopLeft); +} + +template<class T> void +SimplifiedVoronoi<T>::_complexBottomRight(const PixelGraph &graph, + PixelGraph::const_iterator graph_it, + Cell *const cells_it, int x, int y) +{ + _genericComplexBottomRight(graph_it, + graph.nodeRight(graph_it), + graph.nodeBottom(graph_it), + graph.nodeBottomRight(graph_it), + cells_it, x, y, + &SimplifiedVoronoi::_complexBottomRightTransform, + &SimplifiedVoronoi::_complexBottomRightTransformTop, + &SimplifiedVoronoi::_complexBottomRightTransformTopRight, + &SimplifiedVoronoi::_complexBottomRightTransformRight, + &SimplifiedVoronoi::_complexBottomRightTransformBottomRight, + &SimplifiedVoronoi::_complexBottomRightTransformBottom, + &SimplifiedVoronoi::_complexBottomRightTransformBottomLeft, + &SimplifiedVoronoi::_complexBottomRightTransformLeft, + &SimplifiedVoronoi::_complexBottomRightTransformTopLeft); +} + +template<class T> void +SimplifiedVoronoi<T>::_complexBottomLeft(const PixelGraph &graph, + PixelGraph::const_iterator graph_it, + Cell *const cells_it, int x, int y) +{ + _genericComplexBottomRight(graph_it, + graph.nodeBottom(graph_it), + graph.nodeLeft(graph_it), + graph.nodeBottomLeft(graph_it), + cells_it, x, y, + &SimplifiedVoronoi::_complexBottomLeftTransform, + &SimplifiedVoronoi::_complexBottomLeftTransformTop, + &SimplifiedVoronoi::_complexBottomLeftTransformTopRight, + &SimplifiedVoronoi::_complexBottomLeftTransformRight, + &SimplifiedVoronoi::_complexBottomLeftTransformBottomRight, + &SimplifiedVoronoi::_complexBottomLeftTransformBottom, + &SimplifiedVoronoi::_complexBottomLeftTransformBottomLeft, + &SimplifiedVoronoi::_complexBottomLeftTransformLeft, + &SimplifiedVoronoi::_complexBottomLeftTransformTopLeft); +} + +template<class T> void +SimplifiedVoronoi<T>::_complexTopLeftTransform(Point<T> &p, T dx, T dy) +{ + p.x -= dx; + p.y -= dy; +} + +template<class T> void +SimplifiedVoronoi<T>::_complexTopRightTransform(Point<T> &p, T dx, T dy) +{ + p.x += dy; + p.y -= dx; +} + +template<class T> void +SimplifiedVoronoi<T>::_complexBottomRightTransform(Point<T> &p, T dx, T dy) +{ + p.x += dx; + p.y += dy; +} + +template<class T> void +SimplifiedVoronoi<T>::_complexBottomLeftTransform(Point<T> &p, T dx, T dy) +{ + p.x -= dy; + p.y += dx; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopLeftTransformTop(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.bottom; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopLeftTransformTopRight(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.bottomleft; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopLeftTransformRight(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.left; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopLeftTransformBottomRight(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.topleft; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopLeftTransformBottom(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.top; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopLeftTransformBottomLeft(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.topright; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopLeftTransformLeft(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.right; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopLeftTransformTopLeft(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.bottomright; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopRightTransformTop(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.left; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopRightTransformTopRight(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.topleft; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopRightTransformRight(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.top; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopRightTransformBottomRight(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.topright; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopRightTransformBottom(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.right; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopRightTransformBottomLeft(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.bottomright; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopRightTransformLeft(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.bottom; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexTopRightTransformTopLeft(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.bottomleft; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomRightTransformTop(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.top; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomRightTransformTopRight(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.topright; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomRightTransformRight(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.right; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomRightTransformBottomRight(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.bottomright; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomRightTransformBottom(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.bottom; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomRightTransformBottomLeft(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.bottomleft; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomRightTransformLeft(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.left; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomRightTransformTopLeft(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.topleft; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomLeftTransformTop(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.right; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomLeftTransformTopRight(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.bottomright; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomLeftTransformRight(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.bottom; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomLeftTransformBottomRight(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.bottomleft; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomLeftTransformBottom(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.left; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomLeftTransformBottomLeft(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.topleft; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomLeftTransformLeft(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.top; +} + +template<class T> +bool SimplifiedVoronoi<T>::_complexBottomLeftTransformTopLeft(PixelGraph::const_iterator graph_it) +{ + return graph_it->adj.topright; +} + +template<class T> +void +SimplifiedVoronoi<T> +::_genericComplexBottomRight(PixelGraph::const_iterator a_it, + PixelGraph::const_iterator b_it, + PixelGraph::const_iterator c_it, + PixelGraph::const_iterator d_it, + Cell *const cells_it, int x, int y, + PointTransform transform, + NodeTransform top, + NodeTransform topright, + NodeTransform right, + NodeTransform bottomright, + NodeTransform bottom, + NodeTransform bottomleft, + NodeTransform left, + NodeTransform topleft) +{ + using colorspace::contour_edge; + using colorspace::same_color; + + const Point<T> initial(x, y); + + if ( bottomright(a_it) ) { + // this and bottom-right are connected + + bool smooth[2] = { + same_color(a_it->rgba, d_it->rgba) + right(a_it), + same_color(a_it->rgba, d_it->rgba) + bottom(a_it) + }; + + Point<T> borderMid = initial; + { + transform(borderMid, 1, 1); + borderMid = _midpoint(initial, borderMid); + } + + Point<T> vertices[2] = {initial, initial}; + { + transform(vertices[0], 1, 0); + vertices[0] = _adjust(_midpoint(borderMid, vertices[0]), smooth[0]); + + transform(vertices[1], 0, 1); + vertices[1] = _adjust(_midpoint(borderMid, vertices[1]), smooth[1]); + } + + if ( !smooth[0] ) { + cells_it->vertices.push_back(vertices[0]); + { + Point<T> another = vertices[0]; + transform(another, + - ( 0.1875 + - ( topright(a_it) - topleft(b_it) ) * 0.1875 ), + // y + - ( 0.5625 + - ( topright(a_it) + topleft(b_it) ) * 0.1875 )); + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertices[0]; + transform(another, + - ( 0.0625 + - ( topright(a_it) - topleft(b_it) ) * 0.0625 ), + // y + - ( 0.1875 + - ( topright(a_it) + topleft(b_it) ) * 0.0625) ); + another.smooth = true; + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertices[0]; + transform(another, + 0.1875 + - ( bottomright(b_it) + topright(d_it) ) * 0.0625, + // y + 0.0625 + + ( bottomright(b_it) - topright(d_it) ) * 0.0625); + cells_it->vertices.push_back(another); + } + { + transform(vertices[0], + 0.0625 + + ( topright(a_it) - topright(d_it) - topleft(b_it) + - bottomright(b_it) ) * 0.03125, + // y + - ( 0.0625 + + ( topright(d_it) - topright(a_it) + - topleft(b_it) - bottomright(b_it) ) + * 0.03125 )); + } + } + + cells_it->vertices.push_back(vertices[0]); + + if ( !smooth[1] ) { + { + Point<T> another = vertices[1]; + transform(another, + - ( 0.0625 + + ( bottomleft(d_it) - bottomleft(a_it) + - topleft(c_it) - bottomright(c_it) ) + * 0.03125 ), + // y + 0.0625 + + ( bottomleft(a_it) - bottomleft(d_it) + - topleft(c_it) - bottomright(c_it) ) * 0.03125); + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertices[1]; + transform(another, + 0.0625 + + ( bottomright(c_it) - bottomleft(d_it) ) * 0.0625, + // y + 0.1875 + - ( bottomright(c_it) + bottomleft(d_it) ) * 0.0625); + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertices[1]; + transform(another, + - ( 0.1875 + - ( bottomleft(a_it) + topleft(c_it) ) + * 0.0625 ), + // y + - ( 0.0625 + - ( bottomleft(a_it) - topleft(c_it) ) + * 0.0625 )); + another.smooth = true; + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertices[1]; + transform(another, + - ( 0.5625 + - ( bottomleft(a_it) + topleft(c_it) ) + * 0.1875 ), + // y + - ( 0.1875 + - ( bottomleft(a_it) - topleft(c_it) ) + * 0.1875 )); + cells_it->vertices.push_back(another); + } + } + + cells_it->vertices.push_back(vertices[1]); + } else if ( bottomleft(b_it) ) { + // right and bottom are connected + + Point<T> vertex = initial; + transform(vertex, 1, 1); + vertex = _adjust(_midpoint(_midpoint(initial, vertex), initial), true); + cells_it->vertices.push_back(vertex); + } else { + // Connections don't affect the shape of this squared-like + // pixel + + Point<T> vertex = initial; + transform(vertex, 1, 1); + vertex = _adjust(_midpoint(initial, vertex)); + + // compute smoothness + if ( right(a_it) ) { + // this and right are connected + + if ( !right(c_it) && !( bottom(a_it) && bottom(b_it) ) ) { + // bottom and bottom-right are disconnected + + bool foreign_is_contour = contour_edge(c_it->rgba, d_it->rgba); + bool twin_is_contour = contour_edge(b_it->rgba, d_it->rgba); + bool another_is_contour = contour_edge(a_it->rgba, c_it->rgba); + + if ( another_is_contour + twin_is_contour + + foreign_is_contour == 2 ) { + vertex.smooth = !foreign_is_contour; + + if ( !vertex.smooth ) { + if ( another_is_contour ) { + { + Point<T> another = vertex; + T amount = 0.125 + - ( ( bottomright(c_it) + topleft(c_it) ) + * 0.03125 ); + transform(another, - amount, amount); + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertex; + T amount = 0.0625 * bottomright(c_it); + transform(another, amount, 0.25 - amount); + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertex; + T amount = 0.0625 * topleft(c_it); + transform(another, - ( 0.25 - amount ), + - amount); + another.smooth = true; + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertex; + T amount = 0.1875 * topleft(c_it); + transform(another, - ( 0.75 - amount ), + - amount); + cells_it->vertices.push_back(another); + } + } else if ( twin_is_contour ) { + T amount = 0.125 + - ( ( bottomleft(d_it) + topright(d_it) ) + * 0.03125 ); + transform(vertex, amount, amount); + } + } + } else { + // {this, right} is the pair with the angle + // closest to 180 degrees + vertex.smooth = true; + } + } else { + // there might be 2-color, then vertex.smooth = true + + // or it might be 1-color and doesn't matter, + // because the current node will disappear + vertex.smooth + = !( bottom(a_it) ^ bottom(b_it) ); + + if ( vertex.smooth ) { + vertex.smooth + = same_color(a_it->rgba, b_it->rgba) + + same_color(a_it->rgba, c_it->rgba) + + same_color(d_it->rgba, b_it->rgba) + + same_color(d_it->rgba, c_it->rgba) == 2; + } + } + } else if ( bottom(a_it) ) { + // this and bottom are connected + + if ( !bottom(b_it) && !( right(a_it) && right(c_it) ) ) { + // right and bottom-right are disconnected + + bool foreign_is_contour = contour_edge(b_it->rgba, d_it->rgba); + bool twin_is_contour = contour_edge(c_it->rgba, d_it->rgba); + bool another_is_contour = contour_edge(a_it->rgba, b_it->rgba); + + if ( another_is_contour + twin_is_contour + + foreign_is_contour == 2 ) { + vertex.smooth = !foreign_is_contour; + + if ( !vertex.smooth ) { + if ( another_is_contour ) { + cells_it->vertices.push_back(vertex); + { + Point<T> another = vertex; + T amount = 0.1875 * topleft(b_it); + transform(another, - amount, + - ( 0.75 - amount )); + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertex; + T amount = 0.0625 * topleft(b_it); + transform(another, - amount, + - ( 0.25 - amount )); + another.smooth = true; + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertex; + T amount = 0.0625 * bottomright(b_it); + transform(another, 0.25 - amount, amount); + cells_it->vertices.push_back(another); + } + { + T amount = 0.125 + - (bottomright(b_it) + topleft(b_it)) + * 0.03125; + transform(vertex, amount, - amount); + } + } else if ( twin_is_contour ) { + T amount = 0.125 + - ( ( topright(d_it) + bottomleft(d_it) ) + * 0.03125 ); + transform(vertex, amount, amount); + } + } + } else { + // {this, bottom} is the pair with the angle + // closest to 180 degrees + vertex.smooth = true; + } + } else { + // there might be 2-color, then vertex.smooth = true + + // or it might be 1-color and doesn't matter, + // because the current node will disappear + vertex.smooth = !( right(a_it) ^ right(c_it) ); + + if ( vertex.smooth ) { + vertex.smooth + = same_color(a_it->rgba, c_it->rgba) + + same_color(a_it->rgba, b_it->rgba) + + same_color(d_it->rgba, b_it->rgba) + + same_color(d_it->rgba, c_it->rgba) == 2; + } + } + } else if ( bottom(b_it) ) { + // right and bottom-right are connected + + bool special = false; + + bool foreign_is_contour = contour_edge(c_it->rgba, d_it->rgba); + + // the neighbor similar in 90° feature + bool similar_neighbor_is_contour + = contour_edge(a_it->rgba, c_it->rgba); + + if ( contour_edge(a_it->rgba, b_it->rgba) + + similar_neighbor_is_contour + + foreign_is_contour == 2 ) { + vertex.smooth = !foreign_is_contour; + + if ( !vertex.smooth ) { + if ( similar_neighbor_is_contour ) { + { + Point<T> another = vertex; + T amount = 0.125 + - ( topleft(c_it) + bottomright(c_it) ) + * 0.03125; + transform(another, - amount, amount); + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertex; + T amount = 0.0625 * bottomright(c_it); + transform(another, amount, 0.25 - amount); + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertex; + T amount = 0.0625 * topleft(c_it); + transform(another, - ( 0.25 - amount ), - amount); + another.smooth = true; + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertex; + T amount = 0.1875 * topleft(c_it); + transform(another, - ( 0.75 - amount ), - amount); + cells_it->vertices.push_back(another); + } + } else { + special = true; + } + } + } else { + // {right, bottom-right} is the pair with the + // angle closest to 180 degrees + vertex.smooth = false; + + special = true; + } + + if ( special ) { + cells_it->vertices.push_back(vertex); + { + Point<T> another = vertex; + T amount = 0.1875; + transform(another, + - ( topleft(b_it) - topright(a_it) ) * amount, + // y + - ( 0.75 + - ( topleft(b_it) + topright(a_it) ) + * amount )); + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertex; + T amount = 0.0625; + transform(another, + - ( topleft(b_it) - topright(a_it) ) * amount, + // y + - ( 0.25 + - ( topleft(b_it) + topright(a_it) ) + * amount )); + another.smooth = true; + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertex; + T amount = 0.0625; + transform(another, - amount + * ( bottomleft(d_it) - bottomright(c_it) ), + // y + 0.25 - amount + * ( bottomleft(d_it) + bottomright(c_it) )); + cells_it->vertices.push_back(another); + } + { + transform(vertex, + - ( topleft(b_it) + bottomleft(d_it) + - topright(a_it) - bottomright(c_it) ) + * 0.03125, + // y + ( topleft(b_it) - bottomleft(d_it) + + topright(a_it) - bottomright(c_it) ) + * 0.03125); + } + } + } else if ( right(c_it) ) { + // bottom and bottom-right are connected + + bool special = false; + + bool foreign_is_contour = contour_edge(b_it->rgba, d_it->rgba); + + // the neighbor similar in 90° feature + bool similar_neighbor_is_contour + = contour_edge(a_it->rgba, b_it->rgba); + + if ( contour_edge(a_it->rgba, c_it->rgba) + + similar_neighbor_is_contour + + foreign_is_contour == 2 ) { + vertex.smooth = !foreign_is_contour; + + if ( !vertex.smooth ) { + if ( similar_neighbor_is_contour ) { + cells_it->vertices.push_back(vertex); + { + Point<T> another = vertex; + T amount = 0.1875 * topleft(b_it); + transform(another, - amount, - ( 0.75 - amount )); + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertex; + T amount = 0.0625 * topleft(b_it); + transform(another, - amount, - ( 0.25 - amount )); + another.smooth = true; + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertex; + T amount = 0.0625 * bottomright(b_it); + transform(another, 0.25 - amount, amount); + cells_it->vertices.push_back(another); + } + { + T amount = 0.125 + - 0.03125 * (topleft(b_it) + bottomright(b_it)); + transform(vertex, amount, - amount); + } + } else { + special = true; + } + } + } else { + // {bottom, bottom-right} is the pair with the + // angle closest to 180 degrees + vertex.smooth = false; + + special = true; + } + + if ( special ) { + { + Point<T> another = vertex; + T amount = 0.03125; + transform(another, + amount + * ( topleft(c_it) - topright(d_it) + + bottomleft(a_it) - bottomright(b_it) ), + // y + - amount + * ( topleft(c_it) + topright(d_it) + - bottomleft(a_it) - bottomright(b_it) )); + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertex; + T amount = 0.0625; + transform(another, + 0.25 - amount + * ( topright(d_it) + bottomright(b_it) ), + // y + - amount + * ( topright(d_it) - bottomright(b_it) )); + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertex; + T amount = 0.0625; + transform(another, + - ( 0.25 - amount + * ( topleft(c_it) + bottomleft(a_it) ) ), + // y + - amount + * ( topleft(c_it) - bottomleft(a_it) )); + another.smooth = true; + cells_it->vertices.push_back(another); + } + { + Point<T> another = vertex; + T amount = 0.1875; + transform(another, + - ( 0.75 - amount + * ( topleft(c_it) + bottomleft(a_it) ) ), + // y + - amount + * ( topleft(c_it) - bottomleft(a_it) )); + cells_it->vertices.push_back(another); + } + } + } else { + // there is a 4-color pattern, where the current node + // won't be smooth + vertex.smooth = false; + } + + cells_it->vertices.push_back(vertex); + } +} + +} // namespace Tracer + +#endif // LIBDEPIXELIZE_TRACER_SIMPLIFIEDVORONOI_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/libdepixelize/priv/splines.h b/src/libdepixelize/priv/splines.h new file mode 100644 index 000000000..c7ef2b492 --- /dev/null +++ b/src/libdepixelize/priv/splines.h @@ -0,0 +1,155 @@ +/* This file is part of the libdepixelize project + Copyright (C) 2013 VinÃcius dos Santos Oliveira <vini.ipsmaker@gmail.com> + + GNU Lesser General Public License Usage + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + You should have received a copy of the GNU Lesser General Public License + along with this library. If not, see <http://www.gnu.org/licenses/>. + + GNU General Public License Usage + Alternatively, this library may be used under the terms of the GNU General + Public License as published by the Free Software Foundation, either version + 2 of the License, or (at your option) any later version. + You should have received a copy of the GNU General Public License along with + this library. If not, see <http://www.gnu.org/licenses/>. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. +*/ + +#ifndef LIBDEPIXELIZE_TRACER_SPLINES_PRIV_H +#define LIBDEPIXELIZE_TRACER_SPLINES_PRIV_H + +#include "../splines.h" +#include "homogeneoussplines.h" + +namespace Tracer { + +template<class T> +Geom::Point to_geom_point(Point<T> p) +{ + return Geom::Point(p.x, p.y); +} + +template<class T> +Geom::Path worker_helper(const std::vector< Point<T> > &source, bool optimize) +{ + typedef Geom::LineSegment Line; + typedef Geom::QuadraticBezier Quad; + typedef typename std::vector< Point<T> >::const_iterator iterator; + + iterator it = source.begin(); + Geom::Path ret(to_geom_point((source.back() + *it) / 2)); + + for ( iterator end = --source.end() ; it != end ; ++it ) { + Point<T> next = *(it + 1); + Point<T> middle = (*it + next) / 2; + + if ( !it->smooth ) { + // TODO: remove redundant colinear points + ret.appendNew<Line>(Geom::Point(it->x, it->y)); + ret.appendNew<Line>(Geom::Point(middle.x, middle.y)); + } else { + ret.appendNew<Quad>(Geom::Point(it->x, it->y), + Geom::Point(middle.x, middle.y)); + } + } + + { + Point<T> next = source.front(); + Point<T> middle = (*it + next) / 2; + + if ( !it->smooth ) { + ret.appendNew<Line>(Geom::Point(it->x, it->y)); + ret.appendNew<Line>(Geom::Point(middle.x, middle.y)); + } else { + ret.appendNew<Quad>(Geom::Point(it->x, it->y), + Geom::Point(middle.x, middle.y)); + } + } + + return ret; +} + +/** + * It should be used by worker threads. Convert only one object. + */ +template<class T> +void worker(const typename HomogeneousSplines<T>::Polygon &source, + Splines::Path &dest, bool optimize) +{ + dest.pathVector.reserve(source.holes.size() + 1); + + for ( int i = 0 ; i != 4 ; ++i ) + dest.rgba[i] = source.rgba[i]; + + dest.pathVector.push_back(worker_helper(source.vertices, optimize)); + + for ( typename std::vector< std::vector< Point<T> > >::const_iterator + it = source.holes.begin(), end = source.holes.end() + ; it != end ; ++it ) { + dest.pathVector.push_back(worker_helper(*it, optimize)); + } +} + +template<typename T> +Splines::Splines(const SimplifiedVoronoi<T> &diagram) +{ + _paths.reserve(diagram.size()); + + for ( typename SimplifiedVoronoi<T>::const_iterator it = diagram.begin() + , end = diagram.end() ; it != end ; ++it ) { + Path path; + + path.pathVector + .push_back(Geom::Path(to_geom_point(it->vertices.front()))); + + for ( typename std::vector< Point<T> >::const_iterator + it2 = it->vertices.begin(), end2 = it->vertices.end() + ; it2 != end2 ; ++it2 ) { + path.pathVector.back() + .appendNew<Geom::LineSegment>(Geom::Point(it2->x, it2->y)); + } + + for ( int i = 0 ; i != 4 ; ++i ) + path.rgba[i] = it->rgba[i]; + + _paths.push_back(path); + } +} + +template<class T> +Splines::Splines(const HomogeneousSplines<T> &homogeneousSplines, + bool optimize, int nthreads) : + _paths(homogeneousSplines.size()), + _width(homogeneousSplines.width()), + _height(homogeneousSplines.height()) +{ + // TODO: It should be threaded + iterator paths_it = begin(); + for ( typename HomogeneousSplines<T>::const_iterator + it = homogeneousSplines.begin(), end = homogeneousSplines.end() + ; it != end ; ++it, ++paths_it ) { + worker<T>(*it, *paths_it, optimize); + } +} + +} // namespace Tracer + +#endif // LIBDEPIXELIZE_TRACER_SPLINES_PRIV_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/libdepixelize/splines.h b/src/libdepixelize/splines.h new file mode 100644 index 000000000..c4b455aae --- /dev/null +++ b/src/libdepixelize/splines.h @@ -0,0 +1,120 @@ +/* This file is part of the libdepixelize project + Copyright (C) 2013 VinÃcius dos Santos Oliveira <vini.ipsmaker@gmail.com> + + GNU Lesser General Public License Usage + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + You should have received a copy of the GNU Lesser General Public License + along with this library. If not, see <http://www.gnu.org/licenses/>. + + GNU General Public License Usage + Alternatively, this library may be used under the terms of the GNU General + Public License as published by the Free Software Foundation, either version + 2 of the License, or (at your option) any later version. + You should have received a copy of the GNU General Public License along with + this library. If not, see <http://www.gnu.org/licenses/>. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. +*/ + +#ifndef LIBDEPIXELIZE_TRACER_SPLINES_H +#define LIBDEPIXELIZE_TRACER_SPLINES_H + +#include <2geom/pathvector.h> +#include <glib.h> + +namespace Tracer { + +template<typename T> +class SimplifiedVoronoi; + +template<typename T> +class HomogeneousSplines; + +class Splines +{ +public: + struct Path + { + /** + * It may be benefited from C++11 move references. + */ + Geom::PathVector pathVector; + + guint8 rgba[4]; + }; + + typedef std::vector<Path>::iterator iterator; + typedef std::vector<Path>::const_iterator const_iterator; + + Splines() /* = default */ {} + + template<typename T> + Splines(const SimplifiedVoronoi<T> &simplifiedVoronoi); + + /** + * There are two levels of optimization. The first level only removes + * redundant points of colinear points. The second level uses the + * Kopf-Lischinski optimization. The first level is always enabled. + * The second level is enabled using \p optimize. + */ + template<typename T> + Splines(const HomogeneousSplines<T> &homogeneousSplines, bool optimize, + int nthreads); + + // Iterators + iterator begin() + { + return _paths.begin(); + } + + const_iterator begin() const + { + return _paths.begin(); + } + + iterator end() + { + return _paths.end(); + } + + const_iterator end() const + { + return _paths.end(); + } + + int width() const + { + return _width; + } + + int height() const + { + return _height; + } + +private: + std::vector<Path> _paths; + int _width; + int _height; +}; + +} // namespace Tracer + +#endif // LIBDEPIXELIZE_TRACER_SPLINES_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/libnrtype/Layout-TNG-Compute.cpp b/src/libnrtype/Layout-TNG-Compute.cpp index 1b2704a7e..7ea089c93 100644 --- a/src/libnrtype/Layout-TNG-Compute.cpp +++ b/src/libnrtype/Layout-TNG-Compute.cpp @@ -706,7 +706,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ if (newcluster){ // find where the text ends for this log_cluster end_byte = it_span->start.iter_span->text_bytes; // Upper limit - for(unsigned next_glyph_index = glyph_index+1; next_glyph_index < it_span->end_glyph_index; next_glyph_index++){ + for(int next_glyph_index = glyph_index+1; next_glyph_index < unbroken_span.glyph_string->num_glyphs; next_glyph_index++){ if(unbroken_span.glyph_string->glyphs[next_glyph_index].attr.is_cluster_start){ end_byte = unbroken_span.glyph_string->log_clusters[next_glyph_index]; break; diff --git a/src/live_effects/lpeobject.cpp b/src/live_effects/lpeobject.cpp index 3e4e40198..d61f2b2fa 100644 --- a/src/live_effects/lpeobject.cpp +++ b/src/live_effects/lpeobject.cpp @@ -20,33 +20,18 @@ //#define LIVEPATHEFFECT_VERBOSE -static void livepatheffect_on_repr_attr_changed (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive, void * data); +#include "sp-factory.h" -static SPObjectClass *livepatheffect_parent_class; -/** - * Registers the LivePathEffect class with Gdk and returns its type number. - */ -GType -LivePathEffectObject::livepatheffect_get_type () -{ - static GType livepatheffect_type = 0; - - if (!livepatheffect_type) { - GTypeInfo livepatheffect_info = { - sizeof (LivePathEffectObjectClass), - NULL, NULL, - (GClassInitFunc) LivePathEffectObject::livepatheffect_class_init, - NULL, NULL, - sizeof (LivePathEffectObject), - 16, - (GInstanceInitFunc) LivePathEffectObject::livepatheffect_init, - NULL, - }; - livepatheffect_type = g_type_register_static (SP_TYPE_OBJECT, "LivePathEffectObject", &livepatheffect_info, (GTypeFlags)0); - } - return livepatheffect_type; +namespace { + SPObject* createLivepatheffect() { + return new LivePathEffectObject(); + } + + bool livepatheffectRegistered = SPFactory::instance().registerObject("inkscape:path-effect", createLivepatheffect); } +static void livepatheffect_on_repr_attr_changed (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive, void * data); + static Inkscape::XML::NodeEventVector const livepatheffect_repr_events = { NULL, /* child_added */ NULL, /* child_removed */ @@ -56,57 +41,31 @@ static Inkscape::XML::NodeEventVector const livepatheffect_repr_events = { }; -/** - * Callback to initialize livepatheffect vtable. - */ -void -LivePathEffectObject::livepatheffect_class_init(LivePathEffectObjectClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - - livepatheffect_parent_class = (SPObjectClass *) g_type_class_ref(SP_TYPE_OBJECT); - - sp_object_class->build = livepatheffect_build; - sp_object_class->release = livepatheffect_release; - - sp_object_class->set = livepatheffect_set; - sp_object_class->write = livepatheffect_write; -} - -/** - * Callback to initialize livepatheffect object. - */ -void -LivePathEffectObject::livepatheffect_init(LivePathEffectObject *lpeobj) +LivePathEffectObject::LivePathEffectObject() + : SPObject(), effecttype(Inkscape::LivePathEffect::INVALID_LPE), effecttype_set(false), + lpe(NULL) { #ifdef LIVEPATHEFFECT_VERBOSE g_message("Init livepatheffectobject"); #endif - lpeobj->effecttype = Inkscape::LivePathEffect::INVALID_LPE; - lpeobj->lpe = NULL; +} - lpeobj->effecttype_set = false; +LivePathEffectObject::~LivePathEffectObject() { } /** * Virtual build: set livepatheffect attributes from its associated XML node. */ -void -LivePathEffectObject::livepatheffect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ -#ifdef LIVEPATHEFFECT_VERBOSE - g_message("Build livepatheffect"); -#endif - g_assert(object != NULL); - g_assert(SP_IS_OBJECT(object)); +void LivePathEffectObject::build(SPDocument *document, Inkscape::XML::Node *repr) { + g_assert(this != NULL); + g_assert(SP_IS_OBJECT(this)); - if (((SPObjectClass *) livepatheffect_parent_class)->build) - (* ((SPObjectClass *) livepatheffect_parent_class)->build)(object, document, repr); + SPObject::build(document, repr); - object->readAttr( "effect" ); + this->readAttr( "effect" ); if (repr) { - repr->addListener (&livepatheffect_repr_events, object); + repr->addListener (&livepatheffect_repr_events, this); } /* Register ourselves, is this necessary? */ @@ -116,17 +75,8 @@ LivePathEffectObject::livepatheffect_build(SPObject *object, SPDocument *documen /** * Virtual release of livepatheffect members before destruction. */ -void -LivePathEffectObject::livepatheffect_release(SPObject *object) -{ -#ifdef LIVEPATHEFFECT_VERBOSE - g_print("Releasing livepatheffect"); -#endif - - LivePathEffectObject *lpeobj = LIVEPATHEFFECT(object); - - object->getRepr()->removeListenerByData(object); - +void LivePathEffectObject::release() { + this->getRepr()->removeListenerByData(this); /* if (object->document) { @@ -142,77 +92,64 @@ LivePathEffectObject::livepatheffect_release(SPObject *object) } gradient->modified_connection.~connection(); - */ - if (lpeobj->lpe) { - delete lpeobj->lpe; - lpeobj->lpe = NULL; + if (this->lpe) { + delete this->lpe; + this->lpe = NULL; } - lpeobj->effecttype = Inkscape::LivePathEffect::INVALID_LPE; - if (((SPObjectClass *) livepatheffect_parent_class)->release) - ((SPObjectClass *) livepatheffect_parent_class)->release(object); + this->effecttype = Inkscape::LivePathEffect::INVALID_LPE; + + SPObject::release(); } /** * Virtual set: set attribute to value. */ -void -LivePathEffectObject::livepatheffect_set(SPObject *object, unsigned key, gchar const *value) -{ - LivePathEffectObject *lpeobj = LIVEPATHEFFECT(object); +void LivePathEffectObject::set(unsigned key, gchar const *value) { #ifdef LIVEPATHEFFECT_VERBOSE g_print("Set livepatheffect"); #endif + switch (key) { case SP_PROP_PATH_EFFECT: - if (lpeobj->lpe) { - delete lpeobj->lpe; - lpeobj->lpe = NULL; + if (this->lpe) { + delete this->lpe; + this->lpe = NULL; } if ( value && Inkscape::LivePathEffect::LPETypeConverter.is_valid_key(value) ) { - lpeobj->effecttype = Inkscape::LivePathEffect::LPETypeConverter.get_id_from_key(value); - lpeobj->lpe = Inkscape::LivePathEffect::Effect::New(lpeobj->effecttype, lpeobj); - lpeobj->effecttype_set = true; + this->effecttype = Inkscape::LivePathEffect::LPETypeConverter.get_id_from_key(value); + this->lpe = Inkscape::LivePathEffect::Effect::New(this->effecttype, this); + this->effecttype_set = true; } else { - lpeobj->effecttype = Inkscape::LivePathEffect::INVALID_LPE; - lpeobj->effecttype_set = false; + this->effecttype = Inkscape::LivePathEffect::INVALID_LPE; + this->effecttype_set = false; } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } - if (((SPObjectClass *) livepatheffect_parent_class)->set) { - ((SPObjectClass *) livepatheffect_parent_class)->set(object, key, value); - } + SPObject::set(key, value); } /** * Virtual write: write object attributes to repr. */ -Inkscape::XML::Node * -LivePathEffectObject::livepatheffect_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ -#ifdef LIVEPATHEFFECT_VERBOSE - g_print("Write livepatheffect"); -#endif - - LivePathEffectObject *lpeobj = LIVEPATHEFFECT(object); - +Inkscape::XML::Node* LivePathEffectObject::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("inkscape:path-effect"); } - if ((flags & SP_OBJECT_WRITE_ALL) || lpeobj->lpe) { - repr->setAttribute("effect", Inkscape::LivePathEffect::LPETypeConverter.get_key(lpeobj->effecttype).c_str()); + if ((flags & SP_OBJECT_WRITE_ALL) || this->lpe) { + repr->setAttribute("effect", Inkscape::LivePathEffect::LPETypeConverter.get_key(this->effecttype).c_str()); - lpeobj->lpe->writeParamsToSVG(); + this->lpe->writeParamsToSVG(); } - if (((SPObjectClass *) livepatheffect_parent_class)->write) - (* ((SPObjectClass *) livepatheffect_parent_class)->write)(object, xml_doc, repr, flags); + SPObject::write(xml_doc, repr, flags); return repr; } diff --git a/src/live_effects/lpeobject.h b/src/live_effects/lpeobject.h index 2d04f8842..534a12897 100644 --- a/src/live_effects/lpeobject.h +++ b/src/live_effects/lpeobject.h @@ -22,17 +22,14 @@ namespace Inkscape { } } -#define TYPE_LIVEPATHEFFECT (LivePathEffectObject::livepatheffect_get_type()) -#define LIVEPATHEFFECT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), TYPE_LIVEPATHEFFECT, LivePathEffectObject)) -#define IS_LIVEPATHEFFECT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), TYPE_LIVEPATHEFFECT)) - -/// The LivePathEffect vtable. -struct LivePathEffectObjectClass { - SPObjectClass parent_class; -}; +#define LIVEPATHEFFECT(obj) ((LivePathEffectObject*)obj) +#define IS_LIVEPATHEFFECT(obj) (dynamic_cast<const LivePathEffectObject*>((SPObject*)obj)) class LivePathEffectObject : public SPObject { public: + LivePathEffectObject(); + virtual ~LivePathEffectObject(); + Inkscape::LivePathEffect::EffectType effecttype; bool effecttype_set; @@ -43,21 +40,16 @@ public: * So one should always check whether the returned value is NULL or not */ Inkscape::LivePathEffect::Effect * get_lpe() { return lpe; }; -private: Inkscape::LivePathEffect::Effect *lpe; // this can be NULL in a valid LivePathEffectObject - /* C-style class functions: */ -public: - static GType livepatheffect_get_type(); -private: - static void livepatheffect_class_init(LivePathEffectObjectClass *klass); - static void livepatheffect_init(LivePathEffectObject *stop); - static void livepatheffect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); - static void livepatheffect_release(SPObject *object); - static void livepatheffect_set(SPObject *object, unsigned key, gchar const *value); - static Inkscape::XML::Node *livepatheffect_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void set(unsigned int key, const gchar* value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); +}; #endif diff --git a/src/lpe-tool-context.cpp b/src/lpe-tool-context.cpp index 062a75a7b..63707c1c5 100644 --- a/src/lpe-tool-context.cpp +++ b/src/lpe-tool-context.cpp @@ -43,13 +43,6 @@ using Inkscape::Util::unit_table; -static void sp_lpetool_context_dispose(GObject *object); - -static void sp_lpetool_context_setup(SPEventContext *ec); -static void sp_lpetool_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *); -static gint sp_lpetool_context_item_handler(SPEventContext *ec, SPItem *item, GdkEvent *event); -static gint sp_lpetool_context_root_handler(SPEventContext *ec, GdkEvent *event); - void sp_lpetool_context_selection_changed(Inkscape::Selection *selection, gpointer data); const int num_subtools = 8; @@ -66,96 +59,80 @@ SubtoolEntry lpesubtools[] = { {Inkscape::LivePathEffect::MIRROR_SYMMETRY, "draw-geometry-mirror"} }; -G_DEFINE_TYPE(SPLPEToolContext, sp_lpetool_context, SP_TYPE_PEN_CONTEXT); -static void -sp_lpetool_context_class_init(SPLPEToolContextClass *klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - SPEventContextClass *event_context_class = (SPEventContextClass *) klass; +#include "tool-factory.h" - object_class->dispose = sp_lpetool_context_dispose; +namespace { + SPEventContext* createLPEToolContext() { + return new SPLPEToolContext(); + } - event_context_class->setup = sp_lpetool_context_setup; - event_context_class->set = sp_lpetool_context_set; - event_context_class->root_handler = sp_lpetool_context_root_handler; - event_context_class->item_handler = sp_lpetool_context_item_handler; + bool lpetoolContextRegistered = ToolFactory::instance().registerObject("/tools/lpetool", createLPEToolContext); } -static void -sp_lpetool_context_init(SPLPEToolContext *lc) -{ - lc->cursor_shape = cursor_crosshairs_xpm; - lc->hot_x = 7; - lc->hot_y = 7; - - lc->canvas_bbox = NULL; - lc->measuring_items = new std::map<SPPath *, SPCanvasItem*>; - - new (&lc->sel_changed_connection) sigc::connection(); +const std::string& SPLPEToolContext::getPrefsPath() { + return SPLPEToolContext::prefsPath; } -static void -sp_lpetool_context_dispose(GObject *object) -{ - SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(object); - delete lc->shape_editor; +const std::string SPLPEToolContext::prefsPath = "/tools/lpetool"; - if (lc->canvas_bbox) { - sp_canvas_item_destroy(SP_CANVAS_ITEM(lc->canvas_bbox)); - lc->canvas_bbox = NULL; - } +SPLPEToolContext::SPLPEToolContext() : SPPenContext() { + this->mode = Inkscape::LivePathEffect::BEND_PATH; + this->shape_editor = 0; - lpetool_delete_measuring_items(lc); - delete lc->measuring_items; - lc->measuring_items = NULL; + this->cursor_shape = cursor_crosshairs_xpm; + this->hot_x = 7; + this->hot_y = 7; - lc->sel_changed_connection.disconnect(); - lc->sel_changed_connection.~connection(); + this->canvas_bbox = NULL; + this->measuring_items = new std::map<SPPath *, SPCanvasItem*>; +} - if (lc->_lpetool_message_context) { - delete lc->_lpetool_message_context; +SPLPEToolContext::~SPLPEToolContext() { + delete this->shape_editor; + this->shape_editor = NULL; + + if (this->canvas_bbox) { + sp_canvas_item_destroy(SP_CANVAS_ITEM(this->canvas_bbox)); + this->canvas_bbox = NULL; } - G_OBJECT_CLASS(sp_lpetool_context_parent_class)->dispose(object); -} + lpetool_delete_measuring_items(this); + delete this->measuring_items; + this->measuring_items = NULL; -static void -sp_lpetool_context_setup(SPEventContext *ec) -{ - SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(ec); + this->sel_changed_connection.disconnect(); +} - if (((SPEventContextClass *) sp_lpetool_context_parent_class)->setup) - ((SPEventContextClass *) sp_lpetool_context_parent_class)->setup(ec); +void SPLPEToolContext::setup() { + SPPenContext::setup(); - Inkscape::Selection *selection = sp_desktop_selection (ec->desktop); + Inkscape::Selection *selection = sp_desktop_selection (this->desktop); SPItem *item = selection->singleItem(); - lc->sel_changed_connection.disconnect(); - lc->sel_changed_connection = - selection->connectChanged(sigc::bind(sigc::ptr_fun(&sp_lpetool_context_selection_changed), (gpointer)lc)); + this->sel_changed_connection.disconnect(); + this->sel_changed_connection = + selection->connectChanged(sigc::bind(sigc::ptr_fun(&sp_lpetool_context_selection_changed), (gpointer)this)); - lc->shape_editor = new ShapeEditor(ec->desktop); + this->shape_editor = new ShapeEditor(this->desktop); - lpetool_context_switch_mode(lc, Inkscape::LivePathEffect::INVALID_LPE); - lpetool_context_reset_limiting_bbox(lc); - lpetool_create_measuring_items(lc); + lpetool_context_switch_mode(this, Inkscape::LivePathEffect::INVALID_LPE); + lpetool_context_reset_limiting_bbox(this); + lpetool_create_measuring_items(this); // TODO temp force: - ec->enableSelectionCue(); + this->enableSelectionCue(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (item) { - lc->shape_editor->set_item(item, SH_NODEPATH); - lc->shape_editor->set_item(item, SH_KNOTHOLDER); + this->shape_editor->set_item(item, SH_NODEPATH); + this->shape_editor->set_item(item, SH_KNOTHOLDER); } if (prefs->getBool("/tools/lpetool/selcue")) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } - - lc->_lpetool_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack()); } /** @@ -171,32 +148,21 @@ void sp_lpetool_context_selection_changed(Inkscape::Selection *selection, gpoint lc->shape_editor->set_item(item, SH_KNOTHOLDER); } -static void -sp_lpetool_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val) -{ - if (val->getEntryName() == "mode") { +void SPLPEToolContext::set(const Inkscape::Preferences::Entry& val) { + if (val.getEntryName() == "mode") { Inkscape::Preferences::get()->setString("/tools/geometric/mode", "drag"); - SP_PEN_CONTEXT(ec)->mode = SP_PEN_CONTEXT_MODE_DRAG; - } - - /* - //pass on up to parent class to handle common attributes. - if ( sp_lpetool_context_parent_class->set ) { - sp_lpetool_context_parent_class->set(ec, key, val); + SP_PEN_CONTEXT(this)->mode = SPPenContext::MODE_DRAG; } - */ } -static gint -sp_lpetool_context_item_handler(SPEventContext *ec, SPItem *item, GdkEvent *event) -{ +bool SPLPEToolContext::item_handler(SPItem* item, GdkEvent* event) { gint ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: { // select the clicked item but do nothing else - Inkscape::Selection * const selection = sp_desktop_selection(ec->desktop); + Inkscape::Selection * const selection = sp_desktop_selection(this->desktop); selection->clear(); selection->add(item); ret = TRUE; @@ -211,32 +177,28 @@ sp_lpetool_context_item_handler(SPEventContext *ec, SPItem *item, GdkEvent *even } if (!ret) { - if (((SPEventContextClass *) sp_lpetool_context_parent_class)->item_handler) - ret = ((SPEventContextClass *) sp_lpetool_context_parent_class)->item_handler(ec, item, event); + ret = SPPenContext::item_handler(item, event); } return ret; } -gint -sp_lpetool_context_root_handler(SPEventContext *event_context, GdkEvent *event) -{ - SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(event_context); - SPDesktop *desktop = event_context->desktop; +bool SPLPEToolContext::root_handler(GdkEvent* event) { Inkscape::Selection *selection = sp_desktop_selection (desktop); bool ret = false; - if (sp_pen_context_has_waiting_LPE(lc)) { + if (sp_pen_context_has_waiting_LPE(this)) { // quit when we are waiting for a LPE to be applied - ret = ((SPEventContextClass *) sp_lpetool_context_parent_class)->root_handler(event_context, event); + //ret = ((SPEventContextClass *) sp_lpetool_context_parent_class)->root_handler(event_context, event); + ret = this->root_handler(event); return ret; } switch (event->type) { case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { - if (lc->mode == Inkscape::LivePathEffect::INVALID_LPE) { + if (event->button.button == 1 && !this->space_panning) { + if (this->mode == Inkscape::LivePathEffect::INVALID_LPE) { // don't do anything for now if we are inactive (except clearing the selection // since this was a click into empty space) selection->clear(); @@ -246,9 +208,9 @@ sp_lpetool_context_root_handler(SPEventContext *event_context, GdkEvent *event) } // save drag origin - event_context->xp = (gint) event->button.x; - event_context->yp = (gint) event->button.y; - event_context->within_tolerance = true; + this->xp = (gint) event->button.x; + this->yp = (gint) event->button.y; + this->within_tolerance = true; using namespace Inkscape::LivePathEffect; @@ -258,10 +220,11 @@ sp_lpetool_context_root_handler(SPEventContext *event_context, GdkEvent *event) //bool over_stroke = lc->shape_editor->is_over_stroke(Geom::Point(event->button.x, event->button.y), true); - sp_pen_context_wait_for_LPE_mouse_clicks(lc, type, Inkscape::LivePathEffect::Effect::acceptsNumClicks(type)); + sp_pen_context_wait_for_LPE_mouse_clicks(this, type, Inkscape::LivePathEffect::Effect::acceptsNumClicks(type)); // we pass the mouse click on to pen tool as the first click which it should collect - ret = ((SPEventContextClass *) sp_lpetool_context_parent_class)->root_handler(event_context, event); + //ret = ((SPEventContextClass *) sp_lpetool_context_parent_class)->root_handler(event_context, event); + ret = this->root_handler(event); } break; @@ -297,9 +260,7 @@ sp_lpetool_context_root_handler(SPEventContext *event_context, GdkEvent *event) } if (!ret) { - if (((SPEventContextClass *) sp_lpetool_context_parent_class)->root_handler) { - ret = ((SPEventContextClass *) sp_lpetool_context_parent_class)->root_handler(event_context, event); - } + ret = SPPenContext::root_handler(event); } return ret; diff --git a/src/lpe-tool-context.h b/src/lpe-tool-context.h index 7b85b09f2..0e9851cdb 100644 --- a/src/lpe-tool-context.h +++ b/src/lpe-tool-context.h @@ -17,11 +17,8 @@ #include "pen-context.h" -#define SP_TYPE_LPETOOL_CONTEXT (sp_lpetool_context_get_type()) -#define SP_LPETOOL_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_LPETOOL_CONTEXT, SPLPEToolContext)) -#define SP_LPETOOL_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_LPETOOL_CONTEXT, SPLPEToolContextClass)) -#define SP_IS_LPETOOL_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_LPETOOL_CONTEXT)) -#define SP_IS_LPETOOL_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_LPETOOL_CONTEXT)) +#define SP_LPETOOL_CONTEXT(obj) (dynamic_cast<SPLPEToolContext*>((SPEventContext*)obj)) +#define SP_IS_LPETOOL_CONTEXT(obj) (dynamic_cast<const SPLPEToolContext*>((const SPEventContext*)obj) != NULL) /* This is the list of subtools from which the toolbar of the LPETool is built automatically */ extern const int num_subtools; @@ -44,20 +41,30 @@ class Selection; class ShapeEditor; -struct SPLPEToolContext : public SPPenContext { +class SPLPEToolContext : public SPPenContext { +public: + SPLPEToolContext(); + virtual ~SPLPEToolContext(); + ShapeEditor* shape_editor; SPCanvasItem *canvas_bbox; Inkscape::LivePathEffect::EffectType mode; std::map<SPPath *, SPCanvasItem*> *measuring_items; - Inkscape::MessageContext *_lpetool_message_context; - sigc::connection sel_changed_connection; sigc::connection sel_modified_connection; -}; -struct SPLPEToolContextClass : public SPEventContextClass{}; + static const std::string prefsPath; + + virtual const std::string& getPrefsPath(); + +protected: + virtual void setup(); + virtual void set(const Inkscape::Preferences::Entry& val); + virtual bool root_handler(GdkEvent* event); + virtual bool item_handler(SPItem* item, GdkEvent* event); +}; int lpetool_mode_to_index(Inkscape::LivePathEffect::EffectType const type); int lpetool_item_has_construction(SPLPEToolContext *lc, SPItem *item); @@ -70,8 +77,6 @@ void lpetool_delete_measuring_items(SPLPEToolContext *lc); void lpetool_update_measuring_items(SPLPEToolContext *lc); void lpetool_show_measuring_info(SPLPEToolContext *lc, bool show = true); -GType sp_lpetool_context_get_type(void); - #endif // SP_LPETOOL_CONTEXT_H_SEEN /* diff --git a/src/main.cpp b/src/main.cpp index 29f431aa8..27346a230 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -78,7 +78,6 @@ #include "sp-namedview.h" #include "sp-guide.h" -#include "sp-object-repr.h" #include "xml/repr.h" #include "io/sys.h" @@ -854,8 +853,8 @@ static GSList *fixupFilenameEncoding( GSList* fl ) static int sp_common_main( int argc, char const **argv, GSList **flDest ) { /// \todo fixme: Move these to some centralized location (Lauris) - sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW); - sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE); + //sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW); + //sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE); // temporarily switch gettext encoding to locale, so that help messages can be output properly diff --git a/src/marker.cpp b/src/marker.cpp index 057fcbfbd..730985b01 100644 --- a/src/marker.cpp +++ b/src/marker.cpp @@ -35,12 +35,6 @@ struct SPMarkerView { std::vector<Inkscape::DrawingItem *> items; }; -static void sp_marker_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_marker_release (SPObject *object); -static void sp_marker_set (SPObject *object, unsigned int key, const gchar *value); -static void sp_marker_update (SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_marker_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - static Inkscape::DrawingItem *sp_marker_private_show (SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); static void sp_marker_private_hide (SPItem *item, unsigned int key); static Geom::OptRect sp_marker_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type); @@ -48,39 +42,37 @@ static void sp_marker_print (SPItem *item, SPPrintContext *ctx); static void sp_marker_view_remove (SPMarker *marker, SPMarkerView *view, unsigned int destroyitems); -G_DEFINE_TYPE(SPMarker, sp_marker, SP_TYPE_GROUP); +#include "sp-factory.h" -/** - * Initializes a SPMarkerClass object. Establishes the function pointers to the class' - * member routines in the class vtable, and sets pointers to parent classes. - */ -static void sp_marker_class_init(SPMarkerClass *klass) -{ - SPObjectClass *sp_object_class = reinterpret_cast<SPObjectClass *>(klass); - SPItemClass *sp_item_class = reinterpret_cast<SPItemClass *>(klass); - - sp_object_class->build = sp_marker_build; - sp_object_class->release = sp_marker_release; - sp_object_class->set = sp_marker_set; - sp_object_class->update = sp_marker_update; - sp_object_class->write = sp_marker_write; - - sp_item_class->show = sp_marker_private_show; - sp_item_class->hide = sp_marker_private_hide; - sp_item_class->bbox = sp_marker_bbox; - sp_item_class->print = sp_marker_print; +namespace { + SPObject* createMarker() { + return new SPMarker(); + } + + bool markerRegistered = SPFactory::instance().registerObject("svg:marker", createMarker); +} + +SPMarker::SPMarker() : SPGroup() { + this->aspect_clip = 0; + this->aspect_align = 0; + this->aspect_set = 0; + this->markerUnits = 0; + this->orient_auto = 0; + this->markerUnits_set = 0; + this->orient_set = 0; + this->orient = 0; + + this->viewBox = Geom::OptRect(); + this->c2p.setIdentity(); + this->views = NULL; } /** * Initializes an SPMarker object. This notes the marker's viewBox is * not set and initializes the marker's c2p identity matrix. */ -static void -sp_marker_init (SPMarker *marker) -{ - marker->viewBox = Geom::OptRect(); - marker->c2p.setIdentity(); - marker->views = NULL; + +SPMarker::~SPMarker() { } /** @@ -93,20 +85,32 @@ sp_marker_init (SPMarker *marker) * * \see SPObject::build() */ -static void sp_marker_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - object->readAttr( "markerUnits" ); - object->readAttr( "refX" ); - object->readAttr( "refY" ); - object->readAttr( "markerWidth" ); - object->readAttr( "markerHeight" ); - object->readAttr( "orient" ); - object->readAttr( "viewBox" ); - object->readAttr( "preserveAspectRatio" ); - - if (reinterpret_cast<SPObjectClass *>(sp_marker_parent_class)->build) { - reinterpret_cast<SPObjectClass *>(sp_marker_parent_class)->build(object, document, repr); +void SPMarker::build(SPDocument *document, Inkscape::XML::Node *repr) { + this->readAttr( "markerUnits" ); + this->readAttr( "refX" ); + this->readAttr( "refY" ); + this->readAttr( "markerWidth" ); + this->readAttr( "markerHeight" ); + this->readAttr( "orient" ); + this->readAttr( "viewBox" ); + this->readAttr( "preserveAspectRatio" ); + + SPGroup::build(document, repr); +} + +void SPMarker::release() { + while (this->views) { + // Destroy all DrawingItems etc. + // Parent class ::hide method + //reinterpret_cast<SPItemClass *>(parent_class)->hide(marker, marker->views->key); + // CPPIFY: correct one? + SPGroup::hide(this->views->key); + + + sp_marker_view_remove (this, this->views, TRUE); } + + SPGroup::release(); } /** @@ -121,127 +125,144 @@ static void sp_marker_build(SPObject *object, SPDocument *document, Inkscape::XM * * \see SPObject::release() */ -static void sp_marker_release(SPObject *object) -{ - SPMarker *marker = reinterpret_cast<SPMarker *>(object); - - while (marker->views) { - // Destroy all DrawingItems etc. - // Parent class ::hide method - reinterpret_cast<SPItemClass *>(sp_marker_parent_class)->hide(marker, marker->views->key); - sp_marker_view_remove (marker, marker->views, TRUE); - } - - if (reinterpret_cast<SPObjectClass *>(sp_marker_parent_class)->release) { - reinterpret_cast<SPObjectClass *>(sp_marker_parent_class)->release(object); - } -} - -/** - * Sets an attribute, 'key', of a marker object to 'value'. Supported - * attributes that can be set with this routine include: - * - * SP_ATTR_MARKERUNITS - * SP_ATTR_REFX - * SP_ATTR_REFY - * SP_ATTR_MARKERWIDTH - * SP_ATTR_MARKERHEIGHT - * SP_ATTR_ORIENT - * SP_ATTR_VIEWBOX - * SP_ATTR_PRESERVEASPECTRATIO - */ -static void sp_marker_set(SPObject *object, unsigned int key, const gchar *value) -{ - SPMarker *marker = SP_MARKER(object); +void SPMarker::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_MARKERUNITS: - marker->markerUnits_set = FALSE; - marker->markerUnits = SP_MARKER_UNITS_STROKEWIDTH; + this->markerUnits_set = FALSE; + this->markerUnits = SP_MARKER_UNITS_STROKEWIDTH; + if (value) { if (!strcmp (value, "strokeWidth")) { - marker->markerUnits_set = TRUE; + this->markerUnits_set = TRUE; } else if (!strcmp (value, "userSpaceOnUse")) { - marker->markerUnits = SP_MARKER_UNITS_USERSPACEONUSE; - marker->markerUnits_set = TRUE; + this->markerUnits = SP_MARKER_UNITS_USERSPACEONUSE; + this->markerUnits_set = TRUE; } } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); break; + case SP_ATTR_REFX: - marker->refX.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->refX.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_REFY: - marker->refY.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->refY.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_MARKERWIDTH: - marker->markerWidth.readOrUnset(value, SVGLength::NONE, 3.0, 3.0); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->markerWidth.readOrUnset(value, SVGLength::NONE, 3.0, 3.0); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_MARKERHEIGHT: - marker->markerHeight.readOrUnset(value, SVGLength::NONE, 3.0, 3.0); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->markerHeight.readOrUnset(value, SVGLength::NONE, 3.0, 3.0); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_ORIENT: - marker->orient_set = FALSE; - marker->orient_auto = FALSE; - marker->orient = 0.0; + this->orient_set = FALSE; + this->orient_auto = FALSE; + this->orient = 0.0; + if (value) { if (!strcmp (value, "auto")) { - marker->orient_auto = TRUE; - marker->orient_set = TRUE; - } else if (sp_svg_number_read_f (value, &marker->orient)) { - marker->orient_set = TRUE; + this->orient_auto = TRUE; + this->orient_set = TRUE; + } else if (sp_svg_number_read_f (value, &this->orient)) { + this->orient_set = TRUE; } } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_VIEWBOX: - marker->viewBox = Geom::OptRect(); + this->viewBox = Geom::OptRect(); + if (value) { double x, y, width, height; char *eptr; + /* fixme: We have to take original item affine into account */ /* fixme: Think (Lauris) */ eptr = (gchar *) value; x = g_ascii_strtod (eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + y = g_ascii_strtod (eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + width = g_ascii_strtod (eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + height = g_ascii_strtod (eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + if ((width > 0) && (height > 0)) { /* Set viewbox */ - marker->viewBox = Geom::Rect( Geom::Point(x,y), - Geom::Point(x + width, y + height) ); + this->viewBox = Geom::Rect(Geom::Point(x, y), Geom::Point(x + width, y + height)); } } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); break; + case SP_ATTR_PRESERVEASPECTRATIO: /* Do setup before, so we can use break to escape */ - marker->aspect_set = FALSE; - marker->aspect_align = SP_ASPECT_NONE; - marker->aspect_clip = SP_ASPECT_MEET; - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + this->aspect_set = FALSE; + this->aspect_align = SP_ASPECT_NONE; + this->aspect_clip = SP_ASPECT_MEET; + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + if (value) { int len; gchar c[256]; const gchar *p, *e; unsigned int align, clip; p = value; - while (*p && *p == 32) p += 1; - if (!*p) break; + + while (*p && *p == 32) { + p += 1; + } + + if (!*p) { + break; + } + e = p; - while (*e && *e != 32) e += 1; + + while (*e && *e != 32) { + e += 1; + } + len = e - p; - if (len > 8) break; + + if (len > 8) { + break; + } + memcpy (c, value, len); + c[len] = 0; + /* Now the actual part */ if (!strcmp (c, "none")) { align = SP_ASPECT_NONE; @@ -266,8 +287,13 @@ static void sp_marker_set(SPObject *object, unsigned int key, const gchar *value } else { break; } + clip = SP_ASPECT_MEET; - while (*e && *e == 32) e += 1; + + while (*e && *e == 32) { + e += 1; + } + if (*e) { if (!strcmp (e, "meet")) { clip = SP_ASPECT_MEET; @@ -277,25 +303,20 @@ static void sp_marker_set(SPObject *object, unsigned int key, const gchar *value break; } } - marker->aspect_set = TRUE; - marker->aspect_align = align; - marker->aspect_clip = clip; + + this->aspect_set = TRUE; + this->aspect_align = align; + this->aspect_clip = clip; } break; + default: - if (((SPObjectClass *) sp_marker_parent_class)->set) - ((SPObjectClass *) sp_marker_parent_class)->set (object, key, value); + SPGroup::set(key, value); break; } } -/** - * Updates <marker> when its attributes have changed. Takes care of setting up - * transformations and viewBoxes. - */ -static void sp_marker_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPMarker *marker = SP_MARKER(object); +void SPMarker::update(SPCtx *ctx, guint flags) { SPItemCtx rctx; // fixme: We have to set up clip here too @@ -308,15 +329,15 @@ static void sp_marker_update(SPObject *object, SPCtx *ctx, guint flags) rctx.i2vp = Geom::identity(); // Set up viewport - rctx.viewport = Geom::Rect::from_xywh(0, 0, marker->markerWidth.computed, marker->markerHeight.computed); + rctx.viewport = Geom::Rect::from_xywh(0, 0, this->markerWidth.computed, this->markerHeight.computed); // Start with identity transform - marker->c2p.setIdentity(); + this->c2p.setIdentity(); // Viewbox is always present, either implicitly or explicitly Geom::Rect vb; - if (marker->viewBox) { - vb = *marker->viewBox; + if (this->viewBox) { + vb = *this->viewBox; } else { vb = rctx.viewport; } @@ -328,7 +349,8 @@ static void sp_marker_update(SPObject *object, SPCtx *ctx, guint flags) // double y = 0; double width = 0; double height = 0; - if (marker->aspect_align == SP_ASPECT_NONE) { + + if (this->aspect_align == SP_ASPECT_NONE) { // x = 0.0; // y = 0.0; width = rctx.viewport.width(); @@ -338,7 +360,7 @@ static void sp_marker_update(SPObject *object, SPCtx *ctx, guint flags) // Things are getting interesting scalex = rctx.viewport.width() / (vb.width()); scaley = rctx.viewport.height() / (vb.height()); - scale = (marker->aspect_clip == SP_ASPECT_MEET) ? MIN (scalex, scaley) : MAX (scalex, scaley); + scale = (this->aspect_clip == SP_ASPECT_MEET) ? MIN (scalex, scaley) : MAX (scalex, scaley); width = (vb.width()) * scale; height = (vb.height()) * scale; @@ -386,53 +408,43 @@ static void sp_marker_update(SPObject *object, SPCtx *ctx, guint flags) break; }*/ } + // TODO fixme: all that work is done to figure out x and y, which are just ignored. Check why. // viewbox transformation and reference translation - marker->c2p = Geom::Translate(-marker->refX.computed, -marker->refY.computed) * + this->c2p = Geom::Translate(-this->refX.computed, -this->refY.computed) * Geom::Scale(width / vb.width(), height / vb.height()); - rctx.i2doc = marker->c2p * rctx.i2doc; + rctx.i2doc = this->c2p * rctx.i2doc; // If viewBox is set reinitialize child viewport // Otherwise it already correct - if (marker->viewBox) { - rctx.viewport = *marker->viewBox; + if (this->viewBox) { + rctx.viewport = *this->viewBox; rctx.i2vp = Geom::identity(); } // And invoke parent method - if (((SPObjectClass *) (sp_marker_parent_class))->update) { - ((SPObjectClass *) (sp_marker_parent_class))->update (object, (SPCtx *) &rctx, flags); - } + SPGroup::update((SPCtx *) &rctx, flags); // As last step set additional transform of drawing group - for (SPMarkerView *v = marker->views; v != NULL; v = v->next) { + for (SPMarkerView *v = this->views; v != NULL; v = v->next) { for (unsigned i = 0 ; i < v->items.size() ; i++) { if (v->items[i]) { Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(v->items[i]); - g->setChildTransform(marker->c2p); + g->setChildTransform(this->c2p); } } } } -/** - * Writes the object's properties into its repr object. - */ -static Inkscape::XML::Node * -sp_marker_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPMarker *marker; - - marker = SP_MARKER (object); - +Inkscape::XML::Node* SPMarker::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:marker"); } - if (marker->markerUnits_set) { - if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) { + if (this->markerUnits_set) { + if (this->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) { repr->setAttribute("markerUnits", "strokeWidth"); } else { repr->setAttribute("markerUnits", "userSpaceOnUse"); @@ -440,47 +452,57 @@ sp_marker_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::X } else { repr->setAttribute("markerUnits", NULL); } - if (marker->refX._set) { - sp_repr_set_svg_double(repr, "refX", marker->refX.computed); + + if (this->refX._set) { + sp_repr_set_svg_double(repr, "refX", this->refX.computed); } else { repr->setAttribute("refX", NULL); } - if (marker->refY._set) { - sp_repr_set_svg_double (repr, "refY", marker->refY.computed); + + if (this->refY._set) { + sp_repr_set_svg_double (repr, "refY", this->refY.computed); } else { repr->setAttribute("refY", NULL); } - if (marker->markerWidth._set) { - sp_repr_set_svg_double (repr, "markerWidth", marker->markerWidth.computed); + + if (this->markerWidth._set) { + sp_repr_set_svg_double (repr, "markerWidth", this->markerWidth.computed); } else { repr->setAttribute("markerWidth", NULL); } - if (marker->markerHeight._set) { - sp_repr_set_svg_double (repr, "markerHeight", marker->markerHeight.computed); + + if (this->markerHeight._set) { + sp_repr_set_svg_double (repr, "markerHeight", this->markerHeight.computed); } else { repr->setAttribute("markerHeight", NULL); } - if (marker->orient_set) { - if (marker->orient_auto) { + + if (this->orient_set) { + if (this->orient_auto) { repr->setAttribute("orient", "auto"); } else { - sp_repr_set_css_double(repr, "orient", marker->orient); + sp_repr_set_css_double(repr, "orient", this->orient); } } else { repr->setAttribute("orient", NULL); } + /* fixme: */ //XML Tree being used directly here while it shouldn't be.... - repr->setAttribute("viewBox", object->getRepr()->attribute("viewBox")); + repr->setAttribute("viewBox", this->getRepr()->attribute("viewBox")); //XML Tree being used directly here while it shouldn't be.... - repr->setAttribute("preserveAspectRatio", object->getRepr()->attribute("preserveAspectRatio")); + repr->setAttribute("preserveAspectRatio", this->getRepr()->attribute("preserveAspectRatio")); - if (((SPObjectClass *) (sp_marker_parent_class))->write) - ((SPObjectClass *) (sp_marker_parent_class))->write (object, xml_doc, repr, flags); + SPGroup::write(xml_doc, repr, flags); return repr; } +Inkscape::DrawingItem* SPMarker::show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { + // CPPIFY: correct? + return SPGroup::show(drawing, key, flags); +} + /** * This routine is disabled to break propagation. */ @@ -491,6 +513,11 @@ sp_marker_private_show (SPItem */*item*/, Inkscape::Drawing &/*drawing*/, unsign return NULL; } +void SPMarker::hide(unsigned int key) { + // CPPIFY: correct? + SPGroup::hide(key); +} + /** * This routine is disabled to break propagation. */ @@ -500,6 +527,10 @@ sp_marker_private_hide (SPItem */*item*/, unsigned int /*key*/) /* Break propagation */ } +Geom::OptRect SPMarker::bbox(Geom::Affine const &transform, SPItem::BBoxType type) { + return Geom::OptRect(); +} + /** * This routine is disabled to break propagation. */ @@ -510,6 +541,10 @@ sp_marker_bbox(SPItem const *, Geom::Affine const &, SPItem::BBoxType) return Geom::OptRect(); } +void SPMarker::print(SPPrintContext* ctx) { + +} + /** * This routine is disabled to break propagation. */ @@ -543,7 +578,8 @@ sp_marker_show_dimension (SPMarker *marker, unsigned int key, unsigned int size) if (view && (view->items.size() != size)) { /* Free old view and allocate new */ /* Parent class ::hide method */ - ((SPItemClass *) sp_marker_parent_class)->hide ((SPItem *) marker, key); + marker->hide(key); + sp_marker_view_remove (marker, view, TRUE); view = NULL; } @@ -582,9 +618,8 @@ sp_marker_show_instance ( SPMarker *marker, Inkscape::DrawingItem *parent, } if (!v->items[pos]) { /* Parent class ::show method */ - v->items[pos] = ((SPItemClass *) sp_marker_parent_class)->show ((SPItem *) marker, - parent->drawing(), key, - SP_ITEM_REFERENCE_FLAGS); + v->items[pos] = marker->show(parent->drawing(), key, SP_ITEM_REFERENCE_FLAGS); + if (v->items[pos]) { /* fixme: Position (Lauris) */ parent->prependChild(v->items[pos]); @@ -629,7 +664,8 @@ sp_marker_hide (SPMarker *marker, unsigned int key) next = v->next; if (v->key == key) { /* Parent class ::hide method */ - ((SPItemClass *) sp_marker_parent_class)->hide ((SPItem *) marker, key); + marker->hide(key); + sp_marker_view_remove (marker, v, TRUE); return; } diff --git a/src/marker.h b/src/marker.h index 147fafeb8..aae4e020f 100644 --- a/src/marker.h +++ b/src/marker.h @@ -19,8 +19,8 @@ */ #define SP_TYPE_MARKER (sp_marker_get_type ()) -#define SP_MARKER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_MARKER, SPMarker)) -#define SP_IS_MARKER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_MARKER)) +#define SP_MARKER(obj) (dynamic_cast<SPMarker*>((SPObject*)obj)) +#define SP_IS_MARKER(obj) (dynamic_cast<const SPMarker*>((SPObject*)obj) != NULL) struct SPMarkerView; @@ -32,7 +32,11 @@ struct SPMarkerView; #include "sp-marker-loc.h" #include "uri-references.h" -struct SPMarker : public SPGroup { +class SPMarker : public SPGroup { +public: + SPMarker(); + virtual ~SPMarker(); + /* units */ unsigned int markerUnits_set : 1; unsigned int markerUnits : 1; @@ -63,13 +67,19 @@ struct SPMarker : public SPGroup { /* Private views */ SPMarkerView *views; -}; -struct SPMarkerClass { - SPGroupClass parent_class; -}; + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void release(); + virtual void set(unsigned int key, gchar const* value); + virtual void update(SPCtx *ctx, guint flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); -GType sp_marker_get_type (void); + virtual Inkscape::DrawingItem* show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); + virtual void hide(unsigned int key); + + virtual Geom::OptRect bbox(Geom::Affine const &transform, SPItem::BBoxType type); + virtual void print(SPPrintContext *ctx); +}; class SPMarkerReference : public Inkscape::URIReference { SPMarkerReference(SPObject *obj) : URIReference(obj) {} diff --git a/src/measure-context.cpp b/src/measure-context.cpp index 37e87d3d9..8db703205 100644 --- a/src/measure-context.cpp +++ b/src/measure-context.cpp @@ -48,24 +48,28 @@ using Inkscape::ControlManager; using Inkscape::CTLINE_SECONDARY; using Inkscape::Util::unit_table; -static void sp_measure_context_setup(SPEventContext *ec); -static void sp_measure_context_finish(SPEventContext *ec); - -static gint sp_measure_context_root_handler(SPEventContext *event_context, GdkEvent *event); -static gint sp_measure_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event); - -static gint xp = 0; // where drag started -static gint yp = 0; -static gint tolerance = 0; -static bool within_tolerance = false; - Geom::Point start_point; boost::optional<Geom::Point> explicitBase; boost::optional<Geom::Point> lastEnd; std::vector<Inkscape::Display::TemporaryItem*> measure_tmp_items; -G_DEFINE_TYPE(SPMeasureContext, sp_measure_context, SP_TYPE_EVENT_CONTEXT); + +#include "tool-factory.h" + +namespace { + SPEventContext* createMeasureContext() { + return new SPMeasureContext(); + } + + bool measureContextRegistered = ToolFactory::instance().registerObject("/tools/measure", createMeasureContext); +} + +const std::string& SPMeasureContext::getPrefsPath() { + return SPMeasureContext::prefsPath; +} + +const std::string SPMeasureContext::prefsPath = "/tools/measure"; namespace { @@ -232,55 +236,46 @@ void createAngleDisplayCurve(SPDesktop *desktop, Geom::Point const ¢er, Geom } // namespace -static void sp_measure_context_class_init(SPMeasureContextClass *klass) -{ - SPEventContextClass *event_context_class = reinterpret_cast<SPEventContextClass *>(klass); - event_context_class->setup = sp_measure_context_setup; - event_context_class->finish = sp_measure_context_finish; +SPMeasureContext::SPMeasureContext() : SPEventContext() { + this->grabbed = 0; - event_context_class->root_handler = sp_measure_context_root_handler; - event_context_class->item_handler = sp_measure_context_item_handler; + this->cursor_shape = cursor_measure_xpm; + this->hot_x = 4; + this->hot_y = 4; } -static void sp_measure_context_init(SPMeasureContext *measure_context) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(measure_context); - - event_context->cursor_shape = cursor_measure_xpm; - event_context->hot_x = 4; - event_context->hot_y = 4; +SPMeasureContext::~SPMeasureContext() { } -static void sp_measure_context_finish(SPEventContext *ec) -{ - SPMeasureContext *mc = SP_MEASURE_CONTEXT(ec); - - ec->enableGrDrag(false); +void SPMeasureContext::finish() { + this->enableGrDrag(false); - if (mc->grabbed) { - sp_canvas_item_ungrab(mc->grabbed, GDK_CURRENT_TIME); - mc->grabbed = NULL; - } -} - -static void sp_measure_context_setup(SPEventContext *ec) -{ - if (SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->setup) { - SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->setup(ec); + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, GDK_CURRENT_TIME); + this->grabbed = NULL; } } -static gint sp_measure_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event) -{ - gint ret = FALSE; - - if (SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->item_handler) { - ret = SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->item_handler(event_context, item, event); - } - - return ret; -} +//void SPMeasureContext::setup() { +// SPEventContext* ec = this; +// +//// if (SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->setup) { +//// SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->setup(ec); +//// } +// SPEventContext::setup(); +//} + +//gint SPMeasureContext::item_handler(SPItem* item, GdkEvent* event) { +// gint ret = FALSE; +// +//// if (SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->item_handler) { +//// ret = SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->item_handler(event_context, item, event); +//// } +// ret = SPEventContext::item_handler(item, event); +// +// return ret; +//} static bool GeomPointSortPredicate(const Geom::Point& p1, const Geom::Point& p2) { @@ -317,23 +312,20 @@ static void calculate_intersections(SPDesktop * /*desktop*/, SPItem* item, Geom: } } -static gint sp_measure_context_root_handler(SPEventContext *event_context, GdkEvent *event) -{ - SPDesktop *desktop = event_context->desktop; +bool SPMeasureContext::root_handler(GdkEvent* event) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); - SPMeasureContext *mc = SP_MEASURE_CONTEXT(event_context); gint ret = FALSE; switch (event->type) { - case GDK_BUTTON_PRESS: - { + case GDK_BUTTON_PRESS: { Geom::Point const button_w(event->button.x, event->button.y); explicitBase = boost::none; lastEnd = boost::none; start_point = desktop->w2d(button_w); - if (event->button.button == 1 && !event_context->space_panning) { + + if (event->button.button == 1 && !this->space_panning) { // save drag origin xp = static_cast<gint>(event->button.x); yp = static_cast<gint>(event->button.y); @@ -350,12 +342,10 @@ static gint sp_measure_context_root_handler(SPEventContext *event_context, GdkEv sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK, NULL, event->button.time); - mc->grabbed = SP_CANVAS_ITEM(desktop->acetate); + this->grabbed = SP_CANVAS_ITEM(desktop->acetate); break; } - - case GDK_KEY_PRESS: - { + case GDK_KEY_PRESS: { if ((event->key.keyval == GDK_KEY_Shift_L) || (event->key.keyval == GDK_KEY_Shift_R)) { if (lastEnd) { explicitBase = lastEnd; @@ -363,10 +353,8 @@ static gint sp_measure_context_root_handler(SPEventContext *event_context, GdkEv } break; } - - case GDK_MOTION_NOTIFY: - { - if (!((event->motion.state & GDK_BUTTON1_MASK) && !event_context->space_panning)) { + case GDK_MOTION_NOTIFY: { + if (!((event->motion.state & GDK_BUTTON1_MASK) && !this->space_panning)) { if (!(event->motion.state & GDK_SHIFT_MASK)) { Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point const motion_dt(desktop->w2d(motion_w)); @@ -397,6 +385,7 @@ static gint sp_measure_context_root_handler(SPEventContext *event_context, GdkEv for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) { desktop->remove_temporary_canvasitem(measure_tmp_items[idx]); } + measure_tmp_items.clear(); Geom::Point const motion_w(event->motion.x, event->motion.y); @@ -404,7 +393,7 @@ static gint sp_measure_context_root_handler(SPEventContext *event_context, GdkEv Geom::Point end_point = motion_dt; if (event->motion.state & GDK_CONTROL_MASK) { - spdc_endpoint_snap_rotation(event_context, end_point, start_point, event->motion.state); + spdc_endpoint_snap_rotation(this, end_point, start_point, event->motion.state); } else { if (!(event->motion.state & GDK_SHIFT_MASK)) { SnapManager &m = desktop->namedview->snap_manager; @@ -417,7 +406,6 @@ static gint sp_measure_context_root_handler(SPEventContext *event_context, GdkEv } } - Geom::PathVector lineseg; Geom::Path p; p.start(desktop->dt2doc(start_point)); @@ -435,6 +423,7 @@ static gint sp_measure_context_root_handler(SPEventContext *event_context, GdkEv baseAngle = atan2(deltay2, deltax2); angle -= baseAngle; + if (angle < -M_PI) { angle += 2 * M_PI; } else if (angle > M_PI) { @@ -447,6 +436,7 @@ static gint sp_measure_context_root_handler(SPEventContext *event_context, GdkEv #define NPOINTS 800 std::vector<Geom::Point> points; + for (double i = 0; i < NPOINTS; i++) { points.push_back(desktop->d2w(start_point + (i / NPOINTS) * (end_point - start_point))); } @@ -740,10 +730,8 @@ static gint sp_measure_context_root_handler(SPEventContext *event_context, GdkEv } break; } - - case GDK_BUTTON_RELEASE: - { - sp_event_context_discard_delayed_snap_event(event_context); + case GDK_BUTTON_RELEASE: { + sp_event_context_discard_delayed_snap_event(this); explicitBase = boost::none; lastEnd = boost::none; @@ -751,12 +739,14 @@ static gint sp_measure_context_root_handler(SPEventContext *event_context, GdkEv for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) { desktop->remove_temporary_canvasitem(measure_tmp_items[idx]); } + measure_tmp_items.clear(); - if (mc->grabbed) { - sp_canvas_item_ungrab(mc->grabbed, event->button.time); - mc->grabbed = NULL; + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, event->button.time); + this->grabbed = NULL; } + xp = 0; yp = 0; break; @@ -766,9 +756,7 @@ static gint sp_measure_context_root_handler(SPEventContext *event_context, GdkEv } if (!ret) { - if (SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->root_handler) { - ret = SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->root_handler(event_context, event); - } + ret = SPEventContext::root_handler(event); } return ret; diff --git a/src/measure-context.h b/src/measure-context.h index b7673ad0d..e42265045 100644 --- a/src/measure-context.h +++ b/src/measure-context.h @@ -14,19 +14,23 @@ #include "event-context.h" -#define SP_TYPE_MEASURE_CONTEXT (sp_measure_context_get_type()) -#define SP_MEASURE_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_MEASURE_CONTEXT, SPMeasureContext)) -#define SP_IS_MEASURE_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_MEASURE_CONTEXT)) +#define SP_MEASURE_CONTEXT(obj) (dynamic_cast<SPMeasureContext*>((SPEventContext*)obj)) +#define SP_IS_MEASURE_CONTEXT(obj) (dynamic_cast<const SPMeasureContext*>((const SPEventContext*)obj) != NULL) -struct SPMeasureContext { - SPEventContext event_context; - SPCanvasItem *grabbed; -}; +class SPMeasureContext : public SPEventContext { +public: + SPMeasureContext(); + virtual ~SPMeasureContext(); -struct SPMeasureContextClass { - SPEventContextClass parent_class; -}; + static const std::string prefsPath; + + virtual void finish(); + virtual bool root_handler(GdkEvent* event); -GType sp_measure_context_get_type(void); + virtual const std::string& getPrefsPath(); + +private: + SPCanvasItem* grabbed; +}; #endif // SEEN_SP_MEASURING_CONTEXT_H diff --git a/src/menus-skeleton.h b/src/menus-skeleton.h index 5b141902b..2334a08c1 100644 --- a/src/menus-skeleton.h +++ b/src/menus-skeleton.h @@ -222,6 +222,7 @@ static char const menus_skeleton[] = " <verb verb-id=\"ObjectToPath\" />\n" " <verb verb-id=\"StrokeToPath\" />\n" " <verb verb-id=\"SelectionTrace\" />\n" +" <verb verb-id=\"SelectionPixelArt\" />\n" " <separator/>\n" " <verb verb-id=\"SelectionUnion\" />\n" " <verb verb-id=\"SelectionDiff\" />\n" diff --git a/src/mesh-context.cpp b/src/mesh-context.cpp index 62a45f98b..ecd847fa4 100644 --- a/src/mesh-context.cpp +++ b/src/mesh-context.cpp @@ -53,59 +53,49 @@ using Inkscape::DocumentUndo; -static void sp_mesh_context_dispose(GObject *object); - -static void sp_mesh_context_setup(SPEventContext *ec); - -static gint sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event); - static void sp_mesh_drag(SPMeshContext &rc, Geom::Point const pt, guint state, guint32 etime); -G_DEFINE_TYPE(SPMeshContext, sp_mesh_context, SP_TYPE_EVENT_CONTEXT); -static void sp_mesh_context_class_init(SPMeshContextClass *klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - SPEventContextClass *event_context_class = (SPEventContextClass *) klass; +#include "tool-factory.h" - object_class->dispose = sp_mesh_context_dispose; +namespace { + SPEventContext* createMeshContext() { + return new SPMeshContext(); + } - event_context_class->setup = sp_mesh_context_setup; - event_context_class->root_handler = sp_mesh_context_root_handler; + bool meshContextRegistered = ToolFactory::instance().registerObject("/tools/mesh", createMeshContext); } -static void sp_mesh_context_init(SPMeshContext *gr_context) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(gr_context); - - gr_context->cursor_addnode = false; - event_context->cursor_shape = cursor_gradient_xpm; - event_context->hot_x = 4; - event_context->hot_y = 4; - event_context->xp = 0; - event_context->yp = 0; - event_context->tolerance = 6; - event_context->within_tolerance = false; - event_context->item_to_select = NULL; +const std::string& SPMeshContext::getPrefsPath() { + return SPMeshContext::prefsPath; } -static void sp_mesh_context_dispose(GObject *object) -{ - SPMeshContext *rc = SP_MESH_CONTEXT(object); - SPEventContext *ec = SP_EVENT_CONTEXT(object); - - ec->enableGrDrag(false); - - if (rc->_message_context) { - delete rc->_message_context; - } +const std::string SPMeshContext::prefsPath = "/tools/mesh"; + +SPMeshContext::SPMeshContext() : SPEventContext() { + this->selcon = 0; + this->node_added = false; + this->subselcon = 0; + + this->cursor_addnode = false; + this->cursor_shape = cursor_gradient_xpm; + this->hot_x = 4; + this->hot_y = 4; + this->xp = 0; + this->yp = 0; + this->tolerance = 6; + this->within_tolerance = false; + this->item_to_select = NULL; +} - rc->selcon->disconnect(); - delete rc->selcon; - rc->subselcon->disconnect(); - delete rc->subselcon; +SPMeshContext::~SPMeshContext() { + this->enableGrDrag(false); - G_OBJECT_CLASS(sp_mesh_context_parent_class)->dispose(object); + this->selcon->disconnect(); + delete this->selcon; + + this->subselcon->disconnect(); + delete this->subselcon; } const gchar *ms_handle_descr [] = { @@ -114,20 +104,20 @@ const gchar *ms_handle_descr [] = { N_("Mesh gradient <b>tensor</b>") }; -static void -mesh_selection_changed (Inkscape::Selection *, gpointer data) -{ - SPMeshContext *rc = (SPMeshContext *) data; +void SPMeshContext::selection_changed(Inkscape::Selection* sel) { + GrDrag *drag = this->_grdrag; + Inkscape::Selection *selection = sp_desktop_selection(this->desktop); - GrDrag *drag = rc->_grdrag; - Inkscape::Selection *selection = sp_desktop_selection(SP_EVENT_CONTEXT(rc)->desktop); if (selection == NULL) { return; } + guint n_obj = g_slist_length((GSList *) selection->itemList()); - if (!drag->isNonEmpty() || selection->isEmpty()) + if (!drag->isNonEmpty() || selection->isEmpty()) { return; + } + guint n_tot = drag->numDraggers(); guint n_sel = drag->numSelected(); @@ -140,7 +130,7 @@ mesh_selection_changed (Inkscape::Selection *, gpointer data) //TRANSLATORS: Mind the space in front. This is part of a compound message ngettext(" out of %d mesh handle"," out of %d mesh handles",n_tot), ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL); - rc->_message_context->setF(Inkscape::NORMAL_MESSAGE, + this->message_context->setF(Inkscape::NORMAL_MESSAGE, message,_(ms_handle_descr[drag->singleSelectedDraggerSingleDraggableType()]), n_tot, n_obj); } else { gchar * message = @@ -151,7 +141,7 @@ mesh_selection_changed (Inkscape::Selection *, gpointer data) drag->singleSelectedDraggerNumDraggables()), ngettext(" out of %d mesh handle"," out of %d mesh handles",n_tot), ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL); - rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,message,drag->singleSelectedDraggerNumDraggables(), n_tot, n_obj); + this->message_context->setF(Inkscape::NORMAL_MESSAGE,message,drag->singleSelectedDraggerNumDraggables(), n_tot, n_obj); } } else if (n_sel > 1) { //TRANSLATORS: The plural refers to number of selected mesh handles. This is part of a compound message (part two indicates selected object count) @@ -159,9 +149,9 @@ mesh_selection_changed (Inkscape::Selection *, gpointer data) g_strconcat(ngettext("<b>%d</b> mesh handle selected out of %d","<b>%d</b> mesh handles selected out of %d",n_sel), //TRANSLATORS: Mind the space in front. (Refers to gradient handles selected). This is part of a compound message ngettext(" on %d selected object"," on %d selected objects",n_obj),NULL); - rc->_message_context->setF(Inkscape::NORMAL_MESSAGE,message, n_sel, n_tot, n_obj); + this->message_context->setF(Inkscape::NORMAL_MESSAGE,message, n_sel, n_tot, n_obj); } else if (n_sel == 0) { - rc->_message_context->setF(Inkscape::NORMAL_MESSAGE, + this->message_context->setF(Inkscape::NORMAL_MESSAGE, //TRANSLATORS: The plural refers to number of selected objects ngettext("<b>No</b> mesh handles selected out of %d on %d selected object", "<b>No</b> mesh handles selected out of %d on %d selected objects",n_obj), n_tot, n_obj); @@ -234,35 +224,29 @@ mesh_selection_changed (Inkscape::Selection *, gpointer data) // } } - -static void -mesh_subselection_changed (gpointer, gpointer data) -{ - mesh_selection_changed (NULL, data); -} - - -static void sp_mesh_context_setup(SPEventContext *ec) -{ - SPMeshContext *rc = SP_MESH_CONTEXT(ec); - - if (((SPEventContextClass *) sp_mesh_context_parent_class)->setup) { - ((SPEventContextClass *) sp_mesh_context_parent_class)->setup(ec); - } +void SPMeshContext::setup() { + SPEventContext::setup(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/tools/mesh/selcue", true)) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } - ec->enableGrDrag(); - Inkscape::Selection *selection = sp_desktop_selection(ec->desktop); + this->enableGrDrag(); + Inkscape::Selection *selection = sp_desktop_selection(this->desktop); + + this->selcon = new sigc::connection(selection->connectChanged( + sigc::mem_fun(this, &SPMeshContext::selection_changed) + )); - rc->_message_context = new Inkscape::MessageContext(sp_desktop_message_stack(ec->desktop)); + this->subselcon = new sigc::connection(this->desktop->connectToolSubselectionChanged( + sigc::hide(sigc::bind( + sigc::mem_fun(*this, &SPMeshContext::selection_changed), + (Inkscape::Selection*)NULL) + ) + )); - rc->selcon = new sigc::connection (selection->connectChanged( sigc::bind (sigc::ptr_fun(&mesh_selection_changed), rc))); - rc->subselcon = new sigc::connection (ec->desktop->connectToolSubselectionChanged(sigc::bind (sigc::ptr_fun(&mesh_subselection_changed), rc))); - mesh_selection_changed(selection, rc); + this->selection_changed(selection); } void @@ -452,28 +436,21 @@ sp_mesh_context_corner_operation (SPMeshContext *rc, MeshCornerOperation operati /** Handles all keyboard and mouse input for meshs. */ -static gint -sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) -{ - // static int count = 0; - // std::cout << "sp_mesh_context_root_handler: " << count++ << std::endl; +bool SPMeshContext::root_handler(GdkEvent* event) { static bool dragging; - SPDesktop *desktop = event_context->desktop; Inkscape::Selection *selection = sp_desktop_selection (desktop); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - SPMeshContext *rc = SP_MESH_CONTEXT(event_context); - - event_context->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); + this->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); double const nudge = prefs->getDoubleLimited("/options/nudgedistance/value", 2, 0, 1000, "px"); // in px - GrDrag *drag = event_context->_grdrag; + GrDrag *drag = this->_grdrag; g_assert (drag); gint ret = FALSE; - switch (event->type) { + switch (event->type) { case GDK_2BUTTON_PRESS: #ifdef DEBUG_MESH @@ -485,27 +462,24 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) // If not over a line, create new gradients for selected objects. if ( event->button.button == 1 ) { - // Are we over a mesh line? bool over_line = false; SPCtrlCurve *line = NULL; + if (drag->lines) { for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) { line = (SPCtrlCurve*) l->data; - over_line |= sp_mesh_context_is_over_line (rc, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y)); + over_line |= sp_mesh_context_is_over_line (this, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y)); } } if (over_line) { // We take the first item in selection, because with doubleclick, the first click // always resets selection to the single object under cursor - sp_mesh_context_split_near_point(rc, SP_ITEM(selection->itemList()->data), rc->mousepoint_doc, event->button.time); - + sp_mesh_context_split_near_point(this, SP_ITEM(selection->itemList()->data), this->mousepoint_doc, event->button.time); } else { // Create a new gradient with default coordinates. - for (GSList const* i = selection->itemList(); i != NULL; i = i->next) { - SPItem *item = SP_ITEM(i->data); SPGradientType new_type = SP_GRADIENT_TYPE_MESH; Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; @@ -522,6 +496,7 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) DocumentUndo::done(sp_desktop_document (desktop), SP_VERB_CONTEXT_MESH, _("Create default mesh")); } + ret = TRUE; } break; @@ -534,14 +509,13 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) // Button down // If Shift key down: do rubber band selection // Else set origin for drag. A drag creates a new gradient if one does not exist - - if ( event->button.button == 1 && !event_context->space_panning ) { + if ( event->button.button == 1 && !this->space_panning ) { Geom::Point button_w(event->button.x, event->button.y); // save drag origin - event_context->xp = (gint) button_w[Geom::X]; - event_context->yp = (gint) button_w[Geom::Y]; - event_context->within_tolerance = true; + this->xp = (gint) button_w[Geom::X]; + this->yp = (gint) button_w[Geom::Y]; + this->within_tolerance = true; dragging = true; @@ -551,8 +525,9 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) } else { // remember clicked item, disregarding groups, honoring Alt; do nothing with Crtl to // enable Ctrl+doubleclick of exactly the selected item(s) - if (!(event->button.state & GDK_CONTROL_MASK)) - event_context->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE); + if (!(event->button.state & GDK_CONTROL_MASK)) { + this->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE); + } if (!selection->isEmpty()) { SnapManager &m = desktop->namedview->snap_manager; @@ -560,7 +535,8 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) m.freeSnapReturnByRef(button_dt, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); } - rc->origin = button_dt; + + this->origin = button_dt; } ret = TRUE; @@ -568,41 +544,37 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) break; case GDK_MOTION_NOTIFY: - // Mouse move - - if ( dragging - && ( event->motion.state & GDK_BUTTON1_MASK ) && !event_context->space_panning ) - { + if ( dragging && ( event->motion.state & GDK_BUTTON1_MASK ) && !this->space_panning ) { #ifdef DEBUG_MESH std::cout << "sp_mesh_context_root_handler: GDK_MOTION_NOTIFY: Dragging" << std::endl; #endif - if ( event_context->within_tolerance - && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance ) - && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) { + if ( this->within_tolerance + && ( abs( (gint) event->motion.x - this->xp ) < this->tolerance ) + && ( abs( (gint) event->motion.y - this->yp ) < this->tolerance ) ) { break; // do not drag if we're within tolerance from origin } // Once the user has moved farther than tolerance from the original location // (indicating they intend to draw, not click), then always process the // motion notify coordinates as given (no snapping back to origin) - event_context->within_tolerance = false; + this->within_tolerance = false; Geom::Point const motion_w(event->motion.x, event->motion.y); - Geom::Point const motion_dt = event_context->desktop->w2d(motion_w); + Geom::Point const motion_dt = this->desktop->w2d(motion_w); if (Inkscape::Rubberband::get(desktop)->is_started()) { Inkscape::Rubberband::get(desktop)->move(motion_dt); - event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw around</b> handles to select them")); + this->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw around</b> handles to select them")); } else { // Create new gradient with coordinates determined by drag. - sp_mesh_drag(*rc, motion_dt, event->motion.state, event->motion.time); + sp_mesh_drag(*this, motion_dt, event->motion.state, event->motion.time); } + gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; - } else { // Not dragging @@ -612,7 +584,7 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) m.setup(desktop); Geom::Point const motion_w(event->motion.x, event->motion.y); - Geom::Point const motion_dt = event_context->desktop->w2d(motion_w); + Geom::Point const motion_dt = this->desktop->w2d(motion_w); m.preSnap(Inkscape::SnapCandidatePoint(motion_dt, Inkscape::SNAPSOURCE_OTHER_HANDLE)); m.unSetup(); @@ -627,20 +599,21 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) // Change cursor shape if over line bool over_line = false; + if (drag->lines) { for (GSList *l = drag->lines; l != NULL; l = l->next) { - over_line |= sp_mesh_context_is_over_line (rc, (SPItem*) l->data, Geom::Point(event->motion.x, event->motion.y)); + over_line |= sp_mesh_context_is_over_line (this, (SPItem*) l->data, Geom::Point(event->motion.x, event->motion.y)); } } - if (rc->cursor_addnode && !over_line) { - event_context->cursor_shape = cursor_gradient_xpm; - sp_event_context_update_cursor(event_context); - rc->cursor_addnode = false; - } else if (!rc->cursor_addnode && over_line) { - event_context->cursor_shape = cursor_gradient_add_xpm; - sp_event_context_update_cursor(event_context); - rc->cursor_addnode = true; + if (this->cursor_addnode && !over_line) { + this->cursor_shape = cursor_gradient_xpm; + this->sp_event_context_update_cursor(); + this->cursor_addnode = false; + } else if (!this->cursor_addnode && over_line) { + this->cursor_shape = cursor_gradient_add_xpm; + this->sp_event_context_update_cursor(); + this->cursor_addnode = true; } } break; @@ -651,29 +624,30 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) std::cout << "sp_mesh_context_root_handler: GDK_BUTTON_RELEASE" << std::endl; #endif - event_context->xp = event_context->yp = 0; - if ( event->button.button == 1 && !event_context->space_panning ) { + this->xp = this->yp = 0; + if ( event->button.button == 1 && !this->space_panning ) { // Check if over line bool over_line = false; SPCtrlLine *line = NULL; + if (drag->lines) { for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) { line = (SPCtrlLine*) l->data; - over_line = sp_mesh_context_is_over_line (rc, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y)); - if (over_line) + over_line = sp_mesh_context_is_over_line (this, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y)); + + if (over_line) { break; + } } } if ( (event->button.state & GDK_CONTROL_MASK) && (event->button.state & GDK_MOD1_MASK ) ) { if (over_line && line) { - sp_mesh_context_split_near_point(rc, line->item, rc->mousepoint_doc, 0); + sp_mesh_context_split_near_point(this, line->item, this->mousepoint_doc, 0); ret = TRUE; } - } else { - dragging = false; // unless clicked with Ctrl (to enable Ctrl+doubleclick). @@ -682,29 +656,28 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) break; } - if (!event_context->within_tolerance) { + if (!this->within_tolerance) { // we've been dragging, either do nothing (grdrag handles that), // or rubberband-select if we have rubberband Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop); - if (r->is_started() && !event_context->within_tolerance) { + + if (r->is_started() && !this->within_tolerance) { // this was a rubberband drag if (r->getMode() == RUBBERBAND_MODE_RECT) { Geom::OptRect const b = r->getRectangle(); drag->selectRect(*b); } } - - } else if (event_context->item_to_select) { + } else if (this->item_to_select) { if (over_line && line) { // Clicked on an existing mesh line, don't change selection. This stops // possible change in selection during a double click with overlapping objects - } - else { + } else { // no dragging, select clicked item if any if (event->button.state & GDK_SHIFT_MASK) { - selection->toggle(event_context->item_to_select); + selection->toggle(this->item_to_select); } else { - selection->set(event_context->item_to_select); + selection->set(this->item_to_select); } } } else { @@ -716,9 +689,10 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) } } - event_context->item_to_select = NULL; + this->item_to_select = NULL; ret = TRUE; } + Inkscape::Rubberband::get(desktop)->stop(); } break; @@ -739,7 +713,7 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_Shift_R: case GDK_KEY_Meta_L: // Meta is when you press Shift+Alt (at least on my machine) case GDK_KEY_Meta_R: - sp_event_show_modifier_tip (event_context->defaultMessageContext(), event, + sp_event_show_modifier_tip (this->defaultMessageContext(), event, _("FIXME<b>Ctrl</b>: snap mesh angle"), _("FIXME<b>Shift</b>: draw mesh around the starting point"), NULL); @@ -759,6 +733,7 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) } else { selection->clear(); } + ret = TRUE; //TODO: make dragging escapable by Esc break; @@ -767,33 +742,46 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_KP_Left: case GDK_KEY_KP_4: if (!MOD__CTRL(event)) { // not ctrl - gint mul = 1 + gobble_key_events( - get_group0_keyval(&event->key), 0); // with any mask + gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask + if (MOD__ALT(event)) { // alt - if (MOD__SHIFT(event)) drag->selected_move_screen(mul*-10, 0); // shift - else drag->selected_move_screen(mul*-1, 0); // no shift - } - else { // no alt - if (MOD__SHIFT(event)) drag->selected_move(mul*-10*nudge, 0); // shift - else drag->selected_move(mul*-nudge, 0); // no shift + if (MOD__SHIFT(event)) { + drag->selected_move_screen(mul*-10, 0); // shift + } else { + drag->selected_move_screen(mul*-1, 0); // no shift + } + } else { // no alt + if (MOD__SHIFT(event)) { + drag->selected_move(mul*-10*nudge, 0); // shift + } else { + drag->selected_move(mul*-nudge, 0); // no shift + } } + ret = TRUE; } break; + case GDK_KEY_Up: // move handle up case GDK_KEY_KP_Up: case GDK_KEY_KP_8: if (!MOD__CTRL(event)) { // not ctrl - gint mul = 1 + gobble_key_events( - get_group0_keyval(&event->key), 0); // with any mask + gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask + if (MOD__ALT(event)) { // alt - if (MOD__SHIFT(event)) drag->selected_move_screen(0, mul*10); // shift - else drag->selected_move_screen(0, mul*1); // no shift - } - else { // no alt - if (MOD__SHIFT(event)) drag->selected_move(0, mul*10*nudge); // shift - else drag->selected_move(0, mul*nudge); // no shift + if (MOD__SHIFT(event)) { + drag->selected_move_screen(0, mul*10); // shift + } else { + drag->selected_move_screen(0, mul*1); // no shift + } + } else { // no alt + if (MOD__SHIFT(event)) { + drag->selected_move(0, mul*10*nudge); // shift + } else { + drag->selected_move(0, mul*nudge); // no shift + } } + ret = TRUE; } break; @@ -802,16 +790,22 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_KP_Right: case GDK_KEY_KP_6: if (!MOD__CTRL(event)) { // not ctrl - gint mul = 1 + gobble_key_events( - get_group0_keyval(&event->key), 0); // with any mask + gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask + if (MOD__ALT(event)) { // alt - if (MOD__SHIFT(event)) drag->selected_move_screen(mul*10, 0); // shift - else drag->selected_move_screen(mul*1, 0); // no shift - } - else { // no alt - if (MOD__SHIFT(event)) drag->selected_move(mul*10*nudge, 0); // shift - else drag->selected_move(mul*nudge, 0); // no shift + if (MOD__SHIFT(event)) { + drag->selected_move_screen(mul*10, 0); // shift + } else { + drag->selected_move_screen(mul*1, 0); // no shift + } + } else { // no alt + if (MOD__SHIFT(event)) { + drag->selected_move(mul*10*nudge, 0); // shift + } else { + drag->selected_move(mul*nudge, 0); // no shift + } } + ret = TRUE; } break; @@ -820,16 +814,22 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_KP_Down: case GDK_KEY_KP_2: if (!MOD__CTRL(event)) { // not ctrl - gint mul = 1 + gobble_key_events( - get_group0_keyval(&event->key), 0); // with any mask + gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask + if (MOD__ALT(event)) { // alt - if (MOD__SHIFT(event)) drag->selected_move_screen(0, mul*-10); // shift - else drag->selected_move_screen(0, mul*-1); // no shift - } - else { // no alt - if (MOD__SHIFT(event)) drag->selected_move(0, mul*-10*nudge); // shift - else drag->selected_move(0, mul*-nudge); // no shift + if (MOD__SHIFT(event)) { + drag->selected_move_screen(0, mul*-10); // shift + } else { + drag->selected_move_screen(0, mul*-1); // no shift + } + } else { // no alt + if (MOD__SHIFT(event)) { + drag->selected_move(0, mul*-10*nudge); // shift + } else { + drag->selected_move(0, mul*-nudge); // no shift + } } + ret = TRUE; } break; @@ -856,7 +856,7 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_b: // Toggle mesh side between lineto and curveto. case GDK_KEY_B: if (MOD__ALT(event) && drag->isNonEmpty() && drag->hasSelection()) { - sp_mesh_context_corner_operation ( rc, MG_CORNER_SIDE_TOGGLE ); + sp_mesh_context_corner_operation ( this, MG_CORNER_SIDE_TOGGLE ); ret = TRUE; } break; @@ -864,7 +864,7 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_c: // Convert mesh side from generic Bezier to Bezier approximating arc, case GDK_KEY_C: // preserving handle direction. if (MOD__ALT(event) && drag->isNonEmpty() && drag->hasSelection()) { - sp_mesh_context_corner_operation ( rc, MG_CORNER_SIDE_ARC ); + sp_mesh_context_corner_operation ( this, MG_CORNER_SIDE_ARC ); ret = TRUE; } break; @@ -872,7 +872,7 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_g: // Toggle mesh tensor points on/off case GDK_KEY_G: if (MOD__ALT(event) && drag->isNonEmpty() && drag->hasSelection()) { - sp_mesh_context_corner_operation ( rc, MG_CORNER_TENSOR_TOGGLE ); + sp_mesh_context_corner_operation ( this, MG_CORNER_TENSOR_TOGGLE ); ret = TRUE; } break; @@ -880,7 +880,7 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_j: // Smooth corner color case GDK_KEY_J: if (MOD__ALT(event) && drag->isNonEmpty() && drag->hasSelection()) { - sp_mesh_context_corner_operation ( rc, MG_CORNER_COLOR_SMOOTH ); + sp_mesh_context_corner_operation ( this, MG_CORNER_COLOR_SMOOTH ); ret = TRUE; } break; @@ -888,7 +888,7 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_k: // Pick corner color case GDK_KEY_K: if (MOD__ALT(event) && drag->isNonEmpty() && drag->hasSelection()) { - sp_mesh_context_corner_operation ( rc, MG_CORNER_COLOR_PICK ); + sp_mesh_context_corner_operation ( this, MG_CORNER_COLOR_PICK ); ret = TRUE; } break; @@ -913,7 +913,7 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_Shift_R: case GDK_KEY_Meta_L: // Meta is when you press Shift+Alt case GDK_KEY_Meta_R: - event_context->defaultMessageContext()->clear(); + this->defaultMessageContext()->clear(); break; default: break; @@ -924,18 +924,13 @@ sp_mesh_context_root_handler(SPEventContext *event_context, GdkEvent *event) } if (!ret) { - if (((SPEventContextClass *) sp_mesh_context_parent_class)->root_handler) { - ret = ((SPEventContextClass *) sp_mesh_context_parent_class)->root_handler(event_context, event); - } + ret = SPEventContext::root_handler(event); } return ret; } - -static void sp_mesh_drag(SPMeshContext &rc, Geom::Point const /*pt*/, guint /*state*/, guint32 /*etime*/) -{ - +static void sp_mesh_drag(SPMeshContext &rc, Geom::Point const /*pt*/, guint /*state*/, guint32 /*etime*/) { SPDesktop *desktop = SP_EVENT_CONTEXT(&rc)->desktop; Inkscape::Selection *selection = sp_desktop_selection(desktop); SPDocument *document = sp_desktop_document(desktop); @@ -993,7 +988,7 @@ static void sp_mesh_drag(SPMeshContext &rc, Geom::Point const /*pt*/, guint /*st // status text; we do not track coords because this branch is run once, not all the time // during drag int n_objects = g_slist_length((GSList *) selection->itemList()); - rc._message_context->setF(Inkscape::NORMAL_MESSAGE, + rc.message_context->setF(Inkscape::NORMAL_MESSAGE, ngettext("<b>Gradient</b> for %d object; with <b>Ctrl</b> to snap angle", "<b>Gradient</b> for %d objects; with <b>Ctrl</b> to snap angle", n_objects), n_objects); diff --git a/src/mesh-context.h b/src/mesh-context.h index e5d06ec0a..531587654 100644 --- a/src/mesh-context.h +++ b/src/mesh-context.h @@ -21,13 +21,13 @@ #include <sigc++/sigc++.h> #include "event-context.h" -#define SP_TYPE_MESH_CONTEXT (sp_mesh_context_get_type()) -#define SP_MESH_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_MESH_CONTEXT, SPMeshContext)) -#define SP_MESH_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_MESH_CONTEXT, SPMeshContextClass)) -#define SP_IS_MESH_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_MESH_CONTEXT)) -#define SP_IS_MESH_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_MESH_CONTEXT)) +#define SP_MESH_CONTEXT(obj) (dynamic_cast<SPMeshContext*>((SPEventContext*)obj)) +#define SP_IS_MESH_CONTEXT(obj) (dynamic_cast<const SPMeshContext*>((const SPEventContext*)obj) != NULL) -struct SPMeshContext : public SPEventContext { +class SPMeshContext : public SPEventContext { +public: + SPMeshContext(); + virtual ~SPMeshContext(); Geom::Point origin; @@ -37,18 +37,19 @@ struct SPMeshContext : public SPEventContext { Geom::Point mousepoint_doc; // stores mousepoint when over_line in doc coords - Inkscape::MessageContext *_message_context; - sigc::connection *selcon; sigc::connection *subselcon; -}; -struct SPMeshContextClass { - SPEventContextClass parent_class; -}; + static const std::string prefsPath; -// Standard Gtk function -GType sp_mesh_context_get_type(); + virtual void setup(); + virtual bool root_handler(GdkEvent* event); + + virtual const std::string& getPrefsPath(); + +private: + void selection_changed(Inkscape::Selection* sel); +}; void sp_mesh_context_select_next(SPEventContext *event_context); void sp_mesh_context_select_prev(SPEventContext *event_context); diff --git a/src/object-edit.cpp b/src/object-edit.cpp index 54aef2b71..25bc62a7f 100644 --- a/src/object-edit.cpp +++ b/src/object-edit.cpp @@ -1164,7 +1164,7 @@ SpiralKnotHolderEntityInner::knot_set(Geom::Point const &p, Geom::Point const &o } else { // roll/unroll from inside gdouble arg_t0; - sp_spiral_get_polar(spiral, spiral->t0, NULL, &arg_t0); + spiral->getPolar(spiral->t0, NULL, &arg_t0); gdouble arg_tmp = atan2(dy, dx) - arg_t0; gdouble arg_t0_new = arg_tmp - floor((arg_tmp+M_PI)/(2.0*M_PI))*2.0*M_PI + arg_t0; @@ -1213,7 +1213,7 @@ SpiralKnotHolderEntityOuter::knot_set(Geom::Point const &p, Geom::Point const &/ } else { // roll/unroll // arg of the spiral outer end double arg_1; - sp_spiral_get_polar(spiral, 1, NULL, &arg_1); + spiral->getPolar(1, NULL, &arg_1); // its fractional part after the whole turns are subtracted double arg_r = arg_1 - sp_round(arg_1, 2.0*M_PI); @@ -1241,7 +1241,7 @@ SpiralKnotHolderEntityOuter::knot_set(Geom::Point const &p, Geom::Point const &/ // the rad at that t: double rad_new = 0; if (t_temp > spiral->t0) - sp_spiral_get_polar(spiral, t_temp, &rad_new, NULL); + spiral->getPolar(t_temp, &rad_new, NULL); // change the revo (converting diff from radians to the number of turns) spiral->revo += diff/(2*M_PI); @@ -1252,7 +1252,7 @@ SpiralKnotHolderEntityOuter::knot_set(Geom::Point const &p, Geom::Point const &/ if (!(state & GDK_MOD1_MASK) && rad_new > 1e-3 && rad_new/spiral->rad < 2) { // adjust t0 too so that the inner point stays unmoved double r0; - sp_spiral_get_polar(spiral, spiral->t0, &r0, NULL); + spiral->getPolar(spiral->t0, &r0, NULL); spiral->rad = rad_new; spiral->t0 = pow(r0 / spiral->rad, 1.0/spiral->exp); } @@ -1268,7 +1268,7 @@ SpiralKnotHolderEntityInner::knot_get() const { SPSpiral const *spiral = SP_SPIRAL(item); - return sp_spiral_get_xy(spiral, spiral->t0); + return spiral->getXY(spiral->t0); } Geom::Point @@ -1276,7 +1276,7 @@ SpiralKnotHolderEntityOuter::knot_get() const { SPSpiral const *spiral = SP_SPIRAL(item); - return sp_spiral_get_xy(spiral, 1.0); + return spiral->getXY(1.0); } void diff --git a/src/object-snapper.h b/src/object-snapper.h index 31e1ee501..c0dab5c58 100644 --- a/src/object-snapper.h +++ b/src/object-snapper.h @@ -15,7 +15,7 @@ #include "splivarot.h" #include "snap-candidate.h" -struct SPNamedView; +class SPNamedView; class SPItem; class SPObject; diff --git a/src/pen-context.cpp b/src/pen-context.cpp index 6f51d59cb..97bc03676 100644 --- a/src/pen-context.cpp +++ b/src/pen-context.cpp @@ -69,14 +69,6 @@ //BSpline End using Inkscape::ControlManager; -static void sp_pen_context_dispose(GObject *object); - -static void sp_pen_context_setup(SPEventContext *ec); -static void sp_pen_context_finish(SPEventContext *ec); -static void sp_pen_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val); -static gint sp_pen_context_root_handler(SPEventContext *ec, GdkEvent *event); -static gint sp_pen_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event); - static void spdc_pen_set_initial_point(SPPenContext *pc, Geom::Point const p); /* *BSpline @@ -137,84 +129,69 @@ static void pen_set_to_nearest_horiz_vert(const SPPenContext *const pc, Geom::Po static int pen_last_paraxial_dir = 0; // last used direction in horizontal/vertical mode; 0 = horizontal, 1 = vertical -G_DEFINE_TYPE(SPPenContext, sp_pen_context, SP_TYPE_DRAW_CONTEXT); -/** - * Initialize the SPPenContext vtable. - */ -static void sp_pen_context_class_init(SPPenContextClass *klass) -{ - GObjectClass *object_class; - SPEventContextClass *event_context_class; +#include "tool-factory.h" - object_class = (GObjectClass *) klass; - event_context_class = (SPEventContextClass *) klass; +namespace { + SPEventContext* createPenContext() { + return new SPPenContext(); + } - object_class->dispose = sp_pen_context_dispose; + bool penContextRegistered = ToolFactory::instance().registerObject("/tools/freehand/pen", createPenContext); +} - event_context_class->setup = sp_pen_context_setup; - event_context_class->finish = sp_pen_context_finish; - event_context_class->set = sp_pen_context_set; - event_context_class->root_handler = sp_pen_context_root_handler; - event_context_class->item_handler = sp_pen_context_item_handler; +const std::string& SPPenContext::getPrefsPath() { + return SPPenContext::prefsPath; } -/** - * Callback to initialize SPPenContext object. - */ -static void sp_pen_context_init(SPPenContext *pc) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(pc); +const std::string SPPenContext::prefsPath = "/tools/freehand/pen"; - event_context->cursor_shape = cursor_pen_xpm; - event_context->hot_x = 4; - event_context->hot_y = 4; +SPPenContext::SPPenContext() : SPDrawContext() { + this->polylines_only = false; + this->polylines_paraxial = false; + this->expecting_clicks_for_LPE = 0; - pc->npoints = 0; - pc->mode = SP_PEN_CONTEXT_MODE_CLICK; - pc->state = SP_PEN_CONTEXT_POINT; + this->cursor_shape = cursor_pen_xpm; + this->hot_x = 4; + this->hot_y = 4; - pc->c0 = NULL; - pc->c1 = NULL; - pc->cl0 = NULL; - pc->cl1 = NULL; + this->npoints = 0; + this->mode = MODE_CLICK; + this->state = POINT; - pc->events_disabled = 0; + this->c0 = NULL; + this->c1 = NULL; + this->cl0 = NULL; + this->cl1 = NULL; - pc->num_clicks = 0; - pc->waiting_LPE = NULL; - pc->waiting_item = NULL; -} + this->events_disabled = 0; -/** - * Callback to destroy the SPPenContext object's members and itself. - */ -static void sp_pen_context_dispose(GObject *object) -{ - SPPenContext *pc = SP_PEN_CONTEXT(object); + this->num_clicks = 0; + this->waiting_LPE = NULL; + this->waiting_item = NULL; +} - if (pc->c0) { - sp_canvas_item_destroy(pc->c0); - pc->c0 = NULL; +SPPenContext::~SPPenContext() { + if (this->c0) { + sp_canvas_item_destroy(this->c0); + this->c0 = NULL; } - if (pc->c1) { - sp_canvas_item_destroy(pc->c1); - pc->c1 = NULL; + if (this->c1) { + sp_canvas_item_destroy(this->c1); + this->c1 = NULL; } - if (pc->cl0) { - sp_canvas_item_destroy(pc->cl0); - pc->cl0 = NULL; + if (this->cl0) { + sp_canvas_item_destroy(this->cl0); + this->cl0 = NULL; } - if (pc->cl1) { - sp_canvas_item_destroy(pc->cl1); - pc->cl1 = NULL; + if (this->cl1) { + sp_canvas_item_destroy(this->cl1); + this->cl1 = NULL; } - G_OBJECT_CLASS(sp_pen_context_parent_class)->dispose(object); - - if (pc->expecting_clicks_for_LPE > 0) { + if (this->expecting_clicks_for_LPE > 0) { // we received too few clicks to sanely set the parameter path so we remove the LPE from the item - sp_lpe_item_remove_current_path_effect(pc->waiting_item, false); + sp_lpe_item_remove_current_path_effect(this->waiting_item, false); } } @@ -243,55 +220,49 @@ void sp_pen_context_set_mode(SPPenContext *const pc, guint mode) { /** * Callback to initialize SPPenContext object. */ -static void sp_pen_context_setup(SPEventContext *ec) -{ - SPPenContext *pc = SP_PEN_CONTEXT(ec); - - if (((SPEventContextClass *) sp_pen_context_parent_class)->setup) { - ((SPEventContextClass *) sp_pen_context_parent_class)->setup(ec); - } +void SPPenContext::setup() { + SPDrawContext::setup(); ControlManager &mgr = ControlManager::getManager(); // Pen indicators - pc->c0 = mgr.createControl(sp_desktop_controls(SP_EVENT_CONTEXT_DESKTOP(ec)), Inkscape::CTRL_TYPE_ADJ_HANDLE); - mgr.track(pc->c0); + this->c0 = mgr.createControl(sp_desktop_controls(SP_EVENT_CONTEXT_DESKTOP(this)), Inkscape::CTRL_TYPE_ADJ_HANDLE); + mgr.track(this->c0); - pc->c1 = mgr.createControl(sp_desktop_controls(SP_EVENT_CONTEXT_DESKTOP(ec)), Inkscape::CTRL_TYPE_ADJ_HANDLE); - mgr.track(pc->c1); + this->c1 = mgr.createControl(sp_desktop_controls(SP_EVENT_CONTEXT_DESKTOP(this)), Inkscape::CTRL_TYPE_ADJ_HANDLE); + mgr.track(this->c1); - pc->cl0 = mgr.createControlLine(sp_desktop_controls(SP_EVENT_CONTEXT_DESKTOP(ec))); - pc->cl1 = mgr.createControlLine(sp_desktop_controls(SP_EVENT_CONTEXT_DESKTOP(ec))); + this->cl0 = mgr.createControlLine(sp_desktop_controls(SP_EVENT_CONTEXT_DESKTOP(this))); + this->cl1 = mgr.createControlLine(sp_desktop_controls(SP_EVENT_CONTEXT_DESKTOP(this))); + sp_canvas_item_hide(this->c0); + sp_canvas_item_hide(this->c1); + sp_canvas_item_hide(this->cl0); + sp_canvas_item_hide(this->cl1); - sp_canvas_item_hide(pc->c0); - sp_canvas_item_hide(pc->c1); - sp_canvas_item_hide(pc->cl0); - sp_canvas_item_hide(pc->cl1); - - sp_event_context_read(ec, "mode"); + sp_event_context_read(this, "mode"); - pc->anchor_statusbar = false; + this->anchor_statusbar = false; - sp_pen_context_set_polyline_mode(pc); + sp_pen_context_set_polyline_mode(this); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/tools/freehand/pen/selcue")) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } } static void pen_cancel (SPPenContext *const pc) { pc->num_clicks = 0; - pc->state = SP_PEN_CONTEXT_STOP; + pc->state = SPPenContext::STOP; spdc_reset_colors(pc); sp_canvas_item_hide(pc->c0); sp_canvas_item_hide(pc->c1); sp_canvas_item_hide(pc->cl0); sp_canvas_item_hide(pc->cl1); - pc->_message_context->clear(); - pc->_message_context->flash(Inkscape::NORMAL_MESSAGE, _("Drawing cancelled")); + pc->message_context->clear(); + pc->message_context->flash(Inkscape::NORMAL_MESSAGE, _("Drawing cancelled")); pc->desktop->canvas->endForcedFullRedraws(); } @@ -299,34 +270,27 @@ static void pen_cancel (SPPenContext *const pc) /** * Finalization callback. */ -static void sp_pen_context_finish(SPEventContext *ec) -{ - SPPenContext *pc = SP_PEN_CONTEXT(ec); - - sp_event_context_discard_delayed_snap_event(ec); +void SPPenContext::finish() { + sp_event_context_discard_delayed_snap_event(this); - if (pc->npoints != 0) { - pen_cancel (pc); + if (this->npoints != 0) { + pen_cancel(this); } - if (((SPEventContextClass *) sp_pen_context_parent_class)->finish) { - ((SPEventContextClass *) sp_pen_context_parent_class)->finish(ec); - } + SPDrawContext::finish(); } /** * Callback that sets key to value in pen context. */ -static void sp_pen_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val) -{ - SPPenContext *pc = SP_PEN_CONTEXT(ec); - Glib::ustring name = val->getEntryName(); +void SPPenContext::set(const Inkscape::Preferences::Entry& val) { + Glib::ustring name = val.getEntryName(); if (name == "mode") { - if ( val->getString() == "drag" ) { - pc->mode = SP_PEN_CONTEXT_MODE_DRAG; + if ( val.getString() == "drag" ) { + this->mode = MODE_DRAG; } else { - pc->mode = SP_PEN_CONTEXT_MODE_CLICK; + this->mode = MODE_CLICK; } } } @@ -373,26 +337,22 @@ static void spdc_endpoint_snap_handle(SPPenContext const *const pc, Geom::Point } } -static gint sp_pen_context_item_handler(SPEventContext *ec, SPItem *item, GdkEvent *event) -{ - SPPenContext *const pc = SP_PEN_CONTEXT(ec); - +bool SPPenContext::item_handler(SPItem* item, GdkEvent* event) { gint ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: - ret = pen_handle_button_press(pc, event->button); + ret = pen_handle_button_press(this, event->button); break; case GDK_BUTTON_RELEASE: - ret = pen_handle_button_release(pc, event->button); + ret = pen_handle_button_release(this, event->button); break; default: break; } if (!ret) { - if (((SPEventContextClass *) sp_pen_context_parent_class)->item_handler) - ret = ((SPEventContextClass *) sp_pen_context_parent_class)->item_handler(ec, item, event); + ret = SPDrawContext::item_handler(item, event); } return ret; @@ -401,31 +361,28 @@ static gint sp_pen_context_item_handler(SPEventContext *ec, SPItem *item, GdkEve /** * Callback to handle all pen events. */ -static gint sp_pen_context_root_handler(SPEventContext *ec, GdkEvent *event) -{ - SPPenContext *const pc = SP_PEN_CONTEXT(ec); - +bool SPPenContext::root_handler(GdkEvent* event) { gint ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: - ret = pen_handle_button_press(pc, event->button); + ret = pen_handle_button_press(this, event->button); break; case GDK_MOTION_NOTIFY: - ret = pen_handle_motion_notify(pc, event->motion); + ret = pen_handle_motion_notify(this, event->motion); break; case GDK_BUTTON_RELEASE: - ret = pen_handle_button_release(pc, event->button); + ret = pen_handle_button_release(this, event->button); break; case GDK_2BUTTON_PRESS: - ret = pen_handle_2button_press(pc, event->button); + ret = pen_handle_2button_press(this, event->button); break; case GDK_KEY_PRESS: - ret = pen_handle_key_press(pc, event); + ret = pen_handle_key_press(this, event); break; default: @@ -433,11 +390,7 @@ static gint sp_pen_context_root_handler(SPEventContext *ec, GdkEvent *event) } if (!ret) { - gint (*const parent_root_handler)(SPEventContext *, GdkEvent *) - = ((SPEventContextClass *) sp_pen_context_parent_class)->root_handler; - if (parent_root_handler) { - ret = parent_root_handler(ec, event); - } + ret = SPDrawContext::root_handler(event); } return ret; @@ -470,7 +423,7 @@ static gint pen_handle_button_press(SPPenContext *const pc, GdkEventButton const // make sure this is not the last click for a waiting LPE (otherwise we want to finish the path) && (pc->expecting_clicks_for_LPE != 1)) { - if (Inkscape::have_viable_layer(desktop, dc->_message_context) == false) { + if (Inkscape::have_viable_layer(desktop, dc->message_context) == false) { return TRUE; } @@ -487,27 +440,28 @@ static gint pen_handle_button_press(SPPenContext *const pc, GdkEventButton const pen_within_tolerance = true; switch (pc->mode) { - case SP_PEN_CONTEXT_MODE_CLICK: + case SPPenContext::MODE_CLICK: // In click mode we add point on release switch (pc->state) { - case SP_PEN_CONTEXT_POINT: - case SP_PEN_CONTEXT_CONTROL: - case SP_PEN_CONTEXT_CLOSE: + case SPPenContext::POINT: + case SPPenContext::CONTROL: + case SPPenContext::CLOSE: break; - case SP_PEN_CONTEXT_STOP: + case SPPenContext::STOP: // This is allowed, if we just canceled curve - pc->state = SP_PEN_CONTEXT_POINT; + pc->state = SPPenContext::POINT; break; default: break; } break; - case SP_PEN_CONTEXT_MODE_DRAG: + case SPPenContext::MODE_DRAG: switch (pc->state) { - case SP_PEN_CONTEXT_STOP: + case SPPenContext::STOP: // This is allowed, if we just canceled curve - case SP_PEN_CONTEXT_POINT: - if (pc->npoints == 0 ) { + + case SPPenContext::POINT: + if (pc->npoints == 0) { Geom::Point p; if ((bevent.state & GDK_CONTROL_MASK) && (pc->polylines_only || pc->polylines_paraxial)) { @@ -568,7 +522,7 @@ static gint pen_handle_button_press(SPPenContext *const pc, GdkEventButton const p = anchor->dp; // we hit an anchor, will finish the curve (either with or without closing) // in release handler - pc->state = SP_PEN_CONTEXT_CLOSE; + pc->state = SPPenContext::CLOSE; if (pc->green_anchor && pc->green_anchor->active) { // we clicked on the current curve start, so close it even if @@ -584,16 +538,18 @@ static gint pen_handle_button_press(SPPenContext *const pc, GdkEventButton const spdc_pen_set_subsequent_point(pc, p, true); } } + //BSpline //Evitamos la creación de un punto de control para que se cree el nodo en el evento de soltar - pc->state = (pc->spiro || pc->bspline || pc->polylines_only) ? SP_PEN_CONTEXT_POINT : SP_PEN_CONTEXT_CONTROL; + pc->state = (pc->spiro || pc->bspline || pc->polylines_only) ? SPPenContext::POINT : SPPenContext::CONTROL; //BSpline End + ret = TRUE; break; - case SP_PEN_CONTEXT_CONTROL: + case SPPenContext::CONTROL: g_warning("Button down in CONTROL state"); break; - case SP_PEN_CONTEXT_CLOSE: + case SPPenContext::CLOSE: g_warning("Button down in CLOSE state"); break; default: @@ -670,9 +626,9 @@ static gint pen_handle_motion_notify(SPPenContext *const pc, GdkEventMotion cons // Test, whether we hit any anchor SPDrawAnchor *anchor = spdc_test_inside(pc, event_w); switch (pc->mode) { - case SP_PEN_CONTEXT_MODE_CLICK: + case SPPenContext::MODE_CLICK: switch (pc->state) { - case SP_PEN_CONTEXT_POINT: + case SPPenContext::POINT: if ( pc->npoints != 0 ) { // Only set point, if we are already appending spdc_endpoint_snap(pc, p, mevent.state); @@ -685,23 +641,23 @@ static gint pen_handle_motion_notify(SPPenContext *const pc, GdkEventMotion cons m.unSetup(); } break; - case SP_PEN_CONTEXT_CONTROL: - case SP_PEN_CONTEXT_CLOSE: + case SPPenContext::CONTROL: + case SPPenContext::CLOSE: // Placing controls is last operation in CLOSE state spdc_endpoint_snap(pc, p, mevent.state); spdc_pen_set_ctrl(pc, p, mevent.state); ret = TRUE; break; - case SP_PEN_CONTEXT_STOP: + case SPPenContext::STOP: // This is perfectly valid break; default: break; } break; - case SP_PEN_CONTEXT_MODE_DRAG: + case SPPenContext::MODE_DRAG: switch (pc->state) { - case SP_PEN_CONTEXT_POINT: + case SPPenContext::POINT: if ( pc->npoints > 0 ) { // Only set point, if we are already appending @@ -714,13 +670,13 @@ static gint pen_handle_motion_notify(SPPenContext *const pc, GdkEventMotion cons if (anchor && !pc->anchor_statusbar) { if(!pc->spiro && !pc->bspline){ - pc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>click and drag</b> to close and finish the path.")); + pc->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>click and drag</b> to close and finish the path.")); }else{ - pc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>click and drag</b> to close and finish the path. Shift to cusp node")); + pc->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>click and drag</b> to close and finish the path. Shift to cusp node")); } pc->anchor_statusbar = true; } else if (!anchor && pc->anchor_statusbar) { - pc->_message_context->clear(); + pc->message_context->clear(); pc->anchor_statusbar = false; } @@ -728,13 +684,13 @@ static gint pen_handle_motion_notify(SPPenContext *const pc, GdkEventMotion cons } else { if (anchor && !pc->anchor_statusbar) { if(!pc->spiro && !pc->bspline){ - pc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>click and drag</b> to continue the path from this point.")); + pc->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>click and drag</b> to continue the path from this point.")); }else{ - pc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>click and drag</b> to continue the path from this point. Shift to cusp node")); + pc->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>click and drag</b> to continue the path from this point. Shift to cusp node")); } pc->anchor_statusbar = true; } else if (!anchor && pc->anchor_statusbar) { - pc->_message_context->clear(); + pc->message_context->clear(); pc->anchor_statusbar = false; } if (!sp_event_context_knot_mouseover(pc)) { @@ -745,8 +701,8 @@ static gint pen_handle_motion_notify(SPPenContext *const pc, GdkEventMotion cons } } break; - case SP_PEN_CONTEXT_CONTROL: - case SP_PEN_CONTEXT_CLOSE: + case SPPenContext::CONTROL: + case SPPenContext::CLOSE: // Placing controls is last operation in CLOSE state // snap the handle spdc_endpoint_snap_handle(pc, p, mevent.state); @@ -759,7 +715,7 @@ static gint pen_handle_motion_notify(SPPenContext *const pc, GdkEventMotion cons gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; break; - case SP_PEN_CONTEXT_STOP: + case SPPenContext::STOP: // This is perfectly valid break; default: @@ -818,9 +774,9 @@ static gint pen_handle_button_release(SPPenContext *const pc, GdkEventButton con } //BSpline End switch (pc->mode) { - case SP_PEN_CONTEXT_MODE_CLICK: + case SPPenContext::MODE_CLICK: switch (pc->state) { - case SP_PEN_CONTEXT_POINT: + case SPPenContext::POINT: if ( pc->npoints == 0 ) { // Start new thread only with button release if (anchor) { @@ -843,17 +799,17 @@ static gint pen_handle_button_release(SPPenContext *const pc, GdkEventButton con p = anchor->dp; } } - pc->state = SP_PEN_CONTEXT_CONTROL; + pc->state = SPPenContext::CONTROL; ret = TRUE; break; - case SP_PEN_CONTEXT_CONTROL: + case SPPenContext::CONTROL: // End current segment spdc_endpoint_snap(pc, p, revent.state); spdc_pen_finish_segment(pc, p, revent.state); - pc->state = SP_PEN_CONTEXT_POINT; + pc->state = SPPenContext::POINT; ret = TRUE; break; - case SP_PEN_CONTEXT_CLOSE: + case SPPenContext::CLOSE: // End current segment if (!anchor) { // Snap node only if not hitting anchor spdc_endpoint_snap(pc, p, revent.state); @@ -866,30 +822,27 @@ static gint pen_handle_button_release(SPPenContext *const pc, GdkEventButton con } //BSpline End spdc_pen_finish(pc, TRUE); - pc->state = SP_PEN_CONTEXT_POINT; + pc->state = SPPenContext::POINT; ret = TRUE; break; - case SP_PEN_CONTEXT_STOP: + case SPPenContext::STOP: // This is allowed, if we just canceled curve - pc->state = SP_PEN_CONTEXT_POINT; + pc->state = SPPenContext::POINT; ret = TRUE; break; default: break; } break; - case SP_PEN_CONTEXT_MODE_DRAG: + case SPPenContext::MODE_DRAG: switch (pc->state) { - case SP_PEN_CONTEXT_POINT: - case SP_PEN_CONTEXT_CONTROL: + case SPPenContext::POINT: + case SPPenContext::CONTROL: spdc_endpoint_snap(pc, p, revent.state); spdc_pen_finish_segment(pc, p, revent.state); break; - case SP_PEN_CONTEXT_CLOSE: - // End current segment - if (!anchor) { // Snap node only if not hitting anchor - spdc_endpoint_snap(pc, p, revent.state); - } + case SPPenContext::CLOSE: + spdc_endpoint_snap(pc, p, revent.state); spdc_pen_finish_segment(pc, p, revent.state); //BSpline //Ocultamos la guia del penultimo nodo al cerrar la curva @@ -905,13 +858,13 @@ static gint pen_handle_button_release(SPPenContext *const pc, GdkEventButton con spdc_pen_finish(pc, FALSE); } break; - case SP_PEN_CONTEXT_STOP: + case SPPenContext::STOP: // This is allowed, if we just cancelled curve break; default: break; } - pc->state = SP_PEN_CONTEXT_POINT; + pc->state = SPPenContext::POINT; ret = TRUE; break; default: @@ -1373,7 +1326,7 @@ static gint pen_handle_key_press(SPPenContext *const pc, GdkEvent *event) //BSpline End sp_canvas_item_hide(pc->cl0); sp_canvas_item_hide(pc->cl1); - pc->state = SP_PEN_CONTEXT_POINT; + pc->state = SPPenContext::POINT; spdc_pen_set_subsequent_point(pc, pt, true); pen_last_paraxial_dir = !pen_last_paraxial_dir; //BSpline @@ -1451,7 +1404,7 @@ static void spdc_pen_set_angle_distance_status_message(SPPenContext *const pc, G } } - pc->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, message, angle, dist->str); + pc->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, message, angle, dist->str); g_string_free(dist, FALSE); } @@ -2212,8 +2165,8 @@ static void spdc_pen_set_ctrl(SPPenContext *const pc, Geom::Point const p, guint sp_canvas_item_show(pc->c0); sp_canvas_item_show(pc->cl0); bool is_symm = false; - if ( ( ( pc->mode == SP_PEN_CONTEXT_MODE_CLICK ) && ( state & GDK_CONTROL_MASK ) ) || - ( ( pc->mode == SP_PEN_CONTEXT_MODE_DRAG ) && !( state & GDK_SHIFT_MASK ) ) ) { + if ( ( ( pc->mode == SPPenContext::MODE_CLICK ) && ( state & GDK_CONTROL_MASK ) ) || + ( ( pc->mode == SPPenContext::MODE_DRAG ) && !( state & GDK_SHIFT_MASK ) ) ) { Geom::Point delta = p - pc->p[3]; pc->p[2] = pc->p[3] - delta; is_symm = true; @@ -2273,7 +2226,7 @@ static void spdc_pen_finish(SPPenContext *const pc, gboolean const closed) pen_disable_events(pc); SPDesktop *const desktop = pc->desktop; - pc->_message_context->clear(); + pc->message_context->clear(); desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Drawing finished")); pc->red_curve->reset(); @@ -2282,7 +2235,7 @@ static void spdc_pen_finish(SPPenContext *const pc, gboolean const closed) pc->ea = NULL; pc->npoints = 0; - pc->state = SP_PEN_CONTEXT_POINT; + pc->state = SPPenContext::POINT; sp_canvas_item_hide(pc->c0); sp_canvas_item_hide(pc->c1); diff --git a/src/pen-context.h b/src/pen-context.h index 4485539cd..051455317 100644 --- a/src/pen-context.h +++ b/src/pen-context.h @@ -8,38 +8,39 @@ #include "draw-context.h" #include "live_effects/effect.h" -#define SP_TYPE_PEN_CONTEXT (sp_pen_context_get_type()) -#define SP_PEN_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_PEN_CONTEXT, SPPenContext)) -#define SP_PEN_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_PEN_CONTEXT, SPPenContextClass)) -#define SP_IS_PEN_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_PEN_CONTEXT)) -#define SP_IS_PEN_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_PEN_CONTEXT)) - -enum { - SP_PEN_CONTEXT_POINT, - SP_PEN_CONTEXT_CONTROL, - SP_PEN_CONTEXT_CLOSE, - SP_PEN_CONTEXT_STOP -}; - -enum { - SP_PEN_CONTEXT_MODE_CLICK, - SP_PEN_CONTEXT_MODE_DRAG -}; +#define SP_PEN_CONTEXT(obj) (dynamic_cast<SPPenContext*>((SPEventContext*)obj)) +#define SP_IS_PEN_CONTEXT(obj) (dynamic_cast<const SPPenContext*>((const SPEventContext*)obj) != NULL) struct SPCtrlLine; /** * SPPenContext: a context for pen tool events. */ -struct SPPenContext : public SPDrawContext { +class SPPenContext : public SPDrawContext { +public: + SPPenContext(); + virtual ~SPPenContext(); + + enum Mode { + MODE_CLICK, + MODE_DRAG + }; + + enum State { + POINT, + CONTROL, + CLOSE, + STOP + }; + Geom::Point p[5]; /** \invar npoints in {0, 2, 5}. */ // npoints somehow determines the type of the node (what does it mean, exactly? the number of Bezier handles?) gint npoints; - unsigned int mode : 1; - unsigned int state : 2; + Mode mode; + State state; bool polylines_only; bool polylines_paraxial; @@ -61,12 +62,18 @@ struct SPPenContext : public SPDrawContext { SPCtrlLine *cl1; unsigned int events_disabled : 1; -}; -/// The SPPenContext vtable (empty). -struct SPPenContextClass : public SPEventContextClass { }; + static const std::string prefsPath; + + virtual const std::string& getPrefsPath(); -GType sp_pen_context_get_type(); +protected: + virtual void setup(); + virtual void finish(); + virtual void set(const Inkscape::Preferences::Entry& val); + virtual bool root_handler(GdkEvent* event); + virtual bool item_handler(SPItem* item, GdkEvent* event); +}; inline bool sp_pen_context_has_waiting_LPE(SPPenContext *pc) { // note: waiting_LPE_type is defined in SPDrawContext diff --git a/src/pencil-context.cpp b/src/pencil-context.cpp index 304f81890..9869b0756 100644 --- a/src/pencil-context.cpp +++ b/src/pencil-context.cpp @@ -45,10 +45,6 @@ #include "display/curve.h" #include "livarot/Path.h" -static void sp_pencil_context_setup(SPEventContext *ec); -static void sp_pencil_context_dispose(GObject *object); - -static gint sp_pencil_context_root_handler(SPEventContext *event_context, GdkEvent *event); static gint pencil_handle_button_press(SPPencilContext *const pc, GdkEventButton const &bevent); static gint pencil_handle_motion_notify(SPPencilContext *const pc, GdkEventMotion const &mevent); static gint pencil_handle_button_release(SPPencilContext *const pc, GdkEventButton const &revent); @@ -68,72 +64,51 @@ static bool pencil_within_tolerance = false; static bool in_svg_plane(Geom::Point const &p) { return Geom::LInfty(p) < 1e18; } -G_DEFINE_TYPE(SPPencilContext, sp_pencil_context, SP_TYPE_DRAW_CONTEXT); +#include "tool-factory.h" -/** - * Initialize SPPencilContext vtable. - */ -static void -sp_pencil_context_class_init(SPPencilContextClass *klass) -{ - GObjectClass *object_class; - SPEventContextClass *event_context_class; - - object_class = (GObjectClass *) klass; - event_context_class = (SPEventContextClass *) klass; +namespace { + SPEventContext* createPencilContext() { + return new SPPencilContext(); + } - object_class->dispose = sp_pencil_context_dispose; + bool pencilContextRegistered = ToolFactory::instance().registerObject("/tools/freehand/pencil", createPencilContext); +} - event_context_class->setup = sp_pencil_context_setup; - event_context_class->root_handler = sp_pencil_context_root_handler; +const std::string& SPPencilContext::getPrefsPath() { + return SPPencilContext::prefsPath; } -/** - * Callback to initialize SPPencilContext object. - */ -static void -sp_pencil_context_init(SPPencilContext *pc) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(pc); +const std::string SPPencilContext::prefsPath = "/tools/freehand/pencil"; - event_context->cursor_shape = cursor_pencil_xpm; - event_context->hot_x = 4; - event_context->hot_y = 4; +SPPencilContext::SPPencilContext() : SPDrawContext() { + this->is_drawing = false; - pc->npoints = 0; - pc->state = SP_PENCIL_CONTEXT_IDLE; - pc->req_tangent = Geom::Point(0, 0); + this->cursor_shape = cursor_pencil_xpm; + this->hot_x = 4; + this->hot_y = 4; + + this->npoints = 0; + this->state = SP_PENCIL_CONTEXT_IDLE; + this->req_tangent = Geom::Point(0, 0); // since SPPencilContext is not properly constructed... - pc->sketch_interpolation = Geom::Piecewise<Geom::D2<Geom::SBasis> >(); - pc->sketch_n = 0; + this->sketch_interpolation = Geom::Piecewise<Geom::D2<Geom::SBasis> >(); + this->sketch_n = 0; } -/** - * Callback to setup SPPencilContext object. - */ -static void -sp_pencil_context_setup(SPEventContext *ec) -{ +void SPPencilContext::setup() { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/tools/freehand/pencil/selcue")) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } - if (((SPEventContextClass *) sp_pencil_context_parent_class)->setup) { - ((SPEventContextClass *) sp_pencil_context_parent_class)->setup(ec); - } + SPDrawContext::setup(); - SPPencilContext *const pc = SP_PENCIL_CONTEXT(ec); - pc->is_drawing = false; - - pc->anchor_statusbar = false; + this->is_drawing = false; + this->anchor_statusbar = false; } -static void -sp_pencil_context_dispose(GObject *object) -{ - G_OBJECT_CLASS(sp_pencil_context_parent_class)->dispose(object); +SPPencilContext::~SPPencilContext() { } /** Snaps new node relative to the previous node. */ @@ -157,32 +132,28 @@ spdc_endpoint_snap(SPPencilContext const *pc, Geom::Point &p, guint const state) /** * Callback for handling all pencil context events. */ -gint -sp_pencil_context_root_handler(SPEventContext *const ec, GdkEvent *event) -{ - SPPencilContext *const pc = SP_PENCIL_CONTEXT(ec); - +bool SPPencilContext::root_handler(GdkEvent* event) { gint ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: - ret = pencil_handle_button_press(pc, event->button); + ret = pencil_handle_button_press(this, event->button); break; case GDK_MOTION_NOTIFY: - ret = pencil_handle_motion_notify(pc, event->motion); + ret = pencil_handle_motion_notify(this, event->motion); break; case GDK_BUTTON_RELEASE: - ret = pencil_handle_button_release(pc, event->button); + ret = pencil_handle_button_release(this, event->button); break; case GDK_KEY_PRESS: - ret = pencil_handle_key_press(pc, get_group0_keyval (&event->key), event->key.state); + ret = pencil_handle_key_press(this, get_group0_keyval (&event->key), event->key.state); break; case GDK_KEY_RELEASE: - ret = pencil_handle_key_release(pc, get_group0_keyval (&event->key), event->key.state); + ret = pencil_handle_key_release(this, get_group0_keyval (&event->key), event->key.state); break; default: @@ -190,11 +161,7 @@ sp_pencil_context_root_handler(SPEventContext *const ec, GdkEvent *event) } if (!ret) { - gint (*const parent_root_handler)(SPEventContext *, GdkEvent *) - = ((SPEventContextClass *) sp_pencil_context_parent_class)->root_handler; - if (parent_root_handler) { - ret = parent_root_handler(ec, event); - } + ret = SPDrawContext::root_handler(event); } return ret; @@ -211,7 +178,7 @@ pencil_handle_button_press(SPPencilContext *const pc, GdkEventButton const &beve SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(dc); Inkscape::Selection *selection = sp_desktop_selection(desktop); - if (Inkscape::have_viable_layer(desktop, dc->_message_context) == false) { + if (Inkscape::have_viable_layer(desktop, dc->message_context) == false) { return TRUE; } @@ -372,21 +339,21 @@ pencil_handle_motion_notify(SPPencilContext *const pc, GdkEventMotion const &mev } if (anchor && !pc->anchor_statusbar) { - pc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Release</b> here to close and finish the path.")); + pc->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Release</b> here to close and finish the path.")); pc->anchor_statusbar = true; } else if (!anchor && pc->anchor_statusbar) { - pc->_message_context->clear(); + pc->message_context->clear(); pc->anchor_statusbar = false; } else if (!anchor) { - pc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("Drawing a freehand path")); + pc->message_context->set(Inkscape::NORMAL_MESSAGE, _("Drawing a freehand path")); } } else { if (anchor && !pc->anchor_statusbar) { - pc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b> to continue the path from this point.")); + pc->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b> to continue the path from this point.")); pc->anchor_statusbar = true; } else if (!anchor && pc->anchor_statusbar) { - pc->_message_context->clear(); + pc->message_context->clear(); pc->anchor_statusbar = false; } } @@ -530,8 +497,8 @@ pencil_cancel (SPPencilContext *const pc) pc->green_anchor = sp_draw_anchor_destroy(pc->green_anchor); } - pc->_message_context->clear(); - pc->_message_context->flash(Inkscape::NORMAL_MESSAGE, _("Drawing cancelled")); + pc->message_context->clear(); + pc->message_context->flash(Inkscape::NORMAL_MESSAGE, _("Drawing cancelled")); pc->desktop->canvas->endForcedFullRedraws(); } diff --git a/src/pencil-context.h b/src/pencil-context.h index aa0f60eb2..b3ded0242 100644 --- a/src/pencil-context.h +++ b/src/pencil-context.h @@ -7,12 +7,8 @@ #include "draw-context.h" - -#define SP_TYPE_PENCIL_CONTEXT (sp_pencil_context_get_type()) -#define SP_PENCIL_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_PENCIL_CONTEXT, SPPencilContext)) -#define SP_PENCIL_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_PENCIL_CONTEXT, SPPencilContextClass)) -#define SP_IS_PENCIL_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_PENCIL_CONTEXT)) -#define SP_IS_PENCIL_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_PENCIL_CONTEXT)) +#define SP_PENCIL_CONTEXT(obj) (dynamic_cast<SPPencilContext*>((SPEventContext*)obj)) +#define SP_IS_PENCIL_CONTEXT(obj) (dynamic_cast<const SPPencilContext*>((const SPEventContext*)obj) != NULL) enum PencilState { SP_PENCIL_CONTEXT_IDLE, @@ -24,7 +20,11 @@ enum PencilState { /** * SPPencilContext: a context for pencil tool events */ -struct SPPencilContext : public SPDrawContext { +class SPPencilContext : public SPDrawContext { +public: + SPPencilContext(); + virtual ~SPPencilContext(); + Geom::Point p[16]; gint npoints; PencilState state; @@ -36,13 +36,15 @@ struct SPPencilContext : public SPDrawContext { Geom::Piecewise<Geom::D2<Geom::SBasis> > sketch_interpolation; // the current proposal from the sketched paths unsigned sketch_n; // number of sketches done -}; -/// The SPPencilContext vtable (empty). -struct SPPencilContextClass : public SPEventContextClass { }; + static const std::string prefsPath; -GType sp_pencil_context_get_type(); + virtual const std::string& getPrefsPath(); +protected: + virtual void setup(); + virtual bool root_handler(GdkEvent* event); +}; #endif /* !SEEN_PENCIL_CONTEXT_H */ diff --git a/src/persp3d.cpp b/src/persp3d.cpp index 2744efb75..a0e6f1c02 100644 --- a/src/persp3d.cpp +++ b/src/persp3d.cpp @@ -27,12 +27,6 @@ using Inkscape::DocumentUndo; -static void persp3d_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void persp3d_release(SPObject *object); -static void persp3d_set(SPObject *object, unsigned key, gchar const *value); -static void persp3d_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *persp3d_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - static void persp3d_on_repr_attr_changed (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive, void * data); static void persp3d_update_with_point (Persp3DImpl *persp_impl, Proj::Axis const axis, Proj::Pt2 const &new_image); @@ -40,6 +34,16 @@ static gchar * persp3d_pt_to_str (Persp3DImpl *persp_impl, Proj::Axis const axis static int global_counter = 0; +#include "sp-factory.h" + +namespace { + SPObject* createPersp3D() { + return new Persp3D(); + } + + bool persp3DRegistered = SPFactory::instance().registerObject("inkscape:persp3d", createPersp3D); +} + /* Constructor/destructor for the internal class */ Persp3DImpl::Persp3DImpl() { @@ -49,8 +53,6 @@ Persp3DImpl::Persp3DImpl() { my_counter = global_counter++; } -G_DEFINE_TYPE(Persp3D, persp3d, SP_TYPE_OBJECT); - static Inkscape::XML::NodeEventVector const persp3d_repr_events = { NULL, /* child_added */ NULL, /* child_removed */ @@ -59,56 +61,37 @@ static Inkscape::XML::NodeEventVector const persp3d_repr_events = { NULL /* order_changed */ }; -/** - * Callback to initialize Persp3D vtable. - */ -static void persp3d_class_init(Persp3DClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - sp_object_class->build = persp3d_build; - sp_object_class->release = persp3d_release; - sp_object_class->set = persp3d_set; - sp_object_class->update = persp3d_update; - sp_object_class->write = persp3d_write; +Persp3D::Persp3D() : SPObject() { + this->perspective_impl = new Persp3DImpl(); } -/** - * Callback to initialize Persp3D object. - */ -static void -persp3d_init(Persp3D *persp) -{ - persp->perspective_impl = new Persp3DImpl(); +Persp3D::~Persp3D() { } + /** * Virtual build: set persp3d attributes from its associated XML node. */ -static void persp3d_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) persp3d_parent_class)->build) - (* ((SPObjectClass *) persp3d_parent_class)->build)(object, document, repr); +void Persp3D::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPObject::build(document, repr); - /* calls sp_object_set for the respective attributes */ - // The transformation matrix is updated according to the values we read for the VPs - object->readAttr( "inkscape:vp_x" ); - object->readAttr( "inkscape:vp_y" ); - object->readAttr( "inkscape:vp_z" ); - object->readAttr( "inkscape:persp3d-origin" ); + this->readAttr( "inkscape:vp_x" ); + this->readAttr( "inkscape:vp_y" ); + this->readAttr( "inkscape:vp_z" ); + this->readAttr( "inkscape:persp3d-origin" ); if (repr) { - repr->addListener (&persp3d_repr_events, object); + repr->addListener (&persp3d_repr_events, this); } } /** * Virtual release of Persp3D members before destruction. */ -static void persp3d_release(SPObject *object) { - Persp3D *persp = SP_PERSP3D(object); - delete persp->perspective_impl; - object->getRepr()->removeListenerByData(object); +void Persp3D::release() { + delete this->perspective_impl; + this->getRepr()->removeListenerByData(this); } @@ -117,10 +100,8 @@ static void persp3d_release(SPObject *object) { */ // FIXME: Currently we only read the finite positions of vanishing points; // should we move VPs into their own repr (as it's done for SPStop, e.g.)? -static void -persp3d_set(SPObject *object, unsigned key, gchar const *value) -{ - Persp3DImpl *persp_impl = SP_PERSP3D(object)->perspective_impl; +void Persp3D::set(unsigned key, gchar const *value) { + Persp3DImpl *persp_impl = this->perspective_impl; switch (key) { case SP_ATTR_INKSCAPE_PERSP3D_VP_X: { @@ -152,8 +133,7 @@ persp3d_set(SPObject *object, unsigned key, gchar const *value) } } default: { - if (((SPObjectClass *) persp3d_parent_class)->set) - (* ((SPObjectClass *) persp3d_parent_class)->set)(object, key, value); + SPObject::set(key, value); break; } } @@ -169,17 +149,14 @@ persp3d_set(SPObject *object, unsigned key, gchar const *value) } } -static void -persp3d_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void Persp3D::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { /* TODO: Should we update anything here? */ } - if (((SPObjectClass *) persp3d_parent_class)->update) - ((SPObjectClass *) persp3d_parent_class)->update(object, ctx, flags); + SPObject::update(ctx, flags); } Persp3D *persp3d_create_xml_element(SPDocument *document, Persp3DImpl *dup) {// if dup is given, copy the attributes over @@ -238,10 +215,8 @@ Persp3D *persp3d_document_first_persp(SPDocument *document) /** * Virtual write: write object attributes to repr. */ -static Inkscape::XML::Node * -persp3d_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - Persp3DImpl *persp_impl = SP_PERSP3D(object)->perspective_impl; +Inkscape::XML::Node* Persp3D::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { + Persp3DImpl *persp_impl = this->perspective_impl; if ((flags & SP_OBJECT_WRITE_BUILD & SP_OBJECT_WRITE_EXT) && !repr) { // this is where we end up when saving as plain SVG (also in other circumstances?); @@ -264,8 +239,7 @@ persp3d_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML: repr->setAttribute("inkscape:persp3d-origin", str); } - if (((SPObjectClass *) persp3d_parent_class)->write) - (* ((SPObjectClass *) persp3d_parent_class)->write)(object, xml_doc, repr, flags); + SPObject::write(xml_doc, repr, flags); return repr; } diff --git a/src/persp3d.h b/src/persp3d.h index 25db4787c..cb7e7f900 100644 --- a/src/persp3d.h +++ b/src/persp3d.h @@ -12,11 +12,8 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#define SP_TYPE_PERSP3D (persp3d_get_type ()) -#define SP_PERSP3D(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_PERSP3D, Persp3D)) -#define SP_PERSP3D_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_PERSP3D, Persp3DClass)) -#define SP_IS_PERSP3D(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_PERSP3D)) -#define SP_IS_PERSP3D_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_PERSP3D)) +#define SP_PERSP3D(obj) (dynamic_cast<Persp3D*>((SPObject*)obj)) +#define SP_IS_PERSP3D(obj) (dynamic_cast<const Persp3D*>((SPObject*)obj) != NULL) #include <list> #include <vector> @@ -27,7 +24,7 @@ #include "inkscape.h" class SPBox3D; -struct Box3DContext; +class Box3DContext; class Persp3DImpl { public: @@ -46,17 +43,24 @@ public: // friend class Persp3D; }; -struct Persp3D : public SPObject { +class Persp3D : public SPObject { +public: + Persp3D(); + virtual ~Persp3D(); + Persp3DImpl *perspective_impl; -}; -struct Persp3DClass { - SPItemClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + virtual void set(unsigned int key, const gchar* value); + + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); +}; -/* Standard GType function */ -GType persp3d_get_type (void); // FIXME: Make more of these inline! inline Persp3D * persp3d_get_from_repr (Inkscape::XML::Node *repr) { diff --git a/src/profile-manager.h b/src/profile-manager.h index 9d361f40c..be9446c17 100644 --- a/src/profile-manager.h +++ b/src/profile-manager.h @@ -17,7 +17,7 @@ class SPDocument; namespace Inkscape { -struct ColorProfile; +class ColorProfile; class ProfileManager : public DocumentSubset, public GC::Finalized diff --git a/src/rect-context.cpp b/src/rect-context.cpp index 17675745f..8a7427928 100644 --- a/src/rect-context.cpp +++ b/src/rect-context.cpp @@ -46,172 +46,117 @@ using Inkscape::DocumentUndo; -//static const double goldenratio = 1.61803398874989484820; // golden ratio +#include "tool-factory.h" -static void sp_rect_context_dispose(GObject *object); +namespace { + SPEventContext* createRectContext() { + return new SPRectContext(); + } -static void sp_rect_context_setup(SPEventContext *ec); -static void sp_rect_context_finish(SPEventContext *ec); -static void sp_rect_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val); - -static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent *event); -static gint sp_rect_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event); - -static void sp_rect_drag(SPRectContext &rc, Geom::Point const pt, guint state); -static void sp_rect_finish(SPRectContext *rc); -static void sp_rect_cancel(SPRectContext *rc); - -G_DEFINE_TYPE(SPRectContext, sp_rect_context, SP_TYPE_EVENT_CONTEXT); - -static void sp_rect_context_class_init(SPRectContextClass *klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - SPEventContextClass *event_context_class = (SPEventContextClass *) klass; - - object_class->dispose = sp_rect_context_dispose; - - event_context_class->setup = sp_rect_context_setup; - event_context_class->finish = sp_rect_context_finish; - event_context_class->set = sp_rect_context_set; - event_context_class->root_handler = sp_rect_context_root_handler; - event_context_class->item_handler = sp_rect_context_item_handler; + bool rectContextRegistered = ToolFactory::instance().registerObject("/tools/shapes/rect", createRectContext); } -static void sp_rect_context_init(SPRectContext *rect_context) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(rect_context); +const std::string& SPRectContext::getPrefsPath() { + return SPRectContext::prefsPath; +} - event_context->cursor_shape = cursor_rect_xpm; - event_context->hot_x = 4; - event_context->hot_y = 4; - event_context->xp = 0; - event_context->yp = 0; - event_context->tolerance = 0; - event_context->within_tolerance = false; - event_context->item_to_select = NULL; - event_context->tool_url = "/tools/shapes/rect"; +const std::string SPRectContext::prefsPath = "/tools/shapes/rect"; - rect_context->item = NULL; +SPRectContext::SPRectContext() : SPEventContext() { + this->cursor_shape = cursor_rect_xpm; + this->hot_x = 4; + this->hot_y = 4; + this->xp = 0; + this->yp = 0; + this->tolerance = 0; + this->within_tolerance = false; + this->item_to_select = NULL; - rect_context->rx = 0.0; - rect_context->ry = 0.0; + this->rect = NULL; - new (&rect_context->sel_changed_connection) sigc::connection(); + this->rx = 0.0; + this->ry = 0.0; } -static void sp_rect_context_finish(SPEventContext *ec) -{ - SPRectContext *rc = SP_RECT_CONTEXT(ec); - SPDesktop *desktop = ec->desktop; +void SPRectContext::finish() { + sp_canvas_item_ungrab(SP_CANVAS_ITEM(this->desktop->acetate), GDK_CURRENT_TIME); + + this->finishItem(); + this->sel_changed_connection.disconnect(); - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), GDK_CURRENT_TIME); - sp_rect_finish(rc); - rc->sel_changed_connection.disconnect(); - - if (((SPEventContextClass *) sp_rect_context_parent_class)->finish) { - ((SPEventContextClass *) sp_rect_context_parent_class)->finish(ec); - } + SPEventContext::finish(); } +SPRectContext::~SPRectContext() { + this->enableGrDrag(false); -static void sp_rect_context_dispose(GObject *object) -{ - SPRectContext *rc = SP_RECT_CONTEXT(object); - SPEventContext *ec = SP_EVENT_CONTEXT(object); + this->sel_changed_connection.disconnect(); - ec->enableGrDrag(false); - - rc->sel_changed_connection.disconnect(); - rc->sel_changed_connection.~connection(); - - delete ec->shape_editor; - ec->shape_editor = NULL; + delete this->shape_editor; + this->shape_editor = NULL; /* fixme: This is necessary because we do not grab */ - if (rc->item) { - sp_rect_finish(rc); - } - - if (rc->_message_context) { - delete rc->_message_context; + if (this->rect) { + this->finishItem(); } - - G_OBJECT_CLASS(sp_rect_context_parent_class)->dispose(object); } /** * Callback that processes the "changed" signal on the selection; * destroys old and creates new knotholder. */ -static void sp_rect_context_selection_changed(Inkscape::Selection *selection, gpointer data) -{ - SPRectContext *rc = SP_RECT_CONTEXT(data); - SPEventContext *ec = SP_EVENT_CONTEXT(rc); - - ec->shape_editor->unset_item(SH_KNOTHOLDER); - SPItem *item = selection->singleItem(); - ec->shape_editor->set_item(item, SH_KNOTHOLDER); +void SPRectContext::selection_changed(Inkscape::Selection* selection) { + this->shape_editor->unset_item(SH_KNOTHOLDER); + this->shape_editor->set_item(selection->singleItem(), SH_KNOTHOLDER); } -static void sp_rect_context_setup(SPEventContext *ec) -{ - SPRectContext *rc = SP_RECT_CONTEXT(ec); - - if (((SPEventContextClass *) sp_rect_context_parent_class)->setup) { - ((SPEventContextClass *) sp_rect_context_parent_class)->setup(ec); - } +void SPRectContext::setup() { + SPEventContext::setup(); - ec->shape_editor = new ShapeEditor(ec->desktop); + this->shape_editor = new ShapeEditor(this->desktop); - SPItem *item = sp_desktop_selection(ec->desktop)->singleItem(); + SPItem *item = sp_desktop_selection(this->desktop)->singleItem(); if (item) { - ec->shape_editor->set_item(item, SH_KNOTHOLDER); + this->shape_editor->set_item(item, SH_KNOTHOLDER); } - rc->sel_changed_connection.disconnect(); - rc->sel_changed_connection = sp_desktop_selection(ec->desktop)->connectChanged( - sigc::bind(sigc::ptr_fun(&sp_rect_context_selection_changed), (gpointer)rc) + this->sel_changed_connection.disconnect(); + this->sel_changed_connection = sp_desktop_selection(this->desktop)->connectChanged( + sigc::mem_fun(this, &SPRectContext::selection_changed) ); - sp_event_context_read(ec, "rx"); - sp_event_context_read(ec, "ry"); + sp_event_context_read(this, "rx"); + sp_event_context_read(this, "ry"); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/tools/shapes/selcue")) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } if (prefs->getBool("/tools/shapes/gradientdrag")) { - ec->enableGrDrag(); + this->enableGrDrag(); } - - rc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack()); } -static void sp_rect_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val) -{ - SPRectContext *rc = SP_RECT_CONTEXT(ec); - +void SPRectContext::set(const Inkscape::Preferences::Entry& val) { /* fixme: Proper error handling for non-numeric data. Use a locale-independent function like * g_ascii_strtod (or a thin wrapper that does the right thing for invalid values inf/nan). */ - Glib::ustring name = val->getEntryName(); + Glib::ustring name = val.getEntryName(); + if ( name == "rx" ) { - rc->rx = val->getDoubleLimited(); // prevents NaN and +/-Inf from messing up + this->rx = val.getDoubleLimited(); // prevents NaN and +/-Inf from messing up } else if ( name == "ry" ) { - rc->ry = val->getDoubleLimited(); + this->ry = val.getDoubleLimited(); } } -static gint sp_rect_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event) -{ - SPDesktop *desktop = event_context->desktop; - +bool SPRectContext::item_handler(SPItem* item, GdkEvent* event) { gint ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: - if ( event->button.button == 1 && !event_context->space_panning) { - Inkscape::setup_for_drag_start(desktop, event_context, event); + if ( event->button.button == 1 && !this->space_panning) { + Inkscape::setup_for_drag_start(desktop, this, event); ret = TRUE; } break; @@ -220,52 +165,50 @@ static gint sp_rect_context_item_handler(SPEventContext *event_context, SPItem * break; } - if (((SPEventContextClass *) sp_rect_context_parent_class)->item_handler) { - ret = ((SPEventContextClass *) sp_rect_context_parent_class)->item_handler(event_context, item, event); + if (!ret) { + ret = SPEventContext::item_handler(item, event); } return ret; } -static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent *event) -{ +bool SPRectContext::root_handler(GdkEvent* event) { static bool dragging; - SPDesktop *desktop = event_context->desktop; + SPDesktop *desktop = this->desktop; Inkscape::Selection *selection = sp_desktop_selection (desktop); - SPRectContext *rc = SP_RECT_CONTEXT(event_context); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - event_context->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); + this->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); gint ret = FALSE; + switch (event->type) { case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { - Geom::Point const button_w(event->button.x, - event->button.y); + if (event->button.button == 1 && !this->space_panning) { + Geom::Point const button_w(event->button.x, event->button.y); // save drag origin - event_context->xp = (gint) button_w[Geom::X]; - event_context->yp = (gint) button_w[Geom::Y]; - event_context->within_tolerance = true; + this->xp = (gint) button_w[Geom::X]; + this->yp = (gint) button_w[Geom::Y]; + this->within_tolerance = true; // remember clicked item, disregarding groups, honoring Alt - event_context->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE); + this->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE); dragging = true; /* Position center */ Geom::Point button_dt(desktop->w2d(button_w)); - rc->center = button_dt; + this->center = button_dt; /* Snap center */ SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); m.freeSnapReturnByRef(button_dt, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); - rc->center = button_dt; + this->center = button_dt; sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), ( GDK_KEY_PRESS_MASK | @@ -280,25 +223,25 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent break; case GDK_MOTION_NOTIFY: if ( dragging - && (event->motion.state & GDK_BUTTON1_MASK) && !event_context->space_panning) + && (event->motion.state & GDK_BUTTON1_MASK) && !this->space_panning) { - if ( event_context->within_tolerance - && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance ) - && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) { + if ( this->within_tolerance + && ( abs( (gint) event->motion.x - this->xp ) < this->tolerance ) + && ( abs( (gint) event->motion.y - this->yp ) < this->tolerance ) ) { break; // do not drag if we're within tolerance from origin } // Once the user has moved farther than tolerance from the original location // (indicating they intend to draw, not click), then always process the // motion notify coordinates as given (no snapping back to origin) - event_context->within_tolerance = false; + this->within_tolerance = false; Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point motion_dt(desktop->w2d(motion_w)); - sp_rect_drag(*rc, motion_dt, event->motion.state); // this will also handle the snapping + this->drag(motion_dt, event->motion.state); // this will also handle the snapping gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; - } else if (!sp_event_context_knot_mouseover(rc)) { + } else if (!sp_event_context_knot_mouseover(this)) { SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); @@ -310,27 +253,27 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent } break; case GDK_BUTTON_RELEASE: - event_context->xp = event_context->yp = 0; - if (event->button.button == 1 && !event_context->space_panning) { + this->xp = this->yp = 0; + if (event->button.button == 1 && !this->space_panning) { dragging = false; - sp_event_context_discard_delayed_snap_event(event_context); + sp_event_context_discard_delayed_snap_event(this); - if (!event_context->within_tolerance) { + if (!this->within_tolerance) { // we've been dragging, finish the rect - sp_rect_finish(rc); - } else if (event_context->item_to_select) { + this->finishItem(); + } else if (this->item_to_select) { // no dragging, select clicked item if any if (event->button.state & GDK_SHIFT_MASK) { - selection->toggle(event_context->item_to_select); + selection->toggle(this->item_to_select); } else { - selection->set(event_context->item_to_select); + selection->set(this->item_to_select); } } else { // click in an empty space selection->clear(); } - event_context->item_to_select = NULL; + this->item_to_select = NULL; ret = TRUE; sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); @@ -347,7 +290,7 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent case GDK_KEY_Meta_L: // Meta is when you press Shift+Alt (at least on my machine) case GDK_KEY_Meta_R: if (!dragging){ - sp_event_show_modifier_tip (event_context->defaultMessageContext(), event, + sp_event_show_modifier_tip (this->defaultMessageContext(), event, _("<b>Ctrl</b>: make square or integer-ratio rect, lock a rounded corner circular"), _("<b>Shift</b>: draw around the starting point"), NULL); @@ -381,9 +324,9 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent case GDK_KEY_Escape: if (dragging) { dragging = false; - sp_event_context_discard_delayed_snap_event(event_context); + sp_event_context_discard_delayed_snap_event(this); // if drawing, cancel, otherwise pass it up for deselecting - sp_rect_cancel(rc); + this->cancel(); ret = TRUE; } break; @@ -393,10 +336,11 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); dragging = false; - sp_event_context_discard_delayed_snap_event(event_context); - if (!event_context->within_tolerance) { + sp_event_context_discard_delayed_snap_event(this); + + if (!this->within_tolerance) { // we've been dragging, finish the rect - sp_rect_finish(rc); + this->finishItem(); } // do not return true, so that space would work switching to selector } @@ -405,7 +349,7 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent case GDK_KEY_Delete: case GDK_KEY_KP_Delete: case GDK_KEY_BackSpace: - ret = event_context->deleteSelectedDrag(MOD__CTRL_ONLY(event)); + ret = this->deleteSelectedDrag(MOD__CTRL_ONLY(event)); break; default: @@ -422,7 +366,7 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent case GDK_KEY_Shift_R: case GDK_KEY_Meta_L: // Meta is when you press Shift+Alt case GDK_KEY_Meta_R: - event_context->defaultMessageContext()->clear(); + this->defaultMessageContext()->clear(); break; default: break; @@ -433,136 +377,135 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent } if (!ret) { - if (((SPEventContextClass *) sp_rect_context_parent_class)->root_handler) { - ret = ((SPEventContextClass *) sp_rect_context_parent_class)->root_handler(event_context, event); - } + ret = SPEventContext::root_handler(event); } return ret; } -static void sp_rect_drag(SPRectContext &rc, Geom::Point const pt, guint state) -{ - SPDesktop *desktop = SP_EVENT_CONTEXT(&rc)->desktop; +void SPRectContext::drag(Geom::Point const pt, guint state) { + SPDesktop *desktop = this->desktop; - if (!rc.item) { - - if (Inkscape::have_viable_layer(desktop, rc._message_context) == false) { + if (!this->rect) { + if (Inkscape::have_viable_layer(desktop, this->message_context) == false) { return; } // Create object - Inkscape::XML::Document *xml_doc = SP_EVENT_CONTEXT_DOCUMENT(&rc)->getReprDoc(); + Inkscape::XML::Document *xml_doc = this->desktop->doc()->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:rect"); // Set style sp_desktop_apply_style_tool (desktop, repr, "/tools/shapes/rect", false); - rc.item = (SPItem *) desktop->currentLayer()->appendChildRepr(repr); + this->rect = SP_RECT(desktop->currentLayer()->appendChildRepr(repr)); Inkscape::GC::release(repr); - rc.item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); - rc.item->updateRepr(); + + this->rect->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); + this->rect->updateRepr(); desktop->canvas->forceFullRedrawAfterInterruptions(5); } - Geom::Rect const r = Inkscape::snap_rectangular_box(desktop, rc.item, pt, rc.center, state); + Geom::Rect const r = Inkscape::snap_rectangular_box(desktop, this->rect, pt, this->center, state); - sp_rect_position_set(SP_RECT(rc.item), r.min()[Geom::X], r.min()[Geom::Y], r.dimensions()[Geom::X], r.dimensions()[Geom::Y]); - if ( rc.rx != 0.0 ) { - sp_rect_set_rx (SP_RECT(rc.item), TRUE, rc.rx); + this->rect->setPosition(r.min()[Geom::X], r.min()[Geom::Y], r.dimensions()[Geom::X], r.dimensions()[Geom::Y]); + + if (this->rx != 0.0) { + this->rect->setRx(true, this->rx); } - if ( rc.ry != 0.0 ) { - if (rc.rx == 0.0) - sp_rect_set_ry (SP_RECT(rc.item), TRUE, CLAMP(rc.ry, 0, MIN(r.dimensions()[Geom::X], r.dimensions()[Geom::Y])/2)); + + if (this->ry != 0.0) { + if (this->rx == 0.0) + this->rect->setRy(true, CLAMP(this->ry, 0, MIN(r.dimensions()[Geom::X], r.dimensions()[Geom::Y])/2)); else - sp_rect_set_ry (SP_RECT(rc.item), TRUE, CLAMP(rc.ry, 0, r.dimensions()[Geom::Y])); + this->rect->setRy(true, CLAMP(this->ry, 0, r.dimensions()[Geom::Y])); } // status text double rdimx = r.dimensions()[Geom::X]; double rdimy = r.dimensions()[Geom::Y]; + Inkscape::Util::Quantity rdimx_q = Inkscape::Util::Quantity(rdimx, "px"); Inkscape::Util::Quantity rdimy_q = Inkscape::Util::Quantity(rdimy, "px"); GString *xs = g_string_new(rdimx_q.string(*desktop->namedview->doc_units).c_str()); GString *ys = g_string_new(rdimy_q.string(*desktop->namedview->doc_units).c_str()); + if (state & GDK_CONTROL_MASK) { int ratio_x, ratio_y; bool is_golden_ratio = false; + if (fabs (rdimx) > fabs (rdimy)) { if (fabs(rdimx / rdimy - goldenratio) < 1e-6) { is_golden_ratio = true; } + ratio_x = (int) rint (rdimx / rdimy); ratio_y = 1; } else { if (fabs(rdimy / rdimx - goldenratio) < 1e-6) { is_golden_ratio = true; } + ratio_x = 1; ratio_y = (int) rint (rdimy / rdimx); } + if (!is_golden_ratio) { - rc._message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Rectangle</b>: %s × %s (constrained to ratio %d:%d); with <b>Shift</b> to draw around the starting point"), xs->str, ys->str, ratio_x, ratio_y); + this->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Rectangle</b>: %s × %s (constrained to ratio %d:%d); with <b>Shift</b> to draw around the starting point"), xs->str, ys->str, ratio_x, ratio_y); } else { if (ratio_y == 1) { - rc._message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Rectangle</b>: %s × %s (constrained to golden ratio 1.618 : 1); with <b>Shift</b> to draw around the starting point"), xs->str, ys->str); + this->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Rectangle</b>: %s × %s (constrained to golden ratio 1.618 : 1); with <b>Shift</b> to draw around the starting point"), xs->str, ys->str); } else { - rc._message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Rectangle</b>: %s × %s (constrained to golden ratio 1 : 1.618); with <b>Shift</b> to draw around the starting point"), xs->str, ys->str); + this->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Rectangle</b>: %s × %s (constrained to golden ratio 1 : 1.618); with <b>Shift</b> to draw around the starting point"), xs->str, ys->str); } } } else { - rc._message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Rectangle</b>: %s × %s; with <b>Ctrl</b> to make square or integer-ratio rectangle; with <b>Shift</b> to draw around the starting point"), xs->str, ys->str); + this->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Rectangle</b>: %s × %s; with <b>Ctrl</b> to make square or integer-ratio rectangle; with <b>Shift</b> to draw around the starting point"), xs->str, ys->str); } + g_string_free(xs, FALSE); g_string_free(ys, FALSE); } -static void sp_rect_finish(SPRectContext *rc) -{ - rc->_message_context->clear(); +void SPRectContext::finishItem() { + this->message_context->clear(); - if ( rc->item != NULL ) { - SPRect *rect = SP_RECT(rc->item); - if (rect->width.computed == 0 || rect->height.computed == 0) { - sp_rect_cancel(rc); // Don't allow the creating of zero sized rectangle, for example when the start and and point snap to the snap grid point + if (this->rect != NULL) { + if (this->rect->width.computed == 0 || this->rect->height.computed == 0) { + this->cancel(); // Don't allow the creating of zero sized rectangle, for example when the start and and point snap to the snap grid point return; } - SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(rc); + this->rect->updateRepr(); - SP_OBJECT(rc->item)->updateRepr(); + this->desktop->canvas->endForcedFullRedraws(); - desktop->canvas->endForcedFullRedraws(); + sp_desktop_selection(this->desktop)->set(this->rect); - sp_desktop_selection(desktop)->set(rc->item); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT, - _("Create rectangle")); + DocumentUndo::done(sp_desktop_document(this->desktop), SP_VERB_CONTEXT_RECT, _("Create rectangle")); - rc->item = NULL; + this->rect = NULL; } } -static void sp_rect_cancel(SPRectContext *rc) -{ - SPDesktop *desktop = SP_EVENT_CONTEXT(rc)->desktop; - - sp_desktop_selection(desktop)->clear(); - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0); +void SPRectContext::cancel(){ + sp_desktop_selection(this->desktop)->clear(); + sp_canvas_item_ungrab(SP_CANVAS_ITEM(this->desktop->acetate), 0); - if (rc->item != NULL) { - SP_OBJECT(rc->item)->deleteObject(); - rc->item = NULL; + if (this->rect != NULL) { + this->rect->deleteObject(); + this->rect = NULL; } - rc->within_tolerance = false; - rc->xp = 0; - rc->yp = 0; - rc->item_to_select = NULL; + this->within_tolerance = false; + this->xp = 0; + this->yp = 0; + this->item_to_select = NULL; - desktop->canvas->endForcedFullRedraws(); + this->desktop->canvas->endForcedFullRedraws(); - DocumentUndo::cancel(sp_desktop_document(desktop)); + DocumentUndo::cancel(sp_desktop_document(this->desktop)); } diff --git a/src/rect-context.h b/src/rect-context.h index 5b6c5373e..a85968b1c 100644 --- a/src/rect-context.h +++ b/src/rect-context.h @@ -19,14 +19,28 @@ #include <2geom/point.h> #include "event-context.h" -#define SP_TYPE_RECT_CONTEXT (sp_rect_context_get_type ()) -#define SP_RECT_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_RECT_CONTEXT, SPRectContext)) -#define SP_RECT_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_RECT_CONTEXT, SPRectContextClass)) -#define SP_IS_RECT_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_RECT_CONTEXT)) -#define SP_IS_RECT_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_RECT_CONTEXT)) - -struct SPRectContext : public SPEventContext { - SPItem *item; +#include "sp-rect.h" + +#define SP_RECT_CONTEXT(obj) (dynamic_cast<SPRectContext*>((SPEventContext*)obj)) +#define SP_IS_RECT_CONTEXT(obj) (dynamic_cast<const SPRectContext*>((const SPEventContext*)obj) != NULL) + +class SPRectContext : public SPEventContext { +public: + SPRectContext(); + virtual ~SPRectContext(); + + static const std::string prefsPath; + + virtual void setup(); + virtual void finish(); + virtual void set(const Inkscape::Preferences::Entry& val); + virtual bool root_handler(GdkEvent* event); + virtual bool item_handler(SPItem* item, GdkEvent* event); + + virtual const std::string& getPrefsPath(); + +private: + SPRect *rect; Geom::Point center; gdouble rx; /* roundness radius (x direction) */ @@ -34,15 +48,10 @@ struct SPRectContext : public SPEventContext { sigc::connection sel_changed_connection; - Inkscape::MessageContext *_message_context; -}; - -struct SPRectContextClass { - SPEventContextClass parent_class; + void drag(Geom::Point const pt, guint state); + void finishItem(); + void cancel(); + void selection_changed(Inkscape::Selection* selection); }; -/* Standard Gtk function */ - -GType sp_rect_context_get_type (void); - #endif diff --git a/src/select-context.cpp b/src/select-context.cpp index df90d62cb..99eb01fea 100644 --- a/src/select-context.cpp +++ b/src/select-context.cpp @@ -52,44 +52,28 @@ using Inkscape::DocumentUndo; -static void sp_select_context_dispose(GObject *object); - -static void sp_select_context_setup(SPEventContext *ec); -static void sp_select_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val); -static gint sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event); -static gint sp_select_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event); -static void sp_select_context_reset_opacities(SPEventContext *event_context); - static GdkCursor *CursorSelectMouseover = NULL; static GdkCursor *CursorSelectDragging = NULL; GdkPixbuf *handles[13]; static gint rb_escaped = 0; // if non-zero, rubberband was canceled by esc, so the next button release should not deselect static gint drag_escaped = 0; // if non-zero, drag was canceled by esc +#include "tool-factory.h" -static gint xp = 0, yp = 0; // where drag started -static gint tolerance = 0; -static bool within_tolerance = false; -static bool is_cycling = false; -static bool moved_while_cycling = false; -SPEventContext *prev_event_context = NULL; +namespace { + SPEventContext* createSelectContext() { + return new SPSelectContext(); + } + bool selectContextRegistered = ToolFactory::instance().registerObject("/tools/select", createSelectContext); +} -G_DEFINE_TYPE(SPSelectContext, sp_select_context, SP_TYPE_EVENT_CONTEXT); +const std::string& SPSelectContext::getPrefsPath() { + return SPSelectContext::prefsPath; +} -static void -sp_select_context_class_init(SPSelectContextClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - SPEventContextClass *event_context_class = SP_EVENT_CONTEXT_CLASS(klass); +const std::string SPSelectContext::prefsPath = "/tools/select"; - object_class->dispose = sp_select_context_dispose; - - event_context_class->setup = sp_select_context_setup; - event_context_class->set = sp_select_context_set; - event_context_class->root_handler = sp_select_context_root_handler; - event_context_class->item_handler = sp_select_context_item_handler; -} //Creates rotated variations for handles static void @@ -101,25 +85,28 @@ sp_load_handles(int start, int count, char const **xpm) { } } -static void -sp_select_context_init(SPSelectContext *sc) -{ - sc->dragging = FALSE; - sc->moved = FALSE; - sc->button_press_shift = false; - sc->button_press_ctrl = false; - sc->button_press_alt = false; - sc->cycling_items = NULL; - sc->cycling_items_cmp = NULL; - sc->cycling_items_selected_before = NULL; - sc->cycling_cur_item = NULL; - sc->cycling_wrap = true; - sc->_seltrans = NULL; - sc->_describer = NULL; +SPSelectContext::SPSelectContext() : SPEventContext() { + this->grabbed = 0; + this->item = 0; + + this->dragging = FALSE; + this->moved = FALSE; + this->button_press_shift = false; + this->button_press_ctrl = false; + this->button_press_alt = false; + this->cycling_items = NULL; + this->cycling_items_cmp = NULL; + this->cycling_items_selected_before = NULL; + this->cycling_cur_item = NULL; + this->cycling_wrap = true; + this->_seltrans = NULL; + this->_describer = NULL; + // cursors in select context CursorSelectMouseover = sp_cursor_new_from_xpm(cursor_select_m_xpm , 1, 1); CursorSelectDragging = sp_cursor_new_from_xpm(cursor_select_d_xpm , 1, 1); + // selection handles sp_load_handles(0, 2, handle_scale_xpm); sp_load_handles(2, 2, handle_stretch_xpm); @@ -128,23 +115,27 @@ sp_select_context_init(SPSelectContext *sc) sp_load_handles(12, 1, handle_center_xpm); } -static void -sp_select_context_dispose(GObject *object) -{ - SPSelectContext *sc = SP_SELECT_CONTEXT(object); - SPEventContext * ec = SP_EVENT_CONTEXT (object); +//static gint xp = 0, yp = 0; // where drag started +//static gint tolerance = 0; +//static bool within_tolerance = false; +static bool is_cycling = false; +static bool moved_while_cycling = false; +SPEventContext *prev_event_context = NULL; + - ec->enableGrDrag(false); +SPSelectContext::~SPSelectContext() { + this->enableGrDrag(false); - if (sc->grabbed) { - sp_canvas_item_ungrab(sc->grabbed, GDK_CURRENT_TIME); - sc->grabbed = NULL; + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, GDK_CURRENT_TIME); + this->grabbed = NULL; } - delete sc->_seltrans; - sc->_seltrans = NULL; - delete sc->_describer; - sc->_describer = NULL; + delete this->_seltrans; + this->_seltrans = NULL; + + delete this->_describer; + this->_describer = NULL; if (CursorSelectDragging) { #if GTK_CHECK_VERSION(3,0,0) @@ -154,6 +145,7 @@ sp_select_context_dispose(GObject *object) #endif CursorSelectDragging = NULL; } + if (CursorSelectMouseover) { #if GTK_CHECK_VERSION(3,0,0) g_object_unref(CursorSelectMouseover); @@ -162,93 +154,77 @@ sp_select_context_dispose(GObject *object) #endif CursorSelectMouseover = NULL; } - - G_OBJECT_CLASS(sp_select_context_parent_class)->dispose(object); } -static void -sp_select_context_setup(SPEventContext *ec) -{ - SPSelectContext *select_context = SP_SELECT_CONTEXT(ec); - - if ((SP_EVENT_CONTEXT_CLASS(sp_select_context_parent_class))->setup) { - (SP_EVENT_CONTEXT_CLASS(sp_select_context_parent_class))->setup(ec); - } +void SPSelectContext::setup() { + SPEventContext::setup(); - SPDesktop *desktop = ec->desktop; - - select_context->_describer = new Inkscape::SelectionDescriber( + this->_describer = new Inkscape::SelectionDescriber( desktop->selection, desktop->messageStack(), _("Click selection to toggle scale/rotation handles"), _("No objects selected. Click, Shift+click, Alt+scroll mouse on top of objects, or drag around objects to select.") - ); + ); - select_context->_seltrans = new Inkscape::SelTrans(desktop); + this->_seltrans = new Inkscape::SelTrans(desktop); - sp_event_context_read(ec, "show"); - sp_event_context_read(ec, "transform"); + sp_event_context_read(this, "show"); + sp_event_context_read(this, "transform"); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/tools/select/gradientdrag")) { - ec->enableGrDrag(); + this->enableGrDrag(); } } -static void -sp_select_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val) -{ - SPSelectContext *sc = SP_SELECT_CONTEXT(ec); - Glib::ustring path = val->getEntryName(); +void SPSelectContext::set(const Inkscape::Preferences::Entry& val) { + Glib::ustring path = val.getEntryName(); if (path == "show") { - if (val->getString() == "outline") { - sc->_seltrans->setShow(Inkscape::SelTrans::SHOW_OUTLINE); + if (val.getString() == "outline") { + this->_seltrans->setShow(Inkscape::SelTrans::SHOW_OUTLINE); } else { - sc->_seltrans->setShow(Inkscape::SelTrans::SHOW_CONTENT); + this->_seltrans->setShow(Inkscape::SelTrans::SHOW_CONTENT); } } } -static bool -sp_select_context_abort(SPEventContext *event_context) -{ - SPDesktop *desktop = event_context->desktop; - SPSelectContext *sc = SP_SELECT_CONTEXT(event_context); - Inkscape::SelTrans *seltrans = sc->_seltrans; +bool SPSelectContext::sp_select_context_abort() { + Inkscape::SelTrans *seltrans = this->_seltrans; - if (sc->dragging) { - if (sc->moved) { // cancel dragging an object + if (this->dragging) { + if (this->moved) { // cancel dragging an object seltrans->ungrab(); - sc->moved = FALSE; - sc->dragging = FALSE; - sp_event_context_discard_delayed_snap_event(event_context); + this->moved = FALSE; + this->dragging = FALSE; + sp_event_context_discard_delayed_snap_event(this); drag_escaped = 1; - if (sc->item) { + if (this->item) { // only undo if the item is still valid - if (sc->item->document) { + if (this->item->document) { DocumentUndo::undo(sp_desktop_document(desktop)); } - sp_object_unref( sc->item, NULL); - } else if (sc->button_press_ctrl) { + sp_object_unref( this->item, NULL); + } else if (this->button_press_ctrl) { // NOTE: This is a workaround to a bug. // When the ctrl key is held, sc->item is not defined // so in this case (only), we skip the object doc check DocumentUndo::undo(sp_desktop_document(desktop)); } - sc->item = NULL; + this->item = NULL; - SP_EVENT_CONTEXT(sc)->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Move canceled.")); + SP_EVENT_CONTEXT(this)->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Move canceled.")); return true; } } else { if (Inkscape::Rubberband::get(desktop)->is_started()) { Inkscape::Rubberband::get(desktop)->stop(); rb_escaped = 1; - SP_EVENT_CONTEXT(sc)->defaultMessageContext()->clear(); - SP_EVENT_CONTEXT(sc)->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Selection canceled.")); + SP_EVENT_CONTEXT(this)->defaultMessageContext()->clear(); + SP_EVENT_CONTEXT(this)->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Selection canceled.")); return true; } } @@ -297,26 +273,20 @@ sp_select_context_up_one_layer(SPDesktop *desktop) } } -static gint -sp_select_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event) -{ +bool SPSelectContext::item_handler(SPItem* item, GdkEvent* event) { gint ret = FALSE; - SPDesktop *desktop = event_context->desktop; - SPSelectContext *sc = SP_SELECT_CONTEXT(event_context); - Inkscape::SelTrans *seltrans = sc->_seltrans; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); // make sure we still have valid objects to move around - if (sc->item && sc->item->document == NULL) { - sp_select_context_abort(event_context); + if (this->item && this->item->document == NULL) { + this->sp_select_context_abort(); } switch (event->type) { case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { + if (event->button.button == 1 && !this->space_panning) { /* Left mousebutton */ // save drag origin @@ -325,42 +295,46 @@ sp_select_context_item_handler(SPEventContext *event_context, SPItem *item, GdkE within_tolerance = true; // remember what modifiers were on before button press - sc->button_press_shift = (event->button.state & GDK_SHIFT_MASK) ? true : false; - sc->button_press_ctrl = (event->button.state & GDK_CONTROL_MASK) ? true : false; - sc->button_press_alt = (event->button.state & GDK_MOD1_MASK) ? true : false; + this->button_press_shift = (event->button.state & GDK_SHIFT_MASK) ? true : false; + this->button_press_ctrl = (event->button.state & GDK_CONTROL_MASK) ? true : false; + this->button_press_alt = (event->button.state & GDK_MOD1_MASK) ? true : false; if (event->button.state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)) { // if shift or ctrl was pressed, do not move objects; // pass the event to root handler which will perform rubberband, shift-click, ctrl-click, ctrl-drag } else { - GdkWindow* window = gtk_widget_get_window (GTK_WIDGET (sp_desktop_canvas(desktop))); + GdkWindow* window = gtk_widget_get_window (GTK_WIDGET (sp_desktop_canvas(desktop))); - sc->dragging = TRUE; - sc->moved = FALSE; + this->dragging = TRUE; + this->moved = FALSE; + gdk_window_set_cursor(window, CursorSelectDragging); desktop->canvas->forceFullRedrawAfterInterruptions(5); - // remember the clicked item in sc->item: - if (sc->item) { - sp_object_unref(sc->item, NULL); - sc->item = NULL; + // remember the clicked item in this->item: + if (this->item) { + sp_object_unref(this->item, NULL); + this->item = NULL; } - sc->item = sp_event_context_find_item (desktop, + + this->item = sp_event_context_find_item (desktop, Geom::Point(event->button.x, event->button.y), event->button.state & GDK_MOD1_MASK, FALSE); - sp_object_ref(sc->item, NULL); + sp_object_ref(this->item, NULL); rb_escaped = drag_escaped = 0; - if (sc->grabbed) { - sp_canvas_item_ungrab(sc->grabbed, event->button.time); - sc->grabbed = NULL; + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, event->button.time); + this->grabbed = NULL; } + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->drawing), GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK, NULL, event->button.time); - sc->grabbed = SP_CANVAS_ITEM(desktop->drawing); + + this->grabbed = SP_CANVAS_ITEM(desktop->drawing); desktop->canvas->forceFullRedrawAfterInterruptions(5); @@ -368,43 +342,41 @@ sp_select_context_item_handler(SPEventContext *event_context, SPItem *item, GdkE } } else if (event->button.button == 3) { // right click; do not eat it so that right-click menu can appear, but cancel dragging & rubberband - sp_select_context_abort(event_context); + this->sp_select_context_abort(); } break; - case GDK_ENTER_NOTIFY: - { - if (!desktop->isWaitingCursor() && !sc->dragging) { + case GDK_ENTER_NOTIFY: { + if (!desktop->isWaitingCursor() && !this->dragging) { GdkWindow* window = gtk_widget_get_window (GTK_WIDGET (sp_desktop_canvas(desktop))); gdk_window_set_cursor(window, CursorSelectMouseover); } break; } - case GDK_LEAVE_NOTIFY: - if (!desktop->isWaitingCursor() && !sc->dragging) { + if (!desktop->isWaitingCursor() && !this->dragging) { GdkWindow* window = gtk_widget_get_window (GTK_WIDGET (sp_desktop_canvas(desktop))); - gdk_window_set_cursor(window, event_context->cursor); - } + gdk_window_set_cursor(window, this->cursor); + } break; case GDK_KEY_PRESS: if (get_group0_keyval (&event->key) == GDK_KEY_space) { - if (sc->dragging && sc->grabbed) { + if (this->dragging && this->grabbed) { /* stamping mode: show content mode moving */ - seltrans->stamp(); + _seltrans->stamp(); ret = TRUE; } } else if (get_group0_keyval (&event->key) == GDK_KEY_Tab) { - if (sc->dragging && sc->grabbed) { - seltrans->getNextClosestPoint(false); + if (this->dragging && this->grabbed) { + _seltrans->getNextClosestPoint(false); ret = TRUE; } } else if (get_group0_keyval (&event->key) == GDK_KEY_ISO_Left_Tab) { - if (sc->dragging && sc->grabbed) { - seltrans->getNextClosestPoint(true); + if (this->dragging && this->grabbed) { + _seltrans->getNextClosestPoint(true); ret = TRUE; } } @@ -415,66 +387,86 @@ sp_select_context_item_handler(SPEventContext *event_context, SPItem *item, GdkE } if (!ret) { - if ((SP_EVENT_CONTEXT_CLASS(sp_select_context_parent_class))->item_handler) - ret = (SP_EVENT_CONTEXT_CLASS(sp_select_context_parent_class))->item_handler(event_context, item, event); + ret = SPEventContext::item_handler(item, event); } return ret; } -static void -sp_select_context_cycle_through_items(SPSelectContext *sc, Inkscape::Selection *selection, GdkEventScroll *scroll_event, bool shift_pressed) { - if (!sc->cycling_cur_item) +void SPSelectContext::sp_select_context_cycle_through_items(Inkscape::Selection *selection, GdkEventScroll *scroll_event, bool shift_pressed) { + if (!this->cycling_cur_item) { return; + } Inkscape::DrawingItem *arenaitem; - SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; - SPItem *item = SP_ITEM(sc->cycling_cur_item->data); + SPItem *item = SP_ITEM(this->cycling_cur_item->data); // Deactivate current item - if (!g_list_find(sc->cycling_items_selected_before, item) && selection->includes(item)) + if (!g_list_find(this->cycling_items_selected_before, item) && selection->includes(item)) { selection->remove(item); + } + arenaitem = item->get_arenaitem(desktop->dkey); arenaitem->setOpacity(0.3); // Find next item and activate it GList *next; if (scroll_event->direction == GDK_SCROLL_UP) { - next = sc->cycling_cur_item->next; - if (next == NULL && sc->cycling_wrap) - next = sc->cycling_items; + next = this->cycling_cur_item->next; + if (next == NULL && this->cycling_wrap) + next = this->cycling_items; } else { - next = sc->cycling_cur_item->prev; - if (next == NULL && sc->cycling_wrap) - next = g_list_last(sc->cycling_items); + next = this->cycling_cur_item->prev; + if (next == NULL && this->cycling_wrap) + next = g_list_last(this->cycling_items); } + if (next) { - sc->cycling_cur_item = next; - item = SP_ITEM(sc->cycling_cur_item->data); + this->cycling_cur_item = next; + item = SP_ITEM(this->cycling_cur_item->data); } + arenaitem = item->get_arenaitem(desktop->dkey); arenaitem->setOpacity(1.0); - if (shift_pressed) + if (shift_pressed) { selection->add(item); - else + } else { selection->set(item); + } } -static gint -sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) + +static void +sp_select_context_reset_opacities(SPEventContext *event_context) { + // SPDesktop *desktop = event_context->desktop; + SPSelectContext *sc = SP_SELECT_CONTEXT(event_context); + Inkscape::DrawingItem *arenaitem; + for (GList *l = sc->cycling_items; l != NULL; l = g_list_next(l)) { + arenaitem = SP_ITEM(l->data)->get_arenaitem(event_context->desktop->dkey); + arenaitem->setOpacity(SP_SCALE24_TO_FLOAT(SP_ITEM(l->data)->style->opacity.value)); + } + g_list_free(sc->cycling_items); + g_list_free(sc->cycling_items_selected_before); + g_list_free(sc->cycling_items_cmp); + sc->cycling_items = NULL; + sc->cycling_items_selected_before = NULL; + sc->cycling_cur_item = NULL; + sc->cycling_items_cmp = NULL; +} + +bool SPSelectContext::root_handler(GdkEvent* event) { + SPItem *item = NULL; + SPItem *item_at_point = NULL, *group_at_point = NULL, *item_in_group = NULL; gint ret = FALSE; - SPDesktop *desktop = event_context->desktop; - SPSelectContext *sc = SP_SELECT_CONTEXT(event_context); - Inkscape::SelTrans *seltrans = sc->_seltrans; Inkscape::Selection *selection = sp_desktop_selection(desktop); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); // make sure we still have valid objects to move around - if (sc->item && sc->item->document == NULL) { - sp_select_context_abort(event_context); + if (this->item && this->item->document == NULL) { + this->sp_select_context_abort(); } switch (event->type) { @@ -482,11 +474,12 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) if (event->button.button == 1) { if (!selection->isEmpty()) { SPItem *clicked_item = static_cast<SPItem *>(selection->itemList()->data); + if (SP_IS_GROUP(clicked_item) && !SP_IS_BOX3D(clicked_item)) { // enter group if it's not a 3D box desktop->setCurrentLayer(reinterpret_cast<SPObject *>(clicked_item)); sp_desktop_selection(desktop)->clear(); - sc->dragging = false; - sp_event_context_discard_delayed_snap_event(event_context); + this->dragging = false; + sp_event_context_discard_delayed_snap_event(this); desktop->canvas->endForcedFullRedraws(); } else { // switch tool @@ -497,12 +490,13 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) } else { sp_select_context_up_one_layer(desktop); } + ret = TRUE; } break; - case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { + case GDK_BUTTON_PRESS: + if (event->button.button == 1 && !this->space_panning) { // save drag origin xp = (gint) event->button.x; yp = (gint) event->button.y; @@ -510,43 +504,51 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) Geom::Point const button_pt(event->button.x, event->button.y); Geom::Point const p(desktop->w2d(button_pt)); - if (event->button.state & GDK_MOD1_MASK) + + if (event->button.state & GDK_MOD1_MASK) { Inkscape::Rubberband::get(desktop)->setMode(RUBBERBAND_MODE_TOUCHPATH); + } + Inkscape::Rubberband::get(desktop)->start(desktop, p); - if (sc->grabbed) { - sp_canvas_item_ungrab(sc->grabbed, event->button.time); - sc->grabbed = NULL; + + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, event->button.time); + this->grabbed = NULL; } + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK, NULL, event->button.time); - sc->grabbed = SP_CANVAS_ITEM(desktop->acetate); + + this->grabbed = SP_CANVAS_ITEM(desktop->acetate); // remember what modifiers were on before button press - sc->button_press_shift = (event->button.state & GDK_SHIFT_MASK) ? true : false; - sc->button_press_ctrl = (event->button.state & GDK_CONTROL_MASK) ? true : false; - sc->button_press_alt = (event->button.state & GDK_MOD1_MASK) ? true : false; + this->button_press_shift = (event->button.state & GDK_SHIFT_MASK) ? true : false; + this->button_press_ctrl = (event->button.state & GDK_CONTROL_MASK) ? true : false; + this->button_press_alt = (event->button.state & GDK_MOD1_MASK) ? true : false; - sc->moved = FALSE; + this->moved = FALSE; rb_escaped = drag_escaped = 0; ret = TRUE; } else if (event->button.button == 3) { // right click; do not eat it so that right-click menu can appear, but cancel dragging & rubberband - sp_select_context_abort(event_context); + this->sp_select_context_abort(); } break; case GDK_MOTION_NOTIFY: { - if (is_cycling) - { - moved_while_cycling = true; - prev_event_context = event_context; - } - tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); - if ((event->motion.state & GDK_BUTTON1_MASK) && !event_context->space_panning) { + if (is_cycling) + { + moved_while_cycling = true; + prev_event_context = this; + } + + tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); + + if ((event->motion.state & GDK_BUTTON1_MASK) && !this->space_panning) { Geom::Point const motion_pt(event->motion.x, event->motion.y); Geom::Point const p(desktop->w2d(motion_pt)); @@ -560,73 +562,90 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) // motion notify coordinates as given (no snapping back to origin) within_tolerance = false; - if (sc->button_press_ctrl || (sc->button_press_alt && !sc->button_press_shift && !selection->isEmpty())) { + if (this->button_press_ctrl || (this->button_press_alt && !this->button_press_shift && !selection->isEmpty())) { // if it's not click and ctrl or alt was pressed (the latter with some selection // but not with shift) we want to drag rather than rubberband - sc->dragging = TRUE; - GdkWindow* window = gtk_widget_get_window (GTK_WIDGET (sp_desktop_canvas(desktop))); + this->dragging = TRUE; + + GdkWindow* window = gtk_widget_get_window (GTK_WIDGET (sp_desktop_canvas(desktop))); + gdk_window_set_cursor(window, CursorSelectDragging); desktop->canvas->forceFullRedrawAfterInterruptions(5); } - if (sc->dragging) { + if (this->dragging) { /* User has dragged fast, so we get events on root (lauris)*/ // not only that; we will end up here when ctrl-dragging as well // and also when we started within tolerance, but trespassed tolerance outside of item Inkscape::Rubberband::get(desktop)->stop(); - SP_EVENT_CONTEXT(sc)->defaultMessageContext()->clear(); - SPItem *item_at_point = desktop->getItemAtPoint(Geom::Point(event->button.x, event->button.y), FALSE); - if (!item_at_point) // if no item at this point, try at the click point (bug 1012200) + this->defaultMessageContext()->clear(); + + item_at_point = desktop->getItemAtPoint(Geom::Point(event->button.x, event->button.y), FALSE); + + if (!item_at_point) { // if no item at this point, try at the click point (bug 1012200) item_at_point = desktop->getItemAtPoint(Geom::Point(xp, yp), FALSE); - if (item_at_point || sc->moved || sc->button_press_alt) { + } + + if (item_at_point || this->moved || this->button_press_alt) { // drag only if starting from an item, or if something is already grabbed, or if alt-dragging - if (!sc->moved) { - SPItem *item_in_group = desktop->getItemAtPoint(Geom::Point(event->button.x, event->button.y), TRUE); - SPItem *group_at_point = desktop->getGroupAtPoint(Geom::Point(event->button.x, event->button.y)); - if (SP_IS_LAYER(selection->single())) + if (!this->moved) { + item_in_group = desktop->getItemAtPoint(Geom::Point(event->button.x, event->button.y), TRUE); + group_at_point = desktop->getGroupAtPoint(Geom::Point(event->button.x, event->button.y)); + + if (SP_IS_LAYER(selection->single())) { group_at_point = SP_GROUP(selection->single()); + } // group-at-point is meant to be topmost item if it's a group, // not topmost group of all items at point if (group_at_point != item_in_group && !(group_at_point && item_at_point && - group_at_point->isAncestorOf(item_at_point))) + group_at_point->isAncestorOf(item_at_point))) { group_at_point = NULL; + } // if neither a group nor an item (possibly in a group) at point are selected, set selection to the item at point if ((!item_in_group || !selection->includes(item_in_group)) && (!group_at_point || !selection->includes(group_at_point)) - && !sc->button_press_alt) { + && !this->button_press_alt) { // select what is under cursor - if (!seltrans->isEmpty()) { - seltrans->resetState(); + if (!_seltrans->isEmpty()) { + _seltrans->resetState(); } + // when simply ctrl-dragging, we don't want to go into groups - if (item_at_point && !selection->includes(item_at_point)) + if (item_at_point && !selection->includes(item_at_point)) { selection->set(item_at_point); + } } // otherwise, do not change selection so that dragging selected-within-group items, as well as alt-dragging, is possible - seltrans->grab(p, -1, -1, FALSE, TRUE); - sc->moved = TRUE; + + _seltrans->grab(p, -1, -1, FALSE, TRUE); + this->moved = TRUE; + } + + if (!_seltrans->isEmpty()) { + _seltrans->moveTo(p, event->button.state); } - if (!seltrans->isEmpty()) - seltrans->moveTo(p, event->button.state); + desktop->scroll_to_point(p); gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; } else { - sc->dragging = FALSE; - sp_event_context_discard_delayed_snap_event(event_context); + this->dragging = FALSE; + sp_event_context_discard_delayed_snap_event(this); desktop->canvas->endForcedFullRedraws(); } } else { if (Inkscape::Rubberband::get(desktop)->is_started()) { Inkscape::Rubberband::get(desktop)->move(p); + if (Inkscape::Rubberband::get(desktop)->getMode() == RUBBERBAND_MODE_TOUCHPATH) { - event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw over</b> objects to select them; release <b>Alt</b> to switch to rubberband selection")); + this->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw over</b> objects to select them; release <b>Alt</b> to switch to rubberband selection")); } else { - event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag around</b> objects to select them; press <b>Alt</b> to switch to touch selection")); + this->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag around</b> objects to select them; press <b>Alt</b> to switch to touch selection")); } + gobble_motion_events(GDK_BUTTON1_MASK); } } @@ -635,55 +654,62 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) } case GDK_BUTTON_RELEASE: xp = yp = 0; - if ((event->button.button == 1) && (sc->grabbed) && !event_context->space_panning) { - if (sc->dragging) { + + if ((event->button.button == 1) && (this->grabbed) && !this->space_panning) { + if (this->dragging) { GdkWindow* window; - if (sc->moved) { + + if (this->moved) { // item has been moved - seltrans->ungrab(); - sc->moved = FALSE; + _seltrans->ungrab(); + this->moved = FALSE; #ifdef WITH_DBUS - dbus_send_ping(desktop, sc->item); + dbus_send_ping(desktop, this->item); #endif - } else if (sc->item && !drag_escaped) { + } else if (this->item && !drag_escaped) { // item has not been moved -> simply a click, do selecting if (!selection->isEmpty()) { if (event->button.state & GDK_SHIFT_MASK) { // with shift, toggle selection - seltrans->resetState(); - selection->toggle(sc->item); + _seltrans->resetState(); + selection->toggle(this->item); } else { SPObject* single = selection->single(); // without shift, increase state (i.e. toggle scale/rotation handles) - if (selection->includes(sc->item)) { - seltrans->increaseState(); - } else if (SP_IS_LAYER(single) && single->isAncestorOf(sc->item)) { - seltrans->increaseState(); + if (selection->includes(this->item)) { + _seltrans->increaseState(); + } else if (SP_IS_LAYER(single) && single->isAncestorOf(this->item)) { + _seltrans->increaseState(); } else { - seltrans->resetState(); - selection->set(sc->item); + _seltrans->resetState(); + selection->set(this->item); } } } else { // simple or shift click, no previous selection - seltrans->resetState(); - selection->set(sc->item); + _seltrans->resetState(); + selection->set(this->item); } } - sc->dragging = FALSE; - window = gtk_widget_get_window (GTK_WIDGET (sp_desktop_canvas(desktop))); + + this->dragging = FALSE; + window = gtk_widget_get_window (GTK_WIDGET (sp_desktop_canvas(desktop))); + gdk_window_set_cursor(window, CursorSelectMouseover); - sp_event_context_discard_delayed_snap_event(event_context); + sp_event_context_discard_delayed_snap_event(this); desktop->canvas->endForcedFullRedraws(); - if (sc->item) { - sp_object_unref( sc->item, NULL); + if (this->item) { + sp_object_unref( this->item, NULL); } - sc->item = NULL; + + this->item = NULL; } else { Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop); + if (r->is_started() && !within_tolerance) { // this was a rubberband drag GSList *items = NULL; + if (r->getMode() == RUBBERBAND_MODE_RECT) { Geom::OptRect const b = r->getRectangle(); items = sp_desktop_document(desktop)->getItemsInBox(desktop->dkey, *b); @@ -691,9 +717,9 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) items = sp_desktop_document(desktop)->getItemsAtPoints(desktop->dkey, r->getPoints()); } - seltrans->resetState(); + _seltrans->resetState(); r->stop(); - SP_EVENT_CONTEXT(sc)->defaultMessageContext()->clear(); + this->defaultMessageContext()->clear(); if (event->button.state & GDK_SHIFT_MASK) { // with shift, add to selection @@ -702,20 +728,20 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) // without shift, simply select anew selection->setList (items); } + g_slist_free (items); } else { // it was just a click, or a too small rubberband r->stop(); - if (sc->button_press_shift && !rb_escaped && !drag_escaped) { - // this was a shift+click or alt+shift+click, select what was clicked upon - sc->button_press_shift = false; + if (this->button_press_shift && !rb_escaped && !drag_escaped) { + // this was a shift+click or alt+shift+click, select what was clicked upon + this->button_press_shift = false; - SPItem *item = NULL; - if (sc->button_press_ctrl) { + if (this->button_press_ctrl) { // go into groups, honoring Alt item = sp_event_context_find_item (desktop, Geom::Point(event->button.x, event->button.y), event->button.state & GDK_MOD1_MASK, TRUE); - sc->button_press_ctrl = FALSE; + this->button_press_ctrl = FALSE; } else { // don't go into groups, honoring Alt item = sp_event_context_find_item (desktop, @@ -727,53 +753,56 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) item = NULL; } - } else if ((sc->button_press_ctrl || sc->button_press_alt) && !rb_escaped && !drag_escaped) { // ctrl+click, alt+click + } else if ((this->button_press_ctrl || this->button_press_alt) && !rb_escaped && !drag_escaped) { // ctrl+click, alt+click + item = sp_event_context_find_item (desktop, + Geom::Point(event->button.x, event->button.y), this->button_press_alt, this->button_press_ctrl); - SPItem *item = sp_event_context_find_item (desktop, - Geom::Point(event->button.x, event->button.y), sc->button_press_alt, sc->button_press_ctrl); - - sc->button_press_ctrl = FALSE; - sc->button_press_alt = FALSE; + this->button_press_ctrl = FALSE; + this->button_press_alt = FALSE; if (item) { if (selection->includes(item)) { - seltrans->increaseState(); + _seltrans->increaseState(); } else { - seltrans->resetState(); + _seltrans->resetState(); selection->set(item); } + item = NULL; } - } else { // click without shift, simply deselect, unless with Alt or something was cancelled if (!selection->isEmpty()) { - if (!(rb_escaped) && !(drag_escaped) && !(event->button.state & GDK_MOD1_MASK)) + if (!(rb_escaped) && !(drag_escaped) && !(event->button.state & GDK_MOD1_MASK)) { selection->clear(); + } + rb_escaped = 0; ret = TRUE; } } } + ret = TRUE; } - if (sc->grabbed) { - sp_canvas_item_ungrab(sc->grabbed, event->button.time); - sc->grabbed = NULL; + + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, event->button.time); + this->grabbed = NULL; } desktop->updateNow(); } + if (event->button.button == 1) { Inkscape::Rubberband::get(desktop)->stop(); // might have been started in another tool! } - sc->button_press_shift = false; - sc->button_press_ctrl = false; - sc->button_press_alt = false; + + this->button_press_shift = false; + this->button_press_ctrl = false; + this->button_press_alt = false; break; - case GDK_SCROLL: - { - SPSelectContext *sc = SP_SELECT_CONTEXT(event_context); + case GDK_SCROLL: { GdkEventScroll *scroll_event = (GdkEventScroll*) event; if (scroll_event->state & GDK_MOD1_MASK) { // alt modified pressed @@ -793,21 +822,22 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) SPItem *item = desktop->getItemAtPoint(p, true, NULL); // Save pointer to current cycle-item so that we can find it again later, in the freshly built list - SPItem *tmp_cur_item = sc->cycling_cur_item ? SP_ITEM(sc->cycling_cur_item->data) : NULL; - g_list_free(sc->cycling_items); - sc->cycling_items = NULL; - sc->cycling_cur_item = NULL; + SPItem *tmp_cur_item = this->cycling_cur_item ? SP_ITEM(this->cycling_cur_item->data) : NULL; + g_list_free(this->cycling_items); + this->cycling_items = NULL; + this->cycling_cur_item = NULL; while(item != NULL) { - sc->cycling_items = g_list_append(sc->cycling_items, item); + this->cycling_items = g_list_append(this->cycling_items, item); item = desktop->getItemAtPoint(p, true, item); } /* Compare current item list with item list during previous scroll ... */ GList *l1, *l2; bool item_lists_differ = false; + // Note that we can do an 'or' comparison in the loop because it is safe to call g_list_next with a NULL pointer. - for (l1 = sc->cycling_items, l2 = sc->cycling_items_cmp; l1 != NULL || l2 != NULL; l1 = g_list_next(l1), l2 = g_list_next(l2)) { + for (l1 = this->cycling_items, l2 = this->cycling_items_cmp; l1 != NULL || l2 != NULL; l1 = g_list_next(l1), l2 = g_list_next(l2)) { if ((l1 !=NULL && l2 == NULL) || (l1 == NULL && l2 != NULL) || (l1->data != l2->data)) { item_lists_differ = true; break; @@ -818,46 +848,52 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) if (!item_lists_differ) { // ... find current item in the freshly built list and continue cycling ... // TODO: This wouldn't be necessary if cycling_cur_item pointed to an element of cycling_items_cmp instead - sc->cycling_cur_item = g_list_find(sc->cycling_items, tmp_cur_item); - g_assert(sc->cycling_cur_item != NULL || sc->cycling_items == NULL); + this->cycling_cur_item = g_list_find(this->cycling_items, tmp_cur_item); + g_assert(this->cycling_cur_item != NULL || this->cycling_items == NULL); } else { // ... otherwise reset opacities for outdated items ... Inkscape::DrawingItem *arenaitem; - for(GList *l = sc->cycling_items_cmp; l != NULL; l = l->next) { + + for(GList *l = this->cycling_items_cmp; l != NULL; l = l->next) { arenaitem = SP_ITEM(l->data)->get_arenaitem(desktop->dkey); arenaitem->setOpacity(1.0); - //if (!shift_pressed && !g_list_find(sc->cycling_items_selected_before, SP_ITEM(l->data)) && selection->includes(SP_ITEM(l->data))) - if (!g_list_find(sc->cycling_items_selected_before, SP_ITEM(l->data)) && selection->includes(SP_ITEM(l->data))) + //if (!shift_pressed && !g_list_find(this->cycling_items_selected_before, SP_ITEM(l->data)) && selection->includes(SP_ITEM(l->data))) + if (!g_list_find(this->cycling_items_selected_before, SP_ITEM(l->data)) && selection->includes(SP_ITEM(l->data))) { selection->remove(SP_ITEM(l->data)); + } } // ... clear the lists ... - g_list_free(sc->cycling_items_cmp); - g_list_free(sc->cycling_items_selected_before); - sc->cycling_items_cmp = NULL; - sc->cycling_items_selected_before = NULL; - sc->cycling_cur_item = NULL; + g_list_free(this->cycling_items_cmp); + g_list_free(this->cycling_items_selected_before); + + this->cycling_items_cmp = NULL; + this->cycling_items_selected_before = NULL; + this->cycling_cur_item = NULL; // ... and rebuild them with the new items. - sc->cycling_items_cmp = g_list_copy(sc->cycling_items); - for(GList *l = sc->cycling_items; l != NULL; l = l->next) { - SPItem *item = SP_ITEM(l->data); + this->cycling_items_cmp = g_list_copy(this->cycling_items); + SPItem *item; + + for(GList *l = this->cycling_items; l != NULL; l = l->next) { + item = SP_ITEM(l->data); arenaitem = item->get_arenaitem(desktop->dkey); arenaitem->setOpacity(0.3); + if (selection->includes(item)) { // already selected items are stored separately, too - sc->cycling_items_selected_before = g_list_append(sc->cycling_items_selected_before, item); + this->cycling_items_selected_before = g_list_append(this->cycling_items_selected_before, item); } } // set the current item to the bottommost one so that the cycling step below re-starts at the top - sc->cycling_cur_item = g_list_last(sc->cycling_items); + this->cycling_cur_item = g_list_last(this->cycling_items); } - sc->cycling_wrap = prefs->getBool("/options/selection/cycleWrap", true); + this->cycling_wrap = prefs->getBool("/options/selection/cycleWrap", true); // Cycle through the items underneath the mouse pointer, one-by-one - sp_select_context_cycle_through_items(sc, selection, scroll_event, shift_pressed); + this->sp_select_context_cycle_through_items(selection, scroll_event, shift_pressed); ret = TRUE; @@ -872,10 +908,10 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) } case GDK_KEY_PRESS: // keybindings for select context - - { - { - guint keyval = get_group0_keyval(&event->key); + { + { + guint keyval = get_group0_keyval(&event->key); + bool alt = ( MOD__ALT(event) || (keyval == GDK_KEY_Alt_L) || (keyval == GDK_KEY_Alt_R) @@ -883,8 +919,8 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) || (keyval == GDK_KEY_Meta_R)); if (!key_is_a_modifier (keyval)) { - event_context->defaultMessageContext()->clear(); - } else if (sc->grabbed || seltrans->isGrabbed()) { + this->defaultMessageContext()->clear(); + } else if (this->grabbed || _seltrans->isGrabbed()) { if (Inkscape::Rubberband::get(desktop)->is_started()) { // if Alt then change cursor to moving cursor: if (alt) { @@ -896,13 +932,15 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) break; } } else { - sp_event_show_modifier_tip (event_context->defaultMessageContext(), event, + sp_event_show_modifier_tip (this->defaultMessageContext(), event, _("<b>Ctrl</b>: click to select in groups; drag to move hor/vert"), _("<b>Shift</b>: click to toggle select; drag for rubberband selection"), _("<b>Alt</b>: click to select under; scroll mouse-wheel to cycle-select; drag to move selected or select by touch")); + // if Alt and nonempty selection, show moving cursor ("move selected"): if (alt && !selection->isEmpty() && !desktop->isWaitingCursor()) { - GdkWindow* window = gtk_widget_get_window (GTK_WIDGET (sp_desktop_canvas(desktop))); + GdkWindow* window = gtk_widget_get_window (GTK_WIDGET (sp_desktop_canvas(desktop))); + gdk_window_set_cursor(window, CursorSelectDragging); } //*/ @@ -918,70 +956,100 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_Left: // move selection left case GDK_KEY_KP_Left: if (!MOD__CTRL(event)) { // not ctrl - gint mul = 1 + gobble_key_events( - get_group0_keyval(&event->key), 0); // with any mask + gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask + if (MOD__ALT(event)) { // alt - if (MOD__SHIFT(event)) sp_selection_move_screen(sp_desktop_selection(desktop), mul*-10, 0); // shift - else sp_selection_move_screen(sp_desktop_selection(desktop), mul*-1, 0); // no shift - } - else { // no alt - if (MOD__SHIFT(event)) sp_selection_move(sp_desktop_selection(desktop), mul*-10*nudge, 0); // shift - else sp_selection_move(sp_desktop_selection(desktop), mul*-nudge, 0); // no shift + if (MOD__SHIFT(event)) { + sp_selection_move_screen(sp_desktop_selection(desktop), mul*-10, 0); // shift + } else { + sp_selection_move_screen(sp_desktop_selection(desktop), mul*-1, 0); // no shift + } + } else { // no alt + if (MOD__SHIFT(event)) { + sp_selection_move(sp_desktop_selection(desktop), mul*-10*nudge, 0); // shift + } else { + sp_selection_move(sp_desktop_selection(desktop), mul*-nudge, 0); // no shift + } } + ret = TRUE; } break; + case GDK_KEY_Up: // move selection up case GDK_KEY_KP_Up: if (!MOD__CTRL(event)) { // not ctrl - gint mul = 1 + gobble_key_events( - get_group0_keyval(&event->key), 0); // with any mask + gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask + if (MOD__ALT(event)) { // alt - if (MOD__SHIFT(event)) sp_selection_move_screen(sp_desktop_selection(desktop), 0, mul*10); // shift - else sp_selection_move_screen(sp_desktop_selection(desktop), 0, mul*1); // no shift - } - else { // no alt - if (MOD__SHIFT(event)) sp_selection_move(sp_desktop_selection(desktop), 0, mul*10*nudge); // shift - else sp_selection_move(sp_desktop_selection(desktop), 0, mul*nudge); // no shift + if (MOD__SHIFT(event)) { + sp_selection_move_screen(sp_desktop_selection(desktop), 0, mul*10); // shift + } else { + sp_selection_move_screen(sp_desktop_selection(desktop), 0, mul*1); // no shift + } + } else { // no alt + if (MOD__SHIFT(event)) { + sp_selection_move(sp_desktop_selection(desktop), 0, mul*10*nudge); // shift + } else { + sp_selection_move(sp_desktop_selection(desktop), 0, mul*nudge); // no shift + } } + ret = TRUE; } break; + case GDK_KEY_Right: // move selection right case GDK_KEY_KP_Right: if (!MOD__CTRL(event)) { // not ctrl - gint mul = 1 + gobble_key_events( - get_group0_keyval(&event->key), 0); // with any mask + gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask + if (MOD__ALT(event)) { // alt - if (MOD__SHIFT(event)) sp_selection_move_screen(sp_desktop_selection(desktop), mul*10, 0); // shift - else sp_selection_move_screen(sp_desktop_selection(desktop), mul*1, 0); // no shift - } - else { // no alt - if (MOD__SHIFT(event)) sp_selection_move(sp_desktop_selection(desktop), mul*10*nudge, 0); // shift - else sp_selection_move(sp_desktop_selection(desktop), mul*nudge, 0); // no shift + if (MOD__SHIFT(event)) { + sp_selection_move_screen(sp_desktop_selection(desktop), mul*10, 0); // shift + } else { + sp_selection_move_screen(sp_desktop_selection(desktop), mul*1, 0); // no shift + } + } else { // no alt + if (MOD__SHIFT(event)) { + sp_selection_move(sp_desktop_selection(desktop), mul*10*nudge, 0); // shift + } else { + sp_selection_move(sp_desktop_selection(desktop), mul*nudge, 0); // no shift + } } + ret = TRUE; } break; + case GDK_KEY_Down: // move selection down case GDK_KEY_KP_Down: if (!MOD__CTRL(event)) { // not ctrl - gint mul = 1 + gobble_key_events( - get_group0_keyval(&event->key), 0); // with any mask + gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask + if (MOD__ALT(event)) { // alt - if (MOD__SHIFT(event)) sp_selection_move_screen(sp_desktop_selection(desktop), 0, mul*-10); // shift - else sp_selection_move_screen(sp_desktop_selection(desktop), 0, mul*-1); // no shift - } - else { // no alt - if (MOD__SHIFT(event)) sp_selection_move(sp_desktop_selection(desktop), 0, mul*-10*nudge); // shift - else sp_selection_move(sp_desktop_selection(desktop), 0, mul*-nudge); // no shift + if (MOD__SHIFT(event)) { + sp_selection_move_screen(sp_desktop_selection(desktop), 0, mul*-10); // shift + } else { + sp_selection_move_screen(sp_desktop_selection(desktop), 0, mul*-1); // no shift + } + } else { // no alt + if (MOD__SHIFT(event)) { + sp_selection_move(sp_desktop_selection(desktop), 0, mul*-10*nudge); // shift + } else { + sp_selection_move(sp_desktop_selection(desktop), 0, mul*-nudge); // no shift + } } + ret = TRUE; } break; + case GDK_KEY_Escape: - if (!sp_select_context_abort(event_context)) + if (!this->sp_select_context_abort()) { selection->clear(); + } + ret = TRUE; break; @@ -992,14 +1060,16 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) ret = TRUE; } break; + case GDK_KEY_space: /* stamping mode: show outline mode moving */ /* FIXME: Is next condition ok? (lauris) */ - if (sc->dragging && sc->grabbed) { - seltrans->stamp(); + if (this->dragging && this->grabbed) { + _seltrans->stamp(); ret = TRUE; } break; + case GDK_KEY_x: case GDK_KEY_X: if (MOD__ALT_ONLY(event)) { @@ -1007,90 +1077,98 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) ret = TRUE; } break; + case GDK_KEY_bracketleft: if (MOD__ALT(event)) { - gint mul = 1 + gobble_key_events( - get_group0_keyval(&event->key), 0); // with any mask + gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask sp_selection_rotate_screen(selection, mul*1); } else if (MOD__CTRL(event)) { sp_selection_rotate(selection, 90); } else if (snaps) { sp_selection_rotate(selection, 180.0/snaps); } + ret = TRUE; break; + case GDK_KEY_bracketright: if (MOD__ALT(event)) { - gint mul = 1 + gobble_key_events( - get_group0_keyval(&event->key), 0); // with any mask + gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask sp_selection_rotate_screen(selection, -1*mul); } else if (MOD__CTRL(event)) { sp_selection_rotate(selection, -90); } else if (snaps) { sp_selection_rotate(selection, -180.0/snaps); } + ret = TRUE; break; + case GDK_KEY_less: case GDK_KEY_comma: if (MOD__ALT(event)) { - gint mul = 1 + gobble_key_events( - get_group0_keyval(&event->key), 0); // with any mask + gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask sp_selection_scale_screen(selection, -2*mul); } else if (MOD__CTRL(event)) { sp_selection_scale_times(selection, 0.5); } else { - gint mul = 1 + gobble_key_events( - get_group0_keyval(&event->key), 0); // with any mask + gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask sp_selection_scale(selection, -offset*mul); } + ret = TRUE; break; + case GDK_KEY_greater: case GDK_KEY_period: if (MOD__ALT(event)) { - gint mul = 1 + gobble_key_events( - get_group0_keyval(&event->key), 0); // with any mask + gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask sp_selection_scale_screen(selection, 2*mul); } else if (MOD__CTRL(event)) { sp_selection_scale_times(selection, 2); } else { - gint mul = 1 + gobble_key_events( - get_group0_keyval(&event->key), 0); // with any mask + gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask sp_selection_scale(selection, offset*mul); } + ret = TRUE; break; + case GDK_KEY_Return: if (MOD__CTRL_ONLY(event)) { if (selection->singleItem()) { SPItem *clicked_item = selection->singleItem(); - if ( SP_IS_GROUP(clicked_item) || - SP_IS_BOX3D(clicked_item)) { // enter group or a 3D box + + if ( SP_IS_GROUP(clicked_item) || SP_IS_BOX3D(clicked_item)) { // enter group or a 3D box desktop->setCurrentLayer(reinterpret_cast<SPObject *>(clicked_item)); sp_desktop_selection(desktop)->clear(); } else { - SP_EVENT_CONTEXT(sc)->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Selected object is not a group. Cannot enter.")); + this->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Selected object is not a group. Cannot enter.")); } } + ret = TRUE; } break; + case GDK_KEY_BackSpace: if (MOD__CTRL_ONLY(event)) { sp_select_context_up_one_layer(desktop); ret = TRUE; } break; + case GDK_KEY_s: case GDK_KEY_S: if (MOD__SHIFT_ONLY(event)) { if (!selection->isEmpty()) { - seltrans->increaseState(); + _seltrans->increaseState(); } + ret = TRUE; } break; + case GDK_KEY_g: case GDK_KEY_G: if (MOD__SHIFT_ONLY(event)) { @@ -1098,17 +1176,18 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) ret = true; } break; + default: break; } break; - } - case GDK_KEY_RELEASE: - { + } + case GDK_KEY_RELEASE: { guint keyval = get_group0_keyval(&event->key); - if (key_is_a_modifier (keyval)) - event_context->defaultMessageContext()->clear(); - + if (key_is_a_modifier (keyval)) { + this->defaultMessageContext()->clear(); + } + bool alt = ( MOD__ALT(event) || (keyval == GDK_KEY_Alt_L) || (keyval == GDK_KEY_Alt_R) @@ -1123,10 +1202,12 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) } else { if (alt) { // TODO: Should we have a variable like is_cycling or is it harmless to run this piece of code each time? // quit cycle-selection and reset opacities - if (is_cycling){ - sp_select_context_reset_opacities(event_context); - is_cycling = false; - } + if (is_cycling) + { + sp_select_context_reset_opacities(this); + is_cycling = false; + } + } } @@ -1138,36 +1219,18 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) //gdk_window_set_cursor(window, event_context->cursor); } break; + default: break; } if (!ret) { - if ((SP_EVENT_CONTEXT_CLASS(sp_select_context_parent_class))->root_handler) - ret = (SP_EVENT_CONTEXT_CLASS(sp_select_context_parent_class))->root_handler(event_context, event); + ret = SPEventContext::root_handler(event); } return ret; } -static void sp_select_context_reset_opacities(SPEventContext *event_context) -{ - // SPDesktop *desktop = event_context->desktop; - SPSelectContext *sc = SP_SELECT_CONTEXT(event_context); - for (GList *l = sc->cycling_items; l != NULL; l = g_list_next(l)) { - Inkscape::DrawingItem *arenaitem = SP_ITEM(l->data)->get_arenaitem(event_context->desktop->dkey); - arenaitem->setOpacity(SP_SCALE24_TO_FLOAT(SP_ITEM(l->data)->style->opacity.value)); - } - g_list_free(sc->cycling_items); - g_list_free(sc->cycling_items_selected_before); - g_list_free(sc->cycling_items_cmp); - sc->cycling_items = NULL; - sc->cycling_items_selected_before = NULL; - sc->cycling_cur_item = NULL; - sc->cycling_items_cmp = NULL; -} - - /* Local Variables: mode:c++ diff --git a/src/select-context.h b/src/select-context.h index a6877f802..bcea8537a 100644 --- a/src/select-context.h +++ b/src/select-context.h @@ -15,11 +15,8 @@ #include "event-context.h" #include <gtk/gtk.h> -#define SP_TYPE_SELECT_CONTEXT (sp_select_context_get_type ()) -#define SP_SELECT_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_SELECT_CONTEXT, SPSelectContext)) -#define SP_SELECT_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_SELECT_CONTEXT, SPSelectContextClass)) -#define SP_IS_SELECT_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_SELECT_CONTEXT)) -#define SP_IS_SELECT_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_SELECT_CONTEXT)) +#define SP_SELECT_CONTEXT(obj) (dynamic_cast<SPSelectContext*>((SPEventContext*)obj)) +#define SP_IS_SELECT_CONTEXT(obj) (dynamic_cast<const SPSelectContext*>((const SPEventContext*)obj) != NULL) struct SPCanvasItem; @@ -29,7 +26,11 @@ namespace Inkscape { class SelectionDescriber; } -struct SPSelectContext : public SPEventContext { +class SPSelectContext : public SPEventContext { +public: + SPSelectContext(); + virtual ~SPSelectContext(); + guint dragging : 1; guint moved : 1; bool button_press_shift; @@ -46,14 +47,19 @@ struct SPSelectContext : public SPEventContext { SPCanvasItem *grabbed; Inkscape::SelTrans *_seltrans; Inkscape::SelectionDescriber *_describer; -}; -struct SPSelectContextClass { - SPEventContextClass parent_class; -}; + static const std::string prefsPath; -/* Standard Gtk function */ + virtual void setup(); + virtual void set(const Inkscape::Preferences::Entry& val); + virtual bool root_handler(GdkEvent* event); + virtual bool item_handler(SPItem* item, GdkEvent* event); -GType sp_select_context_get_type (void); + virtual const std::string& getPrefsPath(); + +private: + bool sp_select_context_abort(); + void sp_select_context_cycle_through_items(Inkscape::Selection *selection, GdkEventScroll *scroll_event, bool shift_pressed); +}; #endif diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 868f5a35c..91b99e3f4 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -70,10 +70,10 @@ SPCycleType SP_CYCLING = SP_CYCLE_FOCUS; #include "document-undo.h" #include "sp-gradient.h" #include "sp-gradient-reference.h" -#include "sp-linear-gradient-fns.h" +#include "sp-linear-gradient.h" #include "sp-pattern.h" #include "sp-symbol.h" -#include "sp-radial-gradient-fns.h" +#include "sp-radial-gradient.h" #include "gradient-context.h" #include "sp-namedview.h" #include "preferences.h" @@ -96,6 +96,7 @@ SPCycleType SP_CYCLING = SP_CYCLE_FOCUS; #include "uri-references.h" #include "display/curve.h" #include "display/canvas-bpath.h" +#include "display/cairo-utils.h" #include "inkscape-private.h" #include "path-chemistry.h" #include "ui/tool/control-point-selection.h" @@ -2873,7 +2874,7 @@ static void sp_selection_to_guides_recursive(SPItem *item, bool deleteitem, bool sp_selection_to_guides_recursive(SP_ITEM(i->data), deleteitem, wholegroups); } } else { - item->convert_item_to_guides(); + item->convert_to_guides(); if (deleteitem) { item->deleteObject(true); @@ -3480,9 +3481,10 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) } // Import the image back - GdkPixbuf *pb = gdk_pixbuf_new_from_file(filepath, NULL); + Inkscape::Pixbuf *pb = Inkscape::Pixbuf::create_from_file(filepath); if (pb) { // Create the repr for the image + // TODO: avoid unnecessary roundtrip between data URI and decoded pixbuf Inkscape::XML::Node * repr = xml_doc->createElement("svg:image"); sp_embed_image(repr, pb); if (res == Inkscape::Util::Quantity::convert(1, "in", "px")) { // for default 90 dpi, snap it to pixel grid diff --git a/src/selection-describer.cpp b/src/selection-describer.cpp index b5704bb76..4c2229667 100644 --- a/src/selection-describer.cpp +++ b/src/selection-describer.cpp @@ -38,51 +38,53 @@ #include "sp-polyline.h" #include "sp-spiral.h" +// CPPIFY: this is ugly. static const gchar * type2term(SPItem *item) { - GType type = G_OBJECT_TYPE( item ); - if (type == SP_TYPE_ANCHOR) - //TRANSLATORS: "Link" means internet link (anchor) - { return C_("Web", "Link"); } - if (type == SP_TYPE_CIRCLE) - { return _("Circle"); } - if (type == SP_TYPE_ELLIPSE) - { return _("Ellipse"); } - if (type == SP_TYPE_FLOWTEXT) - { return _("Flowed text"); } - if (type == SP_TYPE_GROUP) - { return _("Group"); } - if (type == SP_TYPE_IMAGE) - { return _("Image"); } - if (type == SP_TYPE_LINE) - { return _("Line"); } - if (type == SP_TYPE_PATH) - { return _("Path"); } - if (type == SP_TYPE_POLYGON) - { return _("Polygon"); } - if (type == SP_TYPE_POLYLINE) - { return _("Polyline"); } - if (type == SP_TYPE_RECT) - { return _("Rectangle"); } - if (type == SP_TYPE_BOX3D) - { return _("3D Box"); } - if (type == SP_TYPE_TEXT) - { return C_("Object", "Text"); } - if (type == SP_TYPE_USE) - if (SP_IS_SYMBOL(item->firstChild())) - { return C_("Object", "Symbol"); } - // TRANSLATORS: "Clone" is a noun, type of object - { return C_("Object", "Clone"); } - if (type == SP_TYPE_ARC) - { return _("Ellipse"); } - if (type == SP_TYPE_OFFSET) - { return _("Offset path"); } - if (type == SP_TYPE_SPIRAL) - { return _("Spiral"); } - if (type == SP_TYPE_STAR) - { return _("Star"); } - return NULL; +// GType type = G_OBJECT_TYPE( item ); +// if (type == SP_TYPE_ANCHOR) +// //TRANSLATORS: "Link" means internet link (anchor) +// { return C_("Web", "Link"); } +// if (type == SP_TYPE_CIRCLE) +// { return _("Circle"); } +// if (type == SP_TYPE_ELLIPSE) +// { return _("Ellipse"); } +// if (type == SP_TYPE_FLOWTEXT) +// { return _("Flowed text"); } +// if (type == SP_TYPE_GROUP) +// { return _("Group"); } +// if (type == SP_TYPE_IMAGE) +// { return _("Image"); } +// if (type == SP_TYPE_LINE) +// { return _("Line"); } +// if (type == SP_TYPE_PATH) +// { return _("Path"); } +// if (type == SP_TYPE_POLYGON) +// { return _("Polygon"); } +// if (type == SP_TYPE_POLYLINE) +// { return _("Polyline"); } +// if (type == SP_TYPE_RECT) +// { return _("Rectangle"); } +// if (type == SP_TYPE_BOX3D) +// { return _("3D Box"); } +// if (type == SP_TYPE_TEXT) +// { return C_("Object", "Text"); } +// if (type == SP_TYPE_USE) +// if (SP_IS_SYMBOL(item->firstChild())) +// { return C_("Object", "Symbol"); } +// // TRANSLATORS: "Clone" is a noun, type of object +// { return C_("Object", "Clone"); } +// if (type == SP_TYPE_ARC) +// { return _("Ellipse"); } +// if (type == SP_TYPE_OFFSET) +// { return _("Offset path"); } +// if (type == SP_TYPE_SPIRAL) +// { return _("Spiral"); } +// if (type == SP_TYPE_STAR) +// { return _("Star"); } +// return NULL; + return "Selektion-Describer ---"; } static GSList *collect_terms (GSList *items) diff --git a/src/selection.h b/src/selection.h index 32eade21f..394ab64ff 100644 --- a/src/selection.h +++ b/src/selection.h @@ -31,7 +31,7 @@ class SPDesktop; class SPItem; class SPBox3D; -struct Persp3D; +class Persp3D; namespace Inkscape { class LayerModel; diff --git a/src/snap.h b/src/snap.h index 6a87d95cc..67af20063 100644 --- a/src/snap.h +++ b/src/snap.h @@ -31,7 +31,7 @@ enum SPGuideDragType { // used both here and in desktop-events.cpp }; class SPGuide; -struct SPNamedView; +class SPNamedView; /** * Class to coordinate snapping operations. diff --git a/src/sp-anchor.cpp b/src/sp-anchor.cpp index 8b52cf400..d9a8c4142 100644 --- a/src/sp-anchor.cpp +++ b/src/sp-anchor.cpp @@ -25,75 +25,53 @@ #include "ui/view/view.h" #include "document.h" -static void sp_anchor_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_anchor_release(SPObject *object); -static void sp_anchor_set(SPObject *object, unsigned int key, const gchar *value); -static Inkscape::XML::Node *sp_anchor_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); +#include "sp-factory.h" -static gchar *sp_anchor_description(SPItem *item); -static gint sp_anchor_event(SPItem *item, SPEvent *event); +namespace { + SPObject* createAnchor() { + return new SPAnchor(); + } -G_DEFINE_TYPE(SPAnchor, sp_anchor, SP_TYPE_GROUP); - -static void sp_anchor_class_init(SPAnchorClass *ac) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) ac; - SPItemClass *item_class = (SPItemClass *) ac; - - sp_object_class->build = sp_anchor_build; - sp_object_class->release = sp_anchor_release; - sp_object_class->set = sp_anchor_set; - sp_object_class->write = sp_anchor_write; - - item_class->description = sp_anchor_description; - item_class->event = sp_anchor_event; + bool anchorRegistered = SPFactory::instance().registerObject("svg:a", createAnchor); } -static void sp_anchor_init(SPAnchor *anchor) -{ - anchor->href = NULL; +SPAnchor::SPAnchor() : SPGroup() { + this->href = NULL; } -static void sp_anchor_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) (sp_anchor_parent_class))->build) { - ((SPObjectClass *) (sp_anchor_parent_class))->build(object, document, repr); - } - - object->readAttr( "xlink:type" ); - object->readAttr( "xlink:role" ); - object->readAttr( "xlink:arcrole" ); - object->readAttr( "xlink:title" ); - object->readAttr( "xlink:show" ); - object->readAttr( "xlink:actuate" ); - object->readAttr( "xlink:href" ); - object->readAttr( "target" ); +SPAnchor::~SPAnchor() { } -static void sp_anchor_release(SPObject *object) -{ - SPAnchor *anchor = SP_ANCHOR(object); +void SPAnchor::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPGroup::build(document, repr); + + this->readAttr( "xlink:type" ); + this->readAttr( "xlink:role" ); + this->readAttr( "xlink:arcrole" ); + this->readAttr( "xlink:title" ); + this->readAttr( "xlink:show" ); + this->readAttr( "xlink:actuate" ); + this->readAttr( "xlink:href" ); + this->readAttr( "target" ); +} - if (anchor->href) { - g_free(anchor->href); - anchor->href = NULL; +void SPAnchor::release() { + if (this->href) { + g_free(this->href); + this->href = NULL; } - if (((SPObjectClass *) sp_anchor_parent_class)->release) { - ((SPObjectClass *) sp_anchor_parent_class)->release(object); - } + SPGroup::release(); } -static void sp_anchor_set(SPObject *object, unsigned int key, const gchar *value) -{ - SPAnchor *anchor = SP_ANCHOR(object); - +void SPAnchor::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_XLINK_HREF: - g_free(anchor->href); - anchor->href = g_strdup(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + g_free(this->href); + this->href = g_strdup(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_XLINK_TYPE: case SP_ATTR_XLINK_ROLE: case SP_ATTR_XLINK_ARCROLE: @@ -101,12 +79,11 @@ static void sp_anchor_set(SPObject *object, unsigned int key, const gchar *value case SP_ATTR_XLINK_SHOW: case SP_ATTR_XLINK_ACTUATE: case SP_ATTR_TARGET: - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; + default: - if (((SPObjectClass *) (sp_anchor_parent_class))->set) { - ((SPObjectClass *) (sp_anchor_parent_class))->set(object, key, value); - } + SPGroup::set(key, value); break; } } @@ -114,40 +91,33 @@ static void sp_anchor_set(SPObject *object, unsigned int key, const gchar *value #define COPY_ATTR(rd,rs,key) (rd)->setAttribute((key), rs->attribute(key)); -static Inkscape::XML::Node *sp_anchor_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPAnchor *anchor = SP_ANCHOR(object); - +Inkscape::XML::Node* SPAnchor::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:a"); } - repr->setAttribute("xlink:href", anchor->href); + repr->setAttribute("xlink:href", this->href); - if (repr != object->getRepr()) { + if (repr != this->getRepr()) { // XML Tree being directly used while it shouldn't be in the // below COPY_ATTR lines - COPY_ATTR(repr, object->getRepr(), "xlink:type"); - COPY_ATTR(repr, object->getRepr(), "xlink:role"); - COPY_ATTR(repr, object->getRepr(), "xlink:arcrole"); - COPY_ATTR(repr, object->getRepr(), "xlink:title"); - COPY_ATTR(repr, object->getRepr(), "xlink:show"); - COPY_ATTR(repr, object->getRepr(), "xlink:actuate"); - COPY_ATTR(repr, object->getRepr(), "target"); + COPY_ATTR(repr, this->getRepr(), "xlink:type"); + COPY_ATTR(repr, this->getRepr(), "xlink:role"); + COPY_ATTR(repr, this->getRepr(), "xlink:arcrole"); + COPY_ATTR(repr, this->getRepr(), "xlink:title"); + COPY_ATTR(repr, this->getRepr(), "xlink:show"); + COPY_ATTR(repr, this->getRepr(), "xlink:actuate"); + COPY_ATTR(repr, this->getRepr(), "target"); } - if (((SPObjectClass *) (sp_anchor_parent_class))->write) { - ((SPObjectClass *) (sp_anchor_parent_class))->write(object, xml_doc, repr, flags); - } + SPGroup::write(xml_doc, repr, flags); return repr; } -static gchar *sp_anchor_description(SPItem *item) -{ - SPAnchor *anchor = SP_ANCHOR(item); - if (anchor->href) { - char *quoted_href = xml_quote_strdup(anchor->href); +gchar* SPAnchor::description() { + if (this->href) { + char *quoted_href = xml_quote_strdup(this->href); char *ret = g_strdup_printf(_("<b>Link</b> to %s"), quoted_href); g_free(quoted_href); return ret; @@ -157,24 +127,23 @@ static gchar *sp_anchor_description(SPItem *item) } /* fixme: We should forward event to appropriate container/view */ - -static gint sp_anchor_event(SPItem *item, SPEvent *event) -{ - SPAnchor *anchor = SP_ANCHOR(item); - +gint SPAnchor::event(SPEvent* event) { switch (event->type) { case SP_EVENT_ACTIVATE: - if (anchor->href) { - g_print("Activated xlink:href=\"%s\"\n", anchor->href); + if (this->href) { + g_print("Activated xlink:href=\"%s\"\n", this->href); return TRUE; } break; + case SP_EVENT_MOUSEOVER: (static_cast<Inkscape::UI::View::View*>(event->data))->mouseover(); break; + case SP_EVENT_MOUSEOUT: (static_cast<Inkscape::UI::View::View*>(event->data))->mouseout(); break; + default: break; } diff --git a/src/sp-anchor.h b/src/sp-anchor.h index 3c6481d94..cada9665e 100644 --- a/src/sp-anchor.h +++ b/src/sp-anchor.h @@ -15,20 +15,23 @@ #include "sp-item-group.h" -#define SP_TYPE_ANCHOR (sp_anchor_get_type ()) -#define SP_ANCHOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_ANCHOR, SPAnchor)) -#define SP_ANCHOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_ANCHOR, SPAnchorClass)) -#define SP_IS_ANCHOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_ANCHOR)) -#define SP_IS_ANCHOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_ANCHOR)) +#define SP_ANCHOR(obj) (dynamic_cast<SPAnchor*>((SPObject*)obj)) +#define SP_IS_ANCHOR(obj) (dynamic_cast<const SPAnchor*>((SPObject*)obj) != NULL) + +class SPAnchor : public SPGroup { +public: + SPAnchor(); + virtual ~SPAnchor(); -struct SPAnchor : public SPGroup { gchar *href; -}; -struct SPAnchorClass { - SPGroupClass parent_class; -}; + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void release(); + virtual void set(unsigned int key, gchar const* value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); -GType sp_anchor_get_type (void); + virtual gchar* description(); + virtual gint event(SPEvent *event); +}; #endif diff --git a/src/sp-clippath.cpp b/src/sp-clippath.cpp index 059cbcf2b..8e2e7d7a6 100644 --- a/src/sp-clippath.cpp +++ b/src/sp-clippath.cpp @@ -37,119 +37,92 @@ struct SPClipPathView { Geom::OptRect bbox; }; -static void sp_clippath_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_clippath_release(SPObject * object); -static void sp_clippath_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_clippath_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref); -static void sp_clippath_update(SPObject *object, SPCtx *ctx, guint flags); -static void sp_clippath_modified(SPObject *object, guint flags); -static Inkscape::XML::Node* sp_clippath_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); static SPClipPathView* sp_clippath_view_new_prepend(SPClipPathView *list, unsigned int key, Inkscape::DrawingItem *arenaitem); static SPClipPathView* sp_clippath_view_list_remove(SPClipPathView *list, SPClipPathView *view); -G_DEFINE_TYPE(SPClipPath, sp_clippath, SP_TYPE_OBJECTGROUP); +#include "sp-factory.h" -static void -sp_clippath_class_init(SPClipPathClass *klass) -{ - SPObjectClass *sp_object_class = SP_OBJECT_CLASS(klass); - - sp_object_class->build = sp_clippath_build; - sp_object_class->release = sp_clippath_release; - sp_object_class->set = sp_clippath_set; - sp_object_class->child_added = sp_clippath_child_added; - sp_object_class->update = sp_clippath_update; - sp_object_class->modified = sp_clippath_modified; - sp_object_class->write = sp_clippath_write; +namespace { + SPObject* createClipPath() { + return new SPClipPath(); + } + + bool clipPathRegistered = SPFactory::instance().registerObject("svg:clipPath", createClipPath); } -static void -sp_clippath_init(SPClipPath *cp) -{ - cp->clipPathUnits_set = FALSE; - cp->clipPathUnits = SP_CONTENT_UNITS_USERSPACEONUSE; +SPClipPath::SPClipPath() : SPObjectGroup() { + this->clipPathUnits_set = FALSE; + this->clipPathUnits = SP_CONTENT_UNITS_USERSPACEONUSE; - cp->display = NULL; + this->display = NULL; } -static void -sp_clippath_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_clippath_parent_class)->build) - ((SPObjectClass *) sp_clippath_parent_class)->build(object, document, repr); +SPClipPath::~SPClipPath() { +} - object->readAttr( "style" ); - object->readAttr( "clipPathUnits" ); +void SPClipPath::build(SPDocument* doc, Inkscape::XML::Node* repr) { + SPObjectGroup::build(doc, repr); + + this->readAttr( "style" ); + this->readAttr( "clipPathUnits" ); /* Register ourselves */ - document->addResource("clipPath", object); + doc->addResource("clipPath", this); } -static void -sp_clippath_release(SPObject * object) -{ - if (object->document) { +void SPClipPath::release() { + if (this->document) { // Unregister ourselves - object->document->removeResource("clipPath", object); + this->document->removeResource("clipPath", this); } - SPClipPath *cp = SP_CLIPPATH(object); - while (cp->display) { + while (this->display) { /* We simply unref and let item manage this in handler */ - cp->display = sp_clippath_view_list_remove(cp->display, cp->display); + this->display = sp_clippath_view_list_remove(this->display, this->display); } - if (((SPObjectClass *) (sp_clippath_parent_class))->release) { - ((SPObjectClass *) sp_clippath_parent_class)->release(object); - } + SPObjectGroup::release(); } -static void -sp_clippath_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPClipPath *cp = SP_CLIPPATH(object); - +void SPClipPath::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_CLIPPATHUNITS: - cp->clipPathUnits = SP_CONTENT_UNITS_USERSPACEONUSE; - cp->clipPathUnits_set = FALSE; + this->clipPathUnits = SP_CONTENT_UNITS_USERSPACEONUSE; + this->clipPathUnits_set = FALSE; + if (value) { if (!strcmp(value, "userSpaceOnUse")) { - cp->clipPathUnits_set = TRUE; + this->clipPathUnits_set = TRUE; } else if (!strcmp(value, "objectBoundingBox")) { - cp->clipPathUnits = SP_CONTENT_UNITS_OBJECTBOUNDINGBOX; - cp->clipPathUnits_set = TRUE; + this->clipPathUnits = SP_CONTENT_UNITS_OBJECTBOUNDINGBOX; + this->clipPathUnits_set = TRUE; } } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; default: if (SP_ATTRIBUTE_IS_CSS(key)) { - sp_style_read_from_object(object->style, object); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + sp_style_read_from_object(this->style, this); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); } else { - if (((SPObjectClass *) sp_clippath_parent_class)->set) { - ((SPObjectClass *) sp_clippath_parent_class)->set(object, key, value); - } + SPObjectGroup::set(key, value); } break; } } -static void -sp_clippath_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) -{ +void SPClipPath::child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref) { /* Invoke SPObjectGroup implementation */ - ((SPObjectClass *) (sp_clippath_parent_class))->child_added(object, child, ref); + SPObjectGroup::child_added(child, ref); /* Show new object */ - SPObject *ochild = object->document->getObjectByRepr(child); + SPObject *ochild = this->document->getObjectByRepr(child); + if (SP_IS_ITEM(ochild)) { - SPClipPath *cp = SP_CLIPPATH(object); - for (SPClipPathView *v = cp->display; v != NULL; v = v->next) { - Inkscape::DrawingItem *ac = SP_ITEM(ochild)->invoke_show( v->arenaitem->drawing(), - v->key, - SP_ITEM_REFERENCE_FLAGS); + for (SPClipPathView *v = this->display; v != NULL; v = v->next) { + Inkscape::DrawingItem *ac = SP_ITEM(ochild)->invoke_show(v->arenaitem->drawing(), v->key, SP_ITEM_REFERENCE_FLAGS); + if (ac) { v->arenaitem->prependChild(ac); } @@ -157,35 +130,36 @@ sp_clippath_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape:: } } -static void -sp_clippath_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPClipPath::update(SPCtx* ctx, unsigned int flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } flags &= SP_OBJECT_MODIFIED_CASCADE; - SPObjectGroup *og = SP_OBJECTGROUP(object); GSList *l = NULL; - for ( SPObject *child = og->firstChild(); child; child = child->getNext()) { - g_object_ref(G_OBJECT(child)); + for ( SPObject *child = this->firstChild(); child; child = child->getNext()) { + sp_object_ref(child); l = g_slist_prepend(l, child); } + l = g_slist_reverse(l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->updateDisplay(ctx, flags); } - g_object_unref(G_OBJECT(child)); + + sp_object_unref(child); } - SPClipPath *cp = SP_CLIPPATH(object); - for (SPClipPathView *v = cp->display; v != NULL; v = v->next) { + for (SPClipPathView *v = this->display; v != NULL; v = v->next) { Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); - if (cp->clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX && v->bbox) { + + if (this->clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX && v->bbox) { Geom::Affine t = Geom::Scale(v->bbox->dimensions()); t.setTranslation(v->bbox->min()); g->setChildTransform(t); @@ -195,54 +169,51 @@ sp_clippath_update(SPObject *object, SPCtx *ctx, guint flags) } } -static void -sp_clippath_modified(SPObject *object, guint flags) -{ +void SPClipPath::modified(unsigned int flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } flags &= SP_OBJECT_MODIFIED_CASCADE; - SPObjectGroup *og = SP_OBJECTGROUP(object); GSList *l = NULL; - for (SPObject *child = og->firstChild(); child; child = child->getNext()) { - g_object_ref(G_OBJECT(child)); + for (SPObject *child = this->firstChild(); child; child = child->getNext()) { + sp_object_ref(child); l = g_slist_prepend(l, child); } + l = g_slist_reverse(l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->emitModified(flags); } - g_object_unref(G_OBJECT(child)); + + sp_object_unref(child); } } -static Inkscape::XML::Node* -sp_clippath_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPClipPath::write(Inkscape::XML::Document* xml_doc, Inkscape::XML::Node* repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:clipPath"); } - if (((SPObjectClass *) (sp_clippath_parent_class))->write) { - ((SPObjectClass *) (sp_clippath_parent_class))->write(object, xml_doc, repr, flags); - } + SPObjectGroup::write(xml_doc, repr, flags); return repr; } -Inkscape::DrawingItem *SPClipPath::show(Inkscape::Drawing &drawing, unsigned int key) -{ +Inkscape::DrawingItem *SPClipPath::show(Inkscape::Drawing &drawing, unsigned int key) { Inkscape::DrawingGroup *ai = new Inkscape::DrawingGroup(drawing); display = sp_clippath_view_new_prepend(display, key, ai); for ( SPObject *child = firstChild() ; child ; child = child->getNext() ) { if (SP_IS_ITEM(child)) { Inkscape::DrawingItem *ac = SP_ITEM(child)->invoke_show(drawing, key, SP_ITEM_REFERENCE_FLAGS); + if (ac) { /* The order is not important in clippath */ ai->appendChild(ac); @@ -255,13 +226,13 @@ Inkscape::DrawingItem *SPClipPath::show(Inkscape::Drawing &drawing, unsigned int t.setTranslation(display->bbox->min()); ai->setChildTransform(t); } + ai->setStyle(this->style); return ai; } -void SPClipPath::hide(unsigned int key) -{ +void SPClipPath::hide(unsigned int key) { for ( SPObject *child = firstChild() ; child; child = child->getNext() ) { if (SP_IS_ITEM(child)) { SP_ITEM(child)->invoke_hide(key); @@ -279,8 +250,7 @@ void SPClipPath::hide(unsigned int key) g_assert_not_reached(); } -void SPClipPath::setBBox(unsigned int key, Geom::OptRect const &bbox) -{ +void SPClipPath::setBBox(unsigned int key, Geom::OptRect const &bbox) { for (SPClipPathView *v = display; v != NULL; v = v->next) { if (v->key == key) { v->bbox = bbox; @@ -289,15 +259,16 @@ void SPClipPath::setBBox(unsigned int key, Geom::OptRect const &bbox) } } -Geom::OptRect SPClipPath::geometricBounds(Geom::Affine const &transform) -{ - SPObject *i = 0; +Geom::OptRect SPClipPath::geometricBounds(Geom::Affine const &transform) { Geom::OptRect bbox; - for (i = firstChild(); i; i = i->getNext()) { - if (!SP_IS_ITEM(i)) continue; - Geom::OptRect tmp = SP_ITEM(i)->geometricBounds(Geom::Affine(SP_ITEM(i)->transform) * transform); - bbox.unionWith(tmp); + + for (SPObject *i = firstChild(); i; i = i->getNext()) { + if (SP_IS_ITEM(i)) { + Geom::OptRect tmp = SP_ITEM(i)->geometricBounds(Geom::Affine(SP_ITEM(i)->transform) * transform); + bbox.unionWith(tmp); + } } + return bbox; } diff --git a/src/sp-clippath.h b/src/sp-clippath.h index 17546c6d3..ba7a90a57 100644 --- a/src/sp-clippath.h +++ b/src/sp-clippath.h @@ -15,11 +15,8 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#define SP_TYPE_CLIPPATH (sp_clippath_get_type()) -#define SP_CLIPPATH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_CLIPPATH, SPClipPath)) -#define SP_CLIPPATH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_CLIPPATH, SPClipPathClass)) -#define SP_IS_CLIPPATH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_CLIPPATH)) -#define SP_IS_CLIPPATH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_CLIPPATH)) +#define SP_CLIPPATH(obj) (dynamic_cast<SPClipPath*>((SPObject*)obj)) +#define SP_IS_CLIPPATH(obj) (dynamic_cast<const SPClipPath*>((SPObject*)obj) != NULL) struct SPClipPathView; @@ -27,8 +24,6 @@ struct SPClipPathView; #include "uri-references.h" #include "xml/node.h" -GType sp_clippath_get_type() G_GNUC_CONST; - namespace Inkscape { class Drawing; @@ -38,6 +33,9 @@ class DrawingItem; class SPClipPath : public SPObjectGroup { public: + SPClipPath(); + virtual ~SPClipPath(); + class Reference; unsigned int clipPathUnits_set : 1; @@ -53,18 +51,21 @@ public: void setBBox(unsigned int key, Geom::OptRect const &bbox); Geom::OptRect geometricBounds(Geom::Affine const &transform); -private: - friend class SPClipPathClass; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); -class SPClipPathClass { -public: - SPObjectGroupClass parent_class; + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + + virtual void set(unsigned int key, const gchar* value); -private: - friend class SPClipPath; + virtual void update(SPCtx* ctx, unsigned int flags); + virtual void modified(unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); }; + class SPClipPathReference : public Inkscape::URIReference { public: SPClipPathReference(SPObject *obj) : URIReference(obj) {} diff --git a/src/sp-conn-end-pair.cpp b/src/sp-conn-end-pair.cpp index 8e89b28fb..52a421550 100644 --- a/src/sp-conn-end-pair.cpp +++ b/src/sp-conn-end-pair.cpp @@ -192,7 +192,7 @@ SPConnEndPair::getAttachedItems(SPItem *h2attItem[2]) const { // selected through the XML editor, it makes sense just to detach // connectors from them. if (SP_IS_GROUP(h2attItem[h])) { - if (SP_GROUP(h2attItem[h])->group->getItemCount() == 0) { + if (SP_GROUP(h2attItem[h])->getItemCount() == 0) { // This group is empty, so detach. sp_conn_end_detach(_path, h); h2attItem[h] = NULL; diff --git a/src/sp-defs.cpp b/src/sp-defs.cpp index f7a906163..334570076 100644 --- a/src/sp-defs.cpp +++ b/src/sp-defs.cpp @@ -20,66 +20,45 @@ #include "xml/repr.h" #include "document.h" -static void sp_defs_release (SPObject *object); -static void sp_defs_update (SPObject *object, - SPCtx *ctx, - guint flags); -static void sp_defs_modified(SPObject *object, - guint flags); -static Inkscape::XML::Node* sp_defs_write (SPObject *object, - Inkscape::XML::Document *doc, - Inkscape::XML::Node *repr, - guint flags); - -G_DEFINE_TYPE(SPDefs, sp_defs, SP_TYPE_OBJECT); - -static void -sp_defs_class_init(SPDefsClass *dc) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) dc; - - sp_object_class->release = sp_defs_release; - sp_object_class->update = sp_defs_update; - sp_object_class->modified = sp_defs_modified; - sp_object_class->write = sp_defs_write; +#include "sp-factory.h" + +namespace { + SPObject* createDefs() { + return new SPDefs(); + } + + bool defsRegistered = SPFactory::instance().registerObject("svg:defs", createDefs); } -static void -sp_defs_init(SPDefs * /*defs*/) -{ +SPDefs::SPDefs() : SPObject() { } -static void -sp_defs_release(SPObject *object) -{ - if (((SPObjectClass *) (sp_defs_parent_class))->release) { - ((SPObjectClass *) (sp_defs_parent_class))->release(object); - } +SPDefs::~SPDefs() { } -static void -sp_defs_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPDefs::release() { + SPObject::release(); +} + +void SPDefs::update(SPCtx *ctx, guint flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } flags &= SP_OBJECT_MODIFIED_CASCADE; - GSList *l = g_slist_reverse(object->childList(true)); + GSList *l = g_slist_reverse(this->childList(true)); while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->updateDisplay(ctx, flags); } - g_object_unref (G_OBJECT (child)); + sp_object_unref(child); } } -static void -sp_defs_modified(SPObject *object, guint flags) -{ +void SPDefs::modified(unsigned int flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } @@ -87,8 +66,8 @@ sp_defs_modified(SPObject *object, guint flags) flags &= SP_OBJECT_MODIFIED_CASCADE; GSList *l = NULL; - for ( SPObject *child = object->firstChild() ; child; child = child->getNext() ) { - g_object_ref(G_OBJECT(child)); + for ( SPObject *child = this->firstChild() ; child; child = child->getNext() ) { + sp_object_ref(child); l = g_slist_prepend(l, child); } @@ -100,13 +79,11 @@ sp_defs_modified(SPObject *object, guint flags) if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->emitModified(flags); } - g_object_unref( G_OBJECT(child) ); + sp_object_unref(child); } } -static Inkscape::XML::Node* -sp_defs_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPDefs::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if (flags & SP_OBJECT_WRITE_BUILD) { if (!repr) { @@ -114,7 +91,7 @@ sp_defs_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML: } GSList *l = NULL; - for ( SPObject *child = object->firstChild() ; child; child = child->getNext() ) { + for ( SPObject *child = this->firstChild() ; child; child = child->getNext() ) { Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags); if (crepr) { l = g_slist_prepend(l, crepr); @@ -128,14 +105,12 @@ sp_defs_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML: } } else { - for ( SPObject *child = object->firstChild() ; child; child = child->getNext() ) { + for ( SPObject *child = this->firstChild() ; child; child = child->getNext() ) { child->updateRepr(flags); } } - if (((SPObjectClass *) (sp_defs_parent_class))->write) { - (* ((SPObjectClass *) (sp_defs_parent_class))->write)(object, xml_doc, repr, flags); - } + SPObject::write(xml_doc, repr, flags); return repr; } diff --git a/src/sp-defs.h b/src/sp-defs.h index e1d343979..6efdea1f3 100644 --- a/src/sp-defs.h +++ b/src/sp-defs.h @@ -15,28 +15,21 @@ #include "sp-object.h" -#define SP_TYPE_DEFS (sp_defs_get_type()) -#define SP_DEFS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_DEFS, SPDefs)) -#define SP_DEFS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_DEFS, SPDefsClass)) -#define SP_IS_DEFS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_DEFS)) -#define SP_IS_DEFS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_DEFS)) - -GType sp_defs_get_type(void) G_GNUC_CONST; +#define SP_DEFS(obj) (dynamic_cast<SPDefs*>((SPObject*)obj)) +#define SP_IS_DEFS(obj) (dynamic_cast<const SPDefs*>((SPObject*)obj) != NULL) class SPDefs : public SPObject { -private: - friend class SPDefsClass; -}; - -class SPDefsClass { public: - SPObjectClass parent_class; - -private: - friend class SPDefs; + SPDefs(); + virtual ~SPDefs(); + +protected: + virtual void release(); + virtual void update(SPCtx* ctx, unsigned int flags); + virtual void modified(unsigned int flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); }; - #endif // !SEEN_SP_DEFS_H /* diff --git a/src/sp-desc.cpp b/src/sp-desc.cpp index aec90714d..199ae0176 100644 --- a/src/sp-desc.cpp +++ b/src/sp-desc.cpp @@ -16,33 +16,31 @@ #include "sp-desc.h" #include "xml/repr.h" -static Inkscape::XML::Node *sp_desc_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); +#include "sp-factory.h" -G_DEFINE_TYPE(SPDesc, sp_desc, SP_TYPE_OBJECT); +namespace { + SPObject* createDesc() { + return new SPDesc(); + } -static void sp_desc_class_init(SPDescClass *klass) -{ - SPObjectClass *sp_object_class = reinterpret_cast<SPObjectClass *>(klass); + bool descRegistered = SPFactory::instance().registerObject("svg:desc", createDesc); +} - sp_object_class->write = sp_desc_write; +SPDesc::SPDesc() : SPObject() { } -static void sp_desc_init(SPDesc */*desc*/) -{ +SPDesc::~SPDesc() { } /** * Writes it's settings to an incoming repr object, if any. */ -static Inkscape::XML::Node *sp_desc_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPDesc::write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) { if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } - if ((static_cast<SPObjectClass *>(sp_desc_parent_class))->write) { - (static_cast<SPObjectClass *>(sp_desc_parent_class))->write(object, doc, repr, flags); - } + SPObject::write(doc, repr, flags); return repr; } diff --git a/src/sp-desc.h b/src/sp-desc.h index 41ef08020..2bb42b333 100644 --- a/src/sp-desc.h +++ b/src/sp-desc.h @@ -14,16 +14,16 @@ #include "sp-object.h" -#define SP_TYPE_DESC (sp_desc_get_type ()) -#define SP_IS_DESC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_DESC)) +#define SP_DESC(obj) (dynamic_cast<SPDesc*>((SPObject*)obj)) +#define SP_IS_DESC(obj) (dynamic_cast<const SPDesc*>((SPObject*)obj) != NULL) -struct SPDesc : public SPObject { -}; +class SPDesc : public SPObject { +public: + SPDesc(); + virtual ~SPDesc(); -struct SPDescClass { - SPObjectClass parent_class; +protected: + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); }; -GType sp_desc_get_type (void); - #endif diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp index bf019fb13..7c6066054 100644 --- a/src/sp-ellipse.cpp +++ b/src/sp-ellipse.cpp @@ -35,6 +35,28 @@ #define noELLIPSE_VERBOSE + +#include "sp-factory.h" + +namespace { + SPObject* createEllipse() { + return new SPEllipse(); + } + + SPObject* createCircle() { + return new SPCircle(); + } + + SPObject* createArc() { + return new SPArc(); + } + + bool ellipseRegistered = SPFactory::instance().registerObject("svg:ellipse", createEllipse); + bool circleRegistered = SPFactory::instance().registerObject("svg:circle", createCircle); + bool arcRegistered = SPFactory::instance().registerObject("arc", createArc); +} + + #ifndef M_PI #define M_PI 3.14159265358979323846 #endif @@ -64,83 +86,51 @@ static double sp_round(double x, double y) } #endif -static void sp_genericellipse_update(SPObject *object, SPCtx *ctx, guint flags); - -static void sp_genericellipse_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); - -static void sp_genericellipse_set_shape(SPShape *shape); -static void sp_genericellipse_update_patheffect (SPLPEItem *lpeitem, bool write); - -static Inkscape::XML::Node *sp_genericellipse_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, - guint flags); - static gboolean sp_arc_set_elliptical_path_attribute(SPArc *arc, Inkscape::XML::Node *repr); -G_DEFINE_TYPE(SPGenericEllipse, sp_genericellipse, SP_TYPE_SHAPE); - -static void sp_genericellipse_class_init(SPGenericEllipseClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPItemClass *item_class = (SPItemClass *) klass; - SPLPEItemClass *lpe_item_class = (SPLPEItemClass *) klass; - SPShapeClass *shape_class = (SPShapeClass *) klass; - - sp_object_class->update = sp_genericellipse_update; - sp_object_class->write = sp_genericellipse_write; +SPGenericEllipse::SPGenericEllipse() : SPShape() { + this->cx.unset(); + this->cy.unset(); + this->rx.unset(); + this->ry.unset(); - item_class->snappoints = sp_genericellipse_snappoints; - - shape_class->set_shape = sp_genericellipse_set_shape; - lpe_item_class->update_patheffect = sp_genericellipse_update_patheffect; + this->start = 0.0; + this->end = SP_2PI; + this->closed = TRUE; } -static void -sp_genericellipse_init(SPGenericEllipse *ellipse) -{ - ellipse->cx.unset(); - ellipse->cy.unset(); - ellipse->rx.unset(); - ellipse->ry.unset(); - - ellipse->start = 0.0; - ellipse->end = SP_2PI; - ellipse->closed = TRUE; +SPGenericEllipse::~SPGenericEllipse() { } -static void -sp_genericellipse_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPGenericEllipse::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - SPGenericEllipse *ellipse = (SPGenericEllipse *) object; - SPStyle const *style = object->style; Geom::Rect const &viewbox = ((SPItemCtx const *) ctx)->viewport; double const dx = viewbox.width(); double const dy = viewbox.height(); double const dr = sqrt(dx*dx + dy*dy)/sqrt(2); - double const em = style->font_size.computed; + double const em = this->style->font_size.computed; double const ex = em * 0.5; // fixme: get from pango or libnrtype - ellipse->cx.update(em, ex, dx); - ellipse->cy.update(em, ex, dy); - ellipse->rx.update(em, ex, dr); - ellipse->ry.update(em, ex, dr); - static_cast<SPShape *>(object)->setShape(); + + this->cx.update(em, ex, dx); + this->cy.update(em, ex, dy); + this->rx.update(em, ex, dr); + this->ry.update(em, ex, dr); + + this->set_shape(); } - if (((SPObjectClass *) sp_genericellipse_parent_class)->update) - ((SPObjectClass *) sp_genericellipse_parent_class)->update(object, ctx, flags); + SPShape::update(ctx, flags); } -static void -sp_genericellipse_update_patheffect(SPLPEItem *lpeitem, bool write) -{ - SPShape *shape = (SPShape *) lpeitem; - sp_genericellipse_set_shape(shape); +void SPGenericEllipse::update_patheffect(bool write) { + this->set_shape(); if (write) { - Inkscape::XML::Node *repr = shape->getRepr(); - if ( shape->_curve != NULL ) { - gchar *str = sp_svg_write_path(shape->_curve->get_pathvector()); + Inkscape::XML::Node *repr = this->getRepr(); + + if ( this->_curve != NULL ) { + gchar *str = sp_svg_write_path(this->_curve->get_pathvector()); repr->setAttribute("d", str); g_free(str); } else { @@ -148,22 +138,23 @@ sp_genericellipse_update_patheffect(SPLPEItem *lpeitem, bool write) } } - ((SPObject *)shape)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } /* fixme: Think (Lauris) */ /* Can't we use arcto in this method? */ -static void sp_genericellipse_set_shape(SPShape *shape) -{ - if (sp_lpe_item_has_broken_path_effect(SP_LPE_ITEM(shape))) { +void SPGenericEllipse::set_shape() { + if (sp_lpe_item_has_broken_path_effect(this)) { g_warning ("The ellipse shape has unknown LPE on it! Convert to path to make it editable preserving the appearance; editing it as ellipse will remove the bad LPE"); - if (shape->getRepr()->attribute("d")) { + + if (this->getRepr()->attribute("d")) { // unconditionally read the curve from d, if any, to preserve appearance - Geom::PathVector pv = sp_svg_read_pathv(shape->getRepr()->attribute("d")); + Geom::PathVector pv = sp_svg_read_pathv(this->getRepr()->attribute("d")); SPCurve *cold = new SPCurve(pv); - shape->setCurveInsync( cold, TRUE); + this->setCurveInsync( cold, TRUE); cold->unref(); } + return; } @@ -173,38 +164,43 @@ static void sp_genericellipse_set_shape(SPShape *shape) double len; gint slice = FALSE; - SPGenericEllipse *ellipse = (SPGenericEllipse *) shape; - - if ((ellipse->rx.computed < 1e-18) || (ellipse->ry.computed < 1e-18)) { - return; + if ((this->rx.computed < 1e-18) || (this->ry.computed < 1e-18)) { + return; } - if (fabs(ellipse->end - ellipse->start) < 1e-9){ - return; + + if (fabs(this->end - this->start) < 1e-9) { + return; } - sp_genericellipse_normalize(ellipse); + sp_genericellipse_normalize(this); - rx = ellipse->rx.computed; - ry = ellipse->ry.computed; + rx = this->rx.computed; + ry = this->ry.computed; // figure out if we have a slice, guarding against rounding errors - len = fmod(ellipse->end - ellipse->start, SP_2PI); - if (len < 0.0) len += SP_2PI; + len = fmod(this->end - this->start, SP_2PI); + + if (len < 0.0) { + len += SP_2PI; + } + if (fabs(len) < 1e-8 || fabs(len - SP_2PI) < 1e-8) { slice = FALSE; - ellipse->end = ellipse->start + SP_2PI; + this->end = this->start + SP_2PI; } else { slice = TRUE; } SPCurve * curve = new SPCurve(); - curve->moveto(cos(ellipse->start), sin(ellipse->start)); + curve->moveto(cos(this->start), sin(this->start)); - for (s = ellipse->start; s < ellipse->end; s += M_PI_2) { + for (s = this->start; s < this->end; s += M_PI_2) { double e = s + M_PI_2; - if (e > ellipse->end){ - e = ellipse->end; + + if (e > this->end) { + e = this->end; } + len = 4*tan((e - s)/4)/3; double x0 = cos(s); double y0 = sin(s); @@ -221,65 +217,69 @@ static void sp_genericellipse_set_shape(SPShape *shape) curve->curveto(x1,y1, x2,y2, x3,y3); } - if (slice && ellipse->closed) { // TODO: is this check for "ellipse->closed" necessary? + if (slice && this->closed) { // TODO: is this check for "ellipse->closed" necessary? curve->lineto(0., 0.); } - if (ellipse->closed) { + + if (this->closed) { curve->closepath(); } - Geom::Affine aff = Geom::Scale(rx, ry) * Geom::Translate(ellipse->cx.computed, ellipse->cy.computed); + Geom::Affine aff = Geom::Scale(rx, ry) * Geom::Translate(this->cx.computed, this->cy.computed); curve->transform(aff); /* Reset the shape's curve to the "original_curve" * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ - shape->setCurveInsync( curve, TRUE); - shape->setCurveBeforeLPE(curve); + this->setCurveInsync( curve, TRUE); + this->setCurveBeforeLPE(curve); - if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(shape)) && sp_lpe_item_path_effects_enabled(SP_LPE_ITEM(shape))) { + if (sp_lpe_item_has_path_effect(this) && sp_lpe_item_path_effects_enabled(this)) { SPCurve *c_lpe = curve->copy(); - bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM (shape), c_lpe); + bool success = sp_lpe_item_perform_path_effect(this, c_lpe); + if (success) { - shape->setCurveInsync( c_lpe, TRUE); + this->setCurveInsync( c_lpe, TRUE); } + c_lpe->unref(); } + curve->unref(); } -static void sp_genericellipse_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) -{ - g_assert(item != NULL); - g_assert(SP_IS_GENERICELLIPSE(item)); - - SPGenericEllipse *ellipse = SP_GENERICELLIPSE(item); - sp_genericellipse_normalize(ellipse); - Geom::Affine const i2dt = item->i2dt_affine(); +void SPGenericEllipse::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) { + sp_genericellipse_normalize(this); + Geom::Affine const i2dt = this->i2dt_affine(); // figure out if we have a slice, while guarding against rounding errors bool slice = false; - double len = fmod(ellipse->end - ellipse->start, SP_2PI); - if (len < 0.0) len += SP_2PI; + double len = fmod(this->end - this->start, SP_2PI); + + if (len < 0.0) { + len += SP_2PI; + } + if (fabs(len) < 1e-8 || fabs(len - SP_2PI) < 1e-8) { slice = false; - ellipse->end = ellipse->start + SP_2PI; + this->end = this->start + SP_2PI; } else { slice = true; } - double rx = ellipse->rx.computed; - double ry = ellipse->ry.computed; - double cx = ellipse->cx.computed; - double cy = ellipse->cy.computed; + double rx = this->rx.computed; + double ry = this->ry.computed; + double cx = this->cx.computed; + double cy = this->cy.computed; Geom::Point pt; - // Snap to the 4 quadrant points of the ellipse, but only if the arc + // Snap to the 4 quadrant points of the this, but only if the arc // spans far enough to include them if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_ELLIPSE_QUADRANT_POINT)) { double angle = 0; + for (angle = 0; angle < SP_2PI; angle += M_PI_2) { - if (angle >= ellipse->start && angle <= ellipse->end) { + if (angle >= this->start && angle <= this->end) { pt = Geom::Point(cx + cos(angle)*rx, cy + sin(angle)*ry) * i2dt; p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_ELLIPSE_QUADRANT_POINT, Inkscape::SNAPTARGET_ELLIPSE_QUADRANT_POINT)); } @@ -287,13 +287,16 @@ static void sp_genericellipse_snappoints(SPItem const *item, std::vector<Inkscap } // Add the centre, if we have a closed slice or when explicitly asked for - bool c1 = snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_NODE_CUSP) && slice && ellipse->closed; + bool c1 = snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_NODE_CUSP) && slice && this->closed; bool c2 = snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_OBJECT_MIDPOINT); + if (c1 || c2) { pt = Geom::Point(cx, cy) * i2dt; + if (c1) { p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP)); } + if (c2) { p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT)); } @@ -302,13 +305,14 @@ static void sp_genericellipse_snappoints(SPItem const *item, std::vector<Inkscap // And if we have a slice, also snap to the endpoints if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_NODE_CUSP) && slice) { // Add the start point, if it's not coincident with a quadrant point - if (fmod(ellipse->start, M_PI_2) != 0.0 ) { - pt = Geom::Point(cx + cos(ellipse->start)*rx, cy + sin(ellipse->start)*ry) * i2dt; + if (fmod(this->start, M_PI_2) != 0.0 ) { + pt = Geom::Point(cx + cos(this->start)*rx, cy + sin(this->start)*ry) * i2dt; p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP)); } + // Add the end point, if it's not coincident with a quadrant point - if (fmod(ellipse->end, M_PI_2) != 0.0 ) { - pt = Geom::Point(cx + cos(ellipse->end)*rx, cy + sin(ellipse->end)*ry) * i2dt; + if (fmod(this->end, M_PI_2) != 0.0 ) { + pt = Geom::Point(cx + cos(this->end)*rx, cy + sin(this->end)*ry) * i2dt; p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP)); } } @@ -320,141 +324,111 @@ sp_genericellipse_normalize(SPGenericEllipse *ellipse) ellipse->start = fmod(ellipse->start, SP_2PI); ellipse->end = fmod(ellipse->end, SP_2PI); - if (ellipse->start < 0.0) + if (ellipse->start < 0.0) { ellipse->start += SP_2PI; + } + double diff = ellipse->start - ellipse->end; - if (diff >= 0.0) + + if (diff >= 0.0) { ellipse->end += diff - fmod(diff, SP_2PI) + SP_2PI; + } /* Now we keep: 0 <= start < end <= 2*PI */ } -static Inkscape::XML::Node *sp_genericellipse_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPGenericEllipse *ellipse = SP_GENERICELLIPSE(object); - +Inkscape::XML::Node* SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if (flags & SP_OBJECT_WRITE_EXT) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:path"); } - sp_repr_set_svg_double(repr, "sodipodi:cx", ellipse->cx.computed); - sp_repr_set_svg_double(repr, "sodipodi:cy", ellipse->cy.computed); - sp_repr_set_svg_double(repr, "sodipodi:rx", ellipse->rx.computed); - sp_repr_set_svg_double(repr, "sodipodi:ry", ellipse->ry.computed); + sp_repr_set_svg_double(repr, "sodipodi:cx", this->cx.computed); + sp_repr_set_svg_double(repr, "sodipodi:cy", this->cy.computed); + sp_repr_set_svg_double(repr, "sodipodi:rx", this->rx.computed); + sp_repr_set_svg_double(repr, "sodipodi:ry", this->ry.computed); - if (SP_IS_ARC(ellipse)) { - sp_arc_set_elliptical_path_attribute(SP_ARC(object), object->getRepr()); + if (SP_IS_ARC(this)) { + sp_arc_set_elliptical_path_attribute(SP_ARC(this), this->getRepr()); } } - sp_genericellipse_set_shape ((SPShape *) ellipse); // evaluate SPCurve - if (((SPObjectClass *) sp_genericellipse_parent_class)->write) { - ((SPObjectClass *) sp_genericellipse_parent_class)->write(object, xml_doc, repr, flags); - } + this->set_shape(); // evaluate SPCurve + + SPShape::write(xml_doc, repr, flags); return repr; } /* SVG <ellipse> element */ - -static void sp_ellipse_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static Inkscape::XML::Node *sp_ellipse_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_ellipse_set(SPObject *object, unsigned int key, gchar const *value); -static gchar *sp_ellipse_description(SPItem *item); - -G_DEFINE_TYPE(SPEllipse, sp_ellipse, SP_TYPE_GENERICELLIPSE); - -static void sp_ellipse_class_init(SPEllipseClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPItemClass *item_class = (SPItemClass *) klass; - - sp_object_class->build = sp_ellipse_build; - sp_object_class->write = sp_ellipse_write; - sp_object_class->set = sp_ellipse_set; - - item_class->description = sp_ellipse_description; +SPEllipse::SPEllipse() : SPGenericEllipse() { } -static void -sp_ellipse_init(SPEllipse */*ellipse*/) -{ - /* Nothing special */ +SPEllipse::~SPEllipse() { } -static void -sp_ellipse_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_ellipse_parent_class)->build) - (* ((SPObjectClass *) sp_ellipse_parent_class)->build) (object, document, repr); +void SPEllipse::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPGenericEllipse::build(document, repr); - object->readAttr( "cx" ); - object->readAttr( "cy" ); - object->readAttr( "rx" ); - object->readAttr( "ry" ); + this->readAttr( "cx" ); + this->readAttr( "cy" ); + this->readAttr( "rx" ); + this->readAttr( "ry" ); } -static Inkscape::XML::Node * -sp_ellipse_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPGenericEllipse *ellipse; - - ellipse = SP_GENERICELLIPSE(object); +Inkscape::XML::Node* SPEllipse::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:ellipse"); } - sp_repr_set_svg_double(repr, "cx", ellipse->cx.computed); - sp_repr_set_svg_double(repr, "cy", ellipse->cy.computed); - sp_repr_set_svg_double(repr, "rx", ellipse->rx.computed); - sp_repr_set_svg_double(repr, "ry", ellipse->ry.computed); + sp_repr_set_svg_double(repr, "cx", this->cx.computed); + sp_repr_set_svg_double(repr, "cy", this->cy.computed); + sp_repr_set_svg_double(repr, "rx", this->rx.computed); + sp_repr_set_svg_double(repr, "ry", this->ry.computed); - if (((SPObjectClass *) sp_ellipse_parent_class)->write) - (* ((SPObjectClass *) sp_ellipse_parent_class)->write) (object, xml_doc, repr, flags); + SPGenericEllipse::write(xml_doc, repr, flags); return repr; } -static void -sp_ellipse_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPGenericEllipse *ellipse; - - ellipse = SP_GENERICELLIPSE(object); +void SPEllipse::set(unsigned int key, gchar const* value) { switch (key) { case SP_ATTR_CX: - ellipse->cx.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->cx.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_CY: - ellipse->cy.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->cy.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_RX: - if (!ellipse->rx.read(value) || (ellipse->rx.value <= 0.0)) { - ellipse->rx.unset(); + if (!this->rx.read(value) || (this->rx.value <= 0.0)) { + this->rx.unset(); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_RY: - if (!ellipse->ry.read(value) || (ellipse->ry.value <= 0.0)) { - ellipse->ry.unset(); + if (!this->ry.read(value) || (this->ry.value <= 0.0)) { + this->ry.unset(); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + default: - if (((SPObjectClass *) sp_ellipse_parent_class)->set) - ((SPObjectClass *) sp_ellipse_parent_class)->set(object, key, value); + SPGenericEllipse::set(key, value); break; } } -static gchar *sp_ellipse_description(SPItem */*item*/) -{ - return g_strdup(_("<b>Ellipse</b>")); +gchar* SPEllipse::description() { + return g_strdup(_("<b>Ellipse</b>")); } @@ -477,145 +451,84 @@ sp_ellipse_position_set(SPEllipse *ellipse, gdouble x, gdouble y, gdouble rx, gd } /* SVG <circle> element */ - -static void sp_circle_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static Inkscape::XML::Node *sp_circle_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_circle_set(SPObject *object, unsigned int key, gchar const *value); -static gchar *sp_circle_description(SPItem *item); - -G_DEFINE_TYPE(SPCircle, sp_circle, SP_TYPE_GENERICELLIPSE); - -static void -sp_circle_class_init(SPCircleClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPItemClass *item_class = (SPItemClass *) klass; - - sp_object_class->build = sp_circle_build; - sp_object_class->write = sp_circle_write; - sp_object_class->set = sp_circle_set; - - item_class->description = sp_circle_description; +SPCircle::SPCircle() : SPGenericEllipse() { } -static void -sp_circle_init(SPCircle */*circle*/) -{ - /* Nothing special */ +SPCircle::~SPCircle() { } -static void -sp_circle_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_circle_parent_class)->build) - (* ((SPObjectClass *) sp_circle_parent_class)->build)(object, document, repr); +void SPCircle::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPGenericEllipse::build(document, repr); - object->readAttr( "cx" ); - object->readAttr( "cy" ); - object->readAttr( "r" ); + this->readAttr( "cx" ); + this->readAttr( "cy" ); + this->readAttr( "r" ); } -static Inkscape::XML::Node * -sp_circle_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPGenericEllipse *ellipse; - - ellipse = SP_GENERICELLIPSE(object); +Inkscape::XML::Node* SPCircle::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:circle"); } - sp_repr_set_svg_double(repr, "cx", ellipse->cx.computed); - sp_repr_set_svg_double(repr, "cy", ellipse->cy.computed); - sp_repr_set_svg_double(repr, "r", ellipse->rx.computed); + sp_repr_set_svg_double(repr, "cx", this->cx.computed); + sp_repr_set_svg_double(repr, "cy", this->cy.computed); + sp_repr_set_svg_double(repr, "r", this->rx.computed); - if (((SPObjectClass *) sp_circle_parent_class)->write) - ((SPObjectClass *) sp_circle_parent_class)->write(object, xml_doc, repr, flags); + SPGenericEllipse::write(xml_doc, repr, flags); return repr; } -static void -sp_circle_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPGenericEllipse *ge; - - ge = SP_GENERICELLIPSE(object); - +void SPCircle::set(unsigned int key, gchar const* value) { switch (key) { case SP_ATTR_CX: - ge->cx.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->cx.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_CY: - ge->cy.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->cy.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_R: - if (!ge->rx.read(value) || ge->rx.value <= 0.0) { - ge->rx.unset(); + if (!this->rx.read(value) || this->rx.value <= 0.0) { + this->rx.unset(); } - ge->ry = ge->rx; - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->ry = this->rx; + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + default: - if (((SPObjectClass *) sp_circle_parent_class)->set) - ((SPObjectClass *) sp_circle_parent_class)->set(object, key, value); + SPGenericEllipse::set(key, value); break; } } -static gchar *sp_circle_description(SPItem */*item*/) -{ - return g_strdup(_("<b>Circle</b>")); +gchar* SPCircle::description() { + return g_strdup(_("<b>Circle</b>")); } /* <path sodipodi:type="arc"> element */ - -static void sp_arc_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static Inkscape::XML::Node *sp_arc_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_arc_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_arc_modified(SPObject *object, guint flags); - -static gchar *sp_arc_description(SPItem *item); - -G_DEFINE_TYPE(SPArc, sp_arc, SP_TYPE_GENERICELLIPSE); - -static void -sp_arc_class_init(SPArcClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPItemClass *item_class = (SPItemClass *) klass; - - sp_object_class->build = sp_arc_build; - sp_object_class->write = sp_arc_write; - sp_object_class->set = sp_arc_set; - sp_object_class->modified = sp_arc_modified; - - item_class->description = sp_arc_description; +SPArc::SPArc() : SPGenericEllipse() { } -static void -sp_arc_init(SPArc */*arc*/) -{ - /* Nothing special */ +SPArc::~SPArc() { } -static void -sp_arc_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_arc_parent_class)->build) - (* ((SPObjectClass *) sp_arc_parent_class)->build) (object, document, repr); +void SPArc::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPGenericEllipse::build(document, repr); - object->readAttr( "sodipodi:cx" ); - object->readAttr( "sodipodi:cy" ); - object->readAttr( "sodipodi:rx" ); - object->readAttr( "sodipodi:ry" ); + this->readAttr( "sodipodi:cx" ); + this->readAttr( "sodipodi:cy" ); + this->readAttr( "sodipodi:rx" ); + this->readAttr( "sodipodi:ry" ); - object->readAttr( "sodipodi:start" ); - object->readAttr( "sodipodi:end" ); - object->readAttr( "sodipodi:open" ); + this->readAttr( "sodipodi:start" ); + this->readAttr( "sodipodi:end" ); + this->readAttr( "sodipodi:open" ); } /* @@ -660,30 +573,31 @@ sp_arc_set_elliptical_path_attribute(SPArc *arc, Inkscape::XML::Node *repr) return true; } -static Inkscape::XML::Node * -sp_arc_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPGenericEllipse *ge = SP_GENERICELLIPSE(object); - SPArc *arc = SP_ARC(object); - +Inkscape::XML::Node* SPArc::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:path"); } if (flags & SP_OBJECT_WRITE_EXT) { repr->setAttribute("sodipodi:type", "arc"); - sp_repr_set_svg_double(repr, "sodipodi:cx", ge->cx.computed); - sp_repr_set_svg_double(repr, "sodipodi:cy", ge->cy.computed); - sp_repr_set_svg_double(repr, "sodipodi:rx", ge->rx.computed); - sp_repr_set_svg_double(repr, "sodipodi:ry", ge->ry.computed); + + sp_repr_set_svg_double(repr, "sodipodi:cx", this->cx.computed); + sp_repr_set_svg_double(repr, "sodipodi:cy", this->cy.computed); + sp_repr_set_svg_double(repr, "sodipodi:rx", this->rx.computed); + sp_repr_set_svg_double(repr, "sodipodi:ry", this->ry.computed); // write start and end only if they are non-trivial; otherwise remove - gdouble len = fmod(ge->end - ge->start, SP_2PI); - if (len < 0.0) len += SP_2PI; + gdouble len = fmod(this->end - this->start, SP_2PI); + + if (len < 0.0) { + len += SP_2PI; + } + if (!(fabs(len) < 1e-8 || fabs(len - SP_2PI) < 1e-8)) { - sp_repr_set_svg_double(repr, "sodipodi:start", ge->start); - sp_repr_set_svg_double(repr, "sodipodi:end", ge->end); - repr->setAttribute("sodipodi:open", (!ge->closed) ? "true" : NULL); + sp_repr_set_svg_double(repr, "sodipodi:start", this->start); + sp_repr_set_svg_double(repr, "sodipodi:end", this->end); + + repr->setAttribute("sodipodi:open", (!this->closed) ? "true" : NULL); } else { repr->setAttribute("sodipodi:end", NULL); repr->setAttribute("sodipodi:start", NULL); @@ -692,86 +606,90 @@ sp_arc_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML:: } // write d= - sp_arc_set_elliptical_path_attribute(arc, repr); + sp_arc_set_elliptical_path_attribute(this, repr); - if (((SPObjectClass *) sp_arc_parent_class)->write) - ((SPObjectClass *) sp_arc_parent_class)->write(object, xml_doc, repr, flags); + SPGenericEllipse::write(xml_doc, repr, flags); return repr; } -static void -sp_arc_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPGenericEllipse *ge = SP_GENERICELLIPSE(object); - +void SPArc::set(unsigned int key, gchar const* value) { switch (key) { case SP_ATTR_SODIPODI_CX: - ge->cx.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->cx.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_CY: - ge->cy.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->cy.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_RX: - if (!ge->rx.read(value) || ge->rx.computed <= 0.0) { - ge->rx.unset(); + if (!this->rx.read(value) || this->rx.computed <= 0.0) { + this->rx.unset(); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_RY: - if (!ge->ry.read(value) || ge->ry.computed <= 0.0) { - ge->ry.unset(); + if (!this->ry.read(value) || this->ry.computed <= 0.0) { + this->ry.unset(); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_START: if (value) { - sp_svg_number_read_d(value, &ge->start); + sp_svg_number_read_d(value, &this->start); } else { - ge->start = 0; + this->start = 0; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_END: if (value) { - sp_svg_number_read_d(value, &ge->end); + sp_svg_number_read_d(value, &this->end); } else { - ge->end = 2 * M_PI; + this->end = 2 * M_PI; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_OPEN: - ge->closed = (!value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->closed = (!value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + default: - if (((SPObjectClass *) sp_arc_parent_class)->set) - ((SPObjectClass *) sp_arc_parent_class)->set(object, key, value); + SPGenericEllipse::set(key, value); break; } } -static void -sp_arc_modified(SPObject *object, guint flags) -{ +void SPArc::modified(guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - ((SPShape *) object)->setShape(); + this->set_shape(); } - if (((SPObjectClass *) sp_arc_parent_class)->modified) - ((SPObjectClass *) sp_arc_parent_class)->modified(object, flags); + SPGenericEllipse::modified(flags); } -static gchar *sp_arc_description(SPItem *item) -{ - SPGenericEllipse *ge = SP_GENERICELLIPSE(item); - gdouble len = fmod(ge->end - ge->start, SP_2PI); - if (len < 0.0) len += SP_2PI; +gchar* SPArc::description() { + gdouble len = fmod(this->end - this->start, SP_2PI); + + if (len < 0.0) { + len += SP_2PI; + } + if (!(fabs(len) < 1e-8 || fabs(len - SP_2PI) < 1e-8)) { - if (ge->closed) { + if (this->closed) { return g_strdup(_("<b>Segment</b>")); } else { return g_strdup(_("<b>Arc</b>")); diff --git a/src/sp-ellipse.h b/src/sp-ellipse.h index d22501f6b..67e12006a 100644 --- a/src/sp-ellipse.h +++ b/src/sp-ellipse.h @@ -17,17 +17,15 @@ #include "svg/svg-length.h" #include "sp-shape.h" -G_BEGIN_DECLS - /* Common parent class */ +#define SP_GENERICELLIPSE(obj) (dynamic_cast<SPGenericEllipse*>((SPObject*)obj)) +#define SP_IS_GENERICELLIPSE(obj) (dynamic_cast<const SPGenericEllipse*>((SPObject*)obj) != NULL) -#define SP_TYPE_GENERICELLIPSE (sp_genericellipse_get_type ()) -#define SP_GENERICELLIPSE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_GENERICELLIPSE, SPGenericEllipse)) -#define SP_GENERICELLIPSE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_GENERICELLIPSE, SPGenericEllipseClass)) -#define SP_IS_GENERICELLIPSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_GENERICELLIPSE)) -#define SP_IS_GENERICELLIPSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_GENERICELLIPSE)) +class SPGenericEllipse : public SPShape { +public: + SPGenericEllipse(); + virtual ~SPGenericEllipse(); -struct SPGenericEllipse : public SPShape { SVGLength cx; SVGLength cy; SVGLength rx; @@ -35,72 +33,68 @@ struct SPGenericEllipse : public SPShape { unsigned int closed : 1; double start, end; -}; -struct SPGenericEllipseClass { - SPShapeClass parent_class; -}; + virtual void update(SPCtx* ctx, unsigned int flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); -GType sp_genericellipse_get_type (void); + virtual void snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); + virtual void set_shape(); + + virtual void update_patheffect(bool write); +}; /* This is technically priate by we need this in object edit (Lauris) */ void sp_genericellipse_normalize (SPGenericEllipse *ellipse); /* SVG <ellipse> element */ - -#define SP_TYPE_ELLIPSE (sp_ellipse_get_type ()) -#define SP_ELLIPSE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_ELLIPSE, SPEllipse)) -#define SP_ELLIPSE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_ELLIPSE, SPEllipseClass)) -#define SP_IS_ELLIPSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_ELLIPSE)) -#define SP_IS_ELLIPSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_ELLIPSE)) - -struct SPEllipse : public SPGenericEllipse { +#define SP_ELLIPSE(obj) (dynamic_cast<SPEllipse*>((SPObject*)obj)) +#define SP_IS_ELLIPSE(obj) (dynamic_cast<const SPEllipse*>((SPObject*)obj) != NULL) + +class SPEllipse : public SPGenericEllipse { +public: + SPEllipse(); + virtual ~SPEllipse(); + + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + virtual void set(unsigned int key, gchar const* value); + virtual gchar* description(); }; -struct SPEllipseClass { - SPGenericEllipseClass parent_class; -}; - -GType sp_ellipse_get_type (void); - void sp_ellipse_position_set (SPEllipse * ellipse, gdouble x, gdouble y, gdouble rx, gdouble ry); /* SVG <circle> element */ - -#define SP_TYPE_CIRCLE (sp_circle_get_type ()) -#define SP_CIRCLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_CIRCLE, SPCircle)) -#define SP_CIRCLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_CIRCLE, SPCircleClass)) -#define SP_IS_CIRCLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_CIRCLE)) -#define SP_IS_CIRCLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_CIRCLE)) - -struct SPCircle : public SPGenericEllipse { +#define SP_CIRCLE(obj) (dynamic_cast<SPCircle*>((SPObject*)obj)) +#define SP_IS_CIRCLE(obj) (dynamic_cast<const SPCircle*>((SPObject*)obj) != NULL) + +class SPCircle : public SPGenericEllipse { +public: + SPCircle(); + virtual ~SPCircle(); + + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + virtual void set(unsigned int key, gchar const* value); + virtual gchar* description(); }; -struct SPCircleClass { - SPGenericEllipseClass parent_class; -}; - -GType sp_circle_get_type (void); - /* <path sodipodi:type="arc"> element */ - -#define SP_TYPE_ARC (sp_arc_get_type ()) -#define SP_ARC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_ARC, SPArc)) -#define SP_ARC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_ARC, SPArcClass)) -#define SP_IS_ARC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_ARC)) -#define SP_IS_ARC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_ARC)) - -struct SPArc : public SPGenericEllipse { +#define SP_ARC(obj) (dynamic_cast<SPArc*>((SPObject*)obj)) +#define SP_IS_ARC(obj) (dynamic_cast<const SPArc*>((SPObject*)obj) != NULL) + +class SPArc : public SPGenericEllipse { +public: + SPArc(); + virtual ~SPArc(); + + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + virtual void set(unsigned int key, gchar const* value); + virtual gchar* description(); + virtual void modified(unsigned int flags); }; -struct SPArcClass { - SPGenericEllipseClass parent_class; -}; - -GType sp_arc_get_type (void); void sp_arc_position_set (SPArc * arc, gdouble x, gdouble y, gdouble rx, gdouble ry); Geom::Point sp_arc_get_xy (SPArc *ge, gdouble arg); -G_END_DECLS - #endif diff --git a/src/sp-factory.h b/src/sp-factory.h new file mode 100644 index 000000000..0621f77ba --- /dev/null +++ b/src/sp-factory.h @@ -0,0 +1,31 @@ +/** @file + * Factory for SPObject tree + *//* + * Authors: + * Markus Engel + * + * Copyright (C) 2013 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SP_FACTORY_SEEN +#define SP_FACTORY_SEEN + +#include "factory.h" + +class SPObject; +typedef Singleton< Factory<SPObject> > SPFactory; + + +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-filter-primitive.cpp b/src/sp-filter-primitive.cpp index 7ddf3b065..f6b89bc21 100644 --- a/src/sp-filter-primitive.cpp +++ b/src/sp-filter-primitive.cpp @@ -27,70 +27,28 @@ #include "display/nr-filter-primitive.h" #include "display/nr-filter-types.h" -/* FilterPrimitive base class */ -static void sp_filter_primitive_class_init(SPFilterPrimitiveClass *klass); -static void sp_filter_primitive_init(SPFilterPrimitive *filter_primitive); +// CPPIFY: Make pure virtual. +//void SPFilterPrimitive::build_renderer(Inkscape::Filters::Filter* filter) { + // throw; +//} -static void sp_filter_primitive_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_filter_primitive_release(SPObject *object); -static void sp_filter_primitive_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_filter_primitive_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_filter_primitive_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -static SPObjectClass *filter_primitive_parent_class; - -GType sp_filter_primitive_get_type() -{ - static GType filter_primitive_type = 0; - - if (!filter_primitive_type) { - GTypeInfo filter_primitive_info = { - sizeof(SPFilterPrimitiveClass), - NULL, NULL, - (GClassInitFunc) sp_filter_primitive_class_init, - NULL, NULL, - sizeof(SPFilterPrimitive), - 16, - (GInstanceInitFunc) sp_filter_primitive_init, - NULL, /* value_table */ - }; - filter_primitive_type = g_type_register_static(SP_TYPE_OBJECT, "SPFilterPrimitive", &filter_primitive_info, (GTypeFlags)0); - } - return filter_primitive_type; -} - -static void sp_filter_primitive_class_init(SPFilterPrimitiveClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)(klass); - - filter_primitive_parent_class = static_cast<SPObjectClass *>(g_type_class_peek_parent(klass)); - - sp_object_class->build = sp_filter_primitive_build; - sp_object_class->release = sp_filter_primitive_release; - sp_object_class->write = sp_filter_primitive_write; - sp_object_class->set = sp_filter_primitive_set; - sp_object_class->update = sp_filter_primitive_update; - - /* This should never be called on this base class, but only on derived - * classes. */ - klass->build_renderer = NULL; -} - -static void sp_filter_primitive_init(SPFilterPrimitive *filter_primitive) -{ - filter_primitive->image_in = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET; - filter_primitive->image_out = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET; +SPFilterPrimitive::SPFilterPrimitive() : SPObject() { + this->image_in = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET; + this->image_out = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET; // We must keep track if a value is set or not, if not set then the region defaults to 0%, 0%, // 100%, 100% ("x", "y", "width", "height") of the -> filter <- region. If set then // percentages are in terms of bounding box or viewbox, depending on value of "primitiveUnits" // NB: SVGLength.set takes prescaled percent values: 1 means 100% - filter_primitive->x.unset(SVGLength::PERCENT, 0, 0); - filter_primitive->y.unset(SVGLength::PERCENT, 0, 0); - filter_primitive->width.unset(SVGLength::PERCENT, 1, 0); - filter_primitive->height.unset(SVGLength::PERCENT, 1, 0); + this->x.unset(SVGLength::PERCENT, 0, 0); + this->y.unset(SVGLength::PERCENT, 0, 0); + this->width.unset(SVGLength::PERCENT, 1, 0); + this->height.unset(SVGLength::PERCENT, 1, 0); +} + +SPFilterPrimitive::~SPFilterPrimitive() { } /** @@ -98,38 +56,33 @@ static void sp_filter_primitive_init(SPFilterPrimitive *filter_primitive) * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_filter_primitive_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ +void SPFilterPrimitive::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPFilterPrimitive* object = this; + object->readAttr( "style" ); // struct not derived from SPItem, we need to do this ourselves. - object->readAttr( "in" ); - object->readAttr( "result" ); - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "width" ); - object->readAttr( "height" ); - - if ((static_cast<SPObjectClass *>(filter_primitive_parent_class))->build) { - (static_cast<SPObjectClass *>(filter_primitive_parent_class))->build(object, document, repr); - } + object->readAttr( "in" ); + object->readAttr( "result" ); + object->readAttr( "x" ); + object->readAttr( "y" ); + object->readAttr( "width" ); + object->readAttr( "height" ); + + SPObject::build(document, repr); } /** * Drops any allocated memory. */ -static void sp_filter_primitive_release(SPObject *object) -{ - /* deal with our children and our selves here */ - if ((static_cast<SPObjectClass *>(filter_primitive_parent_class))->release) - (static_cast<SPObjectClass *>(filter_primitive_parent_class))->release(object); +void SPFilterPrimitive::release() { + SPObject::release(); } /** * Sets a specific value in the SPFilterPrimitive. */ -static void -sp_filter_primitive_set(SPObject *object, unsigned int key, gchar const *value) -{ +void SPFilterPrimitive::set(unsigned int key, gchar const *value) { + SPFilterPrimitive* object = this; + SPFilterPrimitive *filter_primitive = SP_FILTER_PRIMITIVE(object); (void)filter_primitive; int image_nr; @@ -177,17 +130,15 @@ sp_filter_primitive_set(SPObject *object, unsigned int key, gchar const *value) } /* See if any parents need this value. */ - if (((SPObjectClass *) filter_primitive_parent_class)->set) { - ((SPObjectClass *) filter_primitive_parent_class)->set(object, key, value); - } + SPObject::set(key, value); } /** * Receives update notifications. */ -static void -sp_filter_primitive_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPFilterPrimitive::update(SPCtx *ctx, guint flags) { + SPFilterPrimitive* object = this; + //SPFilterPrimitive *filter_primitive = SP_FILTER_PRIMITIVE(object); // Is this required? @@ -201,17 +152,15 @@ sp_filter_primitive_update(SPObject *object, SPCtx *ctx, guint flags) object->readAttr( "height" ); } - if (((SPObjectClass *) filter_primitive_parent_class)->update) { - ((SPObjectClass *) filter_primitive_parent_class)->update(object, ctx, flags); - } + SPObject::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_filter_primitive_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPFilterPrimitive::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { + SPFilterPrimitive* object = this; + SPFilterPrimitive *prim = SP_FILTER_PRIMITIVE(object); SPFilter *parent = SP_FILTER(object->parent); @@ -226,9 +175,7 @@ sp_filter_primitive_write(SPObject *object, Inkscape::XML::Document *doc, Inksca repr->setAttribute("result", out_name); /* Do we need to add x,y,width,height? */ - if (((SPObjectClass *) filter_primitive_parent_class)->write) { - ((SPObjectClass *) filter_primitive_parent_class)->write(object, doc, repr, flags); - } + SPObject::write(doc, repr, flags); return repr; } diff --git a/src/sp-filter-primitive.h b/src/sp-filter-primitive.h index f06df5611..040e2f31f 100644 --- a/src/sp-filter-primitive.h +++ b/src/sp-filter-primitive.h @@ -17,11 +17,8 @@ #include "sp-object.h" #include "svg/svg-length.h" -#define SP_TYPE_FILTER_PRIMITIVE (sp_filter_primitive_get_type ()) -#define SP_FILTER_PRIMITIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_FILTER_PRIMITIVE, SPFilterPrimitive)) -#define SP_FILTER_PRIMITIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_FILTER_PRIMITIVE, SPFilterPrimitiveClass)) -#define SP_IS_FILTER_PRIMITIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_FILTER_PRIMITIVE)) -#define SP_IS_FILTER_PRIMITIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_FILTER_PRIMITIVE)) +#define SP_FILTER_PRIMITIVE(obj) (dynamic_cast<SPFilterPrimitive*>((SPObject*)obj)) +#define SP_IS_FILTER_PRIMITIVE(obj) (dynamic_cast<const SPFilterPrimitive*>((SPObject*)obj) != NULL) namespace Inkscape { namespace Filters { @@ -29,20 +26,29 @@ class Filter; class FilterPrimitive; } } +class SPFilterPrimitive : public SPObject { +public: + SPFilterPrimitive(); + virtual ~SPFilterPrimitive(); -struct SPFilterPrimitive : public SPObject { int image_in, image_out; /* filter primitive subregion */ SVGLength x, y, height, width; -}; -struct SPFilterPrimitiveClass { - SPObjectClass sp_object_class; - void (* build_renderer)(SPFilterPrimitive*, Inkscape::Filters::Filter*); -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void set(unsigned int key, const gchar* value); -GType sp_filter_primitive_get_type (void); + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + +public: + virtual void build_renderer(Inkscape::Filters::Filter* filter) = 0; +}; /* Common initialization for filter primitives */ void sp_filter_primitive_renderer_common(SPFilterPrimitive *sp_prim, Inkscape::Filters::FilterPrimitive *nr_prim); diff --git a/src/sp-filter-reference.h b/src/sp-filter-reference.h index 7a335aed4..5901dca07 100644 --- a/src/sp-filter-reference.h +++ b/src/sp-filter-reference.h @@ -5,7 +5,7 @@ class SPObject; class SPDocument; -struct SPFilter; +class SPFilter; class SPFilterReference : public Inkscape::URIReference { public: diff --git a/src/sp-filter.cpp b/src/sp-filter.cpp index bce86c465..91389bf7d 100644 --- a/src/sp-filter.cpp +++ b/src/sp-filter.cpp @@ -38,193 +38,159 @@ using std::pair; #include "display/nr-filter.h" -/* Filter base class */ -static void sp_filter_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_filter_release(SPObject *object); -static void sp_filter_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_filter_update(SPObject *object, SPCtx *ctx, guint flags); -static void sp_filter_child_added(SPObject *object, - Inkscape::XML::Node *child, - Inkscape::XML::Node *ref); -static void sp_filter_remove_child(SPObject *object, Inkscape::XML::Node *child); -static Inkscape::XML::Node *sp_filter_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - static void filter_ref_changed(SPObject *old_ref, SPObject *ref, SPFilter *filter); static void filter_ref_modified(SPObject *href, guint flags, SPFilter *filter); -G_DEFINE_TYPE(SPFilter, sp_filter, SP_TYPE_OBJECT); +#include "sp-factory.h" -static void -sp_filter_class_init(SPFilterClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - - sp_object_class->build = sp_filter_build; - sp_object_class->release = sp_filter_release; - sp_object_class->write = sp_filter_write; - sp_object_class->set = sp_filter_set; - sp_object_class->update = sp_filter_update; - sp_object_class->child_added = sp_filter_child_added; - sp_object_class->remove_child = sp_filter_remove_child; +namespace { + SPObject* createFilter() { + return new SPFilter(); + } + + bool filterRegistered = SPFactory::instance().registerObject("svg:filter", createFilter); } -static void -sp_filter_init(SPFilter *filter) +SPFilter::SPFilter() + : SPObject(), filterUnits(SP_FILTER_UNITS_OBJECTBOUNDINGBOX), filterUnits_set(FALSE), + primitiveUnits(SP_FILTER_UNITS_USERSPACEONUSE), primitiveUnits_set(FALSE), + filterRes(NumberOptNumber()), + _renderer(NULL), _image_name(new std::map<gchar *, int, ltstr>), _image_number_next(0) { - filter->href = new SPFilterReference(filter); - filter->href->changedSignal().connect(sigc::bind(sigc::ptr_fun(filter_ref_changed), filter)); - - filter->x = 0; - filter->y = 0; - filter->width = 0; - filter->height = 0; + this->href = new SPFilterReference(this); + this->href->changedSignal().connect(sigc::bind(sigc::ptr_fun(filter_ref_changed), this)); - filter->filterUnits = SP_FILTER_UNITS_OBJECTBOUNDINGBOX; - filter->primitiveUnits = SP_FILTER_UNITS_USERSPACEONUSE; - filter->filterUnits_set = FALSE; - filter->primitiveUnits_set = FALSE; + this->x = 0; + this->y = 0; + this->width = 0; + this->height = 0; - filter->_renderer = NULL; - - filter->_image_name = new std::map<gchar *, int, ltstr>; - filter->_image_name->clear(); - filter->_image_number_next = 0; - - filter->filterRes = NumberOptNumber(); + this->_image_name->clear(); +} - new (&filter->modified_connection) sigc::connection(); +SPFilter::~SPFilter() { } + /** * Reads the Inkscape::XML::Node, and initializes SPFilter variables. For this to get called, * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_filter_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ +void SPFilter::build(SPDocument *document, Inkscape::XML::Node *repr) { //Read values of key attributes from XML nodes into object. - object->readAttr( "style" ); // struct not derived from SPItem, we need to do this ourselves. - object->readAttr( "filterUnits" ); - object->readAttr( "primitiveUnits" ); - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "width" ); - object->readAttr( "height" ); - object->readAttr( "filterRes" ); - object->readAttr( "xlink:href" ); - - if (((SPObjectClass *) sp_filter_parent_class)->build) { - ((SPObjectClass *) sp_filter_parent_class)->build(object, document, repr); - } + this->readAttr( "style" ); // struct not derived from SPItem, we need to do this ourselves. + this->readAttr( "filterUnits" ); + this->readAttr( "primitiveUnits" ); + this->readAttr( "x" ); + this->readAttr( "y" ); + this->readAttr( "width" ); + this->readAttr( "height" ); + this->readAttr( "filterRes" ); + this->readAttr( "xlink:href" ); + + SPObject::build(document, repr); //is this necessary? - document->addResource("filter", object); + document->addResource("filter", this); } /** * Drops any allocated memory. */ -static void sp_filter_release(SPObject *object) -{ - SPFilter *filter = SP_FILTER(object); - - if (object->document) { +void SPFilter::release() { + if (this->document) { // Unregister ourselves - object->document->removeResource("filter", object); + this->document->removeResource("filter", this); } //TODO: release resources here //release href - if (filter->href) { - filter->modified_connection.disconnect(); - filter->href->detach(); - delete filter->href; - filter->href = NULL; + if (this->href) { + this->modified_connection.disconnect(); + this->href->detach(); + delete this->href; + this->href = NULL; } - filter->modified_connection.~connection(); - delete filter->_image_name; + delete this->_image_name; - if (((SPObjectClass *) sp_filter_parent_class)->release) - ((SPObjectClass *) sp_filter_parent_class)->release(object); + SPObject::release(); } /** * Sets a specific value in the SPFilter. */ -static void -sp_filter_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPFilter *filter = SP_FILTER(object); - +void SPFilter::set(unsigned int key, gchar const *value) { switch (key) { case SP_ATTR_FILTERUNITS: if (value) { if (!strcmp(value, "userSpaceOnUse")) { - filter->filterUnits = SP_FILTER_UNITS_USERSPACEONUSE; + this->filterUnits = SP_FILTER_UNITS_USERSPACEONUSE; } else { - filter->filterUnits = SP_FILTER_UNITS_OBJECTBOUNDINGBOX; + this->filterUnits = SP_FILTER_UNITS_OBJECTBOUNDINGBOX; } - filter->filterUnits_set = TRUE; + + this->filterUnits_set = TRUE; } else { - filter->filterUnits = SP_FILTER_UNITS_OBJECTBOUNDINGBOX; - filter->filterUnits_set = FALSE; + this->filterUnits = SP_FILTER_UNITS_OBJECTBOUNDINGBOX; + this->filterUnits_set = FALSE; } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_PRIMITIVEUNITS: if (value) { if (!strcmp(value, "objectBoundingBox")) { - filter->primitiveUnits = SP_FILTER_UNITS_OBJECTBOUNDINGBOX; + this->primitiveUnits = SP_FILTER_UNITS_OBJECTBOUNDINGBOX; } else { - filter->primitiveUnits = SP_FILTER_UNITS_USERSPACEONUSE; + this->primitiveUnits = SP_FILTER_UNITS_USERSPACEONUSE; } - filter->primitiveUnits_set = TRUE; + + this->primitiveUnits_set = TRUE; } else { - filter->primitiveUnits = SP_FILTER_UNITS_USERSPACEONUSE; - filter->primitiveUnits_set = FALSE; + this->primitiveUnits = SP_FILTER_UNITS_USERSPACEONUSE; + this->primitiveUnits_set = FALSE; } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_X: - filter->x.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->x.readOrUnset(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_Y: - filter->y.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->y.readOrUnset(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_WIDTH: - filter->width.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->width.readOrUnset(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_HEIGHT: - filter->height.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->height.readOrUnset(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_FILTERRES: - filter->filterRes.set(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->filterRes.set(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_XLINK_HREF: if (value) { try { - filter->href->attach(Inkscape::URI(value)); + this->href->attach(Inkscape::URI(value)); } catch (Inkscape::BadURIException &e) { g_warning("%s", e.what()); - filter->href->detach(); + this->href->detach(); } } else { - filter->href->detach(); + this->href->detach(); } break; default: // See if any parents need this value. - if (((SPObjectClass *) sp_filter_parent_class)->set) { - ((SPObjectClass *) sp_filter_parent_class)->set(object, key, value); - } + SPObject::set(key, value); break; } } @@ -232,11 +198,7 @@ sp_filter_set(SPObject *object, unsigned int key, gchar const *value) /** * Receives update notifications. */ -static void -sp_filter_update(SPObject *object, SPCtx *ctx, guint flags) -{ - //SPFilter *filter = SP_FILTER(object); - +void SPFilter::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { @@ -244,44 +206,41 @@ sp_filter_update(SPObject *object, SPCtx *ctx, guint flags) } - if (((SPObjectClass *) sp_filter_parent_class)->update) { - ((SPObjectClass *) sp_filter_parent_class)->update(object, ctx, flags); - } + SPObject::update(ctx, flags); } /** * Writes its settings to an incoming repr object, if any. */ -static Inkscape::XML::Node * -sp_filter_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ - SPFilter *filter = SP_FILTER(object); - +Inkscape::XML::Node* SPFilter::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { // Original from sp-item-group.cpp if (flags & SP_OBJECT_WRITE_BUILD) { if (!repr) { - repr = doc->createElement("svg:filter"); + repr = doc->createElement("svg:this"); } + GSList *l = NULL; - for ( SPObject *child = object->firstChild(); child; child = child->getNext() ) { + for ( SPObject *child = this->firstChild(); child; child = child->getNext() ) { Inkscape::XML::Node *crepr = child->updateRepr(doc, NULL, flags); + if (crepr) { l = g_slist_prepend (l, crepr); } } + while (l) { repr->addChild((Inkscape::XML::Node *) l->data, NULL); Inkscape::GC::release((Inkscape::XML::Node *) l->data); l = g_slist_remove (l, l->data); } } else { - for ( SPObject *child = object->firstChild() ; child; child = child->getNext() ) { + for ( SPObject *child = this->firstChild() ; child; child = child->getNext() ) { child->updateRepr(flags); } } - if ((flags & SP_OBJECT_WRITE_ALL) || filter->filterUnits_set) { - switch (filter->filterUnits) { + if ((flags & SP_OBJECT_WRITE_ALL) || this->filterUnits_set) { + switch (this->filterUnits) { case SP_FILTER_UNITS_USERSPACEONUSE: repr->setAttribute("filterUnits", "userSpaceOnUse"); break; @@ -291,8 +250,8 @@ sp_filter_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::N } } - if ((flags & SP_OBJECT_WRITE_ALL) || filter->primitiveUnits_set) { - switch (filter->primitiveUnits) { + if ((flags & SP_OBJECT_WRITE_ALL) || this->primitiveUnits_set) { + switch (this->primitiveUnits) { case SP_FILTER_UNITS_OBJECTBOUNDINGBOX: repr->setAttribute("primitiveUnits", "objectBoundingBox"); break; @@ -302,47 +261,45 @@ sp_filter_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::N } } - if (filter->x._set) { - sp_repr_set_svg_double(repr, "x", filter->x.computed); + if (this->x._set) { + sp_repr_set_svg_double(repr, "x", this->x.computed); } else { repr->setAttribute("x", NULL); } - if (filter->y._set) { - sp_repr_set_svg_double(repr, "y", filter->y.computed); + if (this->y._set) { + sp_repr_set_svg_double(repr, "y", this->y.computed); } else { repr->setAttribute("y", NULL); } - if (filter->width._set) { - sp_repr_set_svg_double(repr, "width", filter->width.computed); + if (this->width._set) { + sp_repr_set_svg_double(repr, "width", this->width.computed); } else { repr->setAttribute("width", NULL); } - if (filter->height._set) { - sp_repr_set_svg_double(repr, "height", filter->height.computed); + if (this->height._set) { + sp_repr_set_svg_double(repr, "height", this->height.computed); } else { repr->setAttribute("height", NULL); } - if (filter->filterRes.getNumber()>=0) { - gchar *tmp = filter->filterRes.getValueString(); + if (this->filterRes.getNumber()>=0) { + gchar *tmp = this->filterRes.getValueString(); repr->setAttribute("filterRes", tmp); g_free(tmp); } else { repr->setAttribute("filterRes", NULL); } - if (filter->href->getURI()) { - gchar *uri_string = filter->href->getURI()->toString(); + if (this->href->getURI()) { + gchar *uri_string = this->href->getURI()->toString(); repr->setAttribute("xlink:href", uri_string); g_free(uri_string); } - if (((SPObjectClass *) sp_filter_parent_class)->write) { - ((SPObjectClass *) sp_filter_parent_class)->write(object, doc, repr, flags); - } + SPObject::write(doc, repr, flags); return repr; } @@ -357,6 +314,7 @@ filter_ref_changed(SPObject *old_ref, SPObject *ref, SPFilter *filter) if (old_ref) { filter->modified_connection.disconnect(); } + if ( SP_IS_FILTER(ref) && ref != filter ) { @@ -375,29 +333,19 @@ static void filter_ref_modified(SPObject */*href*/, guint /*flags*/, SPFilter *f /** * Callback for child_added event. */ -static void -sp_filter_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) -{ - //SPFilter *f = SP_FILTER(object); - - if (((SPObjectClass *) sp_filter_parent_class)->child_added) - (* ((SPObjectClass *) sp_filter_parent_class)->child_added)(object, child, ref); +void SPFilter::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { + SPObject::child_added(child, ref); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } /** * Callback for remove_child event. */ -static void -sp_filter_remove_child(SPObject *object, Inkscape::XML::Node *child) -{ -// SPFilter *f = SP_FILTER(object); - - if (((SPObjectClass *) sp_filter_parent_class)->remove_child) - (* ((SPObjectClass *) sp_filter_parent_class)->remove_child)(object, child); +void SPFilter::remove_child(Inkscape::XML::Node *child) { + SPObject::remove_child(child); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } void sp_filter_build_renderer(SPFilter *sp_filter, Inkscape::Filters::Filter *nr_filter) @@ -429,11 +377,13 @@ void sp_filter_build_renderer(SPFilter *sp_filter, Inkscape::Filters::Filter *nr if (SP_IS_FILTER_PRIMITIVE(primitive_obj)) { SPFilterPrimitive *primitive = SP_FILTER_PRIMITIVE(primitive_obj); g_assert(primitive != NULL); - if (((SPFilterPrimitiveClass*) G_OBJECT_GET_CLASS(primitive))->build_renderer) { - ((SPFilterPrimitiveClass *) G_OBJECT_GET_CLASS(primitive))->build_renderer(primitive, nr_filter); - } else { - g_warning("Cannot build filter renderer: missing builder"); - } + +// if (((SPFilterPrimitiveClass*) G_OBJECT_GET_CLASS(primitive))->build_renderer) { +// ((SPFilterPrimitiveClass *) G_OBJECT_GET_CLASS(primitive))->build_renderer(primitive, nr_filter); +// } else { +// g_warning("Cannot build filter renderer: missing builder"); +// } // CPPIFY: => FilterPrimitive should be abstract. + primitive->build_renderer(nr_filter); } primitive_obj = primitive_obj->next; } diff --git a/src/sp-filter.h b/src/sp-filter.h index 5afe47438..0d087c5bf 100644 --- a/src/sp-filter.h +++ b/src/sp-filter.h @@ -21,11 +21,8 @@ #include <glibmm/ustring.h> -#define SP_TYPE_FILTER (sp_filter_get_type()) -#define SP_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_FILTER, SPFilter)) -#define SP_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_FILTER, SPFilterClass)) -#define SP_IS_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_FILTER)) -#define SP_IS_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_FILTER)) +#define SP_FILTER(obj) (dynamic_cast<SPFilter*>((SPObject*)obj)) +#define SP_IS_FILTER(obj) (dynamic_cast<const SPFilter*>((SPObject*)obj) != NULL) #define SP_FILTER_FILTER_UNITS(f) (SP_FILTER(f)->filterUnits) #define SP_FILTER_PRIMITIVE_UNITS(f) (SP_FILTER(f)->primitiveUnits) @@ -36,13 +33,16 @@ class Filter; } } class SPFilterReference; -struct SPFilterPrimitive; +class SPFilterPrimitive; struct ltstr { bool operator()(const char* s1, const char* s2) const; }; -struct SPFilter : public SPObject { +class SPFilter : public SPObject { +public: + SPFilter(); + virtual ~SPFilter(); SPFilterUnits filterUnits; guint filterUnits_set : 1; @@ -60,13 +60,20 @@ struct SPFilter : public SPObject { std::map<gchar *, int, ltstr>* _image_name; int _image_number_next; -}; -struct SPFilterClass { - SPObjectClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node* child); -GType sp_filter_get_type(); + virtual void set(unsigned int key, const gchar* value); + + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); +}; void sp_filter_set_filter_units(SPFilter *filter, SPFilterUnits filterUnits); void sp_filter_set_primitive_units(SPFilter *filter, SPFilterUnits filterUnits); diff --git a/src/sp-flowdiv.cpp b/src/sp-flowdiv.cpp index c588335d8..867e68441 100644 --- a/src/sp-flowdiv.cpp +++ b/src/sp-flowdiv.cpp @@ -6,91 +6,74 @@ #endif #include "xml/repr.h" -//#include "svg/svg.h" - -//#include "style.h" - #include "sp-flowdiv.h" #include "sp-string.h" #include "document.h" -static void sp_flowdiv_release (SPObject *object); -static Inkscape::XML::Node *sp_flowdiv_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_flowdiv_update (SPObject *object, SPCtx *ctx, unsigned int flags); -static void sp_flowdiv_modified (SPObject *object, guint flags); -static void sp_flowdiv_build (SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr); -static void sp_flowdiv_set (SPObject *object, unsigned int key, const gchar *value); - -static void sp_flowtspan_release (SPObject *object); -static Inkscape::XML::Node *sp_flowtspan_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_flowtspan_update (SPObject *object, SPCtx *ctx, unsigned int flags); -static void sp_flowtspan_modified (SPObject *object, guint flags); -static void sp_flowtspan_build (SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr); -static void sp_flowtspan_set (SPObject *object, unsigned int key, const gchar *value); - -static void sp_flowpara_release (SPObject *object); -static Inkscape::XML::Node *sp_flowpara_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_flowpara_update (SPObject *object, SPCtx *ctx, unsigned int flags); -static void sp_flowpara_modified (SPObject *object, guint flags); -static void sp_flowpara_build (SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr); -static void sp_flowpara_set (SPObject *object, unsigned int key, const gchar *value); - -static void sp_flowline_release (SPObject *object); -static Inkscape::XML::Node *sp_flowline_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_flowline_modified (SPObject *object, guint flags); - -static void sp_flowregionbreak_release (SPObject *object); -static Inkscape::XML::Node *sp_flowregionbreak_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_flowregionbreak_modified (SPObject *object, guint flags); - -G_DEFINE_TYPE(SPFlowdiv, sp_flowdiv, SP_TYPE_ITEM); - -static void sp_flowdiv_class_init(SPFlowdivClass *klass) -{ - SPObjectClass *sp_object_class = reinterpret_cast<SPObjectClass *>(klass); - - sp_object_class->build = sp_flowdiv_build; - sp_object_class->set = sp_flowdiv_set; - sp_object_class->release = sp_flowdiv_release; - sp_object_class->write = sp_flowdiv_write; - sp_object_class->update = sp_flowdiv_update; - sp_object_class->modified = sp_flowdiv_modified; -} - -static void sp_flowdiv_init(SPFlowdiv */*group*/) -{ -} - -static void sp_flowdiv_release(SPObject *object) -{ - if (reinterpret_cast<SPObjectClass *>(sp_flowdiv_parent_class)->release) { - reinterpret_cast<SPObjectClass *>(sp_flowdiv_parent_class)->release(object); - } +#include "sp-factory.h" + +namespace { + SPObject* createFlowdiv() { + return new SPFlowdiv(); + } + + SPObject* createFlowtspan() { + return new SPFlowtspan(); + } + + SPObject* createFlowpara() { + return new SPFlowpara(); + } + + SPObject* createFlowline() { + return new SPFlowline(); + } + + SPObject* createFlowregionbreak() { + return new SPFlowregionbreak(); + } + + bool flowdivRegistered = SPFactory::instance().registerObject("svg:flowDiv", createFlowdiv); + bool flowtspanRegistered = SPFactory::instance().registerObject("svg:flowSpan", createFlowtspan); + bool flowparaRegistered = SPFactory::instance().registerObject("svg:flowPara", createFlowpara); + bool flowlineRegistered = SPFactory::instance().registerObject("svg:flowLine", createFlowline); + bool flowregionbreakRegistered = SPFactory::instance().registerObject("svg:flowRegionBreak", createFlowregionbreak); +} + +SPFlowdiv::SPFlowdiv() : SPItem() { +} + +SPFlowdiv::~SPFlowdiv() { +} + +void SPFlowdiv::release() { + SPItem::release(); } -static void sp_flowdiv_update(SPObject *object, SPCtx *ctx, unsigned int flags) -{ +void SPFlowdiv::update(SPCtx *ctx, unsigned int flags) { SPItemCtx *ictx = reinterpret_cast<SPItemCtx *>(ctx); SPItemCtx cctx = *ictx; - if (reinterpret_cast<SPObjectClass *>(sp_flowdiv_parent_class)->update) { - reinterpret_cast<SPObjectClass *>(sp_flowdiv_parent_class)->update(object, ctx, flags); - } + SPItem::update(ctx, flags); if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; GSList* l = NULL; - for (SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { - g_object_ref( G_OBJECT(child) ); + for (SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { + sp_object_ref(child); l = g_slist_prepend(l, child); } + l = g_slist_reverse(l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { if (SP_IS_ITEM(child)) { SPItem const &chi = *SP_ITEM(child); @@ -101,62 +84,63 @@ static void sp_flowdiv_update(SPObject *object, SPCtx *ctx, unsigned int flags) child->updateDisplay(ctx, flags); } } - g_object_unref( G_OBJECT(child) ); + + sp_object_unref(child); } } -static void sp_flowdiv_modified(SPObject *object, guint flags) -{ - if (reinterpret_cast<SPObjectClass *>(sp_flowdiv_parent_class)->modified) { - reinterpret_cast<SPObjectClass *>(sp_flowdiv_parent_class)->modified(object, flags); - } +void SPFlowdiv::modified(unsigned int flags) { + SPItem::modified(flags); if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; GSList *l = NULL; - for ( SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { - g_object_ref( G_OBJECT(child) ); + for ( SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { + sp_object_ref(child); l = g_slist_prepend(l, child); } + l = g_slist_reverse (l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->emitModified(flags); } - g_object_unref( G_OBJECT(child) ); + + sp_object_unref(child); } } -static void sp_flowdiv_build(SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr) -{ - object->_requireSVGVersion(Inkscape::Version(1, 2)); - if (reinterpret_cast<SPObjectClass *>(sp_flowdiv_parent_class)->build) { - reinterpret_cast<SPObjectClass *>(sp_flowdiv_parent_class)->build(object, doc, repr); - } +void SPFlowdiv::build(SPDocument *doc, Inkscape::XML::Node *repr) { + this->_requireSVGVersion(Inkscape::Version(1, 2)); + + SPItem::build(doc, repr); } -static void sp_flowdiv_set(SPObject *object, unsigned int key, const gchar *value) -{ - if (reinterpret_cast<SPObjectClass *>(sp_flowdiv_parent_class)->set) { - reinterpret_cast<SPObjectClass *>(sp_flowdiv_parent_class)->set(object, key, value); - } +void SPFlowdiv::set(unsigned int key, const gchar* value) { + SPItem::set(key, value); } -static Inkscape::XML::Node *sp_flowdiv_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ + +Inkscape::XML::Node* SPFlowdiv::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ( flags & SP_OBJECT_WRITE_BUILD ) { if ( repr == NULL ) { repr = xml_doc->createElement("svg:flowDiv"); } + GSList *l = NULL; - for (SPObject* child = object->firstChild() ; child ; child = child->getNext() ) { + + for (SPObject* child = this->firstChild() ; child ; child = child->getNext() ) { Inkscape::XML::Node* c_repr = NULL; + if ( SP_IS_FLOWTSPAN (child) ) { c_repr = child->updateRepr(xml_doc, NULL, flags); } else if ( SP_IS_FLOWPARA(child) ) { @@ -164,17 +148,19 @@ static Inkscape::XML::Node *sp_flowdiv_write(SPObject *object, Inkscape::XML::Do } else if ( SP_IS_STRING(child) ) { c_repr = xml_doc->createTextNode(SP_STRING(child)->string.c_str()); } + if ( c_repr ) { l = g_slist_prepend (l, c_repr); } } + while ( l ) { repr->addChild((Inkscape::XML::Node *) l->data, NULL); Inkscape::GC::release((Inkscape::XML::Node *) l->data); l = g_slist_remove(l, l->data); } } else { - for ( SPObject* child = object->firstChild() ; child ; child = child->getNext() ) { + for ( SPObject* child = this->firstChild() ; child ; child = child->getNext() ) { if ( SP_IS_FLOWTSPAN (child) ) { child->updateRepr(flags); } else if ( SP_IS_FLOWPARA(child) ) { @@ -185,9 +171,7 @@ static Inkscape::XML::Node *sp_flowdiv_write(SPObject *object, Inkscape::XML::Do } } - if (((SPObjectClass *) (sp_flowdiv_parent_class))->write) { - ((SPObjectClass *) (sp_flowdiv_parent_class))->write(object, xml_doc, repr, flags); - } + SPItem::write(xml_doc, repr, flags); return repr; } @@ -196,54 +180,41 @@ static Inkscape::XML::Node *sp_flowdiv_write(SPObject *object, Inkscape::XML::Do /* * */ -G_DEFINE_TYPE(SPFlowtspan, sp_flowtspan, SP_TYPE_ITEM); -static void sp_flowtspan_class_init(SPFlowtspanClass *klass) -{ - SPObjectClass *sp_object_class = reinterpret_cast<SPObjectClass *>(klass); - - sp_object_class->build = sp_flowtspan_build; - sp_object_class->set = sp_flowtspan_set; - sp_object_class->release = sp_flowtspan_release; - sp_object_class->write = sp_flowtspan_write; - sp_object_class->update = sp_flowtspan_update; - sp_object_class->modified = sp_flowtspan_modified; +SPFlowtspan::SPFlowtspan() : SPItem() { } -static void sp_flowtspan_init(SPFlowtspan */*group*/) -{ +SPFlowtspan::~SPFlowtspan() { } -static void sp_flowtspan_release(SPObject *object) -{ - if (reinterpret_cast<SPObjectClass *>(sp_flowtspan_parent_class)->release) { - reinterpret_cast<SPObjectClass *>(sp_flowtspan_parent_class)->release(object); - } +void SPFlowtspan::release() { + SPItem::release(); } -static void sp_flowtspan_update(SPObject *object, SPCtx *ctx, unsigned int flags) -{ +void SPFlowtspan::update(SPCtx *ctx, unsigned int flags) { SPItemCtx *ictx = reinterpret_cast<SPItemCtx *>(ctx); SPItemCtx cctx = *ictx; - if (reinterpret_cast<SPObjectClass *>(sp_flowtspan_parent_class)->update) { - reinterpret_cast<SPObjectClass *>(sp_flowtspan_parent_class)->update(object, ctx, flags); - } + SPItem::update(ctx, flags); if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; GSList* l = NULL; - for ( SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { - g_object_ref( G_OBJECT(child) ); + for ( SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { + sp_object_ref(child); l = g_slist_prepend(l, child); } + l = g_slist_reverse (l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { if (SP_IS_ITEM(child)) { SPItem const &chi = *SP_ITEM(child); @@ -254,60 +225,60 @@ static void sp_flowtspan_update(SPObject *object, SPCtx *ctx, unsigned int flags child->updateDisplay(ctx, flags); } } - g_object_unref( G_OBJECT(child) ); + + sp_object_unref(child); } } -static void sp_flowtspan_modified(SPObject *object, guint flags) -{ - if (reinterpret_cast<SPObjectClass *>(sp_flowtspan_parent_class)->modified) { - reinterpret_cast<SPObjectClass *>(sp_flowtspan_parent_class)->modified(object, flags); - } +void SPFlowtspan::modified(unsigned int flags) { + SPItem::modified(flags); if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; GSList *l = NULL; - for ( SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { - g_object_ref( G_OBJECT(child) ); + for ( SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { + sp_object_ref(child); l = g_slist_prepend(l, child); } + l = g_slist_reverse (l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->emitModified(flags); } - g_object_unref( G_OBJECT(child) ); + + sp_object_unref(child); } } -static void sp_flowtspan_build(SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr) -{ - if (reinterpret_cast<SPObjectClass *>(sp_flowtspan_parent_class)->build) { - reinterpret_cast<SPObjectClass *>(sp_flowtspan_parent_class)->build(object, doc, repr); - } + +void SPFlowtspan::build(SPDocument *doc, Inkscape::XML::Node *repr) { + SPItem::build(doc, repr); } -static void sp_flowtspan_set(SPObject *object, unsigned int key, const gchar *value) -{ - if (reinterpret_cast<SPObjectClass *>(sp_flowtspan_parent_class)->set) { - reinterpret_cast<SPObjectClass *>(sp_flowtspan_parent_class)->set(object, key, value); - } +void SPFlowtspan::set(unsigned int key, const gchar* value) { + SPItem::set(key, value); } -static Inkscape::XML::Node *sp_flowtspan_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node *SPFlowtspan::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ( flags&SP_OBJECT_WRITE_BUILD ) { if ( repr == NULL ) { repr = xml_doc->createElement("svg:flowSpan"); } + GSList *l = NULL; - for ( SPObject* child = object->firstChild() ; child ; child = child->getNext() ) { + + for ( SPObject* child = this->firstChild() ; child ; child = child->getNext() ) { Inkscape::XML::Node* c_repr = NULL; + if ( SP_IS_FLOWTSPAN(child) ) { c_repr = child->updateRepr(xml_doc, NULL, flags); } else if ( SP_IS_FLOWPARA(child) ) { @@ -315,17 +286,19 @@ static Inkscape::XML::Node *sp_flowtspan_write(SPObject *object, Inkscape::XML:: } else if ( SP_IS_STRING(child) ) { c_repr = xml_doc->createTextNode(SP_STRING(child)->string.c_str()); } + if ( c_repr ) { l = g_slist_prepend(l, c_repr); } } + while ( l ) { repr->addChild((Inkscape::XML::Node *) l->data, NULL); Inkscape::GC::release((Inkscape::XML::Node *) l->data); l = g_slist_remove(l, l->data); } } else { - for ( SPObject* child = object->firstChild() ; child ; child = child->getNext() ) { + for ( SPObject* child = this->firstChild() ; child ; child = child->getNext() ) { if ( SP_IS_FLOWTSPAN(child) ) { child->updateRepr(flags); } else if ( SP_IS_FLOWPARA(child) ) { @@ -336,66 +309,49 @@ static Inkscape::XML::Node *sp_flowtspan_write(SPObject *object, Inkscape::XML:: } } - if (((SPObjectClass *) (sp_flowtspan_parent_class))->write) { - ((SPObjectClass *) (sp_flowtspan_parent_class))->write(object, xml_doc, repr, flags); - } + SPItem::write(xml_doc, repr, flags); return repr; } - /* * */ -G_DEFINE_TYPE(SPFlowpara, sp_flowpara, SP_TYPE_ITEM); - -static void sp_flowpara_class_init(SPFlowparaClass *klass) -{ - SPObjectClass *sp_object_class = reinterpret_cast<SPObjectClass *>(klass); - - sp_object_class->build = sp_flowpara_build; - sp_object_class->set = sp_flowpara_set; - sp_object_class->release = sp_flowpara_release; - sp_object_class->write = sp_flowpara_write; - sp_object_class->update = sp_flowpara_update; - sp_object_class->modified = sp_flowpara_modified; +SPFlowpara::SPFlowpara() : SPItem() { } -static void sp_flowpara_init (SPFlowpara */*group*/) -{ +SPFlowpara::~SPFlowpara() { } -static void sp_flowpara_release(SPObject *object) -{ - if (reinterpret_cast<SPObjectClass *>(sp_flowpara_parent_class)->release) { - reinterpret_cast<SPObjectClass *>(sp_flowpara_parent_class)->release(object); - } +void SPFlowpara::release() { + SPItem::release(); } -static void sp_flowpara_update(SPObject *object, SPCtx *ctx, unsigned int flags) -{ +void SPFlowpara::update(SPCtx *ctx, unsigned int flags) { SPItemCtx *ictx = reinterpret_cast<SPItemCtx *>(ctx); SPItemCtx cctx = *ictx; - if (reinterpret_cast<SPObjectClass *>(sp_flowpara_parent_class)->update) { - reinterpret_cast<SPObjectClass *>(sp_flowpara_parent_class)->update(object, ctx, flags); - } + SPItem::update(ctx, flags); if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; GSList* l = NULL; - for ( SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { - g_object_ref( G_OBJECT(child) ); + for ( SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { + sp_object_ref(child); l = g_slist_prepend(l, child); } + l = g_slist_reverse (l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { if (SP_IS_ITEM(child)) { SPItem const &chi = *SP_ITEM(child); @@ -406,58 +362,60 @@ static void sp_flowpara_update(SPObject *object, SPCtx *ctx, unsigned int flags) child->updateDisplay(ctx, flags); } } - g_object_unref( G_OBJECT(child) ); + + sp_object_unref(child); } } -static void sp_flowpara_modified(SPObject *object, guint flags) -{ - if (reinterpret_cast<SPObjectClass *>(sp_flowpara_parent_class)->modified) { - reinterpret_cast<SPObjectClass *>(sp_flowpara_parent_class)->modified(object, flags); - } +void SPFlowpara::modified(unsigned int flags) { + SPItem::modified(flags); if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; GSList *l = NULL; - for ( SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { - g_object_ref( G_OBJECT(child) ); + for ( SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { + sp_object_ref(child); l = g_slist_prepend(l, child); } + l = g_slist_reverse (l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->emitModified(flags); } - g_object_unref( G_OBJECT(child) ); + + sp_object_unref(child); } } -static void sp_flowpara_build(SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr) -{ - if (reinterpret_cast<SPObjectClass *>(sp_flowpara_parent_class)->build) { - reinterpret_cast<SPObjectClass *>(sp_flowpara_parent_class)->build(object, doc, repr); - } + +void SPFlowpara::build(SPDocument *doc, Inkscape::XML::Node *repr) { + SPItem::build(doc, repr); } -static void sp_flowpara_set(SPObject *object, unsigned int key, const gchar *value) -{ - if (reinterpret_cast<SPObjectClass *>(sp_flowpara_parent_class)->set) { - reinterpret_cast<SPObjectClass *>(sp_flowpara_parent_class)->set(object, key, value); - } +void SPFlowpara::set(unsigned int key, const gchar* value) { + SPItem::set(key, value); } -static Inkscape::XML::Node *sp_flowpara_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node *SPFlowpara::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ( flags&SP_OBJECT_WRITE_BUILD ) { - if ( repr == NULL ) repr = xml_doc->createElement("svg:flowPara"); + if ( repr == NULL ) { + repr = xml_doc->createElement("svg:flowPara"); + } + GSList *l = NULL; - for ( SPObject* child = object->firstChild() ; child ; child = child->getNext() ) { + + for ( SPObject* child = this->firstChild() ; child ; child = child->getNext() ) { Inkscape::XML::Node* c_repr = NULL; + if ( SP_IS_FLOWTSPAN(child) ) { c_repr = child->updateRepr(xml_doc, NULL, flags); } else if ( SP_IS_FLOWPARA(child) ) { @@ -465,17 +423,19 @@ static Inkscape::XML::Node *sp_flowpara_write(SPObject *object, Inkscape::XML::D } else if ( SP_IS_STRING(child) ) { c_repr = xml_doc->createTextNode(SP_STRING(child)->string.c_str()); } + if ( c_repr ) { l = g_slist_prepend(l, c_repr); } } + while ( l ) { repr->addChild((Inkscape::XML::Node *) l->data, NULL); Inkscape::GC::release((Inkscape::XML::Node *) l->data); l = g_slist_remove(l, l->data); } } else { - for ( SPObject* child = object->firstChild() ; child ; child = child->getNext() ) { + for ( SPObject* child = this->firstChild() ; child ; child = child->getNext() ) { if ( SP_IS_FLOWTSPAN(child) ) { child->updateRepr(flags); } else if ( SP_IS_FLOWPARA(child) ) { @@ -486,119 +446,86 @@ static Inkscape::XML::Node *sp_flowpara_write(SPObject *object, Inkscape::XML::D } } - if (((SPObjectClass *) (sp_flowpara_parent_class))->write) { - ((SPObjectClass *) (sp_flowpara_parent_class))->write(object, xml_doc, repr, flags); - } + SPItem::write(xml_doc, repr, flags); return repr; } + /* * */ -G_DEFINE_TYPE(SPFlowline, sp_flowline, SP_TYPE_OBJECT); - -static void sp_flowline_class_init(SPFlowlineClass *klass) -{ - SPObjectClass *sp_object_class = reinterpret_cast<SPObjectClass *>(klass); - sp_object_class->release = sp_flowline_release; - sp_object_class->write = sp_flowline_write; - sp_object_class->modified = sp_flowline_modified; +SPFlowline::SPFlowline() : SPObject() { } -static void sp_flowline_init(SPFlowline */*group*/) -{ +SPFlowline::~SPFlowline() { } -static void sp_flowline_release(SPObject *object) -{ - if (reinterpret_cast<SPObjectClass *>(sp_flowline_parent_class)->release) { - reinterpret_cast<SPObjectClass *>(sp_flowline_parent_class)->release(object); - } +void SPFlowline::release() { + SPObject::release(); } -static void sp_flowline_modified(SPObject *object, guint flags) -{ - if (reinterpret_cast<SPObjectClass *>(sp_flowline_parent_class)->modified) { - reinterpret_cast<SPObjectClass *>(sp_flowline_parent_class)->modified(object, flags); - } +void SPFlowline::modified(unsigned int flags) { + SPObject::modified(flags); - if (flags & SP_OBJECT_MODIFIED_FLAG) { - flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; - } - flags &= SP_OBJECT_MODIFIED_CASCADE; + if (flags & SP_OBJECT_MODIFIED_FLAG) { + flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; + } + + flags &= SP_OBJECT_MODIFIED_CASCADE; } -static Inkscape::XML::Node *sp_flowline_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node *SPFlowline::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ( flags & SP_OBJECT_WRITE_BUILD ) { if ( repr == NULL ) { repr = xml_doc->createElement("svg:flowLine"); } - } else { } - if (reinterpret_cast<SPObjectClass *>(sp_flowline_parent_class)->write) { - reinterpret_cast<SPObjectClass *>(sp_flowline_parent_class)->write(object, xml_doc, repr, flags); - } + SPObject::write(xml_doc, repr, flags); return repr; } + /* * */ -G_DEFINE_TYPE(SPFlowregionbreak, sp_flowregionbreak, SP_TYPE_OBJECT); -static void sp_flowregionbreak_class_init(SPFlowregionbreakClass *klass) -{ - SPObjectClass *sp_object_class = reinterpret_cast<SPObjectClass *>(klass); - - sp_object_class->release = sp_flowregionbreak_release; - sp_object_class->write = sp_flowregionbreak_write; - sp_object_class->modified = sp_flowregionbreak_modified; +SPFlowregionbreak::SPFlowregionbreak() : SPObject() { } -static void sp_flowregionbreak_init(SPFlowregionbreak */*group*/) -{ +SPFlowregionbreak::~SPFlowregionbreak() { } -static void sp_flowregionbreak_release(SPObject *object) -{ - if (reinterpret_cast<SPObjectClass *>(sp_flowregionbreak_parent_class)->release) { - reinterpret_cast<SPObjectClass *>(sp_flowregionbreak_parent_class)->release(object); - } +void SPFlowregionbreak::release() { + SPObject::release(); } -static void sp_flowregionbreak_modified(SPObject *object, guint flags) -{ - if (reinterpret_cast<SPObjectClass *>(sp_flowregionbreak_parent_class)->modified) { - reinterpret_cast<SPObjectClass *>(sp_flowregionbreak_parent_class)->modified(object, flags); - } +void SPFlowregionbreak::modified(unsigned int flags) { + SPObject::modified(flags); - if (flags & SP_OBJECT_MODIFIED_FLAG) { - flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; - } - flags &= SP_OBJECT_MODIFIED_CASCADE; + if (flags & SP_OBJECT_MODIFIED_FLAG) { + flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; + } + + flags &= SP_OBJECT_MODIFIED_CASCADE; } -static Inkscape::XML::Node *sp_flowregionbreak_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node *SPFlowregionbreak::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ( flags & SP_OBJECT_WRITE_BUILD ) { if ( repr == NULL ) { repr = xml_doc->createElement("svg:flowLine"); } - } else { } - if (reinterpret_cast<SPObjectClass *>(sp_flowregionbreak_parent_class)->write) { - reinterpret_cast<SPObjectClass *>(sp_flowregionbreak_parent_class)->write(object, xml_doc, repr, flags); - } + SPObject::write(xml_doc, repr, flags); return repr; } + /* Local Variables: mode:c++ diff --git a/src/sp-flowdiv.h b/src/sp-flowdiv.h index c01ada3b0..d00cfc51b 100644 --- a/src/sp-flowdiv.h +++ b/src/sp-flowdiv.h @@ -7,78 +7,90 @@ #include "sp-object.h" #include "sp-item.h" -#define SP_TYPE_FLOWDIV (sp_flowdiv_get_type ()) -#define SP_FLOWDIV(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_FLOWDIV, SPFlowdiv)) -#define SP_FLOWDIV_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_FLOWDIV, SPFlowdivClass)) -#define SP_IS_FLOWDIV(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_FLOWDIV)) -#define SP_IS_FLOWDIV_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_FLOWDIV)) - -#define SP_TYPE_FLOWTSPAN (sp_flowtspan_get_type ()) -#define SP_FLOWTSPAN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_FLOWTSPAN, SPFlowtspan)) -#define SP_FLOWTSPAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_FLOWTSPAN, SPFlowtspanClass)) -#define SP_IS_FLOWTSPAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_FLOWTSPAN)) -#define SP_IS_FLOWTSPAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_FLOWTSPAN)) - -#define SP_TYPE_FLOWPARA (sp_flowpara_get_type ()) -#define SP_FLOWPARA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_FLOWPARA, SPFlowpara)) -#define SP_FLOWPARA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_FLOWPARA, SPFlowparaClass)) -#define SP_IS_FLOWPARA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_FLOWPARA)) -#define SP_IS_FLOWPARA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_FLOWPARA)) - -#define SP_TYPE_FLOWLINE (sp_flowline_get_type ()) -#define SP_FLOWLINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_FLOWLINE, SPFlowline)) -#define SP_FLOWLINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_FLOWLINE, SPFlowlineClass)) -#define SP_IS_FLOWLINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_FLOWLINE)) -#define SP_IS_FLOWLINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_FLOWLINE)) - -#define SP_TYPE_FLOWREGIONBREAK (sp_flowregionbreak_get_type ()) -#define SP_FLOWREGIONBREAK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_FLOWREGIONBREAK, SPFlowregionbreak)) -#define SP_FLOWREGIONBREAK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_FLOWREGIONBREAK, SPFlowregionbreakClass)) -#define SP_IS_FLOWREGIONBREAK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_FLOWREGIONBREAK)) -#define SP_IS_FLOWREGIONBREAK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_FLOWREGIONBREAK)) +#define SP_FLOWDIV(obj) (dynamic_cast<SPFlowdiv*>((SPObject*)obj)) +#define SP_IS_FLOWDIV(obj) (dynamic_cast<const SPFlowdiv*>((SPObject*)obj) != NULL) + +#define SP_FLOWTSPAN(obj) (dynamic_cast<SPFlowtspan*>((SPObject*)obj)) +#define SP_IS_FLOWTSPAN(obj) (dynamic_cast<const SPFlowtspan*>((SPObject*)obj) != NULL) + +#define SP_FLOWPARA(obj) (dynamic_cast<SPFlowpara*>((SPObject*)obj)) +#define SP_IS_FLOWPARA(obj) (dynamic_cast<const SPFlowpara*>((SPObject*)obj) != NULL) + +#define SP_FLOWLINE(obj) (dynamic_cast<SPFlowline*>((SPObject*)obj)) +#define SP_IS_FLOWLINE(obj) (dynamic_cast<const SPFlowline*>((SPObject*)obj) != NULL) + +#define SP_FLOWREGIONBREAK(obj) (dynamic_cast<SPFlowregionbreak*>((SPObject*)obj)) +#define SP_IS_FLOWREGIONBREAK(obj) (dynamic_cast<const SPFlowregionbreak*>((SPObject*)obj) != NULL) // these 3 are derivatives of SPItem to get the automatic style handling -struct SPFlowdiv : public SPItem { +class SPFlowdiv : public SPItem { +public: + SPFlowdiv(); + virtual ~SPFlowdiv(); + +protected: + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void release(); + virtual void update(SPCtx* ctx, guint flags); + virtual void modified(unsigned int flags); + + virtual void set(unsigned int key, gchar const* value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); }; -struct SPFlowtspan : public SPItem { -}; +class SPFlowtspan : public SPItem { +public: + SPFlowtspan(); + virtual ~SPFlowtspan(); -struct SPFlowpara : public SPItem { -}; +protected: + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void release(); + virtual void update(SPCtx* ctx, guint flags); + virtual void modified(unsigned int flags); -// these do not need any style -struct SPFlowline : public SPObject { + virtual void set(unsigned int key, gchar const* value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); }; -struct SPFlowregionbreak : public SPObject { -}; +class SPFlowpara : public SPItem { +public: + SPFlowpara(); + virtual ~SPFlowpara(); +protected: + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void release(); + virtual void update(SPCtx* ctx, guint flags); + virtual void modified(unsigned int flags); -struct SPFlowdivClass { - SPItemClass parent_class; + virtual void set(unsigned int key, gchar const* value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); }; -struct SPFlowtspanClass { - SPItemClass parent_class; -}; +// these do not need any style +class SPFlowline : public SPObject { +public: + SPFlowline(); + virtual ~SPFlowline(); -struct SPFlowparaClass { - SPItemClass parent_class; -}; +protected: + virtual void release(); + virtual void modified(unsigned int flags); -struct SPFlowlineClass { - SPObjectClass parent_class; + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); }; -struct SPFlowregionbreakClass { - SPObjectClass parent_class; -}; +class SPFlowregionbreak : public SPObject { +public: + SPFlowregionbreak(); + virtual ~SPFlowregionbreak(); + +protected: + virtual void release(); + virtual void modified(unsigned int flags); -GType sp_flowdiv_get_type (void); -GType sp_flowtspan_get_type (void); -GType sp_flowpara_get_type (void); -GType sp_flowline_get_type (void); -GType sp_flowregionbreak_get_type (void); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); +}; #endif diff --git a/src/sp-flowregion.cpp b/src/sp-flowregion.cpp index 627907cef..3a0aef6be 100644 --- a/src/sp-flowregion.cpp +++ b/src/sp-flowregion.cpp @@ -20,118 +20,79 @@ #include "display/canvas-bpath.h" - #include "livarot/Path.h" #include "livarot/Shape.h" -static void sp_flowregion_dispose (GObject *object); - -static void sp_flowregion_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref); -static void sp_flowregion_remove_child (SPObject * object, Inkscape::XML::Node * child); -static void sp_flowregion_update (SPObject *object, SPCtx *ctx, guint flags); -static void sp_flowregion_modified (SPObject *object, guint flags); -static Inkscape::XML::Node *sp_flowregion_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -static gchar * sp_flowregion_description (SPItem * item); - -G_DEFINE_TYPE(SPFlowregion, sp_flowregion, SP_TYPE_ITEM); - -static void sp_flowregionexclude_dispose (GObject *object); +#include "sp-factory.h" -static void sp_flowregionexclude_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref); -static void sp_flowregionexclude_remove_child (SPObject * object, Inkscape::XML::Node * child); -static void sp_flowregionexclude_update (SPObject *object, SPCtx *ctx, guint flags); -static void sp_flowregionexclude_modified (SPObject *object, guint flags); -static Inkscape::XML::Node *sp_flowregionexclude_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); +namespace { + SPObject* createFlowregion() { + return new SPFlowregion(); + } -static gchar * sp_flowregionexclude_description (SPItem * item); + SPObject* createFlowregionExclude() { + return new SPFlowregionExclude(); + } + bool flowregionRegistered = SPFactory::instance().registerObject("svg:flowRegion", createFlowregion); + bool flowregionExcludeRegistered = SPFactory::instance().registerObject("svg:flowRegionExclude", createFlowregionExclude); +} static void GetDest(SPObject* child,Shape **computed); -static void -sp_flowregion_class_init (SPFlowregionClass *klass) -{ - GObjectClass * object_class; - SPObjectClass * sp_object_class; - SPItemClass * item_class; - - object_class = (GObjectClass *) klass; - sp_object_class = (SPObjectClass *) klass; - item_class = (SPItemClass *) klass; - object_class->dispose = sp_flowregion_dispose; - - sp_object_class->child_added = sp_flowregion_child_added; - sp_object_class->remove_child = sp_flowregion_remove_child; - sp_object_class->update = sp_flowregion_update; - sp_object_class->modified = sp_flowregion_modified; - sp_object_class->write = sp_flowregion_write; - - item_class->description = sp_flowregion_description; -} - -static void -sp_flowregion_init (SPFlowregion *group) -{ - new (&group->computed) std::vector<Shape*>; +SPFlowregion::SPFlowregion() : SPItem() { + //new (&this->computed) std::vector<Shape*>; } -static void -sp_flowregion_dispose(GObject *object) -{ - SPFlowregion *group=(SPFlowregion *)object; - for (std::vector<Shape*>::iterator it = group->computed.begin() ; it != group->computed.end() ; ++it) +SPFlowregion::~SPFlowregion() { + for (std::vector<Shape*>::iterator it = this->computed.begin() ; it != this->computed.end() ; ++it) { delete *it; - group->computed.~vector<Shape*>(); + } + + //this->computed.~vector<Shape*>(); } -static void -sp_flowregion_child_added(SPObject *object, - Inkscape::XML::Node *child, - Inkscape::XML::Node *ref) -{ - SP_OBJECT_CLASS (sp_flowregion_parent_class)->child_added (object, child, ref); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); +void SPFlowregion::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { + SPItem::child_added(child, ref); + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } /* fixme: hide (Lauris) */ -static void -sp_flowregion_remove_child (SPObject * object, Inkscape::XML::Node * child) -{ - if (((SPObjectClass *) (sp_flowregion_parent_class))->remove_child) - (* ((SPObjectClass *) (sp_flowregion_parent_class))->remove_child) (object, child); +void SPFlowregion::remove_child(Inkscape::XML::Node * child) { + SPItem::remove_child(child); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } -static void sp_flowregion_update(SPObject *object, SPCtx *ctx, unsigned int flags) -{ - SPFlowregion *group = SP_FLOWREGION(object); - +void SPFlowregion::update(SPCtx *ctx, unsigned int flags) { SPItemCtx *ictx = reinterpret_cast<SPItemCtx *>(ctx); SPItemCtx cctx = *ictx; - if (((SPObjectClass *) (sp_flowregion_parent_class))->update) { - ((SPObjectClass *) (sp_flowregion_parent_class))->update (object, ctx, flags); - } + SPItem::update(ctx, flags); if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; GSList *l = NULL; - for ( SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { - g_object_ref( G_OBJECT(child) ); + + for ( SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { + sp_object_ref(child); l = g_slist_prepend(l, child); } + l = g_slist_reverse(l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { if (SP_IS_ITEM (child)) { SPItem const &chi = *SP_ITEM(child); @@ -142,10 +103,11 @@ static void sp_flowregion_update(SPObject *object, SPCtx *ctx, unsigned int flag child->updateDisplay(ctx, flags); } } - g_object_unref (G_OBJECT(child)); + + sp_object_unref(child); } - group->UpdateComputed(); + this->UpdateComputed(); } void SPFlowregion::UpdateComputed(void) @@ -162,42 +124,45 @@ void SPFlowregion::UpdateComputed(void) } } -static void -sp_flowregion_modified(SPObject *object, - guint flags) -{ +void SPFlowregion::modified(guint flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; GSList *l = NULL; - for ( SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { - g_object_ref( G_OBJECT(child) ); + + for ( SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { + sp_object_ref(child); l = g_slist_prepend(l, child); } + l = g_slist_reverse(l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->emitModified(flags); } - g_object_unref( G_OBJECT(child) ); + + sp_object_unref(child); } } -static Inkscape::XML::Node *sp_flowregion_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node *SPFlowregion::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if (flags & SP_OBJECT_WRITE_BUILD) { if ( repr == NULL ) { repr = xml_doc->createElement("svg:flowRegion"); } GSList *l = NULL; - for ( SPObject *child = object->firstChild() ; child; child = child->getNext() ) { + for ( SPObject *child = this->firstChild() ; child; child = child->getNext() ) { if ( !SP_IS_TITLE(child) && !SP_IS_DESC(child) ) { Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags); + if (crepr) { l = g_slist_prepend(l, crepr); } @@ -211,23 +176,19 @@ static Inkscape::XML::Node *sp_flowregion_write(SPObject *object, Inkscape::XML: } } else { - for ( SPObject *child = object->firstChild() ; child; child = child->getNext() ) { + for ( SPObject *child = this->firstChild() ; child; child = child->getNext() ) { if ( !SP_IS_TITLE(child) && !SP_IS_DESC(child) ) { child->updateRepr(flags); } } } - if (((SPObjectClass *) (sp_flowregion_parent_class))->write) { - ((SPObjectClass *) (sp_flowregion_parent_class))->write (object, xml_doc, repr, flags); - } + SPItem::write(xml_doc, repr, flags); return repr; } - -static gchar *sp_flowregion_description(SPItem */*item*/) -{ +gchar* SPFlowregion::description() { // TRANSLATORS: "Flow region" is an area where text is allowed to flow return g_strdup_printf(_("Flow region")); } @@ -235,94 +196,57 @@ static gchar *sp_flowregion_description(SPItem */*item*/) /* * */ - -G_DEFINE_TYPE(SPFlowregionExclude, sp_flowregionexclude, SP_TYPE_ITEM); - -static void -sp_flowregionexclude_class_init (SPFlowregionExcludeClass *klass) -{ - GObjectClass * object_class; - SPObjectClass * sp_object_class; - SPItemClass * item_class; - - object_class = (GObjectClass *) klass; - sp_object_class = (SPObjectClass *) klass; - item_class = (SPItemClass *) klass; - - object_class->dispose = sp_flowregionexclude_dispose; - - sp_object_class->child_added = sp_flowregionexclude_child_added; - sp_object_class->remove_child = sp_flowregionexclude_remove_child; - sp_object_class->update = sp_flowregionexclude_update; - sp_object_class->modified = sp_flowregionexclude_modified; - sp_object_class->write = sp_flowregionexclude_write; - - item_class->description = sp_flowregionexclude_description; +SPFlowregionExclude::SPFlowregionExclude() : SPItem() { + this->computed = NULL; } -static void -sp_flowregionexclude_init (SPFlowregionExclude *group) -{ - group->computed = NULL; -} - -static void -sp_flowregionexclude_dispose(GObject *object) -{ - SPFlowregionExclude *group=(SPFlowregionExclude *)object; - if (group->computed) { - delete group->computed; - group->computed = NULL; +SPFlowregionExclude::~SPFlowregionExclude() { + if (this->computed) { + delete this->computed; + this->computed = NULL; } } -static void -sp_flowregionexclude_child_added(SPObject *object, - Inkscape::XML::Node *child, - Inkscape::XML::Node *ref) -{ - SP_OBJECT_CLASS (sp_flowregionexclude_parent_class)->child_added (object, child, ref); +void SPFlowregionExclude::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { + SPItem::child_added(child, ref); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } /* fixme: hide (Lauris) */ -static void -sp_flowregionexclude_remove_child (SPObject * object, Inkscape::XML::Node * child) -{ - if (((SPObjectClass *) (sp_flowregionexclude_parent_class))->remove_child) - (* ((SPObjectClass *) (sp_flowregionexclude_parent_class))->remove_child) (object, child); +void SPFlowregionExclude::remove_child(Inkscape::XML::Node * child) { + SPItem::remove_child(child); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } -static void sp_flowregionexclude_update(SPObject *object, SPCtx *ctx, unsigned int flags) -{ - SPFlowregionExclude *group = SP_FLOWREGIONEXCLUDE (object); - +void SPFlowregionExclude::update(SPCtx *ctx, unsigned int flags) { SPItemCtx *ictx = reinterpret_cast<SPItemCtx *>(ctx); SPItemCtx cctx = *ictx; - if (((SPObjectClass *) (sp_flowregionexclude_parent_class))->update) { - ((SPObjectClass *) (sp_flowregionexclude_parent_class))->update (object, ctx, flags); - } + SPItem::update(ctx, flags); if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; GSList *l = NULL; - for ( SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { - g_object_ref( G_OBJECT(child) ); + + for ( SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { + sp_object_ref(child); l = g_slist_prepend(l, child); } + l = g_slist_reverse (l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { if (SP_IS_ITEM (child)) { SPItem const &chi = *SP_ITEM(child); @@ -333,12 +257,14 @@ static void sp_flowregionexclude_update(SPObject *object, SPCtx *ctx, unsigned i child->updateDisplay(ctx, flags); } } - g_object_unref( G_OBJECT(child) ); + + sp_object_unref(child); } - group->UpdateComputed(); + this->UpdateComputed(); } + void SPFlowregionExclude::UpdateComputed(void) { if (computed) { @@ -351,41 +277,45 @@ void SPFlowregionExclude::UpdateComputed(void) } } -static void -sp_flowregionexclude_modified(SPObject *object, - guint flags) -{ +void SPFlowregionExclude::modified(guint flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; GSList *l = NULL; - for ( SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { - g_object_ref( G_OBJECT(child) ); + + for ( SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { + sp_object_ref(child); l = g_slist_prepend(l, child); } + l = g_slist_reverse (l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->emitModified(flags); } - g_object_unref( G_OBJECT(child) ); + + sp_object_unref(child); } } -static Inkscape::XML::Node *sp_flowregionexclude_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node *SPFlowregionExclude::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if (flags & SP_OBJECT_WRITE_BUILD) { if ( repr == NULL ) { repr = xml_doc->createElement("svg:flowRegionExclude"); } GSList *l = NULL; - for ( SPObject *child = object->firstChild() ; child; child = child->getNext() ) { + + for ( SPObject *child = this->firstChild() ; child; child = child->getNext() ) { Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags); + if (crepr) { l = g_slist_prepend(l, crepr); } @@ -398,21 +328,17 @@ static Inkscape::XML::Node *sp_flowregionexclude_write(SPObject *object, Inkscap } } else { - for ( SPObject *child = object->firstChild() ; child; child = child->getNext() ) { + for ( SPObject *child = this->firstChild() ; child; child = child->getNext() ) { child->updateRepr(flags); } } - if (((SPObjectClass *) (sp_flowregionexclude_parent_class))->write) { - ((SPObjectClass *) (sp_flowregionexclude_parent_class))->write (object, xml_doc, repr, flags); - } + SPItem::write(xml_doc, repr, flags); return repr; } - -static gchar *sp_flowregionexclude_description(SPItem */*item*/) -{ +gchar* SPFlowregionExclude::description() { /* TRANSLATORS: A region "cut out of" a flow region; text is not allowed to flow inside the * flow excluded region. flowRegionExclude in SVG 1.2: see * http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html#flowRegion-elem and diff --git a/src/sp-flowregion.h b/src/sp-flowregion.h index 46b584cf2..59818651a 100644 --- a/src/sp-flowregion.h +++ b/src/sp-flowregion.h @@ -6,45 +6,49 @@ #include "sp-item.h" -#define SP_TYPE_FLOWREGION (sp_flowregion_get_type ()) -#define SP_FLOWREGION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_FLOWREGION, SPFlowregion)) -#define SP_FLOWREGION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_FLOWREGION, SPFlowregionClass)) -#define SP_IS_FLOWREGION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_FLOWREGION)) -#define SP_IS_FLOWREGION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_FLOWREGION)) - -#define SP_TYPE_FLOWREGIONEXCLUDE (sp_flowregionexclude_get_type ()) -#define SP_FLOWREGIONEXCLUDE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_FLOWREGIONEXCLUDE, SPFlowregionExclude)) -#define SP_FLOWREGIONEXCLUDE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_FLOWREGIONEXCLUDE, SPFlowregionExcludeClass)) -#define SP_IS_FLOWREGIONEXCLUDE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_FLOWREGIONEXCLUDE)) -#define SP_IS_FLOWREGIONEXCLUDE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_FLOWREGIONEXCLUDE)) +#define SP_FLOWREGION(obj) (dynamic_cast<SPFlowregion*>((SPObject*)obj)) +#define SP_IS_FLOWREGION(obj) (dynamic_cast<const SPFlowregion*>((SPObject*)obj) != NULL) + +#define SP_FLOWREGIONEXCLUDE(obj) (dynamic_cast<SPFlowregionExclude*>((SPObject*)obj)) +#define SP_IS_FLOWREGIONEXCLUDE(obj) (dynamic_cast<const SPFlowregionExclude*>((SPObject*)obj) != NULL) class Path; class Shape; class flow_dest; class FloatLigne; -struct SPFlowregion : public SPItem { +class SPFlowregion : public SPItem { +public: + SPFlowregion(); + virtual ~SPFlowregion(); + std::vector<Shape*> computed; void UpdateComputed(void); -}; -struct SPFlowregionClass { - SPItemClass parent_class; + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node *child); + virtual void update(SPCtx *ctx, unsigned int flags); + virtual void modified(guint flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + virtual gchar *description(); }; -GType sp_flowregion_get_type (void); +class SPFlowregionExclude : public SPItem { +public: + SPFlowregionExclude(); + virtual ~SPFlowregionExclude(); -struct SPFlowregionExclude : public SPItem { Shape *computed; void UpdateComputed(void); -}; -struct SPFlowregionExcludeClass { - SPItemClass parent_class; + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node *child); + virtual void update(SPCtx *ctx, unsigned int flags); + virtual void modified(guint flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + virtual gchar *description(); }; -GType sp_flowregionexclude_get_type (void); - #endif diff --git a/src/sp-flowtext.cpp b/src/sp-flowtext.cpp index 1d95c2f8a..c7ef579ac 100644 --- a/src/sp-flowtext.cpp +++ b/src/sp-flowtext.cpp @@ -33,108 +33,62 @@ #include "display/drawing-text.h" +#include "sp-factory.h" -static void sp_flowtext_dispose(GObject *object); +namespace { + SPObject* createFlowtext() { + return new SPFlowtext(); + } -static void sp_flowtext_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref); -static void sp_flowtext_remove_child(SPObject *object, Inkscape::XML::Node *child); -static void sp_flowtext_update(SPObject *object, SPCtx *ctx, guint flags); -static void sp_flowtext_modified(SPObject *object, guint flags); -static Inkscape::XML::Node *sp_flowtext_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_flowtext_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_flowtext_set(SPObject *object, unsigned key, gchar const *value); - -static Geom::OptRect sp_flowtext_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type); -static void sp_flowtext_print(SPItem *item, SPPrintContext *ctx); -static gchar *sp_flowtext_description(SPItem *item); -static void sp_flowtext_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); -static Inkscape::DrawingItem *sp_flowtext_show(SPItem *item, Inkscape::Drawing &drawing, unsigned key, unsigned flags); -static void sp_flowtext_hide(SPItem *item, unsigned key); - -G_DEFINE_TYPE(SPFlowtext, sp_flowtext, SP_TYPE_ITEM); - -static void -sp_flowtext_class_init(SPFlowtextClass *klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPItemClass *item_class = (SPItemClass *) klass; - - object_class->dispose = sp_flowtext_dispose; - - sp_object_class->child_added = sp_flowtext_child_added; - sp_object_class->remove_child = sp_flowtext_remove_child; - sp_object_class->update = sp_flowtext_update; - sp_object_class->modified = sp_flowtext_modified; - sp_object_class->write = sp_flowtext_write; - sp_object_class->build = sp_flowtext_build; - sp_object_class->set = sp_flowtext_set; - - item_class->bbox = sp_flowtext_bbox; - item_class->print = sp_flowtext_print; - item_class->description = sp_flowtext_description; - item_class->snappoints = sp_flowtext_snappoints; - item_class->show = sp_flowtext_show; - item_class->hide = sp_flowtext_hide; + bool flowtextRegistered = SPFactory::instance().registerObject("svg:flowRoot", createFlowtext); } -static void -sp_flowtext_init(SPFlowtext *group) -{ - group->par_indent = 0; - new (&group->layout) Inkscape::Text::Layout(); +SPFlowtext::SPFlowtext() : SPItem() { + this->par_indent = 0; + //new (&this->layout) Inkscape::Text::Layout(); } -static void -sp_flowtext_dispose(GObject *object) -{ - SPFlowtext *group = (SPFlowtext*)object; - - group->layout.~Layout(); +SPFlowtext::~SPFlowtext() { + //this->layout.~Layout(); } -static void -sp_flowtext_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) -{ - if (((SPObjectClass *) (sp_flowtext_parent_class))->child_added) - (* ((SPObjectClass *) (sp_flowtext_parent_class))->child_added)(object, child, ref); +void SPFlowtext::child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref) { + SPItem::child_added(child, ref); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } + /* fixme: hide (Lauris) */ -static void -sp_flowtext_remove_child(SPObject *object, Inkscape::XML::Node *child) -{ - if (((SPObjectClass *) (sp_flowtext_parent_class))->remove_child) - (* ((SPObjectClass *) (sp_flowtext_parent_class))->remove_child)(object, child); +void SPFlowtext::remove_child(Inkscape::XML::Node* child) { + SPItem::remove_child(child); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } -static void sp_flowtext_update(SPObject *object, SPCtx *ctx, unsigned flags) -{ - SPFlowtext *group = SP_FLOWTEXT(object); +void SPFlowtext::update(SPCtx* ctx, unsigned int flags) { SPItemCtx *ictx = (SPItemCtx *) ctx; SPItemCtx cctx = *ictx; - if (((SPObjectClass *) (sp_flowtext_parent_class))->update) { - ((SPObjectClass *) (sp_flowtext_parent_class))->update(object, ctx, flags); - } + SPItem::update(ctx, flags); if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; flags &= SP_OBJECT_MODIFIED_CASCADE; GSList *l = NULL; - for (SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { - g_object_ref(G_OBJECT(child)); + + for (SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { + sp_object_ref(child); l = g_slist_prepend(l, child); } + l = g_slist_reverse(l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { if (SP_IS_ITEM(child)) { SPItem const &chi = *SP_ITEM(child); @@ -145,42 +99,46 @@ static void sp_flowtext_update(SPObject *object, SPCtx *ctx, unsigned flags) child->updateDisplay(ctx, flags); } } - g_object_unref(G_OBJECT(child)); + + sp_object_unref(child); } - group->rebuildLayout(); + this->rebuildLayout(); + + Geom::OptRect pbox = this->geometricBounds(); - Geom::OptRect pbox = group->geometricBounds(); - for (SPItemView *v = group->display; v != NULL; v = v->next) { + for (SPItemView *v = this->display; v != NULL; v = v->next) { Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); - group->_clearFlow(g); - g->setStyle(object->style); + this->_clearFlow(g); + g->setStyle(this->style); // pass the bbox of the flowtext object as paintbox (used for paintserver fills) - group->layout.show(g, pbox); + this->layout.show(g, pbox); } } -static void sp_flowtext_modified(SPObject *object, guint flags) -{ - SPObject *ft = object; +void SPFlowtext::modified(unsigned int flags) { SPObject *region = NULL; - if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; + if (flags & SP_OBJECT_MODIFIED_FLAG) { + flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; + } + flags &= SP_OBJECT_MODIFIED_CASCADE; // FIXME: the below stanza is copied over from sp_text_modified, consider factoring it out if (flags & ( SP_OBJECT_STYLE_MODIFIED_FLAG )) { - SPFlowtext *text = SP_FLOWTEXT(object); + SPFlowtext *text = SP_FLOWTEXT(this); Geom::OptRect pbox = text->geometricBounds(); + for (SPItemView* v = text->display; v != NULL; v = v->next) { Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); text->_clearFlow(g); - g->setStyle(object->style); + g->setStyle(this->style); text->layout.show(g, pbox); } } - for ( SPObject *o = ft->firstChild() ; o ; o = o->getNext() ) { + for ( SPObject *o = this->firstChild() ; o ; o = o->getNext() ) { if (SP_IS_FLOWREGION(o)) { region = o; break; @@ -194,39 +152,33 @@ static void sp_flowtext_modified(SPObject *object, guint flags) } } -static void -sp_flowtext_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - object->_requireSVGVersion(Inkscape::Version(1, 2)); +void SPFlowtext::build(SPDocument* doc, Inkscape::XML::Node* repr) { + this->_requireSVGVersion(Inkscape::Version(1, 2)); - if (((SPObjectClass *) (sp_flowtext_parent_class))->build) { - (* ((SPObjectClass *) (sp_flowtext_parent_class))->build)(object, document, repr); - } + SPItem::build(doc, repr); - object->readAttr( "inkscape:layoutOptions" ); // must happen after css has been read + this->readAttr( "inkscape:layoutOptions" ); // must happen after css has been read } -static void -sp_flowtext_set(SPObject *object, unsigned key, gchar const *value) -{ - SPFlowtext *group = (SPFlowtext *) object; - +void SPFlowtext::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_LAYOUT_OPTIONS: { // deprecated attribute, read for backward compatibility only //XML Tree being directly used while it shouldn't be. - SPCSSAttr *opts = sp_repr_css_attr(group->getRepr(), "inkscape:layoutOptions"); + SPCSSAttr *opts = sp_repr_css_attr(this->getRepr(), "inkscape:layoutOptions"); { gchar const *val = sp_repr_css_property(opts, "justification", NULL); - if (val != NULL && !object->style->text_align.set) { + + if (val != NULL && !this->style->text_align.set) { if ( strcmp(val, "0") == 0 || strcmp(val, "false") == 0 ) { - object->style->text_align.value = SP_CSS_TEXT_ALIGN_LEFT; + this->style->text_align.value = SP_CSS_TEXT_ALIGN_LEFT; } else { - object->style->text_align.value = SP_CSS_TEXT_ALIGN_JUSTIFY; + this->style->text_align.value = SP_CSS_TEXT_ALIGN_JUSTIFY; } - object->style->text_align.set = TRUE; - object->style->text_align.inherit = FALSE; - object->style->text_align.computed = object->style->text_align.value; + + this->style->text_align.set = TRUE; + this->style->text_align.inherit = FALSE; + this->style->text_align.computed = this->style->text_align.value; } } /* no equivalent css attribute for these two (yet) @@ -247,146 +199,136 @@ sp_flowtext_set(SPObject *object, unsigned key, gchar const *value) */ { // This would probably translate to padding-left, if SPStyle had it. gchar const *val = sp_repr_css_property(opts, "par-indent", NULL); + if ( val == NULL ) { - group->par_indent = 0.0; + this->par_indent = 0.0; } else { - sp_repr_get_double((Inkscape::XML::Node*)opts, "par-indent", &group->par_indent); + sp_repr_get_double((Inkscape::XML::Node*)opts, "par-indent", &this->par_indent); } } + sp_repr_css_attr_unref(opts); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } + default: - if (((SPObjectClass *) (sp_flowtext_parent_class))->set) { - (* ((SPObjectClass *) (sp_flowtext_parent_class))->set)(object, key, value); - } + SPItem::set(key, value); break; } } -static Inkscape::XML::Node *sp_flowtext_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPFlowtext::write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) { if ( flags & SP_OBJECT_WRITE_BUILD ) { if ( repr == NULL ) { - repr = xml_doc->createElement("svg:flowRoot"); + repr = doc->createElement("svg:flowRoot"); } + GSList *l = NULL; - for (SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { + + for (SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { Inkscape::XML::Node *c_repr = NULL; + if ( SP_IS_FLOWDIV(child) || SP_IS_FLOWPARA(child) || SP_IS_FLOWREGION(child) || SP_IS_FLOWREGIONEXCLUDE(child)) { - c_repr = child->updateRepr(xml_doc, NULL, flags); + c_repr = child->updateRepr(doc, NULL, flags); } + if ( c_repr ) { l = g_slist_prepend(l, c_repr); } } + while ( l ) { repr->addChild((Inkscape::XML::Node *) l->data, NULL); Inkscape::GC::release((Inkscape::XML::Node *) l->data); l = g_slist_remove(l, l->data); } } else { - for (SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { + for (SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { if ( SP_IS_FLOWDIV(child) || SP_IS_FLOWPARA(child) || SP_IS_FLOWREGION(child) || SP_IS_FLOWREGIONEXCLUDE(child) ) { child->updateRepr(flags); } } } - if (((SPObjectClass *) (sp_flowtext_parent_class))->write) { - ((SPObjectClass *) (sp_flowtext_parent_class))->write(object, xml_doc, repr, flags); - } + SPItem::write(doc, repr, flags); return repr; } -static Geom::OptRect -sp_flowtext_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type) -{ - SPFlowtext *group = SP_FLOWTEXT(item); - Geom::OptRect bbox = group->layout.bounds(transform); +Geom::OptRect SPFlowtext::bbox(Geom::Affine const &transform, SPItem::BBoxType type) { + Geom::OptRect bbox = this->layout.bounds(transform); // Add stroke width // FIXME this code is incorrect - if (bbox && type == SPItem::VISUAL_BBOX && !item->style->stroke.isNone()) { + if (bbox && type == SPItem::VISUAL_BBOX && !this->style->stroke.isNone()) { double scale = transform.descrim(); - bbox->expandBy(0.5 * item->style->stroke_width.computed * scale); + bbox->expandBy(0.5 * this->style->stroke_width.computed * scale); } + return bbox; } -static void -sp_flowtext_print(SPItem *item, SPPrintContext *ctx) -{ - SPFlowtext *group = SP_FLOWTEXT(item); +void SPFlowtext::print(SPPrintContext *ctx) { Geom::OptRect pbox, bbox, dbox; + pbox = this->geometricBounds(); + bbox = this->desktopVisualBounds(); + dbox = Geom::Rect::from_xywh(Geom::Point(0,0), this->document->getDimensions()); - pbox = item->geometricBounds(); - bbox = item->desktopVisualBounds(); - dbox = Geom::Rect::from_xywh(Geom::Point(0,0), item->document->getDimensions()); - Geom::Affine const ctm (item->i2dt_affine()); + Geom::Affine const ctm (this->i2dt_affine()); - group->layout.print(ctx, pbox, dbox, bbox, ctm); + this->layout.print(ctx, pbox, dbox, bbox, ctm); } - -static gchar *sp_flowtext_description(SPItem *item) -{ - Inkscape::Text::Layout const &layout = SP_FLOWTEXT(item)->layout; +gchar* SPFlowtext::description() { + Inkscape::Text::Layout const &layout = SP_FLOWTEXT(this)->layout; int const nChars = layout.iteratorToCharIndex(layout.end()); char const *trunc = (layout.inputTruncated()) ? _(" [truncated]") : ""; - if (SP_FLOWTEXT(item)->has_internal_frame()) { + if (SP_FLOWTEXT(this)->has_internal_frame()) { return g_strdup_printf(ngettext("<b>Flowed text</b> (%d character%s)", "<b>Flowed text</b> (%d characters%s)", nChars), nChars, trunc); } else { return g_strdup_printf(ngettext("<b>Linked flowed text</b> (%d character%s)", "<b>Linked flowed text</b> (%d characters%s)", nChars), nChars, trunc); } } -static void sp_flowtext_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) -{ +void SPFlowtext::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) { if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_TEXT_BASELINE)) { // Choose a point on the baseline for snapping from or to, with the horizontal position // of this point depending on the text alignment (left vs. right) - Inkscape::Text::Layout const *layout = te_get_layout((SPItem *) item); + Inkscape::Text::Layout const *layout = te_get_layout((SPItem *) this); + if (layout != NULL && layout->outputExists()) { boost::optional<Geom::Point> pt = layout->baselineAnchorPoint(); + if (pt) { - p.push_back(Inkscape::SnapCandidatePoint((*pt) * item->i2dt_affine(), Inkscape::SNAPSOURCE_TEXT_ANCHOR, Inkscape::SNAPTARGET_TEXT_ANCHOR)); + p.push_back(Inkscape::SnapCandidatePoint((*pt) * this->i2dt_affine(), Inkscape::SNAPSOURCE_TEXT_ANCHOR, Inkscape::SNAPTARGET_TEXT_ANCHOR)); } } } } -static Inkscape::DrawingItem * -sp_flowtext_show(SPItem *item, Inkscape::Drawing &drawing, unsigned/* key*/, unsigned /*flags*/) -{ - SPFlowtext *group = (SPFlowtext *) item; +Inkscape::DrawingItem* SPFlowtext::show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { Inkscape::DrawingGroup *flowed = new Inkscape::DrawingGroup(drawing); flowed->setPickChildren(false); - flowed->setStyle(group->style); + flowed->setStyle(this->style); // pass the bbox of the flowtext object as paintbox (used for paintserver fills) - Geom::OptRect bbox = group->geometricBounds(); - group->layout.show(flowed, bbox); + Geom::OptRect bbox = this->geometricBounds(); + this->layout.show(flowed, bbox); return flowed; } -static void -sp_flowtext_hide(SPItem *item, unsigned int key) -{ - if (((SPItemClass *) sp_flowtext_parent_class)->hide) - ((SPItemClass *) sp_flowtext_parent_class)->hide(item, key); +void SPFlowtext::hide(unsigned int key) { + SPItem::hide(key); } /* * */ - void SPFlowtext::_buildLayoutInput(SPObject *root, Shape const *exclusion_shape, std::list<Shape> *shapes, SPObject **pending_line_break_object) { Inkscape::Text::Layout::OptionalTextTagAttrs pi; @@ -459,13 +401,14 @@ void SPFlowtext::_buildLayoutInput(SPObject *root, Shape const *exclusion_shape, Shape* SPFlowtext::_buildExclusionShape() const { - Shape *shape = new Shape; - Shape *shape_temp = new Shape; + Shape *shape = new Shape(); + Shape *shape_temp = new Shape(); for (SPObject *child = children ; child ; child = child->getNext() ) { // RH: is it right that this shouldn't be recursive? if ( SP_IS_FLOWREGIONEXCLUDE(child) ) { SPFlowregionExclude *c_child = SP_FLOWREGIONEXCLUDE(child); + if ( c_child->computed && c_child->computed->hasEdges() ) { if (shape->hasEdges()) { shape_temp->Booleen(shape, c_child->computed, bool_op_union); @@ -476,7 +419,9 @@ Shape* SPFlowtext::_buildExclusionShape() const } } } + delete shape_temp; + return shape; } @@ -679,7 +624,7 @@ SPItem *create_flowtext_with_internal_frame (SPDesktop *desktop, Geom::Point p0, Geom::Coord const w = x1 - x0; Geom::Coord const h = y1 - y0; - sp_rect_position_set(rect, x0, y0, w, h); + rect->setPosition(x0, y0, w, h); rect->updateRepr(); Inkscape::XML::Node *para_repr = xml_doc->createElement("svg:flowPara"); diff --git a/src/sp-flowtext.h b/src/sp-flowtext.h index 944503a1e..bd7c5990a 100644 --- a/src/sp-flowtext.h +++ b/src/sp-flowtext.h @@ -9,11 +9,8 @@ #include <2geom/forward.h> #include "libnrtype/Layout-TNG.h" -#define SP_TYPE_FLOWTEXT (sp_flowtext_get_type ()) -#define SP_FLOWTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_FLOWTEXT, SPFlowtext)) -#define SP_FLOWTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_FLOWTEXT, SPFlowtextClass)) -#define SP_IS_FLOWTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_FLOWTEXT)) -#define SP_IS_FLOWTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_FLOWTEXT)) +#define SP_FLOWTEXT(obj) (dynamic_cast<SPFlowtext*>((SPObject*)obj)) +#define SP_IS_FLOWTEXT(obj) (dynamic_cast<const SPFlowtext*>((SPObject*)obj) != NULL) namespace Inkscape { @@ -22,8 +19,11 @@ class DrawingGroup; } // namespace Inkscape +class SPFlowtext : public SPItem { +public: + SPFlowtext(); + virtual ~SPFlowtext(); -struct SPFlowtext : public SPItem { /** Completely recalculates the layout. */ void rebuildLayout(); @@ -51,13 +51,26 @@ private: of this flowroot. */ Shape* _buildExclusionShape() const; -}; +public: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); -struct SPFlowtextClass { - SPItemClass parent_class; -}; + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node* child); + + virtual void set(unsigned int key, const gchar* value); -GType sp_flowtext_get_type (void); + virtual void update(SPCtx* ctx, unsigned int flags); + virtual void modified(unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + + virtual Geom::OptRect bbox(Geom::Affine const &transform, SPItem::BBoxType type); + virtual void print(SPPrintContext *ctx); + virtual gchar* description(); + virtual Inkscape::DrawingItem* show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); + virtual void hide(unsigned int key); + virtual void snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); +}; SPItem *create_flowtext_with_internal_frame (SPDesktop *desktop, Geom::Point p1, Geom::Point p2); diff --git a/src/sp-font-face.cpp b/src/sp-font-face.cpp index 6b6d07c6d..9782f0c83 100644 --- a/src/sp-font-face.cpp +++ b/src/sp-font-face.cpp @@ -259,170 +259,133 @@ static std::vector<FontFaceStretchType> sp_read_fontFaceStretchType(gchar const return v; } -static void sp_fontface_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_fontface_release(SPObject *object); -static void sp_fontface_set(SPObject *object, unsigned int key, const gchar *value); -static Inkscape::XML::Node *sp_fontface_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -static void sp_fontface_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref); -static void sp_fontface_remove_child(SPObject *object, Inkscape::XML::Node *child); -static void sp_fontface_update(SPObject *object, SPCtx *ctx, guint flags); - -G_DEFINE_TYPE(SPFontFace, sp_fontface, SP_TYPE_OBJECT); - -static void sp_fontface_class_init(SPFontFaceClass *fc) -{ - SPObjectClass *sp_object_class = reinterpret_cast<SPObjectClass *>(fc); - - sp_object_class->build = sp_fontface_build; - sp_object_class->release = sp_fontface_release; - sp_object_class->set = sp_fontface_set; - sp_object_class->write = sp_fontface_write; - sp_object_class->child_added = sp_fontface_child_added; - sp_object_class->remove_child = sp_fontface_remove_child; - sp_object_class->update = sp_fontface_update; +#include "sp-factory.h" + +namespace { + SPObject* createFontFace() { + return new SPFontFace(); + } + + bool fontFaceRegistered = SPFactory::instance().registerObject("svg:font-face", createFontFace); } -static void sp_fontface_init(SPFontFace *face) -{ +SPFontFace::SPFontFace() : SPObject() { std::vector<FontFaceStyleType> style; style.push_back(SP_FONTFACE_STYLE_ALL); - face->font_style = style; + this->font_style = style; std::vector<FontFaceVariantType> variant; variant.push_back(SP_FONTFACE_VARIANT_NORMAL); - face->font_variant = variant; + this->font_variant = variant; std::vector<FontFaceWeightType> weight; weight.push_back(SP_FONTFACE_WEIGHT_ALL); - face->font_weight = weight; + this->font_weight = weight; std::vector<FontFaceStretchType> stretch; stretch.push_back(SP_FONTFACE_STRETCH_NORMAL); - face->font_stretch = stretch; - face->font_family = NULL; - /* - //face->font_style = ; - //face->font_variant = ; - //face->font_weight = ; - //face->font_stretch = ; - face->font_size = NULL; - //face->unicode_range = ; - face->units_per_em = 1000; - //face->panose_1 = ; - face->stem_v = ; - face->stem_h = ; - face->slope = 0; - face->cap_height = ; - face->x_height = ; - face->accent_height = ; - face->ascent = ; - face->descent = ; - face->widths = NULL; - face->bbox = NULL; - face->ideographic = ; - face->alphabetic = ; - face->mathematical = ; - face->hanging = ; - face->v_ideographic = ; - face->v_alphabetic = ; - face->v_mathematical = ; - face->v_hanging = ; - face->underline_position = ; - face->underline_thickness = ; - face->strikethrough_position = ; - face->strikethrough_thickness = ; - face->overline_position = ; - face->overline_thickness = ; -*/ + this->font_stretch = stretch; + this->font_family = NULL; + + //this->font_style = ; + //this->font_variant = ; + //this->font_weight = ; + //this->font_stretch = ; + this->font_size = NULL; + //this->unicode_range = ; + this->units_per_em = 1000; + //this->panose_1 = ; + this->stemv = 0; + this->stemh = 0; + this->slope = 0; + this->cap_height = 0; + this->x_height = 0; + this->accent_height = 0; + this->ascent = 0; + this->descent = 0; + this->widths = NULL; + this->bbox = NULL; + this->ideographic = 0; + this->alphabetic = 0; + this->mathematical = 0; + this->hanging = 0; + this->v_ideographic = 0; + this->v_alphabetic = 0; + this->v_mathematical = 0; + this->v_hanging = 0; + this->underline_position = 0; + this->underline_thickness = 0; + this->strikethrough_position = 0; + this->strikethrough_thickness = 0; + this->overline_position = 0; + this->overline_thickness = 0; } -static void sp_fontface_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if ((SP_OBJECT_CLASS(sp_fontface_parent_class))->build) { - (SP_OBJECT_CLASS(sp_fontface_parent_class))->build(object, document, repr); - } - - object->readAttr( "font-family" ); - object->readAttr( "font-style" ); - object->readAttr( "font-variant" ); - object->readAttr( "font-weight" ); - object->readAttr( "font-stretch" ); - object->readAttr( "font-size" ); - object->readAttr( "unicode-range" ); - object->readAttr( "units-per-em" ); - object->readAttr( "panose-1" ); - object->readAttr( "stem-v" ); - object->readAttr( "stem-h" ); - object->readAttr( "slope" ); - object->readAttr( "cap-height" ); - object->readAttr( "x-height" ); - object->readAttr( "accent-height" ); - object->readAttr( "ascent" ); - object->readAttr( "descent" ); - object->readAttr( "widths" ); - object->readAttr( "bbox" ); - object->readAttr( "ideographic" ); - object->readAttr( "alphabetic" ); - object->readAttr( "mathematical" ); - object->readAttr( "ranging" ); - object->readAttr( "v-ideogaphic" ); - object->readAttr( "v-alphabetic" ); - object->readAttr( "v-mathematical" ); - object->readAttr( "v-hanging" ); - object->readAttr( "underline-position" ); - object->readAttr( "underline-thickness" ); - object->readAttr( "strikethrough-position" ); - object->readAttr( "strikethrough-thickness" ); - object->readAttr( "overline-position" ); - object->readAttr( "overline-thickness" ); +SPFontFace::~SPFontFace() { } -static void sp_fontface_children_modified(SPFontFace */*sp_fontface*/) -{ +void SPFontFace::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPObject::build(document, repr); + + this->readAttr( "font-family" ); + this->readAttr( "font-style" ); + this->readAttr( "font-variant" ); + this->readAttr( "font-weight" ); + this->readAttr( "font-stretch" ); + this->readAttr( "font-size" ); + this->readAttr( "unicode-range" ); + this->readAttr( "units-per-em" ); + this->readAttr( "panose-1" ); + this->readAttr( "stem-v" ); + this->readAttr( "stem-h" ); + this->readAttr( "slope" ); + this->readAttr( "cap-height" ); + this->readAttr( "x-height" ); + this->readAttr( "accent-height" ); + this->readAttr( "ascent" ); + this->readAttr( "descent" ); + this->readAttr( "widths" ); + this->readAttr( "bbox" ); + this->readAttr( "ideographic" ); + this->readAttr( "alphabetic" ); + this->readAttr( "mathematical" ); + this->readAttr( "ranging" ); + this->readAttr( "v-ideogaphic" ); + this->readAttr( "v-alphabetic" ); + this->readAttr( "v-mathematical" ); + this->readAttr( "v-hanging" ); + this->readAttr( "underline-position" ); + this->readAttr( "underline-thickness" ); + this->readAttr( "strikethrough-position" ); + this->readAttr( "strikethrough-thickness" ); + this->readAttr( "overline-position" ); + this->readAttr( "overline-thickness" ); } /** * Callback for child_added event. */ -static void -sp_fontface_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) -{ - SPFontFace *f = SP_FONTFACE(object); - - if ((SP_OBJECT_CLASS(sp_fontface_parent_class))->child_added) - (* (SP_OBJECT_CLASS(sp_fontface_parent_class))->child_added)(object, child, ref); +void SPFontFace::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { + SPObject::child_added(child, ref); - sp_fontface_children_modified(f); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } /** * Callback for remove_child event. */ -static void -sp_fontface_remove_child(SPObject *object, Inkscape::XML::Node *child) -{ - SPFontFace *f = SP_FONTFACE(object); +void SPFontFace::remove_child(Inkscape::XML::Node *child) { + SPObject::remove_child(child); - if ((SP_OBJECT_CLASS(sp_fontface_parent_class))->remove_child) - (* (SP_OBJECT_CLASS(sp_fontface_parent_class))->remove_child)(object, child); - - sp_fontface_children_modified(f); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } -static void sp_fontface_release(SPObject *object) -{ - if ((SP_OBJECT_CLASS(sp_fontface_parent_class))->release) { - (SP_OBJECT_CLASS(sp_fontface_parent_class))->release(object); - } +void SPFontFace::release() { + SPObject::release(); } -static void sp_fontface_set(SPObject *object, unsigned int key, const gchar *value) -{ - SPFontFace *face = SP_FONTFACE(object); +void SPFontFace::set(unsigned int key, const gchar *value) { std::vector<FontFaceStyleType> style; std::vector<FontFaceVariantType> variant; std::vector<FontFaceWeightType> weight; @@ -430,22 +393,24 @@ static void sp_fontface_set(SPObject *object, unsigned int key, const gchar *val switch (key) { case SP_PROP_FONT_FAMILY: - if (face->font_family) { - g_free(face->font_family); + if (this->font_family) { + g_free(this->font_family); } - face->font_family = g_strdup(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->font_family = g_strdup(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_PROP_FONT_STYLE: style = sp_read_fontFaceStyleType(value); - if (face->font_style.size() != style.size()){ - face->font_style = style; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->font_style.size() != style.size()){ + this->font_style = style; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } else { for (unsigned int i=0;i<style.size();i++){ - if (style[i] != face->font_style[i]){ - face->font_style = style; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (style[i] != this->font_style[i]){ + this->font_style = style; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } } @@ -453,14 +418,15 @@ static void sp_fontface_set(SPObject *object, unsigned int key, const gchar *val break; case SP_PROP_FONT_VARIANT: variant = sp_read_fontFaceVariantType(value); - if (face->font_variant.size() != variant.size()){ - face->font_variant = variant; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->font_variant.size() != variant.size()){ + this->font_variant = variant; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } else { for (unsigned int i=0;i<variant.size();i++){ - if (variant[i] != face->font_variant[i]){ - face->font_variant = variant; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (variant[i] != this->font_variant[i]){ + this->font_variant = variant; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } } @@ -468,14 +434,15 @@ static void sp_fontface_set(SPObject *object, unsigned int key, const gchar *val break; case SP_PROP_FONT_WEIGHT: weight = sp_read_fontFaceWeightType(value); - if (face->font_weight.size() != weight.size()){ - face->font_weight = weight; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->font_weight.size() != weight.size()){ + this->font_weight = weight; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } else { for (unsigned int i=0;i<weight.size();i++){ - if (weight[i] != face->font_weight[i]){ - face->font_weight = weight; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (weight[i] != this->font_weight[i]){ + this->font_weight = weight; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } } @@ -483,14 +450,15 @@ static void sp_fontface_set(SPObject *object, unsigned int key, const gchar *val break; case SP_PROP_FONT_STRETCH: stretch = sp_read_fontFaceStretchType(value); - if (face->font_stretch.size() != stretch.size()){ - face->font_stretch = stretch; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->font_stretch.size() != stretch.size()){ + this->font_stretch = stretch; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } else { for (unsigned int i=0;i<stretch.size();i++){ - if (stretch[i] != face->font_stretch[i]){ - face->font_stretch = stretch; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (stretch[i] != this->font_stretch[i]){ + this->font_stretch = stretch; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } } @@ -499,214 +467,235 @@ static void sp_fontface_set(SPObject *object, unsigned int key, const gchar *val case SP_ATTR_UNITS_PER_EM: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->units_per_em){ - face->units_per_em = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->units_per_em){ + this->units_per_em = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_STEMV: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->stemv){ - face->stemv = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->stemv){ + this->stemv = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_STEMH: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->stemh){ - face->stemh = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->stemh){ + this->stemh = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_SLOPE: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->slope){ - face->slope = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->slope){ + this->slope = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_CAP_HEIGHT: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->cap_height){ - face->cap_height = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->cap_height){ + this->cap_height = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_X_HEIGHT: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->x_height){ - face->x_height = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->x_height){ + this->x_height = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_ACCENT_HEIGHT: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->accent_height){ - face->accent_height = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->accent_height){ + this->accent_height = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_ASCENT: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->ascent){ - face->ascent = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->ascent){ + this->ascent = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_DESCENT: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->descent){ - face->descent = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->descent){ + this->descent = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_IDEOGRAPHIC: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->ideographic){ - face->ideographic = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->ideographic){ + this->ideographic = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_ALPHABETIC: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->alphabetic){ - face->alphabetic = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->alphabetic){ + this->alphabetic = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_MATHEMATICAL: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->mathematical){ - face->mathematical = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->mathematical){ + this->mathematical = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_HANGING: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->hanging){ - face->hanging = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->hanging){ + this->hanging = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_V_IDEOGRAPHIC: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->v_ideographic){ - face->v_ideographic = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->v_ideographic){ + this->v_ideographic = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_V_ALPHABETIC: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->v_alphabetic){ - face->v_alphabetic = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->v_alphabetic){ + this->v_alphabetic = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_V_MATHEMATICAL: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->v_mathematical){ - face->v_mathematical = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->v_mathematical){ + this->v_mathematical = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_V_HANGING: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->v_hanging){ - face->v_hanging = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->v_hanging){ + this->v_hanging = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_UNDERLINE_POSITION: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->underline_position){ - face->underline_position = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->underline_position){ + this->underline_position = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_UNDERLINE_THICKNESS: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->underline_thickness){ - face->underline_thickness = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->underline_thickness){ + this->underline_thickness = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_STRIKETHROUGH_POSITION: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->strikethrough_position){ - face->strikethrough_position = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->strikethrough_position){ + this->strikethrough_position = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_STRIKETHROUGH_THICKNESS: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->strikethrough_thickness){ - face->strikethrough_thickness = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->strikethrough_thickness){ + this->strikethrough_thickness = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_OVERLINE_POSITION: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->overline_position){ - face->overline_position = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->overline_position){ + this->overline_position = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_OVERLINE_THICKNESS: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != face->overline_thickness){ - face->overline_thickness = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->overline_thickness){ + this->overline_thickness = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } default: - if ((SP_OBJECT_CLASS(sp_fontface_parent_class))->set) { - (SP_OBJECT_CLASS(sp_fontface_parent_class))->set(object, key, value); - } + SPObject::set(key, value); break; } } @@ -714,56 +703,49 @@ static void sp_fontface_set(SPObject *object, unsigned int key, const gchar *val /** * Receives update notifications. */ -static void -sp_fontface_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPFontFace::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG)) { - object->readAttr( "font-family" ); - object->readAttr( "font-style" ); - object->readAttr( "font-variant" ); - object->readAttr( "font-weight" ); - object->readAttr( "font-stretch" ); - object->readAttr( "font-size" ); - object->readAttr( "unicode-range" ); - object->readAttr( "units-per-em" ); - object->readAttr( "panose-1" ); - object->readAttr( "stemv" ); - object->readAttr( "stemh" ); - object->readAttr( "slope" ); - object->readAttr( "cap-height" ); - object->readAttr( "x-height" ); - object->readAttr( "accent-height" ); - object->readAttr( "ascent" ); - object->readAttr( "descent" ); - object->readAttr( "widths" ); - object->readAttr( "bbox" ); - object->readAttr( "ideographic" ); - object->readAttr( "alphabetic" ); - object->readAttr( "mathematical" ); - object->readAttr( "hanging" ); - object->readAttr( "v-ideographic" ); - object->readAttr( "v-alphabetic" ); - object->readAttr( "v-mathematical" ); - object->readAttr( "v-hanging" ); - object->readAttr( "underline-position" ); - object->readAttr( "underline-thickness" ); - object->readAttr( "strikethrough-position" ); - object->readAttr( "strikethrough-thickness" ); - object->readAttr( "overline-position" ); - object->readAttr( "overline-thickness" ); + this->readAttr( "font-family" ); + this->readAttr( "font-style" ); + this->readAttr( "font-variant" ); + this->readAttr( "font-weight" ); + this->readAttr( "font-stretch" ); + this->readAttr( "font-size" ); + this->readAttr( "unicode-range" ); + this->readAttr( "units-per-em" ); + this->readAttr( "panose-1" ); + this->readAttr( "stemv" ); + this->readAttr( "stemh" ); + this->readAttr( "slope" ); + this->readAttr( "cap-height" ); + this->readAttr( "x-height" ); + this->readAttr( "accent-height" ); + this->readAttr( "ascent" ); + this->readAttr( "descent" ); + this->readAttr( "widths" ); + this->readAttr( "bbox" ); + this->readAttr( "ideographic" ); + this->readAttr( "alphabetic" ); + this->readAttr( "mathematical" ); + this->readAttr( "hanging" ); + this->readAttr( "v-ideographic" ); + this->readAttr( "v-alphabetic" ); + this->readAttr( "v-mathematical" ); + this->readAttr( "v-hanging" ); + this->readAttr( "underline-position" ); + this->readAttr( "underline-thickness" ); + this->readAttr( "strikethrough-position" ); + this->readAttr( "strikethrough-thickness" ); + this->readAttr( "overline-position" ); + this->readAttr( "overline-thickness" ); } - if ((SP_OBJECT_CLASS(sp_fontface_parent_class))->update) { - (SP_OBJECT_CLASS(sp_fontface_parent_class))->update(object, ctx, flags); - } + SPObject::update(ctx, flags); } #define COPY_ATTR(rd,rs,key) (rd)->setAttribute((key), rs->attribute(key)); -static Inkscape::XML::Node *sp_fontface_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPFontFace *face = SP_FONTFACE(object); - +Inkscape::XML::Node* SPFontFace::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:font-face"); } @@ -776,74 +758,72 @@ static Inkscape::XML::Node *sp_fontface_write(SPObject *object, Inkscape::XML::D //sp_repr_set_svg_double(repr, "font-stretch", face->font_stretch); //sp_repr_set_svg_double(repr, "font-size", face->font_size); //sp_repr_set_svg_double(repr, "unicode-range", face->unicode_range); - sp_repr_set_svg_double(repr, "units-per-em", face->units_per_em); + sp_repr_set_svg_double(repr, "units-per-em", this->units_per_em); //sp_repr_set_svg_double(repr, "panose-1", face->panose_1); - sp_repr_set_svg_double(repr, "stemv", face->stemv); - sp_repr_set_svg_double(repr, "stemh", face->stemh); - sp_repr_set_svg_double(repr, "slope", face->slope); - sp_repr_set_svg_double(repr, "cap-height", face->cap_height); - sp_repr_set_svg_double(repr, "x-height", face->x_height); - sp_repr_set_svg_double(repr, "accent-height", face->accent_height); - sp_repr_set_svg_double(repr, "ascent", face->ascent); - sp_repr_set_svg_double(repr, "descent", face->descent); + sp_repr_set_svg_double(repr, "stemv", this->stemv); + sp_repr_set_svg_double(repr, "stemh", this->stemh); + sp_repr_set_svg_double(repr, "slope", this->slope); + sp_repr_set_svg_double(repr, "cap-height", this->cap_height); + sp_repr_set_svg_double(repr, "x-height", this->x_height); + sp_repr_set_svg_double(repr, "accent-height", this->accent_height); + sp_repr_set_svg_double(repr, "ascent", this->ascent); + sp_repr_set_svg_double(repr, "descent", this->descent); //sp_repr_set_svg_double(repr, "widths", face->widths); //sp_repr_set_svg_double(repr, "bbox", face->bbox); - sp_repr_set_svg_double(repr, "ideographic", face->ideographic); - sp_repr_set_svg_double(repr, "alphabetic", face->alphabetic); - sp_repr_set_svg_double(repr, "mathematical", face->mathematical); - sp_repr_set_svg_double(repr, "hanging", face->hanging); - sp_repr_set_svg_double(repr, "v-ideographic", face->v_ideographic); - sp_repr_set_svg_double(repr, "v-alphabetic", face->v_alphabetic); - sp_repr_set_svg_double(repr, "v-mathematical", face->v_mathematical); - sp_repr_set_svg_double(repr, "v-hanging", face->v_hanging); - sp_repr_set_svg_double(repr, "underline-position", face->underline_position); - sp_repr_set_svg_double(repr, "underline-thickness", face->underline_thickness); - sp_repr_set_svg_double(repr, "strikethrough-position", face->strikethrough_position); - sp_repr_set_svg_double(repr, "strikethrough-thickness", face->strikethrough_thickness); - sp_repr_set_svg_double(repr, "overline-position", face->overline_position); - sp_repr_set_svg_double(repr, "overline-thickness", face->overline_thickness); - - if (repr != object->getRepr()) { + sp_repr_set_svg_double(repr, "ideographic", this->ideographic); + sp_repr_set_svg_double(repr, "alphabetic", this->alphabetic); + sp_repr_set_svg_double(repr, "mathematical", this->mathematical); + sp_repr_set_svg_double(repr, "hanging", this->hanging); + sp_repr_set_svg_double(repr, "v-ideographic", this->v_ideographic); + sp_repr_set_svg_double(repr, "v-alphabetic", this->v_alphabetic); + sp_repr_set_svg_double(repr, "v-mathematical", this->v_mathematical); + sp_repr_set_svg_double(repr, "v-hanging", this->v_hanging); + sp_repr_set_svg_double(repr, "underline-position", this->underline_position); + sp_repr_set_svg_double(repr, "underline-thickness", this->underline_thickness); + sp_repr_set_svg_double(repr, "strikethrough-position", this->strikethrough_position); + sp_repr_set_svg_double(repr, "strikethrough-thickness", this->strikethrough_thickness); + sp_repr_set_svg_double(repr, "overline-position", this->overline_position); + sp_repr_set_svg_double(repr, "overline-thickness", this->overline_thickness); + + if (repr != this->getRepr()) { // In all COPY_ATTR given below the XML tree is // being used directly while it shouldn't be. - COPY_ATTR(repr, object->getRepr(), "font-family"); - COPY_ATTR(repr, object->getRepr(), "font-style"); - COPY_ATTR(repr, object->getRepr(), "font-variant"); - COPY_ATTR(repr, object->getRepr(), "font-weight"); - COPY_ATTR(repr, object->getRepr(), "font-stretch"); - COPY_ATTR(repr, object->getRepr(), "font-size"); - COPY_ATTR(repr, object->getRepr(), "unicode-range"); - COPY_ATTR(repr, object->getRepr(), "units-per-em"); - COPY_ATTR(repr, object->getRepr(), "panose-1"); - COPY_ATTR(repr, object->getRepr(), "stemv"); - COPY_ATTR(repr, object->getRepr(), "stemh"); - COPY_ATTR(repr, object->getRepr(), "slope"); - COPY_ATTR(repr, object->getRepr(), "cap-height"); - COPY_ATTR(repr, object->getRepr(), "x-height"); - COPY_ATTR(repr, object->getRepr(), "accent-height"); - COPY_ATTR(repr, object->getRepr(), "ascent"); - COPY_ATTR(repr, object->getRepr(), "descent"); - COPY_ATTR(repr, object->getRepr(), "widths"); - COPY_ATTR(repr, object->getRepr(), "bbox"); - COPY_ATTR(repr, object->getRepr(), "ideographic"); - COPY_ATTR(repr, object->getRepr(), "alphabetic"); - COPY_ATTR(repr, object->getRepr(), "mathematical"); - COPY_ATTR(repr, object->getRepr(), "hanging"); - COPY_ATTR(repr, object->getRepr(), "v-ideographic"); - COPY_ATTR(repr, object->getRepr(), "v-alphabetic"); - COPY_ATTR(repr, object->getRepr(), "v-mathematical"); - COPY_ATTR(repr, object->getRepr(), "v-hanging"); - COPY_ATTR(repr, object->getRepr(), "underline-position"); - COPY_ATTR(repr, object->getRepr(), "underline-thickness"); - COPY_ATTR(repr, object->getRepr(), "strikethrough-position"); - COPY_ATTR(repr, object->getRepr(), "strikethrough-thickness"); - COPY_ATTR(repr, object->getRepr(), "overline-position"); - COPY_ATTR(repr, object->getRepr(), "overline-thickness"); + COPY_ATTR(repr, this->getRepr(), "font-family"); + COPY_ATTR(repr, this->getRepr(), "font-style"); + COPY_ATTR(repr, this->getRepr(), "font-variant"); + COPY_ATTR(repr, this->getRepr(), "font-weight"); + COPY_ATTR(repr, this->getRepr(), "font-stretch"); + COPY_ATTR(repr, this->getRepr(), "font-size"); + COPY_ATTR(repr, this->getRepr(), "unicode-range"); + COPY_ATTR(repr, this->getRepr(), "units-per-em"); + COPY_ATTR(repr, this->getRepr(), "panose-1"); + COPY_ATTR(repr, this->getRepr(), "stemv"); + COPY_ATTR(repr, this->getRepr(), "stemh"); + COPY_ATTR(repr, this->getRepr(), "slope"); + COPY_ATTR(repr, this->getRepr(), "cap-height"); + COPY_ATTR(repr, this->getRepr(), "x-height"); + COPY_ATTR(repr, this->getRepr(), "accent-height"); + COPY_ATTR(repr, this->getRepr(), "ascent"); + COPY_ATTR(repr, this->getRepr(), "descent"); + COPY_ATTR(repr, this->getRepr(), "widths"); + COPY_ATTR(repr, this->getRepr(), "bbox"); + COPY_ATTR(repr, this->getRepr(), "ideographic"); + COPY_ATTR(repr, this->getRepr(), "alphabetic"); + COPY_ATTR(repr, this->getRepr(), "mathematical"); + COPY_ATTR(repr, this->getRepr(), "hanging"); + COPY_ATTR(repr, this->getRepr(), "v-ideographic"); + COPY_ATTR(repr, this->getRepr(), "v-alphabetic"); + COPY_ATTR(repr, this->getRepr(), "v-mathematical"); + COPY_ATTR(repr, this->getRepr(), "v-hanging"); + COPY_ATTR(repr, this->getRepr(), "underline-position"); + COPY_ATTR(repr, this->getRepr(), "underline-thickness"); + COPY_ATTR(repr, this->getRepr(), "strikethrough-position"); + COPY_ATTR(repr, this->getRepr(), "strikethrough-thickness"); + COPY_ATTR(repr, this->getRepr(), "overline-position"); + COPY_ATTR(repr, this->getRepr(), "overline-thickness"); } - if ((SP_OBJECT_CLASS(sp_fontface_parent_class))->write) { - (SP_OBJECT_CLASS(sp_fontface_parent_class))->write(object, xml_doc, repr, flags); - } + SPObject::write(xml_doc, repr, flags); return repr; } diff --git a/src/sp-font-face.h b/src/sp-font-face.h index 968644556..531dd5843 100644 --- a/src/sp-font-face.h +++ b/src/sp-font-face.h @@ -24,13 +24,8 @@ #include "sp-object.h" -G_BEGIN_DECLS - -#define SP_TYPE_FONTFACE (sp_fontface_get_type ()) -#define SP_FONTFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_FONTFACE, SPFontFace)) -#define SP_FONTFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_FONTFACE, SPFontFaceClass)) -#define SP_IS_FONTFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_FONTFACE)) -#define SP_IS_FONTFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_FONTFACE)) +#define SP_FONTFACE(obj) (dynamic_cast<SPFontFace*>((SPObject*)obj)) +#define SP_IS_FONTFACE(obj) (dynamic_cast<const SPFontFace*>((SPObject*)obj) != NULL) enum FontFaceStyleType{ SP_FONTFACE_STYLE_ALL, @@ -76,7 +71,11 @@ enum FontFaceUnicodeRangeType{ FONTFACE_UNICODERANGE_FIXME_HERE, }; -struct SPFontFace : public SPObject { +class SPFontFace : public SPObject { +public: + SPFontFace(); + virtual ~SPFontFace(); + char* font_family; std::vector<FontFaceStyleType> font_style; std::vector<FontFaceVariantType> font_variant; @@ -110,14 +109,19 @@ struct SPFontFace : public SPObject { double strikethrough_thickness; double overline_position; double overline_thickness; -}; -struct SPFontFaceClass { - SPObjectClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); -GType sp_fontface_get_type (void); + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node* child); -G_END_DECLS + virtual void set(unsigned int key, const gchar* value); + + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); +}; #endif //#ifndef __SP_FONTFACE_H__ diff --git a/src/sp-font.cpp b/src/sp-font.cpp index a03890fc7..4ac3278d7 100644 --- a/src/sp-font.cpp +++ b/src/sp-font.cpp @@ -23,28 +23,14 @@ #include "display/nr-svgfonts.h" -static void sp_font_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_font_release(SPObject *object); -static void sp_font_set(SPObject *object, unsigned int key, const gchar *value); -static Inkscape::XML::Node *sp_font_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -static void sp_font_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref); -static void sp_font_remove_child(SPObject *object, Inkscape::XML::Node *child); -static void sp_font_update(SPObject *object, SPCtx *ctx, guint flags); - -G_DEFINE_TYPE(SPFont, sp_font, SP_TYPE_OBJECT); - -static void sp_font_class_init(SPFontClass *fc) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) fc; - - sp_object_class->build = sp_font_build; - sp_object_class->release = sp_font_release; - sp_object_class->set = sp_font_set; - sp_object_class->write = sp_font_write; - sp_object_class->child_added = sp_font_child_added; - sp_object_class->remove_child = sp_font_remove_child; - sp_object_class->update = sp_font_update; +#include "sp-factory.h" + +namespace { + SPObject* createFont() { + return new SPFont(); + } + + bool fontRegistered = SPFactory::instance().registerObject("svg:font", createFont); } //I think we should have extra stuff here and in the set method in order to set default value as specified at http://www.w3.org/TR/SVG/fonts.html @@ -54,142 +40,121 @@ double FNT_DEFAULT_ADV = 90; // TODO determine proper default double FNT_DEFAULT_ASCENT = 90; // TODO determine proper default double FNT_UNITS_PER_EM = 90; // TODO determine proper default -static void sp_font_init(SPFont *font) -{ - font->horiz_origin_x = 0; - font->horiz_origin_y = 0; - font->horiz_adv_x = FNT_DEFAULT_ADV; - font->vert_origin_x = FNT_DEFAULT_ADV / 2.0; - font->vert_origin_y = FNT_DEFAULT_ASCENT; - font->vert_adv_y = FNT_UNITS_PER_EM; +SPFont::SPFont() : SPObject() { + this->horiz_origin_x = 0; + this->horiz_origin_y = 0; + this->horiz_adv_x = FNT_DEFAULT_ADV; + this->vert_origin_x = FNT_DEFAULT_ADV / 2.0; + this->vert_origin_y = FNT_DEFAULT_ASCENT; + this->vert_adv_y = FNT_UNITS_PER_EM; } -static void sp_font_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) (sp_font_parent_class))->build) { - ((SPObjectClass *) (sp_font_parent_class))->build(object, document, repr); - } - - object->readAttr( "horiz-origin-x" ); - object->readAttr( "horiz-origin-y" ); - object->readAttr( "horiz-adv-x" ); - object->readAttr( "vert-origin-x" ); - object->readAttr( "vert-origin-y" ); - object->readAttr( "vert-adv-y" ); - - document->addResource("font", object); +SPFont::~SPFont() { } +void SPFont::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPObject::build(document, repr); -static void sp_font_children_modified(SPFont */*sp_font*/) -{ + this->readAttr( "horiz-origin-x" ); + this->readAttr( "horiz-origin-y" ); + this->readAttr( "horiz-adv-x" ); + this->readAttr( "vert-origin-x" ); + this->readAttr( "vert-origin-y" ); + this->readAttr( "vert-adv-y" ); + + document->addResource("font", this); } /** * Callback for child_added event. */ -static void -sp_font_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) -{ - SPFont *f = SP_FONT(object); - - if (((SPObjectClass *) sp_font_parent_class)->child_added) - (* ((SPObjectClass *) sp_font_parent_class)->child_added)(object, child, ref); +void SPFont::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { + SPObject::child_added(child, ref); - sp_font_children_modified(f); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } /** * Callback for remove_child event. */ -static void -sp_font_remove_child(SPObject *object, Inkscape::XML::Node *child) -{ - SPFont *f = SP_FONT(object); - - if (((SPObjectClass *) sp_font_parent_class)->remove_child) - (* ((SPObjectClass *) sp_font_parent_class)->remove_child)(object, child); +void SPFont::remove_child(Inkscape::XML::Node* child) { + SPObject::remove_child(child); - sp_font_children_modified(f); - object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } -static void sp_font_release(SPObject *object) -{ - //SPFont *font = SP_FONT(object); - object->document->removeResource("font", object); +void SPFont::release() { + this->document->removeResource("font", this); - if (((SPObjectClass *) sp_font_parent_class)->release) { - ((SPObjectClass *) sp_font_parent_class)->release(object); - } + SPObject::release(); } -static void sp_font_set(SPObject *object, unsigned int key, const gchar *value) -{ - SPFont *font = SP_FONT(object); - +void SPFont::set(unsigned int key, const gchar *value) { // TODO these are floating point, so some epsilon comparison would be good switch (key) { case SP_ATTR_HORIZ_ORIGIN_X: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != font->horiz_origin_x){ - font->horiz_origin_x = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->horiz_origin_x){ + this->horiz_origin_x = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_HORIZ_ORIGIN_Y: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != font->horiz_origin_y){ - font->horiz_origin_y = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->horiz_origin_y){ + this->horiz_origin_y = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_HORIZ_ADV_X: { double number = value ? g_ascii_strtod(value, 0) : FNT_DEFAULT_ADV; - if (number != font->horiz_adv_x){ - font->horiz_adv_x = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->horiz_adv_x){ + this->horiz_adv_x = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_VERT_ORIGIN_X: { double number = value ? g_ascii_strtod(value, 0) : FNT_DEFAULT_ADV / 2.0; - if (number != font->vert_origin_x){ - font->vert_origin_x = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->vert_origin_x){ + this->vert_origin_x = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_VERT_ORIGIN_Y: { double number = value ? g_ascii_strtod(value, 0) : FNT_DEFAULT_ASCENT; - if (number != font->vert_origin_y){ - font->vert_origin_y = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->vert_origin_y){ + this->vert_origin_y = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_VERT_ADV_Y: { double number = value ? g_ascii_strtod(value, 0) : FNT_UNITS_PER_EM; - if (number != font->vert_adv_y){ - font->vert_adv_y = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->vert_adv_y){ + this->vert_adv_y = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } default: - if (((SPObjectClass *) (sp_font_parent_class))->set) { - ((SPObjectClass *) (sp_font_parent_class))->set(object, key, value); - } + SPObject::set(key, value); break; } } @@ -197,54 +162,45 @@ static void sp_font_set(SPObject *object, unsigned int key, const gchar *value) /** * Receives update notifications. */ -static void -sp_font_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPFont::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG)) { - object->readAttr( "horiz-origin-x" ); - object->readAttr( "horiz-origin-y" ); - object->readAttr( "horiz-adv-x" ); - object->readAttr( "vert-origin-x" ); - object->readAttr( "vert-origin-y" ); - object->readAttr( "vert-adv-y" ); + this->readAttr( "horiz-origin-x" ); + this->readAttr( "horiz-origin-y" ); + this->readAttr( "horiz-adv-x" ); + this->readAttr( "vert-origin-x" ); + this->readAttr( "vert-origin-y" ); + this->readAttr( "vert-adv-y" ); } - if (((SPObjectClass *) sp_font_parent_class)->update) { - ((SPObjectClass *) sp_font_parent_class)->update(object, ctx, flags); - } + SPObject::update(ctx, flags); } #define COPY_ATTR(rd,rs,key) (rd)->setAttribute((key), rs->attribute(key)); -static Inkscape::XML::Node *sp_font_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPFont *font = SP_FONT(object); - +Inkscape::XML::Node* SPFont::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = xml_doc->createElement("svg:font"); + repr = xml_doc->createElement("svg:this"); } - sp_repr_set_svg_double(repr, "horiz-origin-x", font->horiz_origin_x); - sp_repr_set_svg_double(repr, "horiz-origin-y", font->horiz_origin_y); - sp_repr_set_svg_double(repr, "horiz-adv-x", font->horiz_adv_x); - sp_repr_set_svg_double(repr, "vert-origin-x", font->vert_origin_x); - sp_repr_set_svg_double(repr, "vert-origin-y", font->vert_origin_y); - sp_repr_set_svg_double(repr, "vert-adv-y", font->vert_adv_y); + sp_repr_set_svg_double(repr, "horiz-origin-x", this->horiz_origin_x); + sp_repr_set_svg_double(repr, "horiz-origin-y", this->horiz_origin_y); + sp_repr_set_svg_double(repr, "horiz-adv-x", this->horiz_adv_x); + sp_repr_set_svg_double(repr, "vert-origin-x", this->vert_origin_x); + sp_repr_set_svg_double(repr, "vert-origin-y", this->vert_origin_y); + sp_repr_set_svg_double(repr, "vert-adv-y", this->vert_adv_y); - if (repr != object->getRepr()) { + if (repr != this->getRepr()) { // All the below COPY_ATTR funtions are directly using // the XML Tree while they shouldn't - COPY_ATTR(repr, object->getRepr(), "horiz-origin-x"); - COPY_ATTR(repr, object->getRepr(), "horiz-origin-y"); - COPY_ATTR(repr, object->getRepr(), "horiz-adv-x"); - COPY_ATTR(repr, object->getRepr(), "vert-origin-x"); - COPY_ATTR(repr, object->getRepr(), "vert-origin-y"); - COPY_ATTR(repr, object->getRepr(), "vert-adv-y"); + COPY_ATTR(repr, this->getRepr(), "horiz-origin-x"); + COPY_ATTR(repr, this->getRepr(), "horiz-origin-y"); + COPY_ATTR(repr, this->getRepr(), "horiz-adv-x"); + COPY_ATTR(repr, this->getRepr(), "vert-origin-x"); + COPY_ATTR(repr, this->getRepr(), "vert-origin-y"); + COPY_ATTR(repr, this->getRepr(), "vert-adv-y"); } - if (((SPObjectClass *) (sp_font_parent_class))->write) { - ((SPObjectClass *) (sp_font_parent_class))->write(object, xml_doc, repr, flags); - } + SPObject::write(xml_doc, repr, flags); return repr; } diff --git a/src/sp-font.h b/src/sp-font.h index a0f895a52..6e6f4eec2 100644 --- a/src/sp-font.h +++ b/src/sp-font.h @@ -18,25 +18,33 @@ #include "sp-object.h" -#define SP_TYPE_FONT (sp_font_get_type ()) -#define SP_FONT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_FONT, SPFont)) -#define SP_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_FONT, SPFontClass)) -#define SP_IS_FONT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_FONT)) -#define SP_IS_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_FONT)) +#define SP_FONT(obj) (dynamic_cast<SPFont*>((SPObject*)obj)) +#define SP_IS_FONT(obj) (dynamic_cast<const SPFont*>((SPObject*)obj) != NULL) + +class SPFont : public SPObject { +public: + SPFont(); + virtual ~SPFont(); -struct SPFont : public SPObject { double horiz_origin_x; double horiz_origin_y; double horiz_adv_x; double vert_origin_x; double vert_origin_y; double vert_adv_y; -}; -struct SPFontClass { - SPObjectClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node* child); -GType sp_font_get_type (void); + virtual void set(unsigned int key, const gchar* value); + + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); +}; #endif //#ifndef SP_FONT_H_SEEN diff --git a/src/sp-glyph-kerning.cpp b/src/sp-glyph-kerning.cpp index 10884fb81..be47c7621 100644 --- a/src/sp-glyph-kerning.cpp +++ b/src/sp-glyph-kerning.cpp @@ -25,182 +25,118 @@ #include <string> #include <cstring> -static void sp_glyph_kerning_class_init(SPGlyphKerningClass *gc); -static void sp_glyph_kerning_init(SPGlyphKerning *glyph); -static void sp_glyph_kerning_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_glyph_kerning_release(SPObject *object); -static void sp_glyph_kerning_set(SPObject *object, unsigned int key, const gchar *value); -static Inkscape::XML::Node *sp_glyph_kerning_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_glyph_kerning_update(SPObject *object, SPCtx *ctx, guint flags); - -static SPObjectClass *parent_class; - -GType sp_glyph_kerning_h_get_type(void) -{ - static GType type = 0; - - if (!type) { - GTypeInfo info = { - sizeof(SPGlyphKerningClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) sp_glyph_kerning_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(SPHkern), - 16, /* n_preallocs */ - (GInstanceInitFunc) sp_glyph_kerning_init, - NULL, /* value_table */ - }; - type = g_type_register_static(SP_TYPE_OBJECT, "SPHkern", &info, (GTypeFlags) 0); - } - - return type; +SPGlyphKerning::SPGlyphKerning() : SPObject() { +//TODO: correct these values: + this->u1 = NULL; + this->g1 = NULL; + this->u2 = NULL; + this->g2 = NULL; + this->k = 0; } -GType sp_glyph_kerning_v_get_type(void) -{ - static GType type = 0; - - if (!type) { - GTypeInfo info = { - sizeof(SPGlyphKerningClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) sp_glyph_kerning_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(SPVkern), - 16, /* n_preallocs */ - (GInstanceInitFunc) sp_glyph_kerning_init, - NULL, /* value_table */ - }; - type = g_type_register_static(SP_TYPE_OBJECT, "SPVkern", &info, (GTypeFlags) 0); - } - - return type; +SPGlyphKerning::~SPGlyphKerning() { } -static void sp_glyph_kerning_class_init(SPGlyphKerningClass *gc) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) gc; +void SPGlyphKerning::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPObject::build(document, repr); - parent_class = (SPObjectClass*)g_type_class_peek_parent(gc); - - sp_object_class->build = sp_glyph_kerning_build; - sp_object_class->release = sp_glyph_kerning_release; - sp_object_class->set = sp_glyph_kerning_set; - sp_object_class->write = sp_glyph_kerning_write; - sp_object_class->update = sp_glyph_kerning_update; + this->readAttr( "u1" ); + this->readAttr( "g1" ); + this->readAttr( "u2" ); + this->readAttr( "g2" ); + this->readAttr( "k" ); } -static void sp_glyph_kerning_init(SPGlyphKerning *glyph) -{ -//TODO: correct these values: - glyph->u1 = NULL; - glyph->g1 = NULL; - glyph->u2 = NULL; - glyph->g2 = NULL; - glyph->k = 0; -} - -static void sp_glyph_kerning_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) (parent_class))->build) { - ((SPObjectClass *) (parent_class))->build(object, document, repr); - } - - object->readAttr( "u1" ); - object->readAttr( "g1" ); - object->readAttr( "u2" ); - object->readAttr( "g2" ); - object->readAttr( "k" ); -} - -static void sp_glyph_kerning_release(SPObject *object) -{ - //SPGlyphKerning *glyph = SP_GLYPH_KERNING(object); - - if (((SPObjectClass *) parent_class)->release) { - ((SPObjectClass *) parent_class)->release(object); - } +void SPGlyphKerning::release() { + SPObject::release(); } GlyphNames::GlyphNames(const gchar* value){ - if (value) this->names = strdup(value); + if (value) { + this->names = strdup(value); + } } GlyphNames::~GlyphNames(){ - if (this->names) g_free(this->names); + if (this->names) { + g_free(this->names); + } } bool GlyphNames::contains(const char* name){ - if (!(this->names) || !name) return false; + if (!(this->names) || !name) { + return false; + } + std::istringstream is(this->names); std::string str; std::string s(name); - while (is >> str){ - if (str == s) return true; + + while (is >> str) { + if (str == s) { + return true; + } } + return false; } -static void sp_glyph_kerning_set(SPObject *object, unsigned int key, const gchar *value) -{ - SPGlyphKerning * glyphkern = (SPGlyphKerning*) object; //even if it is a VKern this will work. I did it this way just to avoind warnings. - +void SPGlyphKerning::set(unsigned int key, const gchar *value) { switch (key) { case SP_ATTR_U1: { - if (glyphkern->u1) { - delete glyphkern->u1; + if (this->u1) { + delete this->u1; } - glyphkern->u1 = new UnicodeRange(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->u1 = new UnicodeRange(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } case SP_ATTR_U2: { - if (glyphkern->u2) { - delete glyphkern->u2; + if (this->u2) { + delete this->u2; } - glyphkern->u2 = new UnicodeRange(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->u2 = new UnicodeRange(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } case SP_ATTR_G1: { - if (glyphkern->g1) { - delete glyphkern->g1; + if (this->g1) { + delete this->g1; } - glyphkern->g1 = new GlyphNames(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->g1 = new GlyphNames(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } case SP_ATTR_G2: { - if (glyphkern->g2) { - delete glyphkern->g2; + if (this->g2) { + delete this->g2; } - glyphkern->g2 = new GlyphNames(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->g2 = new GlyphNames(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } case SP_ATTR_K: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != glyphkern->k){ - glyphkern->k = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->k){ + this->k = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } default: { - if (((SPObjectClass *) (parent_class))->set) { - ((SPObjectClass *) (parent_class))->set(object, key, value); - } + SPObject::set(key, value); break; } } @@ -209,62 +145,50 @@ static void sp_glyph_kerning_set(SPObject *object, unsigned int key, const gchar /** * * Receives update notifications. * */ -static void -sp_glyph_kerning_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPGlyphKerning *glyph = (SPGlyphKerning *)object; - (void)glyph; - +void SPGlyphKerning::update(SPCtx *ctx, guint flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { /* do something to trigger redisplay, updates? */ - object->readAttr( "u1" ); - object->readAttr( "u2" ); - object->readAttr( "g2" ); - object->readAttr( "k" ); + this->readAttr( "u1" ); + this->readAttr( "u2" ); + this->readAttr( "g2" ); + this->readAttr( "k" ); } - if (((SPObjectClass *) parent_class)->update) { - ((SPObjectClass *) parent_class)->update(object, ctx, flags); - } + SPObject::update(ctx, flags); } #define COPY_ATTR(rd,rs,key) (rd)->setAttribute((key), rs->attribute(key)); -static Inkscape::XML::Node *sp_glyph_kerning_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ -// SPGlyphKerning *glyph = SP_GLYPH_KERNING(object); - - if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = xml_doc->createElement("svg:glyphkerning");//fix this! - } - -/* I am commenting out this part because I am not certain how does it work. I will have to study it later. Juca - repr->setAttribute("unicode", glyph->unicode); - repr->setAttribute("glyph-name", glyph->glyph_name); - repr->setAttribute("d", glyph->d); - sp_repr_set_svg_double(repr, "orientation", (double) glyph->orientation); - sp_repr_set_svg_double(repr, "arabic-form", (double) glyph->arabic_form); - repr->setAttribute("lang", glyph->lang); - sp_repr_set_svg_double(repr, "horiz-adv-x", glyph->horiz_adv_x); - sp_repr_set_svg_double(repr, "vert-origin-x", glyph->vert_origin_x); - sp_repr_set_svg_double(repr, "vert-origin-y", glyph->vert_origin_y); - sp_repr_set_svg_double(repr, "vert-adv-y", glyph->vert_adv_y); -*/ - if (repr != object->getRepr()) { - // All the COPY_ATTR functions below use - // XML Tree directly, while they shouldn't. - COPY_ATTR(repr, object->getRepr(), "u1"); - COPY_ATTR(repr, object->getRepr(), "g1"); - COPY_ATTR(repr, object->getRepr(), "u2"); - COPY_ATTR(repr, object->getRepr(), "g2"); - COPY_ATTR(repr, object->getRepr(), "k"); - } - - if (((SPObjectClass *) (parent_class))->write) { - ((SPObjectClass *) (parent_class))->write(object, xml_doc, repr, flags); - } - - return repr; +Inkscape::XML::Node* SPGlyphKerning::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { + if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { + repr = xml_doc->createElement("svg:glyphkerning");//fix this! + } + + /* I am commenting out this part because I am not certain how does it work. I will have to study it later. Juca + repr->setAttribute("unicode", glyph->unicode); + repr->setAttribute("glyph-name", glyph->glyph_name); + repr->setAttribute("d", glyph->d); + sp_repr_set_svg_double(repr, "orientation", (double) glyph->orientation); + sp_repr_set_svg_double(repr, "arabic-form", (double) glyph->arabic_form); + repr->setAttribute("lang", glyph->lang); + sp_repr_set_svg_double(repr, "horiz-adv-x", glyph->horiz_adv_x); + sp_repr_set_svg_double(repr, "vert-origin-x", glyph->vert_origin_x); + sp_repr_set_svg_double(repr, "vert-origin-y", glyph->vert_origin_y); + sp_repr_set_svg_double(repr, "vert-adv-y", glyph->vert_adv_y); + */ + if (repr != this->getRepr()) { + // All the COPY_ATTR functions below use + // XML Tree directly, while they shouldn't. + COPY_ATTR(repr, this->getRepr(), "u1"); + COPY_ATTR(repr, this->getRepr(), "g1"); + COPY_ATTR(repr, this->getRepr(), "u2"); + COPY_ATTR(repr, this->getRepr(), "g2"); + COPY_ATTR(repr, this->getRepr(), "k"); + } + + SPObject::write(xml_doc, repr, flags); + + return repr; } /* Local Variables: diff --git a/src/sp-glyph-kerning.h b/src/sp-glyph-kerning.h index b7f733cad..5cae6b9dd 100644 --- a/src/sp-glyph-kerning.h +++ b/src/sp-glyph-kerning.h @@ -19,17 +19,23 @@ #include "sp-object.h" #include "unicoderange.h" -#define SP_TYPE_HKERN (sp_glyph_kerning_h_get_type ()) -#define SP_HKERN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_HKERN, SPHkern)) -#define SP_HKERN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_HKERN, SPGlyphKerningClass)) -#define SP_IS_HKERN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_HKERN)) -#define SP_IS_HKERN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_HKERN)) - -#define SP_TYPE_VKERN (sp_glyph_kerning_v_get_type ()) -#define SP_VKERN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_VKERN, SPVkern)) -#define SP_VKERN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_VKERN, SPGlyphKerningClass)) -#define SP_IS_VKERN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_VKERN)) -#define SP_IS_VKERN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_VKERN)) +//#define SP_HKERN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_HKERN, SPHkern)) +//#define SP_HKERN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_HKERN, SPGlyphKerningClass)) +//#define SP_IS_HKERN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_HKERN)) +//#define SP_IS_HKERN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_HKERN)) + +#define SP_HKERN(obj) (dynamic_cast<SPHkern*>((SPObject*)obj)) +#define SP_IS_HKERN(obj) (dynamic_cast<const SPHkern*>((SPObject*)obj) != NULL) + +//#define SP_VKERN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_VKERN, SPVkern)) +//#define SP_VKERN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_VKERN, SPGlyphKerningClass)) +//#define SP_IS_VKERN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_VKERN)) +//#define SP_IS_VKERN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_VKERN)) + +#define SP_VKERN(obj) (dynamic_cast<SPVkern*>((SPObject*)obj)) +#define SP_IS_VKERN(obj) (dynamic_cast<const SPVkern*>((SPObject*)obj) != NULL) + +// CPPIFY: These casting macros are buggy, as Vkern and Hkern aren't "real" classes. class GlyphNames{ public: @@ -40,22 +46,34 @@ private: gchar* names; }; -struct SPGlyphKerning : public SPObject { +class SPGlyphKerning : public SPObject { +public: + SPGlyphKerning(); + virtual ~SPGlyphKerning(); + UnicodeRange* u1; GlyphNames* g1; UnicodeRange* u2; GlyphNames* g2; double k; + +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void set(unsigned int key, const gchar* value); + + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); }; -struct SPHkern : public SPGlyphKerning {}; -struct SPVkern : public SPGlyphKerning {}; +class SPHkern : public SPGlyphKerning { -struct SPGlyphKerningClass { - SPObjectClass parent_class; }; -GType sp_glyph_kerning_h_get_type (void); -GType sp_glyph_kerning_v_get_type (void); +class SPVkern : public SPGlyphKerning { + +}; #endif //#ifndef __SP_GLYPH_KERNING_H__ diff --git a/src/sp-glyph.cpp b/src/sp-glyph.cpp index 0417ea8c1..695af03ba 100644 --- a/src/sp-glyph.cpp +++ b/src/sp-glyph.cpp @@ -22,87 +22,86 @@ #include "document.h" #include <cstring> -static void sp_glyph_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_glyph_release(SPObject *object); -static void sp_glyph_set(SPObject *object, unsigned int key, const gchar *value); -static Inkscape::XML::Node *sp_glyph_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_glyph_update(SPObject *object, SPCtx *ctx, guint flags); +#include "sp-factory.h" -G_DEFINE_TYPE(SPGlyph, sp_glyph, SP_TYPE_OBJECT); +namespace { + SPObject* createGlyph() { + return new SPGlyph(); + } -static void sp_glyph_class_init(SPGlyphClass *gc) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) gc; - - sp_object_class->build = sp_glyph_build; - sp_object_class->release = sp_glyph_release; - sp_object_class->set = sp_glyph_set; - sp_object_class->write = sp_glyph_write; - sp_object_class->update = sp_glyph_update; + bool glyphRegistered = SPFactory::instance().registerObject("svg:glyph", createGlyph); } -static void sp_glyph_init(SPGlyph *glyph) -{ +SPGlyph::SPGlyph() : SPObject() { //TODO: correct these values: - new (&glyph->unicode) Glib::ustring(); - new (&glyph->glyph_name) Glib::ustring(); - glyph->d = NULL; - glyph->orientation = GLYPH_ORIENTATION_BOTH; - glyph->arabic_form = GLYPH_ARABIC_FORM_INITIAL; - glyph->lang = NULL; - glyph->horiz_adv_x = 0; - glyph->vert_origin_x = 0; - glyph->vert_origin_y = 0; - glyph->vert_adv_y = 0; + this->d = NULL; + this->orientation = GLYPH_ORIENTATION_BOTH; + this->arabic_form = GLYPH_ARABIC_FORM_INITIAL; + this->lang = NULL; + this->horiz_adv_x = 0; + this->vert_origin_x = 0; + this->vert_origin_y = 0; + this->vert_adv_y = 0; } -static void sp_glyph_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) (sp_glyph_parent_class))->build) { - ((SPObjectClass *) (sp_glyph_parent_class))->build(object, document, repr); - } - - object->readAttr( "unicode" ); - object->readAttr( "glyph-name" ); - object->readAttr( "d" ); - object->readAttr( "orientation" ); - object->readAttr( "arabic-form" ); - object->readAttr( "lang" ); - object->readAttr( "horiz-adv-x" ); - object->readAttr( "vert-origin-x" ); - object->readAttr( "vert-origin-y" ); - object->readAttr( "vert-adv-y" ); +SPGlyph::~SPGlyph() { } -static void sp_glyph_release(SPObject *object) -{ - //SPGlyph *glyph = SP_GLYPH(object); +void SPGlyph::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPObject::build(document, repr); - if (((SPObjectClass *) sp_glyph_parent_class)->release) { - ((SPObjectClass *) sp_glyph_parent_class)->release(object); - } + this->readAttr( "unicode" ); + this->readAttr( "glyph-name" ); + this->readAttr( "d" ); + this->readAttr( "orientation" ); + this->readAttr( "arabic-form" ); + this->readAttr( "lang" ); + this->readAttr( "horiz-adv-x" ); + this->readAttr( "vert-origin-x" ); + this->readAttr( "vert-origin-y" ); + this->readAttr( "vert-adv-y" ); +} + +void SPGlyph::release() { + SPObject::release(); } static glyphArabicForm sp_glyph_read_arabic_form(gchar const *value){ - if (!value) return GLYPH_ARABIC_FORM_INITIAL; //TODO: verify which is the default default (for me, the spec is not clear) + if (!value) { + return GLYPH_ARABIC_FORM_INITIAL; //TODO: verify which is the default default (for me, the spec is not clear) + } + switch(value[0]){ case 'i': - if (strncmp(value, "initial", 7) == 0) return GLYPH_ARABIC_FORM_INITIAL; - if (strncmp(value, "isolated", 8) == 0) return GLYPH_ARABIC_FORM_ISOLATED; + if (strncmp(value, "initial", 7) == 0) { + return GLYPH_ARABIC_FORM_INITIAL; + } + + if (strncmp(value, "isolated", 8) == 0) { + return GLYPH_ARABIC_FORM_ISOLATED; + } break; case 'm': - if (strncmp(value, "medial", 6) == 0) return GLYPH_ARABIC_FORM_MEDIAL; + if (strncmp(value, "medial", 6) == 0) { + return GLYPH_ARABIC_FORM_MEDIAL; + } break; case 't': - if (strncmp(value, "terminal", 8) == 0) return GLYPH_ARABIC_FORM_TERMINAL; + if (strncmp(value, "terminal", 8) == 0) { + return GLYPH_ARABIC_FORM_TERMINAL; + } break; } + return GLYPH_ARABIC_FORM_INITIAL; //TODO: VERIFY DEFAULT! } static glyphOrientation sp_glyph_read_orientation(gchar const *value){ - if (!value) return GLYPH_ORIENTATION_BOTH; + if (!value) { + return GLYPH_ORIENTATION_BOTH; + } + switch(value[0]){ case 'h': return GLYPH_ORIENTATION_HORIZONTAL; @@ -111,102 +110,118 @@ static glyphOrientation sp_glyph_read_orientation(gchar const *value){ return GLYPH_ORIENTATION_VERTICAL; break; } + //ERROR? TODO: VERIFY PROPER ERROR HANDLING return GLYPH_ORIENTATION_BOTH; } -static void sp_glyph_set(SPObject *object, unsigned int key, const gchar *value) -{ - SPGlyph *glyph = SP_GLYPH(object); - +void SPGlyph::set(unsigned int key, const gchar *value) { switch (key) { case SP_ATTR_UNICODE: { - glyph->unicode.clear(); - if (value) glyph->unicode.append(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->unicode.clear(); + + if (value) { + this->unicode.append(value); + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } case SP_ATTR_GLYPH_NAME: { - glyph->glyph_name.clear(); - if (value) glyph->glyph_name.append(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->glyph_name.clear(); + + if (value) { + this->glyph_name.append(value); + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } case SP_ATTR_D: { - if (glyph->d) g_free(glyph->d); - glyph->d = g_strdup(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (this->d) { + g_free(this->d); + } + + this->d = g_strdup(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } case SP_ATTR_ORIENTATION: { glyphOrientation orient = sp_glyph_read_orientation(value); - if (glyph->orientation != orient){ - glyph->orientation = orient; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->orientation != orient){ + this->orientation = orient; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_ARABIC_FORM: { glyphArabicForm form = sp_glyph_read_arabic_form(value); - if (glyph->arabic_form != form){ - glyph->arabic_form = form; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (this->arabic_form != form){ + this->arabic_form = form; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_LANG: { - if (glyph->lang) g_free(glyph->lang); - glyph->lang = g_strdup(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (this->lang) { + g_free(this->lang); + } + + this->lang = g_strdup(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } case SP_ATTR_HORIZ_ADV_X: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != glyph->horiz_adv_x){ - glyph->horiz_adv_x = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->horiz_adv_x){ + this->horiz_adv_x = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_VERT_ORIGIN_X: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != glyph->vert_origin_x){ - glyph->vert_origin_x = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->vert_origin_x){ + this->vert_origin_x = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_VERT_ORIGIN_Y: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != glyph->vert_origin_y){ - glyph->vert_origin_y = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->vert_origin_y){ + this->vert_origin_y = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_VERT_ADV_Y: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != glyph->vert_adv_y){ - glyph->vert_adv_y = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + if (number != this->vert_adv_y){ + this->vert_adv_y = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } default: { - if (((SPObjectClass *) (sp_glyph_parent_class))->set) { - ((SPObjectClass *) (sp_glyph_parent_class))->set(object, key, value); - } + SPObject::set(key, value); break; } } @@ -215,73 +230,61 @@ static void sp_glyph_set(SPObject *object, unsigned int key, const gchar *value) /** * * Receives update notifications. * */ -static void -sp_glyph_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPGlyph *glyph = SP_GLYPH(object); - (void)glyph; - +void SPGlyph::update(SPCtx *ctx, guint flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { /* do something to trigger redisplay, updates? */ - object->readAttr( "unicode" ); - object->readAttr( "glyph-name" ); - object->readAttr( "d" ); - object->readAttr( "orientation" ); - object->readAttr( "arabic-form" ); - object->readAttr( "lang" ); - object->readAttr( "horiz-adv-x" ); - object->readAttr( "vert-origin-x" ); - object->readAttr( "vert-origin-y" ); - object->readAttr( "vert-adv-y" ); + this->readAttr( "unicode" ); + this->readAttr( "glyph-name" ); + this->readAttr( "d" ); + this->readAttr( "orientation" ); + this->readAttr( "arabic-form" ); + this->readAttr( "lang" ); + this->readAttr( "horiz-adv-x" ); + this->readAttr( "vert-origin-x" ); + this->readAttr( "vert-origin-y" ); + this->readAttr( "vert-adv-y" ); } - if (((SPObjectClass *) sp_glyph_parent_class)->update) { - ((SPObjectClass *) sp_glyph_parent_class)->update(object, ctx, flags); - } + SPObject::update(ctx, flags); } #define COPY_ATTR(rd,rs,key) (rd)->setAttribute((key), rs->attribute(key)); -static Inkscape::XML::Node *sp_glyph_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ -// SPGlyph *glyph = SP_GLYPH(object); - - if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = xml_doc->createElement("svg:glyph"); - } +Inkscape::XML::Node* SPGlyph::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { + if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { + repr = xml_doc->createElement("svg:glyph"); + } -/* I am commenting out this part because I am not certain how does it work. I will have to study it later. Juca - repr->setAttribute("unicode", glyph->unicode); - repr->setAttribute("glyph-name", glyph->glyph_name); - repr->setAttribute("d", glyph->d); - sp_repr_set_svg_double(repr, "orientation", (double) glyph->orientation); - sp_repr_set_svg_double(repr, "arabic-form", (double) glyph->arabic_form); - repr->setAttribute("lang", glyph->lang); - sp_repr_set_svg_double(repr, "horiz-adv-x", glyph->horiz_adv_x); - sp_repr_set_svg_double(repr, "vert-origin-x", glyph->vert_origin_x); - sp_repr_set_svg_double(repr, "vert-origin-y", glyph->vert_origin_y); - sp_repr_set_svg_double(repr, "vert-adv-y", glyph->vert_adv_y); -*/ - if (repr != object->getRepr()) { - // All the COPY_ATTR functions below use - // XML Tree directly while they shouldn't. - COPY_ATTR(repr, object->getRepr(), "unicode"); - COPY_ATTR(repr, object->getRepr(), "glyph-name"); - COPY_ATTR(repr, object->getRepr(), "d"); - COPY_ATTR(repr, object->getRepr(), "orientation"); - COPY_ATTR(repr, object->getRepr(), "arabic-form"); - COPY_ATTR(repr, object->getRepr(), "lang"); - COPY_ATTR(repr, object->getRepr(), "horiz-adv-x"); - COPY_ATTR(repr, object->getRepr(), "vert-origin-x"); - COPY_ATTR(repr, object->getRepr(), "vert-origin-y"); - COPY_ATTR(repr, object->getRepr(), "vert-adv-y"); - } + /* I am commenting out this part because I am not certain how does it work. I will have to study it later. Juca + repr->setAttribute("unicode", glyph->unicode); + repr->setAttribute("glyph-name", glyph->glyph_name); + repr->setAttribute("d", glyph->d); + sp_repr_set_svg_double(repr, "orientation", (double) glyph->orientation); + sp_repr_set_svg_double(repr, "arabic-form", (double) glyph->arabic_form); + repr->setAttribute("lang", glyph->lang); + sp_repr_set_svg_double(repr, "horiz-adv-x", glyph->horiz_adv_x); + sp_repr_set_svg_double(repr, "vert-origin-x", glyph->vert_origin_x); + sp_repr_set_svg_double(repr, "vert-origin-y", glyph->vert_origin_y); + sp_repr_set_svg_double(repr, "vert-adv-y", glyph->vert_adv_y); + */ + if (repr != this->getRepr()) { + // All the COPY_ATTR functions below use + // XML Tree directly while they shouldn't. + COPY_ATTR(repr, this->getRepr(), "unicode"); + COPY_ATTR(repr, this->getRepr(), "glyph-name"); + COPY_ATTR(repr, this->getRepr(), "d"); + COPY_ATTR(repr, this->getRepr(), "orientation"); + COPY_ATTR(repr, this->getRepr(), "arabic-form"); + COPY_ATTR(repr, this->getRepr(), "lang"); + COPY_ATTR(repr, this->getRepr(), "horiz-adv-x"); + COPY_ATTR(repr, this->getRepr(), "vert-origin-x"); + COPY_ATTR(repr, this->getRepr(), "vert-origin-y"); + COPY_ATTR(repr, this->getRepr(), "vert-adv-y"); + } - if (((SPObjectClass *) (sp_glyph_parent_class))->write) { - ((SPObjectClass *) (sp_glyph_parent_class))->write(object, xml_doc, repr, flags); - } + SPObject::write(xml_doc, repr, flags); - return repr; + return repr; } /* Local Variables: diff --git a/src/sp-glyph.h b/src/sp-glyph.h index 7556b0e25..798d9ff2f 100644 --- a/src/sp-glyph.h +++ b/src/sp-glyph.h @@ -18,11 +18,8 @@ #include "sp-object.h" -#define SP_TYPE_GLYPH (sp_glyph_get_type ()) -#define SP_GLYPH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_GLYPH, SPGlyph)) -#define SP_GLYPH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_GLYPH, SPGlyphClass)) -#define SP_IS_GLYPH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_GLYPH)) -#define SP_IS_GLYPH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_GLYPH)) +#define SP_GLYPH(obj) (dynamic_cast<SPGlyph*>((SPObject*)obj)) +#define SP_IS_GLYPH(obj) (dynamic_cast<const SPGlyph*>((SPObject*)obj) != NULL) enum glyphArabicForm { GLYPH_ARABIC_FORM_INITIAL, @@ -37,7 +34,11 @@ enum glyphOrientation { GLYPH_ORIENTATION_BOTH }; -struct SPGlyph : public SPObject { +class SPGlyph : public SPObject { +public: + SPGlyph(); + virtual ~SPGlyph(); + Glib::ustring unicode; Glib::ustring glyph_name; char* d; @@ -48,12 +49,16 @@ struct SPGlyph : public SPObject { double vert_origin_x; double vert_origin_y; double vert_adv_y; -}; -struct SPGlyphClass { - SPObjectClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); -GType sp_glyph_get_type (void); + virtual void set(unsigned int key, const gchar* value); + + virtual void update(SPCtx* ctx, unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); +}; #endif //#ifndef __SP_GLYPH_H__ diff --git a/src/sp-gradient-fns.h b/src/sp-gradient-fns.h deleted file mode 100644 index 165fd3ed8..000000000 --- a/src/sp-gradient-fns.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef SEEN_SP_GRADIENT_FNS_H -#define SEEN_SP_GRADIENT_FNS_H - -/** \file - * Macros and fn declarations related to gradients. - */ - -#include <glib.h> -#include <glib-object.h> -#include <2geom/forward.h> -#include "sp-gradient-spread.h" -#include "sp-gradient-units.h" - -class SPGradient; -struct SPMeshGradient; - -SPGradientSpread sp_gradient_get_spread (SPGradient *gradient); - -/* Gradient repr methods */ -void sp_gradient_repr_write_vector(SPGradient *gr); -void sp_gradient_repr_clear_vector(SPGradient *gr); - -void sp_meshgradient_repr_write(SPMeshGradient *mg); - -cairo_pattern_t *sp_gradient_create_preview_pattern(SPGradient *gradient, double width); - -/** Transforms to/from gradient position space in given environment */ -Geom::Affine sp_gradient_get_g2d_matrix(SPGradient const *gr, Geom::Affine const &ctm, - Geom::Rect const &bbox); -Geom::Affine sp_gradient_get_gs2d_matrix(SPGradient const *gr, Geom::Affine const &ctm, - Geom::Rect const &bbox); -void sp_gradient_set_gs2d_matrix(SPGradient *gr, Geom::Affine const &ctm, Geom::Rect const &bbox, - Geom::Affine const &gs2d); - - -#endif /* !SEEN_SP_GRADIENT_FNS_H */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-gradient.cpp b/src/sp-gradient.cpp index 1f2cfdd41..adfff3609 100644 --- a/src/sp-gradient.cpp +++ b/src/sp-gradient.cpp @@ -60,214 +60,6 @@ /// Has to be power of 2 Seems to be unused. //#define NCOLORS NR_GRADIENT_VECTOR_LENGTH -// SPStop -static void sp_stop_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_stop_set(SPObject *object, unsigned key, gchar const *value); -static Inkscape::XML::Node *sp_stop_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -G_DEFINE_TYPE(SPStop, sp_stop, SP_TYPE_OBJECT); - - -// SPMeshRow -static void sp_meshrow_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_meshrow_set(SPObject *object, unsigned key, gchar const *value); -static Inkscape::XML::Node *sp_meshrow_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -G_DEFINE_TYPE(SPMeshRow, sp_meshrow, SP_TYPE_OBJECT); - - -// SPMeshPatch -static void sp_meshpatch_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_meshpatch_set(SPObject *object, unsigned key, gchar const *value); -static Inkscape::XML::Node *sp_meshpatch_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -G_DEFINE_TYPE(SPMeshPatch, sp_meshpatch, SP_TYPE_OBJECT); - - -class SPGradientImpl -{ - friend class SPGradient; - - static void classInit(SPGradientClass *klass); - - static void init(SPGradient *gr); - static void build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); - static void release(SPObject *object); - static void modified(SPObject *object, guint flags); - static Inkscape::XML::Node *write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); - - static void gradientRefModified(SPObject *href, guint flags, SPGradient *gradient); - static void gradientRefChanged(SPObject *old_ref, SPObject *ref, SPGradient *gr); - - static void childAdded(SPObject *object, - Inkscape::XML::Node *child, - Inkscape::XML::Node *ref); - static void removeChild(SPObject *object, Inkscape::XML::Node *child); - - static void setGradientAttr(SPObject *object, unsigned key, gchar const *value); -}; - -/** - * Callback to initialize SPStop vtable. - */ -static void sp_stop_class_init(SPStopClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - - sp_object_class->build = sp_stop_build; - sp_object_class->set = sp_stop_set; - sp_object_class->write = sp_stop_write; -} - -/** - * Callback to initialize SPStop object. - */ -static void -sp_stop_init(SPStop *stop) -{ - stop->offset = 0.0; - stop->currentColor = false; - stop->specified_color.set( 0x000000ff ); - stop->opacity = 1.0; -} - -/** - * Virtual build: set stop attributes from its associated XML node. - */ -static void sp_stop_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_stop_parent_class)->build) - (* ((SPObjectClass *) sp_stop_parent_class)->build)(object, document, repr); - - object->readAttr( "offset" ); - object->readAttr( "stop-color" ); - object->readAttr( "stop-opacity" ); - object->readAttr( "style" ); - object->readAttr( "path" ); // For mesh -} - -/** - * Virtual set: set attribute to value. - */ -static void -sp_stop_set(SPObject *object, unsigned key, gchar const *value) -{ - SPStop *stop = SP_STOP(object); - - switch (key) { - case SP_ATTR_STYLE: { - /** \todo - * fixme: We are reading simple values 3 times during build (Lauris). - * \par - * We need presentation attributes etc. - * \par - * remove the hackish "style reading" from here: see comments in - * sp_object_get_style_property about the bugs in our current - * approach. However, note that SPStyle doesn't currently have - * stop-color and stop-opacity properties. - */ - { - gchar const *p = object->getStyleProperty( "stop-color", "black"); - if (streq(p, "currentColor")) { - stop->currentColor = true; - } else { - stop->specified_color = SPStop::readStopColor( p ); - } - } - { - gchar const *p = object->getStyleProperty( "stop-opacity", "1"); - gdouble opacity = sp_svg_read_percentage(p, stop->opacity); - stop->opacity = opacity; - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); - break; - } - case SP_PROP_STOP_COLOR: { - { - gchar const *p = object->getStyleProperty( "stop-color", "black"); - if (streq(p, "currentColor")) { - stop->currentColor = true; - } else { - stop->currentColor = false; - stop->specified_color = SPStop::readStopColor( p ); - } - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); - break; - } - case SP_PROP_STOP_OPACITY: { - { - gchar const *p = object->getStyleProperty( "stop-opacity", "1"); - gdouble opacity = sp_svg_read_percentage(p, stop->opacity); - stop->opacity = opacity; - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); - break; - } - case SP_ATTR_OFFSET: { - stop->offset = sp_svg_read_percentage(value, 0.0); - object->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); - break; - } - case SP_PROP_STOP_PATH: { - if (value) { - stop->path_string = new Glib::ustring( value ); - //Geom::PathVector pv = sp_svg_read_pathv(value); - //SPCurve *curve = new SPCurve(pv); - //if( curve ) { - // std::cout << "Got Curve" << std::endl; - //curve->unref(); - //} - } - break; - } - default: { - if (((SPObjectClass *) sp_stop_parent_class)->set) - (* ((SPObjectClass *) sp_stop_parent_class)->set)(object, key, value); - break; - } - } -} - -/** - * Virtual write: write object attributes to repr. - */ -static Inkscape::XML::Node * -sp_stop_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPStop *stop = SP_STOP(object); - - if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = xml_doc->createElement("svg:stop"); - } - - Glib::ustring colorStr = stop->specified_color.toString(); - gfloat opacity = stop->opacity; - - if (((SPObjectClass *) sp_stop_parent_class)->write) { - (* ((SPObjectClass *) sp_stop_parent_class)->write)(object, xml_doc, repr, flags); - } - - // Since we do a hackish style setting here (because SPStyle does not support stop-color and - // stop-opacity), we must do it AFTER calling the parent write method; otherwise - // sp_object_write would clear our style= attribute (bug 1695287) - - Inkscape::CSSOStringStream os; - os << "stop-color:"; - if (stop->currentColor) { - os << "currentColor"; - } else { - os << colorStr; - } - os << ";stop-opacity:" << opacity; - repr->setAttribute("style", os.str().c_str()); - repr->setAttribute("stop-color", NULL); - repr->setAttribute("stop-opacity", NULL); - sp_repr_set_css_double(repr, "offset", stop->offset); - /* strictly speaking, offset an SVG <number> rather than a CSS one, but exponents make no sense - * for offset proportions. */ - - return repr; -} - - bool SPGradient::hasStops() const { return has_stops; @@ -344,396 +136,196 @@ gboolean SPGradient::isEquivalent(SPGradient *that) } -/** - * Return stop's color as 32bit value. - */ -guint32 -sp_stop_get_rgba32(SPStop const *const stop) -{ - guint32 rgb0 = 0; - /* Default value: arbitrarily black. (SVG1.1 and CSS2 both say that the initial - * value depends on user agent, and don't give any further restrictions that I can - * see.) */ - if (stop->currentColor) { - char const *str = stop->getStyleProperty( "color", NULL); - if (str) { - rgb0 = sp_svg_read_color(str, rgb0); - } - unsigned const alpha = static_cast<unsigned>(stop->opacity * 0xff + 0.5); - g_return_val_if_fail((alpha & ~0xff) == 0, - rgb0 | 0xff); - return rgb0 | alpha; - } else { - return stop->specified_color.toRGBA32( stop->opacity ); - } -} - -/* - * Mesh Row - */ - -/** - * Callback to initialize SPMeshRow vtable. - */ -static void sp_meshrow_class_init(SPMeshRowClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - - sp_object_class->build = sp_meshrow_build; - sp_object_class->set = sp_meshrow_set; - sp_object_class->write = sp_meshrow_write; -} - -/** - * Callback to initialize SPMeshRow object. - */ -static void sp_meshrow_init(SPMeshRow * /*meshrow*/) -{ - // Do nothing -} - -/** - * Virtual build: set meshrow attributes from its associated XML node. - */ -static void sp_meshrow_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_meshrow_parent_class)->build) - (* ((SPObjectClass *) sp_meshrow_parent_class)->build)(object, document, repr); - - // No attributes -} - -/** - * Virtual set: set attribute to value. - */ -static void sp_meshrow_set(SPObject * /*object*/, unsigned /*key*/, gchar const * /*value*/) -{ - // Do nothing -} - -/** - * Virtual write: write object attributes to repr. - */ -static Inkscape::XML::Node * -sp_meshrow_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - //SPMeshRow *meshrow = SP_MESHROW(object); - - if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = xml_doc->createElement("svg:meshRow"); - } - - if (((SPObjectClass *) sp_meshrow_parent_class)->write) { - (* ((SPObjectClass *) sp_meshrow_parent_class)->write)(object, xml_doc, repr, flags); - } - - return repr; -} - -/* - * Mesh Patch - */ - -/** - * Callback to initialize SPMeshPatch vtable. - */ -static void sp_meshpatch_class_init(SPMeshPatchClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - - sp_object_class->build = sp_meshpatch_build; - sp_object_class->set = sp_meshpatch_set; - sp_object_class->write = sp_meshpatch_write; -} - -/** - * Callback to initialize SPMeshPatch object. - */ -static void sp_meshpatch_init(SPMeshPatch * /*meshpatch*/) -{ - // Do nothing -} - -/** - * Virtual build: set meshpatch attributes from its associated XML node. - */ -static void sp_meshpatch_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_meshpatch_parent_class)->build) - (* ((SPObjectClass *) sp_meshpatch_parent_class)->build)(object, document, repr); - - object->readAttr( "tensor" ); -} - -/** - * Virtual set: set attribute to value. - */ -static void -sp_meshpatch_set(SPObject *object, unsigned key, gchar const *value) -{ - SPMeshPatch *patch = SP_MESHPATCH(object); - - switch (key) { - case SP_ATTR_TENSOR: { - if (value) { - patch->tensor_string = new Glib::ustring( value ); - // std::cout << "sp_meshpatch_set: Tensor string: " << patch->tensor_string->c_str() << std::endl; - } - break; - } - default: { - // Do nothing - } - } -} - -/** - * Virtual write: write object attributes to repr. - */ -static Inkscape::XML::Node * -sp_meshpatch_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - //SPMeshPatch *meshpatch = SP_MESHPATCH(object); - - if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = xml_doc->createElement("svg:meshPatch"); - } - - if (((SPObjectClass *) sp_meshpatch_parent_class)->write) { - (* ((SPObjectClass *) sp_meshpatch_parent_class)->write)(object, xml_doc, repr, flags); - } - - return repr; -} - - /* * Gradient */ +SPGradient::SPGradient() : SPPaintServer(), units(), + spread(), + ref(NULL), + state(2), + vector() { -static SPPaintServerClass *gradient_parent_class; - -/** - * Registers SPGradient class and returns its type. - */ -GType SPGradient::getType() -{ - static GType gradient_type = 0; - if (!gradient_type) { - - GTypeInfo gradient_info = { - sizeof(SPGradientClass), - NULL, NULL, - (GClassInitFunc) SPGradientImpl::classInit, - NULL, NULL, - sizeof(SPGradient), - 16, - (GInstanceInitFunc) SPGradientImpl::init, - NULL, /* value_table */ - }; - gradient_type = g_type_register_static(SP_TYPE_PAINT_SERVER, "SPGradient", - &gradient_info, (GTypeFlags)0); - } - return gradient_type; -} - -/** - * SPGradient vtable initialization. - */ -void SPGradientImpl::classInit(SPGradientClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - - gradient_parent_class = (SPPaintServerClass *)g_type_class_ref(SP_TYPE_PAINT_SERVER); - - sp_object_class->build = SPGradientImpl::build; - sp_object_class->release = SPGradientImpl::release; - sp_object_class->set = SPGradientImpl::setGradientAttr; - sp_object_class->child_added = SPGradientImpl::childAdded; - sp_object_class->remove_child = SPGradientImpl::removeChild; - sp_object_class->modified = SPGradientImpl::modified; - sp_object_class->write = SPGradientImpl::write; -} + this->has_patches = 0; -/** - * Callback for SPGradient object initialization. - */ -void SPGradientImpl::init(SPGradient *gr) -{ - gr->ref = new SPGradientReference(gr); - gr->ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(SPGradientImpl::gradientRefChanged), gr)); + this->ref = new SPGradientReference(this); + this->ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(SPGradient::gradientRefChanged), this)); /** \todo * Fixme: reprs being rearranged (e.g. via the XML editor) * may require us to clear the state. */ - gr->state = SP_GRADIENT_STATE_UNKNOWN; + this->state = SP_GRADIENT_STATE_UNKNOWN; - gr->units = SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX; - gr->units_set = FALSE; + this->units = SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX; + this->units_set = FALSE; - gr->gradientTransform = Geom::identity(); - gr->gradientTransform_set = FALSE; + this->gradientTransform = Geom::identity(); + this->gradientTransform_set = FALSE; - gr->spread = SP_GRADIENT_SPREAD_PAD; - gr->spread_set = FALSE; + this->spread = SP_GRADIENT_SPREAD_PAD; + this->spread_set = FALSE; - gr->has_stops = FALSE; + this->has_stops = FALSE; - gr->vector.built = false; - gr->vector.stops.clear(); + this->vector.built = false; + this->vector.stops.clear(); + + //new (&this->modified_connection) sigc::connection(); +} - new (&gr->modified_connection) sigc::connection(); +SPGradient::~SPGradient() { } /** * Virtual build: set gradient attributes from its associated repr. */ -void SPGradientImpl::build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) +void SPGradient::build(SPDocument *document, Inkscape::XML::Node *repr) { - SPGradient *gradient = SP_GRADIENT(object); - // Work-around in case a swatch had been marked for immediate collection: if ( repr->attribute("osb:paint") && repr->attribute("inkscape:collect") ) { repr->setAttribute("inkscape:collect", 0); } - if (((SPObjectClass *) gradient_parent_class)->build) { - (* ((SPObjectClass *) gradient_parent_class)->build)(object, document, repr); - } + SPPaintServer::build(document, repr); - for ( SPObject *ochild = object->firstChild() ; ochild ; ochild = ochild->getNext() ) { + for ( SPObject *ochild = this->firstChild() ; ochild ; ochild = ochild->getNext() ) { if (SP_IS_STOP(ochild)) { - gradient->has_stops = TRUE; + this->has_stops = TRUE; break; } } - object->readAttr( "gradientUnits" ); - object->readAttr( "gradientTransform" ); - object->readAttr( "spreadMethod" ); - object->readAttr( "xlink:href" ); - object->readAttr( "osb:paint" ); + this->readAttr( "gradientUnits" ); + this->readAttr( "gradientTransform" ); + this->readAttr( "spreadMethod" ); + this->readAttr( "xlink:href" ); + this->readAttr( "osb:paint" ); // Register ourselves - document->addResource("gradient", object); + document->addResource("gradient", this); } /** * Virtual release of SPGradient members before destruction. */ -void SPGradientImpl::release(SPObject *object) +void SPGradient::release() { - SPGradient *gradient = (SPGradient *) object; #ifdef SP_GRADIENT_VERBOSE - g_print("Releasing gradient %s\n", object->getId()); + g_print("Releasing this %s\n", this->getId()); #endif - if (object->document) { + if (this->document) { // Unregister ourselves - object->document->removeResource("gradient", object); + this->document->removeResource("gradient", this); } - if (gradient->ref) { - gradient->modified_connection.disconnect(); - gradient->ref->detach(); - delete gradient->ref; - gradient->ref = NULL; + if (this->ref) { + this->modified_connection.disconnect(); + this->ref->detach(); + delete this->ref; + this->ref = NULL; } - gradient->modified_connection.~connection(); + //this->modified_connection.~connection(); - if (((SPObjectClass *) gradient_parent_class)->release) - ((SPObjectClass *) gradient_parent_class)->release(object); + SPPaintServer::release(); } /** * Set gradient attribute to value. */ -void SPGradientImpl::setGradientAttr(SPObject *object, unsigned key, gchar const *value) +void SPGradient::set(unsigned key, gchar const *value) { - SPGradient *gr = SP_GRADIENT(object); - switch (key) { case SP_ATTR_GRADIENTUNITS: if (value) { if (!strcmp(value, "userSpaceOnUse")) { - gr->units = SP_GRADIENT_UNITS_USERSPACEONUSE; + this->units = SP_GRADIENT_UNITS_USERSPACEONUSE; } else { - gr->units = SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX; + this->units = SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX; } - gr->units_set = TRUE; + + this->units_set = TRUE; } else { - gr->units = SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX; - gr->units_set = FALSE; + this->units = SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX; + this->units_set = FALSE; } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_GRADIENTTRANSFORM: { Geom::Affine t; if (value && sp_svg_transform_read(value, &t)) { - gr->gradientTransform = t; - gr->gradientTransform_set = TRUE; + this->gradientTransform = t; + this->gradientTransform_set = TRUE; } else { - gr->gradientTransform = Geom::identity(); - gr->gradientTransform_set = FALSE; + this->gradientTransform = Geom::identity(); + this->gradientTransform_set = FALSE; } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } case SP_ATTR_SPREADMETHOD: if (value) { if (!strcmp(value, "reflect")) { - gr->spread = SP_GRADIENT_SPREAD_REFLECT; + this->spread = SP_GRADIENT_SPREAD_REFLECT; } else if (!strcmp(value, "repeat")) { - gr->spread = SP_GRADIENT_SPREAD_REPEAT; + this->spread = SP_GRADIENT_SPREAD_REPEAT; } else { - gr->spread = SP_GRADIENT_SPREAD_PAD; + this->spread = SP_GRADIENT_SPREAD_PAD; } - gr->spread_set = TRUE; + + this->spread_set = TRUE; } else { - gr->spread_set = FALSE; + this->spread_set = FALSE; } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_XLINK_HREF: if (value) { try { - gr->ref->attach(Inkscape::URI(value)); + this->ref->attach(Inkscape::URI(value)); } catch (Inkscape::BadURIException &e) { g_warning("%s", e.what()); - gr->ref->detach(); + this->ref->detach(); } } else { - gr->ref->detach(); + this->ref->detach(); } break; + case SP_ATTR_OSB_SWATCH: { bool newVal = (value != 0); bool modified = false; - if (newVal != gr->swatch) { - gr->swatch = newVal; + + if (newVal != this->swatch) { + this->swatch = newVal; modified = true; } + if (newVal) { // Might need to flip solid/gradient - Glib::ustring paintVal = ( gr->hasStops() && (gr->getStopCount() == 0) ) ? "solid" : "gradient"; + Glib::ustring paintVal = ( this->hasStops() && (this->getStopCount() == 0) ) ? "solid" : "gradient"; + if ( paintVal != value ) { - gr->setAttribute( "osb:paint", paintVal.c_str(), 0 ); + this->setAttribute( "osb:paint", paintVal.c_str(), 0 ); modified = true; } } + if (modified) { - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } } break; default: - if (((SPObjectClass *) gradient_parent_class)->set) { - ((SPObjectClass *) gradient_parent_class)->set(object, key, value); - } + SPPaintServer::set(key, value); break; } } @@ -741,7 +333,7 @@ void SPGradientImpl::setGradientAttr(SPObject *object, unsigned key, gchar const /** * Gets called when the gradient is (re)attached to another gradient. */ -void SPGradientImpl::gradientRefChanged(SPObject *old_ref, SPObject *ref, SPGradient *gr) +void SPGradient::gradientRefChanged(SPObject *old_ref, SPObject *ref, SPGradient *gr) { if (old_ref) { gr->modified_connection.disconnect(); @@ -749,7 +341,7 @@ void SPGradientImpl::gradientRefChanged(SPObject *old_ref, SPObject *ref, SPGrad if ( SP_IS_GRADIENT(ref) && ref != gr ) { - gr->modified_connection = ref->connectModified(sigc::bind<2>(sigc::ptr_fun(&SPGradientImpl::gradientRefModified), gr)); + gr->modified_connection = ref->connectModified(sigc::bind<2>(sigc::ptr_fun(&SPGradient::gradientRefModified), gr)); } // Per SVG, all unset attributes must be inherited from linked gradient. @@ -770,83 +362,78 @@ void SPGradientImpl::gradientRefChanged(SPObject *old_ref, SPObject *ref, SPGrad /** * Callback for child_added event. */ -void SPGradientImpl::childAdded(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) +void SPGradient::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { - SPGradient *gr = SP_GRADIENT(object); - - gr->invalidateVector(); + this->invalidateVector(); - if (((SPObjectClass *) gradient_parent_class)->child_added) { - (* ((SPObjectClass *) gradient_parent_class)->child_added)(object, child, ref); - } + SPPaintServer::child_added(child, ref); - SPObject *ochild = object->get_child_by_repr(child); + SPObject *ochild = this->get_child_by_repr(child); if ( ochild && SP_IS_STOP(ochild) ) { - gr->has_stops = TRUE; - if ( gr->getStopCount() > 0 ) { - gchar const * attr = gr->getAttribute("osb:paint"); + this->has_stops = TRUE; + if ( this->getStopCount() > 0 ) { + gchar const * attr = this->getAttribute("osb:paint"); if ( attr && strcmp(attr, "gradient") ) { - gr->setAttribute( "osb:paint", "gradient", 0 ); + this->setAttribute( "osb:paint", "gradient", 0 ); } } } /// \todo Fixme: should we schedule "modified" here? - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } /** * Callback for remove_child event. */ -void SPGradientImpl::removeChild(SPObject *object, Inkscape::XML::Node *child) +void SPGradient::remove_child(Inkscape::XML::Node *child) { - SPGradient *gr = SP_GRADIENT(object); + this->invalidateVector(); - gr->invalidateVector(); + SPPaintServer::remove_child(child); - if (((SPObjectClass *) gradient_parent_class)->remove_child) { - (* ((SPObjectClass *) gradient_parent_class)->remove_child)(object, child); - } - - gr->has_stops = FALSE; - for ( SPObject *ochild = object->firstChild() ; ochild ; ochild = ochild->getNext() ) { + this->has_stops = FALSE; + for ( SPObject *ochild = this->firstChild() ; ochild ; ochild = ochild->getNext() ) { if (SP_IS_STOP(ochild)) { - gr->has_stops = TRUE; + this->has_stops = TRUE; break; } } - if ( gr->getStopCount() == 0 ) { - gchar const * attr = gr->getAttribute("osb:paint"); + if ( this->getStopCount() == 0 ) { + gchar const * attr = this->getAttribute("osb:paint"); + if ( attr && strcmp(attr, "solid") ) { - gr->setAttribute( "osb:paint", "solid", 0 ); + this->setAttribute( "osb:paint", "solid", 0 ); } } /* Fixme: should we schedule "modified" here? */ - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } /** * Callback for modified event. */ -void SPGradientImpl::modified(SPObject *object, guint flags) +void SPGradient::modified(guint flags) { - SPGradient *gr = SP_GRADIENT(object); - if (flags & SP_OBJECT_CHILD_MODIFIED_FLAG) { - if( gr->get_type() != SP_GRADIENT_TYPE_MESH ) { - gr->invalidateVector(); + // CPPIFY + //if( this->get_type() != SP_GRADIENT_TYPE_MESH ) { + if (!SP_IS_MESHGRADIENT(this)) { + this->invalidateVector(); } else { - gr->invalidateArray(); + this->invalidateArray(); } } if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { - if( gr->get_type() != SP_GRADIENT_TYPE_MESH ) { - gr->ensureVector(); + // CPPIFY + //if( this->get_type() != SP_GRADIENT_TYPE_MESH ) { + if (!SP_IS_MESHGRADIENT(this)) { + this->ensureVector(); } else { - gr->ensureArray(); + this->ensureArray(); } } @@ -855,18 +442,23 @@ void SPGradientImpl::modified(SPObject *object, guint flags) // FIXME: climb up the ladder of hrefs GSList *l = NULL; - for (SPObject *child = object->firstChild() ; child; child = child->getNext() ) { - g_object_ref(G_OBJECT(child)); + + for (SPObject *child = this->firstChild() ; child; child = child->getNext() ) { + sp_object_ref(child); l = g_slist_prepend(l, child); } + l = g_slist_reverse(l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->emitModified(flags); } - g_object_unref(G_OBJECT(child)); + + sp_object_unref(child); } } @@ -895,22 +487,21 @@ int SPGradient::getStopCount() const /** * Write gradient attributes to repr. */ -Inkscape::XML::Node *SPGradientImpl::write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) +Inkscape::XML::Node *SPGradient::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { - SPGradient *gr = SP_GRADIENT(object); - - if (((SPObjectClass *) gradient_parent_class)->write) { - (* ((SPObjectClass *) gradient_parent_class)->write)(object, xml_doc, repr, flags); - } + SPPaintServer::write(xml_doc, repr, flags); if (flags & SP_OBJECT_WRITE_BUILD) { GSList *l = NULL; - for (SPObject *child = object->firstChild(); child; child = child->getNext()) { + + for (SPObject *child = this->firstChild(); child; child = child->getNext()) { Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags); + if (crepr) { l = g_slist_prepend(l, crepr); } } + while (l) { repr->addChild((Inkscape::XML::Node *) l->data, NULL); Inkscape::GC::release((Inkscape::XML::Node *) l->data); @@ -918,14 +509,14 @@ Inkscape::XML::Node *SPGradientImpl::write(SPObject *object, Inkscape::XML::Docu } } - if (gr->ref->getURI()) { - gchar *uri_string = gr->ref->getURI()->toString(); + if (this->ref->getURI()) { + gchar *uri_string = this->ref->getURI()->toString(); repr->setAttribute("xlink:href", uri_string); g_free(uri_string); } - if ((flags & SP_OBJECT_WRITE_ALL) || gr->units_set) { - switch (gr->units) { + if ((flags & SP_OBJECT_WRITE_ALL) || this->units_set) { + switch (this->units) { case SP_GRADIENT_UNITS_USERSPACEONUSE: repr->setAttribute("gradientUnits", "userSpaceOnUse"); break; @@ -935,17 +526,17 @@ Inkscape::XML::Node *SPGradientImpl::write(SPObject *object, Inkscape::XML::Docu } } - if ((flags & SP_OBJECT_WRITE_ALL) || gr->gradientTransform_set) { - gchar *c=sp_svg_transform_write(gr->gradientTransform); + if ((flags & SP_OBJECT_WRITE_ALL) || this->gradientTransform_set) { + gchar *c=sp_svg_transform_write(this->gradientTransform); repr->setAttribute("gradientTransform", c); g_free(c); } - if ((flags & SP_OBJECT_WRITE_ALL) || gr->spread_set) { - /* FIXME: Ensure that gr->spread is the inherited value - * if !gr->spread_set. Not currently happening: see SPGradient::modified. + if ((flags & SP_OBJECT_WRITE_ALL) || this->spread_set) { + /* FIXME: Ensure that this->spread is the inherited value + * if !this->spread_set. Not currently happening: see SPGradient::modified. */ - switch (gr->spread) { + switch (this->spread) { case SP_GRADIENT_SPREAD_REFLECT: repr->setAttribute("spreadMethod", "reflect"); break; @@ -958,8 +549,8 @@ Inkscape::XML::Node *SPGradientImpl::write(SPObject *object, Inkscape::XML::Docu } } - if ( (flags & SP_OBJECT_WRITE_EXT) && gr->isSwatch() ) { - if ( gr->isSolid() ) { + if ( (flags & SP_OBJECT_WRITE_EXT) && this->isSwatch() ) { + if ( this->isSolid() ) { repr->setAttribute( "osb:paint", "solid" ); } else { repr->setAttribute( "osb:paint", "gradient" ); @@ -1191,7 +782,7 @@ sp_gradient_repr_write_vector(SPGradient *gr) } -void SPGradientImpl::gradientRefModified(SPObject */*href*/, guint /*flags*/, SPGradient *gradient) +void SPGradient::gradientRefModified(SPObject */*href*/, guint /*flags*/, SPGradient *gradient) { if ( gradient->invalidateVector() ) { gradient->requestModified(SP_OBJECT_MODIFIED_FLAG); @@ -1405,424 +996,12 @@ sp_gradient_set_gs2d_matrix(SPGradient *gr, Geom::Affine const &ctm, gr->requestModified(SP_OBJECT_MODIFIED_FLAG); } -/* - * Linear Gradient - */ -static void sp_lineargradient_build(SPObject *object, - SPDocument *document, - Inkscape::XML::Node *repr); -static void sp_lineargradient_set(SPObject *object, unsigned key, gchar const *value); -static Inkscape::XML::Node *sp_lineargradient_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, - guint flags); -static cairo_pattern_t *sp_lineargradient_create_pattern(SPPaintServer *ps, cairo_t *ct, Geom::OptRect const &bbox, double opacity); -G_DEFINE_TYPE(SPLinearGradient, sp_lineargradient, SP_TYPE_GRADIENT); -/** - * SPLinearGradient vtable initialization. - */ -static void sp_lineargradient_class_init(SPLinearGradientClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPPaintServerClass *ps_class = (SPPaintServerClass *) klass; - - sp_object_class->build = sp_lineargradient_build; - sp_object_class->set = sp_lineargradient_set; - sp_object_class->write = sp_lineargradient_write; - - ps_class->pattern_new = sp_lineargradient_create_pattern; -} - -/** - * Callback for SPLinearGradient object initialization. - */ -static void sp_lineargradient_init(SPLinearGradient *lg) -{ - lg->x1.unset(SVGLength::PERCENT, 0.0, 0.0); - lg->y1.unset(SVGLength::PERCENT, 0.0, 0.0); - lg->x2.unset(SVGLength::PERCENT, 1.0, 1.0); - lg->y2.unset(SVGLength::PERCENT, 0.0, 0.0); -} - -/** - * Callback: set attributes from associated repr. - */ -static void sp_lineargradient_build(SPObject *object, - SPDocument *document, - Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_lineargradient_parent_class)->build) - (* ((SPObjectClass *) sp_lineargradient_parent_class)->build)(object, document, repr); - - object->readAttr( "x1" ); - object->readAttr( "y1" ); - object->readAttr( "x2" ); - object->readAttr( "y2" ); -} - -/** - * Callback: set attribute. - */ -static void -sp_lineargradient_set(SPObject *object, unsigned key, gchar const *value) -{ - SPLinearGradient *lg = SP_LINEARGRADIENT(object); - - switch (key) { - case SP_ATTR_X1: - lg->x1.readOrUnset(value, SVGLength::PERCENT, 0.0, 0.0); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_Y1: - lg->y1.readOrUnset(value, SVGLength::PERCENT, 0.0, 0.0); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_X2: - lg->x2.readOrUnset(value, SVGLength::PERCENT, 1.0, 1.0); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_Y2: - lg->y2.readOrUnset(value, SVGLength::PERCENT, 0.0, 0.0); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - default: - if (((SPObjectClass *) sp_lineargradient_parent_class)->set) - (* ((SPObjectClass *) sp_lineargradient_parent_class)->set)(object, key, value); - break; - } -} - -/** - * Callback: write attributes to associated repr. - */ -static Inkscape::XML::Node * -sp_lineargradient_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPLinearGradient *lg = SP_LINEARGRADIENT(object); - - if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = xml_doc->createElement("svg:linearGradient"); - } - - if ((flags & SP_OBJECT_WRITE_ALL) || lg->x1._set) - sp_repr_set_svg_double(repr, "x1", lg->x1.computed); - if ((flags & SP_OBJECT_WRITE_ALL) || lg->y1._set) - sp_repr_set_svg_double(repr, "y1", lg->y1.computed); - if ((flags & SP_OBJECT_WRITE_ALL) || lg->x2._set) - sp_repr_set_svg_double(repr, "x2", lg->x2.computed); - if ((flags & SP_OBJECT_WRITE_ALL) || lg->y2._set) - sp_repr_set_svg_double(repr, "y2", lg->y2.computed); - - if (((SPObjectClass *) sp_lineargradient_parent_class)->write) - (* ((SPObjectClass *) sp_lineargradient_parent_class)->write)(object, xml_doc, repr, flags); - - return repr; -} - -/** - * Directly set properties of linear gradient and request modified. - */ -void -sp_lineargradient_set_position(SPLinearGradient *lg, - gdouble x1, gdouble y1, - gdouble x2, gdouble y2) -{ - g_return_if_fail(lg != NULL); - g_return_if_fail(SP_IS_LINEARGRADIENT(lg)); - - /* fixme: units? (Lauris) */ - lg->x1.set(SVGLength::NONE, x1, x1); - lg->y1.set(SVGLength::NONE, y1, y1); - lg->x2.set(SVGLength::NONE, x2, x2); - lg->y2.set(SVGLength::NONE, y2, y2); - - lg->requestModified(SP_OBJECT_MODIFIED_FLAG); -} - -/* - * Radial Gradient - */ - -static void sp_radialgradient_build(SPObject *object, - SPDocument *document, - Inkscape::XML::Node *repr); -static void sp_radialgradient_set(SPObject *object, unsigned key, gchar const *value); -static Inkscape::XML::Node *sp_radialgradient_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, - guint flags); -static cairo_pattern_t *sp_radialgradient_create_pattern(SPPaintServer *ps, cairo_t *ct, Geom::OptRect const &bbox, double opacity); -G_DEFINE_TYPE(SPRadialGradient, sp_radialgradient, SP_TYPE_GRADIENT); - -/** - * SPRadialGradient vtable initialization. - */ -static void sp_radialgradient_class_init(SPRadialGradientClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPPaintServerClass *ps_class = (SPPaintServerClass *) klass; - - sp_object_class->build = sp_radialgradient_build; - sp_object_class->set = sp_radialgradient_set; - sp_object_class->write = sp_radialgradient_write; - - ps_class->pattern_new = sp_radialgradient_create_pattern; -} - -/** - * Callback for SPRadialGradient object initialization. - */ -static void -sp_radialgradient_init(SPRadialGradient *rg) -{ - rg->cx.unset(SVGLength::PERCENT, 0.5, 0.5); - rg->cy.unset(SVGLength::PERCENT, 0.5, 0.5); - rg->r.unset(SVGLength::PERCENT, 0.5, 0.5); - rg->fx.unset(SVGLength::PERCENT, 0.5, 0.5); - rg->fy.unset(SVGLength::PERCENT, 0.5, 0.5); -} - -/** - * Set radial gradient attributes from associated repr. - */ -static void -sp_radialgradient_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_radialgradient_parent_class)->build) - (* ((SPObjectClass *) sp_radialgradient_parent_class)->build)(object, document, repr); - - object->readAttr( "cx" ); - object->readAttr( "cy" ); - object->readAttr( "r" ); - object->readAttr( "fx" ); - object->readAttr( "fy" ); -} - -/** - * Set radial gradient attribute. - */ -static void -sp_radialgradient_set(SPObject *object, unsigned key, gchar const *value) -{ - SPRadialGradient *rg = SP_RADIALGRADIENT(object); - - switch (key) { - case SP_ATTR_CX: - if (!rg->cx.read(value)) { - rg->cx.unset(SVGLength::PERCENT, 0.5, 0.5); - } - if (!rg->fx._set) { - rg->fx.value = rg->cx.value; - rg->fx.computed = rg->cx.computed; - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_CY: - if (!rg->cy.read(value)) { - rg->cy.unset(SVGLength::PERCENT, 0.5, 0.5); - } - if (!rg->fy._set) { - rg->fy.value = rg->cy.value; - rg->fy.computed = rg->cy.computed; - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_R: - if (!rg->r.read(value)) { - rg->r.unset(SVGLength::PERCENT, 0.5, 0.5); - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_FX: - if (!rg->fx.read(value)) { - rg->fx.unset(rg->cx.unit, rg->cx.value, rg->cx.computed); - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_FY: - if (!rg->fy.read(value)) { - rg->fy.unset(rg->cy.unit, rg->cy.value, rg->cy.computed); - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - default: - if (((SPObjectClass *) sp_radialgradient_parent_class)->set) - ((SPObjectClass *) sp_radialgradient_parent_class)->set(object, key, value); - break; - } -} - -/** - * Write radial gradient attributes to associated repr. - */ -static Inkscape::XML::Node * -sp_radialgradient_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPRadialGradient *rg = SP_RADIALGRADIENT(object); - - if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = xml_doc->createElement("svg:radialGradient"); - } - - if ((flags & SP_OBJECT_WRITE_ALL) || rg->cx._set) sp_repr_set_svg_double(repr, "cx", rg->cx.computed); - if ((flags & SP_OBJECT_WRITE_ALL) || rg->cy._set) sp_repr_set_svg_double(repr, "cy", rg->cy.computed); - if ((flags & SP_OBJECT_WRITE_ALL) || rg->r._set) sp_repr_set_svg_double(repr, "r", rg->r.computed); - if ((flags & SP_OBJECT_WRITE_ALL) || rg->fx._set) sp_repr_set_svg_double(repr, "fx", rg->fx.computed); - if ((flags & SP_OBJECT_WRITE_ALL) || rg->fy._set) sp_repr_set_svg_double(repr, "fy", rg->fy.computed); - - if (((SPObjectClass *) sp_radialgradient_parent_class)->write) - (* ((SPObjectClass *) sp_radialgradient_parent_class)->write)(object, xml_doc, repr, flags); - - return repr; -} - -/** - * Directly set properties of radial gradient and request modified. - */ -void -sp_radialgradient_set_position(SPRadialGradient *rg, - gdouble cx, gdouble cy, gdouble fx, gdouble fy, gdouble r) -{ - g_return_if_fail(rg != NULL); - g_return_if_fail(SP_IS_RADIALGRADIENT(rg)); - - /* fixme: units? (Lauris) */ - rg->cx.set(SVGLength::NONE, cx, cx); - rg->cy.set(SVGLength::NONE, cy, cy); - rg->fx.set(SVGLength::NONE, fx, fx); - rg->fy.set(SVGLength::NONE, fy, fy); - rg->r.set(SVGLength::NONE, r, r); - - rg->requestModified(SP_OBJECT_MODIFIED_FLAG); -} - -/* - * Mesh Gradient - */ - -//#define MESH_DEBUG - -static void sp_meshgradient_build(SPObject *object, - SPDocument *document, - Inkscape::XML::Node *repr); -static void sp_meshgradient_set(SPObject *object, unsigned key, gchar const *value); -static Inkscape::XML::Node *sp_meshgradient_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, - guint flags); -static cairo_pattern_t *sp_meshgradient_create_pattern(SPPaintServer *ps, cairo_t *ct, Geom::OptRect const &bbox, double opacity); -G_DEFINE_TYPE(SPMeshGradient, sp_meshgradient, SP_TYPE_GRADIENT); - -/** - * SPMeshGradient vtable initialization. - */ -static void sp_meshgradient_class_init(SPMeshGradientClass *klass) -{ -#ifdef MESH_DEBUG - std::cout << "sp_meshgradient_class_init()" << std::endl; -#endif - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPPaintServerClass *ps_class = (SPPaintServerClass *) klass; - - sp_object_class->build = sp_meshgradient_build; - sp_object_class->set = sp_meshgradient_set; - sp_object_class->write = sp_meshgradient_write; - - ps_class->pattern_new = sp_meshgradient_create_pattern; -} - -/** - * Callback for SPMeshGradient object initialization. - */ -static void -sp_meshgradient_init(SPMeshGradient *mg) -{ - // Start coordinate of mesh - mg->x.unset(SVGLength::NONE, 0.0, 0.0); - mg->y.unset(SVGLength::NONE, 0.0, 0.0); -} - -/** - * Set mesh gradient attributes from associated repr. - */ -static void -sp_meshgradient_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_meshgradient_parent_class)->build) - (* ((SPObjectClass *) sp_meshgradient_parent_class)->build)(object, document, repr); - - // Start coordinate of mesh - object->readAttr( "x" ); - object->readAttr( "y" ); -} - -/** - * Set mesh gradient attribute. - */ -static void -sp_meshgradient_set(SPObject *object, unsigned key, gchar const *value) -{ - SPMeshGradient *mg = SP_MESHGRADIENT(object); - - switch (key) { - case SP_ATTR_X: - if (!mg->x.read(value)) { - mg->x.unset(SVGLength::NONE, 0.0, 0.0); - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_Y: - if (!mg->y.read(value)) { - mg->y.unset(SVGLength::NONE, 0.0, 0.0); - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - default: - if (((SPObjectClass *) sp_meshgradient_parent_class)->set) - ((SPObjectClass *) sp_meshgradient_parent_class)->set(object, key, value); - break; - } -} - -/** - * Write mesh gradient attributes to associated repr. - */ -static Inkscape::XML::Node * -sp_meshgradient_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - -#ifdef MESH_DEBUG - std::cout << "sp_meshgradient_write() ***************************" << std::endl; -#endif - SPMeshGradient *mg = SP_MESHGRADIENT(object); - - if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = xml_doc->createElement("svg:meshGradient"); - } - - if ((flags & SP_OBJECT_WRITE_ALL) || mg->x._set) sp_repr_set_svg_double(repr, "x", mg->x.computed); - if ((flags & SP_OBJECT_WRITE_ALL) || mg->y._set) sp_repr_set_svg_double(repr, "y", mg->y.computed); - - if (((SPObjectClass *) sp_meshgradient_parent_class)->write) - (* ((SPObjectClass *) sp_meshgradient_parent_class)->write)(object, xml_doc, repr, flags); - - return repr; -} - -/** - * Directly set properties of mesh gradient and request modified. - */ -void -sp_meshgradient_set_position(SPMeshGradient *mg, gdouble x, gdouble y) -{ - g_return_if_fail(mg != NULL); - g_return_if_fail(SP_IS_MESHGRADIENT(mg)); - - mg->x.set(SVGLength::NONE, x, x); - mg->y.set(SVGLength::NONE, y, y); - - mg->requestModified(SP_OBJECT_MODIFIED_FLAG); -} /* CAIRO RENDERING STUFF */ -static void +void sp_gradient_pattern_common_setup(cairo_pattern_t *cp, SPGradient *gr, Geom::OptRect const &bbox, @@ -1860,216 +1039,14 @@ sp_gradient_pattern_common_setup(cairo_pattern_t *cp, ink_cairo_pattern_set_matrix(cp, gs2user.inverse()); } -static cairo_pattern_t * -sp_radialgradient_create_pattern(SPPaintServer *ps, - cairo_t *ct, - Geom::OptRect const &bbox, - double opacity) -{ - SPRadialGradient *rg = SP_RADIALGRADIENT(ps); - SPGradient *gr = SP_GRADIENT(ps); - - gr->ensureVector(); - - Geom::Point focus(rg->fx.computed, rg->fy.computed); - Geom::Point center(rg->cx.computed, rg->cy.computed); - double radius = rg->r.computed; - double scale = 1.0; - double tolerance = cairo_get_tolerance(ct); - - // NOTE: SVG2 will allow the use of a focus circle which can - // have its center outside the first circle. - - // code below suggested by Cairo devs to overcome tolerance problems - // more: https://bugs.freedesktop.org/show_bug.cgi?id=40918 - - // Corrected for - // https://bugs.launchpad.net/inkscape/+bug/970355 - - Geom::Affine gs2user = gr->gradientTransform; - Geom::Scale gs2user_scale; - - if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX && bbox) { - Geom::Affine bbox2user(bbox->width(), 0, 0, bbox->height(), bbox->left(), bbox->top()); - gs2user *= bbox2user; - gs2user_scale = Geom::Scale( gs2user[0], gs2user[3] ); - } - - Geom::Point d = focus - center; - Geom::Point d_user = d * gs2user_scale; - Geom::Point r_user( radius, 0 ); - r_user *= gs2user_scale; - - if (d_user.length() + tolerance > r_user.length()) { - scale = r_user.length() / d_user.length(); - double dx = d_user.x(), dy = d_user.y(); - cairo_user_to_device_distance(ct, &dx, &dy); - if (!Geom::are_near(dx, 0, tolerance) || - !Geom::are_near(dy, 0, tolerance)) - { - scale *= 1.0 - 2.0 * tolerance / hypot(dx, dy); - } - } - - cairo_pattern_t *cp = cairo_pattern_create_radial( - scale * d.x() + center.x(), scale * d.y() + center.y(), 0, - center.x(), center.y(), radius); - - sp_gradient_pattern_common_setup(cp, gr, bbox, opacity); - - return cp; -} - -static cairo_pattern_t *sp_meshgradient_create_pattern(SPPaintServer *ps, - cairo_t * /* ct */, -#if defined(MESH_DEBUG) || (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 4)) - Geom::OptRect const &bbox, - double opacity -#else - Geom::OptRect const & /*bbox*/, - double /*opacity*/ -#endif - ) -{ - using Geom::X; - using Geom::Y; - -#ifdef MESH_DEBUG - std::cout << "sp_meshgradient_create_pattern: (" << bbox->x0 << "," << bbox->y0 << ") (" << bbox->x1 << "," << bbox->y1 << ") " << opacity << std::endl; -#endif - //SPMeshGradient *mg = SP_MESHGRADIENT(ps); - SPGradient *gr = SP_GRADIENT(ps); - - gr->ensureArray(); - - cairo_pattern_t *cp = NULL; - -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 4) - SPMeshNodeArray* array = &(gr->array); - - cp = cairo_pattern_create_mesh(); - - for( unsigned int i = 0; i < array->patch_rows(); ++i ) { - for( unsigned int j = 0; j < array->patch_columns(); ++j ) { - - SPMeshPatchI patch( &(array->nodes), i, j ); - - cairo_mesh_pattern_begin_patch( cp ); - cairo_mesh_pattern_move_to( cp, patch.getPoint( 0, 0 )[X], patch.getPoint( 0, 0 )[Y] ); - - for( unsigned int k = 0; k < 4; ++k ) { -#ifdef DEBUG_MESH - std::cout << i << " " << j << " " - << patch.getPathType( k ) << " ("; - for( int p = 0; p < 4; ++p ) { - std::cout << patch.getPoint( k, p ); - } - std::cout << ") " - << patch.getColor( k ).toString() << std::endl; -#endif - - switch ( patch.getPathType( k ) ) { - case 'l': - case 'L': - case 'z': - case 'Z': - cairo_mesh_pattern_line_to( cp, - patch.getPoint( k, 3 )[X], - patch.getPoint( k, 3 )[Y] ); - break; - case 'c': - case 'C': - { - std::vector< Geom::Point > pts = patch.getPointsForSide( k ); - cairo_mesh_pattern_curve_to( cp, - pts[1][X], pts[1][Y], - pts[2][X], pts[2][Y], - pts[3][X], pts[3][Y] ); - break; - } - default: - // Shouldn't happen - std::cout << "sp_meshgradient_create_pattern: path error" << std::endl; - } - - if( patch.tensorIsSet(k) ) { - // Tensor point defined relative to corner. - Geom::Point t = patch.getTensorPoint(k); - cairo_mesh_pattern_set_control_point( cp, k, t[X], t[Y] ); - //std::cout << " sp_meshgradient_create_pattern: tensor " << k - // << " set to " << t << "." << std::endl; - } else { - // Geom::Point t = patch.coonsTensorPoint(k); - //std::cout << " sp_meshgradient_create_pattern: tensor " << k - // << " calculated as " << t << "." <<std::endl; - } - - cairo_mesh_pattern_set_corner_color_rgba( - cp, k, - patch.getColor( k ).v.c[0], - patch.getColor( k ).v.c[1], - patch.getColor( k ).v.c[2], - patch.getOpacity( k ) * opacity ); - } - - cairo_mesh_pattern_end_patch( cp ); - } - } - - // set pattern matrix - Geom::Affine gs2user = gr->gradientTransform; - if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) { - Geom::Affine bbox2user(bbox->width(), 0, 0, bbox->height(), bbox->left(), bbox->top()); - gs2user *= bbox2user; - } - ink_cairo_pattern_set_matrix(cp, gs2user.inverse()); - -#else - static bool shown = false; - if( !shown ) { - std::cout << "sp_meshgradient_create_pattern: needs cairo >= 1.11.4, using " - << cairo_version_string() << std::endl; - shown = true; - } -#endif - -/* - cairo_pattern_t *cp = cairo_pattern_create_radial( - rg->fx.computed, rg->fy.computed, 0, - rg->cx.computed, rg->cy.computed, rg->r.computed); - sp_gradient_pattern_common_setup(cp, gr, bbox, opacity); -*/ - - return cp; -} - -static cairo_pattern_t * -sp_lineargradient_create_pattern(SPPaintServer *ps, - cairo_t */* ct */, - Geom::OptRect const &bbox, - double opacity) -{ - SPLinearGradient *lg = SP_LINEARGRADIENT(ps); - SPGradient *gr = SP_GRADIENT(ps); - - gr->ensureVector(); - - cairo_pattern_t *cp = cairo_pattern_create_linear( - lg->x1.computed, lg->y1.computed, - lg->x2.computed, lg->y2.computed); - - sp_gradient_pattern_common_setup(cp, gr, bbox, opacity); - - return cp; -} - cairo_pattern_t * sp_gradient_create_preview_pattern(SPGradient *gr, double width) { cairo_pattern_t *pat = NULL; - if( gr->get_type() != SP_GRADIENT_TYPE_MESH ) { - + // CPPIFY + //if( gr->get_type() != SP_GRADIENT_TYPE_MESH ) { + if (!SP_IS_MESHGRADIENT(gr)) { gr->ensureVector(); pat = cairo_pattern_create_linear(0, 0, width, 0); @@ -2085,13 +1062,6 @@ sp_gradient_create_preview_pattern(SPGradient *gr, double width) return pat; } -void -sp_meshgradient_repr_write(SPMeshGradient *mg) -{ - mg->array.write( mg ); -} - - /* Local Variables: mode:c++ diff --git a/src/sp-gradient.h b/src/sp-gradient.h index 57ffa5570..46eb41cdb 100644 --- a/src/sp-gradient.h +++ b/src/sp-gradient.h @@ -27,14 +27,22 @@ #include <stddef.h> #include <sigc++/connection.h> + + +//#include <glib.h> +//#include <glib-object.h> +//#include <2geom/forward.h> +//#include "sp-gradient-spread.h" +//#include "sp-gradient-units.h" +// +//class SPGradient; +//struct SPMeshGradient; + class SPGradientReference; -struct SPStop; +class SPStop; -#define SP_TYPE_GRADIENT (SPGradient::getType()) -#define SP_GRADIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_GRADIENT, SPGradient)) -#define SP_GRADIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_GRADIENT, SPGradientClass)) -#define SP_IS_GRADIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_GRADIENT)) -#define SP_IS_GRADIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_GRADIENT)) +#define SP_GRADIENT(obj) (dynamic_cast<SPGradient*>((SPObject*)obj)) +#define SP_IS_GRADIENT(obj) (dynamic_cast<const SPGradient*>((SPObject*)obj) != NULL) enum SPGradientType { SP_GRADIENT_TYPE_UNKNOWN, @@ -87,7 +95,6 @@ std::vector<PaintTarget> const &allPaintTargets(); } // namespace Inkscape - /** * Gradient * @@ -95,6 +102,10 @@ std::vector<PaintTarget> const &allPaintTargets(); * \todo fixme: Implement more here (Lauris) */ class SPGradient : public SPPaintServer { +public: + SPGradient(); + virtual ~SPGradient(); + private: /** gradientUnits attribute */ SPGradientUnits units; @@ -117,14 +128,6 @@ private: guint has_patches : 1; public: - SPGradient() : - units(), - spread(), - ref(NULL), - state(2), - vector() - {} - /** Reference (href) */ SPGradientReference *ref; @@ -192,26 +195,49 @@ public: void setSwatch(bool swatch = true); + static void gradientRefModified(SPObject *href, guint flags, SPGradient *gradient); + static void gradientRefChanged(SPObject *old_ref, SPObject *ref, SPGradient *gr); + private: bool invalidateVector(); bool invalidateArray(); void rebuildVector(); void rebuildArray(); - friend class SPGradientImpl; -// friend class SPLGPainter; -// friend class SPRGPainter; -}; +protected: + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void release(); + virtual void modified(guint flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); -/** - * The SPGradient vtable. - */ -struct SPGradientClass { - SPPaintServerClass parent_class; + virtual void child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref); + virtual void remove_child(Inkscape::XML::Node *child); + + virtual void set(unsigned key, gchar const *value); }; +void +sp_gradient_pattern_common_setup(cairo_pattern_t *cp, + SPGradient *gr, + Geom::OptRect const &bbox, + double opacity); + +/* Gradient repr methods */ +void sp_gradient_repr_write_vector(SPGradient *gr); +void sp_gradient_repr_clear_vector(SPGradient *gr); + +void sp_meshgradient_repr_write(SPMeshGradient *mg); + +cairo_pattern_t *sp_gradient_create_preview_pattern(SPGradient *gradient, double width); + +/** Transforms to/from gradient position space in given environment */ +Geom::Affine sp_gradient_get_g2d_matrix(SPGradient const *gr, Geom::Affine const &ctm, + Geom::Rect const &bbox); +Geom::Affine sp_gradient_get_gs2d_matrix(SPGradient const *gr, Geom::Affine const &ctm, + Geom::Rect const &bbox); +void sp_gradient_set_gs2d_matrix(SPGradient *gr, Geom::Affine const &ctm, Geom::Rect const &bbox, + Geom::Affine const &gs2d); -#include "sp-gradient-fns.h" #endif // SEEN_SP_GRADIENT_H diff --git a/src/sp-guide.cpp b/src/sp-guide.cpp index 961e53e04..039edc90f 100644 --- a/src/sp-guide.cpp +++ b/src/sp-guide.cpp @@ -46,144 +46,158 @@ using Inkscape::DocumentUndo; using std::vector; -enum { - PROP_0, - PROP_COLOR, - PROP_HICOLOR -}; - -static void sp_guide_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void sp_guide_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); - -static void sp_guide_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_guide_release(SPObject *object); -static void sp_guide_set(SPObject *object, unsigned int key, const gchar *value); - -G_DEFINE_TYPE(SPGuide, sp_guide, SP_TYPE_OBJECT); - -static void sp_guide_class_init(SPGuideClass *gc) -{ - GObjectClass *gobject_class = (GObjectClass *) gc; - SPObjectClass *sp_object_class = (SPObjectClass *) gc; - - gobject_class->set_property = sp_guide_set_property; - gobject_class->get_property = sp_guide_get_property; - - sp_object_class->build = sp_guide_build; - sp_object_class->release = sp_guide_release; - sp_object_class->set = sp_guide_set; - - g_object_class_install_property(gobject_class, - PROP_COLOR, - g_param_spec_uint("color", "Color", "Color", - 0, - 0xffffffff, - 0xff000000, - (GParamFlags) G_PARAM_READWRITE)); - - g_object_class_install_property(gobject_class, - PROP_HICOLOR, - g_param_spec_uint("hicolor", "HiColor", "HiColor", - 0, - 0xffffffff, - 0xff000000, - (GParamFlags) G_PARAM_READWRITE)); +//enum { +// PROP_0, +// PROP_COLOR, +// PROP_HICOLOR +//}; +// +//static void sp_guide_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +//static void sp_guide_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +#include "sp-factory.h" + +namespace { + SPObject* createGuide() { + return new SPGuide(); + } + + bool guideRegistered = SPFactory::instance().registerObject("sodipodi:guide", createGuide); } -static void sp_guide_init(SPGuide *guide) -{ - guide->normal_to_line = Geom::Point(0.,1.); - guide->point_on_line = Geom::Point(0.,0.); - guide->color = 0x0000ff7f; - guide->hicolor = 0xff00007f; +//static void sp_guide_class_init(SPGuideClass *gc) +//{ +// GObjectClass *gobject_class = (GObjectClass *) gc; +// +// gobject_class->set_property = sp_guide_set_property; +// gobject_class->get_property = sp_guide_get_property; +// +// g_object_class_install_property(gobject_class, +// PROP_COLOR, +// g_param_spec_uint("color", "Color", "Color", +// 0, +// 0xffffffff, +// 0xff000000, +// (GParamFlags) G_PARAM_READWRITE)); +// +// g_object_class_install_property(gobject_class, +// PROP_HICOLOR, +// g_param_spec_uint("hicolor", "HiColor", "HiColor", +// 0, +// 0xffffffff, +// 0xff000000, +// (GParamFlags) G_PARAM_READWRITE)); +//} +// CPPIFY: properties! + +SPGuide::SPGuide() : SPObject() { + this->label = NULL; + this->views = NULL; + + this->normal_to_line = Geom::Point(0.,1.); + this->point_on_line = Geom::Point(0.,0.); + this->color = 0x0000ff7f; + this->hicolor = 0xff00007f; } -static void sp_guide_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec */*pspec*/) -{ - SPGuide &guide = *SP_GUIDE(object); +SPGuide::~SPGuide() { +} - switch (prop_id) { - case PROP_COLOR: - guide.color = g_value_get_uint(value); - for (GSList *l = guide.views; l != NULL; l = l->next) { - sp_guideline_set_color(SP_GUIDELINE(l->data), guide.color); - } - break; +guint32 SPGuide::getColor() const { + return color; +} - case PROP_HICOLOR: - guide.hicolor = g_value_get_uint(value); - break; - } +guint32 SPGuide::getHiColor() const { + return hicolor; } -static void sp_guide_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec */*pspec*/) -{ - SPGuide const &guide = *SP_GUIDE(object); +void SPGuide::setColor(guint32 c) { + color = c; - switch (prop_id) { - case PROP_COLOR: - g_value_set_uint(value, guide.color); - break; - case PROP_HICOLOR: - g_value_set_uint(value, guide.hicolor); - break; - } + for (GSList *l = this->views; l != NULL; l = l->next) { + sp_guideline_set_color(SP_GUIDELINE(l->data), this->color); + } } -static void sp_guide_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if ((SP_OBJECT_CLASS(sp_guide_parent_class))->build) { - (* (SP_OBJECT_CLASS(sp_guide_parent_class))->build)(object, document, repr); - } +void SPGuide::setHiColor(guint32 h) { + this->hicolor = h; +} - object->readAttr( "inkscape:label" ); - object->readAttr( "orientation" ); - object->readAttr( "position" ); +//static void sp_guide_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec */*pspec*/) +//{ +// SPGuide &guide = *SP_GUIDE(object); +// +// switch (prop_id) { +// case PROP_COLOR: +// guide.color = g_value_get_uint(value); +// for (GSList *l = guide.views; l != NULL; l = l->next) { +// sp_guideline_set_color(SP_GUIDELINE(l->data), guide.color); +// } +// break; +// +// case PROP_HICOLOR: +// guide.hicolor = g_value_get_uint(value); +// break; +// } +//} +// +//static void sp_guide_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec */*pspec*/) +//{ +// SPGuide const &guide = *SP_GUIDE(object); +// +// switch (prop_id) { +// case PROP_COLOR: +// g_value_set_uint(value, guide.color); +// break; +// case PROP_HICOLOR: +// g_value_set_uint(value, guide.hicolor); +// break; +// } +//} + +void SPGuide::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPObject::build(document, repr); + + this->readAttr( "inkscape:label" ); + this->readAttr( "orientation" ); + this->readAttr( "position" ); /* Register */ - document->addResource("guide", object); + document->addResource("guide", this); } -static void sp_guide_release(SPObject *object) -{ - SPGuide *guide = (SPGuide *) object; - - while (guide->views) { - sp_guideline_delete(SP_GUIDELINE(guide->views->data)); - guide->views = g_slist_remove(guide->views, guide->views->data); +void SPGuide::release() { + while (this->views) { + sp_guideline_delete(SP_GUIDELINE(this->views->data)); + this->views = g_slist_remove(this->views, this->views->data); } - if (object->document) { + if (this->document) { // Unregister ourselves - object->document->removeResource("guide", object); + this->document->removeResource("guide", this); } - if ((SP_OBJECT_CLASS(sp_guide_parent_class))->release) { - (SP_OBJECT_CLASS(sp_guide_parent_class))->release(object); - } + SPObject::release(); } -static void sp_guide_set(SPObject *object, unsigned int key, const gchar *value) -{ - SPGuide *guide = SP_GUIDE(object); - +void SPGuide::set(unsigned int key, const gchar *value) { switch (key) { case SP_ATTR_INKSCAPE_LABEL: if (value) { - guide->label = g_strdup(value); + this->label = g_strdup(value); } else { - guide->label = NULL; + this->label = NULL; } - sp_guide_set_label(*guide, guide->label, false); + sp_guide_set_label(*this, this->label, false); break; case SP_ATTR_ORIENTATION: { if (value && !strcmp(value, "horizontal")) { /* Visual representation of a horizontal line, constrain vertically (y coordinate). */ - guide->normal_to_line = Geom::Point(0., 1.); + this->normal_to_line = Geom::Point(0., 1.); } else if (value && !strcmp(value, "vertical")) { - guide->normal_to_line = Geom::Point(1., 0.); + this->normal_to_line = Geom::Point(1., 0.); } else if (value) { gchar ** strarray = g_strsplit(value, ",", 2); double newx, newy; @@ -193,16 +207,16 @@ static void sp_guide_set(SPObject *object, unsigned int key, const gchar *value) if (success == 2 && (fabs(newx) > 1e-6 || fabs(newy) > 1e-6)) { Geom::Point direction(newx, newy); direction.normalize(); - guide->normal_to_line = direction; + this->normal_to_line = direction; } else { // default to vertical line for bad arguments - guide->normal_to_line = Geom::Point(1., 0.); + this->normal_to_line = Geom::Point(1., 0.); } } else { // default to vertical line for bad arguments - guide->normal_to_line = Geom::Point(1., 0.); + this->normal_to_line = Geom::Point(1., 0.); } - sp_guide_set_normal(*guide, guide->normal_to_line, false); + sp_guide_set_normal(*this, this->normal_to_line, false); } break; case SP_ATTR_POSITION: @@ -214,29 +228,27 @@ static void sp_guide_set(SPObject *object, unsigned int key, const gchar *value) success += sp_svg_number_read_d(strarray[1], &newy); g_strfreev (strarray); if (success == 2) { - guide->point_on_line = Geom::Point(newx, newy); + this->point_on_line = Geom::Point(newx, newy); } else if (success == 1) { // before 0.46 style guideline definition. - const gchar *attr = object->getRepr()->attribute("orientation"); + const gchar *attr = this->getRepr()->attribute("orientation"); if (attr && !strcmp(attr, "horizontal")) { - guide->point_on_line = Geom::Point(0, newx); + this->point_on_line = Geom::Point(0, newx); } else { - guide->point_on_line = Geom::Point(newx, 0); + this->point_on_line = Geom::Point(newx, 0); } } } else { // default to (0,0) for bad arguments - guide->point_on_line = Geom::Point(0,0); + this->point_on_line = Geom::Point(0,0); } // update position in non-committing way // fixme: perhaps we need to add an update method instead, and request_update here - sp_guide_moveto(*guide, guide->point_on_line, false); + sp_guide_moveto(*this, this->point_on_line, false); } break; default: - if ((SP_OBJECT_CLASS(sp_guide_parent_class))->set) { - (SP_OBJECT_CLASS(sp_guide_parent_class))->set(object, key, value); - } + SPObject::set(key, value); break; } } diff --git a/src/sp-guide.h b/src/sp-guide.h index 45ce405cd..fa4f0033b 100644 --- a/src/sp-guide.h +++ b/src/sp-guide.h @@ -23,17 +23,15 @@ struct SPCanvas; struct SPCanvasGroup; class SPDesktop; -G_BEGIN_DECLS - -#define SP_TYPE_GUIDE (sp_guide_get_type()) -#define SP_GUIDE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_GUIDE, SPGuide)) -#define SP_GUIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_GUIDE, SPGuideClass)) -#define SP_IS_GUIDE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_GUIDE)) -#define SP_IS_GUIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_GUIDE)) +#define SP_GUIDE(obj) (dynamic_cast<SPGuide*>((SPObject*)obj)) +#define SP_IS_GUIDE(obj) (dynamic_cast<const SPGuide*>((SPObject*)obj) != NULL) /* Represents the constraint on p that dot(g.direction, p) == g.position. */ class SPGuide : public SPObject { public: + SPGuide(); + virtual ~SPGuide(); + char* label; Geom::Point normal_to_line; Geom::Point point_on_line; @@ -43,6 +41,11 @@ public: GSList *views; std::vector<SPGuideAttachment> attached_items; + guint32 getColor() const; + guint32 getHiColor() const; + void setColor(guint32 c); + void setHiColor(guint32 h); + inline bool isHorizontal() const { return (normal_to_line[Geom::X] == 0.); }; inline bool isVertical() const { return (normal_to_line[Geom::Y] == 0.); }; inline double angle() const { return std::atan2( - normal_to_line[Geom::X], normal_to_line[Geom::Y] ); }; @@ -52,15 +55,13 @@ public: void sensitize(SPCanvas *canvas, gboolean sensitive); Geom::Point getPositionFrom(Geom::Point const &pt) const; double getDistanceFrom(Geom::Point const &pt) const; -}; -class SPGuideClass { -public: - SPObjectClass parent_class; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + virtual void set(unsigned int key, const gchar* value); }; -GType sp_guide_get_type(); - void sp_guide_pt_pairs_to_guides(SPDocument *doc, std::list<std::pair<Geom::Point, Geom::Point> > &pts); void sp_guide_create_guides_around_page(SPDesktop *dt); void sp_guide_delete_all_guides(SPDesktop *dt); @@ -73,8 +74,6 @@ void sp_guide_remove(SPGuide *guide); char *sp_guide_description(SPGuide const *guide, const bool verbose = true); -G_END_DECLS - #endif // SEEN_SP_GUIDE_H /* diff --git a/src/sp-image.cpp b/src/sp-image.cpp index 0e692eb40..80daf33c3 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -17,9 +17,6 @@ # include "config.h" #endif -// This has to be included prior to anything that includes setjmp.h, it croaks otherwise -#include <png.h> - #include <cstring> #include <algorithm> #include <string> @@ -43,8 +40,9 @@ #include "xml/repr.h" #include "snap-candidate.h" #include "preferences.h" - #include "io/sys.h" +#include "sp-factory.h" + #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) #include "cms-system.h" #include "color-profile.h" @@ -75,23 +73,9 @@ #define MAGIC_EPSILON_TOO 1e-18 // TODO: also check if it is correct to be using two different epsilon values -static void sp_image_build (SPObject * object, SPDocument * document, Inkscape::XML::Node * repr); -static void sp_image_release (SPObject * object); -static void sp_image_set (SPObject *object, unsigned int key, const gchar *value); -static void sp_image_update (SPObject *object, SPCtx *ctx, unsigned int flags); -static void sp_image_modified (SPObject *object, unsigned int flags); -static Inkscape::XML::Node *sp_image_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -static Geom::OptRect sp_image_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type); -static void sp_image_print (SPItem * item, SPPrintContext *ctx); -static gchar * sp_image_description (SPItem * item); -static void sp_image_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); -static Inkscape::DrawingItem *sp_image_show (SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); -static Geom::Affine sp_image_set_transform (SPItem *item, Geom::Affine const &xform); static void sp_image_set_curve(SPImage *image); -static GdkPixbuf *sp_image_repr_read_image( time_t& modTime, gchar*& pixPath, const gchar *href, const gchar *absref, const gchar *base ); -static GdkPixbuf *sp_image_pixbuf_force_rgba (GdkPixbuf * pixbuf); +static Inkscape::Pixbuf *sp_image_repr_read_image(gchar const *href, gchar const *absref, gchar const *base ); static void sp_image_update_arenaitem (SPImage *img, Inkscape::DrawingImage *ai); static void sp_image_update_canvas_image (SPImage *image); static GdkPixbuf * sp_image_repr_read_dataURI (const gchar * uri_data); @@ -130,211 +114,131 @@ extern guint update_in_progress; #define DEBUG_MESSAGE_SCISLAC(key, ...) #endif // DEBUG_LCMS -namespace Inkscape { -namespace IO { - -GdkPixbuf* pixbuf_new_from_file(const char *filename, time_t &modTime, gchar*& pixPath) -{ - GdkPixbuf* buf = NULL; - modTime = 0; - if ( pixPath ) { - g_free(pixPath); - pixPath = NULL; - } - - //test correctness of filename - if (!g_file_test (filename, G_FILE_TEST_EXISTS)){ - return NULL; - } - struct stat stdir; - int val = g_stat(filename, &stdir); - if (stdir.st_mode & S_IFDIR){ - g_warning("Linked image file %s is a directory", filename); - return NULL; - } - - // we need to load the entire pixbuf into memory - gchar *data = NULL; - gsize len = 0; - - if (g_file_get_contents(filename, &data, &len, NULL)) { - if (!val) { - modTime = stdir.st_mtime; - pixPath = g_strdup(filename); - } - - GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); - gdk_pixbuf_loader_write(loader, (guchar *) data, len, NULL); - gdk_pixbuf_loader_close(loader, NULL); - - buf = gdk_pixbuf_loader_get_pixbuf(loader); - if (buf) { - g_object_ref(buf); - buf = sp_image_pixbuf_force_rgba(buf); - pixbuf_set_mime_data(buf, (guchar *) data, len, gdk_pixbuf_loader_get_format(loader)); - } else { - g_free(data); - g_warning("Error loading pixbuf"); - } - - // TODO: we could also read DPI, ICC profile, gamma correction, and other information - // from the file. This can be done by using format-specific libraries e.g. libpng. - } else { - g_warning("Unable to open linked file: %s", filename); - } - - return buf; +namespace { +SPObject* createImage() { + return new SPImage(); } -} +bool imageRegistered = SPFactory::instance().registerObject("svg:image", createImage); } -G_DEFINE_TYPE(SPImage, sp_image, SP_TYPE_ITEM); +SPImage::SPImage() : SPItem() { + this->aspect_clip = 0; -static void sp_image_class_init( SPImageClass * klass ) -{ - SPObjectClass *sp_object_class = SP_OBJECT_CLASS(klass); - SPItemClass *item_class = SP_ITEM_CLASS(klass); - - sp_object_class->build = sp_image_build; - sp_object_class->release = sp_image_release; - sp_object_class->set = sp_image_set; - sp_object_class->update = sp_image_update; - sp_object_class->modified = sp_image_modified; - sp_object_class->write = sp_image_write; - - item_class->bbox = sp_image_bbox; - item_class->print = sp_image_print; - item_class->description = sp_image_description; - item_class->show = sp_image_show; - item_class->snappoints = sp_image_snappoints; - item_class->set_transform = sp_image_set_transform; -} + this->x.unset(); + this->y.unset(); + this->width.unset(); + this->height.unset(); + this->aspect_align = SP_ASPECT_NONE; + this->clipbox = Geom::Rect(); + this->sx = this->sy = 1.0; + this->ox = this->oy = 0.0; -static void sp_image_init( SPImage *image ) -{ - image->x.unset(); - image->y.unset(); - image->width.unset(); - image->height.unset(); - image->aspect_align = SP_ASPECT_NONE; - image->clipbox = Geom::Rect(); - image->sx = image->sy = 1.0; - image->ox = image->oy = 0.0; - - image->curve = NULL; - - image->href = 0; + this->curve = NULL; + + this->href = 0; #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - image->color_profile = 0; + this->color_profile = 0; #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - image->pixbuf = 0; - image->pixPath = 0; - image->lastMod = 0; + this->pixbuf = 0; } -static void sp_image_build( SPObject *object, SPDocument *document, Inkscape::XML::Node *repr ) -{ - if (((SPObjectClass *) sp_image_parent_class)->build) { - ((SPObjectClass *) sp_image_parent_class)->build (object, document, repr); - } +SPImage::~SPImage() { +} + +void SPImage::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPItem::build(document, repr); - object->readAttr( "xlink:href" ); - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "width" ); - object->readAttr( "height" ); - object->readAttr( "preserveAspectRatio" ); - object->readAttr( "color-profile" ); + this->readAttr( "xlink:href" ); + this->readAttr( "x" ); + this->readAttr( "y" ); + this->readAttr( "width" ); + this->readAttr( "height" ); + this->readAttr( "preserveAspectRatio" ); + this->readAttr( "color-profile" ); /* Register */ - document->addResource("image", object); + document->addResource("image", this); } -static void sp_image_release( SPObject *object ) -{ - SPImage *image = SP_IMAGE(object); - - if (object->document) { +void SPImage::release() { + if (this->document) { // Unregister ourselves - object->document->removeResource("image", object); + this->document->removeResource("image", this); } - if (image->href) { - g_free (image->href); - image->href = NULL; + if (this->href) { + g_free (this->href); + this->href = NULL; } - if (image->pixbuf) { - g_object_set_data(G_OBJECT(image->pixbuf), "cairo_surface", NULL); - g_object_unref (image->pixbuf); - image->pixbuf = NULL; - } + delete this->pixbuf; + this->pixbuf = NULL; #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - if (image->color_profile) { - g_free (image->color_profile); - image->color_profile = NULL; + if (this->color_profile) { + g_free (this->color_profile); + this->color_profile = NULL; } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - if (image->pixPath) { - g_free(image->pixPath); - image->pixPath = 0; - } - - if (image->curve) { - image->curve = image->curve->unref(); + if (this->curve) { + this->curve = this->curve->unref(); } - if (((SPObjectClass *) sp_image_parent_class)->release) { - ((SPObjectClass *) sp_image_parent_class)->release (object); - } + SPItem::release(); } -static void sp_image_set( SPObject *object, unsigned int key, const gchar *value ) -{ - SPImage *image = SP_IMAGE (object); - +void SPImage::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_XLINK_HREF: - g_free (image->href); - image->href = (value) ? g_strdup (value) : NULL; - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_IMAGE_HREF_MODIFIED_FLAG); + g_free (this->href); + this->href = (value) ? g_strdup (value) : NULL; + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_IMAGE_HREF_MODIFIED_FLAG); break; + case SP_ATTR_X: - if (!image->x.readAbsolute(value)) { + if (!this->x.readAbsolute(value)) { /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */ - image->x.unset(); + this->x.unset(); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_Y: - if (!image->y.readAbsolute(value)) { + if (!this->y.readAbsolute(value)) { /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */ - image->y.unset(); + this->y.unset(); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_WIDTH: - if (!image->width.readAbsolute(value)) { + if (!this->width.readAbsolute(value)) { /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */ - image->width.unset(); + this->width.unset(); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_HEIGHT: - if (!image->height.readAbsolute(value)) { + if (!this->height.readAbsolute(value)) { /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */ - image->height.unset(); + this->height.unset(); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_PRESERVEASPECTRATIO: /* Do setup before, so we can use break to escape */ - image->aspect_align = SP_ASPECT_NONE; - image->aspect_clip = SP_ASPECT_MEET; - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + this->aspect_align = SP_ASPECT_NONE; + this->aspect_clip = SP_ASPECT_MEET; + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + if (value) { int len; gchar c[256]; @@ -373,8 +277,11 @@ static void sp_image_set( SPObject *object, unsigned int key, const gchar *value } else { break; } + clip = SP_ASPECT_MEET; + while (*e && *e == 32) e += 1; + if (*e) { if (!strcmp (e, "meet")) { clip = SP_ASPECT_MEET; @@ -384,90 +291,81 @@ static void sp_image_set( SPObject *object, unsigned int key, const gchar *value break; } } - image->aspect_align = align; - image->aspect_clip = clip; + + this->aspect_align = align; + this->aspect_clip = clip; } break; #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) case SP_PROP_COLOR_PROFILE: - if ( image->color_profile ) { - g_free (image->color_profile); + if ( this->color_profile ) { + g_free (this->color_profile); } - image->color_profile = (value) ? g_strdup (value) : NULL; + + this->color_profile = (value) ? g_strdup (value) : NULL; if ( value ) { - DEBUG_MESSAGE( lcmsFour, "<image> color-profile set to '%s'", value ); + DEBUG_MESSAGE( lcmsFour, "<this> color-profile set to '%s'", value ); } else { - DEBUG_MESSAGE( lcmsFour, "<image> color-profile cleared" ); + DEBUG_MESSAGE( lcmsFour, "<this> color-profile cleared" ); } // TODO check on this HREF_MODIFIED flag - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_IMAGE_HREF_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_IMAGE_HREF_MODIFIED_FLAG); break; + #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) default: - if (((SPObjectClass *) (sp_image_parent_class))->set) - ((SPObjectClass *) (sp_image_parent_class))->set (object, key, value); + SPItem::set(key, value); break; } - sp_image_set_curve(image); //creates a curve at the image's boundary for snapping + sp_image_set_curve(this); //creates a curve at the image's boundary for snapping } -static void sp_image_update( SPObject *object, SPCtx *ctx, unsigned int flags ) -{ - SPImage *image = SP_IMAGE(object); - SPDocument *doc = object->document; +void SPImage::update(SPCtx *ctx, unsigned int flags) { + SPDocument *doc = this->document; - if (((SPObjectClass *) (sp_image_parent_class))->update) { - ((SPObjectClass *) (sp_image_parent_class))->update (object, ctx, flags); - } + SPItem::update(ctx, flags); if (flags & SP_IMAGE_HREF_MODIFIED_FLAG) { - if (image->pixbuf) { - g_object_unref (image->pixbuf); - image->pixbuf = NULL; - } - if ( image->pixPath ) { - g_free(image->pixPath); - image->pixPath = 0; - } - image->lastMod = 0; - if (image->href) { - GdkPixbuf *pixbuf; - pixbuf = sp_image_repr_read_image ( - image->lastMod, - image->pixPath, - - //XML Tree being used directly while it shouldn't be. - object->getRepr()->attribute("xlink:href"), + delete this->pixbuf; + this->pixbuf = NULL; - //XML Tree being used directly while it shouldn't be. - object->getRepr()->attribute("sodipodi:absref"), + if (this->href) { + Inkscape::Pixbuf *pixbuf = NULL; + pixbuf = sp_image_repr_read_image ( + this->getRepr()->attribute("xlink:href"), + this->getRepr()->attribute("sodipodi:absref"), doc->getBase()); + if (pixbuf) { // BLIP #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - if ( image->color_profile ) + if ( this->color_profile ) { - int imagewidth = gdk_pixbuf_get_width( pixbuf ); - int imageheight = gdk_pixbuf_get_height( pixbuf ); - int rowstride = gdk_pixbuf_get_rowstride( pixbuf ); - guchar* px = gdk_pixbuf_get_pixels( pixbuf ); + // TODO: this will prevent using MIME data when exporting. + // Integrate color correction into loading. + pixbuf->ensurePixelFormat(Inkscape::Pixbuf::PF_GDK); + int imagewidth = pixbuf->width(); + int imageheight = pixbuf->height(); + int rowstride = pixbuf->rowstride();; + guchar* px = pixbuf->pixels(); if ( px ) { DEBUG_MESSAGE( lcmsFive, "in <image>'s sp_image_update. About to call colorprofile_get_handle()" ); guint profIntent = Inkscape::RENDERING_INTENT_UNKNOWN; - cmsHPROFILE prof = Inkscape::CMSSystem::getHandle( object->document, + cmsHPROFILE prof = Inkscape::CMSSystem::getHandle( this->document, &profIntent, - image->color_profile ); + this->color_profile ); if ( prof ) { cmsProfileClassSignature profileClass = cmsGetDeviceClass( prof ); if ( profileClass != cmsSigNamedColorClass ) { int intent = INTENT_PERCEPTUAL; + switch ( profIntent ) { case Inkscape::RENDERING_INTENT_RELATIVE_COLORIMETRIC: intent = INTENT_RELATIVE_COLORIMETRIC; @@ -484,6 +382,7 @@ static void sp_image_update( SPObject *object, SPCtx *ctx, unsigned int flags ) default: intent = INTENT_PERCEPTUAL; } + cmsHPROFILE destProf = cmsCreate_sRGBProfile(); cmsHTRANSFORM transf = cmsCreateTransform( prof, TYPE_RGBA_8, @@ -514,39 +413,40 @@ static void sp_image_update( SPObject *object, SPCtx *ctx, unsigned int flags ) } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - image->pixbuf = pixbuf; + this->pixbuf = pixbuf; } } } - if (image->pixbuf) { + if (this->pixbuf) { /* fixme: We are slightly violating spec here (Lauris) */ - if (!image->width._set) { - image->width.computed = gdk_pixbuf_get_width(image->pixbuf); + if (!this->width._set) { + this->width.computed = this->pixbuf->width(); } - if (!image->height._set) { - image->height.computed = gdk_pixbuf_get_height(image->pixbuf); + + if (!this->height._set) { + this->height.computed = this->pixbuf->height(); } } - Geom::Point p(image->x.computed, image->y.computed); - Geom::Point wh(image->width.computed, image->height.computed); - image->clipbox = Geom::Rect(p, p + wh); + this->clipbox = Geom::Rect::from_xywh( + this->x.computed, this->y.computed, + this->width.computed, this->height.computed); - image->ox = image->x.computed; - image->oy = image->y.computed; + this->ox = this->x.computed; + this->oy = this->y.computed; - int pixwidth = gdk_pixbuf_get_width (image->pixbuf); - int pixheight = gdk_pixbuf_get_height (image->pixbuf); + int pixwidth = this->pixbuf->width(); + int pixheight = this->pixbuf->height(); - image->sx = image->width.computed / pixwidth; - image->sy = image->height.computed / pixheight; + this->sx = this->width.computed / pixwidth; + this->sy = this->height.computed / pixheight; // preserveAspectRatio calculate bounds / clipping rectangle -- EAF - if (image->pixbuf && (image->aspect_align != SP_ASPECT_NONE)) { + if (this->pixbuf && (this->aspect_align != SP_ASPECT_NONE)) { double x, y; - switch (image->aspect_align) { + switch (this->aspect_align) { case SP_ASPECT_XMIN_YMIN: x = 0.0; y = 0.0; @@ -589,127 +489,117 @@ static void sp_image_update( SPObject *object, SPCtx *ctx, unsigned int flags ) break; } - if (image->aspect_clip == SP_ASPECT_SLICE) { - double scale = std::max(image->sx, image->sy); - image->sx = scale; - image->sy = scale; + if (this->aspect_clip == SP_ASPECT_SLICE) { + double scale = std::max(this->sx, this->sy); + this->sx = scale; + this->sy = scale; } else { - double scale = std::min(image->sx, image->sy); - image->sx = scale; - image->sy = scale; + double scale = std::min(this->sx, this->sy); + this->sx = scale; + this->sy = scale; } - double vw = pixwidth * image->sx; - double vh = pixheight * image->sy; - image->ox += x * (image->width.computed - vw); - image->oy += y * (image->height.computed - vh); + double vw = pixwidth * this->sx; + double vh = pixheight * this->sy; + this->ox += x * (this->width.computed - vw); + this->oy += y * (this->height.computed - vh); } - sp_image_update_canvas_image ((SPImage *) object); + sp_image_update_canvas_image ((SPImage *) this); } -static void sp_image_modified( SPObject *object, unsigned int flags ) -{ - SPImage *image = SP_IMAGE (object); - - if (((SPObjectClass *) (sp_image_parent_class))->modified) { - (* ((SPObjectClass *) (sp_image_parent_class))->modified) (object, flags); - } +void SPImage::modified(unsigned int flags) { +// SPItem::onModified(flags); if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { - for (SPItemView *v = image->display; v != NULL; v = v->next) { + for (SPItemView *v = this->display; v != NULL; v = v->next) { Inkscape::DrawingImage *img = dynamic_cast<Inkscape::DrawingImage *>(v->arenaitem); - img->setStyle(object->style); + img->setStyle(this->style); } } } -static Inkscape::XML::Node *sp_image_write( SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags ) -{ - SPImage *image = SP_IMAGE (object); +Inkscape::XML::Node *SPImage::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags ) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:image"); } - repr->setAttribute("xlink:href", image->href); + repr->setAttribute("xlink:href", this->href); + /* fixme: Reset attribute if needed (Lauris) */ - if (image->x._set) { - sp_repr_set_svg_double(repr, "x", image->x.computed); + if (this->x._set) { + sp_repr_set_svg_double(repr, "x", this->x.computed); } - if (image->y._set) { - sp_repr_set_svg_double(repr, "y", image->y.computed); + + if (this->y._set) { + sp_repr_set_svg_double(repr, "y", this->y.computed); } - if (image->width._set) { - sp_repr_set_svg_double(repr, "width", image->width.computed); + + if (this->width._set) { + sp_repr_set_svg_double(repr, "width", this->width.computed); } - if (image->height._set) { - sp_repr_set_svg_double(repr, "height", image->height.computed); + + if (this->height._set) { + sp_repr_set_svg_double(repr, "height", this->height.computed); } //XML Tree being used directly here while it shouldn't be... - repr->setAttribute("preserveAspectRatio", object->getRepr()->attribute("preserveAspectRatio")); + repr->setAttribute("preserveAspectRatio", this->getRepr()->attribute("preserveAspectRatio")); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - if (image->color_profile) { - repr->setAttribute("color-profile", image->color_profile); + if (this->color_profile) { + repr->setAttribute("color-profile", this->color_profile); } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - if (((SPObjectClass *) (sp_image_parent_class))->write) { - ((SPObjectClass *) (sp_image_parent_class))->write (object, xml_doc, repr, flags); - } + SPItem::write(xml_doc, repr, flags); return repr; } -static Geom::OptRect sp_image_bbox( SPItem const *item,Geom::Affine const &transform, SPItem::BBoxType /*type*/ ) -{ - SPImage const &image = *SP_IMAGE(item); +Geom::OptRect SPImage::bbox(Geom::Affine const &transform, SPItem::BBoxType type) { Geom::OptRect bbox; - if ((image.width.computed > 0.0) && (image.height.computed > 0.0)) { - bbox = Geom::Rect::from_xywh(image.x.computed, image.y.computed, image.width.computed, image.height.computed); + if ((this->width.computed > 0.0) && (this->height.computed > 0.0)) { + bbox = Geom::Rect::from_xywh(this->x.computed, this->y.computed, this->width.computed, this->height.computed); *bbox *= transform; } + return bbox; } -static void sp_image_print( SPItem *item, SPPrintContext *ctx ) -{ - SPImage *image = SP_IMAGE(item); +void SPImage::print(SPPrintContext *ctx) { + if (this->pixbuf && (this->width.computed > 0.0) && (this->height.computed > 0.0) ) { + Inkscape::Pixbuf *pb = new Inkscape::Pixbuf(*this->pixbuf); + pb->ensurePixelFormat(Inkscape::Pixbuf::PF_GDK); - if (image->pixbuf && (image->width.computed > 0.0) && (image->height.computed > 0.0) ) { - GdkPixbuf *pb = gdk_pixbuf_copy(image->pixbuf); - // GObject data is not copied, so we have to set the pixel format explicitly - g_object_set_data_full(G_OBJECT(pb), "pixel_format", g_strdup("argb32"), g_free); - ink_pixbuf_ensure_normal(pb); + guchar *px = pb->pixels(); + int w = pb->width(); + int h = pb->height(); + int rs = pb->rowstride(); + //int pixskip = gdk_pixbuf_get_n_channels(pb) * gdk_pixbuf_get_bits_per_sample(pb) / 8; + int pixskip = 4; - guchar *px = gdk_pixbuf_get_pixels(pb); - int w = gdk_pixbuf_get_width(pb); - int h = gdk_pixbuf_get_height(pb); - int rs = gdk_pixbuf_get_rowstride(pb); - int pixskip = gdk_pixbuf_get_n_channels(pb) * gdk_pixbuf_get_bits_per_sample(pb) / 8; - - if (image->aspect_align == SP_ASPECT_NONE) { + if (this->aspect_align == SP_ASPECT_NONE) { Geom::Affine t; - Geom::Translate tp(image->x.computed, image->y.computed); - Geom::Scale s(image->width.computed, -image->height.computed); + Geom::Translate tp(this->x.computed, this->y.computed); + Geom::Scale s(this->width.computed, -this->height.computed); Geom::Translate ti(0.0, -1.0); t = s * tp; t = ti * t; - sp_print_image_R8G8B8A8_N(ctx, px, w, h, rs, t, item->style); + sp_print_image_R8G8B8A8_N(ctx, px, w, h, rs, t, this->style); } else { // preserveAspectRatio - double vw = image->width.computed / image->sx; - double vh = image->height.computed / image->sy; + double vw = this->width.computed / this->sx; + double vh = this->height.computed / this->sy; - int trimwidth = std::min<int>(w, ceil(image->width.computed / vw * w)); - int trimheight = std::min<int>(h, ceil(image->height.computed / vh * h)); - int trimx = std::max<int>(0, floor((image->x.computed - image->ox) / vw * w)); - int trimy = std::max<int>(0, floor((image->y.computed - image->oy) / vh * h)); + int trimwidth = std::min<int>(w, ceil(this->width.computed / vw * w)); + int trimheight = std::min<int>(h, ceil(this->height.computed / vh * h)); + int trimx = std::max<int>(0, floor((this->x.computed - this->ox) / vw * w)); + int trimy = std::max<int>(0, floor((this->y.computed - this->oy) / vh * h)); - double vx = std::max<double>(image->ox, image->x.computed); - double vy = std::max<double>(image->oy, image->y.computed); - double vcw = std::min<double>(image->width.computed, vw); - double vch = std::min<double>(image->height.computed, vh); + double vx = std::max<double>(this->ox, this->x.computed); + double vy = std::max<double>(this->oy, this->y.computed); + double vcw = std::min<double>(this->width.computed, vw); + double vch = std::min<double>(this->height.computed, vh); Geom::Affine t; Geom::Translate tp(vx, vy); @@ -717,61 +607,45 @@ static void sp_image_print( SPItem *item, SPPrintContext *ctx ) Geom::Translate ti(0.0, -1.0); t = s * tp; t = ti * t; - sp_print_image_R8G8B8A8_N(ctx, px + trimx*pixskip + trimy*rs, trimwidth, trimheight, rs, t, item->style); + sp_print_image_R8G8B8A8_N(ctx, px + trimx*pixskip + trimy*rs, trimwidth, trimheight, rs, t, this->style); } - g_object_unref(pb); + delete pb; } } -static gchar *sp_image_description( SPItem *item ) -{ - SPImage *image = SP_IMAGE(item); +gchar* SPImage::description() { char *href_desc; - if (image->href) { - href_desc = (strncmp(image->href, "data:", 5) == 0) + + if (this->href) { + href_desc = (strncmp(this->href, "data:", 5) == 0) ? g_strdup(_("embedded")) - : xml_quote_strdup(image->href); + : xml_quote_strdup(this->href); } else { g_warning("Attempting to call strncmp() with a null pointer."); href_desc = g_strdup("(null_pointer)"); // we call g_free() on href_desc } - char *ret = ( image->pixbuf == NULL + char *ret = ( this->pixbuf == NULL ? g_strdup_printf(_("<b>Image with bad reference</b>: %s"), href_desc) : g_strdup_printf(_("<b>Image</b> %d × %d: %s"), - gdk_pixbuf_get_width(image->pixbuf), - gdk_pixbuf_get_height(image->pixbuf), + this->pixbuf->width(), + this->pixbuf->height(), href_desc) ); g_free(href_desc); return ret; } -static Inkscape::DrawingItem *sp_image_show( SPItem *item, Inkscape::Drawing &drawing, unsigned int /*key*/, unsigned int /*flags*/ ) -{ - SPImage * image = SP_IMAGE(item); +Inkscape::DrawingItem* SPImage::show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { Inkscape::DrawingImage *ai = new Inkscape::DrawingImage(drawing); - sp_image_update_arenaitem(image, ai); + sp_image_update_arenaitem(this, ai); return ai; } -/* - * utility function to try loading image from href - * - * docbase/relative_src - * absolute_src - * - */ - -GdkPixbuf *sp_image_repr_read_image( time_t& modTime, char*& pixPath, const gchar *href, const gchar *absref, const gchar *base ) +Inkscape::Pixbuf *sp_image_repr_read_image(gchar const *href, gchar const *absref, gchar const *base) { - GdkPixbuf *pixbuf = 0; - modTime = 0; - if ( pixPath ) { - g_free(pixPath); - pixPath = 0; - } + Inkscape::Pixbuf *inkpb = 0; gchar const *filename = href; @@ -779,18 +653,18 @@ GdkPixbuf *sp_image_repr_read_image( time_t& modTime, char*& pixPath, const gcha if (strncmp (filename,"file:",5) == 0) { gchar *fullname = g_filename_from_uri(filename, NULL, NULL); if (fullname) { - pixbuf = Inkscape::IO::pixbuf_new_from_file(fullname, modTime, pixPath); + inkpb = Inkscape::Pixbuf::create_from_file(fullname); g_free(fullname); - if (pixbuf != NULL) { - return pixbuf; + if (inkpb != NULL) { + return inkpb; } } } else if (strncmp (filename,"data:",5) == 0) { /* data URI - embedded image */ filename += 5; - pixbuf = sp_image_repr_read_dataURI (filename); - if (pixbuf != NULL) { - return pixbuf; + inkpb = Inkscape::Pixbuf::create_from_data_uri(filename); + if (inkpb != NULL) { + return inkpb; } } else { @@ -806,19 +680,19 @@ GdkPixbuf *sp_image_repr_read_image( time_t& modTime, char*& pixPath, const gcha // different dir) or unset (when doc is not saved yet), so we check for base+href existence first, // and if it fails, we also try to use bare href regardless of its g_path_is_absolute if (g_file_test (fullname, G_FILE_TEST_EXISTS) && !g_file_test (fullname, G_FILE_TEST_IS_DIR)) { - pixbuf = Inkscape::IO::pixbuf_new_from_file(fullname, modTime, pixPath); + inkpb = Inkscape::Pixbuf::create_from_file(fullname); g_free (fullname); - if (pixbuf != NULL) { - return pixbuf; + if (inkpb != NULL) { + return inkpb; } } } /* try filename as absolute */ if (g_file_test (filename, G_FILE_TEST_EXISTS) && !g_file_test (filename, G_FILE_TEST_IS_DIR)) { - pixbuf = Inkscape::IO::pixbuf_new_from_file(filename, modTime, pixPath); - if (pixbuf != NULL) { - return pixbuf; + inkpb = Inkscape::Pixbuf::create_from_file(filename); + if (inkpb != NULL) { + return inkpb; } } } @@ -834,31 +708,20 @@ GdkPixbuf *sp_image_repr_read_image( time_t& modTime, char*& pixPath, const gcha g_warning ("xlink:href did not resolve to a valid image file, now trying sodipodi:absref=\"%s\"", absref); } - pixbuf = Inkscape::IO::pixbuf_new_from_file(filename, modTime, pixPath); - if (pixbuf != NULL) { - return pixbuf; + inkpb = Inkscape::Pixbuf::create_from_file(filename); + if (inkpb != NULL) { + return inkpb; } } /* Nope: We do not find any valid pixmap file :-( */ - pixbuf = gdk_pixbuf_new_from_xpm_data((const gchar **) brokenimage_xpm); + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data((const gchar **) brokenimage_xpm); + inkpb = new Inkscape::Pixbuf(pixbuf); /* It should be included xpm, so if it still does not does load, */ /* our libraries are broken */ - g_assert (pixbuf != NULL); + g_assert (inkpb != NULL); - return pixbuf; -} - -static GdkPixbuf *sp_image_pixbuf_force_rgba( GdkPixbuf * pixbuf ) -{ - GdkPixbuf* result; - if (gdk_pixbuf_get_has_alpha(pixbuf)) { - result = pixbuf; - } else { - result = gdk_pixbuf_add_alpha(pixbuf, FALSE, 0, 0, 0); - g_object_unref(pixbuf); - } - return result; + return inkpb; } /* We assert that realpixbuf is either NULL or identical size to pixbuf */ @@ -866,7 +729,7 @@ static void sp_image_update_arenaitem (SPImage *image, Inkscape::DrawingImage *ai) { ai->setStyle(SP_OBJECT(image)->style); - ai->setARGB32Pixbuf(image->pixbuf); + ai->setPixbuf(image->pixbuf); ai->setOrigin(Geom::Point(image->ox, image->oy)); ai->setScale(image->sx, image->sy); ai->setClipbox(image->clipbox); @@ -881,29 +744,26 @@ static void sp_image_update_canvas_image(SPImage *image) } } -static void sp_image_snappoints( SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs ) -{ +void SPImage::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) { /* An image doesn't have any nodes to snap, but still we want to be able snap one image to another. Therefore we will create some snappoints at the corner, similar to a rect. If the image is rotated, then the snappoints will rotate with it. Again, just like a rect. */ - g_assert(item != NULL); - g_assert(SP_IS_IMAGE(item)); - - if (item->clip_ref->getObject()) { + if (this->clip_ref->getObject()) { //We are looking at a clipped image: do not return any snappoints, as these might be //far far away from the visible part from the clipped image //TODO Do return snappoints, but only when within visual bounding box } else { if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_IMG_CORNER)) { // The image has not been clipped: return its corners, which might be rotated for example - SPImage &image = *SP_IMAGE(item); - double const x0 = image.x.computed; - double const y0 = image.y.computed; - double const x1 = x0 + image.width.computed; - double const y1 = y0 + image.height.computed; - Geom::Affine const i2d (item->i2dt_affine ()); + double const x0 = this->x.computed; + double const y0 = this->y.computed; + double const x1 = x0 + this->width.computed; + double const y1 = y0 + this->height.computed; + + Geom::Affine const i2d (this->i2dt_affine ()); + p.push_back(Inkscape::SnapCandidatePoint(Geom::Point(x0, y0) * i2d, Inkscape::SNAPSOURCE_IMG_CORNER, Inkscape::SNAPTARGET_IMG_CORNER)); p.push_back(Inkscape::SnapCandidatePoint(Geom::Point(x0, y1) * i2d, Inkscape::SNAPSOURCE_IMG_CORNER, Inkscape::SNAPTARGET_IMG_CORNER)); p.push_back(Inkscape::SnapCandidatePoint(Geom::Point(x1, y1) * i2d, Inkscape::SNAPSOURCE_IMG_CORNER, Inkscape::SNAPTARGET_IMG_CORNER)); @@ -917,18 +777,16 @@ static void sp_image_snappoints( SPItem const *item, std::vector<Inkscape::SnapC * Transform x, y, set x, y, clear translation */ -static Geom::Affine sp_image_set_transform( SPItem *item, Geom::Affine const &xform ) -{ - SPImage *image = SP_IMAGE(item); - +Geom::Affine SPImage::set_transform(Geom::Affine const &xform) { /* Calculate position in parent coords. */ - Geom::Point pos( Geom::Point(image->x.computed, image->y.computed) * xform ); + Geom::Point pos( Geom::Point(this->x.computed, this->y.computed) * xform ); /* This function takes care of translation and scaling, we return whatever parts we can't handle. */ Geom::Affine ret(Geom::Affine(xform).withoutTranslation()); Geom::Point const scale(hypot(ret[0], ret[1]), hypot(ret[2], ret[3])); + if ( scale[Geom::X] > MAGIC_EPSILON ) { ret[0] /= scale[Geom::X]; ret[1] /= scale[Geom::X]; @@ -936,6 +794,7 @@ static Geom::Affine sp_image_set_transform( SPItem *item, Geom::Affine const &xf ret[0] = 1.0; ret[1] = 0.0; } + if ( scale[Geom::Y] > MAGIC_EPSILON ) { ret[2] /= scale[Geom::Y]; ret[3] /= scale[Geom::Y]; @@ -944,126 +803,19 @@ static Geom::Affine sp_image_set_transform( SPItem *item, Geom::Affine const &xf ret[3] = 1.0; } - image->width = image->width.computed * scale[Geom::X]; - image->height = image->height.computed * scale[Geom::Y]; + this->width = this->width.computed * scale[Geom::X]; + this->height = this->height.computed * scale[Geom::Y]; /* Find position in item coords */ pos = pos * ret.inverse(); - image->x = pos[Geom::X]; - image->y = pos[Geom::Y]; + this->x = pos[Geom::X]; + this->y = pos[Geom::Y]; - item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); return ret; } -static GdkPixbuf *sp_image_repr_read_dataURI( const gchar * uri_data ) -{ - GdkPixbuf * pixbuf = NULL; - - gint data_is_image = 0; - gint data_is_base64 = 0; - - const gchar * data = uri_data; - - while (*data) { - if (strncmp(data,"base64",6) == 0) { - /* base64-encoding */ - data_is_base64 = 1; - data_is_image = 1; // Illustrator produces embedded images without MIME type, so we assume it's image no matter what - data += 6; - } - else if (strncmp(data,"image/png",9) == 0) { - /* PNG image */ - data_is_image = 1; - data += 9; - } - else if (strncmp(data,"image/jpg",9) == 0) { - /* JPEG image */ - data_is_image = 1; - data += 9; - } - else if (strncmp(data,"image/jpeg",10) == 0) { - /* JPEG image */ - data_is_image = 1; - data += 10; - } - else { /* unrecognized option; skip it */ - while (*data) { - if (((*data) == ';') || ((*data) == ',')) { - break; - } - data++; - } - } - if ((*data) == ';') { - data++; - continue; - } - if ((*data) == ',') { - data++; - break; - } - } - - if ((*data) && data_is_image && data_is_base64) { - pixbuf = sp_image_repr_read_b64(data); - } - - return pixbuf; -} - -static GdkPixbuf *sp_image_repr_read_b64(gchar const *uri_data) -{ - GdkPixbuf *pixbuf = NULL; - GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); - - if (!loader) return NULL; - - gsize decoded_len = 0; - guchar *decoded = g_base64_decode(uri_data, &decoded_len); - - if (gdk_pixbuf_loader_write(loader, decoded, decoded_len, NULL)) { - gdk_pixbuf_loader_close(loader, NULL); - pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); - g_object_ref(pixbuf); - pixbuf = sp_image_pixbuf_force_rgba(pixbuf); - pixbuf_set_mime_data(pixbuf, decoded, decoded_len, gdk_pixbuf_loader_get_format(loader)); - } else { - g_free(decoded); - } - g_object_unref(loader); - - return pixbuf; -} - -// takes ownership of passed data -static void pixbuf_set_mime_data(GdkPixbuf *pb, guchar *data, gsize len, GdkPixbufFormat *fmt) -{ - cairo_surface_t *s = ink_cairo_surface_get_for_pixbuf(pb); - - gchar const *mimetype = NULL; - gchar *fmt_name = gdk_pixbuf_format_get_name(fmt); - Glib::ustring name = fmt_name; - g_free(fmt_name); - - if (name == "jpeg") { - mimetype = CAIRO_MIME_TYPE_JPEG; - } else if (name == "jpeg2000") { - mimetype = CAIRO_MIME_TYPE_JP2; - } else if (name == "png") { - mimetype = CAIRO_MIME_TYPE_PNG; - } - - if (mimetype != NULL) { - cairo_surface_set_mime_data(s, mimetype, data, len, g_free, data); - //g_message("Setting Cairo MIME data: %s", mimetype); - } else { - g_free(data); - //g_message("Not setting Cairo MIME data: unknown format %s", name.c_str()); - } -} - static void sp_image_set_curve( SPImage *image ) { //create a curve at the image's boundary for snapping @@ -1072,7 +824,7 @@ static void sp_image_set_curve( SPImage *image ) image->curve = image->curve->unref(); } } else { - Geom::OptRect rect = sp_image_bbox(image, Geom::identity(), SPItem::VISUAL_BBOX); + Geom::OptRect rect = image->bbox(Geom::identity(), SPItem::VISUAL_BBOX); SPCurve *c = SPCurve::new_from_rect(*rect, true); if (image->curve) { @@ -1099,52 +851,32 @@ SPCurve *sp_image_get_curve( SPImage *image ) return result; } -void sp_embed_image(Inkscape::XML::Node *image_node, GdkPixbuf *pb) +void sp_embed_image(Inkscape::XML::Node *image_node, Inkscape::Pixbuf *pb) { - static gchar const *mimetypes[] = { - CAIRO_MIME_TYPE_JPEG, CAIRO_MIME_TYPE_JP2, CAIRO_MIME_TYPE_PNG, NULL }; - static guint mimetypes_len = g_strv_length(const_cast<gchar**>(mimetypes)); - bool free_data = false; // check whether the pixbuf has MIME data guchar *data = NULL; gsize len = 0; - gchar const *data_mimetype = NULL; - - cairo_surface_t *s = reinterpret_cast<cairo_surface_t*>(g_object_get_data(G_OBJECT(pb), "cairo_surface")); - if (s) { - for (guint i = 0; i < mimetypes_len; ++i) { - unsigned long len_long = 0; - cairo_surface_get_mime_data(s, mimetypes[i], const_cast<unsigned char const **>(&data), &len_long); - len = len_long; // this assumes that the added range of long is not needed. the code below assumes gsize range of values is sufficient. - if (data != NULL) { - data_mimetype = mimetypes[i]; - break; - } - } - } + std::string data_mimetype; - if (data == NULL) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - Glib::ustring quality = Glib::ustring::format(prefs->getInt("/dialogs/import/quality", 100)); + data = const_cast<guchar *>(pb->getMimeData(len, data_mimetype)); + if (data == NULL) { // if there is no supported MIME data, embed as PNG data_mimetype = "image/png"; - ink_pixbuf_ensure_normal(pb); - gdk_pixbuf_save_to_buffer(pb, reinterpret_cast<gchar**>(&data), &len, "png", NULL, - "quality", quality.c_str(), NULL); + gdk_pixbuf_save_to_buffer(pb->getPixbufRaw(), reinterpret_cast<gchar**>(&data), &len, "png", NULL, NULL); free_data = true; } // Save base64 encoded data in image node // this formula taken from Glib docs gsize needed_size = len * 4 / 3 + len * 4 / (3 * 72) + 7; - needed_size += 5 + 8 + strlen(data_mimetype); // 5 bytes for data: + 8 for ;base64, + needed_size += 5 + 8 + data_mimetype.size(); // 5 bytes for data: + 8 for ;base64, gchar *buffer = (gchar *) g_malloc(needed_size); gchar *buf_work = buffer; - buf_work += g_sprintf(buffer, "data:%s;base64,", data_mimetype); + buf_work += g_sprintf(buffer, "data:%s;base64,", data_mimetype.c_str()); gint state = 0; gint save = 0; @@ -1164,21 +896,21 @@ void sp_embed_image(Inkscape::XML::Node *image_node, GdkPixbuf *pb) void sp_image_refresh_if_outdated( SPImage* image ) { - if ( image->href && image->lastMod ) { + if ( image->href && image->pixbuf && image->pixbuf->modificationTime()) { // It *might* change struct stat st; memset(&st, 0, sizeof(st)); int val = 0; - if (g_file_test (image->pixPath, G_FILE_TEST_EXISTS)){ - val = g_stat(image->pixPath, &st); + if (g_file_test (image->pixbuf->originalPath().c_str(), G_FILE_TEST_EXISTS)){ + val = g_stat(image->pixbuf->originalPath().c_str(), &st); } if ( !val ) { // stat call worked. Check time now - if ( st.st_mtime != image->lastMod ) { + if ( st.st_mtime != image->pixbuf->modificationTime() ) { SPCtx *ctx = 0; unsigned int flags = SP_IMAGE_HREF_MODIFIED_FLAG; - sp_image_update(image, ctx, flags); + image->update(ctx, flags); } } } diff --git a/src/sp-image.h b/src/sp-image.h index c197f6473..bfc10e7f2 100644 --- a/src/sp-image.h +++ b/src/sp-image.h @@ -1,9 +1,6 @@ -#ifndef __SP_IMAGE_H__ -#define __SP_IMAGE_H__ - -/* +/** @file * SVG <image> implementation - * + *//* * Authors: * Lauris Kaplinski <lauris@kaplinski.com> * Edward Flick (EAF) @@ -14,22 +11,25 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#define SP_TYPE_IMAGE (sp_image_get_type ()) -#define SP_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_IMAGE, SPImage)) -#define SP_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_IMAGE, SPImageClass)) -#define SP_IS_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_IMAGE)) -#define SP_IS_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_IMAGE)) - -/* SPImage */ +#ifndef SEEN_INKSCAPE_SP_IMAGE_H +#define SEEN_INKSCAPE_SP_IMAGE_H #include <gdk-pixbuf/gdk-pixbuf.h> #include <glibmm/ustring.h> #include "svg/svg-length.h" -#include "sp-item.h" +#include "sp-shape.h" + +#define SP_IMAGE(obj) (dynamic_cast<SPImage*>((SPObject*)obj)) +#define SP_IS_IMAGE(obj) (dynamic_cast<const SPImage*>((SPObject*)obj) != NULL) #define SP_IMAGE_HREF_MODIFIED_FLAG SP_OBJECT_USER_MODIFIED_FLAG_A -struct SPImage : public SPItem { +namespace Inkscape { class Pixbuf; } +class SPImage : public SPItem { +public: + SPImage(); + virtual ~SPImage(); + SVGLength x; SVGLength y; SVGLength width; @@ -53,20 +53,26 @@ struct SPImage : public SPItem { gchar *color_profile; #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - GdkPixbuf *pixbuf; - gchar *pixPath; - time_t lastMod; -}; + Inkscape::Pixbuf *pixbuf; -struct SPImageClass { - SPItemClass parent_class; -}; + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void release(); + virtual void set(unsigned int key, gchar const* value); + virtual void update(SPCtx *ctx, guint flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + virtual void modified(unsigned int flags); -GType sp_image_get_type (void); + virtual Geom::OptRect bbox(Geom::Affine const &transform, SPItem::BBoxType type); + virtual void print(SPPrintContext *ctx); + virtual gchar* description(); + virtual Inkscape::DrawingItem* show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); + virtual void snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); + virtual Geom::Affine set_transform(Geom::Affine const &transform); +}; /* Return duplicate of curve or NULL */ SPCurve *sp_image_get_curve (SPImage *image); -void sp_embed_image(Inkscape::XML::Node *imgnode, GdkPixbuf *pb); +void sp_embed_image(Inkscape::XML::Node *imgnode, Inkscape::Pixbuf *pb); void sp_image_refresh_if_outdated( SPImage* image ); #endif diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index a2eda6625..010cc5449 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -53,153 +53,190 @@ using Inkscape::DocumentUndo; -static void sp_group_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_group_release(SPObject *object); -static void sp_group_dispose(GObject *object); - -static void sp_group_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref); -static void sp_group_remove_child (SPObject * object, Inkscape::XML::Node * child); -static void sp_group_order_changed (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * old_ref, Inkscape::XML::Node * new_ref); -static void sp_group_update (SPObject *object, SPCtx *ctx, guint flags); -static void sp_group_modified (SPObject *object, guint flags); -static Inkscape::XML::Node *sp_group_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_group_set(SPObject *object, unsigned key, char const *value); - -static Geom::OptRect sp_group_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type); -static void sp_group_print (SPItem * item, SPPrintContext *ctx); -static gchar * sp_group_description (SPItem * item); -static Inkscape::DrawingItem *sp_group_show (SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); -static void sp_group_hide (SPItem * item, unsigned int key); -static void sp_group_snappoints (SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); - -static void sp_group_update_patheffect(SPLPEItem *lpeitem, bool write); static void sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write); -G_DEFINE_TYPE(SPGroup, sp_group, SP_TYPE_LPE_ITEM); +#include "sp-factory.h" -static void -sp_group_class_init (SPGroupClass *klass) -{ - GObjectClass * object_class; - SPObjectClass * sp_object_class; - SPItemClass * item_class; - SPLPEItemClass * lpe_item_class; - - object_class = (GObjectClass *) klass; - sp_object_class = (SPObjectClass *) klass; - item_class = (SPItemClass *) klass; - lpe_item_class = (SPLPEItemClass *) klass; - - object_class->dispose = sp_group_dispose; - - sp_object_class->child_added = sp_group_child_added; - sp_object_class->remove_child = sp_group_remove_child; - sp_object_class->order_changed = sp_group_order_changed; - sp_object_class->update = sp_group_update; - sp_object_class->modified = sp_group_modified; - sp_object_class->set = sp_group_set; - sp_object_class->write = sp_group_write; - sp_object_class->release = sp_group_release; - sp_object_class->build = sp_group_build; - - item_class->bbox = sp_group_bbox; - item_class->print = sp_group_print; - item_class->description = sp_group_description; - item_class->show = sp_group_show; - item_class->hide = sp_group_hide; - item_class->snappoints = sp_group_snappoints; - - lpe_item_class->update_patheffect = sp_group_update_patheffect; +namespace { + SPObject* createGroup() { + return new SPGroup(); + } + + bool groupRegistered = SPFactory::instance().registerObject("svg:g", createGroup); } -static void -sp_group_init (SPGroup *group) -{ - group->_layer_mode = SPGroup::GROUP; - group->group = new CGroup(group); - new (&group->_display_modes) std::map<unsigned int, SPGroup::LayerMode>(); +SPGroup::SPGroup() : SPLPEItem() { + this->_layer_mode = SPGroup::GROUP; + //new (&this->_display_modes) std::map<unsigned int, SPGroup::LayerMode>(); } -static void sp_group_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - object->readAttr( "inkscape:groupmode" ); +SPGroup::~SPGroup() { + //this->_display_modes.~map(); +} - if (((SPObjectClass *)sp_group_parent_class)->build) { - ((SPObjectClass *)sp_group_parent_class)->build(object, document, repr); - } +void SPGroup::build(SPDocument *document, Inkscape::XML::Node *repr) { + this->readAttr( "inkscape:groupmode" ); + + SPLPEItem::build(document, repr); } -static void sp_group_release(SPObject *object) { - if ( SP_GROUP(object)->_layer_mode == SPGroup::LAYER ) { - object->document->removeResource("layer", object); - } - if (((SPObjectClass *)sp_group_parent_class)->release) { - ((SPObjectClass *)sp_group_parent_class)->release(object); +void SPGroup::release() { + if (this->_layer_mode == SPGroup::LAYER) { + this->document->removeResource("layer", this); } -} -static void -sp_group_dispose(GObject *object) -{ - SP_GROUP(object)->_display_modes.~map(); - delete SP_GROUP(object)->group; + SPLPEItem::release(); } -static void sp_group_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) -{ - SPGroup *group = SP_GROUP(object); +void SPGroup::child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref) { + SPLPEItem::child_added(child, ref); + + SPObject *last_child = this->lastChild(); + + if (last_child && last_child->getRepr() == child) { + // optimization for the common special case where the child is being added at the end + SPObject *ochild = last_child; + if ( SP_IS_ITEM(ochild) ) { + /* TODO: this should be moved into SPItem somehow */ + SPItemView *v; + Inkscape::DrawingItem *ac; + + for (v = this->display; v != NULL; v = v->next) { + ac = SP_ITEM (ochild)->invoke_show (v->arenaitem->drawing(), v->key, v->flags); + + if (ac) { + v->arenaitem->appendChild(ac); + } + } + } + } else { // general case + SPObject *ochild = this->get_child_by_repr(child); + if ( ochild && SP_IS_ITEM(ochild) ) { + /* TODO: this should be moved into SPItem somehow */ + SPItemView *v; + Inkscape::DrawingItem *ac; - if (((SPObjectClass *) (sp_group_parent_class))->child_added) { - (* ((SPObjectClass *) (sp_group_parent_class))->child_added) (object, child, ref); + unsigned position = SP_ITEM(ochild)->pos_in_parent(); + + for (v = this->display; v != NULL; v = v->next) { + ac = SP_ITEM (ochild)->invoke_show (v->arenaitem->drawing(), v->key, v->flags); + + if (ac) { + v->arenaitem->prependChild(ac); + ac->setZOrder(position); + } + } + } } - group->group->onChildAdded(child); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } /* fixme: hide (Lauris) */ -static void -sp_group_remove_child (SPObject * object, Inkscape::XML::Node * child) -{ - if (((SPObjectClass *) (sp_group_parent_class))->remove_child) - (* ((SPObjectClass *) (sp_group_parent_class))->remove_child) (object, child); +void SPGroup::remove_child(Inkscape::XML::Node *child) { + SPLPEItem::remove_child(child); - SP_GROUP(object)->group->onChildRemoved(child); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } -static void -sp_group_order_changed (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref) +void SPGroup::order_changed (Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref) { - if (((SPObjectClass *) (sp_group_parent_class))->order_changed) - (* ((SPObjectClass *) (sp_group_parent_class))->order_changed) (object, child, old_ref, new_ref); + SPLPEItem::order_changed(child, old_ref, new_ref); + + SPObject *ochild = this->get_child_by_repr(child); + if ( ochild && SP_IS_ITEM(ochild) ) { + /* TODO: this should be moved into SPItem somehow */ + SPItemView *v; + unsigned position = SP_ITEM(ochild)->pos_in_parent(); + for ( v = SP_ITEM (ochild)->display ; v != NULL ; v = v->next ) { + v->arenaitem->setZOrder(position); + } + } - SP_GROUP(object)->group->onOrderChanged(child, old_ref, new_ref); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } -static void -sp_group_update (SPObject *object, SPCtx *ctx, unsigned int flags) -{ - if (((SPObjectClass *) (sp_group_parent_class))->update) - ((SPObjectClass *) (sp_group_parent_class))->update (object, ctx, flags); +void SPGroup::update(SPCtx *ctx, unsigned int flags) { + SPLPEItem::update(ctx, flags); + + SPItemCtx *ictx, cctx; + + ictx = (SPItemCtx *) ctx; + cctx = *ictx; + + if (flags & SP_OBJECT_MODIFIED_FLAG) { + flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; + } + + flags &= SP_OBJECT_MODIFIED_CASCADE; + + if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { + for (SPItemView *v = this->display; v != NULL; v = v->next) { + Inkscape::DrawingGroup *group = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); + group->setStyle(this->style); + } + } + + GSList *l = g_slist_reverse(this->childList(true, SPObject::ActionUpdate)); + while (l) { + SPObject *child = SP_OBJECT (l->data); + l = g_slist_remove (l, child); - SP_GROUP(object)->group->onUpdate(ctx, flags); + if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { + if (SP_IS_ITEM (child)) { + SPItem const &chi = *SP_ITEM(child); + cctx.i2doc = chi.transform * ictx->i2doc; + cctx.i2vp = chi.transform * ictx->i2vp; + child->updateDisplay((SPCtx *)&cctx, flags); + } else { + child->updateDisplay(ctx, flags); + } + } + + sp_object_unref(child); + } } -static void -sp_group_modified (SPObject *object, guint flags) -{ - if (((SPObjectClass *) (sp_group_parent_class))->modified) - ((SPObjectClass *) (sp_group_parent_class))->modified (object, flags); +void SPGroup::modified(guint flags) { + SPLPEItem::modified(flags); + + SPObject *child; + + if (flags & SP_OBJECT_MODIFIED_FLAG) { + flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; + } + + flags &= SP_OBJECT_MODIFIED_CASCADE; + + if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { + for (SPItemView *v = this->display; v != NULL; v = v->next) { + Inkscape::DrawingGroup *group = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); + group->setStyle(this->style); + } + } + + GSList *l = g_slist_reverse(this->childList(true)); + + while (l) { + child = SP_OBJECT (l->data); + l = g_slist_remove (l, child); - SP_GROUP(object)->group->onModified(flags); + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { + child->emitModified(flags); + } + + sp_object_unref(child); + } } -static Inkscape::XML::Node * sp_group_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPGroup::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { + SPGroup* object = this; SPGroup *group = SP_GROUP(object); if (flags & SP_OBJECT_WRITE_BUILD) { GSList *l; + if (!repr) { if (SP_IS_SWITCH(object)) { repr = xml_doc->createElement("svg:switch"); @@ -207,15 +244,19 @@ static Inkscape::XML::Node * sp_group_write(SPObject *object, Inkscape::XML::Doc repr = xml_doc->createElement("svg:g"); } } + l = NULL; + for (SPObject *child = object->firstChild(); child; child = child->getNext() ) { if ( !SP_IS_TITLE(child) && !SP_IS_DESC(child) ) { Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags); + if (crepr) { l = g_slist_prepend (l, crepr); } } } + while (l) { repr->addChild((Inkscape::XML::Node *) l->data, NULL); Inkscape::GC::release((Inkscape::XML::Node *) l->data); @@ -240,69 +281,109 @@ static Inkscape::XML::Node * sp_group_write(SPObject *object, Inkscape::XML::Doc } else { value = NULL; } + repr->setAttribute("inkscape:groupmode", value); } - if (((SPObjectClass *) (sp_group_parent_class))->write) { - ((SPObjectClass *) (sp_group_parent_class))->write (object, xml_doc, repr, flags); - } + SPLPEItem::write(xml_doc, repr, flags); return repr; } -static Geom::OptRect -sp_group_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type) +Geom::OptRect SPGroup::bbox(Geom::Affine const &transform, SPItem::BBoxType bboxtype) { - return SP_GROUP(item)->group->bounds(type, transform); -} + Geom::OptRect bbox; -static void -sp_group_print (SPItem * item, SPPrintContext *ctx) -{ - SP_GROUP(item)->group->onPrint(ctx); + GSList *l = this->childList(false, SPObject::ActionBBox); + + while (l) { + SPObject *o = SP_OBJECT (l->data); + + if (SP_IS_ITEM(o) && !SP_ITEM(o)->isHidden()) { + SPItem *child = SP_ITEM(o); + Geom::Affine const ct(child->transform * transform); + bbox |= child->bounds(bboxtype, ct); + } + + l = g_slist_remove (l, o); + } + + return bbox; } -static gchar * sp_group_description (SPItem * item) -{ - return SP_GROUP(item)->group->getDescription(); +void SPGroup::print(SPPrintContext *ctx) { + GSList *l = g_slist_reverse(this->childList(false)); + + while (l) { + SPObject *o = SP_OBJECT (l->data); + + if (SP_IS_ITEM(o)) { + SP_ITEM(o)->invoke_print (ctx); + } + + l = g_slist_remove (l, o); + } } -static void sp_group_set(SPObject *object, unsigned key, char const *value) { - SPGroup *group = SP_GROUP(object); +gchar *SPGroup::description() { + gint len = this->getItemCount(); + return g_strdup_printf( + ngettext("<b>Group</b> of <b>%d</b> object", + "<b>Group</b> of <b>%d</b> objects", + len), len); +} +void SPGroup::set(unsigned int key, gchar const* value) { switch (key) { case SP_ATTR_INKSCAPE_GROUPMODE: if ( value && !strcmp(value, "layer") ) { - group->setLayerMode(SPGroup::LAYER); + this->setLayerMode(SPGroup::LAYER); } else if ( value && !strcmp(value, "maskhelper") ) { - group->setLayerMode(SPGroup::MASK_HELPER); + this->setLayerMode(SPGroup::MASK_HELPER); } else { - group->setLayerMode(SPGroup::GROUP); + this->setLayerMode(SPGroup::GROUP); } break; - default: { - if (((SPObjectClass *) (sp_group_parent_class))->set) { - (* ((SPObjectClass *) (sp_group_parent_class))->set)(object, key, value); - } - } + + default: + SPLPEItem::set(key, value); + break; } } -static Inkscape::DrawingItem * -sp_group_show (SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) -{ - return SP_GROUP(item)->group->show(drawing, key, flags); +Inkscape::DrawingItem *SPGroup::show (Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { + Inkscape::DrawingGroup *ai; + + ai = new Inkscape::DrawingGroup(drawing); + ai->setPickChildren(this->effectiveLayerMode(key) == SPGroup::LAYER); + ai->setStyle(this->style); + + this->_showChildren(drawing, ai, key, flags); + return ai; } -static void -sp_group_hide (SPItem *item, unsigned int key) -{ - SP_GROUP(item)->group->hide(key); +void SPGroup::hide (unsigned int key) { + SPItem * child; + + GSList *l = g_slist_reverse(this->childList(false, SPObject::ActionShow)); + + while (l) { + SPObject *o = SP_OBJECT (l->data); + + if (SP_IS_ITEM (o)) { + child = SP_ITEM (o); + child->invoke_hide (key); + } + + l = g_slist_remove (l, o); + } + +// SPLPEItem::onHide(key); } -static void sp_group_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) -{ - for ( SPObject const *o = item->firstChild(); o; o = o->getNext() ) + +void SPGroup::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) { + for ( SPObject const *o = this->firstChild(); o; o = o->getNext() ) { if (SP_IS_ITEM(o)) { SP_ITEM(o)->getSnappoints(p, snapprefs); @@ -561,152 +642,9 @@ void SPGroup::translateChildItems(Geom::Translate const &tr) } } -CGroup::CGroup(SPGroup *group) { - _group = group; -} - -CGroup::~CGroup() { -} - -void CGroup::onChildAdded(Inkscape::XML::Node *child) { - SPObject *last_child = _group->lastChild(); - if (last_child && last_child->getRepr() == child) { - // optimization for the common special case where the child is being added at the end - SPObject *ochild = last_child; - if ( SP_IS_ITEM(ochild) ) { - /* TODO: this should be moved into SPItem somehow */ - SPItemView *v; - Inkscape::DrawingItem *ac; - - for (v = _group->display; v != NULL; v = v->next) { - ac = SP_ITEM (ochild)->invoke_show (v->arenaitem->drawing(), v->key, v->flags); - - if (ac) { - v->arenaitem->appendChild(ac); - } - } - } - } else { // general case - SPObject *ochild = _group->get_child_by_repr(child); - if ( ochild && SP_IS_ITEM(ochild) ) { - /* TODO: this should be moved into SPItem somehow */ - SPItemView *v; - Inkscape::DrawingItem *ac; - - unsigned position = SP_ITEM(ochild)->pos_in_parent(); - - for (v = _group->display; v != NULL; v = v->next) { - ac = SP_ITEM (ochild)->invoke_show (v->arenaitem->drawing(), v->key, v->flags); - - if (ac) { - v->arenaitem->prependChild(ac); - ac->setZOrder(position); - } - } - } - } - - _group->requestModified(SP_OBJECT_MODIFIED_FLAG); -} - -void CGroup::onChildRemoved(Inkscape::XML::Node */*child*/) { - _group->requestModified(SP_OBJECT_MODIFIED_FLAG); -} - -void CGroup::onUpdate(SPCtx *ctx, unsigned int flags) { - SPItemCtx *ictx, cctx; - - ictx = (SPItemCtx *) ctx; - cctx = *ictx; - - if (flags & SP_OBJECT_MODIFIED_FLAG) { - flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; - } - - flags &= SP_OBJECT_MODIFIED_CASCADE; - - if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { - SPObject *object = _group; - for (SPItemView *v = _group->display; v != NULL; v = v->next) { - Inkscape::DrawingGroup *group = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); - group->setStyle(object->style); - } - } - - GSList *l = g_slist_reverse(_group->childList(true, SPObject::ActionUpdate)); - while (l) { - SPObject *child = SP_OBJECT (l->data); - l = g_slist_remove (l, child); - if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { - if (SP_IS_ITEM (child)) { - SPItem const &chi = *SP_ITEM(child); - cctx.i2doc = chi.transform * ictx->i2doc; - cctx.i2vp = chi.transform * ictx->i2vp; - child->updateDisplay((SPCtx *)&cctx, flags); - } else { - child->updateDisplay(ctx, flags); - } - } - g_object_unref (G_OBJECT (child)); - } -} - -void CGroup::onModified(guint flags) { - SPObject *child; - - if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; - flags &= SP_OBJECT_MODIFIED_CASCADE; - - if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { - SPObject *object = _group; - for (SPItemView *v = _group->display; v != NULL; v = v->next) { - Inkscape::DrawingGroup *group = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); - group->setStyle(object->style); - } - } - - GSList *l = g_slist_reverse(_group->childList(true)); - while (l) { - child = SP_OBJECT (l->data); - l = g_slist_remove (l, child); - if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { - child->emitModified(flags); - } - g_object_unref (G_OBJECT (child)); - } -} - -Geom::OptRect CGroup::bounds(SPItem::BBoxType type, Geom::Affine const &transform) -{ - Geom::OptRect bbox; - - GSList *l = _group->childList(false, SPObject::ActionBBox); - while (l) { - SPObject *o = SP_OBJECT (l->data); - if (SP_IS_ITEM(o) && !SP_ITEM(o)->isHidden()) { - SPItem *child = SP_ITEM(o); - Geom::Affine const ct(child->transform * transform); - bbox |= child->bounds(type, ct); - } - l = g_slist_remove (l, o); - } - return bbox; -} - -void CGroup::onPrint(SPPrintContext *ctx) { - GSList *l = g_slist_reverse(_group->childList(false)); - while (l) { - SPObject *o = SP_OBJECT (l->data); - if (SP_IS_ITEM(o)) { - SP_ITEM(o)->invoke_print (ctx); - } - l = g_slist_remove (l, o); - } -} - -gint CGroup::getItemCount() { +gint SPGroup::getItemCount() { gint len = 0; - for (SPObject *o = _group->firstChild() ; o ; o = o->getNext() ) { + for (SPObject *o = this->firstChild() ; o ; o = o->getNext() ) { if (SP_IS_ITEM(o)) { len++; } @@ -715,30 +653,10 @@ gint CGroup::getItemCount() { return len; } -gchar *CGroup::getDescription() { - gint len = getItemCount(); - return g_strdup_printf( - ngettext("<b>Group</b> of <b>%d</b> object", - "<b>Group</b> of <b>%d</b> objects", - len), len); -} - -Inkscape::DrawingItem *CGroup::show (Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { - Inkscape::DrawingGroup *ai; - SPObject *object = _group; - - ai = new Inkscape::DrawingGroup(drawing); - ai->setPickChildren(_group->effectiveLayerMode(key) == SPGroup::LAYER); - ai->setStyle(object->style); - - _showChildren(drawing, ai, key, flags); - return ai; -} - -void CGroup::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) { +void SPGroup::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) { Inkscape::DrawingItem *ac = NULL; SPItem * child = NULL; - GSList *l = g_slist_reverse(_group->childList(false, SPObject::ActionShow)); + GSList *l = g_slist_reverse(this->childList(false, SPObject::ActionShow)); while (l) { SPObject *o = SP_OBJECT (l->data); if (SP_IS_ITEM (o)) { @@ -752,67 +670,32 @@ void CGroup::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *a } } -void CGroup::hide (unsigned int key) { - SPItem * child; - - GSList *l = g_slist_reverse(_group->childList(false, SPObject::ActionShow)); - while (l) { - SPObject *o = SP_OBJECT (l->data); - if (SP_IS_ITEM (o)) { - child = SP_ITEM (o); - child->invoke_hide (key); - } - l = g_slist_remove (l, o); - } - - if (((SPItemClass *) sp_group_parent_class)->hide) - ((SPItemClass *) sp_group_parent_class)->hide (_group, key); -} - -void CGroup::onOrderChanged (Inkscape::XML::Node *child, Inkscape::XML::Node *, Inkscape::XML::Node *) -{ - SPObject *ochild = _group->get_child_by_repr(child); - if ( ochild && SP_IS_ITEM(ochild) ) { - /* TODO: this should be moved into SPItem somehow */ - SPItemView *v; - unsigned position = SP_ITEM(ochild)->pos_in_parent(); - for ( v = SP_ITEM (ochild)->display ; v != NULL ; v = v->next ) { - v->arenaitem->setZOrder(position); - } - } - - _group->requestModified(SP_OBJECT_MODIFIED_FLAG); -} - -static void -sp_group_update_patheffect (SPLPEItem *lpeitem, bool write) -{ +void SPGroup::update_patheffect(bool write) { #ifdef GROUP_VERBOSE g_message("sp_group_update_patheffect: %p\n", lpeitem); #endif - g_return_if_fail (lpeitem != NULL); - g_return_if_fail (SP_IS_GROUP (lpeitem)); - GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); + GSList const *item_list = sp_item_group_item_list(this); + for ( GSList const *iter = item_list; iter; iter = iter->next ) { SPObject *subitem = static_cast<SPObject *>(iter->data); + if (SP_IS_LPE_ITEM(subitem)) { - if (SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (subitem))->update_patheffect) { - SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (subitem))->update_patheffect (SP_LPE_ITEM(subitem), write); - } + ((SPLPEItem*)subitem)->update_patheffect(write); } } - if (sp_lpe_item_has_path_effect(lpeitem) && sp_lpe_item_path_effects_enabled(lpeitem)) { - for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); it++) + if (sp_lpe_item_has_path_effect(this) && sp_lpe_item_path_effects_enabled(this)) { + for (PathEffectList::iterator it = this->path_effect_list->begin(); it != this->path_effect_list->end(); it++) { LivePathEffectObject *lpeobj = (*it)->lpeobject; + if (lpeobj && lpeobj->get_lpe()) { - lpeobj->get_lpe()->doBeforeEffect(lpeitem); + lpeobj->get_lpe()->doBeforeEffect(this); } } - sp_group_perform_patheffect(SP_GROUP(lpeitem), SP_GROUP(lpeitem), write); + sp_group_perform_patheffect(this, this, write); } } @@ -820,20 +703,26 @@ static void sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write) { GSList const *item_list = sp_item_group_item_list(SP_GROUP(group)); + for ( GSList const *iter = item_list; iter; iter = iter->next ) { SPObject *subitem = static_cast<SPObject *>(iter->data); + if (SP_IS_GROUP(subitem)) { sp_group_perform_patheffect(SP_GROUP(subitem), topgroup, write); } else if (SP_IS_SHAPE(subitem)) { SPCurve * c = NULL; + if (SP_IS_PATH(subitem)) { c = SP_PATH(subitem)->get_original_curve(); } else { c = SP_SHAPE(subitem)->getCurve(); } + // only run LPEs when the shape has a curve defined if (c) { + c->transform(i2anc_affine(subitem, topgroup)); sp_lpe_item_perform_path_effect(SP_LPE_ITEM(topgroup), c); + c->transform(i2anc_affine(subitem, topgroup).inverse()); SP_SHAPE(subitem)->setCurve(c, TRUE); if (write) { diff --git a/src/sp-item-group.h b/src/sp-item-group.h index c13fa2b75..88ca9657a 100644 --- a/src/sp-item-group.h +++ b/src/sp-item-group.h @@ -16,16 +16,11 @@ #include <map> #include "sp-lpe-item.h" -#define SP_TYPE_GROUP (sp_group_get_type ()) -#define SP_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_GROUP, SPGroup)) -#define SP_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_GROUP, SPGroupClass)) -#define SP_IS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_GROUP)) -#define SP_IS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_GROUP)) +#define SP_GROUP(obj) (dynamic_cast<SPGroup*>((SPObject*)obj)) +#define SP_IS_GROUP(obj) (dynamic_cast<const SPGroup*>((SPObject*)obj) != NULL) #define SP_IS_LAYER(obj) (SP_IS_GROUP(obj) && SP_GROUP(obj)->layerMode() == SPGroup::LAYER) -class CGroup; - namespace Inkscape { class Drawing; @@ -33,7 +28,11 @@ class DrawingItem; } // namespace Inkscape -struct SPGroup : public SPLPEItem { +class SPGroup : public SPLPEItem { +public: + SPGroup(); + virtual ~SPGroup(); + enum LayerMode { GROUP, LAYER, MASK_HELPER }; LayerMode _layer_mode; @@ -54,45 +53,37 @@ struct SPGroup : public SPLPEItem { void setLayerDisplayMode(unsigned int display_key, LayerMode mode); void translateChildItems(Geom::Translate const &tr); - CGroup *group; - + gint getItemCount(); + void _showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags); + private: void _updateLayerMode(unsigned int display_key=0); -}; - -struct SPGroupClass { - SPLPEItemClass parent_class; -}; -/* - * Virtual methods of SPGroup - */ -class CGroup { public: - CGroup(SPGroup *group); - virtual ~CGroup(); - - virtual void onChildAdded(Inkscape::XML::Node *child); - virtual void onChildRemoved(Inkscape::XML::Node *child); - virtual void onUpdate(SPCtx *ctx, unsigned int flags); - virtual void onModified(guint flags); - virtual Geom::OptRect bounds(SPItem::BBoxType type, Geom::Affine const &transform); - virtual void onPrint(SPPrintContext *ctx); - virtual void onOrderChanged(Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref); - virtual gchar *getDescription(); + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void release(); + + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node *child); + virtual void order_changed(Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref); + + virtual void update(SPCtx *ctx, unsigned int flags); + virtual void modified(guint flags); + virtual void set(unsigned int key, gchar const* value); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + + virtual Geom::OptRect bbox(Geom::Affine const &transform, SPItem::BBoxType bboxtype); + virtual void print(SPPrintContext *ctx); + virtual gchar *description(); virtual Inkscape::DrawingItem *show (Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); virtual void hide (unsigned int key); - gint getItemCount(); - -protected: - virtual void _showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags); + virtual void snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); - SPGroup *_group; + virtual void update_patheffect(bool write); }; -GType sp_group_get_type (void); - void sp_item_group_ungroup (SPGroup *group, GSList **children, bool do_done = true); diff --git a/src/sp-item.cpp b/src/sp-item.cpp index a4070c9b3..e6991a1fa 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -75,57 +75,25 @@ #define noSP_ITEM_DEBUG_IDLE -static void sp_item_build (SPObject *object, - SPDocument *document, - Inkscape::XML::Node *repr); -static void sp_item_release(SPObject *object); -static void sp_item_set (SPObject *object, - unsigned key, - gchar const *value); -static void sp_item_update (SPObject *object, - SPCtx *ctx, - guint flags); -static Inkscape::XML::Node* sp_item_write (SPObject *object, - Inkscape::XML::Document *doc, - Inkscape::XML::Node *repr, - guint flags); static SPItemView* sp_item_view_list_remove(SPItemView *list, SPItemView *view); -static gchar *sp_item_private_description(SPItem *item); -static void sp_item_private_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); -G_DEFINE_TYPE(SPItem, sp_item, SP_TYPE_OBJECT); +SPItem::SPItem() : SPObject() { + this->sensitive = 0; + this->clip_ref = NULL; + this->avoidRef = NULL; + this->_is_evaluated = false; + this->stop_paint = 0; + this->_evaluated_status = StatusUnknown; + this->bbox_valid = 0; + this->freeze_stroke_width = false; + this->transform_center_x = 0; + this->transform_center_y = 0; + this->display = NULL; + this->mask_ref = NULL; -/** - * SPItem vtable initialization. - */ -static void -sp_item_class_init(SPItemClass *klass) -{ - SPObjectClass *sp_object_class = SP_OBJECT_CLASS(klass); - - sp_object_class->build = sp_item_build; - sp_object_class->release = sp_item_release; - sp_object_class->set = sp_item_set; - sp_object_class->update = sp_item_update; - sp_object_class->write = sp_item_write; - - klass->description = sp_item_private_description; - klass->snappoints = sp_item_private_snappoints; -} - -/** - * Callback for SPItem object initialization. - */ -static void -sp_item_init(SPItem *item) -{ - item->init(); -} - -void SPItem::init() { sensitive = TRUE; bbox_valid = FALSE; @@ -149,9 +117,12 @@ void SPItem::init() { avoidRef = new SPAvoidRef(this); - new (&constraints) std::vector<SPGuideConstraint>(); + //new (&constraints) std::vector<SPGuideConstraint>(); - new (&_transformed_signal) sigc::signal<void, Geom::Affine const *, SPItem *>(); + //new (&_transformed_signal) sigc::signal<void, Geom::Affine const *, SPItem *>(); +} + +SPItem::~SPItem() { } bool SPItem::isVisibleAndUnlocked() const { @@ -410,10 +381,9 @@ void SPItem::moveTo(SPItem *target, gboolean intoafter) { } } +void SPItem::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPItem* object = this; -static void -sp_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ object->readAttr( "style" ); object->readAttr( "transform" ); object->readAttr( "clip-path" ); @@ -425,15 +395,11 @@ sp_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) object->readAttr( "inkscape:connector-avoid" ); object->readAttr( "inkscape:connection-points" ); - if ((SP_OBJECT_CLASS(sp_item_parent_class))->build) { - (* (SP_OBJECT_CLASS(sp_item_parent_class))->build)(object, document, repr); - } + SPObject::build(document, repr); } -static void -sp_item_release(SPObject *object) -{ - SPItem *item = SP_ITEM(object); +void SPItem::release() { + SPItem* item = this; // Note: do this here before the clip_ref is deleted, since calling // ensureUpToDate() for triggered routing may reference @@ -446,21 +412,18 @@ sp_item_release(SPObject *object) delete item->clip_ref; delete item->mask_ref; - if ((SP_OBJECT_CLASS(sp_item_parent_class))->release) { - (SP_OBJECT_CLASS(sp_item_parent_class))->release(object); - } + SPObject::release(); while (item->display) { item->display = sp_item_view_list_remove(item->display, item->display); } - item->_transformed_signal.~signal(); + //item->_transformed_signal.~signal(); } -static void -sp_item_set(SPObject *object, unsigned key, gchar const *value) -{ - SPItem *item = SP_ITEM(object); +void SPItem::set(unsigned int key, gchar const* value) { + SPItem *item = this; + SPItem* object = item; switch (key) { case SP_ATTR_TRANSFORM: { @@ -541,9 +504,7 @@ sp_item_set(SPObject *object, unsigned key, gchar const *value) sp_style_read_from_object(object->style, object); object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); } else { - if ((SP_OBJECT_CLASS(sp_item_parent_class))->set) { - (* (SP_OBJECT_CLASS(sp_item_parent_class))->set)(object, key, value); - } + SPObject::set(key, value); } break; } @@ -580,7 +541,7 @@ void SPItem::mask_ref_changed(SPObject *old_mask, SPObject *mask, SPItem *item) if (old_mask) { /* Hide mask */ for (SPItemView *v = item->display; v != NULL; v = v->next) { - sp_mask_hide(SP_MASK(old_mask), v->arenaitem->key()); + SP_MASK(old_mask)->sp_mask_hide(v->arenaitem->key()); } } if (SP_IS_MASK(mask)) { @@ -589,24 +550,21 @@ void SPItem::mask_ref_changed(SPObject *old_mask, SPObject *mask, SPItem *item) if (!v->arenaitem->key()) { v->arenaitem->setKey(SPItem::display_key_new(3)); } - Inkscape::DrawingItem *ai = sp_mask_show(SP_MASK(mask), + Inkscape::DrawingItem *ai = SP_MASK(mask)->sp_mask_show( v->arenaitem->drawing(), v->arenaitem->key()); v->arenaitem->setMask(ai); - sp_mask_set_bbox(SP_MASK(mask), v->arenaitem->key(), bbox); + SP_MASK(mask)->sp_mask_set_bbox(v->arenaitem->key(), bbox); mask->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } } } -static void -sp_item_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPItem *item = SP_ITEM(object); +void SPItem::update(SPCtx *ctx, guint flags) { + SPItem *item = this; + SPItem* object = item; - if ((SP_OBJECT_CLASS(sp_item_parent_class))->update) { - (* (SP_OBJECT_CLASS(sp_item_parent_class))->update)(object, ctx, flags); - } +// SPObject::onUpdate(ctx, flags); // any of the modifications defined in sp-object.h might change bbox, // so we invalidate it unconditionally @@ -631,7 +589,7 @@ sp_item_update(SPObject *object, SPCtx *ctx, guint flags) } if (mask) { for (SPItemView *v = item->display; v != NULL; v = v->next) { - sp_mask_set_bbox(mask, v->arenaitem->key(), bbox); + mask->sp_mask_set_bbox(v->arenaitem->key(), bbox); } } } @@ -643,11 +601,9 @@ sp_item_update(SPObject *object, SPCtx *ctx, guint flags) } } } - /* Update bounding box data used by filters */ if (item->style->filter.set && item->display) { Geom::OptRect item_bbox = item->visualBounds(); - SPItemView *itemview = item->display; do { if (itemview->arenaitem) @@ -660,10 +616,9 @@ sp_item_update(SPObject *object, SPCtx *ctx, guint flags) item->avoidRef->handleSettingChange(); } -static Inkscape::XML::Node* -sp_item_write(SPObject *const object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPItem *item = SP_ITEM(object); +Inkscape::XML::Node* SPItem::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { + SPItem *item = this; + SPItem* object = item; // in the case of SP_OBJECT_WRITE_BUILD, the item should always be newly created, // so we need to add any children from the underlying object to the new repr @@ -721,13 +676,16 @@ sp_item_write(SPObject *const object, Inkscape::XML::Document *xml_doc, Inkscape } } - if ((SP_OBJECT_CLASS(sp_item_parent_class))->write) { - (SP_OBJECT_CLASS(sp_item_parent_class))->write(object, xml_doc, repr, flags); - } + SPObject::write(xml_doc, repr, flags); return repr; } +// CPPIFY: make pure virtual +Geom::OptRect SPItem::bbox(Geom::Affine const &transform, SPItem::BBoxType type) { + //throw; + return Geom::OptRect(); +} /** * Get item's geometric bounding box in this item's coordinate system. * @@ -736,10 +694,12 @@ sp_item_write(SPObject *const object, Inkscape::XML::Document *xml_doc, Inkscape Geom::OptRect SPItem::geometricBounds(Geom::Affine const &transform) const { Geom::OptRect bbox; + // call the subclass method - if ((SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->bbox) { - bbox = (SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->bbox(this, transform, SPItem::GEOMETRIC_BBOX); - } + // CPPIFY + //bbox = this->bbox(transform, SPItem::GEOMETRIC_BBOX); + bbox = const_cast<SPItem*>(this)->bbox(transform, SPItem::GEOMETRIC_BBOX); + return bbox; } @@ -756,10 +716,10 @@ Geom::OptRect SPItem::visualBounds(Geom::Affine const &transform) const Geom::OptRect bbox; if ( style && style->filter.href && style->getFilter() && SP_IS_FILTER(style->getFilter())) { - // call the subclass method - if ((SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->bbox) { - bbox = (SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->bbox(this, Geom::identity(), SPItem::VISUAL_BBOX); - } + // call the subclass method + // CPPIFY + //bbox = this->bbox(Geom::identity(), SPItem::VISUAL_BBOX); + bbox = const_cast<SPItem*>(this)->bbox(Geom::identity(), SPItem::VISUAL_BBOX); SPFilter *filter = SP_FILTER(style->getFilter()); // default filer area per the SVG spec: @@ -802,10 +762,10 @@ Geom::OptRect SPItem::visualBounds(Geom::Affine const &transform) const bbox = Geom::OptRect(minp, maxp); *bbox *= transform; } else { - // call the subclass method - if ((SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->bbox) { - bbox = (SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->bbox(this, transform, SPItem::VISUAL_BBOX); - } + // call the subclass method + // CPPIFY + //bbox = this->bbox(transform, SPItem::VISUAL_BBOX); + bbox = const_cast<SPItem*>(this)->bbox(transform, SPItem::VISUAL_BBOX); } if (clip_ref->getObject()) { bbox.intersectWith(SP_CLIPPATH(clip_ref->getObject())->geometricBounds(transform)); @@ -813,6 +773,7 @@ Geom::OptRect SPItem::visualBounds(Geom::Affine const &transform) const return bbox; } + Geom::OptRect SPItem::bounds(BBoxType type, Geom::Affine const &transform) const { if (type == GEOMETRIC_BBOX) { @@ -902,24 +863,22 @@ unsigned SPItem::pos_in_parent() return 0; } -static void -sp_item_private_snappoints(SPItem const * /*item*/, std::vector<Inkscape::SnapCandidatePoint> &/*p*/, Inkscape::SnapPreferences const * /*snapprefs*/) -{ +// CPPIFY: make pure virtual, see below! +void SPItem::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) { + //throw; +} /* This will only be called if the derived class doesn't override this. * see for example sp_genericellipse_snappoints in sp-ellipse.cpp * We don't know what shape we could be dealing with here, so we'll just * do nothing */ -} - void SPItem::getSnappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) const { // Get the snappoints of the item - SPItemClass const &item_class = *SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)); - if (item_class.snappoints) { - item_class.snappoints(this, p, snapprefs); - } + // CPPIFY + //this->snappoints(p, snapprefs); + const_cast<SPItem*>(this)->snappoints(p, snapprefs); // Get the snappoints at the item's center if (snapprefs != NULL && snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER)) { @@ -954,27 +913,27 @@ void SPItem::getSnappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscap } } +// CPPIFY: make pure virtual +void SPItem::print(SPPrintContext* ctx) { + //throw; +} + void SPItem::invoke_print(SPPrintContext *ctx) { if ( !isHidden() ) { - if ( reinterpret_cast<SPItemClass *>(G_OBJECT_GET_CLASS(this))->print ) { - if (!transform.isIdentity() - || style->opacity.value != SP_SCALE24_MAX) - { - sp_print_bind(ctx, transform, SP_SCALE24_TO_FLOAT(style->opacity.value)); - reinterpret_cast<SPItemClass *>(G_OBJECT_GET_CLASS(this))->print(this, ctx); - sp_print_release(ctx); - } else { - reinterpret_cast<SPItemClass *>(G_OBJECT_GET_CLASS(this))->print(this, ctx); - } - } + if (!transform.isIdentity() || style->opacity.value != SP_SCALE24_MAX) { + sp_print_bind(ctx, transform, SP_SCALE24_TO_FLOAT(style->opacity.value)); + this->print(ctx); + sp_print_release(ctx); + } else { + this->print(ctx); + } } } -static gchar* -sp_item_private_description(SPItem * /*item*/) -{ - return g_strdup(_("Object")); +// CPPIFY: is it possible to combine this method with "SPItem::description()"? +gchar* SPItem::description() { + return g_strdup(_("Object")); } /** @@ -982,36 +941,37 @@ sp_item_private_description(SPItem * /*item*/) * * Must be freed by caller. */ -gchar *SPItem::description() +gchar *SPItem::getDetailedDescription() { - if ((SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->description) { - gchar *s = (SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->description(this); - if (s && clip_ref->getObject()) { - gchar *snew = g_strdup_printf (_("%s; <i>clipped</i>"), s); - g_free (s); - s = snew; - } - if (s && mask_ref->getObject()) { - gchar *snew = g_strdup_printf (_("%s; <i>masked</i>"), s); - g_free (s); - s = snew; - } - if ( style && style->filter.href && style->filter.href->getObject() ) { - const gchar *label = style->filter.href->getObject()->label(); - gchar *snew = 0; - if (label) { - snew = g_strdup_printf (_("%s; <i>filtered (%s)</i>"), s, _(label)); - } else { - snew = g_strdup_printf (_("%s; <i>filtered</i>"), s); - } - g_free (s); - s = snew; - } - return s; - } + gchar* s = this->description(); - g_assert_not_reached(); - return NULL; + if (s && clip_ref->getObject()) { + gchar *snew = g_strdup_printf (_("%s; <i>clipped</i>"), s); + g_free (s); + s = snew; + } + + if (s && mask_ref->getObject()) { + gchar *snew = g_strdup_printf (_("%s; <i>masked</i>"), s); + g_free (s); + s = snew; + } + + if ( style && style->filter.href && style->filter.href->getObject() ) { + const gchar *label = style->filter.href->getObject()->label(); + gchar *snew = 0; + + if (label) { + snew = g_strdup_printf (_("%s; <i>filtered (%s)</i>"), s, _(label)); + } else { + snew = g_strdup_printf (_("%s; <i>filtered</i>"), s); + } + + g_free (s); + s = snew; + } + + return s; } /** @@ -1021,9 +981,10 @@ gchar *SPItem::description() int SPItem::ifilt() { int retval=0; - if ((SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->description) { - if ( style && style->filter.href && style->filter.href->getObject() ) { retval=1; } - } + if ( style && style->filter.href && style->filter.href->getObject() ) { + retval=1; + } + return retval; } @@ -1042,12 +1003,17 @@ unsigned SPItem::display_key_new(unsigned numkeys) return dkey - numkeys; } +// CPPIFY: make pure virtual +Inkscape::DrawingItem* SPItem::show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { + //throw; + return 0; +} + Inkscape::DrawingItem *SPItem::invoke_show(Inkscape::Drawing &drawing, unsigned key, unsigned flags) { Inkscape::DrawingItem *ai = NULL; - if ((SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->show) { - ai = (SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->show(this, drawing, key, flags); - } + + ai = this->show(drawing, key, flags); if (ai != NULL) { Geom::OptRect item_bbox = geometricBounds(); @@ -1082,11 +1048,11 @@ Inkscape::DrawingItem *SPItem::invoke_show(Inkscape::Drawing &drawing, unsigned int mask_key = display->arenaitem->key(); // Show and set mask - Inkscape::DrawingItem *ac = sp_mask_show(mask, drawing, mask_key); + Inkscape::DrawingItem *ac = mask->sp_mask_show(drawing, mask_key); ai->setMask(ac); // Update bbox, in case the mask uses bbox units - sp_mask_set_bbox(SP_MASK(mask), mask_key, item_bbox); + SP_MASK(mask)->sp_mask_set_bbox(mask_key, item_bbox); mask->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } if (style->filter.set && display) { @@ -1099,11 +1065,14 @@ Inkscape::DrawingItem *SPItem::invoke_show(Inkscape::Drawing &drawing, unsigned return ai; } +// CPPIFY: make pure virtual +void SPItem::hide(unsigned int key) { + //throw; +} + void SPItem::invoke_hide(unsigned key) { - if ((SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->hide) { - (SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->hide(this, key); - } + this->hide(key); SPItemView *ref = NULL; SPItemView *v = display; @@ -1115,7 +1084,7 @@ void SPItem::invoke_hide(unsigned key) v->arenaitem->setClip(NULL); } if (mask_ref->getObject()) { - sp_mask_hide(mask_ref->getObject(), v->arenaitem->key()); + mask_ref->getObject()->sp_mask_hide(v->arenaitem->key()); v->arenaitem->setMask(NULL); } if (!ref) { @@ -1262,7 +1231,7 @@ static void sp_item_adjust_rects_recursive(SPItem *item, Geom::Affine advertized_transform) { if (SP_IS_RECT (item)) { - sp_rect_compensate_rxry (SP_RECT(item), advertized_transform); + SP_RECT(item)->compensateRxRy(advertized_transform); } for (SPObject *o = item->children; o != NULL; o = o->next) { @@ -1328,6 +1297,13 @@ void SPItem::adjust_livepatheffect (Geom::Affine const &postmul, bool set) } } +// CPPIFY:: make pure virtual? +// Not all SPItems must necessarily have a set transform method! +Geom::Affine SPItem::set_transform(Geom::Affine const &transform) { +// throw; + return transform; +} + /** * Set a new transform on an object. * @@ -1392,14 +1368,19 @@ void SPItem::doWriteTransform(Inkscape::XML::Node *repr, Geom::Affine const &tra gint preserve = prefs->getBool("/options/preservetransform/value", 0); Geom::Affine transform_attr (transform); + + // CPPIFY: check this code. + // If onSetTransform is not overridden, CItem::onSetTransform will return the transform it was given as a parameter. + // onSetTransform cannot be pure due to the fact that not all visible Items are transformable. + if ( // run the object's set_transform (i.e. embed transform) only if: - (SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->set_transform && // it does have a set_transform method !preserve && // user did not chose to preserve all transforms !clip_ref->getObject() && // the object does not have a clippath !mask_ref->getObject() && // the object does not have a mask !(!transform.isTranslation() && style && style->getFilter()) // the object does not have a filter, or the transform is translation (which is supposed to not affect filters) ) { - transform_attr = (SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->set_transform(this, transform); + transform_attr = this->set_transform(transform); + if (freeze_stroke_width) { freeze_stroke_width_recursive(false); } @@ -1430,13 +1411,14 @@ void SPItem::doWriteTransform(Inkscape::XML::Node *repr, Geom::Affine const &tra _transformed_signal.emit(&advertized_transform, this); } +// CPPIFY: see below, do not make pure? +gint SPItem::event(SPEvent* event) { + return FALSE; +} + gint SPItem::emitEvent(SPEvent &event) { - if ((SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->event) { - return (SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->event(this, &event); - } - - return FALSE; + return this->event(&event); } /** @@ -1454,16 +1436,10 @@ void SPItem::set_item_transform(Geom::Affine const &transform_matrix) } } -void SPItem::convert_item_to_guides() { - // Use derived method if present ... - if ((SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->convert_to_guides) { - (*(SP_ITEM_CLASS(G_OBJECT_GET_CLASS(this)))->convert_to_guides)(this); - } else { - // .. otherwise simply place the guides around the item's bounding box - - convert_to_guides(); - } -} +//void SPItem::convert_to_guides() { +// // CPPIFY: If not overridden, call SPItem::convert_to_guides(), see below! +// this->convert_to_guides(); +//} /** diff --git a/src/sp-item.h b/src/sp-item.h index 31b7ac034..8dfb4142a 100644 --- a/src/sp-item.h +++ b/src/sp-item.h @@ -27,7 +27,9 @@ #include "snap-preferences.h" #include "snap-candidate.h" -class SPGuideConstraint; +//class SPGuideConstraint; +#include "sp-guide-constraint.h" + class SPClipPathReference; class SPMaskReference; class SPAvoidRef; @@ -97,15 +99,8 @@ public: Geom::Affine i2vp; }; -class SPItem; -class SPItemClass; - -#define SP_TYPE_ITEM (sp_item_get_type ()) -#define SP_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_ITEM, SPItem)) -#define SP_ITEM_CLASS(clazz) (G_TYPE_CHECK_CLASS_CAST((clazz), SP_TYPE_ITEM, SPItemClass)) -#define SP_IS_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_ITEM)) - -GType sp_item_get_type() G_GNUC_CONST; +#define SP_ITEM(obj) (dynamic_cast<SPItem*>((SPObject*)obj)) +#define SP_IS_ITEM(obj) (dynamic_cast<const SPItem*>((SPObject*)obj) != NULL) /** Abstract base class for all visible shapes. */ class SPItem : public SPObject { @@ -119,6 +114,9 @@ public: VISUAL_BBOX }; + SPItem(); + virtual ~SPItem(); + unsigned int sensitive : 1; unsigned int stop_paint: 1; mutable unsigned bbox_valid : 1; @@ -141,7 +139,6 @@ public: sigc::signal<void, Geom::Affine const *, SPItem *> _transformed_signal; - void init(); bool isLocked() const; void setLocked(bool lock); @@ -191,7 +188,7 @@ public: Geom::OptRect desktopBounds(BBoxType type) const; unsigned pos_in_parent(); - gchar *description(); + gchar *getDetailedDescription(); int ifilt(); void invoke_print(SPPrintContext *ctx); static unsigned int display_key_new(unsigned int numkeys); @@ -215,7 +212,7 @@ public: Geom::Affine i2dt_affine() const; void set_i2d_affine(Geom::Affine const &transform); Geom::Affine dt2i_affine() const; - void convert_to_guides(); + //void convert_to_guides(); private: enum EvaluatedStatus @@ -230,45 +227,25 @@ private: static void clip_ref_changed(SPObject *old_clip, SPObject *clip, SPItem *item); static void mask_ref_changed(SPObject *old_clip, SPObject *clip, SPItem *item); - friend class SPItemClass; -}; - -/// The SPItem vtable. -class SPItemClass { public: - SPObjectClass parent_class; - - /** BBox union in given coordinate system */ - Geom::OptRect (* bbox) (SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type); - - /** Printing method. Assumes ctm is set to item affine matrix */ - /* \todo Think about it, and maybe implement generic export method instead (Lauris) */ - void (* print) (SPItem *item, SPPrintContext *ctx); - - /** Give short description of item (for status display) */ - gchar * (* description) (SPItem * item); - - Inkscape::DrawingItem * (* show) (SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); - void (* hide) (SPItem *item, unsigned int key); - - /** Write to an iterator the points that should be considered for snapping - * as the item's `nodes'. - */ - void (* snappoints) (SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); - - /** Apply the transform optimally, and return any residual transformation */ - Geom::Affine (* set_transform)(SPItem *item, Geom::Affine const &transform); - - /** Convert the item to guidelines */ - void (* convert_to_guides)(SPItem *item); - - /** Emit event, if applicable */ - gint (* event) (SPItem *item, SPEvent *event); - -private: - friend class SPItem; + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void release(); + virtual void set(unsigned int key, gchar const* value); + virtual void update(SPCtx *ctx, guint flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + + virtual Geom::OptRect bbox(Geom::Affine const &transform, SPItem::BBoxType type); + virtual void print(SPPrintContext *ctx); + virtual gchar* description(); + virtual Inkscape::DrawingItem* show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); + virtual void hide(unsigned int key); + virtual void snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); + virtual Geom::Affine set_transform(Geom::Affine const &transform); + virtual void convert_to_guides(); + virtual gint event(SPEvent *event); }; + // Utility Geom::Affine i2anc_affine(SPObject const *item, SPObject const *ancestor); diff --git a/src/sp-line.cpp b/src/sp-line.cpp index 218d0c3b1..3963007de 100644 --- a/src/sp-line.cpp +++ b/src/sp-line.cpp @@ -24,198 +24,148 @@ #include "document.h" #include "inkscape.h" -static void sp_line_build(SPObject * object, SPDocument * document, Inkscape::XML::Node * repr); -static void sp_line_set(SPObject *object, unsigned int key, const gchar *value); -static Inkscape::XML::Node* sp_line_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_line_update(SPObject *object, SPCtx *ctx, guint flags); -static gchar* sp_line_get_description(SPItem * item); -static Geom::Affine sp_line_set_transform(SPItem *item, Geom::Affine const &xform); -static void sp_line_set_shape(SPShape *shape); -static void sp_line_convert_to_guides(SPItem *item); - -G_DEFINE_TYPE(SPLine, sp_line, SP_TYPE_SHAPE); - -static void -sp_line_class_init(SPLineClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPItemClass *item_class = (SPItemClass *) klass; - SPShapeClass *shape_class = (SPShapeClass *) klass; - - sp_object_class->build = sp_line_build; - sp_object_class->set = sp_line_set; - sp_object_class->write = sp_line_write; - sp_object_class->update = sp_line_update; - - item_class->description = sp_line_get_description; - item_class->set_transform = sp_line_set_transform; - item_class->convert_to_guides = sp_line_convert_to_guides; - - shape_class->set_shape = sp_line_set_shape; +#include "sp-factory.h" + +namespace { + SPObject* createLine() { + return new SPLine(); + } + + bool lineRegistered = SPFactory::instance().registerObject("svg:line", createLine); } -static void -sp_line_init(SPLine * line) -{ - line->x1.unset(); - line->y1.unset(); - line->x2.unset(); - line->y2.unset(); +SPLine::SPLine() : SPShape() { + this->x1.unset(); + this->y1.unset(); + this->x2.unset(); + this->y2.unset(); } +SPLine::~SPLine() { +} -static void -sp_line_build(SPObject * object, SPDocument * document, Inkscape::XML::Node * repr) -{ - if (((SPObjectClass *) sp_line_parent_class)->build) { - ((SPObjectClass *) sp_line_parent_class)->build(object, document, repr); - } +void SPLine::build(SPDocument * document, Inkscape::XML::Node * repr) { + SPShape::build(document, repr); - object->readAttr( "x1" ); - object->readAttr( "y1" ); - object->readAttr( "x2" ); - object->readAttr( "y2" ); + this->readAttr( "x1" ); + this->readAttr( "y1" ); + this->readAttr( "x2" ); + this->readAttr( "y2" ); } -static void -sp_line_set(SPObject *object, unsigned int key, const gchar *value) -{ - SPLine * line = SP_LINE(object); - +void SPLine::set(unsigned int key, const gchar* value) { /* fixme: we should really collect updates */ switch (key) { case SP_ATTR_X1: - line->x1.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->x1.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_Y1: - line->y1.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->y1.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_X2: - line->x2.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->x2.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_Y2: - line->y2.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->y2.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + default: - if (((SPObjectClass *) sp_line_parent_class)->set) { - ((SPObjectClass *) sp_line_parent_class)->set(object, key, value); - } + SPShape::set(key, value); break; } } -static void -sp_line_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPLine::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - SPLine *line = SP_LINE(object); - - SPStyle const *style = object->style; + SPStyle const *style = this->style; SPItemCtx const *ictx = (SPItemCtx const *) ctx; double const w = ictx->viewport.width(); double const h = ictx->viewport.height(); double const em = style->font_size.computed; double const ex = em * 0.5; // fixme: get from pango or libnrtype. - line->x1.update(em, ex, w); - line->x2.update(em, ex, w); - line->y1.update(em, ex, h); - line->y2.update(em, ex, h); - ((SPShape *) object)->setShape(); - } + this->x1.update(em, ex, w); + this->x2.update(em, ex, w); + this->y1.update(em, ex, h); + this->y2.update(em, ex, h); - if (((SPObjectClass *) sp_line_parent_class)->update) { - ((SPObjectClass *) sp_line_parent_class)->update(object, ctx, flags); + this->set_shape(); } -} + SPShape::update(ctx, flags); +} -static Inkscape::XML::Node* -sp_line_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPLine *line = SP_LINE(object); - +Inkscape::XML::Node* SPLine::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:line"); } - if (repr != object->getRepr()) { - repr->mergeFrom(object->getRepr(), "id"); + if (repr != this->getRepr()) { + repr->mergeFrom(this->getRepr(), "id"); } - sp_repr_set_svg_double(repr, "x1", line->x1.computed); - sp_repr_set_svg_double(repr, "y1", line->y1.computed); - sp_repr_set_svg_double(repr, "x2", line->x2.computed); - sp_repr_set_svg_double(repr, "y2", line->y2.computed); + sp_repr_set_svg_double(repr, "x1", this->x1.computed); + sp_repr_set_svg_double(repr, "y1", this->y1.computed); + sp_repr_set_svg_double(repr, "x2", this->x2.computed); + sp_repr_set_svg_double(repr, "y2", this->y2.computed); - if (((SPObjectClass *) (sp_line_parent_class))->write) { - ((SPObjectClass *) (sp_line_parent_class))->write(object, xml_doc, repr, flags); - } + SPShape::write(xml_doc, repr, flags); return repr; } -static gchar* -sp_line_get_description(SPItem * /*item*/) -{ - return g_strdup(_("<b>Line</b>")); +gchar* SPLine::description() { + return g_strdup(_("<b>Line</b>")); } -static void -sp_line_convert_to_guides(SPItem *item) -{ - SPLine *line = SP_LINE(item); +void SPLine::convert_to_guides() { Geom::Point points[2]; + Geom::Affine const i2dt(this->i2dt_affine()); - Geom::Affine const i2dt(item->i2dt_affine()); - - points[0] = Geom::Point(line->x1.computed, line->y1.computed)*i2dt; - points[1] = Geom::Point(line->x2.computed, line->y2.computed)*i2dt; + points[0] = Geom::Point(this->x1.computed, this->y1.computed)*i2dt; + points[1] = Geom::Point(this->x2.computed, this->y2.computed)*i2dt; - SPGuide::createSPGuide(item->document, points[0], points[1]); + SPGuide::createSPGuide(this->document, points[0], points[1]); } -static Geom::Affine -sp_line_set_transform(SPItem *item, Geom::Affine const &xform) -{ - SPLine *line = SP_LINE(item); + +Geom::Affine SPLine::set_transform(Geom::Affine const &transform) { Geom::Point points[2]; - points[0] = Geom::Point(line->x1.computed, line->y1.computed); - points[1] = Geom::Point(line->x2.computed, line->y2.computed); + points[0] = Geom::Point(this->x1.computed, this->y1.computed); + points[1] = Geom::Point(this->x2.computed, this->y2.computed); - points[0] *= xform; - points[1] *= xform; + points[0] *= transform; + points[1] *= transform; - line->x1.computed = points[0][Geom::X]; - line->y1.computed = points[0][Geom::Y]; - line->x2.computed = points[1][Geom::X]; - line->y2.computed = points[1][Geom::Y]; + this->x1.computed = points[0][Geom::X]; + this->y1.computed = points[0][Geom::Y]; + this->x2.computed = points[1][Geom::X]; + this->y2.computed = points[1][Geom::Y]; - item->adjust_stroke(xform.descrim()); + this->adjust_stroke(transform.descrim()); - SP_OBJECT(item)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); return Geom::identity(); } -static void -sp_line_set_shape(SPShape *shape) -{ - SPLine *line = SP_LINE(shape); - +void SPLine::set_shape() { SPCurve *c = new SPCurve(); - c->moveto(line->x1.computed, line->y1.computed); - c->lineto(line->x2.computed, line->y2.computed); + c->moveto(this->x1.computed, this->y1.computed); + c->lineto(this->x2.computed, this->y2.computed); - shape->setCurveInsync(c, TRUE); // *_insync does not call update, avoiding infinite recursion when set_shape is called by update - shape->setCurveBeforeLPE(c); + this->setCurveInsync(c, TRUE); // *_insync does not call update, avoiding infinite recursion when set_shape is called by update + this->setCurveBeforeLPE(c); // LPE's cannot be applied to lines. (the result can (generally) not be represented as SPLine) diff --git a/src/sp-line.h b/src/sp-line.h index 836b2df67..ebdfc9f04 100644 --- a/src/sp-line.h +++ b/src/sp-line.h @@ -17,39 +17,31 @@ #include "svg/svg-length.h" #include "sp-shape.h" - - -#define SP_TYPE_LINE (sp_line_get_type()) -#define SP_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_LINE, SPLine)) -#define SP_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_LINE, SPLineClass)) -#define SP_IS_LINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_LINE)) -#define SP_IS_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_LINE)) - -class SPLine; -class SPLineClass; - -GType sp_line_get_type(void) G_GNUC_CONST; +#define SP_LINE(obj) (dynamic_cast<SPLine*>((SPObject*)obj)) +#define SP_IS_LINE(obj) (dynamic_cast<const SPLine*>((SPObject*)obj) != NULL) class SPLine : public SPShape { public: + SPLine(); + virtual ~SPLine(); + SVGLength x1; SVGLength y1; SVGLength x2; SVGLength y2; -private: - friend class SPLineClass; -}; + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + virtual void set(unsigned int key, gchar const* value); -class SPLineClass { -public: - SPShapeClass parent_class; + virtual gchar* description(); + virtual Geom::Affine set_transform(Geom::Affine const &transform); + virtual void convert_to_guides(); + virtual void update(SPCtx* ctx, guint flags); -private: - friend class SPLine; + virtual void set_shape(); }; - #endif // SEEN_SP_LINE_H /* Local Variables: diff --git a/src/sp-linear-gradient-fns.h b/src/sp-linear-gradient-fns.h deleted file mode 100644 index 14e575ebe..000000000 --- a/src/sp-linear-gradient-fns.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef SP_LINEAR_GRADIENT_FNS_H -#define SP_LINEAR_GRADIENT_FNS_H - -/** \file - * Macros and fn declarations related to linear gradients. - */ - -#include <glib-object.h> -#include <glib.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -struct SPLinearGradient; - -#define SP_TYPE_LINEARGRADIENT (sp_lineargradient_get_type()) -#define SP_LINEARGRADIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_LINEARGRADIENT, SPLinearGradient)) -#define SP_LINEARGRADIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_LINEARGRADIENT, SPLinearGradientClass)) -#define SP_IS_LINEARGRADIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_LINEARGRADIENT)) -#define SP_IS_LINEARGRADIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_LINEARGRADIENT)) - -GType sp_lineargradient_get_type(); - -void sp_lineargradient_set_position(SPLinearGradient *lg, gdouble x1, gdouble y1, gdouble x2, gdouble y2); - -#endif /* !SP_LINEAR_GRADIENT_FNS_H */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-linear-gradient.cpp b/src/sp-linear-gradient.cpp new file mode 100644 index 000000000..4e7a08f4b --- /dev/null +++ b/src/sp-linear-gradient.cpp @@ -0,0 +1,109 @@ +#include "sp-linear-gradient.h" + +#include "attributes.h" +#include "xml/repr.h" + +#include "sp-factory.h" + +namespace { + SPObject* createLinearGradient() { + return new SPLinearGradient(); + } + + bool linearGradientRegistered = SPFactory::instance().registerObject("svg:linearGradient", createLinearGradient); +} + + +/* + * Linear Gradient + */ +SPLinearGradient::SPLinearGradient() : SPGradient() { + this->x1.unset(SVGLength::PERCENT, 0.0, 0.0); + this->y1.unset(SVGLength::PERCENT, 0.0, 0.0); + this->x2.unset(SVGLength::PERCENT, 1.0, 1.0); + this->y2.unset(SVGLength::PERCENT, 0.0, 0.0); +} + +SPLinearGradient::~SPLinearGradient() { +} + +void SPLinearGradient::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPGradient::build(document, repr); + + this->readAttr( "x1" ); + this->readAttr( "y1" ); + this->readAttr( "x2" ); + this->readAttr( "y2" ); +} + +/** + * Callback: set attribute. + */ +void SPLinearGradient::set(unsigned int key, const gchar* value) { + switch (key) { + case SP_ATTR_X1: + this->x1.readOrUnset(value, SVGLength::PERCENT, 0.0, 0.0); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_Y1: + this->y1.readOrUnset(value, SVGLength::PERCENT, 0.0, 0.0); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_X2: + this->x2.readOrUnset(value, SVGLength::PERCENT, 1.0, 1.0); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_Y2: + this->y2.readOrUnset(value, SVGLength::PERCENT, 0.0, 0.0); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + default: + SPGradient::set(key, value); + break; + } +} + +/** + * Callback: write attributes to associated repr. + */ +Inkscape::XML::Node* SPLinearGradient::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { + if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { + repr = xml_doc->createElement("svg:linearGradient"); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->x1._set) { + sp_repr_set_svg_double(repr, "x1", this->x1.computed); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->y1._set) { + sp_repr_set_svg_double(repr, "y1", this->y1.computed); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->x2._set) { + sp_repr_set_svg_double(repr, "x2", this->x2.computed); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->y2._set) { + sp_repr_set_svg_double(repr, "y2", this->y2.computed); + } + + SPGradient::write(xml_doc, repr, flags); + + return repr; +} + +cairo_pattern_t* SPLinearGradient::pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity) { + this->ensureVector(); + + cairo_pattern_t *cp = cairo_pattern_create_linear( + this->x1.computed, this->y1.computed, + this->x2.computed, this->y2.computed); + + sp_gradient_pattern_common_setup(cp, this, bbox, opacity); + + return cp; +} diff --git a/src/sp-linear-gradient.h b/src/sp-linear-gradient.h index b99b6b293..ac3fdb04a 100644 --- a/src/sp-linear-gradient.h +++ b/src/sp-linear-gradient.h @@ -7,19 +7,27 @@ #include "sp-gradient.h" #include "svg/svg-length.h" -#include "sp-linear-gradient-fns.h" + +#define SP_LINEARGRADIENT(obj) (dynamic_cast<SPLinearGradient*>((SPObject*)obj)) +#define SP_IS_LINEARGRADIENT(obj) (dynamic_cast<const SPLinearGradient*>((SPObject*)obj) != NULL) /** Linear gradient. */ -struct SPLinearGradient : public SPGradient { +class SPLinearGradient : public SPGradient { +public: + SPLinearGradient(); + virtual ~SPLinearGradient(); + SVGLength x1; SVGLength y1; SVGLength x2; SVGLength y2; -}; -/// The SPLinearGradient vtable. -struct SPLinearGradientClass { - SPGradientClass parent_class; + virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity); + +protected: + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void set(unsigned key, gchar const *value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); }; #endif /* !SP_LINEAR_GRADIENT_H */ diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index d4619e794..c86730048 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -39,18 +39,6 @@ #include <algorithm> /* LPEItem base class */ -static void sp_lpe_item_finalize(GObject *object); - -static void sp_lpe_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_lpe_item_release(SPObject *object); -static void sp_lpe_item_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_lpe_item_update(SPObject *object, SPCtx *ctx, guint flags); -static void sp_lpe_item_modified (SPObject *object, unsigned int flags); -static Inkscape::XML::Node *sp_lpe_item_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); - -static void sp_lpe_item_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref); -static void sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child); - static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable); static void lpeobject_ref_modified(SPObject *href, guint flags, SPLPEItem *lpeitem); @@ -61,128 +49,88 @@ typedef std::list<std::string> HRefList; static std::string patheffectlist_write_svg(PathEffectList const & list); static std::string hreflist_write_svg(HRefList const & list); -G_DEFINE_TYPE(SPLPEItem, sp_lpe_item, SP_TYPE_ITEM); - -static void sp_lpe_item_class_init(SPLPEItemClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS(klass); - SPObjectClass *sp_object_class = SP_OBJECT_CLASS(klass); - - gobject_class->finalize = sp_lpe_item_finalize; - sp_object_class->build = sp_lpe_item_build; - sp_object_class->release = sp_lpe_item_release; - sp_object_class->set = sp_lpe_item_set; - sp_object_class->update = sp_lpe_item_update; - sp_object_class->modified = sp_lpe_item_modified; - sp_object_class->write = sp_lpe_item_write; - sp_object_class->child_added = sp_lpe_item_child_added; - sp_object_class->remove_child = sp_lpe_item_remove_child; - - klass->update_patheffect = NULL; -} - -static void -sp_lpe_item_init(SPLPEItem *lpeitem) -{ - lpeitem->path_effects_enabled = 1; +SPLPEItem::SPLPEItem() : SPItem() { + this->path_effects_enabled = 1; - lpeitem->path_effect_list = new PathEffectList(); - lpeitem->current_path_effect = NULL; + this->path_effect_list = new PathEffectList(); + this->current_path_effect = NULL; - lpeitem->lpe_modified_connection_list = new std::list<sigc::connection>(); + this->lpe_modified_connection_list = new std::list<sigc::connection>(); } -static void sp_lpe_item_finalize(GObject *object) -{ - if (((GObjectClass *) (sp_lpe_item_parent_class))->finalize) { - (* ((GObjectClass *) (sp_lpe_item_parent_class))->finalize)(object); - } +SPLPEItem::~SPLPEItem() { } -/** - * Reads the Inkscape::XML::Node, and initializes SPLPEItem variables. For this to get called, - * our name must be associated with a repr via "sp_object_type_register". Best done through - * sp-object-repr.cpp's repr_name_entries array. - */ -static void sp_lpe_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - object->readAttr( "inkscape:path-effect" ); +void SPLPEItem::build(SPDocument *document, Inkscape::XML::Node *repr) { + this->readAttr( "inkscape:path-effect" ); - if ((SP_OBJECT_CLASS(sp_lpe_item_parent_class))->build) { - (SP_OBJECT_CLASS(sp_lpe_item_parent_class))->build(object, document, repr); - } + SPItem::build(document, repr); } -/** - * Drops any allocated memory. - */ -static void sp_lpe_item_release(SPObject *object) -{ - SPLPEItem *lpeitem = SP_LPE_ITEM(object); - +void SPLPEItem::release() { // disconnect all modified listeners: - for (std::list<sigc::connection>::iterator mod_it = lpeitem->lpe_modified_connection_list->begin(); - mod_it != lpeitem->lpe_modified_connection_list->end(); ++mod_it) + for (std::list<sigc::connection>::iterator mod_it = this->lpe_modified_connection_list->begin(); + mod_it != this->lpe_modified_connection_list->end(); ++mod_it) { mod_it->disconnect(); } - delete lpeitem->lpe_modified_connection_list; - lpeitem->lpe_modified_connection_list = NULL; - PathEffectList::iterator it = lpeitem->path_effect_list->begin(); - while ( it != lpeitem->path_effect_list->end() ) { + delete this->lpe_modified_connection_list; + this->lpe_modified_connection_list = NULL; + + PathEffectList::iterator it = this->path_effect_list->begin(); + + while ( it != this->path_effect_list->end() ) { // unlink and delete all references in the list (*it)->unlink(); delete *it; - it = lpeitem->path_effect_list->erase(it); + it = this->path_effect_list->erase(it); } + // delete the list itself - delete lpeitem->path_effect_list; - lpeitem->path_effect_list = NULL; + delete this->path_effect_list; + this->path_effect_list = NULL; - if ((SP_OBJECT_CLASS(sp_lpe_item_parent_class))->release) - (SP_OBJECT_CLASS(sp_lpe_item_parent_class))->release(object); + SPItem::release(); } -/** - * Sets a specific value in the SPLPEItem. - */ -static void sp_lpe_item_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPLPEItem *lpeitem = SP_LPE_ITEM(object); - +void SPLPEItem::set(unsigned int key, gchar const* value) { switch (key) { case SP_ATTR_INKSCAPE_PATH_EFFECT: { - lpeitem->current_path_effect = NULL; + this->current_path_effect = NULL; // Disable the path effects while populating the LPE list - sp_lpe_item_enable_path_effects(lpeitem, false); + sp_lpe_item_enable_path_effects(this, false); // disconnect all modified listeners: - for ( std::list<sigc::connection>::iterator mod_it = lpeitem->lpe_modified_connection_list->begin(); - mod_it != lpeitem->lpe_modified_connection_list->end(); + for ( std::list<sigc::connection>::iterator mod_it = this->lpe_modified_connection_list->begin(); + mod_it != this->lpe_modified_connection_list->end(); ++mod_it) { mod_it->disconnect(); } - lpeitem->lpe_modified_connection_list->clear(); + + this->lpe_modified_connection_list->clear(); // Clear the path effect list - PathEffectList::iterator it = lpeitem->path_effect_list->begin(); - while ( it != lpeitem->path_effect_list->end() ) + PathEffectList::iterator it = this->path_effect_list->begin(); + + while ( it != this->path_effect_list->end() ) { (*it)->unlink(); delete *it; - it = lpeitem->path_effect_list->erase(it); + it = this->path_effect_list->erase(it); } // Parse the contents of "value" to rebuild the path effect reference list if ( value ) { std::istringstream iss(value); std::string href; + while (std::getline(iss, href, ';')) { - Inkscape::LivePathEffect::LPEObjectReference *path_effect_ref = new Inkscape::LivePathEffect::LPEObjectReference(object); + Inkscape::LivePathEffect::LPEObjectReference *path_effect_ref = new Inkscape::LivePathEffect::LPEObjectReference(this); + try { path_effect_ref->link(href.c_str()); } catch (Inkscape::BadURIException &e) { @@ -192,11 +140,12 @@ static void sp_lpe_item_set(SPObject *object, unsigned int key, gchar const *val path_effect_ref = NULL; } - lpeitem->path_effect_list->push_back(path_effect_ref); + this->path_effect_list->push_back(path_effect_ref); + if ( path_effect_ref->lpeobject && path_effect_ref->lpeobject->get_lpe() ) { // connect modified-listener - lpeitem->lpe_modified_connection_list->push_back( - path_effect_ref->lpeobject->connectModified(sigc::bind(sigc::ptr_fun(&lpeobject_ref_modified), lpeitem)) ); + this->lpe_modified_connection_list->push_back( + path_effect_ref->lpeobject->connectModified(sigc::bind(sigc::ptr_fun(&lpeobject_ref_modified), this)) ); } else { // something has gone wrong in finding the right patheffect. g_warning("Unknown LPE type specified, LPE stack effectively disabled"); @@ -205,64 +154,42 @@ static void sp_lpe_item_set(SPObject *object, unsigned int key, gchar const *val } } - sp_lpe_item_enable_path_effects(lpeitem, true); + sp_lpe_item_enable_path_effects(this, true); } break; + default: - if ((SP_OBJECT_CLASS(sp_lpe_item_parent_class))->set) { - (SP_OBJECT_CLASS(sp_lpe_item_parent_class))->set(object, key, value); - } + SPItem::set(key, value); break; } } -/** - * Receives update notifications. - */ -static void -sp_lpe_item_update(SPObject *object, SPCtx *ctx, guint flags) -{ - if ((SP_OBJECT_CLASS(sp_lpe_item_parent_class))->update) { - (SP_OBJECT_CLASS(sp_lpe_item_parent_class))->update(object, ctx, flags); - } +void SPLPEItem::update(SPCtx* ctx, unsigned int flags) { + SPItem::update(ctx, flags); - // update the helperpaths of all LPEs applied to the item + // update the helperpaths of all LPEs applied to the item // TODO: re-add for the new node tool } -/** - * Sets modified flag for all sub-item views. - */ -static void sp_lpe_item_modified (SPObject *object, unsigned int flags) -{ - if (SP_IS_GROUP(object) && (flags & SP_OBJECT_MODIFIED_FLAG) && (flags & SP_OBJECT_USER_MODIFIED_FLAG_B)) { - sp_lpe_item_update_patheffect(SP_LPE_ITEM(object), true, true); +void SPLPEItem::modified(unsigned int flags) { + if (SP_IS_GROUP(this) && (flags & SP_OBJECT_MODIFIED_FLAG) && (flags & SP_OBJECT_USER_MODIFIED_FLAG_B)) { + sp_lpe_item_update_patheffect(this, true, true); } - if ((SP_OBJECT_CLASS(sp_lpe_item_parent_class))->modified) { - (* (SP_OBJECT_CLASS(sp_lpe_item_parent_class))->modified) (object, flags); - } +// SPItem::onModified(flags); } -/** - * Writes its settings to an incoming repr object, if any. - */ -static Inkscape::XML::Node * sp_lpe_item_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPLPEItem *lpeitem = SP_LPE_ITEM(object); - +Inkscape::XML::Node* SPLPEItem::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if (flags & SP_OBJECT_WRITE_EXT) { - if ( sp_lpe_item_has_path_effect(lpeitem) ) { - std::string href = patheffectlist_write_svg(*lpeitem->path_effect_list); + if ( sp_lpe_item_has_path_effect(this) ) { + std::string href = patheffectlist_write_svg(*this->path_effect_list); repr->setAttribute("inkscape:path-effect", href.c_str()); } else { repr->setAttribute("inkscape:path-effect", NULL); } } - if ((SP_OBJECT_CLASS(sp_lpe_item_parent_class))->write) { - (SP_OBJECT_CLASS(sp_lpe_item_parent_class))->write(object, xml_doc, repr, flags); - } + SPItem::write(xml_doc, repr, flags); return repr; } @@ -271,8 +198,13 @@ static Inkscape::XML::Node * sp_lpe_item_write(SPObject *object, Inkscape::XML:: * returns true when LPE was successful. */ bool sp_lpe_item_perform_path_effect(SPLPEItem *lpeitem, SPCurve *curve) { - if (!lpeitem) return false; - if (!curve) return false; + if (!lpeitem) { + return false; + } + + if (!curve) { + return false; + } if (sp_lpe_item_has_path_effect(lpeitem) && sp_lpe_item_path_effects_enabled(lpeitem)) { for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it) @@ -324,6 +256,11 @@ bool sp_lpe_item_perform_path_effect(SPLPEItem *lpeitem, SPCurve *curve) { return true; } +// CPPIFY: make pure virtual +void SPLPEItem::update_patheffect(bool write) { + //throw; +} + /** * Calls any registered handlers for the update_patheffect action */ @@ -370,9 +307,7 @@ sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool wholetree, bool write) top = lpeitem; } - if (SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (top))->update_patheffect) { - SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (top))->update_patheffect (top, write); - } + top->update_patheffect(write); } /** @@ -639,39 +574,38 @@ void sp_lpe_item_edit_next_param_oncanvas(SPLPEItem *lpeitem, SPDesktop *dt) } } -static void sp_lpe_item_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) -{ - if ((SP_OBJECT_CLASS(sp_lpe_item_parent_class))->child_added) - (* (SP_OBJECT_CLASS(sp_lpe_item_parent_class))->child_added) (object, child, ref); +void SPLPEItem::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { + SPItem::child_added(child, ref); + + if (sp_lpe_item_has_path_effect_recursive(this)) { + SPObject *ochild = this->get_child_by_repr(child); - if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) { - SPObject *ochild = object->get_child_by_repr(child); if ( ochild && SP_IS_LPE_ITEM(ochild) ) { sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(ochild)); } } } +void SPLPEItem::remove_child(Inkscape::XML::Node * child) { + if (sp_lpe_item_has_path_effect_recursive(this)) { + SPObject *ochild = this->get_child_by_repr(child); -static void sp_lpe_item_remove_child(SPObject * object, Inkscape::XML::Node * child) -{ - if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) { - SPObject *ochild = object->get_child_by_repr(child); if ( ochild && SP_IS_LPE_ITEM(ochild) ) { sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(ochild)); } } - if ((SP_OBJECT_CLASS(sp_lpe_item_parent_class))->remove_child) - (* (SP_OBJECT_CLASS(sp_lpe_item_parent_class))->remove_child) (object, child); + SPItem::remove_child(child); } static std::string patheffectlist_write_svg(PathEffectList const & list) { HRefList hreflist; + for (PathEffectList::const_iterator it = list.begin(); it != list.end(); ++it) { hreflist.push_back( std::string((*it)->lpeobject_href) ); } + return hreflist_write_svg(hreflist); } @@ -686,15 +620,18 @@ static std::string hreflist_write_svg(HRefList const & list) { std::string r; bool semicolon_first = false; + for (HRefList::const_iterator it = list.begin(); it != list.end(); ++it) { if (semicolon_first) { r += ';'; } + semicolon_first = true; r += (*it); } + return r; } @@ -703,6 +640,7 @@ PathEffectList sp_lpe_item_get_effect_list(SPLPEItem *lpeitem) { return *(lpeitem->path_effect_list); } + // Return a copy of the effect list PathEffectList const sp_lpe_item_get_effect_list(SPLPEItem const *lpeitem) { @@ -752,6 +690,7 @@ void SPLPEItem::replacePathEffects( std::vector<LivePathEffectObject const *> co { LivePathEffectObject const * current_lpeobj = (*it)->lpeobject; std::vector<LivePathEffectObject const *>::const_iterator found_it(std::find(old_lpeobjs.begin(), old_lpeobjs.end(), current_lpeobj)); + if ( found_it != old_lpeobjs.end() ) { std::vector<LivePathEffectObject const *>::difference_type found_index = std::distance (old_lpeobjs.begin(), found_it); const gchar * repr_id = new_lpeobjs[found_index]->getRepr()->attribute("id"); @@ -763,6 +702,7 @@ void SPLPEItem::replacePathEffects( std::vector<LivePathEffectObject const *> co hreflist.push_back( std::string((*it)->lpeobject_href) ); } } + std::string r = hreflist_write_svg(hreflist); this->getRepr()->setAttribute("inkscape:path-effect", r.c_str()); } diff --git a/src/sp-lpe-item.h b/src/sp-lpe-item.h index 5ff1dee26..925ff34d8 100644 --- a/src/sp-lpe-item.h +++ b/src/sp-lpe-item.h @@ -18,12 +18,10 @@ #include <list> -#define SP_TYPE_LPE_ITEM (sp_lpe_item_get_type()) -#define SP_LPE_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_LPE_ITEM, SPLPEItem)) -#define SP_LPE_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_LPE_ITEM, SPLPEItemClass)) -#define SP_IS_LPE_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_LPE_ITEM)) -#define SP_IS_LPE_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_LPE_ITEM)) +#define SP_LPE_ITEM(obj) (dynamic_cast<SPLPEItem*>((SPObject*)obj)) +#define SP_IS_LPE_ITEM(obj) (dynamic_cast<const SPLPEItem*>((SPObject*)obj) != NULL) +class CLPEItem; class LivePathEffectObject; class SPCurve; class SPDesktop; @@ -42,6 +40,9 @@ typedef std::list<Inkscape::LivePathEffect::LPEObjectReference *> PathEffectList class SPLPEItem : public SPItem { public: + SPLPEItem(); + virtual ~SPLPEItem(); + int path_effects_enabled; PathEffectList* path_effect_list; @@ -52,15 +53,23 @@ public: void replacePathEffects( std::vector<LivePathEffectObject const *> const &old_lpeobjs, std::vector<LivePathEffectObject const *> const &new_lpeobjs ); -}; -struct SPLPEItemClass { - SPItemClass parent_class; - void (* update_patheffect) (SPLPEItem *lpeitem, bool write); -}; + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void set(unsigned int key, gchar const* value); -GType sp_lpe_item_get_type(); + virtual void update(SPCtx* ctx, unsigned int flags); + virtual void modified(unsigned int flags); + + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node* child); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + + virtual void update_patheffect(bool write); +}; void sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool wholetree, bool write); bool sp_lpe_item_perform_path_effect(SPLPEItem *lpeitem, SPCurve *curve); diff --git a/src/sp-mask.cpp b/src/sp-mask.cpp index 4243c9811..9707c9d8e 100644 --- a/src/sp-mask.cpp +++ b/src/sp-mask.cpp @@ -34,129 +34,105 @@ struct SPMaskView { Geom::OptRect bbox; }; -static void sp_mask_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_mask_release (SPObject * object); -static void sp_mask_set (SPObject *object, unsigned int key, const gchar *value); -static void sp_mask_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref); -static void sp_mask_update (SPObject *object, SPCtx *ctx, guint flags); -static void sp_mask_modified (SPObject *object, guint flags); -static Inkscape::XML::Node *sp_mask_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - SPMaskView *sp_mask_view_new_prepend (SPMaskView *list, unsigned int key, Inkscape::DrawingItem *arenaitem); SPMaskView *sp_mask_view_list_remove (SPMaskView *list, SPMaskView *view); -G_DEFINE_TYPE(SPMask, sp_mask, SP_TYPE_OBJECTGROUP); +#include "sp-factory.h" -static void -sp_mask_class_init (SPMaskClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - sp_object_class->build = sp_mask_build; - sp_object_class->release = sp_mask_release; - sp_object_class->set = sp_mask_set; - sp_object_class->child_added = sp_mask_child_added; - sp_object_class->update = sp_mask_update; - sp_object_class->modified = sp_mask_modified; - sp_object_class->write = sp_mask_write; +namespace { + SPObject* createMask() { + return new SPMask(); + } + + bool maskRegistered = SPFactory::instance().registerObject("svg:mask", createMask); } -static void -sp_mask_init (SPMask *mask) -{ - mask->maskUnits_set = FALSE; - mask->maskUnits = SP_CONTENT_UNITS_OBJECTBOUNDINGBOX; +SPMask::SPMask() : SPObjectGroup() { + this->maskUnits_set = FALSE; + this->maskUnits = SP_CONTENT_UNITS_OBJECTBOUNDINGBOX; - mask->maskContentUnits_set = FALSE; - mask->maskContentUnits = SP_CONTENT_UNITS_USERSPACEONUSE; + this->maskContentUnits_set = FALSE; + this->maskContentUnits = SP_CONTENT_UNITS_USERSPACEONUSE; - mask->display = NULL; + this->display = NULL; } -static void -sp_mask_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_mask_parent_class)->build) { - ((SPObjectClass *) sp_mask_parent_class)->build (object, document, repr); - } +SPMask::~SPMask() { +} - object->readAttr( "maskUnits" ); - object->readAttr( "maskContentUnits" ); +void SPMask::build(SPDocument* doc, Inkscape::XML::Node* repr) { + SPObjectGroup::build(doc, repr); + + this->readAttr( "maskUnits" ); + this->readAttr( "maskContentUnits" ); /* Register ourselves */ - document->addResource("mask", object); + doc->addResource("mask", this); } -static void sp_mask_release (SPObject * object) -{ - if (object->document) { +void SPMask::release() { + if (this->document) { // Unregister ourselves - object->document->removeResource("mask", object); + this->document->removeResource("mask", this); } - SPMask *cp = SP_MASK (object); - while (cp->display) { + while (this->display) { // We simply unref and let item manage this in handler - cp->display = sp_mask_view_list_remove (cp->display, cp->display); + this->display = sp_mask_view_list_remove(this->display, this->display); } - if (((SPObjectClass *) (sp_mask_parent_class))->release) { - ((SPObjectClass *) sp_mask_parent_class)->release (object); - } + SPObjectGroup::release(); } -static void -sp_mask_set (SPObject *object, unsigned int key, const gchar *value) -{ - SPMask *mask = SP_MASK (object); - +void SPMask::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_MASKUNITS: - mask->maskUnits = SP_CONTENT_UNITS_OBJECTBOUNDINGBOX; - mask->maskUnits_set = FALSE; + this->maskUnits = SP_CONTENT_UNITS_OBJECTBOUNDINGBOX; + this->maskUnits_set = FALSE; + if (value) { if (!strcmp (value, "userSpaceOnUse")) { - mask->maskUnits = SP_CONTENT_UNITS_USERSPACEONUSE; - mask->maskUnits_set = TRUE; + this->maskUnits = SP_CONTENT_UNITS_USERSPACEONUSE; + this->maskUnits_set = TRUE; } else if (!strcmp (value, "objectBoundingBox")) { - mask->maskUnits_set = TRUE; + this->maskUnits_set = TRUE; } } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_MASKCONTENTUNITS: - mask->maskContentUnits = SP_CONTENT_UNITS_USERSPACEONUSE; - mask->maskContentUnits_set = FALSE; + this->maskContentUnits = SP_CONTENT_UNITS_USERSPACEONUSE; + this->maskContentUnits_set = FALSE; + if (value) { if (!strcmp (value, "userSpaceOnUse")) { - mask->maskContentUnits_set = TRUE; + this->maskContentUnits_set = TRUE; } else if (!strcmp (value, "objectBoundingBox")) { - mask->maskContentUnits = SP_CONTENT_UNITS_OBJECTBOUNDINGBOX; - mask->maskContentUnits_set = TRUE; + this->maskContentUnits = SP_CONTENT_UNITS_OBJECTBOUNDINGBOX; + this->maskContentUnits_set = TRUE; } } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; default: - if (((SPObjectClass *) sp_mask_parent_class)->set) - ((SPObjectClass *) sp_mask_parent_class)->set (object, key, value); + SPObjectGroup::set(key, value); break; } } -static void -sp_mask_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) -{ +void SPMask::child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref) { /* Invoke SPObjectGroup implementation */ - ((SPObjectClass *) (sp_mask_parent_class))->child_added (object, child, ref); + SPObjectGroup::child_added(child, ref); /* Show new object */ - SPObject *ochild = object->document->getObjectByRepr(child); + SPObject *ochild = this->document->getObjectByRepr(child); + if (SP_IS_ITEM (ochild)) { - SPMask *cp = SP_MASK (object); - for (SPMaskView *v = cp->display; v != NULL; v = v->next) { - Inkscape::DrawingItem *ac = SP_ITEM (ochild)->invoke_show ( v->arenaitem->drawing(), - v->key, - SP_ITEM_REFERENCE_FLAGS); + for (SPMaskView *v = this->display; v != NULL; v = v->next) { + Inkscape::DrawingItem *ac = SP_ITEM (ochild)->invoke_show(v->arenaitem->drawing(), v->key, SP_ITEM_REFERENCE_FLAGS); + if (ac) { v->arenaitem->prependChild(ac); } @@ -164,34 +140,37 @@ sp_mask_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML } } -static void sp_mask_update(SPObject *object, SPCtx *ctx, guint flags) -{ + +void SPMask::update(SPCtx* ctx, unsigned int flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } flags &= SP_OBJECT_MODIFIED_CASCADE; - SPObjectGroup *og = SP_OBJECTGROUP(object); GSList *l = NULL; - for (SPObject *child = og->firstChild(); child; child = child->getNext()) { - g_object_ref(G_OBJECT (child)); + for (SPObject *child = this->firstChild(); child; child = child->getNext()) { + sp_object_ref(child); l = g_slist_prepend (l, child); } + l = g_slist_reverse (l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->updateDisplay(ctx, flags); } - g_object_unref(G_OBJECT(child)); + + sp_object_unref(child); } - SPMask *mask = SP_MASK(object); - for (SPMaskView *v = mask->display; v != NULL; v = v->next) { + for (SPMaskView *v = this->display; v != NULL; v = v->next) { Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); - if (mask->maskContentUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX && v->bbox) { + + if (this->maskContentUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX && v->bbox) { Geom::Affine t = Geom::Scale(v->bbox->dimensions()); t.setTranslation(v->bbox->min()); g->setChildTransform(t); @@ -201,40 +180,39 @@ static void sp_mask_update(SPObject *object, SPCtx *ctx, guint flags) } } -static void sp_mask_modified(SPObject *object, guint flags) -{ +void SPMask::modified(unsigned int flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } flags &= SP_OBJECT_MODIFIED_CASCADE; - SPObjectGroup *og = SP_OBJECTGROUP(object); GSList *l = NULL; - for (SPObject *child = og->firstChild(); child; child = child->getNext()) { - g_object_ref(G_OBJECT(child)); + for (SPObject *child = this->firstChild(); child; child = child->getNext()) { + sp_object_ref(child); l = g_slist_prepend(l, child); } + l = g_slist_reverse(l); + while (l) { SPObject *child = SP_OBJECT(l->data); l = g_slist_remove(l, child); + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->emitModified(flags); } - g_object_unref(G_OBJECT(child)); + + sp_object_unref(child); } } -static Inkscape::XML::Node * -sp_mask_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPMask::write(Inkscape::XML::Document* xml_doc, Inkscape::XML::Node* repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:mask"); } - if (((SPObjectClass *) (sp_mask_parent_class))->write) - ((SPObjectClass *) (sp_mask_parent_class))->write (object, xml_doc, repr, flags); + SPObjectGroup::write(xml_doc, repr, flags); return repr; } @@ -271,47 +249,46 @@ sp_mask_create (GSList *reprs, SPDocument *document, Geom::Affine const* applyTr return mask_id; } -Inkscape::DrawingItem *sp_mask_show(SPMask *mask, Inkscape::Drawing &drawing, unsigned int key) -{ - g_return_val_if_fail (mask != NULL, NULL); - g_return_val_if_fail (SP_IS_MASK (mask), NULL); +Inkscape::DrawingItem *SPMask::sp_mask_show(Inkscape::Drawing &drawing, unsigned int key) { + g_return_val_if_fail (this != NULL, NULL); + g_return_val_if_fail (SP_IS_MASK (this), NULL); Inkscape::DrawingGroup *ai = new Inkscape::DrawingGroup(drawing); - mask->display = sp_mask_view_new_prepend (mask->display, key, ai); + this->display = sp_mask_view_new_prepend (this->display, key, ai); - for ( SPObject *child = mask->firstChild() ; child; child = child->getNext() ) { + for ( SPObject *child = this->firstChild() ; child; child = child->getNext() ) { if (SP_IS_ITEM (child)) { Inkscape::DrawingItem *ac = SP_ITEM (child)->invoke_show (drawing, key, SP_ITEM_REFERENCE_FLAGS); + if (ac) { ai->prependChild(ac); } } } - if (mask->maskContentUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX && mask->display->bbox) { - Geom::Affine t = Geom::Scale(mask->display->bbox->dimensions()); - t.setTranslation(mask->display->bbox->min()); + if (this->maskContentUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX && this->display->bbox) { + Geom::Affine t = Geom::Scale(this->display->bbox->dimensions()); + t.setTranslation(this->display->bbox->min()); ai->setChildTransform(t); } return ai; } -void sp_mask_hide(SPMask *cp, unsigned int key) -{ - g_return_if_fail (cp != NULL); - g_return_if_fail (SP_IS_MASK (cp)); +void SPMask::sp_mask_hide(unsigned int key) { + g_return_if_fail (this != NULL); + g_return_if_fail (SP_IS_MASK (this)); - for ( SPObject *child = cp->firstChild(); child; child = child->getNext()) { + for ( SPObject *child = this->firstChild(); child; child = child->getNext()) { if (SP_IS_ITEM (child)) { SP_ITEM(child)->invoke_hide (key); } } - for (SPMaskView *v = cp->display; v != NULL; v = v->next) { + for (SPMaskView *v = this->display; v != NULL; v = v->next) { if (v->key == key) { /* We simply unref and let item to manage this in handler */ - cp->display = sp_mask_view_list_remove (cp->display, v); + this->display = sp_mask_view_list_remove (this->display, v); return; } } @@ -319,10 +296,8 @@ void sp_mask_hide(SPMask *cp, unsigned int key) g_assert_not_reached (); } -void -sp_mask_set_bbox (SPMask *mask, unsigned int key, Geom::OptRect const &bbox) -{ - for (SPMaskView *v = mask->display; v != NULL; v = v->next) { +void SPMask::sp_mask_set_bbox(unsigned int key, Geom::OptRect const &bbox) { + for (SPMaskView *v = this->display; v != NULL; v = v->next) { if (v->key == key) { v->bbox = bbox; break; diff --git a/src/sp-mask.h b/src/sp-mask.h index 97cf95ae1..e08d1e81e 100644 --- a/src/sp-mask.h +++ b/src/sp-mask.h @@ -18,11 +18,8 @@ #include "uri-references.h" #include "xml/node.h" -#define SP_TYPE_MASK (sp_mask_get_type ()) -#define SP_MASK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_MASK, SPMask)) -#define SP_MASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_MASK, SPMaskClass)) -#define SP_IS_MASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_MASK)) -#define SP_IS_MASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_MASK)) +#define SP_MASK(obj) (dynamic_cast<SPMask*>((SPObject*)obj)) +#define SP_IS_MASK(obj) (dynamic_cast<const SPMask*>((SPObject*)obj) != NULL) struct SPMaskView; @@ -34,7 +31,11 @@ class DrawingItem; } // namespace Inkscape -struct SPMask : public SPObjectGroup { +class SPMask : public SPObjectGroup { +public: + SPMask(); + virtual ~SPMask(); + unsigned int maskUnits_set : 1; unsigned int maskUnits : 1; @@ -42,13 +43,25 @@ struct SPMask : public SPObjectGroup { unsigned int maskContentUnits : 1; SPMaskView *display; -}; -struct SPMaskClass { - SPObjectGroupClass parent_class; -}; + Inkscape::DrawingItem *sp_mask_show(Inkscape::Drawing &drawing, unsigned int key); + void sp_mask_hide(unsigned int key); + + void sp_mask_set_bbox(unsigned int key, Geom::OptRect const &bbox); + +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); -GType sp_mask_get_type (void); + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + + virtual void set(unsigned int key, const gchar* value); + + virtual void update(SPCtx* ctx, unsigned int flags); + virtual void modified(unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); +}; class SPMaskReference : public Inkscape::URIReference { public: @@ -95,11 +108,6 @@ protected: } }; -Inkscape::DrawingItem *sp_mask_show (SPMask *mask, Inkscape::Drawing &drawing, unsigned int key); -void sp_mask_hide (SPMask *mask, unsigned int key); - -void sp_mask_set_bbox (SPMask *mask, unsigned int key, Geom::OptRect const &bbox); - const gchar *sp_mask_create (GSList *reprs, SPDocument *document, Geom::Affine const* applyTransform); #endif // SEEN_SP_MASK_H diff --git a/src/sp-mesh-array.h b/src/sp-mesh-array.h index 5a852f003..b10974e7e 100644 --- a/src/sp-mesh-array.h +++ b/src/sp-mesh-array.h @@ -127,7 +127,7 @@ public: void setOpacity( guint i, gdouble o ); }; -struct SPMeshGradient; +class SPMeshGradient; // An array of mesh nodes. class SPMeshNodeArray { diff --git a/src/sp-mesh-gradient-fns.h b/src/sp-mesh-gradient-fns.h deleted file mode 100644 index 4196a6de2..000000000 --- a/src/sp-mesh-gradient-fns.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef SP_MESH_GRADIENT_FNS_H -#define SP_MESH_GRADIENT_FNS_H - -/** \file - * Macros and fn definitions related to mesh gradients. - */ - -#include <glib-object.h> -#include <glib.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -struct SPMeshGradient; - -#define SP_TYPE_MESHGRADIENT (sp_meshgradient_get_type()) -#define SP_MESHGRADIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_MESHGRADIENT, SPMeshGradient)) -#define SP_MESHGRADIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_MESHGRADIENT, SPMeshGradientClass)) -#define SP_IS_MESHGRADIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_MESHGRADIENT)) -#define SP_IS_MESHGRADIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_MESHGRADIENT)) - - -GType sp_meshgradient_get_type(); - -void sp_meshgradient_set_position(SPMeshGradient *mg, gdouble x, gdouble y ); - -#endif /* !SP_MESH_GRADIENT_FNS_H */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-mesh-gradient.cpp b/src/sp-mesh-gradient.cpp new file mode 100644 index 000000000..3fd277f52 --- /dev/null +++ b/src/sp-mesh-gradient.cpp @@ -0,0 +1,214 @@ +#include "sp-mesh-gradient.h" + +#include "attributes.h" +#include "xml/repr.h" +#include "display/cairo-utils.h" + +#include "sp-factory.h" + +namespace { + SPObject* createMeshGradient() { + return new SPMeshGradient(); + } + + bool meshGradientRegistered = SPFactory::instance().registerObject("svg:meshGradient", createMeshGradient); +} + + +/* + * Mesh Gradient + */ +//#define MESH_DEBUG +SPMeshGradient::SPMeshGradient() : SPGradient() { + // Start coordinate of mesh + this->x.unset(SVGLength::NONE, 0.0, 0.0); + this->y.unset(SVGLength::NONE, 0.0, 0.0); +} + +SPMeshGradient::~SPMeshGradient() { +} + +void SPMeshGradient::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPGradient::build(document, repr); + + // Start coordinate of mesh + this->readAttr( "x" ); + this->readAttr( "y" ); +} + + +void SPMeshGradient::set(unsigned key, gchar const *value) { + switch (key) { + case SP_ATTR_X: + if (!this->x.read(value)) { + this->x.unset(SVGLength::NONE, 0.0, 0.0); + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_Y: + if (!this->y.read(value)) { + this->y.unset(SVGLength::NONE, 0.0, 0.0); + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + default: + SPGradient::set(key, value); + break; + } +} + +/** + * Write mesh gradient attributes to associated repr. + */ +Inkscape::XML::Node* SPMeshGradient::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { +#ifdef MESH_DEBUG + std::cout << "sp_meshgradient_write() ***************************" << std::endl; +#endif + + if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { + repr = xml_doc->createElement("svg:meshGradient"); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->x._set) { + sp_repr_set_svg_double(repr, "x", this->x.computed); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->y._set) { + sp_repr_set_svg_double(repr, "y", this->y.computed); + } + + SPGradient::write(xml_doc, repr, flags); + + return repr; +} + +void +sp_meshgradient_repr_write(SPMeshGradient *mg) +{ + mg->array.write( mg ); +} + + +cairo_pattern_t* SPMeshGradient::pattern_new(cairo_t *ct, +#if defined(MESH_DEBUG) || (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 4)) + Geom::OptRect const &bbox, + double opacity +#else + Geom::OptRect const & /*bbox*/, + double /*opacity*/ +#endif + ) +{ + using Geom::X; + using Geom::Y; + +#ifdef MESH_DEBUG + std::cout << "sp_meshgradient_create_pattern: (" << bbox->x0 << "," << bbox->y0 << ") (" << bbox->x1 << "," << bbox->y1 << ") " << opacity << std::endl; +#endif + + this->ensureArray(); + + cairo_pattern_t *cp = NULL; + +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 4) + SPMeshNodeArray* array = &(this->array); + + cp = cairo_pattern_create_mesh(); + + for( unsigned int i = 0; i < array->patch_rows(); ++i ) { + for( unsigned int j = 0; j < array->patch_columns(); ++j ) { + + SPMeshPatchI patch( &(array->nodes), i, j ); + + cairo_mesh_pattern_begin_patch( cp ); + cairo_mesh_pattern_move_to( cp, patch.getPoint( 0, 0 )[X], patch.getPoint( 0, 0 )[Y] ); + + for( unsigned int k = 0; k < 4; ++k ) { +#ifdef DEBUG_MESH + std::cout << i << " " << j << " " + << patch.getPathType( k ) << " ("; + for( int p = 0; p < 4; ++p ) { + std::cout << patch.getPoint( k, p ); + } + std::cout << ") " + << patch.getColor( k ).toString() << std::endl; +#endif + + switch ( patch.getPathType( k ) ) { + case 'l': + case 'L': + case 'z': + case 'Z': + cairo_mesh_pattern_line_to( cp, + patch.getPoint( k, 3 )[X], + patch.getPoint( k, 3 )[Y] ); + break; + case 'c': + case 'C': + { + std::vector< Geom::Point > pts = patch.getPointsForSide( k ); + cairo_mesh_pattern_curve_to( cp, + pts[1][X], pts[1][Y], + pts[2][X], pts[2][Y], + pts[3][X], pts[3][Y] ); + break; + } + default: + // Shouldn't happen + std::cout << "sp_meshgradient_create_pattern: path error" << std::endl; + } + + if( patch.tensorIsSet(k) ) { + // Tensor point defined relative to corner. + Geom::Point t = patch.getTensorPoint(k); + cairo_mesh_pattern_set_control_point( cp, k, t[X], t[Y] ); + //std::cout << " sp_meshgradient_create_pattern: tensor " << k + // << " set to " << t << "." << std::endl; + } else { + // Geom::Point t = patch.coonsTensorPoint(k); + //std::cout << " sp_meshgradient_create_pattern: tensor " << k + // << " calculated as " << t << "." <<std::endl; + } + + cairo_mesh_pattern_set_corner_color_rgba( + cp, k, + patch.getColor( k ).v.c[0], + patch.getColor( k ).v.c[1], + patch.getColor( k ).v.c[2], + patch.getOpacity( k ) * opacity ); + } + + cairo_mesh_pattern_end_patch( cp ); + } + } + + // set pattern matrix + Geom::Affine gs2user = this->gradientTransform; + if (this->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) { + Geom::Affine bbox2user(bbox->width(), 0, 0, bbox->height(), bbox->left(), bbox->top()); + gs2user *= bbox2user; + } + ink_cairo_pattern_set_matrix(cp, gs2user.inverse()); + +#else + static bool shown = false; + if( !shown ) { + std::cout << "sp_meshgradient_create_pattern: needs cairo >= 1.11.4, using " + << cairo_version_string() << std::endl; + shown = true; + } +#endif + +/* + cairo_pattern_t *cp = cairo_pattern_create_radial( + rg->fx.computed, rg->fy.computed, 0, + rg->cx.computed, rg->cy.computed, rg->r.computed); + sp_gradient_pattern_common_setup(cp, gr, bbox, opacity); +*/ + + return cp; +} diff --git a/src/sp-mesh-gradient.h b/src/sp-mesh-gradient.h index 44d6c0e4c..0b570c4dd 100644 --- a/src/sp-mesh-gradient.h +++ b/src/sp-mesh-gradient.h @@ -7,19 +7,26 @@ #include "svg/svg-length.h" #include "sp-gradient.h" -#include "sp-mesh-gradient-fns.h" + +#define SP_MESHGRADIENT(obj) (dynamic_cast<SPMeshGradient*>((SPObject*)obj)) +#define SP_IS_MESHGRADIENT(obj) (dynamic_cast<const SPMeshGradient*>((SPObject*)obj) != NULL) /** Mesh gradient. */ -struct SPMeshGradient : public SPGradient { +class SPMeshGradient : public SPGradient { +public: + SPMeshGradient(); + virtual ~SPMeshGradient(); + SVGLength x; // Upper left corner of mesh SVGLength y; // Upper right corner of mesh -}; -/// The SPMeshGradient vtable. -struct SPMeshGradientClass { - SPGradientClass parent_class; -}; + virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity); +protected: + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void set(unsigned key, gchar const *value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); +}; #endif /* !SP_MESH_GRADIENT_H */ diff --git a/src/sp-mesh-patch-fns.h b/src/sp-mesh-patch-fns.h deleted file mode 100644 index 37fb5a70a..000000000 --- a/src/sp-mesh-patch-fns.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef SP_MESH_PATCH_FNS_H -#define SP_MESH_PATCH_FNS_H - -/** \file - * Macros and fn definitions related to mesh patchs. - */ - -#include <glib-object.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPMeshPatch; - -#define SP_TYPE_MESHPATCH (sp_meshpatch_get_type()) -#define SP_MESHPATCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_MESHPATCH, SPMeshPatch)) -#define SP_MESHPATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_MESHPATCH, SPMeshPatchClass)) -#define SP_IS_MESHPATCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_MESHPATCH)) -#define SP_IS_MESHPATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_MESHPATCH)) - - -GType sp_meshpatch_get_type(); - - -#endif /* !SP_MESH_PATCH_FNS_H */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-mesh-patch.cpp b/src/sp-mesh-patch.cpp index ff1a18a01..216de8270 100644 --- a/src/sp-mesh-patch.cpp +++ b/src/sp-mesh-patch.cpp @@ -17,6 +17,19 @@ #include "sp-mesh-patch.h" #include "style.h" +#include "attributes.h" +#include "xml/repr.h" + +#include "sp-factory.h" + +namespace { + SPObject* createMeshPatch() { + return new SPMeshPatch(); + } + + bool meshPatchRegistered = SPFactory::instance().registerObject("svg:meshPatch", createMeshPatch); +} + SPMeshPatch* SPMeshPatch::getNextMeshPatch() { SPMeshPatch *result = 0; @@ -51,6 +64,61 @@ SPMeshPatch* SPMeshPatch::getPrevMeshPatch() return result; } + +/* + * Mesh Patch + */ + +SPMeshPatch::SPMeshPatch() : SPObject() { + this->tensor_string = NULL; +} + +SPMeshPatch::~SPMeshPatch() { +} + +void SPMeshPatch::build(SPDocument* doc, Inkscape::XML::Node* repr) { + SPObject::build(doc, repr); + + this->readAttr( "tensor" ); +} + +/** + * Virtual build: set meshpatch attributes from its associated XML node. + */ + +void SPMeshPatch::set(unsigned int key, const gchar* value) { + switch (key) { + case SP_ATTR_TENSOR: { + if (value) { + this->tensor_string = new Glib::ustring( value ); + // std::cout << "sp_meshpatch_set: Tensor string: " << patch->tensor_string->c_str() << std::endl; + } + break; + } + default: { + // Do nothing + } + } +} + +/** + * Virtual set: set attribute to value. + */ + +Inkscape::XML::Node* SPMeshPatch::write(Inkscape::XML::Document* xml_doc, Inkscape::XML::Node* repr, guint flags) { + if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { + repr = xml_doc->createElement("svg:meshPatch"); + } + + SPObject::write(xml_doc, repr, flags); + + return repr; +} + +/** + * Virtual write: write object attributes to repr. + */ + /* Local Variables: mode:c++ diff --git a/src/sp-mesh-patch.h b/src/sp-mesh-patch.h index b56a0b95f..ddade6503 100644 --- a/src/sp-mesh-patch.h +++ b/src/sp-mesh-patch.h @@ -17,32 +17,25 @@ //#include "svg/svg-length.h" #include "sp-object.h" -class SPObjectClass; - -struct SPMeshPatch; -struct SPMeshPatchClass; - -#define SP_TYPE_MESHPATCH (sp_meshpatch_get_type()) -#define SP_MESHPATCH(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_MESHPATCH, SPMeshPatch)) -#define SP_MESHPATCH_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_MESHPATCH, SPMeshPatchClass)) -#define SP_IS_MESHPATCH(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_MESHPATCH)) -#define SP_IS_MESHPATCH_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_MESHPATCH)) - -GType sp_meshpatch_get_type(); +#define SP_MESHPATCH(obj) (dynamic_cast<SPMeshPatch*>((SPObject*)obj)) +#define SP_IS_MESHPATCH(obj) (dynamic_cast<const SPMeshPatch*>((SPObject*)obj) != NULL) /** Gradient MeshPatch. */ -struct SPMeshPatch : public SPObject { +class SPMeshPatch : public SPObject { +public: + SPMeshPatch(); + virtual ~SPMeshPatch(); SPMeshPatch* getNextMeshPatch(); SPMeshPatch* getPrevMeshPatch(); Glib::ustring * tensor_string; //SVGLength tx[4]; // Tensor points //SVGLength ty[4]; // Tensor points -}; -/// The SPMeshPatch vtable. -struct SPMeshPatchClass { - SPObjectClass parent_class; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void set(unsigned int key, const gchar* value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); }; #endif /* !SEEN_SP_MESHPATCH_H */ diff --git a/src/sp-mesh-row-fns.h b/src/sp-mesh-row-fns.h deleted file mode 100644 index 5d85fdfea..000000000 --- a/src/sp-mesh-row-fns.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef SP_MESH_ROW_FNS_H -#define SP_MESH_ROW_FNS_H - -/** \file - * Macros and fn definitions related to mesh rows. - */ - -#include <glib-object.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -class SPMeshRow; - -#define SP_TYPE_MESHROW (sp_meshrow_get_type()) -#define SP_MESHROW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_MESHROW, SPMeshRow)) -#define SP_MESHROW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_MESHROW, SPMeshRowClass)) -#define SP_IS_MESHROW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_MESHROW)) -#define SP_IS_MESHROW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_MESHROW)) - - -GType sp_meshrow_get_type(); - - -#endif /* !SP_MESH_ROW_FNS_H */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-mesh-row.cpp b/src/sp-mesh-row.cpp index bc0c59776..04619d6cc 100644 --- a/src/sp-mesh-row.cpp +++ b/src/sp-mesh-row.cpp @@ -17,6 +17,18 @@ #include "sp-mesh-row.h" #include "style.h" +#include "xml/repr.h" + +#include "sp-factory.h" + +namespace { + SPObject* createMeshRow() { + return new SPMeshRow(); + } + + bool meshRowRegistered = SPFactory::instance().registerObject("svg:meshRow", createMeshRow); +} + SPMeshRow* SPMeshRow::getNextMeshRow() { SPMeshRow *result = 0; @@ -51,6 +63,45 @@ SPMeshRow* SPMeshRow::getPrevMeshRow() return result; } + +/* + * Mesh Row + */ +SPMeshRow::SPMeshRow() : SPObject() { +} + +SPMeshRow::~SPMeshRow() { +} + +void SPMeshRow::build(SPDocument* doc, Inkscape::XML::Node* repr) { + SPObject::build(doc, repr); +} + +/** + * Virtual build: set meshrow attributes from its associated XML node. + */ + +void SPMeshRow::set(unsigned int key, const gchar* value) { +} + +/** + * Virtual set: set attribute to value. + */ + +Inkscape::XML::Node* SPMeshRow::write(Inkscape::XML::Document* xml_doc, Inkscape::XML::Node* repr, guint flags) { + if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { + repr = xml_doc->createElement("svg:meshRow"); + } + + SPObject::write(xml_doc, repr, flags); + + return repr; +} + +/** + * Virtual write: write object attributes to repr. + */ + /* Local Variables: mode:c++ diff --git a/src/sp-mesh-row.h b/src/sp-mesh-row.h index 53e311bef..e39bdc631 100644 --- a/src/sp-mesh-row.h +++ b/src/sp-mesh-row.h @@ -14,29 +14,22 @@ #include <glib.h> #include "sp-object.h" -class SPObjectClass; - -struct SPMeshRow; -struct SPMeshRowClass; - -#define SP_TYPE_MESHROW (sp_meshrow_get_type()) -#define SP_MESHROW(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_MESHROW, SPMeshRow)) -#define SP_MESHROW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_MESHROW, SPMeshRowClass)) -#define SP_IS_MESHROW(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_MESHROW)) -#define SP_IS_MESHROW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_MESHROW)) - -GType sp_meshrow_get_type(); +#define SP_MESHROW(obj) (dynamic_cast<SPMeshRow*>((SPObject*)obj)) +#define SP_IS_MESHROW(obj) (dynamic_cast<const SPMeshRow*>((SPObject*)obj) != NULL) /** Gradient MeshRow. */ -struct SPMeshRow : public SPObject { +class SPMeshRow : public SPObject { +public: + SPMeshRow(); + virtual ~SPMeshRow(); SPMeshRow* getNextMeshRow(); SPMeshRow* getPrevMeshRow(); -}; -/// The SPMeshRow vtable. -struct SPMeshRowClass { - SPObjectClass parent_class; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void set(unsigned int key, const gchar* value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); }; #endif /* !SEEN_SP_MESHROW_H */ diff --git a/src/sp-metadata.cpp b/src/sp-metadata.cpp index 79953b708..a093107ac 100644 --- a/src/sp-metadata.cpp +++ b/src/sp-metadata.cpp @@ -33,31 +33,20 @@ /* Metadata base class */ -static void sp_metadata_build (SPObject * object, SPDocument * document, Inkscape::XML::Node * repr); -static void sp_metadata_release (SPObject *object); -static void sp_metadata_set (SPObject *object, unsigned int key, const gchar *value); -static void sp_metadata_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_metadata_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); +#include "sp-factory.h" -G_DEFINE_TYPE(SPMetadata, sp_metadata, SP_TYPE_OBJECT); +namespace { + SPObject* createMetadata() { + return new SPMetadata(); + } -static void -sp_metadata_class_init (SPMetadataClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; + bool metadataRegistered = SPFactory::instance().registerObject("svg:metadata", createMetadata); +} - sp_object_class->build = sp_metadata_build; - sp_object_class->release = sp_metadata_release; - sp_object_class->write = sp_metadata_write; - sp_object_class->set = sp_metadata_set; - sp_object_class->update = sp_metadata_update; +SPMetadata::SPMetadata() : SPObject() { } -static void -sp_metadata_init (SPMetadata *metadata) -{ - (void)metadata; - debug("0x%08x",(unsigned int)metadata); +SPMetadata::~SPMetadata() { } namespace { @@ -74,68 +63,43 @@ void strip_ids_recursively(Inkscape::XML::Node *node) { } -/** - * Reads the Inkscape::XML::Node, and initializes SPMetadata variables. - * - * For this to get called, our name must be associated with - * a repr via "sp_object_type_register". Best done through - * sp-object-repr.cpp's repr_name_entries array. - */ -static void sp_metadata_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ + +void SPMetadata::build(SPDocument* doc, Inkscape::XML::Node* repr) { using Inkscape::XML::NodeSiblingIterator; - debug("0x%08x",(unsigned int)object); + debug("0x%08x",(unsigned int)this); /* clean up our mess from earlier versions; elements under rdf:RDF should not * have id= attributes... */ - static GQuark const rdf_root_name=g_quark_from_static_string("rdf:RDF"); + static GQuark const rdf_root_name = g_quark_from_static_string("rdf:RDF"); + for ( NodeSiblingIterator iter=repr->firstChild() ; iter ; ++iter ) { if ( (GQuark)iter->code() == rdf_root_name ) { strip_ids_recursively(iter); } } - if (((SPObjectClass *) sp_metadata_parent_class)->build) - ((SPObjectClass *) sp_metadata_parent_class)->build (object, document, repr); + SPObject::build(doc, repr); } -/** - * Drops any allocated memory. - */ -static void sp_metadata_release(SPObject *object) -{ - debug("0x%08x",(unsigned int)object); +void SPMetadata::release() { + debug("0x%08x",(unsigned int)this); // handle ourself - if (((SPObjectClass *) sp_metadata_parent_class)->release) - ((SPObjectClass *) sp_metadata_parent_class)->release (object); + SPObject::release(); } -/** - * Sets a specific value in the SPMetadata. - */ -static void -sp_metadata_set(SPObject *object, - unsigned int key, - const gchar *value) -{ - debug("0x%08x %s(%u): '%s'",(unsigned int)object, +void SPMetadata::set(unsigned int key, const gchar* value) { + debug("0x%08x %s(%u): '%s'",(unsigned int)this, sp_attribute_name(key),key,value); // see if any parents need this value - if (SP_OBJECT_CLASS(sp_metadata_parent_class)->set) { - SP_OBJECT_CLASS(sp_metadata_parent_class)->set(object, key, value); - } + SPObject::set(key, value); } -/** - * Receives update notifications. - */ -static void sp_metadata_update(SPObject *object, SPCtx *ctx, guint flags) -{ - debug("0x%08x",(unsigned int)object); +void SPMetadata::update(SPCtx* ctx, unsigned int flags) { + debug("0x%08x",(unsigned int)this); //SPMetadata *metadata = SP_METADATA(object); if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | @@ -145,29 +109,21 @@ static void sp_metadata_update(SPObject *object, SPCtx *ctx, guint flags) } - if (((SPObjectClass *) sp_metadata_parent_class)->update) - ((SPObjectClass *) sp_metadata_parent_class)->update(object, ctx, flags); +// SPObject::onUpdate(ctx, flags); } -/** - * Writes it's settings to an incoming repr object, if any. - */ -static Inkscape::XML::Node *sp_metadata_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ - debug("0x%08x",(unsigned int)object); - //SPMetadata *metadata = SP_METADATA(object); +Inkscape::XML::Node* SPMetadata::write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) { + debug("0x%08x",(unsigned int)this); - if ( repr != object->getRepr() ) { + if ( repr != this->getRepr() ) { if (repr) { - repr->mergeFrom(object->getRepr(), "id"); + repr->mergeFrom(this->getRepr(), "id"); } else { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); } } - if (((SPObjectClass *) sp_metadata_parent_class)->write) { - ((SPObjectClass *) sp_metadata_parent_class)->write(object, doc, repr, flags); - } + SPObject::write(doc, repr, flags); return repr; } diff --git a/src/sp-metadata.h b/src/sp-metadata.h index 454fd8d18..2a9d58e11 100644 --- a/src/sp-metadata.h +++ b/src/sp-metadata.h @@ -17,18 +17,22 @@ /* Metadata base class */ -#define SP_TYPE_METADATA (sp_metadata_get_type ()) -#define SP_METADATA(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_METADATA, SPMetadata)) -#define SP_IS_METADATA(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_METADATA)) +#define SP_METADATA(obj) (dynamic_cast<SPMetadata*>((SPObject*)obj)) +#define SP_IS_METADATA(obj) (dynamic_cast<const SPMetadata*>((SPObject*)obj) != NULL) -struct SPMetadata : public SPObject { -}; +class SPMetadata : public SPObject { +public: + SPMetadata(); + virtual ~SPMetadata(); -struct SPMetadataClass { - SPObjectClass parent_class; -}; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); -GType sp_metadata_get_type (void); + virtual void set(unsigned int key, const gchar* value); + virtual void update(SPCtx* ctx, unsigned int flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); +}; SPMetadata * sp_document_metadata (SPDocument *document); diff --git a/src/sp-missing-glyph.cpp b/src/sp-missing-glyph.cpp index 911c9be92..06b741165 100644 --- a/src/sp-missing-glyph.cpp +++ b/src/sp-missing-glyph.cpp @@ -19,110 +19,93 @@ #include "sp-missing-glyph.h" #include "document.h" -static void sp_missing_glyph_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_missing_glyph_release(SPObject *object); -static void sp_missing_glyph_set(SPObject *object, unsigned int key, const gchar *value); -static Inkscape::XML::Node *sp_missing_glyph_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); +#include "sp-factory.h" -G_DEFINE_TYPE(SPMissingGlyph, sp_missing_glyph, SP_TYPE_OBJECT); +namespace { + SPObject* createMissingGlyph() { + return new SPMissingGlyph(); + } -static void sp_missing_glyph_class_init(SPMissingGlyphClass *gc) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) gc; - - sp_object_class->build = sp_missing_glyph_build; - sp_object_class->release = sp_missing_glyph_release; - sp_object_class->set = sp_missing_glyph_set; - sp_object_class->write = sp_missing_glyph_write; + bool missingGlyphRegistered = SPFactory::instance().registerObject("svg:missing-glyph", createMissingGlyph); } -static void sp_missing_glyph_init(SPMissingGlyph *glyph) -{ +SPMissingGlyph::SPMissingGlyph() : SPObject() { //TODO: correct these values: - glyph->d = NULL; - glyph->horiz_adv_x = 0; - glyph->vert_origin_x = 0; - glyph->vert_origin_y = 0; - glyph->vert_adv_y = 0; + this->d = NULL; + this->horiz_adv_x = 0; + this->vert_origin_x = 0; + this->vert_origin_y = 0; + this->vert_adv_y = 0; } -static void sp_missing_glyph_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) (sp_missing_glyph_parent_class))->build) { - ((SPObjectClass *) (sp_missing_glyph_parent_class))->build(object, document, repr); - } - - object->readAttr( "d" ); - object->readAttr( "horiz-adv-x" ); - object->readAttr( "vert-origin-x" ); - object->readAttr( "vert-origin-y" ); - object->readAttr( "vert-adv-y" ); +SPMissingGlyph::~SPMissingGlyph() { } -static void sp_missing_glyph_release(SPObject *object) -{ - //SPMissingGlyph *glyph = SP_MISSING_GLYPH(object); +void SPMissingGlyph::build(SPDocument* doc, Inkscape::XML::Node* repr) { + SPObject::build(doc, repr); - if (((SPObjectClass *) sp_missing_glyph_parent_class)->release) { - ((SPObjectClass *) sp_missing_glyph_parent_class)->release(object); - } + this->readAttr( "d" ); + this->readAttr( "horiz-adv-x" ); + this->readAttr( "vert-origin-x" ); + this->readAttr( "vert-origin-y" ); + this->readAttr( "vert-adv-y" ); +} + +void SPMissingGlyph::release() { + SPObject::release(); } -static void sp_missing_glyph_set(SPObject *object, unsigned int key, const gchar *value) -{ - SPMissingGlyph *glyph = SP_MISSING_GLYPH(object); +void SPMissingGlyph::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_D: { - if (glyph->d) { - g_free(glyph->d); + if (this->d) { + g_free(this->d); } - glyph->d = g_strdup(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->d = g_strdup(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } case SP_ATTR_HORIZ_ADV_X: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != glyph->horiz_adv_x){ - glyph->horiz_adv_x = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (number != this->horiz_adv_x){ + this->horiz_adv_x = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_VERT_ORIGIN_X: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != glyph->vert_origin_x){ - glyph->vert_origin_x = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (number != this->vert_origin_x){ + this->vert_origin_x = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_VERT_ORIGIN_Y: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != glyph->vert_origin_y){ - glyph->vert_origin_y = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (number != this->vert_origin_y){ + this->vert_origin_y = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } case SP_ATTR_VERT_ADV_Y: { double number = value ? g_ascii_strtod(value, 0) : 0; - if (number != glyph->vert_adv_y){ - glyph->vert_adv_y = number; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (number != this->vert_adv_y){ + this->vert_adv_y = number; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; } default: { - if (((SPObjectClass *) (sp_missing_glyph_parent_class))->set) { - ((SPObjectClass *) (sp_missing_glyph_parent_class))->set(object, key, value); - } + SPObject::set(key, value); break; } } @@ -130,38 +113,35 @@ static void sp_missing_glyph_set(SPObject *object, unsigned int key, const gchar #define COPY_ATTR(rd,rs,key) (rd)->setAttribute((key), rs->attribute(key)); -static Inkscape::XML::Node *sp_missing_glyph_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ -// SPMissingGlyph *glyph = SP_MISSING_GLYPH(object); - - if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = xml_doc->createElement("svg:glyph"); - } - -/* I am commenting out this part because I am not certain how does it work. I will have to study it later. Juca - repr->setAttribute("d", glyph->d); - sp_repr_set_svg_double(repr, "horiz-adv-x", glyph->horiz_adv_x); - sp_repr_set_svg_double(repr, "vert-origin-x", glyph->vert_origin_x); - sp_repr_set_svg_double(repr, "vert-origin-y", glyph->vert_origin_y); - sp_repr_set_svg_double(repr, "vert-adv-y", glyph->vert_adv_y); -*/ - if (repr != object->getRepr()) { - - // All the COPY_ATTR functions below use - // XML Tree directly while they shouldn't. - COPY_ATTR(repr, object->getRepr(), "d"); - COPY_ATTR(repr, object->getRepr(), "horiz-adv-x"); - COPY_ATTR(repr, object->getRepr(), "vert-origin-x"); - COPY_ATTR(repr, object->getRepr(), "vert-origin-y"); - COPY_ATTR(repr, object->getRepr(), "vert-adv-y"); - } - - if (((SPObjectClass *) (sp_missing_glyph_parent_class))->write) { - ((SPObjectClass *) (sp_missing_glyph_parent_class))->write(object, xml_doc, repr, flags); - } - - return repr; +Inkscape::XML::Node* SPMissingGlyph::write(Inkscape::XML::Document* xml_doc, Inkscape::XML::Node* repr, guint flags) { + if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { + repr = xml_doc->createElement("svg:glyph"); + } + + /* I am commenting out this part because I am not certain how does it work. I will have to study it later. Juca + repr->setAttribute("d", glyph->d); + sp_repr_set_svg_double(repr, "horiz-adv-x", glyph->horiz_adv_x); + sp_repr_set_svg_double(repr, "vert-origin-x", glyph->vert_origin_x); + sp_repr_set_svg_double(repr, "vert-origin-y", glyph->vert_origin_y); + sp_repr_set_svg_double(repr, "vert-adv-y", glyph->vert_adv_y); + */ + if (repr != this->getRepr()) { + + // TODO + // All the COPY_ATTR functions below use + // XML Tree directly while they shouldn't. + COPY_ATTR(repr, this->getRepr(), "d"); + COPY_ATTR(repr, this->getRepr(), "horiz-adv-x"); + COPY_ATTR(repr, this->getRepr(), "vert-origin-x"); + COPY_ATTR(repr, this->getRepr(), "vert-origin-y"); + COPY_ATTR(repr, this->getRepr(), "vert-adv-y"); + } + + SPObject::write(xml_doc, repr, flags); + + return repr; } + /* Local Variables: mode:c++ diff --git a/src/sp-missing-glyph.h b/src/sp-missing-glyph.h index 7930df513..a72ed0e99 100644 --- a/src/sp-missing-glyph.h +++ b/src/sp-missing-glyph.h @@ -18,24 +18,27 @@ #include "sp-object.h" -#define SP_TYPE_MISSING_GLYPH (sp_missing_glyph_get_type ()) -#define SP_MISSING_GLYPH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_MISSING_GLYPH, SPMissingGlyph)) -#define SP_MISSING_GLYPH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_MISSING_GLYPH, SPMissingGlyphClass)) -#define SP_IS_MISSING_GLYPH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_MISSING_GLYPH)) -#define SP_IS_MISSING_GLYPH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_MISSING_GLYPH)) - -struct SPMissingGlyph : public SPObject { - char* d; +#define SP_MISSING_GLYPH(obj) (dynamic_cast<SPMissingGlyph*>((SPObject*)obj)) +#define SP_IS_MISSING_GLYPH(obj) (dynamic_cast<const SPMissingGlyph*>((SPObject*)obj) != NULL) + +class SPMissingGlyph : public SPObject { +public: + SPMissingGlyph(); + virtual ~SPMissingGlyph(); + + char* d; + +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + virtual void set(unsigned int key, const gchar* value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + +private: double horiz_adv_x; double vert_origin_x; double vert_origin_y; double vert_adv_y; }; -struct SPMissingGlyphClass { - SPObjectClass parent_class; -}; - -GType sp_missing_glyph_get_type (void); - #endif //#ifndef __SP_MISSING_GLYPH_H__ diff --git a/src/sp-namedview.cpp b/src/sp-namedview.cpp index 48f8eba2a..4464a0be2 100644 --- a/src/sp-namedview.cpp +++ b/src/sp-namedview.cpp @@ -50,50 +50,57 @@ using Inkscape::Util::unit_table; #define DEFAULTBORDERCOLOR 0x000000ff #define DEFAULTPAGECOLOR 0xffffff00 -static void sp_namedview_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_namedview_release(SPObject *object); -static void sp_namedview_set(SPObject *object, unsigned int key, const gchar *value); -static void sp_namedview_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref); -static void sp_namedview_remove_child(SPObject *object, Inkscape::XML::Node *child); -static Inkscape::XML::Node *sp_namedview_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - static void sp_namedview_setup_guides(SPNamedView * nv); static void sp_namedview_show_single_guide(SPGuide* guide, bool show); static gboolean sp_str_to_bool(const gchar *str); static gboolean sp_nv_read_opacity(const gchar *str, guint32 *color); -G_DEFINE_TYPE(SPNamedView, sp_namedview, SP_TYPE_OBJECTGROUP); - -static void sp_namedview_class_init(SPNamedViewClass * klass) -{ - SPObjectClass *sp_object_class = SP_OBJECT_CLASS(klass); - - sp_object_class->build = sp_namedview_build; - sp_object_class->release = sp_namedview_release; - sp_object_class->set = sp_namedview_set; - sp_object_class->child_added = sp_namedview_child_added; - sp_object_class->remove_child = sp_namedview_remove_child; - sp_object_class->write = sp_namedview_write; -} - -static void sp_namedview_init(SPNamedView *nv) -{ - nv->editable = TRUE; - nv->showguides = TRUE; - nv->grids_visible = false; - nv->showborder = TRUE; - nv->showpageshadow = TRUE; +#include "sp-factory.h" - nv->guides = NULL; - nv->viewcount = 0; - nv->grids = NULL; +namespace { + SPObject* createNamedView() { + return new SPNamedView(); + } - nv->default_layer_id = 0; + bool namedViewRegistered = SPFactory::instance().registerObject("sodipodi:namedview", createNamedView); +} - nv->connector_spacing = defaultConnSpacing; +SPNamedView::SPNamedView() : SPObjectGroup(), snap_manager(this) { + this->zoom = 0; + this->guidecolor = 0; + this->guidehicolor = 0; + this->views = NULL; + this->borderlayer = 0; + this->units = NULL; + this->window_x = 0; + this->cy = 0; + this->window_y = 0; + this->doc_units = NULL; + this->pagecolor = 0; + this->cx = 0; + this->pageshadow = 0; + this->window_width = 0; + this->window_height = 0; + this->window_maximized = 0; + this->bordercolor = 0; + + this->editable = TRUE; + this->showguides = TRUE; + this->grids_visible = false; + this->showborder = TRUE; + this->showpageshadow = TRUE; + + this->guides = NULL; + this->viewcount = 0; + this->grids = NULL; + + this->default_layer_id = 0; + + this->connector_spacing = defaultConnSpacing; +} - new (&nv->snap_manager) SnapManager(nv); +SPNamedView::~SPNamedView() { } static void sp_namedview_generate_old_grid(SPNamedView * /*nv*/, SPDocument *document, Inkscape::XML::Node *repr) { @@ -184,353 +191,353 @@ static void sp_namedview_generate_old_grid(SPNamedView * /*nv*/, SPDocument *doc } } -static void sp_namedview_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - SPNamedView *nv = (SPNamedView *) object; - SPObjectGroup *og = (SPObjectGroup *) object; - - if (((SPObjectClass *) (sp_namedview_parent_class))->build) { - (* ((SPObjectClass *) (sp_namedview_parent_class))->build)(object, document, repr); - } - - object->readAttr( "inkscape:document-units" ); - object->readAttr( "units" ); - object->readAttr( "viewonly" ); - object->readAttr( "showguides" ); - object->readAttr( "showgrid" ); - object->readAttr( "gridtolerance" ); - object->readAttr( "guidetolerance" ); - object->readAttr( "objecttolerance" ); - object->readAttr( "guidecolor" ); - object->readAttr( "guideopacity" ); - object->readAttr( "guidehicolor" ); - object->readAttr( "guidehiopacity" ); - object->readAttr( "showborder" ); - object->readAttr( "inkscape:showpageshadow" ); - object->readAttr( "borderlayer" ); - object->readAttr( "bordercolor" ); - object->readAttr( "borderopacity" ); - object->readAttr( "pagecolor" ); - object->readAttr( "inkscape:pageopacity" ); - object->readAttr( "inkscape:pageshadow" ); - object->readAttr( "inkscape:zoom" ); - object->readAttr( "inkscape:cx" ); - object->readAttr( "inkscape:cy" ); - object->readAttr( "inkscape:window-width" ); - object->readAttr( "inkscape:window-height" ); - object->readAttr( "inkscape:window-x" ); - object->readAttr( "inkscape:window-y" ); - object->readAttr( "inkscape:window-maximized" ); - object->readAttr( "inkscape:snap-global" ); - object->readAttr( "inkscape:snap-bbox" ); - object->readAttr( "inkscape:snap-nodes" ); - object->readAttr( "inkscape:snap-others" ); - object->readAttr( "inkscape:snap-from-guide" ); - object->readAttr( "inkscape:snap-center" ); - object->readAttr( "inkscape:snap-smooth-nodes" ); - object->readAttr( "inkscape:snap-midpoints" ); - object->readAttr( "inkscape:snap-object-midpoints" ); - object->readAttr( "inkscape:snap-text-baseline" ); - object->readAttr( "inkscape:snap-bbox-edge-midpoints" ); - object->readAttr( "inkscape:snap-bbox-midpoints" ); - object->readAttr( "inkscape:snap-to-guides" ); - object->readAttr( "inkscape:snap-grids" ); - object->readAttr( "inkscape:snap-intersection-paths" ); - object->readAttr( "inkscape:object-paths" ); - object->readAttr( "inkscape:snap-perpendicular" ); - object->readAttr( "inkscape:snap-tangential" ); - object->readAttr( "inkscape:snap-path-clip" ); - object->readAttr( "inkscape:snap-path-mask" ); - object->readAttr( "inkscape:object-nodes" ); - object->readAttr( "inkscape:bbox-paths" ); - object->readAttr( "inkscape:bbox-nodes" ); - object->readAttr( "inkscape:snap-page" ); - object->readAttr( "inkscape:current-layer" ); - object->readAttr( "inkscape:connector-spacing" ); +void SPNamedView::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPObjectGroup::build(document, repr); + + this->readAttr( "inkscape:document-units" ); + this->readAttr( "units" ); + this->readAttr( "viewonly" ); + this->readAttr( "showguides" ); + this->readAttr( "showgrid" ); + this->readAttr( "gridtolerance" ); + this->readAttr( "guidetolerance" ); + this->readAttr( "objecttolerance" ); + this->readAttr( "guidecolor" ); + this->readAttr( "guideopacity" ); + this->readAttr( "guidehicolor" ); + this->readAttr( "guidehiopacity" ); + this->readAttr( "showborder" ); + this->readAttr( "inkscape:showpageshadow" ); + this->readAttr( "borderlayer" ); + this->readAttr( "bordercolor" ); + this->readAttr( "borderopacity" ); + this->readAttr( "pagecolor" ); + this->readAttr( "inkscape:pageopacity" ); + this->readAttr( "inkscape:pageshadow" ); + this->readAttr( "inkscape:zoom" ); + this->readAttr( "inkscape:cx" ); + this->readAttr( "inkscape:cy" ); + this->readAttr( "inkscape:window-width" ); + this->readAttr( "inkscape:window-height" ); + this->readAttr( "inkscape:window-x" ); + this->readAttr( "inkscape:window-y" ); + this->readAttr( "inkscape:window-maximized" ); + this->readAttr( "inkscape:snap-global" ); + this->readAttr( "inkscape:snap-bbox" ); + this->readAttr( "inkscape:snap-nodes" ); + this->readAttr( "inkscape:snap-others" ); + this->readAttr( "inkscape:snap-from-guide" ); + this->readAttr( "inkscape:snap-center" ); + this->readAttr( "inkscape:snap-smooth-nodes" ); + this->readAttr( "inkscape:snap-midpoints" ); + this->readAttr( "inkscape:snap-object-midpoints" ); + this->readAttr( "inkscape:snap-text-baseline" ); + this->readAttr( "inkscape:snap-bbox-edge-midpoints" ); + this->readAttr( "inkscape:snap-bbox-midpoints" ); + this->readAttr( "inkscape:snap-to-guides" ); + this->readAttr( "inkscape:snap-grids" ); + this->readAttr( "inkscape:snap-intersection-paths" ); + this->readAttr( "inkscape:object-paths" ); + this->readAttr( "inkscape:snap-perpendicular" ); + this->readAttr( "inkscape:snap-tangential" ); + this->readAttr( "inkscape:snap-path-clip" ); + this->readAttr( "inkscape:snap-path-mask" ); + this->readAttr( "inkscape:object-nodes" ); + this->readAttr( "inkscape:bbox-paths" ); + this->readAttr( "inkscape:bbox-nodes" ); + this->readAttr( "inkscape:snap-page" ); + this->readAttr( "inkscape:current-layer" ); + this->readAttr( "inkscape:connector-spacing" ); /* Construct guideline list */ - for (SPObject *o = og->firstChild() ; o; o = o->getNext() ) { + for (SPObject *o = this->firstChild() ; o; o = o->getNext() ) { if (SP_IS_GUIDE(o)) { SPGuide * g = SP_GUIDE(o); - nv->guides = g_slist_prepend(nv->guides, g); - g_object_set(G_OBJECT(g), "color", nv->guidecolor, "hicolor", nv->guidehicolor, NULL); + this->guides = g_slist_prepend(this->guides, g); + //g_object_set(G_OBJECT(g), "color", nv->guidecolor, "hicolor", nv->guidehicolor, NULL); + g->setColor(this->guidecolor); + g->setHiColor(this->guidehicolor); } } // backwards compatibility with grid settings (pre 0.46) - sp_namedview_generate_old_grid(nv, document, repr); + sp_namedview_generate_old_grid(this, document, repr); } -static void sp_namedview_release(SPObject *object) -{ - SPNamedView *namedview = (SPNamedView *) object; - - if (namedview->guides) { - g_slist_free(namedview->guides); - namedview->guides = NULL; +void SPNamedView::release() { + if (this->guides) { + g_slist_free(this->guides); + this->guides = NULL; } // delete grids: - while ( namedview->grids ) { - Inkscape::CanvasGrid *gr = (Inkscape::CanvasGrid *)namedview->grids->data; // get first entry + while ( this->grids ) { + Inkscape::CanvasGrid *gr = (Inkscape::CanvasGrid *)this->grids->data; // get first entry delete gr; - namedview->grids = g_slist_remove_link(namedview->grids, namedview->grids); // deletes first entry + this->grids = g_slist_remove_link(this->grids, this->grids); // deletes first entry } - if (((SPObjectClass *) sp_namedview_parent_class)->release) { - ((SPObjectClass *) sp_namedview_parent_class)->release(object); - } - - namedview->snap_manager.~SnapManager(); + SPObjectGroup::release(); } -static void sp_namedview_set(SPObject *object, unsigned int key, const gchar *value) -{ - SPNamedView *nv = SP_NAMEDVIEW(object); - +void SPNamedView::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_VIEWONLY: - nv->editable = (!value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->editable = (!value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SHOWGUIDES: if (!value) { // show guides if not specified, for backwards compatibility - nv->showguides = TRUE; + this->showguides = TRUE; } else { - nv->showguides = sp_str_to_bool(value); + this->showguides = sp_str_to_bool(value); } - sp_namedview_setup_guides(nv); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + sp_namedview_setup_guides(this); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SHOWGRIDS: if (!value) { // don't show grids if not specified, for backwards compatibility - nv->grids_visible = false; + this->grids_visible = false; } else { - nv->grids_visible = sp_str_to_bool(value); + this->grids_visible = sp_str_to_bool(value); } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_GRIDTOLERANCE: - nv->snap_manager.snapprefs.setGridTolerance(value ? g_ascii_strtod(value, NULL) : 10000); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setGridTolerance(value ? g_ascii_strtod(value, NULL) : 10000); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_GUIDETOLERANCE: - nv->snap_manager.snapprefs.setGuideTolerance(value ? g_ascii_strtod(value, NULL) : 20); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setGuideTolerance(value ? g_ascii_strtod(value, NULL) : 20); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_OBJECTTOLERANCE: - nv->snap_manager.snapprefs.setObjectTolerance(value ? g_ascii_strtod(value, NULL) : 20); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setObjectTolerance(value ? g_ascii_strtod(value, NULL) : 20); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_GUIDECOLOR: - nv->guidecolor = (nv->guidecolor & 0xff) | (DEFAULTGUIDECOLOR & 0xffffff00); + this->guidecolor = (this->guidecolor & 0xff) | (DEFAULTGUIDECOLOR & 0xffffff00); + if (value) { - nv->guidecolor = (nv->guidecolor & 0xff) | sp_svg_read_color(value, nv->guidecolor); + this->guidecolor = (this->guidecolor & 0xff) | sp_svg_read_color(value, this->guidecolor); } - for (GSList *l = nv->guides; l != NULL; l = l->next) { - g_object_set(G_OBJECT(l->data), "color", nv->guidecolor, NULL); + + for (GSList *l = this->guides; l != NULL; l = l->next) { + //g_object_set(G_OBJECT(l->data), "color", nv->guidecolor, NULL); + SP_GUIDE(l->data)->setColor(this->guidecolor); } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_GUIDEOPACITY: - nv->guidecolor = (nv->guidecolor & 0xffffff00) | (DEFAULTGUIDECOLOR & 0xff); - sp_nv_read_opacity(value, &nv->guidecolor); - for (GSList *l = nv->guides; l != NULL; l = l->next) { - g_object_set(G_OBJECT(l->data), "color", nv->guidecolor, NULL); + this->guidecolor = (this->guidecolor & 0xffffff00) | (DEFAULTGUIDECOLOR & 0xff); + sp_nv_read_opacity(value, &this->guidecolor); + + for (GSList *l = this->guides; l != NULL; l = l->next) { + //g_object_set(G_OBJECT(l->data), "color", nv->guidecolor, NULL); + SP_GUIDE(l->data)->setColor(this->guidecolor); } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_GUIDEHICOLOR: - nv->guidehicolor = (nv->guidehicolor & 0xff) | (DEFAULTGUIDEHICOLOR & 0xffffff00); + this->guidehicolor = (this->guidehicolor & 0xff) | (DEFAULTGUIDEHICOLOR & 0xffffff00); + if (value) { - nv->guidehicolor = (nv->guidehicolor & 0xff) | sp_svg_read_color(value, nv->guidehicolor); + this->guidehicolor = (this->guidehicolor & 0xff) | sp_svg_read_color(value, this->guidehicolor); } - for (GSList *l = nv->guides; l != NULL; l = l->next) { - g_object_set(G_OBJECT(l->data), "hicolor", nv->guidehicolor, NULL); + + for (GSList *l = this->guides; l != NULL; l = l->next) { + //g_object_set(G_OBJECT(l->data), "hicolor", nv->guidehicolor, NULL); + SP_GUIDE(l->data)->setHiColor(this->guidehicolor); } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_GUIDEHIOPACITY: - nv->guidehicolor = (nv->guidehicolor & 0xffffff00) | (DEFAULTGUIDEHICOLOR & 0xff); - sp_nv_read_opacity(value, &nv->guidehicolor); - for (GSList *l = nv->guides; l != NULL; l = l->next) { - g_object_set(G_OBJECT(l->data), "hicolor", nv->guidehicolor, NULL); + this->guidehicolor = (this->guidehicolor & 0xffffff00) | (DEFAULTGUIDEHICOLOR & 0xff); + sp_nv_read_opacity(value, &this->guidehicolor); + + for (GSList *l = this->guides; l != NULL; l = l->next) { + //g_object_set(G_OBJECT(l->data), "hicolor", nv->guidehicolor, NULL); + SP_GUIDE(l->data)->setHiColor(this->guidehicolor); } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SHOWBORDER: - nv->showborder = (value) ? sp_str_to_bool (value) : TRUE; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->showborder = (value) ? sp_str_to_bool (value) : TRUE; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_BORDERLAYER: - nv->borderlayer = SP_BORDER_LAYER_BOTTOM; - if (value && !strcasecmp(value, "true")) nv->borderlayer = SP_BORDER_LAYER_TOP; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->borderlayer = SP_BORDER_LAYER_BOTTOM; + if (value && !strcasecmp(value, "true")) this->borderlayer = SP_BORDER_LAYER_TOP; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_BORDERCOLOR: - nv->bordercolor = (nv->bordercolor & 0xff) | (DEFAULTBORDERCOLOR & 0xffffff00); + this->bordercolor = (this->bordercolor & 0xff) | (DEFAULTBORDERCOLOR & 0xffffff00); if (value) { - nv->bordercolor = (nv->bordercolor & 0xff) | sp_svg_read_color (value, nv->bordercolor); + this->bordercolor = (this->bordercolor & 0xff) | sp_svg_read_color (value, this->bordercolor); } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_BORDEROPACITY: - nv->bordercolor = (nv->bordercolor & 0xffffff00) | (DEFAULTBORDERCOLOR & 0xff); - sp_nv_read_opacity(value, &nv->bordercolor); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->bordercolor = (this->bordercolor & 0xffffff00) | (DEFAULTBORDERCOLOR & 0xff); + sp_nv_read_opacity(value, &this->bordercolor); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_PAGECOLOR: - nv->pagecolor = (nv->pagecolor & 0xff) | (DEFAULTPAGECOLOR & 0xffffff00); + this->pagecolor = (this->pagecolor & 0xff) | (DEFAULTPAGECOLOR & 0xffffff00); if (value) { - nv->pagecolor = (nv->pagecolor & 0xff) | sp_svg_read_color(value, nv->pagecolor); + this->pagecolor = (this->pagecolor & 0xff) | sp_svg_read_color(value, this->pagecolor); } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_PAGEOPACITY: - nv->pagecolor = (nv->pagecolor & 0xffffff00) | (DEFAULTPAGECOLOR & 0xff); - sp_nv_read_opacity(value, &nv->pagecolor); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->pagecolor = (this->pagecolor & 0xffffff00) | (DEFAULTPAGECOLOR & 0xff); + sp_nv_read_opacity(value, &this->pagecolor); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_PAGESHADOW: - nv->pageshadow = value? atoi(value) : 2; // 2 is the default - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->pageshadow = value? atoi(value) : 2; // 2 is the default + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SHOWPAGESHADOW: - nv->showpageshadow = (value) ? sp_str_to_bool(value) : TRUE; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->showpageshadow = (value) ? sp_str_to_bool(value) : TRUE; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_ZOOM: - nv->zoom = value ? g_ascii_strtod(value, NULL) : 0; // zero means not set - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->zoom = value ? g_ascii_strtod(value, NULL) : 0; // zero means not set + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_CX: - nv->cx = value ? g_ascii_strtod(value, NULL) : HUGE_VAL; // HUGE_VAL means not set - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->cx = value ? g_ascii_strtod(value, NULL) : HUGE_VAL; // HUGE_VAL means not set + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_CY: - nv->cy = value ? g_ascii_strtod(value, NULL) : HUGE_VAL; // HUGE_VAL means not set - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->cy = value ? g_ascii_strtod(value, NULL) : HUGE_VAL; // HUGE_VAL means not set + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_WINDOW_WIDTH: - nv->window_width = value? atoi(value) : -1; // -1 means not set - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->window_width = value? atoi(value) : -1; // -1 means not set + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_WINDOW_HEIGHT: - nv->window_height = value ? atoi(value) : -1; // -1 means not set - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->window_height = value ? atoi(value) : -1; // -1 means not set + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_WINDOW_X: - nv->window_x = value ? atoi(value) : 0; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->window_x = value ? atoi(value) : 0; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_WINDOW_Y: - nv->window_y = value ? atoi(value) : 0; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->window_y = value ? atoi(value) : 0; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_WINDOW_MAXIMIZED: - nv->window_maximized = value ? atoi(value) : 0; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->window_maximized = value ? atoi(value) : 0; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_GLOBAL: - nv->snap_manager.snapprefs.setSnapEnabledGlobally(value ? sp_str_to_bool(value) : TRUE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setSnapEnabledGlobally(value ? sp_str_to_bool(value) : TRUE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_BBOX: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_BBOX_CATEGORY, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_BBOX_CATEGORY, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_NODE: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_NODE_CATEGORY, value ? sp_str_to_bool(value) : TRUE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_NODE_CATEGORY, value ? sp_str_to_bool(value) : TRUE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_OTHERS: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_OTHERS_CATEGORY, value ? sp_str_to_bool(value) : TRUE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_OTHERS_CATEGORY, value ? sp_str_to_bool(value) : TRUE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_ROTATION_CENTER: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_GRID: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_GRID, value ? sp_str_to_bool(value) : TRUE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_GRID, value ? sp_str_to_bool(value) : TRUE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_GUIDE: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_GUIDE, value ? sp_str_to_bool(value) : TRUE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_GUIDE, value ? sp_str_to_bool(value) : TRUE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_NODE_SMOOTH: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_NODE_SMOOTH, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_NODE_SMOOTH, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_LINE_MIDPOINT: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_LINE_MIDPOINT, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_LINE_MIDPOINT, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_OBJECT_MIDPOINT: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_OBJECT_MIDPOINT, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_OBJECT_MIDPOINT, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_TEXT_BASELINE: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_TEXT_BASELINE, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_TEXT_BASELINE, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_BBOX_EDGE_MIDPOINT: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_BBOX_EDGE_MIDPOINT, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_BBOX_EDGE_MIDPOINT, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_BBOX_MIDPOINT: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_BBOX_MIDPOINT, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_BBOX_MIDPOINT, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_PATH_INTERSECTION: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_PATH_INTERSECTION, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_PATH_INTERSECTION, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_PATH: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_PATH, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_PATH, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_PERP: - nv->snap_manager.snapprefs.setSnapPerp(value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setSnapPerp(value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_TANG: - nv->snap_manager.snapprefs.setSnapTang(value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setSnapTang(value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_PATH_CLIP: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_PATH_CLIP, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_PATH_CLIP, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_PATH_MASK: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_PATH_MASK, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_PATH_MASK, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_NODE_CUSP: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_NODE_CUSP, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_NODE_CUSP, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_BBOX_EDGE: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_BBOX_EDGE, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_BBOX_EDGE, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_BBOX_CORNER: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_BBOX_CORNER, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_BBOX_CORNER, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_PAGE_BORDER: - nv->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_PAGE_BORDER, value ? sp_str_to_bool(value) : FALSE); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_PAGE_BORDER, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_CURRENT_LAYER: - nv->default_layer_id = value ? g_quark_from_string(value) : 0; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->default_layer_id = value ? g_quark_from_string(value) : 0; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_CONNECTOR_SPACING: - nv->connector_spacing = value ? g_ascii_strtod(value, NULL) : + this->connector_spacing = value ? g_ascii_strtod(value, NULL) : defaultConnSpacing; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_DOCUMENT_UNITS: { /* The default unit if the document doesn't override this: e.g. for files saved as @@ -570,8 +577,8 @@ static void sp_namedview_set(SPObject *object, unsigned int key, const gchar *va /* fixme: Don't use g_log (see above). */ } } - nv->doc_units = new_unit; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->doc_units = new_unit; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } case SP_ATTR_UNITS: { @@ -594,14 +601,12 @@ static void sp_namedview_set(SPObject *object, unsigned int key, const gchar *va /* fixme: Don't use g_log (see above). */ } } - nv->units = new_unit; - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->units = new_unit; + this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } default: - if (((SPObjectClass *) (sp_namedview_parent_class))->set) { - ((SPObjectClass *) (sp_namedview_parent_class))->set(object, key, value); - } + SPObjectGroup::set(key, value); break; } } @@ -647,78 +652,77 @@ sp_namedview_add_grid(SPNamedView *nv, Inkscape::XML::Node *repr, SPDesktop *des return grid; } -static void sp_namedview_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) -{ - SPNamedView *nv = (SPNamedView *) object; - - if (((SPObjectClass *) (sp_namedview_parent_class))->child_added) { - (* ((SPObjectClass *) (sp_namedview_parent_class))->child_added)(object, child, ref); - } +void SPNamedView::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { + SPObjectGroup::child_added(child, ref); if (!strcmp(child->name(), "inkscape:grid")) { - sp_namedview_add_grid(nv, child, NULL); + sp_namedview_add_grid(this, child, NULL); } else { - SPObject *no = object->document->getObjectByRepr(child); - if ( !SP_IS_OBJECT(no) ) + SPObject *no = this->document->getObjectByRepr(child); + if ( !SP_IS_OBJECT(no) ) { return; + } 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) { + this->guides = g_slist_prepend(this->guides, g); + + //g_object_set(G_OBJECT(g), "color", this->guidecolor, "hicolor", this->guidehicolor, NULL); + g->setColor(this->guidecolor); + g->setHiColor(this->guidehicolor); + + if (this->editable) { + for (GSList *l = this->views; l != NULL; l = l->next) { g->SPGuide::showSPGuide(static_cast<SPDesktop*>(l->data)->guides, (GCallback) sp_dt_guide_event); - if (static_cast<SPDesktop*>(l->data)->guides_active) - g->sensitize(sp_desktop_canvas(static_cast<SPDesktop*> (l->data)), - TRUE); - sp_namedview_show_single_guide(SP_GUIDE(g), nv->showguides); + + if (static_cast<SPDesktop*>(l->data)->guides_active) { + g->sensitize(sp_desktop_canvas(static_cast<SPDesktop*> (l->data)), TRUE); + } + + sp_namedview_show_single_guide(SP_GUIDE(g), this->showguides); } } } } } -static void sp_namedview_remove_child(SPObject *object, Inkscape::XML::Node *child) -{ - SPNamedView *nv = (SPNamedView *) object; - +void SPNamedView::remove_child(Inkscape::XML::Node *child) { if (!strcmp(child->name(), "inkscape:grid")) { - for ( GSList *iter = nv->grids ; iter ; iter = iter->next ) { + for ( GSList *iter = this->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); + this->grids = g_slist_remove_link(this->grids, iter); break; } } } else { - GSList **ref = &nv->guides; - for ( GSList *iter = nv->guides ; iter ; iter = iter->next ) { + GSList **ref = &this->guides; + for ( GSList *iter = this->guides ; iter ; iter = iter->next ) { + if ( reinterpret_cast<SPObject *>(iter->data)->getRepr() == child ) { *ref = iter->next; iter->next = NULL; g_slist_free_1(iter); break; } + ref = &iter->next; } } - if (((SPObjectClass *) (sp_namedview_parent_class))->remove_child) { - (* ((SPObjectClass *) (sp_namedview_parent_class))->remove_child)(object, child); - } + SPObjectGroup::remove_child(child); } -static Inkscape::XML::Node *sp_namedview_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPNamedView::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ( ( flags & SP_OBJECT_WRITE_EXT ) && - repr != object->getRepr() ) + repr != this->getRepr() ) { if (repr) { - repr->mergeFrom(object->getRepr(), "id"); + repr->mergeFrom(this->getRepr(), "id"); } else { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(xml_doc); } } diff --git a/src/sp-namedview.h b/src/sp-namedview.h index 26febd7d3..30f962d9f 100644 --- a/src/sp-namedview.h +++ b/src/sp-namedview.h @@ -14,19 +14,14 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#define SP_TYPE_NAMEDVIEW (sp_namedview_get_type()) -#define SP_NAMEDVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_NAMEDVIEW, SPNamedView)) -#define SP_NAMEDVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_NAMEDVIEW, SPNamedViewClass)) -#define SP_IS_NAMEDVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_NAMEDVIEW)) -#define SP_IS_NAMEDVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_NAMEDVIEW)) +#define SP_NAMEDVIEW(obj) (dynamic_cast<SPNamedView*>((SPObject*)obj)) +#define SP_IS_NAMEDVIEW(obj) (dynamic_cast<const SPNamedView*>((SPObject*)obj) != NULL) #include "sp-object-group.h" #include "snap.h" #include "document.h" #include "util/units.h" -G_BEGIN_DECLS - namespace Inkscape { class CanvasGrid; namespace Util { @@ -39,7 +34,11 @@ enum { SP_BORDER_LAYER_TOP }; -struct SPNamedView : public SPObjectGroup { +class SPNamedView : public SPObjectGroup { +public: + SPNamedView(); + virtual ~SPNamedView(); + unsigned int editable : 1; unsigned int showguides : 1; unsigned int showborder : 1; @@ -97,13 +96,18 @@ struct SPNamedView : public SPObjectGroup { private: double getMarginLength(gchar const * const key,Inkscape::Util::Unit const * const margin_units,Inkscape::Util::Unit const * const return_units,double const width,double const height,bool const use_width); friend class SPDocument; -}; -struct SPNamedViewClass { - SPObjectGroupClass parent_class; +protected: + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void release(); + virtual void set(unsigned int key, gchar const* value); + + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node* child); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); }; -GType sp_namedview_get_type(); SPNamedView *sp_document_namedview(SPDocument *document, gchar const *name); @@ -115,7 +119,6 @@ void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr); void sp_namedview_show_grids(SPNamedView *namedview, bool show, bool dirty_document); Inkscape::CanvasGrid * sp_namedview_get_first_enabled_grid(SPNamedView *namedview); -G_END_DECLS #endif /* !INKSCAPE_SP_NAMEDVIEW_H */ diff --git a/src/sp-object-group.cpp b/src/sp-object-group.cpp index e2b601ab9..c3967461e 100644 --- a/src/sp-object-group.cpp +++ b/src/sp-object-group.cpp @@ -16,108 +16,60 @@ #include "xml/repr.h" #include "document.h" -static void sp_objectgroup_child_added(SPObject *object, - Inkscape::XML::Node *child, - Inkscape::XML::Node *ref); - -static void sp_objectgroup_remove_child(SPObject *object, - Inkscape::XML::Node *child); - -static void sp_objectgroup_order_changed(SPObject *object, - Inkscape::XML::Node *child, - Inkscape::XML::Node *old_ref, - Inkscape::XML::Node *new_ref); - -static Inkscape::XML::Node* sp_objectgroup_write(SPObject *object, - Inkscape::XML::Document *doc, - Inkscape::XML::Node *repr, - guint flags); - -G_DEFINE_TYPE(SPObjectGroup, sp_objectgroup, SP_TYPE_OBJECT); - -static void -sp_objectgroup_class_init(SPObjectGroupClass *klass) -{ - SPObjectClass * sp_object_class = SP_OBJECT_CLASS(klass); - - sp_object_class->child_added = sp_objectgroup_child_added; - sp_object_class->remove_child = sp_objectgroup_remove_child; - sp_object_class->order_changed = sp_objectgroup_order_changed; - sp_object_class->write = sp_objectgroup_write; +SPObjectGroup::SPObjectGroup() : SPObject() { } -static void -sp_objectgroup_init(SPObjectGroup * /*objectgroup*/) -{ +SPObjectGroup::~SPObjectGroup() { } -static void -sp_objectgroup_child_added(SPObject *object, - Inkscape::XML::Node *child, - Inkscape::XML::Node *ref) -{ - if ((SP_OBJECT_CLASS(sp_objectgroup_parent_class))->child_added) { - (* (SP_OBJECT_CLASS(sp_objectgroup_parent_class))->child_added)(object, child, ref); - } +void SPObjectGroup::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { + SPObject::child_added(child, ref); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } -static void -sp_objectgroup_remove_child(SPObject *object, - Inkscape::XML::Node *child) -{ - if ((SP_OBJECT_CLASS(sp_objectgroup_parent_class))->remove_child) { - (* (SP_OBJECT_CLASS(sp_objectgroup_parent_class))->remove_child)(object, child); - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); +void SPObjectGroup::remove_child(Inkscape::XML::Node *child) { + SPObject::remove_child(child); + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } -static void -sp_objectgroup_order_changed(SPObject *object, - Inkscape::XML::Node *child, - Inkscape::XML::Node *old_ref, - Inkscape::XML::Node *new_ref) -{ - if ((SP_OBJECT_CLASS(sp_objectgroup_parent_class))->order_changed) { - (* (SP_OBJECT_CLASS(sp_objectgroup_parent_class))->order_changed)(object, child, old_ref, new_ref); - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); +void SPObjectGroup::order_changed(Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref) { + SPObject::order_changed(child, old_ref, new_ref); + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); } -static Inkscape::XML::Node* -sp_objectgroup_write(SPObject *object, - Inkscape::XML::Document *xml_doc, - Inkscape::XML::Node *repr, - guint flags) -{ + +Inkscape::XML::Node *SPObjectGroup::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if (flags & SP_OBJECT_WRITE_BUILD) { if (!repr) { repr = xml_doc->createElement("svg:g"); } + GSList *l = 0; - for ( SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { + for ( SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags); + if (crepr) { l = g_slist_prepend(l, crepr); } } + while (l) { repr->addChild(static_cast<Inkscape::XML::Node *>(l->data), NULL); Inkscape::GC::release(static_cast<Inkscape::XML::Node *>(l->data)); l = g_slist_remove(l, l->data); } } else { - for ( SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { + for ( SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { child->updateRepr(flags); } } - if ((SP_OBJECT_CLASS(sp_objectgroup_parent_class))->write) { - SP_OBJECT_CLASS(sp_objectgroup_parent_class)->write(object, xml_doc, repr, flags); - } + SPObject::write(xml_doc, repr, flags); return repr; } diff --git a/src/sp-object-group.h b/src/sp-object-group.h index 88e0e0f4e..4df346228 100644 --- a/src/sp-object-group.h +++ b/src/sp-object-group.h @@ -16,25 +16,21 @@ #include "sp-object.h" -#define SP_TYPE_OBJECTGROUP (sp_objectgroup_get_type ()) -#define SP_OBJECTGROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_OBJECTGROUP, SPObjectGroup)) -#define SP_OBJECTGROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_OBJECTGROUP, SPObjectGroupClass)) -#define SP_IS_OBJECTGROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_OBJECTGROUP)) -#define SP_IS_OBJECTGROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_OBJECTGROUP)) - -GType sp_objectgroup_get_type() G_GNUC_CONST; +#define SP_OBJECTGROUP(obj) (dynamic_cast<SPObjectGroup*>((SPObject*)obj)) +#define SP_IS_OBJECTGROUP(obj) (dynamic_cast<const SPObjectGroup*>((SPObject*)obj) != NULL) class SPObjectGroup : public SPObject { -private: - friend class SPObjectGroupClass; -}; - -class SPObjectGroupClass { public: - SPObjectClass parent_class; + SPObjectGroup(); + virtual ~SPObjectGroup(); + +protected: + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node* child); + + virtual void order_changed(Inkscape::XML::Node* child, Inkscape::XML::Node* old, Inkscape::XML::Node* new_repr); -private: - friend class SPObjectGroup; + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); }; #endif // SEEN_SP_OBJECTGROUP_H diff --git a/src/sp-object-repr.cpp b/src/sp-object-repr.cpp deleted file mode 100644 index eba38ec67..000000000 --- a/src/sp-object-repr.cpp +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Object type dictionary and build frontend - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * Abhishek Sharma - * - * Copyright (C) 1999-2003 Lauris Kaplinski - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "sp-defs.h" -#include "sp-symbol.h" -#include "marker.h" -#include "sp-use.h" -#include "sp-root.h" -#include "sp-image.h" -#include "sp-linear-gradient-fns.h" -#include "sp-mesh-gradient-fns.h" -#include "sp-mesh-row-fns.h" -#include "sp-mesh-patch-fns.h" -#include "sp-object-repr.h" -#include "sp-path.h" -#include "sp-radial-gradient-fns.h" -#include "sp-rect.h" -#include "box3d.h" -#include "box3d-side.h" -#include "persp3d.h" -#include "sp-ellipse.h" -#include "sp-star.h" -#include "sp-stop.h" -#include "sp-spiral.h" -#include "sp-offset.h" -#include "sp-line.h" -#include "sp-metadata.h" -#include "sp-polyline.h" -#include "sp-textpath.h" -#include "sp-tref.h" -#include "sp-tspan.h" -#include "sp-pattern.h" -#include "sp-clippath.h" -#include "sp-mask.h" -#include "sp-anchor.h" -#include "sp-flowdiv.h" -#include "sp-flowregion.h" -#include "sp-flowtext.h" -#include "sp-script.h" -#include "config.h" - -#include "sp-font.h" -#include "sp-font-face.h" -#include "sp-glyph.h" -#include "sp-missing-glyph.h" -#include "sp-glyph-kerning.h" - -#include "sp-style-elem.h" -#include "sp-switch.h" -#include "color-profile.h" -#include "xml/repr.h" -#include "sp-filter.h" -#include "filters/blend.h" -#include "filters/colormatrix.h" -#include "filters/componenttransfer.h" -#include "filters/componenttransfer-funcnode.h" -#include "filters/composite.h" -#include "filters/convolvematrix.h" -#include "filters/diffuselighting.h" -#include "filters/distantlight.h" -#include "filters/displacementmap.h" -#include "filters/flood.h" -#include "filters/gaussian-blur.h" -#include "filters/image.h" -#include "filters/merge.h" -#include "filters/morphology.h" -#include "filters/offset.h" -#include "filters/pointlight.h" -#include "filters/specularlighting.h" -#include "filters/spotlight.h" -#include "filters/tile.h" -#include "filters/turbulence.h" -#include "filters/mergenode.h" -#include "live_effects/lpeobject.h" -#include "sp-title.h" -#include "sp-desc.h" - - -enum NameType { REPR_NAME, SODIPODI_TYPE }; -static unsigned const N_NAME_TYPES = SODIPODI_TYPE + 1; - -static GType name_to_gtype(NameType name_type, gchar const *name); - -SPRoot *sp_object_repr_build_tree(SPDocument *document, Inkscape::XML::Node *repr) -{ - g_assert(document != NULL); - g_assert(repr != NULL); - - gchar const * const name = repr->name(); - g_assert(name != NULL); - GType const type = name_to_gtype(REPR_NAME, name); - g_assert(g_type_is_a(type, SP_TYPE_ROOT)); - gpointer newobj = g_object_new(type, 0); - g_assert(newobj != NULL); - SPObject *const object = SP_OBJECT(newobj); - g_assert(object != NULL); - object->invoke_build(document, repr, FALSE); - - return SP_ROOT(object); -} - -GType -sp_repr_type_lookup(Inkscape::XML::Node *repr) -{ - if ( repr->type() == Inkscape::XML::TEXT_NODE ) { - return SP_TYPE_STRING; - } else if ( repr->type() == Inkscape::XML::ELEMENT_NODE ) { - gchar const * const type_name = repr->attribute("sodipodi:type"); - return ( type_name - ? name_to_gtype(SODIPODI_TYPE, type_name) - : name_to_gtype(REPR_NAME, repr->name()) ); - } else { - return 0; - } -} - -static GHashTable *t2dtable[N_NAME_TYPES] = {NULL}; - -static void -populate_dtables() -{ - struct NameTypeEntry { char const *const name; GType const type_id; }; - NameTypeEntry const repr_name_entries[] = { - { "svg:a", SP_TYPE_ANCHOR }, - //{ "svg:animate", SP_TYPE_ANIMATE }, - { "svg:circle", SP_TYPE_CIRCLE }, - { "svg:color-profile", COLORPROFILE_TYPE }, - { "svg:clipPath", SP_TYPE_CLIPPATH }, - { "svg:defs", SP_TYPE_DEFS }, - { "svg:desc", SP_TYPE_DESC }, - { "svg:ellipse", SP_TYPE_ELLIPSE }, - { "svg:filter", SP_TYPE_FILTER }, - /* Note: flow* elements are proposed additions for SVG 1.2, they aren't in - SVG 1.1. */ - { "svg:flowDiv", SP_TYPE_FLOWDIV }, - { "svg:flowLine", SP_TYPE_FLOWLINE }, - { "svg:flowPara", SP_TYPE_FLOWPARA }, - { "svg:flowRegion", SP_TYPE_FLOWREGION }, - { "svg:flowRegionBreak", SP_TYPE_FLOWREGIONBREAK }, - { "svg:flowRegionExclude", SP_TYPE_FLOWREGIONEXCLUDE }, - { "svg:flowRoot", SP_TYPE_FLOWTEXT }, - { "svg:flowSpan", SP_TYPE_FLOWTSPAN }, - { "svg:font", SP_TYPE_FONT }, - { "svg:font-face", SP_TYPE_FONTFACE }, - { "svg:glyph", SP_TYPE_GLYPH }, - { "svg:missing-glyph", SP_TYPE_MISSING_GLYPH }, - { "svg:hkern", SP_TYPE_HKERN }, - { "svg:vkern", SP_TYPE_VKERN }, - { "svg:g", SP_TYPE_GROUP }, - { "svg:feBlend", SP_TYPE_FEBLEND }, - { "svg:feColorMatrix", SP_TYPE_FECOLORMATRIX }, - { "svg:feComponentTransfer", SP_TYPE_FECOMPONENTTRANSFER }, - { "svg:feComposite", SP_TYPE_FECOMPOSITE }, - { "svg:feConvolveMatrix", SP_TYPE_FECONVOLVEMATRIX }, - { "svg:feDiffuseLighting", SP_TYPE_FEDIFFUSELIGHTING }, - { "svg:feDistantLight", SP_TYPE_FEDISTANTLIGHT }, - { "svg:feDisplacementMap", SP_TYPE_FEDISPLACEMENTMAP }, - { "svg:feFlood", SP_TYPE_FEFLOOD }, - { "svg:feFuncR", SP_TYPE_FEFUNCR }, - { "svg:feFuncG", SP_TYPE_FEFUNCG }, - { "svg:feFuncB", SP_TYPE_FEFUNCB }, - { "svg:feFuncA", SP_TYPE_FEFUNCA }, - { "svg:feGaussianBlur", SP_TYPE_GAUSSIANBLUR }, - { "svg:feImage", SP_TYPE_FEIMAGE }, - { "svg:feMerge", SP_TYPE_FEMERGE }, - { "svg:feMorphology", SP_TYPE_FEMORPHOLOGY }, - { "svg:feOffset", SP_TYPE_FEOFFSET }, - { "svg:fePointLight", SP_TYPE_FEPOINTLIGHT }, - { "svg:feSpecularLighting", SP_TYPE_FESPECULARLIGHTING }, - { "svg:feSpotLight", SP_TYPE_FESPOTLIGHT }, - { "svg:feTile", SP_TYPE_FETILE }, - { "svg:feTurbulence", SP_TYPE_FETURBULENCE }, - { "svg:feMergeNode", SP_TYPE_FEMERGENODE }, - { "svg:image", SP_TYPE_IMAGE }, - { "svg:line", SP_TYPE_LINE }, - { "svg:linearGradient", SP_TYPE_LINEARGRADIENT }, - { "svg:marker", SP_TYPE_MARKER }, - { "svg:mask", SP_TYPE_MASK }, - { "svg:meshGradient", SP_TYPE_MESHGRADIENT }, - { "svg:meshRow", SP_TYPE_MESHROW }, - { "svg:meshPatch", SP_TYPE_MESHPATCH }, - { "svg:metadata", SP_TYPE_METADATA }, - { "svg:path", SP_TYPE_PATH }, - { "svg:pattern", SP_TYPE_PATTERN }, - { "svg:polygon", SP_TYPE_POLYGON }, - { "svg:polyline", SP_TYPE_POLYLINE }, - { "svg:radialGradient", SP_TYPE_RADIALGRADIENT }, - { "svg:rect", SP_TYPE_RECT }, - { "svg:stop", SP_TYPE_STOP }, - { "svg:script", SP_TYPE_SCRIPT }, - { "svg:svg", SP_TYPE_ROOT }, - { "svg:style", SP_TYPE_STYLE_ELEM }, - { "svg:switch", SP_TYPE_SWITCH }, - { "svg:symbol", SP_TYPE_SYMBOL }, - { "svg:text", SP_TYPE_TEXT }, - { "svg:textPath", SP_TYPE_TEXTPATH }, - { "svg:title", SP_TYPE_TITLE }, - { "svg:tref", SP_TYPE_TREF }, - { "svg:tspan", SP_TYPE_TSPAN }, - { "svg:use", SP_TYPE_USE }, - { "inkscape:path-effect", TYPE_LIVEPATHEFFECT } - }; - NameTypeEntry const sodipodi_name_entries[] = { - { "arc", SP_TYPE_ARC }, - { "inkscape:offset", SP_TYPE_OFFSET }, - { "spiral", SP_TYPE_SPIRAL }, - { "star", SP_TYPE_STAR }, - { "inkscape:box3d", SP_TYPE_BOX3D }, - { "inkscape:box3dside", SP_TYPE_BOX3D_SIDE }, - { "inkscape:persp3d", SP_TYPE_PERSP3D } - }; - - NameTypeEntry const *const t2entries[] = { - repr_name_entries, - sodipodi_name_entries - }; - unsigned const t2n_entries[] = { - G_N_ELEMENTS(repr_name_entries), - G_N_ELEMENTS(sodipodi_name_entries) - }; - - for (unsigned nt = 0; nt < N_NAME_TYPES; ++nt) { - NameTypeEntry const *const entries = t2entries[nt]; - unsigned const n_entries = t2n_entries[nt]; - GHashTable *&dtable = t2dtable[nt]; - - dtable = g_hash_table_new(g_str_hash, g_str_equal); - for (unsigned i = 0; i < n_entries; ++i) { - g_hash_table_insert(dtable, - (void *)entries[i].name, - (gpointer) entries[i].type_id); - } - } -} - -static inline void -ensure_dtables_populated() -{ - if (!*t2dtable) { - populate_dtables(); - } -} - -static GType -name_to_gtype(NameType const name_type, gchar const *name) -{ - ensure_dtables_populated(); - - gpointer const data = g_hash_table_lookup(t2dtable[name_type], name); - return ( ( data == NULL ) - ? SP_TYPE_OBJECT - : (GType) data ); -} - -void -sp_object_type_register(gchar const *name, GType const gtype) -{ - GType const current = name_to_gtype(REPR_NAME, name); - if (current == SP_TYPE_OBJECT) { - g_hash_table_insert(t2dtable[REPR_NAME], - const_cast<gchar *>(name), - (gpointer) gtype); - } else { - /* Already registered. */ - if (current != gtype) { - g_warning("repr type `%s' already registered as type #%lu, ignoring attempt to re-register as #%lu.", - name, current, gtype); - } - } -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-object-repr.h b/src/sp-object-repr.h deleted file mode 100644 index 0ac49bba4..000000000 --- a/src/sp-object-repr.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef SEEN_SP_OBJECT_REPR_H -#define SEEN_SP_OBJECT_REPR_H - -/* - * Object type dictionary and build frontend - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 1999-2003 Lauris Kaplinski - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "sp-object.h" -namespace Inkscape { -namespace XML { -class Node; -} -} - - -/** - * Construct an SPRoot and all its descendents from the given repr. - */ -SPRoot *sp_object_repr_build_tree(SPDocument *document, Inkscape::XML::Node *repr); - -GType sp_repr_type_lookup (Inkscape::XML::Node *repr); - -void sp_object_type_register(gchar const *name, GType type); - -#endif // SEEN_SP_OBJECT_REPR_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-object.cpp b/src/sp-object.cpp index b5c93e792..895b36e1c 100644 --- a/src/sp-object.cpp +++ b/src/sp-object.cpp @@ -25,7 +25,7 @@ #include "document.h" #include "preferences.h" #include "style.h" -#include "sp-object-repr.h" +#include "sp-factory.h" #include "sp-paint-server.h" #include "sp-root.h" #include "sp-style-elem.h" @@ -101,121 +101,54 @@ public: } }; -static void sp_object_child_added(SPObject *object, - Inkscape::XML::Node *child, - Inkscape::XML::Node *ref); - -static void sp_object_finalize(GObject *object); - -static void sp_object_remove_child(SPObject *object, - Inkscape::XML::Node *child); - -static void sp_object_order_changed(SPObject *object, - Inkscape::XML::Node *child, - Inkscape::XML::Node *old_ref, - Inkscape::XML::Node *new_ref); - -static void sp_object_release(SPObject *object); -static void sp_object_build(SPObject *object, - SPDocument *document, - Inkscape::XML::Node *repr); - -static void sp_object_private_set(SPObject *object, - unsigned int key, - gchar const *value); - -static Inkscape::XML::Node *sp_object_private_write(SPObject *object, - Inkscape::XML::Document *doc, - Inkscape::XML::Node *repr, - guint flags); - static gchar *sp_object_get_unique_id(SPObject *object, gchar const *defid); -G_DEFINE_TYPE(SPObject, sp_object, G_TYPE_OBJECT); - -/** - * Initializes the SPObject vtable. - */ -static void -sp_object_class_init(SPObjectClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - object_class->finalize = sp_object_finalize; - - klass->child_added = sp_object_child_added; - klass->remove_child = sp_object_remove_child; - klass->order_changed = sp_object_order_changed; - klass->release = sp_object_release; - klass->build = sp_object_build; - klass->set = sp_object_private_set; - klass->write = sp_object_private_write; -} - -/** - * Callback to initialize the SPObject object. - */ -static void -sp_object_init(SPObject *object) +SPObject::SPObject() + : cloned(0), uflags(0), mflags(0), hrefcount(0), _total_hrefcount(0), + document(NULL), parent(NULL), children(NULL), _last_child(NULL), + next(NULL), id(NULL), repr(NULL), refCount(1), + _successor(NULL), _collection_policy(SPObject::COLLECT_WITH_PARENT), + _label(NULL), _default_label(NULL) { - debug("id=%x, typename=%s",object, g_type_name_from_instance((GTypeInstance*)object)); - - object->hrefcount = 0; - object->_total_hrefcount = 0; - object->document = NULL; - object->children = object->_last_child = NULL; - object->parent = object->next = NULL; + debug("id=%x, typename=%s",this, g_type_name_from_instance((GTypeInstance*)object)); //used XML Tree here. - object->getRepr(); // TODO check why this call is made + this->getRepr(); // TODO check why this call is made - SPObjectImpl::setIdNull(object); - - object->_collection_policy = SPObject::COLLECT_WITH_PARENT; - - new (&object->_release_signal) sigc::signal<void, SPObject *>(); - new (&object->_modified_signal) sigc::signal<void, SPObject *, unsigned int>(); - new (&object->_delete_signal) sigc::signal<void, SPObject *>(); - new (&object->_position_changed_signal) sigc::signal<void, SPObject *>(); - object->_successor = NULL; + SPObjectImpl::setIdNull(this); // FIXME: now we create style for all objects, but per SVG, only the following can have style attribute: // vg, g, defs, desc, title, symbol, use, image, switch, path, rect, circle, ellipse, line, polyline, // polygon, text, tspan, tref, textPath, altGlyph, glyphRef, marker, linearGradient, radialGradient, // stop, pattern, clipPath, mask, filter, feImage, a, font, glyph, missing-glyph, foreignObject - object->style = sp_style_new_from_object(object); - - object->_label = NULL; - object->_default_label = NULL; + this->style = sp_style_new_from_object(this); } -/** - * Callback to destroy all members and connections of object and itself. - */ -static void -sp_object_finalize(GObject *object) -{ - SPObject *spobject = (SPObject *)object; +SPObject::~SPObject() { + g_free(this->_label); + g_free(this->_default_label); - g_free(spobject->_label); - g_free(spobject->_default_label); - spobject->_label = NULL; - spobject->_default_label = NULL; + this->_label = NULL; + this->_default_label = NULL; - if (spobject->_successor) { - sp_object_unref(spobject->_successor, NULL); - spobject->_successor = NULL; + if (this->_successor) { + sp_object_unref(this->_successor, NULL); + this->_successor = NULL; } +} + +// CPPIFY: make pure virtual +void SPObject::read_content() { + //throw; +} - spobject->_release_signal.~signal(); - spobject->_modified_signal.~signal(); - spobject->_delete_signal.~signal(); - spobject->_position_changed_signal.~signal(); +void SPObject::update(SPCtx* ctx, unsigned int flags) { + //throw; +} - if (((GObjectClass *) (sp_object_parent_class))->finalize) { - (* ((GObjectClass *) (sp_object_parent_class))->finalize)(object); - } +void SPObject::modified(unsigned int flags) { + //throw; } namespace { @@ -272,7 +205,8 @@ SPObject *sp_object_ref(SPObject *object, SPObject *owner) g_return_val_if_fail(!owner || SP_IS_OBJECT(owner), NULL); Inkscape::Debug::EventTracker<RefEvent> tracker(object); - g_object_ref(G_OBJECT(object)); + //g_object_ref(G_OBJECT(object)); + object->refCount++; return object; } @@ -283,7 +217,13 @@ SPObject *sp_object_unref(SPObject *object, SPObject *owner) g_return_val_if_fail(!owner || SP_IS_OBJECT(owner), NULL); Inkscape::Debug::EventTracker<UnrefEvent> tracker(object); - g_object_unref(G_OBJECT(object)); + //g_object_unref(G_OBJECT(object)); + object->refCount--; + + if (object->refCount < 0) { + delete object; + } + return NULL; } @@ -419,7 +359,7 @@ GSList *SPObject::childList(bool add_ref, Action) { GSList *l = NULL; for ( SPObject *child = firstChild() ; child; child = child->getNext() ) { if (add_ref) { - g_object_ref (G_OBJECT (child)); + sp_object_ref (child); } l = g_slist_prepend (l, child); @@ -634,59 +574,38 @@ SPObject *SPObject::get_child_by_repr(Inkscape::XML::Node *repr) return result; } -/** - * Callback for child_added event. - * Invoked whenever the given mutation event happens in the XML tree. - */ -static void -sp_object_child_added(SPObject *object, - Inkscape::XML::Node *child, - Inkscape::XML::Node *ref) -{ - GType type = sp_repr_type_lookup(child); - if (!type) { - return; - } - SPObject *ochild = SP_OBJECT(g_object_new(type, 0)); - SPObject *prev = ref ? object->get_child_by_repr(ref) : NULL; - object->attach(ochild, prev); - sp_object_unref(ochild, NULL); +void SPObject::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { + SPObject* object = this; + + try { + const std::string typeString = NodeTraits::get_type_string(*child); - ochild->invoke_build(object->document, child, object->cloned); + SPObject* ochild = SPFactory::instance().createObject(typeString); + + SPObject *prev = ref ? object->get_child_by_repr(ref) : NULL; + object->attach(ochild, prev); + sp_object_unref(ochild, NULL); + + ochild->invoke_build(object->document, child, object->cloned); + } catch (const FactoryExceptions::TypeNotRegistered& e) { + if (std::string(e.what()) != "rdf:RDF") { // temporary special case + g_warning("TypeNotRegistered exception: %s", e.what()); + } + } } -/** - * Removes, releases and unrefs all children of object. - * - * This is the opposite of build. It has to be invoked as soon as the - * object is removed from the tree, even if it is still alive according - * to reference count. The frontend unregisters the object from the - * document and releases the SPRepr bindings; implementations should free - * state data and release all child objects. Invoking release on - * SPRoot destroys the whole document tree. - * @see sp_object_build() - */ -static void -sp_object_release(SPObject *object) -{ +void SPObject::release() { + SPObject* object = this; + debug("id=%x, typename=%s", object, g_type_name_from_instance((GTypeInstance*)object)); while (object->children) { object->detach(object->children); } } -/** - * Remove object's child whose node equals repr, release and - * unref it. - * - * Invoked whenever the given mutation event happens in the XML - * tree, BEFORE removal from the XML tree happens, so grouping - * objects can safely release the child data. - */ -static void -sp_object_remove_child(SPObject *object, - Inkscape::XML::Node *child) -{ +void SPObject::remove_child(Inkscape::XML::Node* child) { + SPObject* object = this; + debug("id=%x, typename=%s", object, g_type_name_from_instance((GTypeInstance*)object)); SPObject *ochild = object->get_child_by_repr(child); g_return_if_fail (ochild != NULL || !strcmp("comment", child->name())); // comments have no objects @@ -695,18 +614,9 @@ sp_object_remove_child(SPObject *object, } } -/** - * Move object corresponding to child after sibling object corresponding - * to new_ref. - * Invoked whenever the given mutation event happens in the XML tree. - * @param old_ref Ignored - */ -static void -sp_object_order_changed(SPObject *object, - Inkscape::XML::Node *child, - Inkscape::XML::Node * /*old_ref*/, - Inkscape::XML::Node *new_ref) -{ +void SPObject::order_changed(Inkscape::XML::Node *child, Inkscape::XML::Node * old_ref, Inkscape::XML::Node *new_ref) { + SPObject* object = this; + SPObject *ochild = object->get_child_by_repr(child); g_return_if_fail(ochild != NULL); SPObject *prev = new_ref ? object->get_child_by_repr(new_ref) : NULL; @@ -714,22 +624,9 @@ sp_object_order_changed(SPObject *object, ochild->_position_changed_signal.emit(ochild); } -/** - * Virtual build callback. - * - * This has to be invoked immediately after creation of an SPObject. The - * frontend method ensures that the new object is properly attached to - * the document and repr; implementation then will parse all of the attributes, - * generate the children objects and so on. Invoking build on the SPRoot - * object results in creation of the whole document tree (this is, what - * SPDocument does after the creation of the XML tree). - * @see release() - */ -static void -sp_object_build(SPObject *object, - SPDocument *document, - Inkscape::XML::Node *repr) -{ +void SPObject::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPObject* object = this; + /* Nothing specific here */ debug("id=%x, typename=%s", object, g_type_name_from_instance((GTypeInstance*)object)); @@ -738,14 +635,28 @@ sp_object_build(SPObject *object, object->readAttr("inkscape:collect"); for (Inkscape::XML::Node *rchild = repr->firstChild() ; rchild != NULL; rchild = rchild->next()) { - GType type = sp_repr_type_lookup(rchild); - if (!type) { - continue; +// GType type = sp_repr_type_lookup(rchild); +// if (!type) { +// continue; +// } +// SPObject *child = SP_OBJECT(g_object_new(type, 0)); + +// SPObject* child = SPFactory::instance().createObject(*rchild); +// if (!child) { +// continue; +// } + + try { + const std::string typeString = NodeTraits::get_type_string(*rchild); + + SPObject* child = SPFactory::instance().createObject(typeString); + + object->attach(child, object->lastChild()); + sp_object_unref(child, NULL); + child->invoke_build(document, rchild, object->cloned); + } catch (const FactoryExceptions::TypeNotRegistered& e) { + //g_warning("TypeNotRegistered exception: %s", e.what()); } - SPObject *child = SP_OBJECT(g_object_new(type, 0)); - object->attach(child, object->lastChild()); - sp_object_unref(child, NULL); - child->invoke_build(document, rchild, object->cloned); } } @@ -805,9 +716,7 @@ void SPObject::invoke_build(SPDocument *document, Inkscape::XML::Node *repr, uns } /* Invoke derived methods, if any */ - if (((SPObjectClass *) G_OBJECT_GET_CLASS(this))->build) { - (*((SPObjectClass *) G_OBJECT_GET_CLASS(this))->build)(this, document, repr); - } + this->build(document, repr); /* Signalling (should be connected AFTER processing derived methods */ sp_repr_add_listener(repr, &object_event_vector, this); @@ -816,7 +725,7 @@ void SPObject::invoke_build(SPDocument *document, Inkscape::XML::Node *repr, uns int SPObject::getIntAttribute(char const *key, int def) { sp_repr_get_int(getRepr(),key,&def); - return def; + return def; } unsigned SPObject::getPosition(){ @@ -845,10 +754,8 @@ void SPObject::releaseReferences() { sp_repr_remove_listener_by_data(this->repr, this); this->_release_signal.emit(this); - SPObjectClass *klass=(SPObjectClass *)G_OBJECT_GET_CLASS(this); - if (klass->release) { - klass->release(this); - } + + this->release(); /* all hrefs should be released by the "release" handlers */ g_assert(this->hrefcount == 0); @@ -894,38 +801,28 @@ void SPObject::repr_child_added(Inkscape::XML::Node * /*repr*/, Inkscape::XML::N { SPObject *object = SP_OBJECT(data); - if (((SPObjectClass *) G_OBJECT_GET_CLASS(object))->child_added) { - (*((SPObjectClass *)G_OBJECT_GET_CLASS(object))->child_added)(object, child, ref); - } + object->child_added(child, ref); } void SPObject::repr_child_removed(Inkscape::XML::Node * /*repr*/, Inkscape::XML::Node *child, Inkscape::XML::Node * /*ref*/, gpointer data) { SPObject *object = SP_OBJECT(data); - if (((SPObjectClass *) G_OBJECT_GET_CLASS(object))->remove_child) { - (* ((SPObjectClass *)G_OBJECT_GET_CLASS(object))->remove_child)(object, child); - } + object->remove_child(child); } void SPObject::repr_order_changed(Inkscape::XML::Node * /*repr*/, Inkscape::XML::Node *child, Inkscape::XML::Node *old, Inkscape::XML::Node *newer, gpointer data) { SPObject *object = SP_OBJECT(data); - if (((SPObjectClass *) G_OBJECT_GET_CLASS(object))->order_changed) { - (* ((SPObjectClass *)G_OBJECT_GET_CLASS(object))->order_changed)(object, child, old, newer); - } + object->order_changed(child, old, newer); } -/** - * Callback for set event. - */ -static void sp_object_private_set(SPObject *object, - unsigned int key, - gchar const *value) -{ +void SPObject::set(unsigned int key, gchar const* value) { g_assert(key != SP_ATTR_INVALID); + SPObject* object = this; + switch (key) { case SP_ATTR_ID: @@ -1012,9 +909,7 @@ void SPObject::setKeyValue(unsigned int key, gchar const *value) //g_assert(object != NULL); //g_assert(SP_IS_OBJECT(object)); - if (((SPObjectClass *) G_OBJECT_GET_CLASS(this))->set) { - ((SPObjectClass *) G_OBJECT_GET_CLASS(this))->set(this, key, value); - } + this->set(key, value); } void SPObject::readAttr(gchar const *key) @@ -1052,9 +947,7 @@ void SPObject::repr_content_changed(Inkscape::XML::Node * /*repr*/, gchar const { SPObject *object = SP_OBJECT(data); - if (((SPObjectClass *) G_OBJECT_GET_CLASS(object))->read_content) { - (*((SPObjectClass *) G_OBJECT_GET_CLASS(object))->read_content)(object); - } + object->read_content(); } /** @@ -1072,15 +965,9 @@ static gchar const *sp_xml_get_space_string(unsigned int space) } } -/** - * Callback for write event. - */ -static Inkscape::XML::Node* -sp_object_private_write(SPObject *object, - Inkscape::XML::Document *doc, - Inkscape::XML::Node *repr, - guint flags) -{ +Inkscape::XML::Node* SPObject::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { + SPObject* object = this; + if (!repr && (flags & SP_OBJECT_WRITE_BUILD)) { repr = object->getRepr()->duplicate(doc); if (!( flags & SP_OBJECT_WRITE_EXT )) { @@ -1180,23 +1067,12 @@ Inkscape::XML::Node * SPObject::updateRepr(Inkscape::XML::Document *doc, Inkscap /* cloned objects have no repr */ return NULL; } - if (((SPObjectClass *) G_OBJECT_GET_CLASS(this))->write) { - if (!(flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = getRepr(); - } - return ((SPObjectClass *) G_OBJECT_GET_CLASS(this))->write(this, doc, repr, flags); - } else { - g_warning("Class %s does not implement ::write", G_OBJECT_TYPE_NAME(this)); - if (!repr) { - if (flags & SP_OBJECT_WRITE_BUILD) { - repr = getRepr()->duplicate(doc); - } - /// \todo FIXME: else probably error (Lauris) */ - } else { - repr->mergeFrom(getRepr(), "id"); - } - return repr; + + if (!(flags & SP_OBJECT_WRITE_BUILD) && !repr) { + repr = getRepr(); } + return this->write(doc, repr, flags); + } /* Modification */ @@ -1262,9 +1138,7 @@ void SPObject::updateDisplay(SPCtx *ctx, unsigned int flags) try { - if (((SPObjectClass *) G_OBJECT_GET_CLASS(this))->update) { - ((SPObjectClass *) G_OBJECT_GET_CLASS(this))->update(this, ctx, flags); - } + this->update(ctx, flags); } catch(...) { @@ -1320,13 +1194,12 @@ void SPObject::emitModified(unsigned int flags) * themselves. */ this->mflags = 0; - g_object_ref(G_OBJECT(this)); - SPObjectClass *klass=(SPObjectClass *)G_OBJECT_GET_CLASS(this); - if (klass->modified) { - klass->modified(this, flags); - } + sp_object_ref(this); + + this->modified(flags); + _modified_signal.emit(this, flags); - g_object_unref(G_OBJECT(this)); + sp_object_unref(this); } gchar const *SPObject::getTagName(SPException *ex) const diff --git a/src/sp-object.h b/src/sp-object.h index 19df6a554..4e9a6c938 100644 --- a/src/sp-object.h +++ b/src/sp-object.h @@ -16,12 +16,9 @@ /* SPObject flags */ class SPObject; -class SPObjectClass; -#define SP_TYPE_OBJECT (sp_object_get_type()) -#define SP_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_OBJECT, SPObject)) -#define SP_OBJECT_CLASS(clazz) (G_TYPE_CHECK_CLASS_CAST((clazz), SP_TYPE_OBJECT, SPObjectClass)) -#define SP_IS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_OBJECT)) +#define SP_OBJECT(obj) (dynamic_cast<SPObject*>((SPObject*)obj)) +#define SP_IS_OBJECT(obj) (dynamic_cast<const SPObject*>((SPObject*)obj) != NULL) /* Async modification flags */ #define SP_OBJECT_MODIFIED_FLAG (1 << 0) @@ -114,8 +111,6 @@ struct SPIXmlSpace { guint value : 1; }; -GType sp_object_get_type() G_GNUC_CONST; - /* * Refcounting * @@ -169,7 +164,6 @@ SPObject *sp_object_href(SPObject *object, gpointer owner); */ SPObject *sp_object_hunref(SPObject *object, gpointer owner); - /** * SPObject is an abstract base class of all of the document nodes at the * SVG document level. Each SPObject subclass implements a certain SVG @@ -187,13 +181,16 @@ SPObject *sp_object_hunref(SPObject *object, gpointer owner); * provides document level functionality such as the undo stack, * dictionary and so on. Source: doc/architecture.txt */ -class SPObject : public GObject { +class SPObject { // : public GObject { public: enum CollectionPolicy { COLLECT_WITH_PARENT, ALWAYS_COLLECT }; + SPObject(); + virtual ~SPObject(); + unsigned int cloned : 1; unsigned int uflags : 8; unsigned int mflags : 8; @@ -207,9 +204,13 @@ public: SPObject *next; /* Next object in linked list */ private: + SPObject(const SPObject&); + SPObject& operator=(const SPObject&); + gchar *id; /* Our very own unique id */ Inkscape::XML::Node *repr; /* Our xml representation */ public: + int refCount; /** * Returns the objects current ID string. @@ -791,9 +792,6 @@ private: /* Real handlers of repr signals */ public: - - static GType get_type() {return sp_object_get_type();} - /** * Callback for attr_changed node event. */ @@ -822,37 +820,26 @@ public: static void repr_order_changed(Inkscape::XML::Node *repr, Inkscape::XML::Node *child, Inkscape::XML::Node *old, Inkscape::XML::Node *newer, gpointer data); - friend class SPObjectClass; friend class SPObjectImpl; -}; - -/// The SPObject vtable. -class SPObjectClass { -public: - GObjectClass parent_class; - void (* build) (SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr); - void (* release) (SPObject *object); +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); - /* Virtual handlers of repr signals */ - void (* child_added) (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref); - void (* remove_child) (SPObject *object, Inkscape::XML::Node *child); + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node* child); - void (* order_changed) (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *old, Inkscape::XML::Node *new_repr); + virtual void order_changed(Inkscape::XML::Node* child, Inkscape::XML::Node* old_repr, Inkscape::XML::Node* new_repr); - void (* set) (SPObject *object, unsigned int key, gchar const *value); + virtual void set(unsigned int key, const gchar* value); - void (* read_content) (SPObject *object); + virtual void update(SPCtx* ctx, unsigned int flags); + virtual void modified(unsigned int flags); - /* Update handler */ - void (* update) (SPObject *object, SPCtx *ctx, unsigned int flags); - /* Modification handler */ - void (* modified) (SPObject *object, unsigned int flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); - Inkscape::XML::Node * (* write) (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, unsigned int flags); - -private: - friend class SPObject; +public: + virtual void read_content(); }; diff --git a/src/sp-offset.cpp b/src/sp-offset.cpp index 95511aea3..ef18acc8e 100644 --- a/src/sp-offset.cpp +++ b/src/sp-offset.cpp @@ -43,6 +43,16 @@ class SPDocument; +#include "sp-factory.h" + +namespace { + SPObject* createOffset() { + return new SPOffset(); + } + + bool offsetRegistered = SPFactory::instance().registerObject("inkscape:offset", createOffset); +} + #define noOFFSET_VERBOSE /** \note @@ -68,21 +78,6 @@ class SPDocument; * radius (look in object-edit). */ -static void sp_offset_finalize(GObject *obj); - -static void sp_offset_build (SPObject * object, SPDocument * document, - Inkscape::XML::Node * repr); -static Inkscape::XML::Node *sp_offset_write (SPObject * object, Inkscape::XML::Document *doc, Inkscape::XML::Node * repr, - guint flags); -static void sp_offset_set (SPObject * object, unsigned int key, - const gchar * value); -static void sp_offset_update (SPObject * object, SPCtx * ctx, guint flags); -static void sp_offset_release (SPObject * object); - -static gchar *sp_offset_description (SPItem * item); -static void sp_offset_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); -static void sp_offset_set_shape (SPShape * shape); - static void refresh_offset_source(SPOffset* offset); static void sp_offset_start_listening(SPOffset *offset,SPObject* to); @@ -100,134 +95,89 @@ static void sp_offset_source_modified (SPObject *iSource, guint flags, SPItem *i // reappearing in offset when the radius becomes too large static bool use_slow_but_correct_offset_method=false; -G_DEFINE_TYPE(SPOffset, sp_offset, SP_TYPE_SHAPE); - -/** - * SPOffset vtable initialization. - */ -static void -sp_offset_class_init(SPOffsetClass *klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPItemClass *item_class = (SPItemClass *) klass; - SPShapeClass *shape_class = (SPShapeClass *) klass; - - gobject_class->finalize = sp_offset_finalize; - - sp_object_class->build = sp_offset_build; - sp_object_class->write = sp_offset_write; - sp_object_class->set = sp_offset_set; - sp_object_class->update = sp_offset_update; - sp_object_class->release = sp_offset_release; - - item_class->description = sp_offset_description; - item_class->snappoints = sp_offset_snappoints; +SPOffset::SPOffset() : SPShape() { + this->rad = 1.0; + this->original = NULL; + this->originalPath = NULL; + this->knotSet = false; + this->sourceDirty=false; + this->isUpdating=false; + // init various connections + this->sourceHref = NULL; + this->sourceRepr = NULL; + this->sourceObject = NULL; - shape_class->set_shape = sp_offset_set_shape; -} + new (&this->_modified_connection) sigc::connection(); + new (&this->_delete_connection) sigc::connection(); + new (&this->_changed_connection) sigc::connection(); + new (&this->_transformed_connection) sigc::connection(); -/** - * Callback for SPOffset object initialization. - */ -static void -sp_offset_init(SPOffset *offset) -{ - offset->rad = 1.0; - offset->original = NULL; - offset->originalPath = NULL; - offset->knotSet = false; - offset->sourceDirty=false; - offset->isUpdating=false; - // init various connections - offset->sourceHref = NULL; - offset->sourceRepr = NULL; - offset->sourceObject = NULL; - new (&offset->_modified_connection) sigc::connection(); - new (&offset->_delete_connection) sigc::connection(); - new (&offset->_changed_connection) sigc::connection(); - new (&offset->_transformed_connection) sigc::connection(); // set up the uri reference - offset->sourceRef = new SPUseReference(offset); - offset->_changed_connection = offset->sourceRef->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_offset_href_changed), offset)); + this->sourceRef = new SPUseReference(this); + this->_changed_connection = this->sourceRef->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_offset_href_changed), this)); } -/** - * Callback for SPOffset finalization. - */ -static void -sp_offset_finalize(GObject *obj) -{ - SPOffset *offset = (SPOffset *) obj; - - delete offset->sourceRef; +SPOffset::~SPOffset() { + delete this->sourceRef; - offset->_modified_connection.disconnect(); - offset->_modified_connection.~connection(); - offset->_delete_connection.disconnect(); - offset->_delete_connection.~connection(); - offset->_changed_connection.disconnect(); - offset->_changed_connection.~connection(); - offset->_transformed_connection.disconnect(); - offset->_transformed_connection.~connection(); + this->_modified_connection.disconnect(); + this->_delete_connection.disconnect(); + this->_changed_connection.disconnect(); + this->_transformed_connection.disconnect(); } -/** - * Virtual build: set offset attributes from corresponding repr. - */ -static void -sp_offset_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_offset_parent_class)->build) - ((SPObjectClass *) sp_offset_parent_class)->build (object, document, repr); +void SPOffset::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPShape::build(document, repr); //XML Tree being used directly here while it shouldn't be. - if (object->getRepr()->attribute("inkscape:radius")) { - object->readAttr( "inkscape:radius" ); + if (this->getRepr()->attribute("inkscape:radius")) { + this->readAttr( "inkscape:radius" ); } else { //XML Tree being used directly here (as object->getRepr) //in all the below lines in the block while it shouldn't be. - gchar const *oldA = object->getRepr()->attribute("sodipodi:radius"); - object->getRepr()->setAttribute("inkscape:radius",oldA); - object->getRepr()->setAttribute("sodipodi:radius",NULL); + gchar const *oldA = this->getRepr()->attribute("sodipodi:radius"); + this->getRepr()->setAttribute("inkscape:radius",oldA); + this->getRepr()->setAttribute("sodipodi:radius",NULL); - object->readAttr( "inkscape:radius" ); + this->readAttr( "inkscape:radius" ); } - if (object->getRepr()->attribute("inkscape:original")) { - object->readAttr( "inkscape:original" ); + + if (this->getRepr()->attribute("inkscape:original")) { + this->readAttr( "inkscape:original" ); } else { - gchar const *oldA = object->getRepr()->attribute("sodipodi:original"); - object->getRepr()->setAttribute("inkscape:original",oldA); - object->getRepr()->setAttribute("sodipodi:original",NULL); + gchar const *oldA = this->getRepr()->attribute("sodipodi:original"); + this->getRepr()->setAttribute("inkscape:original",oldA); + this->getRepr()->setAttribute("sodipodi:original",NULL); - object->readAttr( "inkscape:original" ); + this->readAttr( "inkscape:original" ); } - if (object->getRepr()->attribute("xlink:href")) { - object->readAttr( "xlink:href" ); + + if (this->getRepr()->attribute("xlink:href")) { + this->readAttr( "xlink:href" ); } else { - gchar const *oldA = object->getRepr()->attribute("inkscape:href"); + gchar const *oldA = this->getRepr()->attribute("inkscape:href"); + if (oldA) { size_t lA = strlen(oldA); char *nA=(char*)malloc((1+lA+1)*sizeof(char)); + memcpy(nA+1,oldA,lA*sizeof(char)); + nA[0]='#'; nA[lA+1]=0; - object->getRepr()->setAttribute("xlink:href",nA); + + this->getRepr()->setAttribute("xlink:href",nA); + free(nA); - object->getRepr()->setAttribute("inkscape:href",NULL); + + this->getRepr()->setAttribute("inkscape:href",NULL); } - object->readAttr( "xlink:href" ); + + this->readAttr( "xlink:href" ); } } -/** - * Virtual write: write offset attributes to corresponding repr. - */ -static Inkscape::XML::Node * -sp_offset_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPOffset *offset = SP_OFFSET (object); - +Inkscape::XML::Node* SPOffset::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:path"); } @@ -238,66 +188,57 @@ sp_offset_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XM * inkscape:offset="cx cy exp revo rad arg t0" */ repr->setAttribute("sodipodi:type", "inkscape:offset"); - sp_repr_set_svg_double(repr, "inkscape:radius", offset->rad); - repr->setAttribute("inkscape:original", offset->original); - repr->setAttribute("inkscape:href", offset->sourceHref); + sp_repr_set_svg_double(repr, "inkscape:radius", this->rad); + repr->setAttribute("inkscape:original", this->original); + repr->setAttribute("inkscape:href", this->sourceHref); } - // Make sure the object has curve - SPCurve *curve = SP_SHAPE (offset)->getCurve(); + // Make sure the offset has curve + SPCurve *curve = SP_SHAPE (this)->getCurve(); + if (curve == NULL) { - sp_offset_set_shape (SP_SHAPE (offset)); + this->set_shape(); } // write that curve to "d" - char *d = sp_svg_write_path (offset->_curve->get_pathvector()); + char *d = sp_svg_write_path (this->_curve->get_pathvector()); repr->setAttribute("d", d); g_free (d); - if (((SPObjectClass *) (sp_offset_parent_class))->write) - ((SPObjectClass *) (sp_offset_parent_class))->write (object, xml_doc, repr, - flags | SP_SHAPE_WRITE_PATH); + SPShape::write(xml_doc, repr, flags | SP_SHAPE_WRITE_PATH); return repr; } -/** - * Virtual release callback. - */ -static void -sp_offset_release(SPObject *object) -{ - SPOffset *offset = (SPOffset *) object; +void SPOffset::release() { + if (this->original) { + free (this->original); + } - if (offset->original) free (offset->original); - if (offset->originalPath) delete ((Path *) offset->originalPath); - offset->original = NULL; - offset->originalPath = NULL; + if (this->originalPath) { + delete ((Path *) this->originalPath); + } - sp_offset_quit_listening(offset); + this->original = NULL; + this->originalPath = NULL; - offset->_changed_connection.disconnect(); - g_free(offset->sourceHref); - offset->sourceHref = NULL; - offset->sourceRef->detach(); + sp_offset_quit_listening(this); - if (((SPObjectClass *) sp_offset_parent_class)->release) { - ((SPObjectClass *) sp_offset_parent_class)->release (object); - } + this->_changed_connection.disconnect(); -} + g_free(this->sourceHref); -/** - * Set callback: the function that is called whenever a change is made to - * the description of the object. - */ -static void -sp_offset_set(SPObject *object, unsigned key, gchar const *value) -{ - SPOffset *offset = SP_OFFSET (object); + this->sourceHref = NULL; + this->sourceRef->detach(); - if ( offset->sourceDirty ) refresh_offset_source(offset); + SPShape::release(); +} + +void SPOffset::set(unsigned int key, const gchar* value) { + if ( this->sourceDirty ) { + refresh_offset_source(this); + } /* fixme: we should really collect updates */ switch (key) @@ -306,108 +247,112 @@ sp_offset_set(SPObject *object, unsigned key, gchar const *value) case SP_ATTR_SODIPODI_ORIGINAL: if (value == NULL) { } else { - if (offset->original) { - free (offset->original); - delete ((Path *) offset->originalPath); - offset->original = NULL; - offset->originalPath = NULL; + if (this->original) { + free (this->original); + delete ((Path *) this->originalPath); + + this->original = NULL; + this->originalPath = NULL; } - offset->original = strdup (value); + this->original = strdup (value); + + Geom::PathVector pv = sp_svg_read_pathv(this->original); + + this->originalPath = new Path; + reinterpret_cast<Path *>(this->originalPath)->LoadPathVector(pv); - Geom::PathVector pv = sp_svg_read_pathv(offset->original); - offset->originalPath = new Path; - reinterpret_cast<Path *>(offset->originalPath)->LoadPathVector(pv); + this->knotSet = false; - offset->knotSet = false; - if ( offset->isUpdating == false ) object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + if ( this->isUpdating == false ) { + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + } } break; + case SP_ATTR_INKSCAPE_RADIUS: case SP_ATTR_SODIPODI_RADIUS: - if (!sp_svg_length_read_computed_absolute (value, &offset->rad)) { - if (fabs (offset->rad) < 0.01) - offset->rad = (offset->rad < 0) ? -0.01 : 0.01; - offset->knotSet = false; // knotset=false because it's not set from the context + if (!sp_svg_length_read_computed_absolute (value, &this->rad)) { + if (fabs (this->rad) < 0.01) { + this->rad = (this->rad < 0) ? -0.01 : 0.01; + } + + this->knotSet = false; // knotset=false because it's not set from the context + } + + if ( this->isUpdating == false ) { + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } - if ( offset->isUpdating == false ) object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_INKSCAPE_HREF: case SP_ATTR_XLINK_HREF: if ( value == NULL ) { - sp_offset_quit_listening(offset); - if ( offset->sourceHref ) g_free(offset->sourceHref); - offset->sourceHref = NULL; - offset->sourceRef->detach(); + sp_offset_quit_listening(this); + if ( this->sourceHref ) { + g_free(this->sourceHref); + } + + this->sourceHref = NULL; + this->sourceRef->detach(); } else { - if ( offset->sourceHref && ( strcmp(value, offset->sourceHref) == 0 ) ) { + if ( this->sourceHref && ( strcmp(value, this->sourceHref) == 0 ) ) { } else { - if ( offset->sourceHref ) g_free(offset->sourceHref); - offset->sourceHref = g_strdup(value); + if ( this->sourceHref ) { + g_free(this->sourceHref); + } + + this->sourceHref = g_strdup(value); + try { - offset->sourceRef->attach(Inkscape::URI(value)); + this->sourceRef->attach(Inkscape::URI(value)); } catch (Inkscape::BadURIException &e) { g_warning("%s", e.what()); - offset->sourceRef->detach(); + this->sourceRef->detach(); } } } break; + default: - if (((SPObjectClass *) sp_offset_parent_class)->set) - ((SPObjectClass *) sp_offset_parent_class)->set (object, key, value); + SPShape::set(key, value); break; } } -/** - * Update callback: the object has changed, recompute its shape. - */ -static void -sp_offset_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPOffset* offset = SP_OFFSET(object); - offset->isUpdating=true; // prevent sp_offset_set from requesting updates - if ( offset->sourceDirty ) refresh_offset_source(offset); +void SPOffset::update(SPCtx *ctx, guint flags) { + this->isUpdating=true; // prevent sp_offset_set from requesting updates + + if ( this->sourceDirty ) { + refresh_offset_source(this); + } + if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - ((SPShape *) object)->setShape (); + + this->set_shape(); } - offset->isUpdating=false; + + this->isUpdating=false; - if (((SPObjectClass *) sp_offset_parent_class)->update) - ((SPObjectClass *) sp_offset_parent_class)->update (object, ctx, flags); + SPShape::update(ctx, flags); } -/** - * Returns a textual description of object. - */ -static gchar * -sp_offset_description(SPItem *item) -{ - SPOffset *offset = SP_OFFSET (item); - - if ( offset->sourceHref ) { +gchar* SPOffset::description() { + if ( this->sourceHref ) { // TRANSLATORS COMMENT: %s is either "outset" or "inset" depending on sign return g_strdup_printf(_("<b>Linked offset</b>, %s by %f pt"), - (offset->rad >= 0)? _("outset") : _("inset"), fabs (offset->rad)); + (this->rad >= 0)? _("outset") : _("inset"), fabs (this->rad)); } else { // TRANSLATORS COMMENT: %s is either "outset" or "inset" depending on sign return g_strdup_printf(_("<b>Dynamic offset</b>, %s by %f pt"), - (offset->rad >= 0)? _("outset") : _("inset"), fabs (offset->rad)); + (this->rad >= 0)? _("outset") : _("inset"), fabs (this->rad)); } } -/** - * Compute and set shape's offset. - */ -static void -sp_offset_set_shape(SPShape *shape) -{ - SPOffset *offset = SP_OFFSET (shape); - - if ( offset->originalPath == NULL ) { +void SPOffset::set_shape() { + if ( this->originalPath == NULL ) { // oops : no path?! (the offset object should do harakiri) return; } @@ -416,30 +361,35 @@ sp_offset_set_shape(SPShape *shape) #endif // au boulot - if ( fabs(offset->rad) < 0.01 ) { + if ( fabs(this->rad) < 0.01 ) { // grosso modo: 0 - // just put the source shape as the offseted one, no one will notice + // just put the source this as the offseted one, no one will notice // it's also useless to compute the offset with a 0 radius //XML Tree being used directly here while it shouldn't be. - const char *res_d = shape->getRepr()->attribute("inkscape:original"); + const char *res_d = this->getRepr()->attribute("inkscape:original"); + if ( res_d ) { Geom::PathVector pv = sp_svg_read_pathv(res_d); SPCurve *c = new SPCurve(pv); g_assert(c != NULL); - ((SPShape *) offset)->setCurveInsync (c, TRUE); - ((SPShape *) offset)->setCurveBeforeLPE(c); + + this->setCurveInsync (c, TRUE); + this->setCurveBeforeLPE(c); + c->unref(); } + return; } // extra paraniac careful check. the preceding if () should take care of this case - if (fabs (offset->rad) < 0.01) - offset->rad = (offset->rad < 0) ? -0.01 : 0.01; + if (fabs (this->rad) < 0.01) { + this->rad = (this->rad < 0) ? -0.01 : 0.01; + } Path *orig = new Path; - orig->Copy ((Path *) offset->originalPath); + orig->Copy ((Path *)this->originalPath); if ( use_slow_but_correct_offset_method == false ) { // version par outline @@ -451,14 +401,14 @@ sp_offset_set_shape(SPShape *shape) // and now: offset float o_width; - if (offset->rad >= 0) + if (this->rad >= 0) { - o_width = offset->rad; + o_width = this->rad; orig->OutsideOutline (res, o_width, join_round, butt_straight, 20.0); } else { - o_width = -offset->rad; + o_width = -this->rad; orig->OutsideOutline (res, -o_width, join_round, butt_straight, 20.0); } @@ -478,13 +428,16 @@ sp_offset_set_shape(SPShape *shape) theRes->ConvertToForme (orig, 1, originaux); - SPItem *item = shape; - Geom::OptRect bbox = item->desktopVisualBounds(); + Geom::OptRect bbox = this->desktopVisualBounds(); + if ( bbox ) { gdouble size = L2(bbox->dimensions()); - gdouble const exp = item->transform.descrim(); - if (exp != 0) + gdouble const exp = this->transform.descrim(); + + if (exp != 0) { size /= exp; + } + orig->Coalesce (size * 0.001); //g_print ("coa %g exp %g item %p\n", size * 0.001, exp, item); } @@ -515,13 +468,13 @@ sp_offset_set_shape(SPShape *shape) // and now: offset float o_width; - if (offset->rad >= 0) + if (this->rad >= 0) { - o_width = offset->rad; + o_width = this->rad; } else { - o_width = -offset->rad; + o_width = -this->rad; } // one has to have a measure of the details @@ -533,24 +486,32 @@ sp_offset_set_shape(SPShape *shape) { orig->ConvertWithBackData (0.5*o_width); } + orig->Fill (theShape, 0); theRes->ConvertToShape (theShape, fill_positive); + Path *originaux[1]; originaux[0]=orig; + Path *res = new Path; theRes->ConvertToForme (res, 1, originaux); + int nbPart=0; Path** parts=res->SubPaths(nbPart,true); char *holes=(char*)malloc(nbPart*sizeof(char)); + // we offset contours separately, because we can. // this way, we avoid doing a unique big ConvertToShape when dealing with big shapes with lots of holes { Shape* onePart=new Shape; Shape* oneCleanPart=new Shape; + theShape->Reset(); + for (int i=0;i<nbPart;i++) { double partSurf=parts[i]->Surface(); parts[i]->Convert(1.0); + { // raffiner si besoin double bL,bT,bR,bB; @@ -560,29 +521,41 @@ sp_offset_set_shape(SPShape *shape) parts[i]->Convert(0.02*mesure); } } + if ( partSurf < 0 ) { // inverse par rapport a la realite // plein holes[i]=0; parts[i]->Fill(oneCleanPart,0); onePart->ConvertToShape(oneCleanPart,fill_positive); // there aren't intersections in that one, but maybe duplicate points and null edges - oneCleanPart->MakeOffset(onePart,offset->rad,join_round,20.0); + oneCleanPart->MakeOffset(onePart,this->rad,join_round,20.0); onePart->ConvertToShape(oneCleanPart,fill_positive); onePart->CalcBBox(); double typicalSize=0.5*((onePart->rightX-onePart->leftX)+(onePart->bottomY-onePart->topY)); - if ( typicalSize < 0.05 ) typicalSize=0.05; + + if ( typicalSize < 0.05 ) { + typicalSize=0.05; + } + typicalSize*=0.01; - if ( typicalSize > 1.0 ) typicalSize=1.0; + + if ( typicalSize > 1.0 ) { + typicalSize=1.0; + } + onePart->ConvertToForme (parts[i]); parts[i]->ConvertEvenLines (typicalSize); parts[i]->Simplify (typicalSize); + double nPartSurf=parts[i]->Surface(); + if ( nPartSurf >= 0 ) { // inversion de la surface -> disparait delete parts[i]; parts[i]=NULL; } else { } + /* int firstP=theShape->nbPt; for (int j=0;j<onePart->nbPt;j++) theShape->AddPoint(onePart->pts[j].x); for (int j=0;j<onePart->nbAr;j++) theShape->AddEdge(firstP+onePart->aretes[j].st,firstP+onePart->aretes[j].en);*/ @@ -591,19 +564,28 @@ sp_offset_set_shape(SPShape *shape) holes[i]=1; parts[i]->Fill(oneCleanPart,0,false,true,true); onePart->ConvertToShape(oneCleanPart,fill_positive); - oneCleanPart->MakeOffset(onePart,-offset->rad,join_round,20.0); + oneCleanPart->MakeOffset(onePart,-this->rad,join_round,20.0); onePart->ConvertToShape(oneCleanPart,fill_positive); // for (int j=0;j<onePart->nbAr;j++) onePart->Inverse(j); // pas oublier de reinverser onePart->CalcBBox(); double typicalSize=0.5*((onePart->rightX-onePart->leftX)+(onePart->bottomY-onePart->topY)); - if ( typicalSize < 0.05 ) typicalSize=0.05; + + if ( typicalSize < 0.05 ) { + typicalSize=0.05; + } + typicalSize*=0.01; - if ( typicalSize > 1.0 ) typicalSize=1.0; + + if ( typicalSize > 1.0 ) { + typicalSize=1.0; + } + onePart->ConvertToForme (parts[i]); parts[i]->ConvertEvenLines (typicalSize); parts[i]->Simplify (typicalSize); double nPartSurf=parts[i]->Surface(); + if ( nPartSurf >= 0 ) { // inversion de la surface -> disparait delete parts[i]; @@ -621,11 +603,14 @@ sp_offset_set_shape(SPShape *shape) delete onePart; delete oneCleanPart; } + if ( nbPart > 1 ) { theShape->Reset(); + for (int i=0;i<nbPart;i++) { if ( parts[i] ) { parts[i]->ConvertWithBackData(1.0); + if ( holes[i] ) { parts[i]->Fill(theShape,i,true,true,true); } else { @@ -633,12 +618,23 @@ sp_offset_set_shape(SPShape *shape) } } } + theRes->ConvertToShape (theShape, fill_positive); theRes->ConvertToForme (orig,nbPart,parts); - for (int i=0;i<nbPart;i++) if ( parts[i] ) delete parts[i]; + + for (int i=0;i<nbPart;i++) { + if ( parts[i] ) { + delete parts[i]; + } + } } else if ( nbPart == 1 ) { orig->Copy(parts[0]); - for (int i=0;i<nbPart;i++) if ( parts[i] ) delete parts[i]; + + for (int i=0;i<nbPart;i++) { + if ( parts[i] ) { + delete parts[i]; + } + } } else { orig->Reset(); } @@ -653,14 +649,21 @@ sp_offset_set_shape(SPShape *shape) orig->Simplify (1.0 * o_width); }*/ - if ( parts ) free(parts); - if ( holes ) free(holes); + if ( parts ) { + free(parts); + } + + if ( holes ) { + free(holes); + } + delete res; delete theShape; delete theRes; } { char *res_d = NULL; + if (orig->descr_cmd.size() <= 1) { // Aie.... nothing left. @@ -672,27 +675,23 @@ sp_offset_set_shape(SPShape *shape) res_d = orig->svg_dump_path (); } + delete orig; Geom::PathVector pv = sp_svg_read_pathv(res_d); SPCurve *c = new SPCurve(pv); g_assert(c != NULL); - ((SPShape *) offset)->setCurveInsync (c, TRUE); - ((SPShape *) offset)->setCurveBeforeLPE(c); + + this->setCurveInsync (c, TRUE); + this->setCurveBeforeLPE(c); c->unref(); free (res_d); } } -/** - * Virtual snappoints function. - */ -static void sp_offset_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) -{ - if (((SPItemClass *) sp_offset_parent_class)->snappoints) { - ((SPItemClass *) sp_offset_parent_class)->snappoints (item, p, snapprefs); - } +void SPOffset::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) { + SPShape::snappoints(p, snapprefs); } @@ -727,31 +726,53 @@ vectors_are_clockwise (Geom::Point A, Geom::Point B, Geom::Point C) double ca_c = dot(C, A); double ab_a = acos (ab_c); - if (ab_c <= -1.0) + + if (ab_c <= -1.0) { ab_a = M_PI; - if (ab_c >= 1.0) + } + + if (ab_c >= 1.0) { ab_a = 0; - if (ab_s < 0) + } + + if (ab_s < 0) { ab_a = 2 * M_PI - ab_a; + } + double bc_a = acos (bc_c); - if (bc_c <= -1.0) + + if (bc_c <= -1.0) { bc_a = M_PI; - if (bc_c >= 1.0) + } + + if (bc_c >= 1.0) { bc_a = 0; - if (bc_s < 0) + } + + if (bc_s < 0) { bc_a = 2 * M_PI - bc_a; + } + double ca_a = acos (ca_c); - if (ca_c <= -1.0) + + if (ca_c <= -1.0) { ca_a = M_PI; - if (ca_c >= 1.0) + } + + if (ca_c >= 1.0) { ca_a = 0; - if (ca_s < 0) + } + + if (ca_s < 0) { ca_a = 2 * M_PI - ca_a; + } double lim = 2 * M_PI - ca_a; - if (ab_a < lim) + if (ab_a < lim) { return true; + } + return false; } @@ -766,9 +787,10 @@ vectors_are_clockwise (Geom::Point A, Geom::Point B, Geom::Point C) double sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) { - if (offset == NULL || offset->originalPath == NULL - || ((Path *) offset->originalPath)->descr_cmd.size() <= 1) + if (offset == NULL || offset->originalPath == NULL || ((Path *) offset->originalPath)->descr_cmd.size() <= 1) { return 1.0; + } + double dist = 1.0; Shape *theShape = new Shape; Shape *theRes = new Shape; @@ -797,14 +819,16 @@ sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) bool ptSet = false; double arDist = -1.0; bool arSet = false; + // first get the minimum distance to the points for (int i = 0; i < theRes->numberOfPoints(); i++) { if (theRes->getPoint(i).totalDegree() > 0) - { + { Geom::Point nx = theRes->getPoint(i).x; Geom::Point nxpx = px-nx; double ndist = sqrt (dot(nxpx,nxpx)); + if (ptSet == false || fabs (ndist) < fabs (ptDist)) { // we have a new minimum distance @@ -816,6 +840,7 @@ sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) fb = theRes->getPoint(i).incidentEdge[LAST]; pb = theRes->getPoint(i).incidentEdge[LAST]; cb = theRes->getPoint(i).incidentEdge[FIRST]; + do { // one angle @@ -826,10 +851,12 @@ sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) nex = theRes->getEdge(cb).dx; nlen = sqrt (dot(nex , nex)); nex /= nlen; + if (theRes->getEdge(pb).en == i) { prx = -prx; } + if (theRes->getEdge(cb).en == i) { nex = -nex; @@ -850,13 +877,16 @@ sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) } break; } + pb = cb; cb = theRes->NextAt (i, cb); } + while (cb >= 0 && pb >= 0 && pb != fb); } } } + // loop over the edges to try to improve the distance for (int i = 0; i < theRes->numberOfEdges(); i++) { @@ -864,14 +894,17 @@ sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) Geom::Point ex = theRes->getPoint(theRes->getEdge(i).en).x; Geom::Point nx = ex - sx; double len = sqrt (dot(nx,nx)); + if (len > 0.0001) { Geom::Point pxsx=px-sx; double ab = dot(nx,pxsx); + if (ab > 0 && ab < len * len) { // we're in the zone of influence of the segment double ndist = (cross(pxsx,nx)) / len; + if (arSet == false || fabs (ndist) < fabs (arDist)) { arDist = ndist; @@ -880,16 +913,22 @@ sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) } } } + if (arSet || ptSet) { - if (arSet == false) + if (arSet == false) { arDist = ptDist; - if (ptSet == false) + } + + if (ptSet == false) { ptDist = arDist; - if (fabs (ptDist) < fabs (arDist)) + } + + if (fabs (ptDist) < fabs (arDist)) { dist = ptDist; - else + } else { dist = arDist; + } } } @@ -909,8 +948,10 @@ void sp_offset_top_point (SPOffset const * offset, Geom::Point *px) { (*px) = Geom::Point(0, 0); - if (offset == NULL) + + if (offset == NULL) { return; + } if (offset->knotSet) { @@ -919,13 +960,19 @@ sp_offset_top_point (SPOffset const * offset, Geom::Point *px) } SPCurve *curve = SP_SHAPE (offset)->getCurve(); + if (curve == NULL) { - sp_offset_set_shape (SP_SHAPE (offset)); + // CPPIFY + //offset->set_shape(); + const_cast<SPOffset*>(offset)->set_shape(); + curve = SP_SHAPE (offset)->getCurve(); + if (curve == NULL) return; } + if (curve->is_empty()) { curve->unref(); @@ -968,8 +1015,9 @@ static void sp_offset_start_listening(SPOffset *offset,SPObject* to) static void sp_offset_quit_listening(SPOffset *offset) { - if ( offset->sourceObject == NULL ) + if ( offset->sourceObject == NULL ) { return; + } offset->_modified_connection.disconnect(); offset->_delete_connection.disconnect(); @@ -983,9 +1031,14 @@ static void sp_offset_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPOffset *offset) { sp_offset_quit_listening(offset); + if (offset->sourceRef) { SPItem *refobj = offset->sourceRef->getObject(); - if (refobj) sp_offset_start_listening(offset,refobj); + + if (refobj) { + sp_offset_start_listening(offset,refobj); + } + offset->sourceDirty=true; offset->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } @@ -997,6 +1050,7 @@ static void sp_offset_move_compensate(Geom::Affine const *mp, SPItem */*original guint mode = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_PARALLEL); Geom::Affine m(*mp); + if (!(m.isTranslation()) || mode == SP_CLONE_COMPENSATION_NONE) { self->sourceDirty=true; self->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); @@ -1037,7 +1091,11 @@ sp_offset_delete_self(SPObject */*deleted*/, SPOffset *offset) if (mode == SP_CLONE_ORPHANS_UNLINK) { // leave it be. just forget about the source sp_offset_quit_listening(offset); - if ( offset->sourceHref ) g_free(offset->sourceHref); + + if ( offset->sourceHref ) { + g_free(offset->sourceHref); + } + offset->sourceHref = NULL; offset->sourceRef->detach(); } else if (mode == SP_CLONE_ORPHANS_DELETE) { @@ -1050,6 +1108,7 @@ sp_offset_source_modified (SPObject */*iSource*/, guint flags, SPItem *item) { SPOffset *offset = SP_OFFSET(item); offset->sourceDirty=true; + if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG)) { offset->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } @@ -1058,35 +1117,54 @@ sp_offset_source_modified (SPObject */*iSource*/, guint flags, SPItem *item) static void refresh_offset_source(SPOffset* offset) { - if ( offset == NULL ) return; + if ( offset == NULL ) { + return; + } + offset->sourceDirty=false; // le mauvais cas: pas d'attribut d => il faut verifier que c'est une SPShape puis prendre le contour // The bad case: no d attribute. Must check that it's an SPShape and then take the outline. SPObject *refobj=offset->sourceObject; - if ( refobj == NULL ) return; + + if ( refobj == NULL ) { + return; + } + SPItem *item = SP_ITEM (refobj); SPCurve *curve=NULL; - if (!SP_IS_SHAPE (item) && !SP_IS_TEXT (item)) return; + + if (!SP_IS_SHAPE (item) && !SP_IS_TEXT (item)) { + return; + } + if (SP_IS_SHAPE (item)) { curve = SP_SHAPE (item)->getCurve (); - if (curve == NULL) + + if (curve == NULL) { return; + } } + if (SP_IS_TEXT (item)) { curve = SP_TEXT (item)->getNormalizedBpath (); - if (curve == NULL) - return; + + if (curve == NULL) { + return; + } } + Path *orig = new Path; orig->LoadPathVector(curve->get_pathvector()); curve->unref(); if (!item->transform.isIdentity()) { gchar const *t_attr = item->getRepr()->attribute("transform"); + if (t_attr) { Geom::Affine t; + if (sp_svg_transform_read(t_attr, &t)) { orig->Transform(t); } @@ -1105,6 +1183,7 @@ refresh_offset_source(SPOffset* offset) css = sp_repr_css_attr (offset->sourceRepr , "style"); val = sp_repr_css_property (css, "fill-rule", NULL); + if (val && strcmp (val, "nonzero") == 0) { theRes->ConvertToShape (theShape, fill_nonZero); @@ -1143,9 +1222,12 @@ sp_offset_get_source (SPOffset *offset) { if (offset && offset->sourceRef) { SPItem *refobj = offset->sourceRef->getObject(); - if (SP_IS_ITEM (refobj)) + + if (SP_IS_ITEM (refobj)) { return (SPItem *) refobj; + } } + return NULL; } diff --git a/src/sp-offset.h b/src/sp-offset.h index 904f8607c..7fe6a8a24 100644 --- a/src/sp-offset.h +++ b/src/sp-offset.h @@ -16,11 +16,8 @@ #include <stddef.h> #include <sigc++/sigc++.h> -#define SP_TYPE_OFFSET (sp_offset_get_type ()) -#define SP_OFFSET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_OFFSET, SPOffset)) -#define SP_OFFSET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_OFFSET, SPOffsetClass)) -#define SP_IS_OFFSET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_OFFSET)) -#define SP_IS_OFFSET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_OFFSET)) +#define SP_OFFSET(obj) (dynamic_cast<SPOffset*>((SPObject*)obj)) +#define SP_IS_OFFSET(obj) (dynamic_cast<const SPOffset*>((SPObject*)obj) != NULL) class SPUseReference; @@ -52,7 +49,11 @@ class SPUseReference; * points, or more precisely one control point, that's enough to define the * radius (look in object-edit). */ -struct SPOffset : public SPShape { +class SPOffset : public SPShape { +public: + SPOffset(); + virtual ~SPOffset(); + void *originalPath; ///< will be a livarot Path, just don't declare it here to please the gcc linker char *original; ///< SVG description of the source path float rad; ///< offset radius @@ -73,17 +74,18 @@ struct SPOffset : public SPShape { sigc::connection _delete_connection; sigc::connection _changed_connection; sigc::connection _transformed_connection; -}; -/// The SPOffset vtable. -struct SPOffsetClass -{ - SPShapeClass parent_class; -}; + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void set(unsigned int key, gchar const* value); + virtual void update(SPCtx *ctx, guint flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + virtual void release(); + virtual void snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); + virtual gchar* description(); -/* Standard Gtk function */ -GType sp_offset_get_type (void); + virtual void set_shape(); +}; double sp_offset_distance_to_original (SPOffset * offset, Geom::Point px); void sp_offset_top_point (SPOffset const *offset, Geom::Point *px); diff --git a/src/sp-paint-server-reference.h b/src/sp-paint-server-reference.h index 5561af1a3..e08694c2f 100644 --- a/src/sp-paint-server-reference.h +++ b/src/sp-paint-server-reference.h @@ -18,7 +18,7 @@ #include "sp-object.h" #include "uri-references.h" -struct SPPaintServer; +class SPPaintServer; class SPPaintServerReference : public Inkscape::URIReference { public: diff --git a/src/sp-paint-server.cpp b/src/sp-paint-server.cpp index bae0e2242..692265bd8 100644 --- a/src/sp-paint-server.cpp +++ b/src/sp-paint-server.cpp @@ -20,8 +20,6 @@ #include "sp-gradient.h" #include "xml/node.h" -static cairo_pattern_t *sp_paint_server_create_dummy_pattern(SPPaintServer *ps, cairo_t *ct, Geom::OptRect const &bbox, double opacity); - SPPaintServer *SPPaintServerReference::getObject() const { return static_cast<SPPaintServer *>(URIReference::getObject()); @@ -32,43 +30,11 @@ bool SPPaintServerReference::_acceptObject(SPObject *obj) const return SP_IS_PAINT_SERVER(obj); } -G_DEFINE_TYPE(SPPaintServer, sp_paint_server, SP_TYPE_OBJECT); - -static void sp_paint_server_class_init(SPPaintServerClass *psc) -{ - psc->pattern_new = sp_paint_server_create_dummy_pattern; -} - -static void -sp_paint_server_init(SPPaintServer * /*ps*/) -{ -} - -cairo_pattern_t *sp_paint_server_create_pattern(SPPaintServer *ps, - cairo_t *ct, - Geom::OptRect const &bbox, - double opacity) -{ - g_return_val_if_fail(ps != NULL, NULL); - g_return_val_if_fail(SP_IS_PAINT_SERVER(ps), NULL); - - cairo_pattern_t *cp = NULL; - SPPaintServerClass *psc = reinterpret_cast<SPPaintServerClass *>(G_OBJECT_GET_CLASS(ps)); - if ( psc->pattern_new ) { - cp = (*psc->pattern_new)(ps, ct, bbox, opacity); - } - - return cp; +SPPaintServer::SPPaintServer() : SPObject() { + this->swatch = 0; } -static cairo_pattern_t * -sp_paint_server_create_dummy_pattern(SPPaintServer */*ps*/, - cairo_t */* ct */, - Geom::OptRect const &/*bbox*/, - double /* opacity */) -{ - cairo_pattern_t *cp = cairo_pattern_create_rgb(1.0, 0.0, 1.0); - return cp; +SPPaintServer::~SPPaintServer() { } bool SPPaintServer::isSwatch() const @@ -76,6 +42,10 @@ bool SPPaintServer::isSwatch() const return swatch; } + +// TODO: So a solid brush is a gradient with a swatch and zero stops? +// Should we derive a new class for that? Or at least make this method +// virtual and move it out of the way? bool SPPaintServer::isSolid() const { bool solid = false; diff --git a/src/sp-paint-server.h b/src/sp-paint-server.h index f4948dfdb..89c4f6b1b 100644 --- a/src/sp-paint-server.h +++ b/src/sp-paint-server.h @@ -20,31 +20,22 @@ #include "sp-object.h" #include "uri-references.h" -#define SP_TYPE_PAINT_SERVER (sp_paint_server_get_type()) -#define SP_PAINT_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_PAINT_SERVER, SPPaintServer)) -#define SP_PAINT_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_PAINT_SERVER, SPPaintServerClass)) -#define SP_IS_PAINT_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_PAINT_SERVER)) -#define SP_IS_PAINT_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_PAINT_SERVER)) +#define SP_PAINT_SERVER(obj) (dynamic_cast<SPPaintServer*>((SPObject*)obj)) +#define SP_IS_PAINT_SERVER(obj) (dynamic_cast<const SPPaintServer*>((SPObject*)obj) != NULL) -GType sp_paint_server_get_type(void) G_GNUC_CONST; - -struct SPPaintServer : public SPObject { -protected: - bool swatch; +class SPPaintServer : public SPObject { public: + SPPaintServer(); + virtual ~SPPaintServer(); bool isSwatch() const; bool isSolid() const; -}; -struct SPPaintServerClass { - SPObjectClass sp_object_class; - /** Get SPPaint instance. */ - cairo_pattern_t *(*pattern_new)(SPPaintServer *ps, cairo_t *ct, Geom::OptRect const &bbox, double opacity); -}; - -cairo_pattern_t *sp_paint_server_create_pattern(SPPaintServer *ps, cairo_t *ct, Geom::OptRect const &bbox, double opacity); + virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity) = 0; +protected: + bool swatch; +}; #endif // SEEN_SP_PAINT_SERVER_H /* diff --git a/src/sp-path.cpp b/src/sp-path.cpp index 478a689e3..105506d6e 100644 --- a/src/sp-path.cpp +++ b/src/sp-path.cpp @@ -51,74 +51,41 @@ #define noPATH_VERBOSE -static void sp_path_finalize(GObject *obj); -static void sp_path_release(SPObject *object); +#include "sp-factory.h" -static void sp_path_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_path_set(SPObject *object, unsigned key, gchar const *value); +namespace { + SPObject* createPath() { + return new SPPath(); + } -static Inkscape::XML::Node *sp_path_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static Geom::Affine sp_path_set_transform(SPItem *item, Geom::Affine const &xform); -static gchar * sp_path_description(SPItem *item); -static void sp_path_convert_to_guides(SPItem *item); - -static void sp_path_update(SPObject *object, SPCtx *ctx, guint flags); -static void sp_path_update_patheffect(SPLPEItem *lpeitem, bool write); - -G_DEFINE_TYPE(SPPath, sp_path, SP_TYPE_SHAPE); - -/** - * Does the object-oriented work of initializing the class structure - * including parent class, and registers function pointers for - * the functions build, set, write, and set_transform. - */ -static void -sp_path_class_init(SPPathClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPItemClass *item_class = (SPItemClass *) klass; - SPLPEItemClass *lpe_item_class = (SPLPEItemClass *) klass; - - gobject_class->finalize = sp_path_finalize; - - sp_object_class->build = sp_path_build; - sp_object_class->release = sp_path_release; - sp_object_class->set = sp_path_set; - sp_object_class->write = sp_path_write; - sp_object_class->update = sp_path_update; - - item_class->description = sp_path_description; - item_class->set_transform = sp_path_set_transform; - item_class->convert_to_guides = sp_path_convert_to_guides; - - lpe_item_class->update_patheffect = sp_path_update_patheffect; + bool pathRegistered = SPFactory::instance().registerObject("svg:path", createPath); } - gint SPPath::nodesInPath() const { return _curve ? _curve->nodes_in_path() : 0; } -static gchar * -sp_path_description(SPItem * item) -{ - int count = SP_PATH(item)->nodesInPath(); - if (SP_IS_LPE_ITEM(item) && sp_lpe_item_has_path_effect(SP_LPE_ITEM(item))) { - +gchar* SPPath::description() { + int count = this->nodesInPath(); + + if (sp_lpe_item_has_path_effect(this)) { Glib::ustring s; - - PathEffectList effect_list = sp_lpe_item_get_effect_list(SP_LPE_ITEM(item)); + PathEffectList effect_list = sp_lpe_item_get_effect_list(this); + for (PathEffectList::iterator it = effect_list.begin(); it != effect_list.end(); ++it) { LivePathEffectObject *lpeobj = (*it)->lpeobject; - if (!lpeobj || !lpeobj->get_lpe()) + + if (!lpeobj || !lpeobj->get_lpe()) { break; - if (s.empty()) + } + + if (s.empty()) { s = lpeobj->get_lpe()->getName(); - else + } else { s = s + ", " + lpeobj->get_lpe()->getName(); + } } return g_strdup_printf(ngettext("<b>Path</b> (%i node, path effect: %s)", @@ -129,20 +96,16 @@ sp_path_description(SPItem * item) } } -static void -sp_path_convert_to_guides(SPItem *item) -{ - SPPath *path = SP_PATH(item); - - if (!path->_curve) { +void SPPath::convert_to_guides() { + if (!this->_curve) { return; } std::list<std::pair<Geom::Point, Geom::Point> > pts; - Geom::Affine const i2dt(path->i2dt_affine()); - - Geom::PathVector const & pv = path->_curve->get_pathvector(); + Geom::Affine const i2dt(this->i2dt_affine()); + Geom::PathVector const & pv = this->_curve->get_pathvector(); + for(Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) { for(Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++cit) { // only add curves for straight line segments @@ -153,135 +116,101 @@ sp_path_convert_to_guides(SPItem *item) } } - sp_guide_pt_pairs_to_guides(item->document, pts); + sp_guide_pt_pairs_to_guides(this->document, pts); } -/** - * Initializes an SPPath. - */ -static void -sp_path_init(SPPath *path) -{ - new (&path->connEndPair) SPConnEndPair(path); +SPPath::SPPath() : SPShape(), connEndPair(this) { } -static void -sp_path_finalize(GObject *obj) -{ - SPPath *path = (SPPath *) obj; - - path->connEndPair.~SPConnEndPair(); +SPPath::~SPPath() { } -/** - * Given a repr, this sets the data items in the path object such as - * fill & style attributes, markers, and CSS properties. - */ -static void -sp_path_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ +void SPPath::build(SPDocument *document, Inkscape::XML::Node *repr) { /* Are these calls actually necessary? */ - object->readAttr( "marker" ); - object->readAttr( "marker-start" ); - object->readAttr( "marker-mid" ); - object->readAttr( "marker-end" ); + this->readAttr( "marker" ); + this->readAttr( "marker-start" ); + this->readAttr( "marker-mid" ); + this->readAttr( "marker-end" ); - sp_conn_end_pair_build(object); + sp_conn_end_pair_build(this); - if (((SPObjectClass *) sp_path_parent_class)->build) { - ((SPObjectClass *) sp_path_parent_class)->build(object, document, repr); - } + SPShape::build(document, repr); - object->readAttr( "inkscape:original-d" ); - object->readAttr( "d" ); + this->readAttr( "inkscape:original-d" ); + this->readAttr( "d" ); /* d is a required attribute */ - gchar const *d = object->getAttribute("d", NULL); + gchar const *d = this->getAttribute("d", NULL); + if (d == NULL) { - object->setKeyValue( sp_attribute_lookup("d"), ""); + this->setKeyValue( sp_attribute_lookup("d"), ""); } } -static void -sp_path_release(SPObject *object) -{ - SPPath *path = SP_PATH(object); - - path->connEndPair.release(); +void SPPath::release() { + this->connEndPair.release(); - if (((SPObjectClass *) sp_path_parent_class)->release) { - ((SPObjectClass *) sp_path_parent_class)->release(object); - } + SPShape::release(); } -/** - * Sets a value in the path object given by 'key', to 'value'. This is used - * for setting attributes and markers on a path object. - */ -static void -sp_path_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPPath *path = (SPPath *) object; - +void SPPath::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_INKSCAPE_ORIGINAL_D: - if (value) { - Geom::PathVector pv = sp_svg_read_pathv(value); - SPCurve *curve = new SPCurve(pv); - if (curve) { - path->set_original_curve(curve, TRUE, true); - curve->unref(); - } - } else { - path->set_original_curve(NULL, TRUE, true); - } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + if (value) { + Geom::PathVector pv = sp_svg_read_pathv(value); + SPCurve *curve = new SPCurve(pv); + + if (curve) { + this->set_original_curve(curve, TRUE, true); + curve->unref(); + } + } else { + this->set_original_curve(NULL, TRUE, true); + } + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_D: - if (value) { - Geom::PathVector pv = sp_svg_read_pathv(value); - SPCurve *curve = new SPCurve(pv); - if (curve) { - ((SPShape *) path)->setCurve(curve, TRUE); - curve->unref(); - } - } else { - ((SPShape *) path)->setCurve(NULL, TRUE); - } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + if (value) { + Geom::PathVector pv = sp_svg_read_pathv(value); + SPCurve *curve = new SPCurve(pv); + + if (curve) { + this->setCurve(curve, TRUE); + curve->unref(); + } + } else { + this->setCurve(NULL, TRUE); + } + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_PROP_MARKER: case SP_PROP_MARKER_START: case SP_PROP_MARKER_MID: case SP_PROP_MARKER_END: - sp_shape_set_marker(object, key, value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + sp_shape_set_marker(this, key, value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_CONNECTOR_TYPE: case SP_ATTR_CONNECTOR_CURVATURE: case SP_ATTR_CONNECTION_START: case SP_ATTR_CONNECTION_END: case SP_ATTR_CONNECTION_START_POINT: case SP_ATTR_CONNECTION_END_POINT: - path->connEndPair.setAttr(key, value); + this->connEndPair.setAttr(key, value); break; + default: - if (((SPObjectClass *) sp_path_parent_class)->set) { - ((SPObjectClass *) sp_path_parent_class)->set(object, key, value); - } + SPShape::set(key, value); break; } } -/** - * - * Writes the path object into a Inkscape::XML::Node - */ -static Inkscape::XML::Node * -sp_path_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPShape *shape = (SPShape *) object; - +Inkscape::XML::Node* SPPath::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:path"); } @@ -289,8 +218,9 @@ sp_path_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML: #ifdef PATH_VERBOSE g_message("sp_path_write writes 'd' attribute"); #endif - if ( shape->_curve != NULL ) { - gchar *str = sp_svg_write_path(shape->_curve->get_pathvector()); + + if ( this->_curve != NULL ) { + gchar *str = sp_svg_write_path(this->_curve->get_pathvector()); repr->setAttribute("d", str); g_free(str); } else { @@ -298,8 +228,8 @@ g_message("sp_path_write writes 'd' attribute"); } if (flags & SP_OBJECT_WRITE_EXT) { - if ( shape->_curve_before_lpe != NULL ) { - gchar *str = sp_svg_write_path(shape->_curve_before_lpe->get_pathvector()); + if ( this->_curve_before_lpe != NULL ) { + gchar *str = sp_svg_write_path(this->_curve_before_lpe->get_pathvector()); repr->setAttribute("inkscape:original-d", str); g_free(str); } else { @@ -307,101 +237,82 @@ g_message("sp_path_write writes 'd' attribute"); } } - SP_PATH(shape)->connEndPair.writeRepr(repr); + this->connEndPair.writeRepr(repr); - if (((SPObjectClass *)(sp_path_parent_class))->write) { - ((SPObjectClass *)(sp_path_parent_class))->write(object, xml_doc, repr, flags); - } + SPShape::write(xml_doc, repr, flags); return repr; } -static void -sp_path_update(SPObject *object, SPCtx *ctx, guint flags) -{ - if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B; // since we change the description, it's not a "just translation" anymore - } +void SPPath::update(SPCtx *ctx, guint flags) { + if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { + flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B; // since we change the description, it's not a "just translation" anymore + } - if (((SPObjectClass *) sp_path_parent_class)->update) { - ((SPObjectClass *) sp_path_parent_class)->update(object, ctx, flags); - } + SPShape::update(ctx, flags); - SPPath *path = SP_PATH(object); - path->connEndPair.update(); + this->connEndPair.update(); } - -/** - * Writes the given transform into the repr for the given item. - */ -static Geom::Affine -sp_path_set_transform(SPItem *item, Geom::Affine const &xform) -{ - if (!SP_IS_PATH(item)) { - return Geom::identity(); - } - SPPath *path = SP_PATH(item); - - if (!path->_curve) { // 0 nodes, nothing to transform +Geom::Affine SPPath::set_transform(Geom::Affine const &transform) { + if (!this->_curve) { // 0 nodes, nothing to transform return Geom::identity(); } - // Transform the original-d path if this is a valid LPE item, other else the (ordinary) path - if (path->_curve_before_lpe && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(item))) { - if (sp_lpe_item_has_path_effect_of_type(SP_LPE_ITEM(item), Inkscape::LivePathEffect::CLONE_ORIGINAL)) { + // Transform the original-d path if this is a valid LPE this, other else the (ordinary) path + if (this->_curve_before_lpe && sp_lpe_item_has_path_effect_recursive(this)) { + if (sp_lpe_item_has_path_effect_of_type(this, Inkscape::LivePathEffect::CLONE_ORIGINAL)) { // if path has the CLONE_ORIGINAL LPE applied, don't write the transform to the pathdata, but write it 'unoptimized' - return xform; + return transform; } else { - path->_curve_before_lpe->transform(xform); + this->_curve_before_lpe->transform(transform); } } else { - path->_curve->transform(xform); + this->_curve->transform(transform); } // Adjust stroke - item->adjust_stroke(xform.descrim()); + this->adjust_stroke(transform.descrim()); // Adjust pattern fill - item->adjust_pattern(xform); + this->adjust_pattern(transform); // Adjust gradient fill - item->adjust_gradient(xform); + this->adjust_gradient(transform); // Adjust LPE - item->adjust_livepatheffect(xform); + this->adjust_livepatheffect(transform); - item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); // nothing remains - we've written all of the transform, so return identity return Geom::identity(); } -static void -sp_path_update_patheffect(SPLPEItem *lpeitem, bool write) -{ - SPShape * const shape = (SPShape *) lpeitem; - Inkscape::XML::Node *repr = shape->getRepr(); +void SPPath::update_patheffect(bool write) { + Inkscape::XML::Node *repr = this->getRepr(); #ifdef PATH_VERBOSE g_message("sp_path_update_patheffect"); #endif - if (shape->_curve_before_lpe && sp_lpe_item_has_path_effect_recursive(lpeitem)) { - SPCurve *curve = shape->_curve_before_lpe->copy(); + if (this->_curve_before_lpe && sp_lpe_item_has_path_effect_recursive(this)) { + SPCurve *curve = this->_curve_before_lpe->copy(); /* if a path has an lpeitem applied, then reset the curve to the _curve_before_lpe. * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ - shape->setCurveInsync(curve, TRUE); + this->setCurveInsync(curve, TRUE); + + bool success = sp_lpe_item_perform_path_effect(this, curve); - bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM(shape), curve); if (success && write) { - // could also do shape->getRepr()->updateRepr(); but only the d attribute needs updating. + // could also do this->getRepr()->updateRepr(); but only the d attribute needs updating. #ifdef PATH_VERBOSE g_message("sp_path_update_patheffect writes 'd' attribute"); #endif - if ( shape->_curve != NULL ) { - gchar *str = sp_svg_write_path(shape->_curve->get_pathvector()); + + if ( this->_curve != NULL ) { + gchar *str = sp_svg_write_path(this->_curve->get_pathvector()); repr->setAttribute("d", str); g_free(str); } else { @@ -412,13 +323,15 @@ g_message("sp_path_update_patheffect writes 'd' attribute"); if (gchar const * value = repr->attribute("d")) { Geom::PathVector pv = sp_svg_read_pathv(value); SPCurve *oldcurve = new SPCurve(pv); + if (oldcurve) { - shape->setCurve(oldcurve, TRUE); + this->setCurve(oldcurve, TRUE); oldcurve->unref(); } } } - shape->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); curve->unref(); } } @@ -437,6 +350,7 @@ void SPPath::set_original_curve (SPCurve *new_curve, unsigned int owner, bool wr if (_curve_before_lpe) { _curve_before_lpe = _curve_before_lpe->unref(); } + if (new_curve) { if (owner) { _curve_before_lpe = new_curve->ref(); @@ -444,6 +358,7 @@ void SPPath::set_original_curve (SPCurve *new_curve, unsigned int owner, bool wr _curve_before_lpe = new_curve->copy(); } } + sp_lpe_item_update_patheffect(this, true, write); requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } @@ -456,6 +371,7 @@ SPCurve * SPPath::get_original_curve () const if (_curve_before_lpe) { return _curve_before_lpe->copy(); } + return NULL; } diff --git a/src/sp-path.h b/src/sp-path.h index 5dd79212c..42c0f22c8 100644 --- a/src/sp-path.h +++ b/src/sp-path.h @@ -21,15 +21,17 @@ class SPCurve; -#define SP_TYPE_PATH (sp_path_get_type ()) -#define SP_PATH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_PATH, SPPath)) -#define SP_IS_PATH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_PATH)) +#define SP_PATH(obj) (dynamic_cast<SPPath*>((SPObject*)obj)) +#define SP_IS_PATH(obj) (dynamic_cast<const SPPath*>((SPObject*)obj) != NULL) /** * SVG <path> implementation */ class SPPath : public SPShape { public: + SPPath(); + virtual ~SPPath(); + gint nodesInPath() const; // still in lowercase because the names should be clearer on whether curve, curve->copy or curve-ref is returned. @@ -44,13 +46,20 @@ public: // should be made protected public: SPConnEndPair connEndPair; -}; -struct SPPathClass { - SPShapeClass shape_class; -}; + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void release(); + virtual void update(SPCtx* ctx, guint flags); -GType sp_path_get_type (void); + virtual void set(unsigned int key, gchar const* value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + + virtual gchar* description(); + virtual Geom::Affine set_transform(Geom::Affine const &transform); + virtual void convert_to_guides(); + + virtual void update_patheffect(bool write); +}; #endif // SEEN_SP_PATH_H diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index b8368a416..213b57559 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -40,221 +40,222 @@ /* * Pattern */ -static void sp_pattern_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_pattern_release (SPObject *object); -static void sp_pattern_set (SPObject *object, unsigned int key, const gchar *value); -static void sp_pattern_update (SPObject *object, SPCtx *ctx, unsigned int flags); -static void sp_pattern_modified (SPObject *object, unsigned int flags); - static void pattern_ref_changed(SPObject *old_ref, SPObject *ref, SPPattern *pat); static void pattern_ref_modified (SPObject *ref, guint flags, SPPattern *pattern); -static cairo_pattern_t *sp_pattern_create_pattern(SPPaintServer *ps, cairo_t *ct, Geom::OptRect const &bbox, double opacity); - -G_DEFINE_TYPE(SPPattern, sp_pattern, SP_TYPE_PAINT_SERVER); - -static void -sp_pattern_class_init (SPPatternClass *klass) -{ - SPObjectClass *sp_object_class; - SPPaintServerClass *ps_class; - - sp_object_class = (SPObjectClass *) klass; - ps_class = (SPPaintServerClass *) klass; - - sp_object_class->build = sp_pattern_build; - sp_object_class->release = sp_pattern_release; - sp_object_class->set = sp_pattern_set; - sp_object_class->update = sp_pattern_update; - sp_object_class->modified = sp_pattern_modified; +#include "sp-factory.h" - // do we need _write? seems to work without it +namespace { + SPObject* createPattern() { + return new SPPattern(); + } - ps_class->pattern_new = sp_pattern_create_pattern; + bool patternRegistered = SPFactory::instance().registerObject("svg:pattern", createPattern); } -static void -sp_pattern_init (SPPattern *pat) -{ - pat->ref = new SPPatternReference(pat); - pat->ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(pattern_ref_changed), pat)); +SPPattern::SPPattern() : SPPaintServer() { + this->href = NULL; - pat->patternUnits = SP_PATTERN_UNITS_OBJECTBOUNDINGBOX; - pat->patternUnits_set = FALSE; + this->ref = new SPPatternReference(this); + this->ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(pattern_ref_changed), this)); - pat->patternContentUnits = SP_PATTERN_UNITS_USERSPACEONUSE; - pat->patternContentUnits_set = FALSE; + this->patternUnits = SP_PATTERN_UNITS_OBJECTBOUNDINGBOX; + this->patternUnits_set = FALSE; - pat->patternTransform = Geom::identity(); - pat->patternTransform_set = FALSE; + this->patternContentUnits = SP_PATTERN_UNITS_USERSPACEONUSE; + this->patternContentUnits_set = FALSE; - pat->x.unset(); - pat->y.unset(); - pat->width.unset(); - pat->height.unset(); + this->patternTransform = Geom::identity(); + this->patternTransform_set = FALSE; - pat->viewBox_set = FALSE; + this->x.unset(); + this->y.unset(); + this->width.unset(); + this->height.unset(); - new (&pat->modified_connection) sigc::connection(); + this->viewBox_set = FALSE; } -static void -sp_pattern_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_pattern_parent_class)->build) - (* ((SPObjectClass *) sp_pattern_parent_class)->build) (object, document, repr); - - object->readAttr( "patternUnits" ); - object->readAttr( "patternContentUnits" ); - object->readAttr( "patternTransform" ); - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "width" ); - object->readAttr( "height" ); - object->readAttr( "viewBox" ); - object->readAttr( "xlink:href" ); - - /* Register ourselves */ - document->addResource("pattern", object); +SPPattern::~SPPattern() { } -static void sp_pattern_release(SPObject *object) -{ - SPPattern *pat = reinterpret_cast<SPPattern *>(object); +void SPPattern::build(SPDocument* doc, Inkscape::XML::Node* repr) { + SPPaintServer::build(doc, repr); + + this->readAttr( "patternUnits" ); + this->readAttr( "patternContentUnits" ); + this->readAttr( "patternTransform" ); + this->readAttr( "x" ); + this->readAttr( "y" ); + this->readAttr( "width" ); + this->readAttr( "height" ); + this->readAttr( "viewBox" ); + this->readAttr( "xlink:href" ); + + /* Register ourselves */ + doc->addResource("pattern", this); +} - if (object->document) { +void SPPattern::release() { + if (this->document) { // Unregister ourselves - object->document->removeResource("pattern", object); + this->document->removeResource("pattern", this); } - if (pat->ref) { - pat->modified_connection.disconnect(); - pat->ref->detach(); - delete pat->ref; - pat->ref = NULL; + if (this->ref) { + this->modified_connection.disconnect(); + this->ref->detach(); + delete this->ref; + this->ref = NULL; } - pat->modified_connection.~connection(); - - if (((SPObjectClass *) sp_pattern_parent_class)->release) { - ((SPObjectClass *) sp_pattern_parent_class)->release (object); - } + SPPaintServer::release(); } -static void -sp_pattern_set (SPObject *object, unsigned int key, const gchar *value) -{ - SPPattern *pat = SP_PATTERN (object); - - switch (key) { - case SP_ATTR_PATTERNUNITS: - if (value) { - if (!strcmp (value, "userSpaceOnUse")) { - pat->patternUnits = SP_PATTERN_UNITS_USERSPACEONUSE; - } else { - pat->patternUnits = SP_PATTERN_UNITS_OBJECTBOUNDINGBOX; - } - pat->patternUnits_set = TRUE; - } else { - pat->patternUnits_set = FALSE; - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_PATTERNCONTENTUNITS: - if (value) { - if (!strcmp (value, "userSpaceOnUse")) { - pat->patternContentUnits = SP_PATTERN_UNITS_USERSPACEONUSE; - } else { - pat->patternContentUnits = SP_PATTERN_UNITS_OBJECTBOUNDINGBOX; - } - pat->patternContentUnits_set = TRUE; - } else { - pat->patternContentUnits_set = FALSE; - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_PATTERNTRANSFORM: { - Geom::Affine t; - if (value && sp_svg_transform_read (value, &t)) { - pat->patternTransform = t; - pat->patternTransform_set = TRUE; - } else { - pat->patternTransform = Geom::identity(); - pat->patternTransform_set = FALSE; - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - } - case SP_ATTR_X: - pat->x.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_Y: - pat->y.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_WIDTH: - pat->width.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_HEIGHT: - pat->height.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_VIEWBOX: { - /* fixme: Think (Lauris) */ - if (value) { - char *eptr = const_cast<gchar *>(value); - double x = g_ascii_strtod (eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; - double y = g_ascii_strtod (eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; - double width = g_ascii_strtod (eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; - double height = g_ascii_strtod (eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; - if ((width > 0) && (height > 0)) { - pat->viewBox = Geom::Rect::from_xywh(x, y, width, height); - pat->viewBox_set = TRUE; - } else { - pat->viewBox_set = FALSE; - } - } else { - pat->viewBox_set = FALSE; - } - object->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); - break; - } - case SP_ATTR_XLINK_HREF: - if ( value && pat->href && ( strcmp(value, pat->href) == 0 ) ) { - /* Href unchanged, do nothing. */ - } else { - g_free(pat->href); - pat->href = NULL; - if (value) { - // First, set the href field; it's only used in the "unchanged" check above. - pat->href = g_strdup(value); - // Now do the attaching, which emits the changed signal. - if (value) { - try { - pat->ref->attach(Inkscape::URI(value)); - } catch (Inkscape::BadURIException &e) { - g_warning("%s", e.what()); - pat->ref->detach(); - } - } else { - pat->ref->detach(); - } - } - } - break; - default: - if (((SPObjectClass *) sp_pattern_parent_class)->set) - ((SPObjectClass *) sp_pattern_parent_class)->set (object, key, value); - break; - } +void SPPattern::set(unsigned int key, const gchar* value) { + switch (key) { + case SP_ATTR_PATTERNUNITS: + if (value) { + if (!strcmp (value, "userSpaceOnUse")) { + this->patternUnits = SP_PATTERN_UNITS_USERSPACEONUSE; + } else { + this->patternUnits = SP_PATTERN_UNITS_OBJECTBOUNDINGBOX; + } + + this->patternUnits_set = TRUE; + } else { + this->patternUnits_set = FALSE; + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_PATTERNCONTENTUNITS: + if (value) { + if (!strcmp (value, "userSpaceOnUse")) { + this->patternContentUnits = SP_PATTERN_UNITS_USERSPACEONUSE; + } else { + this->patternContentUnits = SP_PATTERN_UNITS_OBJECTBOUNDINGBOX; + } + + this->patternContentUnits_set = TRUE; + } else { + this->patternContentUnits_set = FALSE; + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_PATTERNTRANSFORM: { + Geom::Affine t; + + if (value && sp_svg_transform_read (value, &t)) { + this->patternTransform = t; + this->patternTransform_set = TRUE; + } else { + this->patternTransform = Geom::identity(); + this->patternTransform_set = FALSE; + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + } + case SP_ATTR_X: + this->x.readOrUnset(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_Y: + this->y.readOrUnset(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_WIDTH: + this->width.readOrUnset(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_HEIGHT: + this->height.readOrUnset(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_VIEWBOX: { + /* fixme: Think (Lauris) */ + double x, y, width, height; + char *eptr; + + if (value) { + eptr = (gchar *) value; + x = g_ascii_strtod (eptr, &eptr); + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + + y = g_ascii_strtod (eptr, &eptr); + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + + width = g_ascii_strtod (eptr, &eptr); + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + + height = g_ascii_strtod (eptr, &eptr); + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + + if ((width > 0) && (height > 0)) { + this->viewBox = Geom::Rect::from_xywh(x, y, width, height); + this->viewBox_set = TRUE; + } else { + this->viewBox_set = FALSE; + } + } else { + this->viewBox_set = FALSE; + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + break; + } + case SP_ATTR_XLINK_HREF: + if ( value && this->href && ( strcmp(value, this->href) == 0 ) ) { + /* Href unchanged, do nothing. */ + } else { + g_free(this->href); + this->href = NULL; + + if (value) { + // First, set the href field; it's only used in the "unchanged" check above. + this->href = g_strdup(value); + // Now do the attaching, which emits the changed signal. + if (value) { + try { + this->ref->attach(Inkscape::URI(value)); + } catch (Inkscape::BadURIException &e) { + g_warning("%s", e.what()); + this->ref->detach(); + } + } else { + this->ref->detach(); + } + } + } + break; + + default: + SPPaintServer::set(key, value); + break; + } } + /* TODO: do we need a ::remove_child handler? */ /* fixme: We need ::order_changed handler too (Lauris) */ @@ -265,58 +266,62 @@ static GSList *pattern_getchildren(SPPattern *pat) for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->firstChild()) { // find the first one with children - for (SPObject *child = pat->firstChild() ; child ; child = child->getNext() ) { - l = g_slist_prepend (l, child); + for (SPObject *child = pat->firstChild() ; child ; child = child->getNext() ) { + l = g_slist_prepend (l, child); + } + break; // do not go further up the chain if children are found } - break; // do not go further up the chain if children are found - } } - return l; + return l; } -static void -sp_pattern_update (SPObject *object, SPCtx *ctx, unsigned int flags) -{ - SPPattern *pat = SP_PATTERN (object); +void SPPattern::update(SPCtx* ctx, unsigned int flags) { + if (flags & SP_OBJECT_MODIFIED_FLAG) { + flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; + } - if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; - flags &= SP_OBJECT_MODIFIED_CASCADE; + flags &= SP_OBJECT_MODIFIED_CASCADE; - GSList *l = pattern_getchildren (pat); - l = g_slist_reverse (l); + GSList *l = pattern_getchildren (this); + l = g_slist_reverse (l); - while (l) { - SPObject *child = SP_OBJECT (l->data); - sp_object_ref (child, NULL); - l = g_slist_remove (l, child); - if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { - child->updateDisplay(ctx, flags); - } - sp_object_unref (child, NULL); - } + while (l) { + SPObject *child = SP_OBJECT (l->data); + + sp_object_ref (child, NULL); + l = g_slist_remove (l, child); + + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { + child->updateDisplay(ctx, flags); + } + + sp_object_unref (child, NULL); + } } -static void -sp_pattern_modified (SPObject *object, guint flags) -{ - SPPattern *pat = SP_PATTERN (object); +void SPPattern::modified(unsigned int flags) { + if (flags & SP_OBJECT_MODIFIED_FLAG) { + flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; + } - if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; - flags &= SP_OBJECT_MODIFIED_CASCADE; + flags &= SP_OBJECT_MODIFIED_CASCADE; - GSList *l = pattern_getchildren (pat); - l = g_slist_reverse (l); + GSList *l = pattern_getchildren (this); + l = g_slist_reverse (l); - while (l) { - SPObject *child = SP_OBJECT (l->data); - sp_object_ref (child, NULL); - l = g_slist_remove (l, child); - if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { - child->emitModified(flags); - } - sp_object_unref (child, NULL); - } + while (l) { + SPObject *child = SP_OBJECT (l->data); + + sp_object_ref (child, NULL); + l = g_slist_remove (l, child); + + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { + child->emitModified(flags); + } + + sp_object_unref (child, NULL); + } } /** @@ -325,12 +330,13 @@ Gets called when the pattern is reattached to another <pattern> static void pattern_ref_changed(SPObject *old_ref, SPObject *ref, SPPattern *pat) { - if (old_ref) { - pat->modified_connection.disconnect(); - } - if (SP_IS_PATTERN (ref)) { - pat->modified_connection = ref->connectModified(sigc::bind<2>(sigc::ptr_fun(&pattern_ref_modified), pat)); - } + if (old_ref) { + pat->modified_connection.disconnect(); + } + + if (SP_IS_PATTERN (ref)) { + pat->modified_connection = ref->connectModified(sigc::bind<2>(sigc::ptr_fun(&pattern_ref_modified), pat)); + } pattern_ref_modified (ref, 0, pat); } @@ -570,23 +576,18 @@ static bool pattern_hasItemChildren (SPPattern const *pat) return hasChildren; } -static cairo_pattern_t * -sp_pattern_create_pattern(SPPaintServer *ps, - cairo_t *base_ct, - Geom::OptRect const &bbox, - double opacity) -{ - SPPattern *pat = SP_PATTERN (ps); - +cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &bbox, double opacity) { bool needs_opacity = (1.0 - opacity) >= 1e-3; bool visible = opacity >= 1e-3; - if (!visible) + if (!visible) { return NULL; + } /* Show items */ SPPattern *shown = NULL; - for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { + + for (SPPattern *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { // find the first one with item children if (pat_i && SP_IS_OBJECT(pat_i) && pattern_hasItemChildren(pat_i)) { shown = pat_i; @@ -616,13 +617,13 @@ sp_pattern_create_pattern(SPPaintServer *ps, // viewBox to pattern server Geom::Affine vb2ps = Geom::identity(); - if (shown->viewBox_set) { - Geom::Rect vb = *pattern_viewBox(shown); - gdouble tmp_x = pattern_width (shown) / vb.width(); - gdouble tmp_y = pattern_height (shown) / vb.height(); + if (this->viewBox_set) { + Geom::Rect vb = *pattern_viewBox(this); + gdouble tmp_x = pattern_width (this) / vb.width(); + gdouble tmp_y = pattern_height (this) / vb.height(); // FIXME: preserveAspectRatio must be taken into account here too! - vb2ps = Geom::Affine(tmp_x, 0.0, 0.0, tmp_y, pattern_x(shown) - vb.left() * tmp_x, pattern_y(shown) - vb.top() * tmp_y); + vb2ps = Geom::Affine(tmp_x, 0.0, 0.0, tmp_y, pattern_x(this) - vb.left() * tmp_x, pattern_y(this) - vb.top() * tmp_y); } // We must determine the size and scaling of the pattern at the time it is displayed and render @@ -630,19 +631,19 @@ sp_pattern_create_pattern(SPPaintServer *ps, // Pattern server to user Geom::Affine ps2user; - ps2user = pattern_patternTransform(pat); - if (!pat->viewBox_set && pattern_patternContentUnits (pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { + ps2user = pattern_patternTransform(this); + if (!this->viewBox_set && pattern_patternContentUnits (this) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { /* BBox to user coordinate system */ Geom::Affine bbox2user (bbox->width(), 0.0, 0.0, bbox->height(), bbox->left(), bbox->top()); ps2user *= bbox2user; } - ps2user = Geom::Translate (pattern_x (pat), pattern_y (pat)) * ps2user; + ps2user = Geom::Translate (pattern_x (this), pattern_y (this)) * ps2user; // Pattern size in pattern space - Geom::Rect pattern_tile = Geom::Rect::from_xywh(pattern_x(pat), pattern_y(pat), - pattern_width(pat), pattern_height(pat)); + Geom::Rect pattern_tile = Geom::Rect::from_xywh(pattern_x(this), pattern_y(this), + pattern_width(this), pattern_height(this)); - if (pattern_patternUnits(pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { + if (pattern_patternUnits(this) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { // interpret x, y, width, height in relation to bbox Geom::Affine bbox2user(bbox->width(), 0.0, 0.0, bbox->height(), bbox->left(), bbox->top()); pattern_tile = pattern_tile * bbox2user; diff --git a/src/sp-pattern.h b/src/sp-pattern.h index bcf8dd520..4e3657ccf 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -16,15 +16,11 @@ #include <gtk/gtk.h> #include "sp-item.h" -#define SP_TYPE_PATTERN (sp_pattern_get_type ()) -#define SP_PATTERN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_PATTERN, SPPattern)) -#define SP_PATTERN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SP_TYPE_PATTERN, SPPatternClass)) -#define SP_IS_PATTERN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_PATTERN)) -#define SP_IS_PATTERN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_PATTERN)) -GType sp_pattern_get_type (void); +#define SP_PATTERN(obj) (dynamic_cast<SPPattern*>((SPObject*)obj)) +#define SP_IS_PATTERN(obj) (dynamic_cast<const SPPattern*>((SPObject*)obj) != NULL) -struct SPPattern; +class SPPatternReference; #include "svg/svg-length.h" #include "sp-paint-server.h" @@ -34,25 +30,11 @@ struct SPPattern; #include <sigc++/connection.h> -class SPPatternReference : public Inkscape::URIReference { +class SPPattern : public SPPaintServer { public: - SPPatternReference (SPObject *obj) : URIReference(obj) {} - SPPattern *getObject() const { - return reinterpret_cast<SPPattern *>(URIReference::getObject()); - } - -protected: - virtual bool _acceptObject(SPObject *obj) const { - return SP_IS_PATTERN (obj); - } -}; + SPPattern(); + virtual ~SPPattern(); -enum { - SP_PATTERN_UNITS_USERSPACEONUSE, - SP_PATTERN_UNITS_OBJECTBOUNDINGBOX -}; - -struct SPPattern : public SPPaintServer { /* Reference (href) */ gchar *href; SPPatternReference *ref; @@ -75,10 +57,34 @@ struct SPPattern : public SPPaintServer { guint viewBox_set : 1; sigc::connection modified_connection; + + virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity); + +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + virtual void set(unsigned int key, const gchar* value); + virtual void update(SPCtx* ctx, unsigned int flags); + virtual void modified(unsigned int flags); +}; + + +class SPPatternReference : public Inkscape::URIReference { +public: + SPPatternReference (SPObject *obj) : URIReference(obj) {} + SPPattern *getObject() const { + return reinterpret_cast<SPPattern *>(URIReference::getObject()); + } + +protected: + virtual bool _acceptObject(SPObject *obj) const { + return SP_IS_PATTERN (obj); + } }; -struct SPPatternClass { - SPPaintServerClass parent_class; +enum { + SP_PATTERN_UNITS_USERSPACEONUSE, + SP_PATTERN_UNITS_OBJECTBOUNDINGBOX }; guint pattern_users (SPPattern *pattern); diff --git a/src/sp-polygon.cpp b/src/sp-polygon.cpp index 94000cc9d..983a738ce 100644 --- a/src/sp-polygon.cpp +++ b/src/sp-polygon.cpp @@ -25,40 +25,30 @@ #include "xml/repr.h" #include "document.h" -static void sp_polygon_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static Inkscape::XML::Node *sp_polygon_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); +#include "sp-factory.h" -static gchar *sp_polygon_description(SPItem *item); +namespace { + SPObject* createPolygon() { + return new SPPolygon(); + } -G_DEFINE_TYPE(SPPolygon, sp_polygon, SP_TYPE_SHAPE); - -static void sp_polygon_class_init(SPPolygonClass *pc) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) pc; - SPItemClass *item_class = (SPItemClass *) pc; - - sp_object_class->build = sp_polygon_build; - sp_object_class->write = sp_polygon_write; - sp_object_class->set = sp_polygon_set; + bool polygonRegistered = SPFactory::instance().registerObject("svg:polygon", createPolygon); +} - item_class->description = sp_polygon_description; +SPPolygon::SPPolygon() : SPShape() { } -static void sp_polygon_init(SPPolygon */*polygon*/) -{ - /* Nothing here */ +SPPolygon::~SPPolygon() { } -static void sp_polygon_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_polygon_parent_class)->build) { - ((SPObjectClass *) sp_polygon_parent_class)->build(object, document, repr); - } +void SPPolygon::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPPolygon* object = this; + + SPShape::build(document, repr); object->readAttr( "points" ); } - /* * sp_svg_write_polygon: Write points attribute for polygon tag. * pathv may only contain paths with only straight line segments @@ -82,25 +72,21 @@ static gchar *sp_svg_write_polygon(Geom::PathVector const & pathv) return g_strdup(os.str().c_str()); } -static Inkscape::XML::Node *sp_polygon_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPShape *shape = SP_SHAPE(object); +Inkscape::XML::Node* SPPolygon::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { // Tolerable workaround: we need to update the object's curve before we set points= // because it's out of sync when e.g. some extension attrs of the polygon or star are changed in XML editor - shape->setShape(); + this->set_shape(); if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:polygon"); } /* We can safely write points here, because all subclasses require it too (Lauris) */ - gchar *str = sp_svg_write_polygon(shape->_curve->get_pathvector()); + gchar *str = sp_svg_write_polygon(this->_curve->get_pathvector()); repr->setAttribute("points", str); g_free(str); - if (((SPObjectClass *) (sp_polygon_parent_class))->write) { - ((SPObjectClass *) (sp_polygon_parent_class))->write(object, xml_doc, repr, flags); - } + SPShape::write(xml_doc, repr, flags); return repr; } @@ -118,19 +104,17 @@ static gboolean polygon_get_value(gchar const **p, gdouble *v) gchar *e = NULL; *v = g_ascii_strtod(*p, &e); + if (e == *p) { return false; } *p = e; + return true; } - -void sp_polygon_set(SPObject *object, unsigned int key, const gchar *value) -{ - SPPolygon *polygon = SP_POLYGON(object); - +void SPPolygon::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_POINTS: { if (!value) { @@ -138,6 +122,7 @@ void sp_polygon_set(SPObject *object, unsigned int key, const gchar *value) * http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing. */ break; } + SPCurve *curve = new SPCurve(); gboolean hascpt = FALSE; @@ -146,11 +131,13 @@ void sp_polygon_set(SPObject *object, unsigned int key, const gchar *value) while (TRUE) { gdouble x; + if (!polygon_get_value(&cptr, &x)) { break; } gdouble y; + if (!polygon_get_value(&cptr, &y)) { /* fixme: It is an error for an odd number of points to be specified. We * should display the points up to now (as we currently do, though perhaps @@ -180,21 +167,19 @@ void sp_polygon_set(SPObject *object, unsigned int key, const gchar *value) * a single-point polygon in SPCurve. TODO: add a testcase with only one coordinate pair */ curve->closepath(); } - (SP_SHAPE(polygon))->setCurve(curve, TRUE); + + this->setCurve(curve, TRUE); curve->unref(); break; } default: - if (((SPObjectClass *) sp_polygon_parent_class)->set) { - ((SPObjectClass *) sp_polygon_parent_class)->set(object, key, value); - } + SPShape::set(key, value); break; } } -static gchar *sp_polygon_description(SPItem */*item*/) -{ - return g_strdup(_("<b>Polygon</b>")); +gchar* SPPolygon::description() { + return g_strdup(_("<b>Polygon</b>")); } /* diff --git a/src/sp-polygon.h b/src/sp-polygon.h index 3ea91be76..f9c93ac8f 100644 --- a/src/sp-polygon.h +++ b/src/sp-polygon.h @@ -15,20 +15,20 @@ #include "sp-shape.h" -#define SP_TYPE_POLYGON (sp_polygon_get_type ()) -#define SP_POLYGON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_POLYGON, SPPolygon)) -#define SP_POLYGON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_POLYGON, SPPolygonClass)) -#define SP_IS_POLYGON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_POLYGON)) -#define SP_IS_POLYGON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_POLYGON)) -struct SPPolygon : public SPShape { -}; +#define SP_POLYGON(obj) (dynamic_cast<SPPolygon*>((SPObject*)obj)) +#define SP_IS_POLYGON(obj) (dynamic_cast<const SPPolygon*>((SPObject*)obj) != NULL) -struct SPPolygonClass { - SPShapeClass parent_class; -}; +class SPPolygon : public SPShape { +public: + SPPolygon(); + virtual ~SPPolygon(); -GType sp_polygon_get_type (void); + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + virtual void set(unsigned int key, gchar const* value); + virtual gchar* description(); +}; // made 'public' so that SPCurve can set it as friend: void sp_polygon_set(SPObject *object, unsigned int key, const gchar *value); diff --git a/src/sp-polyline.cpp b/src/sp-polyline.cpp index 2922b66ed..1de5492cd 100644 --- a/src/sp-polyline.cpp +++ b/src/sp-polyline.cpp @@ -20,47 +20,29 @@ #include "xml/repr.h" #include "document.h" -static void sp_polyline_build(SPObject * object, SPDocument * document, Inkscape::XML::Node * repr); -static void sp_polyline_set(SPObject *object, unsigned int key, const gchar *value); -static Inkscape::XML::Node* sp_polyline_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static gchar* sp_polyline_get_description(SPItem * item); +#include "sp-factory.h" +namespace { + SPObject* createPolyLine() { + return new SPPolyLine(); + } -G_DEFINE_TYPE(SPPolyLine, sp_polyline, SP_TYPE_SHAPE); - -static void -sp_polyline_class_init(SPPolyLineClass *klass) -{ - SPObjectClass * sp_object_class = (SPObjectClass *) klass; - SPItemClass * item_class = (SPItemClass *) klass; - - sp_object_class->build = sp_polyline_build; - sp_object_class->set = sp_polyline_set; - sp_object_class->write = sp_polyline_write; + bool polyLineRegistered = SPFactory::instance().registerObject("svg:polyline", createPolyLine); +} - item_class->description = sp_polyline_get_description; +SPPolyLine::SPPolyLine() : SPShape() { } -static void -sp_polyline_init(SPPolyLine * /*polyline*/) -{ +SPPolyLine::~SPPolyLine() { } -static void -sp_polyline_build(SPObject * object, SPDocument * document, Inkscape::XML::Node * repr) -{ - if (((SPObjectClass *) sp_polyline_parent_class)->build) { - ((SPObjectClass *) sp_polyline_parent_class)->build (object, document, repr); - } +void SPPolyLine::build(SPDocument * document, Inkscape::XML::Node * repr) { + SPShape::build(document, repr); - object->readAttr( "points" ); + this->readAttr("points"); } -static void -sp_polyline_set(SPObject *object, unsigned int key, const gchar *value) -{ - SPPolyLine *polyline = SP_POLYLINE(object); - +void SPPolyLine::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_POINTS: { SPCurve * curve; @@ -68,7 +50,10 @@ sp_polyline_set(SPObject *object, unsigned int key, const gchar *value) char * eptr; gboolean hascpt; - if (!value) break; + if (!value) { + break; + } + curve = new SPCurve (); hascpt = FALSE; @@ -81,20 +66,35 @@ sp_polyline_set(SPObject *object, unsigned int key, const gchar *value) while (*cptr != '\0' && (*cptr == ',' || *cptr == '\x20' || *cptr == '\x9' || *cptr == '\xD' || *cptr == '\xA')) { cptr++; } - if (!*cptr) break; + + if (!*cptr) { + break; + } x = g_ascii_strtod (cptr, &eptr); - if (eptr == cptr) break; + + if (eptr == cptr) { + break; + } + cptr = eptr; while (*cptr != '\0' && (*cptr == ',' || *cptr == '\x20' || *cptr == '\x9' || *cptr == '\xD' || *cptr == '\xA')) { cptr++; } - if (!*cptr) break; + + if (!*cptr) { + break; + } y = g_ascii_strtod (cptr, &eptr); - if (eptr == cptr) break; + + if (eptr == cptr) { + break; + } + cptr = eptr; + if (hascpt) { curve->lineto(x, y); } else { @@ -103,41 +103,32 @@ sp_polyline_set(SPObject *object, unsigned int key, const gchar *value) } } - (SP_SHAPE (polyline))->setCurve (curve, TRUE); + this->setCurve(curve, TRUE); curve->unref(); break; } default: - if (((SPObjectClass *) sp_polyline_parent_class)->set) { - ((SPObjectClass *) sp_polyline_parent_class)->set (object, key, value); - } + SPShape::set(key, value); break; } } -static Inkscape::XML::Node* -sp_polyline_write(SPObject *object, - Inkscape::XML::Document *xml_doc, - Inkscape::XML::Node *repr, - guint flags) -{ +Inkscape::XML::Node* SPPolyLine::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:polyline"); } - if (repr != object->getRepr()) { - repr->mergeFrom(object->getRepr(), "id"); + if (repr != this->getRepr()) { + repr->mergeFrom(this->getRepr(), "id"); } - SP_OBJECT_CLASS(sp_polyline_parent_class)->write (object, xml_doc, repr, flags); + SPShape::write(xml_doc, repr, flags); return repr; } -static gchar* -sp_polyline_get_description(SPItem * /*item*/) -{ - return g_strdup(_("<b>Polyline</b>")); +gchar* SPPolyLine::description() { + return g_strdup(_("<b>Polyline</b>")); } diff --git a/src/sp-polyline.h b/src/sp-polyline.h index 047868692..f8b7e9b49 100644 --- a/src/sp-polyline.h +++ b/src/sp-polyline.h @@ -3,30 +3,19 @@ #include "sp-shape.h" - - -#define SP_TYPE_POLYLINE (sp_polyline_get_type ()) -#define SP_POLYLINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_POLYLINE, SPPolyLine)) -#define SP_POLYLINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_POLYLINE, SPPolyLineClass)) -#define SP_IS_POLYLINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_POLYLINE)) -#define SP_IS_POLYLINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_POLYLINE)) - -class SPPolyLine; -class SPPolyLineClass; - -GType sp_polyline_get_type (void) G_GNUC_CONST; +#define SP_POLYLINE(obj) (dynamic_cast<SPPolyLine*>((SPObject*)obj)) +#define SP_IS_POLYLINE(obj) (dynamic_cast<const SPPolyLine*>((SPObject*)obj) != NULL) class SPPolyLine : public SPShape { -private: - friend class SPPolyLineClass; -}; - -class SPPolyLineClass { public: - SPShapeClass parent_class; + SPPolyLine(); + virtual ~SPPolyLine(); + + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void set(unsigned int key, gchar const* value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); -private: - friend class SPPolyLine; + virtual gchar* description(); }; #endif // SEEN_SP_POLYLINE_H diff --git a/src/sp-radial-gradient-fns.h b/src/sp-radial-gradient-fns.h deleted file mode 100644 index 43ed7bf03..000000000 --- a/src/sp-radial-gradient-fns.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef SP_RADIAL_GRADIENT_FNS_H -#define SP_RADIAL_GRADIENT_FNS_H - -/** \file - * Macros and fn definitions related to radial gradients. - */ - -#include <glib-object.h> - -namespace Inkscape { -namespace XML { -class Node; -} -} - -struct SPRadialGradient; - -#define SP_TYPE_RADIALGRADIENT (sp_radialgradient_get_type()) -#define SP_RADIALGRADIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_RADIALGRADIENT, SPRadialGradient)) -#define SP_RADIALGRADIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_RADIALGRADIENT, SPRadialGradientClass)) -#define SP_IS_RADIALGRADIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_RADIALGRADIENT)) -#define SP_IS_RADIALGRADIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_RADIALGRADIENT)) - - -GType sp_radialgradient_get_type(); - -void sp_radialgradient_set_position(SPRadialGradient *rg, gdouble cx, gdouble cy, gdouble fx, gdouble fy, gdouble r); - -#endif /* !SP_RADIAL_GRADIENT_FNS_H */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-radial-gradient.cpp b/src/sp-radial-gradient.cpp new file mode 100644 index 000000000..c8bf5db81 --- /dev/null +++ b/src/sp-radial-gradient.cpp @@ -0,0 +1,190 @@ +#include "sp-radial-gradient.h" + +#include "attributes.h" +#include "xml/repr.h" + +#include "2geom/transforms.h" + +#include "sp-factory.h" + +namespace { + SPObject* createRadialGradient() { + return new SPRadialGradient(); + } + + bool radialGradientRegistered = SPFactory::instance().registerObject("svg:radialGradient", createRadialGradient); +} + +/* + * Radial Gradient + */ +SPRadialGradient::SPRadialGradient() : SPGradient() { + this->cx.unset(SVGLength::PERCENT, 0.5, 0.5); + this->cy.unset(SVGLength::PERCENT, 0.5, 0.5); + this->r.unset(SVGLength::PERCENT, 0.5, 0.5); + this->fx.unset(SVGLength::PERCENT, 0.5, 0.5); + this->fy.unset(SVGLength::PERCENT, 0.5, 0.5); +} + +SPRadialGradient::~SPRadialGradient() { +} + +/** + * Set radial gradient attributes from associated repr. + */ +void SPRadialGradient::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPGradient::build(document, repr); + + this->readAttr( "cx" ); + this->readAttr( "cy" ); + this->readAttr( "r" ); + this->readAttr( "fx" ); + this->readAttr( "fy" ); +} + +/** + * Set radial gradient attribute. + */ +void SPRadialGradient::set(unsigned key, gchar const *value) { + switch (key) { + case SP_ATTR_CX: + if (!this->cx.read(value)) { + this->cx.unset(SVGLength::PERCENT, 0.5, 0.5); + } + + if (!this->fx._set) { + this->fx.value = this->cx.value; + this->fx.computed = this->cx.computed; + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_CY: + if (!this->cy.read(value)) { + this->cy.unset(SVGLength::PERCENT, 0.5, 0.5); + } + + if (!this->fy._set) { + this->fy.value = this->cy.value; + this->fy.computed = this->cy.computed; + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_R: + if (!this->r.read(value)) { + this->r.unset(SVGLength::PERCENT, 0.5, 0.5); + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_FX: + if (!this->fx.read(value)) { + this->fx.unset(this->cx.unit, this->cx.value, this->cx.computed); + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_FY: + if (!this->fy.read(value)) { + this->fy.unset(this->cy.unit, this->cy.value, this->cy.computed); + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + default: + SPGradient::set(key, value); + break; + } +} + +/** + * Write radial gradient attributes to associated repr. + */ +Inkscape::XML::Node* SPRadialGradient::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { + if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { + repr = xml_doc->createElement("svg:radialGradient"); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->cx._set) { + sp_repr_set_svg_double(repr, "cx", this->cx.computed); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->cy._set) { + sp_repr_set_svg_double(repr, "cy", this->cy.computed); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->r._set) { + sp_repr_set_svg_double(repr, "r", this->r.computed); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->fx._set) { + sp_repr_set_svg_double(repr, "fx", this->fx.computed); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->fy._set) { + sp_repr_set_svg_double(repr, "fy", this->fy.computed); + } + + SPGradient::write(xml_doc, repr, flags); + + return repr; +} + +cairo_pattern_t* SPRadialGradient::pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity) { + this->ensureVector(); + + Geom::Point focus(this->fx.computed, this->fy.computed); + Geom::Point center(this->cx.computed, this->cy.computed); + + double radius = this->r.computed; + double scale = 1.0; + double tolerance = cairo_get_tolerance(ct); + + // NOTE: SVG2 will allow the use of a focus circle which can + // have its center outside the first circle. + + // code below suggested by Cairo devs to overcome tolerance problems + // more: https://bugs.freedesktop.org/show_bug.cgi?id=40918 + + // Corrected for + // https://bugs.launchpad.net/inkscape/+bug/970355 + + Geom::Affine gs2user = this->gradientTransform; + Geom::Scale gs2user_scale; + + if (this->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX && bbox) { + Geom::Affine bbox2user(bbox->width(), 0, 0, bbox->height(), bbox->left(), bbox->top()); + gs2user *= bbox2user; + gs2user_scale = Geom::Scale( gs2user[0], gs2user[3] ); + } + + Geom::Point d = focus - center; + Geom::Point d_user = d * gs2user_scale; + Geom::Point r_user( radius, 0 ); + r_user *= gs2user_scale; + + if (d_user.length() + tolerance > r_user.length()) { + scale = r_user.length() / d_user.length(); + double dx = d_user.x(), dy = d_user.y(); + cairo_user_to_device_distance(ct, &dx, &dy); + + if (!Geom::are_near(dx, 0, tolerance) || !Geom::are_near(dy, 0, tolerance)) + { + scale *= 1.0 - 2.0 * tolerance / hypot(dx, dy); + } + } + + cairo_pattern_t *cp = cairo_pattern_create_radial( + scale * d.x() + center.x(), scale * d.y() + center.y(), 0, + center.x(), center.y(), radius); + + sp_gradient_pattern_common_setup(cp, this, bbox, opacity); + + return cp; +} diff --git a/src/sp-radial-gradient.h b/src/sp-radial-gradient.h index b46b9fff3..42ff109aa 100644 --- a/src/sp-radial-gradient.h +++ b/src/sp-radial-gradient.h @@ -8,22 +8,29 @@ #include <glib.h> #include "sp-gradient.h" #include "svg/svg-length.h" -#include "sp-radial-gradient-fns.h" + +#define SP_RADIALGRADIENT(obj) (dynamic_cast<SPRadialGradient*>((SPObject*)obj)) +#define SP_IS_RADIALGRADIENT(obj) (dynamic_cast<const SPRadialGradient*>((SPObject*)obj) != NULL) /** Radial gradient. */ -struct SPRadialGradient : public SPGradient { +class SPRadialGradient : public SPGradient { +public: + SPRadialGradient(); + virtual ~SPRadialGradient(); + SVGLength cx; SVGLength cy; SVGLength r; SVGLength fx; SVGLength fy; -}; -/// The SPRadialGradient vtable. -struct SPRadialGradientClass { - SPGradientClass parent_class; -}; + virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity); +protected: + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void set(unsigned key, gchar const *value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); +}; #endif /* !SP_RADIAL_GRADIENT_H */ diff --git a/src/sp-rect.cpp b/src/sp-rect.cpp index 747a988a9..519b7ba6e 100644 --- a/src/sp-rect.cpp +++ b/src/sp-rect.cpp @@ -31,203 +31,167 @@ #define noRECT_VERBOSE -static void sp_rect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_rect_set(SPObject *object, unsigned key, gchar const *value); -static void sp_rect_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_rect_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -static gchar *sp_rect_description(SPItem *item); -static Geom::Affine sp_rect_set_transform(SPItem *item, Geom::Affine const &xform); -static void sp_rect_convert_to_guides(SPItem *item); - -static void sp_rect_set_shape(SPShape *shape); -static void sp_rect_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); - -G_DEFINE_TYPE(SPRect, sp_rect, SP_TYPE_SHAPE); - -static void -sp_rect_class_init(SPRectClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPItemClass *item_class = (SPItemClass *) klass; - SPShapeClass *shape_class = (SPShapeClass *) klass; - - sp_object_class->build = sp_rect_build; - sp_object_class->write = sp_rect_write; - sp_object_class->set = sp_rect_set; - sp_object_class->update = sp_rect_update; - - item_class->description = sp_rect_description; - item_class->set_transform = sp_rect_set_transform; - item_class->convert_to_guides = sp_rect_convert_to_guides; - item_class->snappoints = sp_rect_snappoints; //override the default sp_shape_snappoints; see sp_rect_snappoints for details - - shape_class->set_shape = sp_rect_set_shape; +#include "sp-factory.h" + +namespace { + SPObject* createRect() { + return new SPRect(); + } + + bool rectRegistered = SPFactory::instance().registerObject("svg:rect", createRect); } -static void -sp_rect_init(SPRect */*rect*/) -{ - /* Initializing to zero is automatic */ - /* sp_svg_length_unset(&rect->x, SP_SVG_UNIT_NONE, 0.0, 0.0); */ - /* sp_svg_length_unset(&rect->y, SP_SVG_UNIT_NONE, 0.0, 0.0); */ - /* sp_svg_length_unset(&rect->width, SP_SVG_UNIT_NONE, 0.0, 0.0); */ - /* sp_svg_length_unset(&rect->height, SP_SVG_UNIT_NONE, 0.0, 0.0); */ - /* sp_svg_length_unset(&rect->rx, SP_SVG_UNIT_NONE, 0.0, 0.0); */ - /* sp_svg_length_unset(&rect->ry, SP_SVG_UNIT_NONE, 0.0, 0.0); */ + +SPRect::SPRect() : SPShape() { } -static void -sp_rect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if ((SP_OBJECT_CLASS(sp_rect_parent_class))->build) - (SP_OBJECT_CLASS(sp_rect_parent_class))->build(object, document, repr); - - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "width" ); - object->readAttr( "height" ); - object->readAttr( "rx" ); - object->readAttr( "ry" ); +SPRect::~SPRect() { } -static void -sp_rect_set(SPObject *object, unsigned key, gchar const *value) -{ - SPRect *rect = SP_RECT(object); +void SPRect::build(SPDocument* doc, Inkscape::XML::Node* repr) { + SPShape::build(doc, repr); + + this->readAttr("x"); + this->readAttr("y"); + this->readAttr("width"); + this->readAttr("height"); + this->readAttr("rx"); + this->readAttr("ry"); +} +void SPRect::set(unsigned key, gchar const *value) { /* fixme: We need real error processing some time */ switch (key) { case SP_ATTR_X: - rect->x.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->x.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_Y: - rect->y.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->y.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_WIDTH: - if (!rect->width.read(value) || rect->width.value < 0.0) { - rect->width.unset(); + if (!this->width.read(value) || this->width.value < 0.0) { + this->width.unset(); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_HEIGHT: - if (!rect->height.read(value) || rect->height.value < 0.0) { - rect->height.unset(); + if (!this->height.read(value) || this->height.value < 0.0) { + this->height.unset(); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_RX: - if (!rect->rx.read(value) || rect->rx.value <= 0.0) { - rect->rx.unset(); + if (!this->rx.read(value) || this->rx.value <= 0.0) { + this->rx.unset(); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_RY: - if (!rect->ry.read(value) || rect->ry.value <= 0.0) { - rect->ry.unset(); + if (!this->ry.read(value) || this->ry.value <= 0.0) { + this->ry.unset(); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + default: - if ((SP_OBJECT_CLASS(sp_rect_parent_class))->set) - (SP_OBJECT_CLASS(sp_rect_parent_class))->set(object, key, value); + SPShape::set(key, value); break; } } -static void -sp_rect_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPRect::update(SPCtx* ctx, unsigned int flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - SPRect *rect = (SPRect *) object; - SPStyle *style = object->style; SPItemCtx const *ictx = (SPItemCtx const *) ctx; + double const w = ictx->viewport.width(); double const h = ictx->viewport.height(); double const em = style->font_size.computed; double const ex = 0.5 * em; // fixme: get x height from pango or libnrtype. - rect->x.update(em, ex, w); - rect->y.update(em, ex, h); - rect->width.update(em, ex, w); - rect->height.update(em, ex, h); - rect->rx.update(em, ex, w); - rect->ry.update(em, ex, h); - ((SPShape *) object)->setShape(); + + this->x.update(em, ex, w); + this->y.update(em, ex, h); + this->width.update(em, ex, w); + this->height.update(em, ex, h); + this->rx.update(em, ex, w); + this->ry.update(em, ex, h); + this->set_shape(); + flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B; // since we change the description, it's not a "just translation" anymore } - if ((SP_OBJECT_CLASS(sp_rect_parent_class))->update) - (SP_OBJECT_CLASS(sp_rect_parent_class))->update(object, ctx, flags); + SPShape::update(ctx, flags); } -static Inkscape::XML::Node * -sp_rect_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPRect *rect = SP_RECT(object); - +Inkscape::XML::Node * SPRect::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:rect"); } - sp_repr_set_svg_double(repr, "width", rect->width.computed); - sp_repr_set_svg_double(repr, "height", rect->height.computed); - if (rect->rx._set) sp_repr_set_svg_double(repr, "rx", rect->rx.computed); - if (rect->ry._set) sp_repr_set_svg_double(repr, "ry", rect->ry.computed); - sp_repr_set_svg_double(repr, "x", rect->x.computed); - sp_repr_set_svg_double(repr, "y", rect->y.computed); + sp_repr_set_svg_double(repr, "width", this->width.computed); + sp_repr_set_svg_double(repr, "height", this->height.computed); + + if (this->rx._set) { + sp_repr_set_svg_double(repr, "rx", this->rx.computed); + } + + if (this->ry._set) { + sp_repr_set_svg_double(repr, "ry", this->ry.computed); + } - sp_rect_set_shape ((SPShape *) rect); // evaluate SPCurve + sp_repr_set_svg_double(repr, "x", this->x.computed); + sp_repr_set_svg_double(repr, "y", this->y.computed); - if ((SP_OBJECT_CLASS(sp_rect_parent_class))->write) - (SP_OBJECT_CLASS(sp_rect_parent_class))->write(object, xml_doc, repr, flags); + this->set_shape(); // evaluate SPCurve + SPShape::write(xml_doc, repr, flags); return repr; } -static gchar * -sp_rect_description(SPItem *item) -{ - g_return_val_if_fail(SP_IS_RECT(item), NULL); - - return g_strdup(_("<b>Rectangle</b>")); +gchar* SPRect::description() { + return g_strdup(_("<b>Rectangle</b>")); } #define C1 0.554 -static void -sp_rect_set_shape(SPShape *shape) -{ - SPRect *rect = (SPRect *) shape; - - if ((rect->height.computed < 1e-18) || (rect->width.computed < 1e-18)) { - SP_SHAPE(rect)->setCurveInsync( NULL, TRUE); - SP_SHAPE(rect)->setCurveBeforeLPE( NULL ); +void SPRect::set_shape() { + if ((this->height.computed < 1e-18) || (this->width.computed < 1e-18)) { + this->setCurveInsync( NULL, TRUE); + this->setCurveBeforeLPE( NULL ); return; } SPCurve *c = new SPCurve(); - double const x = rect->x.computed; - double const y = rect->y.computed; - double const w = rect->width.computed; - double const h = rect->height.computed; + double const x = this->x.computed; + double const y = this->y.computed; + double const w = this->width.computed; + double const h = this->height.computed; double const w2 = w / 2; double const h2 = h / 2; - double const rx = std::min(( rect->rx._set - ? rect->rx.computed - : ( rect->ry._set - ? rect->ry.computed + double const rx = std::min(( this->rx._set + ? this->rx.computed + : ( this->ry._set + ? this->ry.computed : 0.0 ) ), - .5 * rect->width.computed); - double const ry = std::min(( rect->ry._set - ? rect->ry.computed - : ( rect->rx._set - ? rect->rx.computed + .5 * this->width.computed); + double const ry = std::min(( this->ry._set + ? this->ry.computed + : ( this->rx._set + ? this->rx.computed : 0.0 ) ), - .5 * rect->height.computed); + .5 * this->height.computed); /* TODO: Handle negative rx or ry as per * http://www.w3.org/TR/SVG11/shapes.html#RectElementRXAttribute once Inkscape has proper error * handling (see http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing). @@ -238,14 +202,30 @@ sp_rect_set_shape(SPShape *shape) */ if ((rx > 1e-18) && (ry > 1e-18)) { c->moveto(x + rx, y); - if (rx < w2) c->lineto(x + w - rx, y); - c->curveto(x + w - rx * (1 - C1), y, x + w, y + ry * (1 - C1), x + w, y + ry); - if (ry < h2) c->lineto(x + w, y + h - ry); - c->curveto(x + w, y + h - ry * (1 - C1), x + w - rx * (1 - C1), y + h, x + w - rx, y + h); - if (rx < w2) c->lineto(x + rx, y + h); - c->curveto(x + rx * (1 - C1), y + h, x, y + h - ry * (1 - C1), x, y + h - ry); - if (ry < h2) c->lineto(x, y + ry); - c->curveto(x, y + ry * (1 - C1), x + rx * (1 - C1), y, x + rx, y); + + if (rx < w2) { + c->lineto(x + w - rx, y); + } + + c->curveto(x + w - rx * (1 - C1), y, x + w, y + ry * (1 - C1), x + w, y + ry); + + if (ry < h2) { + c->lineto(x + w, y + h - ry); + } + + c->curveto(x + w, y + h - ry * (1 - C1), x + w - rx * (1 - C1), y + h, x + w - rx, y + h); + + if (rx < w2) { + c->lineto(x + rx, y + h); + } + + c->curveto(x + rx * (1 - C1), y + h, x, y + h - ry * (1 - C1), x, y + h - ry); + + if (ry < h2) { + c->lineto(x, y + ry); + } + + c->curveto(x, y + ry * (1 - C1), x + rx * (1 - C1), y, x + rx, y); } else { c->moveto(x + 0.0, y + 0.0); c->lineto(x + w, y + 0.0); @@ -254,8 +234,8 @@ sp_rect_set_shape(SPShape *shape) } c->closepath(); - SP_SHAPE(rect)->setCurveInsync( c, TRUE); - SP_SHAPE(rect)->setCurveBeforeLPE( c ); + this->setCurveInsync(c, true); + this->setCurveBeforeLPE(c); // LPE is not applied because result can generally not be represented as SPRect @@ -264,65 +244,45 @@ sp_rect_set_shape(SPShape *shape) /* fixme: Think (Lauris) */ -void -sp_rect_position_set(SPRect *rect, gdouble x, gdouble y, gdouble width, gdouble height) -{ - g_return_if_fail(rect != NULL); - g_return_if_fail(SP_IS_RECT(rect)); +void SPRect::setPosition(gdouble x, gdouble y, gdouble width, gdouble height) { + this->x.computed = x; + this->y.computed = y; + this->width.computed = width; + this->height.computed = height; - rect->x.computed = x; - rect->y.computed = y; - rect->width.computed = width; - rect->height.computed = height; - - SP_OBJECT(rect)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } -void -sp_rect_set_rx(SPRect *rect, gboolean set, gdouble value) -{ - g_return_if_fail(rect != NULL); - g_return_if_fail(SP_IS_RECT(rect)); +void SPRect::setRx(bool set, gdouble value) { + this->rx._set = set; - rect->rx._set = set; - if (set) rect->rx.computed = value; + if (set) { + this->rx.computed = value; + } - SP_OBJECT(rect)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } -void -sp_rect_set_ry(SPRect *rect, gboolean set, gdouble value) -{ - g_return_if_fail(rect != NULL); - g_return_if_fail(SP_IS_RECT(rect)); +void SPRect::setRy(bool set, gdouble value) { + this->ry._set = set; - rect->ry._set = set; - if (set) rect->ry.computed = value; + if (set) { + this->ry.computed = value; + } - SP_OBJECT(rect)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } -/* - * Initially we'll do: - * Transform x, y, set x, y, clear translation - */ - -/* fixme: Use preferred units somehow (Lauris) */ -/* fixme: Alternately preserve whatever units there are (lauris) */ - -static Geom::Affine -sp_rect_set_transform(SPItem *item, Geom::Affine const &xform) -{ - SPRect *rect = SP_RECT(item); - +Geom::Affine SPRect::set_transform(Geom::Affine const& xform) { /* Calculate rect start in parent coords. */ - Geom::Point pos( Geom::Point(rect->x.computed, rect->y.computed) * xform ); + Geom::Point pos(Geom::Point(this->x.computed, this->y.computed) * xform); /* This function takes care of translation and scaling, we return whatever parts we can't handle. */ Geom::Affine ret(Geom::Affine(xform).withoutTranslation()); gdouble const sw = hypot(ret[0], ret[1]); gdouble const sh = hypot(ret[2], ret[3]); + if (sw > 1e-9) { ret[0] /= sw; ret[1] /= sw; @@ -330,6 +290,7 @@ sp_rect_set_transform(SPItem *item, Geom::Affine const &xform) ret[0] = 1.0; ret[1] = 0.0; } + if (sh > 1e-9) { ret[2] /= sh; ret[3] /= sh; @@ -339,32 +300,34 @@ sp_rect_set_transform(SPItem *item, Geom::Affine const &xform) } /* fixme: Would be nice to preserve units here */ - rect->width = rect->width.computed * sw; - rect->height = rect->height.computed * sh; - if (rect->rx._set) { - rect->rx = rect->rx.computed * sw; + this->width = this->width.computed * sw; + this->height = this->height.computed * sh; + + if (this->rx._set) { + this->rx = this->rx.computed * sw; } - if (rect->ry._set) { - rect->ry = rect->ry.computed * sh; + + if (this->ry._set) { + this->ry = this->ry.computed * sh; } /* Find start in item coords */ pos = pos * ret.inverse(); - rect->x = pos[Geom::X]; - rect->y = pos[Geom::Y]; + this->x = pos[Geom::X]; + this->y = pos[Geom::Y]; - sp_rect_set_shape(rect); + this->set_shape(); // Adjust stroke width - item->adjust_stroke(sqrt(fabs(sw * sh))); + this->adjust_stroke(sqrt(fabs(sw * sh))); // Adjust pattern fill - item->adjust_pattern(xform * ret.inverse()); + this->adjust_pattern(xform * ret.inverse()); // Adjust gradient fill - item->adjust_gradient(xform * ret.inverse()); + this->adjust_gradient(xform * ret.inverse()); - item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); return ret; } @@ -373,163 +336,155 @@ sp_rect_set_transform(SPItem *item, Geom::Affine const &xform) /** Returns the ratio in which the vector from p0 to p1 is stretched by transform */ -static gdouble -vector_stretch(Geom::Point p0, Geom::Point p1, Geom::Affine xform) -{ - if (p0 == p1) +gdouble SPRect::vectorStretch(Geom::Point p0, Geom::Point p1, Geom::Affine xform) { + if (p0 == p1) { return 0; + } + return (Geom::distance(p0 * xform, p1 * xform) / Geom::distance(p0, p1)); } -void -sp_rect_set_visible_rx(SPRect *rect, gdouble rx) -{ +void SPRect::setVisibleRx(gdouble rx) { if (rx == 0) { - rect->rx.computed = 0; - rect->rx._set = false; + this->rx.computed = 0; + this->rx._set = false; } else { - rect->rx.computed = rx / vector_stretch( - Geom::Point(rect->x.computed + 1, rect->y.computed), - Geom::Point(rect->x.computed, rect->y.computed), - rect->transform); - rect->rx._set = true; + this->rx.computed = rx / SPRect::vectorStretch( + Geom::Point(this->x.computed + 1, this->y.computed), + Geom::Point(this->x.computed, this->y.computed), + this->transform); + + this->rx._set = true; } - SP_OBJECT(rect)->updateRepr(); + + this->updateRepr(); } -void -sp_rect_set_visible_ry(SPRect *rect, gdouble ry) -{ +void SPRect::setVisibleRy(gdouble ry) { if (ry == 0) { - rect->ry.computed = 0; - rect->ry._set = false; + this->ry.computed = 0; + this->ry._set = false; } else { - rect->ry.computed = ry / vector_stretch( - Geom::Point(rect->x.computed, rect->y.computed + 1), - Geom::Point(rect->x.computed, rect->y.computed), - rect->transform); - rect->ry._set = true; + this->ry.computed = ry / SPRect::vectorStretch( + Geom::Point(this->x.computed, this->y.computed + 1), + Geom::Point(this->x.computed, this->y.computed), + this->transform); + + this->ry._set = true; } - SP_OBJECT(rect)->updateRepr(); + + this->updateRepr(); } -gdouble -sp_rect_get_visible_rx(SPRect *rect) -{ - if (!rect->rx._set) +gdouble SPRect::getVisibleRx() const { + if (!this->rx._set) { return 0; - return rect->rx.computed * vector_stretch( - Geom::Point(rect->x.computed + 1, rect->y.computed), - Geom::Point(rect->x.computed, rect->y.computed), - rect->transform); + } + + return this->rx.computed * SPRect::vectorStretch( + Geom::Point(this->x.computed + 1, this->y.computed), + Geom::Point(this->x.computed, this->y.computed), + this->transform); } -gdouble -sp_rect_get_visible_ry(SPRect *rect) -{ - if (!rect->ry._set) +gdouble SPRect::getVisibleRy() const { + if (!this->ry._set) { return 0; - return rect->ry.computed * vector_stretch( - Geom::Point(rect->x.computed, rect->y.computed + 1), - Geom::Point(rect->x.computed, rect->y.computed), - rect->transform); + } + + return this->ry.computed * SPRect::vectorStretch( + Geom::Point(this->x.computed, this->y.computed + 1), + Geom::Point(this->x.computed, this->y.computed), + this->transform); } -Geom::Rect -sp_rect_get_rect (SPRect *rect) -{ - Geom::Point p0 = Geom::Point(rect->x.computed, rect->y.computed); - Geom::Point p2 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed); +Geom::Rect SPRect::getRect() const { + Geom::Point p0 = Geom::Point(this->x.computed, this->y.computed); + Geom::Point p2 = Geom::Point(this->x.computed + this->width.computed, this->y.computed + this->height.computed); + return Geom::Rect(p0, p2); } -void -sp_rect_compensate_rxry(SPRect *rect, Geom::Affine xform) -{ - if (rect->rx.computed == 0 && rect->ry.computed == 0) +void SPRect::compensateRxRy(Geom::Affine xform) { + if (this->rx.computed == 0 && this->ry.computed == 0) { return; // nothing to compensate + } // test unit vectors to find out compensation: - Geom::Point c(rect->x.computed, rect->y.computed); + Geom::Point c(this->x.computed, this->y.computed); Geom::Point cx = c + Geom::Point(1, 0); Geom::Point cy = c + Geom::Point(0, 1); // apply previous transform if any - c *= rect->transform; - cx *= rect->transform; - cy *= rect->transform; + c *= this->transform; + cx *= this->transform; + cy *= this->transform; // find out stretches that we need to compensate - gdouble eX = vector_stretch(cx, c, xform); - gdouble eY = vector_stretch(cy, c, xform); + gdouble eX = SPRect::vectorStretch(cx, c, xform); + gdouble eY = SPRect::vectorStretch(cy, c, xform); // If only one of the radii is set, set both radii so they have the same visible length // This is needed because if we just set them the same length in SVG, they might end up unequal because of transform - if ((rect->rx._set && !rect->ry._set) || (rect->ry._set && !rect->rx._set)) { - gdouble r = MAX(rect->rx.computed, rect->ry.computed); - rect->rx.computed = r / eX; - rect->ry.computed = r / eY; + if ((this->rx._set && !this->ry._set) || (this->ry._set && !this->rx._set)) { + gdouble r = MAX(this->rx.computed, this->ry.computed); + this->rx.computed = r / eX; + this->ry.computed = r / eY; } else { - rect->rx.computed = rect->rx.computed / eX; - rect->ry.computed = rect->ry.computed / eY; + this->rx.computed = this->rx.computed / eX; + this->ry.computed = this->ry.computed / eY; } // Note that a radius may end up larger than half-side if the rect is scaled down; // that's ok because this preserves the intended radii in case the rect is enlarged again, // and set_shape will take care of trimming too large radii when generating d= - rect->rx._set = rect->ry._set = true; + this->rx._set = this->ry._set = true; } -void -sp_rect_set_visible_width(SPRect *rect, gdouble width) -{ - rect->width.computed = width / vector_stretch( - Geom::Point(rect->x.computed + 1, rect->y.computed), - Geom::Point(rect->x.computed, rect->y.computed), - rect->transform); - rect->width._set = true; - SP_OBJECT(rect)->updateRepr(); +void SPRect::setVisibleWidth(gdouble width) { + this->width.computed = width / SPRect::vectorStretch( + Geom::Point(this->x.computed + 1, this->y.computed), + Geom::Point(this->x.computed, this->y.computed), + this->transform); + + this->width._set = true; + this->updateRepr(); } -void -sp_rect_set_visible_height(SPRect *rect, gdouble height) -{ - rect->height.computed = height / vector_stretch( - Geom::Point(rect->x.computed, rect->y.computed + 1), - Geom::Point(rect->x.computed, rect->y.computed), - rect->transform); - rect->height._set = true; - SP_OBJECT(rect)->updateRepr(); +void SPRect::setVisibleHeight(gdouble height) { + this->height.computed = height / SPRect::vectorStretch( + Geom::Point(this->x.computed, this->y.computed + 1), + Geom::Point(this->x.computed, this->y.computed), + this->transform); + + this->height._set = true; + this->updateRepr(); } -gdouble -sp_rect_get_visible_width(SPRect *rect) -{ - if (!rect->width._set) +gdouble SPRect::getVisibleWidth() const { + if (!this->width._set) { return 0; - return rect->width.computed * vector_stretch( - Geom::Point(rect->x.computed + 1, rect->y.computed), - Geom::Point(rect->x.computed, rect->y.computed), - rect->transform); + } + + return this->width.computed * SPRect::vectorStretch( + Geom::Point(this->x.computed + 1, this->y.computed), + Geom::Point(this->x.computed, this->y.computed), + this->transform); } -gdouble -sp_rect_get_visible_height(SPRect *rect) -{ - if (!rect->height._set) +gdouble SPRect::getVisibleHeight() const { + if (!this->height._set) { return 0; - return rect->height.computed * vector_stretch( - Geom::Point(rect->x.computed, rect->y.computed + 1), - Geom::Point(rect->x.computed, rect->y.computed), - rect->transform); + } + + return this->height.computed * SPRect::vectorStretch( + Geom::Point(this->x.computed, this->y.computed + 1), + Geom::Point(this->x.computed, this->y.computed), + this->transform); } -/** - * Sets the snappoint p to the unrounded corners of the rectangle - */ -static void sp_rect_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) -{ +void SPRect::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) { /* This method overrides sp_shape_snappoints, which is the default for any shape. The default method returns all eight points along the path of a rounded rectangle, but not the real corners. Snapping the startpoint and endpoint of each rounded corner is not very useful and really confusing. Instead @@ -537,17 +492,12 @@ static void sp_rect_snappoints(SPItem const *item, std::vector<Inkscape::SnapCan but it should be noted that this might be confusing in some cases with relatively large radii. With small radii though the user will easily understand which point is snapping. */ - g_assert(item != NULL); - g_assert(SP_IS_RECT(item)); - - SPRect *rect = SP_RECT(item); + Geom::Affine const i2dt (this->i2dt_affine ()); - Geom::Affine const i2dt (item->i2dt_affine ()); - - Geom::Point p0 = Geom::Point(rect->x.computed, rect->y.computed) * i2dt; - Geom::Point p1 = Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2dt; - Geom::Point p2 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2dt; - Geom::Point p3 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2dt; + Geom::Point p0 = Geom::Point(this->x.computed, this->y.computed) * i2dt; + Geom::Point p1 = Geom::Point(this->x.computed, this->y.computed + this->height.computed) * i2dt; + Geom::Point p2 = Geom::Point(this->x.computed + this->width.computed, this->y.computed + this->height.computed) * i2dt; + Geom::Point p3 = Geom::Point(this->x.computed + this->width.computed, this->y.computed) * i2dt; if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_RECT_CORNER)) { p.push_back(Inkscape::SnapCandidatePoint(p0, Inkscape::SNAPSOURCE_RECT_CORNER, Inkscape::SNAPTARGET_RECT_CORNER)); @@ -566,34 +516,32 @@ static void sp_rect_snappoints(SPItem const *item, std::vector<Inkscape::SnapCan if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_OBJECT_MIDPOINT)) { p.push_back(Inkscape::SnapCandidatePoint((p0 + p2)/2, Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT)); } - } -void -sp_rect_convert_to_guides(SPItem *item) { - SPRect *rect = SP_RECT(item); - +void SPRect::convert_to_guides() { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (!prefs->getBool("/tools/shapes/rect/convertguides", true)) { - rect->convert_to_guides(); + // Use bounding box instead of edges + SPShape::convert_to_guides(); return; } std::list<std::pair<Geom::Point, Geom::Point> > pts; - Geom::Affine const i2dt(rect->i2dt_affine()); + Geom::Affine const i2dt(this->i2dt_affine()); - Geom::Point A1(Geom::Point(rect->x.computed, rect->y.computed) * i2dt); - Geom::Point A2(Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2dt); - Geom::Point A3(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2dt); - Geom::Point A4(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2dt); + Geom::Point A1(Geom::Point(this->x.computed, this->y.computed) * i2dt); + Geom::Point A2(Geom::Point(this->x.computed, this->y.computed + this->height.computed) * i2dt); + Geom::Point A3(Geom::Point(this->x.computed + this->width.computed, this->y.computed + this->height.computed) * i2dt); + Geom::Point A4(Geom::Point(this->x.computed + this->width.computed, this->y.computed) * i2dt); pts.push_back(std::make_pair(A1, A2)); pts.push_back(std::make_pair(A2, A3)); pts.push_back(std::make_pair(A3, A4)); pts.push_back(std::make_pair(A4, A1)); - sp_guide_pt_pairs_to_guides(item->document, pts); + sp_guide_pt_pairs_to_guides(this->document, pts); } /* diff --git a/src/sp-rect.h b/src/sp-rect.h index 1127889c1..28f74f9f9 100644 --- a/src/sp-rect.h +++ b/src/sp-rect.h @@ -18,51 +18,61 @@ #include "sp-shape.h" #include <2geom/forward.h> -G_BEGIN_DECLS -#define SP_TYPE_RECT (sp_rect_get_type ()) -#define SP_RECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_RECT, SPRect)) -#define SP_RECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_RECT, SPRectClass)) -#define SP_IS_RECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_RECT)) -#define SP_IS_RECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_RECT)) +#define SP_RECT(obj) (dynamic_cast<SPRect*>((SPObject*)obj)) +#define SP_IS_RECT(obj) (dynamic_cast<const SPRect*>((SPObject*)obj) != NULL) -struct SPRect : public SPShape { - SVGLength x; - SVGLength y; - SVGLength width; - SVGLength height; - SVGLength rx; - SVGLength ry; -}; +class SPRect : public SPShape { +public: + SPRect(); + virtual ~SPRect(); -struct SPRectClass { - SPShapeClass parent_class; -}; + void setPosition(gdouble x, gdouble y, gdouble width, gdouble height); + + /* If SET if FALSE, VALUE is just ignored */ + void setRx(bool set, gdouble value); + void setRy(bool set, gdouble value); + + gdouble getVisibleRx() const; + void setVisibleRx(gdouble rx); + + gdouble getVisibleRy() const; + void setVisibleRy(gdouble ry); + Geom::Rect getRect() const; -/* Standard GType function */ -GType sp_rect_get_type (void) G_GNUC_CONST; + gdouble getVisibleWidth() const; + void setVisibleWidth(gdouble rx); -void sp_rect_position_set (SPRect * rect, gdouble x, gdouble y, gdouble width, gdouble height); + gdouble getVisibleHeight() const; + void setVisibleHeight(gdouble ry); -/* If SET if FALSE, VALUE is just ignored */ -void sp_rect_set_rx(SPRect * rect, gboolean set, gdouble value); -void sp_rect_set_ry(SPRect * rect, gboolean set, gdouble value); + void compensateRxRy(Geom::Affine xform); -void sp_rect_set_visible_rx (SPRect *rect, gdouble rx); -void sp_rect_set_visible_ry (SPRect *rect, gdouble ry); -gdouble sp_rect_get_visible_rx (SPRect *rect); -gdouble sp_rect_get_visible_ry (SPRect *rect); -Geom::Rect sp_rect_get_rect (SPRect *rect); + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); -void sp_rect_set_visible_width (SPRect *rect, gdouble rx); -void sp_rect_set_visible_height (SPRect *rect, gdouble ry); -gdouble sp_rect_get_visible_width (SPRect *rect); -gdouble sp_rect_get_visible_height (SPRect *rect); + virtual void set(unsigned key, gchar const *value); + virtual void update(SPCtx* ctx, unsigned int flags); -void sp_rect_compensate_rxry (SPRect *rect, Geom::Affine xform); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + virtual gchar* description(); -G_END_DECLS + virtual void set_shape(); + virtual Geom::Affine set_transform(Geom::Affine const& xform); + + virtual void snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); + virtual void convert_to_guides(); + + SVGLength x; + SVGLength y; + SVGLength width; + SVGLength height; + SVGLength rx; + SVGLength ry; + +private: + static gdouble vectorStretch(Geom::Point p0, Geom::Point p1, Geom::Affine xform); +}; #endif // SEEN_SP_RECT_H diff --git a/src/sp-root.cpp b/src/sp-root.cpp index e9ae6dff4..4faefabef 100644 --- a/src/sp-root.cpp +++ b/src/sp-root.cpp @@ -31,216 +31,220 @@ #include "svg/svg.h" #include "xml/repr.h" -static void sp_root_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_root_release(SPObject *object); -static void sp_root_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_root_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref); -static void sp_root_remove_child(SPObject *object, Inkscape::XML::Node *child); -static void sp_root_update(SPObject *object, SPCtx *ctx, guint flags); -static void sp_root_modified(SPObject *object, guint flags); -static Inkscape::XML::Node *sp_root_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -static Inkscape::DrawingItem *sp_root_show(SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); -static void sp_root_print(SPItem *item, SPPrintContext *ctx); - -G_DEFINE_TYPE(SPRoot, sp_root, SP_TYPE_GROUP); - -/** - * Initializes an SPRootClass object by setting its class and parent class objects, and registering - * function pointers (i.e.\ gobject-style virtual functions) for various operations. - */ -static void sp_root_class_init(SPRootClass *klass) -{ - SPObjectClass *sp_object_class = reinterpret_cast<SPObjectClass *>(klass); - SPItemClass *sp_item_class = reinterpret_cast<SPItemClass *>(klass); - - sp_object_class->build = sp_root_build; - sp_object_class->release = sp_root_release; - sp_object_class->set = sp_root_set; - sp_object_class->child_added = sp_root_child_added; - sp_object_class->remove_child = sp_root_remove_child; - sp_object_class->update = sp_root_update; - sp_object_class->modified = sp_root_modified; - sp_object_class->write = sp_root_write; - - sp_item_class->show = sp_root_show; - sp_item_class->print = sp_root_print; +#include "sp-factory.h" + +namespace { + SPObject* createRoot() { + return new SPRoot(); + } + + bool rootRegistered = SPFactory::instance().registerObject("svg:svg", createRoot); } -/** - * Initializes an SPRoot object by setting its default parameter values. - */ -static void sp_root_init(SPRoot *root) -{ +SPRoot::SPRoot() : SPGroup() { + this->aspect_set = 0; + this->aspect_align = 0; + this->onload = NULL; + this->aspect_clip = 0; + static Inkscape::Version const zero_version(0, 0); - sp_version_from_string(SVG_VERSION, &root->original.svg); - root->version.svg = zero_version; - root->original.svg = zero_version; - root->version.inkscape = zero_version; - root->original.inkscape = zero_version; + sp_version_from_string(SVG_VERSION, &this->original.svg); + this->version.svg = zero_version; + this->original.svg = zero_version; + this->version.inkscape = zero_version; + this->original.inkscape = zero_version; - root->x.unset(); - root->y.unset(); - root->width.unset(SVGLength::PERCENT, 1.0, 1.0); - root->height.unset(SVGLength::PERCENT, 1.0, 1.0); + this->x.unset(); + this->y.unset(); + this->width.unset(SVGLength::PERCENT, 1.0, 1.0); + this->height.unset(SVGLength::PERCENT, 1.0, 1.0); - root->viewBox_set = FALSE; + this->viewBox_set = FALSE; - root->c2p.setIdentity(); + this->c2p.setIdentity(); - root->defs = NULL; + this->defs = NULL; } -/** - * Fills in the data for an SPObject from its Inkscape::XML::Node object. - * It fills in data such as version, x, y, width, height, etc. - * It then calls the object's parent class object's build function. - */ -static void sp_root_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - SPGroup *group = (SPGroup *) object; - SPRoot *root = (SPRoot *) object; +SPRoot::~SPRoot() { +} +void SPRoot::build(SPDocument *document, Inkscape::XML::Node *repr) { //XML Tree being used directly here while it shouldn't be. - if ( !object->getRepr()->attribute("version") ) { + if ( !this->getRepr()->attribute("version") ) { repr->setAttribute("version", SVG_VERSION); } - object->readAttr( "version" ); - object->readAttr( "inkscape:version" ); + this->readAttr( "version" ); + this->readAttr( "inkscape:version" ); /* It is important to parse these here, so objects will have viewport build-time */ - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "width" ); - object->readAttr( "height" ); - object->readAttr( "viewBox" ); - object->readAttr( "preserveAspectRatio" ); - object->readAttr( "onload" ); + this->readAttr( "x" ); + this->readAttr( "y" ); + this->readAttr( "width" ); + this->readAttr( "height" ); + this->readAttr( "viewBox" ); + this->readAttr( "preserveAspectRatio" ); + this->readAttr( "onload" ); - if (((SPObjectClass *) sp_root_parent_class)->build) - (* ((SPObjectClass *) sp_root_parent_class)->build) (object, document, repr); + SPGroup::build(document, repr); // Search for first <defs> node - for (SPObject *o = group->firstChild() ; o ; o = o->getNext() ) { + for (SPObject *o = this->firstChild() ; o ; o = o->getNext() ) { if (SP_IS_DEFS(o)) { - root->defs = SP_DEFS(o); + this->defs = SP_DEFS(o); break; } } // clear transform, if any was read in - SVG does not allow transform= on <svg> - SP_ITEM(object)->transform = Geom::identity(); + SP_ITEM(this)->transform = Geom::identity(); } -/** - * This is a destructor routine for SPRoot objects. It de-references any \<def\> items and calls - * the parent class destructor. - */ -static void sp_root_release(SPObject *object) -{ - SPRoot *root = (SPRoot *) object; - root->defs = NULL; +void SPRoot::release() { + this->defs = NULL; - if (((SPObjectClass *) sp_root_parent_class)->release) - ((SPObjectClass *) sp_root_parent_class)->release(object); + SPGroup::release(); } -/** - * Sets the attribute given by key for SPRoot objects to the value specified by value. - */ -static void sp_root_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPRoot *root = SP_ROOT(object); +void SPRoot::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_VERSION: - if (!sp_version_from_string(value, &root->version.svg)) { - root->version.svg = root->original.svg; + if (!sp_version_from_string(value, &this->version.svg)) { + this->version.svg = this->original.svg; } break; + case SP_ATTR_INKSCAPE_VERSION: - if (!sp_version_from_string(value, &root->version.inkscape)) { - root->version.inkscape = root->original.inkscape; + if (!sp_version_from_string(value, &this->version.inkscape)) { + this->version.inkscape = this->original.inkscape; } break; + case SP_ATTR_X: - if (!root->x.readAbsolute(value)) { + if (!this->x.readAbsolute(value)) { /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */ - root->x.unset(); + this->x.unset(); } + /* fixme: I am almost sure these do not require viewport flag (Lauris) */ - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); break; + case SP_ATTR_Y: - if (!root->y.readAbsolute(value)) { + if (!this->y.readAbsolute(value)) { /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */ - root->y.unset(); + this->y.unset(); } + /* fixme: I am almost sure these do not require viewport flag (Lauris) */ - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); break; + case SP_ATTR_WIDTH: - if (!root->width.readAbsolute(value) || !(root->width.computed > 0.0)) { + if (!this->width.readAbsolute(value) || !(this->width.computed > 0.0)) { /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */ - root->width.unset(SVGLength::PERCENT, 1.0, 1.0); + this->width.unset(SVGLength::PERCENT, 1.0, 1.0); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); break; + case SP_ATTR_HEIGHT: - if (!root->height.readAbsolute(value) || !(root->height.computed > 0.0)) { + if (!this->height.readAbsolute(value) || !(this->height.computed > 0.0)) { /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */ - root->height.unset(SVGLength::PERCENT, 1.0, 1.0); + this->height.unset(SVGLength::PERCENT, 1.0, 1.0); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); break; + case SP_ATTR_VIEWBOX: if (value) { double x, y, width, height; char *eptr; + /* fixme: We have to take original item affine into account */ /* fixme: Think (Lauris) */ eptr = (gchar *) value; x = g_ascii_strtod(eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + y = g_ascii_strtod(eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + width = g_ascii_strtod(eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + height = g_ascii_strtod(eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + if ((width > 0) && (height > 0)) { /* Set viewbox */ - root->viewBox = Geom::Rect::from_xywh(x, y, width, height); - root->viewBox_set = TRUE; + this->viewBox = Geom::Rect::from_xywh(x, y, width, height); + this->viewBox_set = TRUE; } else { - root->viewBox_set = FALSE; + this->viewBox_set = FALSE; } } else { - root->viewBox_set = FALSE; + this->viewBox_set = FALSE; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); break; + case SP_ATTR_PRESERVEASPECTRATIO: /* Do setup before, so we can use break to escape */ - root->aspect_set = FALSE; - root->aspect_align = SP_ASPECT_XMID_YMID; - root->aspect_clip = SP_ASPECT_MEET; - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + this->aspect_set = FALSE; + this->aspect_align = SP_ASPECT_XMID_YMID; + this->aspect_clip = SP_ASPECT_MEET; + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + if (value) { int len; gchar c[256]; gchar const *p, *e; unsigned int align, clip; p = value; - while (*p && *p == 32) p += 1; - if (!*p) break; + + while (*p && *p == 32) { + p += 1; + } + + if (!*p) { + break; + } + e = p; - while (*e && *e != 32) e += 1; + + while (*e && *e != 32) { + e += 1; + } + len = e - p; - if (len > 8) break; + + if (len > 8) { + break; + } + memcpy(c, value, len); + c[len] = 0; + /* Now the actual part */ if (!strcmp(c, "none")) { align = SP_ASPECT_NONE; @@ -265,8 +269,13 @@ static void sp_root_set(SPObject *object, unsigned int key, gchar const *value) } else { break; } + clip = SP_ASPECT_MEET; - while (*e && *e == 32) e += 1; + + while (*e && *e == 32) { + e += 1; + } + if (*e) { if (!strcmp(e, "meet")) { clip = SP_ASPECT_MEET; @@ -276,108 +285,91 @@ static void sp_root_set(SPObject *object, unsigned int key, gchar const *value) break; } } - root->aspect_set = TRUE; - root->aspect_align = align; - root->aspect_clip = clip; + + this->aspect_set = TRUE; + this->aspect_align = align; + this->aspect_clip = clip; } break; + case SP_ATTR_ONLOAD: - root->onload = (char *) value; + this->onload = (char *) value; break; + default: /* Pass the set event to the parent */ - if (((SPObjectClass *) sp_root_parent_class)->set) { - ((SPObjectClass *) sp_root_parent_class)->set(object, key, value); - } + SPGroup::set(key, value); break; } } -/** - * This routine is for adding a child SVG object to an SPRoot object. - * The SPRoot object is taken to be an SPGroup. - */ -static void sp_root_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) -{ - SPRoot *root = (SPRoot *) object; - SPGroup *group = (SPGroup *) object; - - if (((SPObjectClass *) (sp_root_parent_class))->child_added) { - (* ((SPObjectClass *) (sp_root_parent_class))->child_added)(object, child, ref); - } +void SPRoot::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { + SPGroup::child_added(child, ref); - SPObject *co = object->document->getObjectByRepr(child); + SPObject *co = this->document->getObjectByRepr(child); g_assert (co != NULL || !strcmp("comment", child->name())); // comment repr node has no object if (co && SP_IS_DEFS(co)) { // We search for first <defs> node - it is not beautiful, but works - for (SPObject *c = group->firstChild() ; c ; c = c->getNext() ) { + for (SPObject *c = this->firstChild() ; c ; c = c->getNext() ) { if (SP_IS_DEFS(c)) { - root->defs = SP_DEFS(c); + this->defs = SP_DEFS(c); break; } } } } -/** - * Removes the given child from this SPRoot object. - */ -static void sp_root_remove_child(SPObject *object, Inkscape::XML::Node *child) -{ - SPRoot *root = (SPRoot *) object; - - if ( root->defs && (root->defs->getRepr() == child) ) { +void SPRoot::remove_child(Inkscape::XML::Node* child) { + if ( this->defs && (this->defs->getRepr() == child) ) { SPObject *iter = 0; + // We search for first remaining <defs> node - it is not beautiful, but works - for ( iter = object->firstChild() ; iter ; iter = iter->getNext() ) { - if ( SP_IS_DEFS(iter) && (SPDefs *)iter != root->defs ) { - root->defs = (SPDefs *)iter; + for ( iter = this->firstChild() ; iter ; iter = iter->getNext() ) { + if ( SP_IS_DEFS(iter) && (SPDefs *)iter != this->defs ) { + this->defs = (SPDefs *)iter; break; } } + if (!iter) { /* we should probably create a new <defs> here? */ - root->defs = NULL; + this->defs = NULL; } } - if (((SPObjectClass *) (sp_root_parent_class))->remove_child) { - (* ((SPObjectClass *) (sp_root_parent_class))->remove_child)(object, child); - } + SPGroup::remove_child(child); } -/** - * This callback routine updates the SPRoot object when its attributes have been changed. - */ -static void sp_root_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPRoot *root = SP_ROOT(object); +void SPRoot::update(SPCtx *ctx, guint flags) { SPItemCtx *ictx = (SPItemCtx *) ctx; /* fixme: This will be invoked too often (Lauris) */ /* fixme: We should calculate only if parent viewport has changed (Lauris) */ /* If position is specified as percentage, calculate actual values */ - if (root->x.unit == SVGLength::PERCENT) { - root->x.computed = root->x.value * ictx->viewport.width(); + if (this->x.unit == SVGLength::PERCENT) { + this->x.computed = this->x.value * ictx->viewport.width(); } - if (root->y.unit == SVGLength::PERCENT) { - root->y.computed = root->y.value * ictx->viewport.height(); + + if (this->y.unit == SVGLength::PERCENT) { + this->y.computed = this->y.value * ictx->viewport.height(); } - if (root->width.unit == SVGLength::PERCENT) { - root->width.computed = root->width.value * ictx->viewport.width(); + + if (this->width.unit == SVGLength::PERCENT) { + this->width.computed = this->width.value * ictx->viewport.width(); } - if (root->height.unit == SVGLength::PERCENT) { - root->height.computed = root->height.value * ictx->viewport.height(); + + if (this->height.unit == SVGLength::PERCENT) { + this->height.computed = this->height.value * ictx->viewport.height(); } /* Create copy of item context */ SPItemCtx rctx = *ictx; /* Calculate child to parent transformation */ - root->c2p.setIdentity(); + this->c2p.setIdentity(); - if (object->parent) { + if (this->parent) { /* * fixme: I am not sure whether setting x and y does or does not * fixme: translate the content of inner SVG. @@ -385,66 +377,75 @@ static void sp_root_update(SPObject *object, SPCtx *ctx, guint flags) * fixme: height seems natural, as this makes the inner svg element * fixme: self-contained. The spec is vague here. */ - root->c2p = Geom::Affine(Geom::Translate(root->x.computed, - root->y.computed)); + this->c2p = Geom::Affine(Geom::Translate(this->x.computed, this->y.computed)); } - if (root->viewBox_set) { + if (this->viewBox_set) { double x, y, width, height; /* Determine actual viewbox in viewport coordinates */ - if (root->aspect_align == SP_ASPECT_NONE) { + if (this->aspect_align == SP_ASPECT_NONE) { x = 0.0; y = 0.0; - width = root->width.computed; - height = root->height.computed; + width = this->width.computed; + height = this->height.computed; } else { double scalex, scaley, scale; /* Things are getting interesting */ - scalex = root->width.computed / root->viewBox.width(); - scaley = root->height.computed / root->viewBox.height(); - scale = (root->aspect_clip == SP_ASPECT_MEET) ? MIN(scalex, scaley) : MAX(scalex, scaley); - width = root->viewBox.width() * scale; - height = root->viewBox.height() * scale; + scalex = this->width.computed / this->viewBox.width(); + scaley = this->height.computed / this->viewBox.height(); + scale = (this->aspect_clip == SP_ASPECT_MEET) ? MIN(scalex, scaley) : MAX(scalex, scaley); + width = this->viewBox.width() * scale; + height = this->viewBox.height() * scale; + /* Now place viewbox to requested position */ /* todo: Use an array lookup to find the 0.0/0.5/1.0 coefficients, as is done for dialogs/align.cpp. */ - switch (root->aspect_align) { + switch (this->aspect_align) { case SP_ASPECT_XMIN_YMIN: x = 0.0; y = 0.0; break; + case SP_ASPECT_XMID_YMIN: - x = 0.5 * (root->width.computed - width); + x = 0.5 * (this->width.computed - width); y = 0.0; break; + case SP_ASPECT_XMAX_YMIN: - x = 1.0 * (root->width.computed - width); + x = 1.0 * (this->width.computed - width); y = 0.0; break; + case SP_ASPECT_XMIN_YMID: x = 0.0; - y = 0.5 * (root->height.computed - height); + y = 0.5 * (this->height.computed - height); break; + case SP_ASPECT_XMID_YMID: - x = 0.5 * (root->width.computed - width); - y = 0.5 * (root->height.computed - height); + x = 0.5 * (this->width.computed - width); + y = 0.5 * (this->height.computed - height); break; + case SP_ASPECT_XMAX_YMID: - x = 1.0 * (root->width.computed - width); - y = 0.5 * (root->height.computed - height); + x = 1.0 * (this->width.computed - width); + y = 0.5 * (this->height.computed - height); break; + case SP_ASPECT_XMIN_YMAX: x = 0.0; - y = 1.0 * (root->height.computed - height); + y = 1.0 * (this->height.computed - height); break; + case SP_ASPECT_XMID_YMAX: - x = 0.5 * (root->width.computed - width); - y = 1.0 * (root->height.computed - height); + x = 0.5 * (this->width.computed - width); + y = 1.0 * (this->height.computed - height); break; + case SP_ASPECT_XMAX_YMAX: - x = 1.0 * (root->width.computed - width); - y = 1.0 * (root->height.computed - height); + x = 1.0 * (this->width.computed - width); + y = 1.0 * (this->height.computed - height); break; + default: x = 0.0; y = 0.0; @@ -453,68 +454,53 @@ static void sp_root_update(SPObject *object, SPCtx *ctx, guint flags) } /* Compose additional transformation from scale and position */ - Geom::Scale const viewBox_length( root->viewBox.dimensions() ); + Geom::Scale const viewBox_length( this->viewBox.dimensions() ); Geom::Scale const new_length(width, height); /* Append viewbox transformation */ /* TODO: The below looks suspicious to me (pjrm): I wonder whether the RHS expression should have c2p at the beginning rather than at the end. Test it. */ - root->c2p = Geom::Translate(-root->viewBox.min()) * ( new_length * viewBox_length.inverse() ) * Geom::Translate(x, y) * root->c2p; + this->c2p = Geom::Translate(-this->viewBox.min()) * ( new_length * viewBox_length.inverse() ) * Geom::Translate(x, y) * this->c2p; } - rctx.i2doc = root->c2p * rctx.i2doc; + rctx.i2doc = this->c2p * rctx.i2doc; /* Initialize child viewport */ - if (root->viewBox_set) { - rctx.viewport = root->viewBox; + if (this->viewBox_set) { + rctx.viewport = this->viewBox; } else { /* fixme: I wonder whether this logic is correct (Lauris) */ Geom::Point minp(0,0); - if (object->parent) { - minp = Geom::Point(root->x.computed, root->y.computed); + if (this->parent) { + minp = Geom::Point(this->x.computed, this->y.computed); } - rctx.viewport = Geom::Rect::from_xywh(minp[Geom::X], minp[Geom::Y], root->width.computed, root->height.computed); + + rctx.viewport = Geom::Rect::from_xywh(minp[Geom::X], minp[Geom::Y], this->width.computed, this->height.computed); } rctx.i2vp = Geom::identity(); /* And invoke parent method */ - if (((SPObjectClass *) (sp_root_parent_class))->update) - ((SPObjectClass *) (sp_root_parent_class))->update(object, (SPCtx *) &rctx, flags); + SPGroup::update((SPCtx *) &rctx, flags); /* As last step set additional transform of drawing group */ - for (SPItemView *v = root->display; v != NULL; v = v->next) { + for (SPItemView *v = this->display; v != NULL; v = v->next) { Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); - g->setChildTransform(root->c2p); + g->setChildTransform(this->c2p); } } -/** - * Calls the <tt>modified</tt> routine of the SPRoot object's parent class. - * Also, if the viewport has been modified, it sets the document size to the new - * height and width. - */ -static void sp_root_modified(SPObject *object, guint flags) -{ - SPRoot *root = SP_ROOT(object); - - if (((SPObjectClass *) (sp_root_parent_class))->modified) - (* ((SPObjectClass *) (sp_root_parent_class))->modified)(object, flags); +void SPRoot::modified(unsigned int flags) { + SPGroup::modified(flags); /* fixme: (Lauris) */ - if (!object->parent && (flags & SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - root->document->emitResizedSignal(root->width.computed, root->height.computed); + if (!this->parent && (flags & SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { + this->document->emitResizedSignal(this->width.computed, this->height.computed); } } -/** - * Writes the object into the repr object, then calls the parent's write routine. - */ -static Inkscape::XML::Node * -sp_root_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPRoot *root = SP_ROOT(object); +Inkscape::XML::Node* SPRoot::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:svg"); } @@ -524,69 +510,55 @@ sp_root_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML: } if ( !repr->attribute("version") ) { - gchar* myversion = sp_version_to_string(root->version.svg); + gchar* myversion = sp_version_to_string(this->version.svg); repr->setAttribute("version", myversion); g_free(myversion); } - if (fabs(root->x.computed) > 1e-9) - sp_repr_set_svg_double(repr, "x", root->x.computed); - if (fabs(root->y.computed) > 1e-9) - sp_repr_set_svg_double(repr, "y", root->y.computed); + if (fabs(this->x.computed) > 1e-9) { + sp_repr_set_svg_double(repr, "x", this->x.computed); + } + + if (fabs(this->y.computed) > 1e-9) { + sp_repr_set_svg_double(repr, "y", this->y.computed); + } /* Unlike all other SPObject, here we want to preserve absolute units too (and only here, * according to the recommendation in http://www.w3.org/TR/SVG11/coords.html#Units). */ - repr->setAttribute("width", sp_svg_length_write_with_units(root->width).c_str()); - repr->setAttribute("height", sp_svg_length_write_with_units(root->height).c_str()); + repr->setAttribute("width", sp_svg_length_write_with_units(this->width).c_str()); + repr->setAttribute("height", sp_svg_length_write_with_units(this->height).c_str()); - if (root->viewBox_set) { + if (this->viewBox_set) { Inkscape::SVGOStringStream os; - os << root->viewBox.left() << " " << root->viewBox.top() << " " - << root->viewBox.width() << " " << root->viewBox.height(); + os << this->viewBox.left() << " " << this->viewBox.top() << " " + << this->viewBox.width() << " " << this->viewBox.height(); + repr->setAttribute("viewBox", os.str().c_str()); } - if (((SPObjectClass *) (sp_root_parent_class))->write) - ((SPObjectClass *) (sp_root_parent_class))->write(object, xml_doc, repr, flags); + SPGroup::write(xml_doc, repr, flags); return repr; } -/** - * Displays the SPRoot item on the drawing. - */ -static Inkscape::DrawingItem * -sp_root_show(SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) -{ - SPRoot *root = SP_ROOT(item); - - Inkscape::DrawingItem *ai; - if (((SPItemClass *) (sp_root_parent_class))->show) { - ai = ((SPItemClass *) (sp_root_parent_class))->show(item, drawing, key, flags); - if (ai) { - Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(ai); - g->setChildTransform(root->c2p); - } - } else { - ai = NULL; +Inkscape::DrawingItem* SPRoot::show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { + Inkscape::DrawingItem *ai = 0; + + ai = SPGroup::show(drawing, key, flags); + + if (ai) { + Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(ai); + g->setChildTransform(this->c2p); } return ai; } -/** - * Virtual print callback. - */ -static void sp_root_print(SPItem *item, SPPrintContext *ctx) -{ - SPRoot *root = SP_ROOT(item); +void SPRoot::print(SPPrintContext* ctx) { + sp_print_bind(ctx, this->c2p, 1.0); - sp_print_bind(ctx, root->c2p, 1.0); - - if (((SPItemClass *) (sp_root_parent_class))->print) { - ((SPItemClass *) (sp_root_parent_class))->print(item, ctx); - } + SPGroup::print(ctx); sp_print_release(ctx); } diff --git a/src/sp-root.h b/src/sp-root.h index e2bad917b..a9f64a53b 100644 --- a/src/sp-root.h +++ b/src/sp-root.h @@ -19,16 +19,17 @@ #include "enums.h" #include "sp-item-group.h" -#define SP_TYPE_ROOT (sp_root_get_type()) -#define SP_ROOT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_ROOT, SPRoot)) -#define SP_ROOT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_ROOT, SPRootClass)) -#define SP_IS_ROOT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_ROOT)) -#define SP_IS_ROOT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_ROOT)) +#define SP_ROOT(obj) (dynamic_cast<SPRoot*>((SPObject*)obj)) +#define SP_IS_ROOT(obj) (dynamic_cast<const SPRoot*>((SPObject*)obj) != NULL) class SPDefs; /** \<svg\> element */ -struct SPRoot : public SPGroup { +class SPRoot : public SPGroup { +public: + SPRoot(); + virtual ~SPRoot(); + struct { Inkscape::Version svg; Inkscape::Version inkscape; @@ -60,14 +61,20 @@ struct SPRoot : public SPGroup { * this \<svg\> element: see writers of this member in sp-root.cpp. */ SPDefs *defs; -}; -struct SPRootClass { - SPGroupClass parent_class; -}; + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void release(); + virtual void set(unsigned int key, gchar const* value); + virtual void update(SPCtx *ctx, guint flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); -GType sp_root_get_type(); + virtual void modified(unsigned int flags); + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node* child); + virtual Inkscape::DrawingItem* show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); + virtual void print(SPPrintContext *ctx); +}; #endif /* !SP_ROOT_H_SEEN */ diff --git a/src/sp-script.cpp b/src/sp-script.cpp index 736ddb4c9..158796e51 100644 --- a/src/sp-script.cpp +++ b/src/sp-script.cpp @@ -16,91 +16,77 @@ #include <cstring> #include "document.h" -static void sp_script_release(SPObject *object); -static void sp_script_update(SPObject *object, SPCtx *ctx, guint flags); -static void sp_script_modified(SPObject *object, guint flags); -static void sp_script_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_script_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static Inkscape::XML::Node *sp_script_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -G_DEFINE_TYPE(SPScript, sp_script, SP_TYPE_OBJECT); - -static void sp_script_class_init(SPScriptClass *sc) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) sc; - - sp_object_class->build = sp_script_build; - sp_object_class->release = sp_script_release; - sp_object_class->update = sp_script_update; - sp_object_class->modified = sp_script_modified; - sp_object_class->write = sp_script_write; - sp_object_class->set = sp_script_set; +#include "sp-factory.h" + +namespace { + SPObject* createScript() { + return new SPScript(); + } + + bool scriptRegistered = SPFactory::instance().registerObject("svg:script", createScript); } -static void sp_script_init(SPScript */*script*/) -{ +SPScript::SPScript() : SPObject() { + this->xlinkhref = NULL; +} +SPScript::~SPScript() { } +void SPScript::build(SPDocument* doc, Inkscape::XML::Node* repr) { + SPObject::build(doc, repr); + + //Read values of key attributes from XML nodes into object. + this->readAttr( "xlink:href" ); + + doc->addResource("script", this); +} /** * Reads the Inkscape::XML::Node, and initializes SPScript variables. For this to get called, * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ -static void -sp_script_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_script_parent_class)->build) { - ((SPObjectClass *) sp_script_parent_class)->build(object, document, repr); - } - - //Read values of key attributes from XML nodes into object. - object->readAttr( "xlink:href" ); - document->addResource("script", object); -} - -static void sp_script_release(SPObject *object) -{ - if (object->document) { +void SPScript::release() { + if (this->document) { // Unregister ourselves - object->document->removeResource("script", object); + this->document->removeResource("script", this); } - if (((SPObjectClass *) sp_script_parent_class)->release) { - ((SPObjectClass *) sp_script_parent_class)->release(object); - } + SPObject::release(); } -static void sp_script_update(SPObject */*object*/, SPCtx */*ctx*/, guint /*flags*/) -{ +void SPScript::update(SPCtx* ctx, unsigned int flags) { } -static void sp_script_modified(SPObject */*object*/, guint /*flags*/) -{ + +void SPScript::modified(unsigned int flags) { } -static void -sp_script_set(SPObject *object, unsigned int key, gchar const *value) -{ - SPScript *scr = SP_SCRIPT(object); +void SPScript::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_XLINK_HREF: - if (scr->xlinkhref) g_free(scr->xlinkhref); - scr->xlinkhref = g_strdup(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + if (this->xlinkhref) { + g_free(this->xlinkhref); + } + + this->xlinkhref = g_strdup(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; default: - if (((SPObjectClass *) sp_script_parent_class)->set) - ((SPObjectClass *) sp_script_parent_class)->set(object, key, value); + SPObject::set(key, value); break; } } -static Inkscape::XML::Node *sp_script_write(SPObject */*object*/, Inkscape::XML::Document */*xml_doc*/, Inkscape::XML::Node *repr, guint /*flags*/) -{ +Inkscape::XML::Node* SPScript::write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags) { + return repr; +} + +//static Inkscape::XML::Node *sp_script_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) +//{ /* TODO: code copied from sp-defs @@ -136,8 +122,9 @@ TODO: (* ((SPObjectClass *) (parent_class))->write)(object, xml_doc, repr, flags); } */ - return repr; -} +// +// return ((SPScript*)object)->cscript->onWrite(xml_doc, repr, flags); +//} /* Local Variables: diff --git a/src/sp-script.h b/src/sp-script.h index 976603b65..95b56e79c 100644 --- a/src/sp-script.h +++ b/src/sp-script.h @@ -14,24 +14,26 @@ #include "sp-item.h" -#define SP_TYPE_SCRIPT (sp_script_get_type()) -#define SP_SCRIPT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_SCRIPT, SPScript)) -#define SP_SCRIPT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_SCRIPT, SPScriptClass)) -#define SP_IS_SCRIPT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_SCRIPT)) -#define SP_IS_SCRIPT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_SCRIPT)) +#define SP_SCRIPT(obj) (dynamic_cast<SPScript*>((SPObject*)obj)) +#define SP_IS_SCRIPT(obj) (dynamic_cast<const SPScript*>((SPObject*)obj) != NULL) /* SPScript */ +class SPScript : public SPObject { +public: + SPScript(); + virtual ~SPScript(); -struct SPScript : public SPObject { gchar *xlinkhref; -}; -struct SPScriptClass { - SPObjectClass parent_class; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + virtual void set(unsigned int key, const gchar* value); + virtual void update(SPCtx* ctx, unsigned int flags); + virtual void modified(unsigned int flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); }; -GType sp_script_get_type(); - #endif /* diff --git a/src/sp-shape.cpp b/src/sp-shape.cpp index 38ffbb20c..8f3d5117f 100644 --- a/src/sp-shape.cpp +++ b/src/sp-shape.cpp @@ -53,104 +53,35 @@ #define noSHAPE_VERBOSE -void sp_shape_print (SPItem * item, SPPrintContext * ctx); -static void sp_shape_finalize (GObject *object); -static void sp_shape_build (SPObject * object, SPDocument * document, Inkscape::XML::Node * repr); -static void sp_shape_release (SPObject *object); -static void sp_shape_set(SPObject *object, unsigned key, gchar const *value); -static void sp_shape_update (SPObject *object, SPCtx *ctx, unsigned int flags); -static void sp_shape_modified (SPObject *object, unsigned int flags); -static Inkscape::XML::Node *sp_shape_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static Geom::OptRect sp_shape_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type); -static Inkscape::DrawingItem *sp_shape_show (SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); -static void sp_shape_hide (SPItem *item, unsigned int key); -static void sp_shape_snappoints (SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); static void sp_shape_update_marker_view (SPShape *shape, Inkscape::DrawingItem *ai); -G_DEFINE_TYPE(SPShape, sp_shape, SP_TYPE_LPE_ITEM); - -/** - * Initializes a SPShapeClass object. Establishes the function pointers to the class' - * member routines in the class vtable, and sets pointers to parent classes. - */ -static void -sp_shape_class_init(SPShapeClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS(klass); - SPObjectClass *sp_object_class = SP_OBJECT_CLASS(klass); - SPItemClass * item_class = SP_ITEM_CLASS(klass); - SPLPEItemClass * lpe_item_class = SP_LPE_ITEM_CLASS(klass); - - gobject_class->finalize = sp_shape_finalize; - - sp_object_class->build = sp_shape_build; - sp_object_class->release = sp_shape_release; - sp_object_class->set = sp_shape_set; - sp_object_class->update = sp_shape_update; - sp_object_class->modified = sp_shape_modified; - sp_object_class->write = sp_shape_write; - - item_class->bbox = sp_shape_bbox; - item_class->print = sp_shape_print; - item_class->show = sp_shape_show; - item_class->hide = sp_shape_hide; - item_class->snappoints = sp_shape_snappoints; - lpe_item_class->update_patheffect = NULL; - - klass->set_shape = NULL; -} - -/** - * Initializes an SPShape object. - */ -static void -sp_shape_init(SPShape *shape) -{ +SPShape::SPShape() : SPLPEItem() { for ( int i = 0 ; i < SP_MARKER_LOC_QTY ; i++ ) { - new (&shape->_release_connect[i]) sigc::connection(); - new (&shape->_modified_connect[i]) sigc::connection(); - shape->_marker[i] = NULL; + new (&this->_release_connect[i]) sigc::connection(); + new (&this->_modified_connect[i]) sigc::connection(); + this->_marker[i] = NULL; } - shape->_curve = NULL; - shape->_curve_before_lpe = NULL; -} -static void -sp_shape_finalize(GObject *object) -{ - SPShape *shape=(SPShape *)object; + this->_curve = NULL; + this->_curve_before_lpe = NULL; +} +SPShape::~SPShape() { for ( int i = 0 ; i < SP_MARKER_LOC_QTY ; i++ ) { - shape->_release_connect[i].disconnect(); - shape->_release_connect[i].~connection(); - shape->_modified_connect[i].disconnect(); - shape->_modified_connect[i].~connection(); - } - - if (((GObjectClass *) (sp_shape_parent_class))->finalize) { - (* ((GObjectClass *) (sp_shape_parent_class))->finalize)(object); + this->_release_connect[i].disconnect(); + this->_modified_connect[i].disconnect(); } } -/** - * Virtual build callback for SPMarker. - * - * This is to be invoked immediately after creation of an SPShape. - * - * \see SPObject::build() - */ -static void -sp_shape_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) (sp_shape_parent_class))->build) { - (*((SPObjectClass *) (sp_shape_parent_class))->build) (object, document, repr); - } +void SPShape::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPLPEItem::build(document, repr); for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) { - sp_shape_set_marker (object, i, object->style->marker[i].value); - } + sp_shape_set_marker (this, i, this->style->marker[i].value); + } } + /** * Removes, releases and unrefs all children of object * @@ -161,69 +92,46 @@ sp_shape_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr * * \see SPObject::release() */ -static void -sp_shape_release(SPObject *object) -{ - SPItem *item; - SPShape *shape; +void SPShape::release() { SPItemView *v; int i; - item = (SPItem *) object; - shape = (SPShape *) object; - for (i = 0; i < SP_MARKER_LOC_QTY; i++) { - if (shape->_marker[i]) { - for (v = item->display; v != NULL; v = v->next) { - sp_marker_hide ((SPMarker *) shape->_marker[i], v->arenaitem->key() + i); + if (this->_marker[i]) { + + for (v = this->display; v != NULL; v = v->next) { + sp_marker_hide ((SPMarker *) this->_marker[i], v->arenaitem->key() + i); } - shape->_release_connect[i].disconnect(); - shape->_modified_connect[i].disconnect(); - shape->_marker[i] = sp_object_hunref (shape->_marker[i], object); + + this->_release_connect[i].disconnect(); + this->_modified_connect[i].disconnect(); + this->_marker[i] = sp_object_hunref (this->_marker[i], this); } } - if (shape->_curve) { - shape->_curve = shape->_curve->unref(); + + if (this->_curve) { + this->_curve = this->_curve->unref(); } - if (shape->_curve_before_lpe) { - shape->_curve_before_lpe = shape->_curve_before_lpe->unref(); + + if (this->_curve_before_lpe) { + this->_curve_before_lpe = this->_curve_before_lpe->unref(); } - if (((SPObjectClass *) sp_shape_parent_class)->release) { - ((SPObjectClass *) sp_shape_parent_class)->release (object); - } + SPLPEItem::release(); } -static void -sp_shape_set(SPObject *object, unsigned int key, gchar const *value) -{ - if (((SPObjectClass *) sp_shape_parent_class)->set) { - ((SPObjectClass *) sp_shape_parent_class)->set(object, key, value); - } +void SPShape::set(unsigned int key, const gchar* value) { + SPLPEItem::set(key, value); } -static Inkscape::XML::Node* -sp_shape_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ - if (((SPObjectClass *)(sp_shape_parent_class))->write) { - ((SPObjectClass *)(sp_shape_parent_class))->write(object, doc, repr, flags); - } - return repr; +Inkscape::XML::Node* SPShape::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { + SPLPEItem::write(xml_doc, repr, flags); + return repr; } -/** - * Updates the shape when its attributes have changed. Also establishes - * marker objects to match the style settings. - */ -static void -sp_shape_update(SPObject *object, SPCtx *ctx, unsigned int flags) -{ - SPShape *shape = (SPShape *) object; - - if (((SPObjectClass *) (sp_shape_parent_class))->update) { - (* ((SPObjectClass *) (sp_shape_parent_class))->update) (object, ctx, flags); - } +void SPShape::update(SPCtx* ctx, guint flags) { + SPLPEItem::update(ctx, flags); /* This stanza checks that an object's marker style agrees with * the marker objects it has allocated. sp_shape_set_marker ensures @@ -231,16 +139,18 @@ sp_shape_update(SPObject *object, SPCtx *ctx, unsigned int flags) * match the style. */ for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) { - sp_shape_set_marker (object, i, object->style->marker[i].value); - } + sp_shape_set_marker (this, i, this->style->marker[i].value); + } if (flags & (SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - SPStyle *style = object->style; + SPStyle *style = this->style; + if (style->stroke_width.unit == SP_CSS_UNIT_PERCENT) { SPItemCtx *ictx = (SPItemCtx *) ctx; double const aw = 1.0 / ictx->i2vp.descrim(); style->stroke_width.computed = style->stroke_width.value * aw; - for (SPItemView *v = ((SPItem *) (shape))->display; v != NULL; v = v->next) { + + for (SPItemView *v = ((SPItem *) (this))->display; v != NULL; v = v->next) { Inkscape::DrawingShape *sh = dynamic_cast<Inkscape::DrawingShape *>(v->arenaitem); sh->setStyle(style); } @@ -250,32 +160,34 @@ sp_shape_update(SPObject *object, SPCtx *ctx, unsigned int flags) if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG)) { /* This is suboptimal, because changing parent style schedules recalculation */ /* But on the other hand - how can we know that parent does not tie style and transform */ - for (SPItemView *v = shape->display; v != NULL; v = v->next) { + for (SPItemView *v = this->display; v != NULL; v = v->next) { Inkscape::DrawingShape *sh = dynamic_cast<Inkscape::DrawingShape *>(v->arenaitem); + if (flags & SP_OBJECT_MODIFIED_FLAG) { - sh->setPath(shape->_curve); + sh->setPath(this->_curve); } } } - if (shape->hasMarkers ()) { + if (this->hasMarkers ()) { /* Dimension marker views */ - for (SPItemView *v = shape->display; v != NULL; v = v->next) { + for (SPItemView *v = this->display; v != NULL; v = v->next) { if (!v->arenaitem->key()) { v->arenaitem->setKey(SPItem::display_key_new (SP_MARKER_LOC_QTY)); } + for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) { - if (shape->_marker[i]) { - sp_marker_show_dimension ((SPMarker *) shape->_marker[i], + if (this->_marker[i]) { + sp_marker_show_dimension ((SPMarker *) this->_marker[i], v->arenaitem->key() + i, - shape->numberOfMarkers (i)); + this->numberOfMarkers (i)); } } } /* Update marker views */ - for (SPItemView *v = shape->display; v != NULL; v = v->next) { - sp_shape_update_marker_view (shape, v->arenaitem); + for (SPItemView *v = this->display; v != NULL; v = v->next) { + sp_shape_update_marker_view (this, v->arenaitem); } } } @@ -474,66 +386,61 @@ sp_shape_update_marker_view(SPShape *shape, Inkscape::DrawingItem *ai) } } -/** - * Sets modified flag for all sub-item views. - */ -static void -sp_shape_modified(SPObject *object, unsigned int flags) -{ - SPShape *shape = SP_SHAPE (object); - - if (((SPObjectClass *) (sp_shape_parent_class))->modified) { - (* ((SPObjectClass *) (sp_shape_parent_class))->modified) (object, flags); - } +void SPShape::modified(unsigned int flags) { + SPLPEItem::modified(flags); if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { - for (SPItemView *v = shape->display; v != NULL; v = v->next) { + for (SPItemView *v = this->display; v != NULL; v = v->next) { Inkscape::DrawingShape *sh = dynamic_cast<Inkscape::DrawingShape *>(v->arenaitem); - sh->setStyle(object->style); + sh->setStyle(this->style); } } } -/** - * Calculates the bounding box for item, storing it into bbox. - * This also includes the bounding boxes of any markers included in the shape. - */ -static Geom::OptRect -sp_shape_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType bboxtype) -{ - SPShape const *shape = SP_SHAPE (item); +Geom::OptRect SPShape::bbox(Geom::Affine const &transform, SPItem::BBoxType bboxtype) { Geom::OptRect bbox; - if (!shape->_curve) return bbox; - bbox = bounds_exact_transformed(shape->_curve->get_pathvector(), transform); - if (!bbox) return bbox; + if (!this->_curve) { + return bbox; + } + + bbox = bounds_exact_transformed(this->_curve->get_pathvector(), transform); + + if (!bbox) { + return bbox; + } if (bboxtype == SPItem::VISUAL_BBOX) { // convert the stroke to a path and calculate that path's geometric bbox - SPStyle* style = item->style; + SPStyle* style = this->style; + if (!style->stroke.isNone()) { - Geom::PathVector *pathv = item_outline(item, true); // calculate bbox_only + Geom::PathVector *pathv = item_outline(this, true); // calculate bbox_only + if (pathv) { bbox |= bounds_exact_transformed(*pathv, transform); delete pathv; } } + // Union with bboxes of the markers, if any - if ( shape->hasMarkers() && !shape->_curve->get_pathvector().empty() ) { + if ( this->hasMarkers() && !this->_curve->get_pathvector().empty() ) { /** \todo make code prettier! */ - Geom::PathVector const & pathv = shape->_curve->get_pathvector(); + Geom::PathVector const & pathv = this->_curve->get_pathvector(); // START marker for (unsigned i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START - if ( shape->_marker[i] ) { - SPMarker* marker = SP_MARKER (shape->_marker[i]); + if ( this->_marker[i] ) { + SPMarker* marker = SP_MARKER (this->_marker[i]); SPItem* marker_item = sp_item_first_item_child( marker ); if (marker_item) { Geom::Affine tr(sp_shape_marker_get_transform_at_start(pathv.begin()->front())); + if (!marker->orient_auto) { Geom::Point transl = tr.translation(); tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl); } + if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) { tr = Geom::Scale(style->stroke_width.computed) * tr; } @@ -546,12 +453,19 @@ sp_shape_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxTyp } } } + // MID marker for (unsigned i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID - if ( !shape->_marker[i] ) continue; - SPMarker* marker = SP_MARKER (shape->_marker[i]); + if ( !this->_marker[i] ) { + continue; + } + + SPMarker* marker = SP_MARKER (this->_marker[i]); SPItem* marker_item = sp_item_first_item_child( marker ); - if ( !marker_item ) continue; + + if ( !marker_item ) { + continue; + } for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) { // START position @@ -559,38 +473,46 @@ sp_shape_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxTyp && ! ((path_it == (pathv.end()-1)) && (path_it->size_default() == 0)) ) // if this is the last path and it is a moveto-only, there is no mid marker there { Geom::Affine tr(sp_shape_marker_get_transform_at_start(path_it->front())); + if (!marker->orient_auto) { Geom::Point transl = tr.translation(); tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl); } + if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) { tr = Geom::Scale(style->stroke_width.computed) * tr; } + tr = marker_item->transform * marker->c2p * tr * transform; bbox |= marker_item->visualBounds(tr); } + // MID position if ( path_it->size_default() > 1) { Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); // outgoing curve + while (curve_it2 != path_it->end_default()) { /* Put marker between curve_it1 and curve_it2. * Loop to end_default (so including closing segment), because when a path is closed, * there should be a midpoint marker between last segment and closing straight line segment */ - SPMarker* marker = SP_MARKER (shape->_marker[i]); + SPMarker* marker = SP_MARKER (this->_marker[i]); SPItem* marker_item = sp_item_first_item_child( marker ); if (marker_item) { Geom::Affine tr(sp_shape_marker_get_transform(*curve_it1, *curve_it2)); + if (!marker->orient_auto) { Geom::Point transl = tr.translation(); tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl); } + if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) { tr = Geom::Scale(style->stroke_width.computed) * tr; } + tr = marker_item->transform * marker->c2p * tr * transform; bbox |= marker_item->visualBounds(tr); } @@ -599,26 +521,31 @@ sp_shape_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxTyp ++curve_it2; } } + // END position if ( path_it != (pathv.end()-1) && !path_it->empty()) { Geom::Curve const &lastcurve = path_it->back_default(); Geom::Affine tr = sp_shape_marker_get_transform_at_end(lastcurve); + if (!marker->orient_auto) { Geom::Point transl = tr.translation(); tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl); } + if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) { tr = Geom::Scale(style->stroke_width.computed) * tr; } + tr = marker_item->transform * marker->c2p * tr * transform; bbox |= marker_item->visualBounds(tr); } } } + // END marker for (unsigned i = 0; i < 4; i += 3) { // SP_MARKER_LOC and SP_MARKER_LOC_END - if ( shape->_marker[i] ) { - SPMarker* marker = SP_MARKER (shape->_marker[i]); + if ( this->_marker[i] ) { + SPMarker* marker = SP_MARKER (this->_marker[i]); SPItem* marker_item = sp_item_first_item_child( marker ); if (marker_item) { @@ -626,16 +553,20 @@ sp_shape_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxTyp * For moveto-only path, this returns the "closing line segment". */ Geom::Path const &path_last = pathv.back(); unsigned int index = path_last.size_default(); + if (index > 0) { index--; } + Geom::Curve const &lastcurve = path_last[index]; Geom::Affine tr = sp_shape_marker_get_transform_at_end(lastcurve); + if (!marker->orient_auto) { Geom::Point transl = tr.translation(); tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl); } + if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) { tr = Geom::Scale(style->stroke_width.computed) * tr; } @@ -650,6 +581,7 @@ sp_shape_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxTyp } } } + return bbox; } @@ -671,40 +603,36 @@ sp_shape_print_invoke_marker_printing(SPObject *obj, Geom::Affine tr, SPStyle co marker_item->transform = old_tr; } } -/** - * Prepares shape for printing. Handles printing of comments for printing - * debugging, sizes the item to fit into the document width/height, - * applies print fill/stroke, sets transforms for markers, and adds - * comment labels. - */ -void -sp_shape_print (SPItem *item, SPPrintContext *ctx) -{ - Geom::OptRect pbox, dbox, bbox; - SPShape *shape = SP_SHAPE(item); - - if (!shape->_curve) return; +void SPShape::print(SPPrintContext* ctx) { + if (!this->_curve) { + return; + } - Geom::PathVector const & pathv = shape->_curve->get_pathvector(); - if (pathv.empty()) return; + Geom::PathVector const & pathv = this->_curve->get_pathvector(); + + if (pathv.empty()) { + return; + } - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gint add_comments = prefs->getBool("/printing/debug/add-label-comments"); - if (add_comments) { - gchar * comment = g_strdup_printf("begin '%s'", - item->defaultLabel()); - sp_print_comment(ctx, comment); - g_free(comment); - } + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gint add_comments = prefs->getBool("/printing/debug/add-label-comments"); + + if (add_comments) { + gchar * comment = g_strdup_printf("begin '%s'", this->defaultLabel()); + sp_print_comment(ctx, comment); + g_free(comment); + } /* fixme: Think (Lauris) */ - pbox = item->geometricBounds(); - bbox = item->desktopVisualBounds(); - dbox = Geom::Rect::from_xywh(Geom::Point(0,0), item->document->getDimensions()); - Geom::Affine const i2dt(item->i2dt_affine()); + Geom::OptRect pbox, dbox, bbox; + pbox = this->geometricBounds(); + bbox = this->desktopVisualBounds(); + dbox = Geom::Rect::from_xywh(Geom::Point(0,0), this->document->getDimensions()); + + Geom::Affine const i2dt(this->i2dt_affine()); - SPStyle* style = item->style; + SPStyle* style = this->style; if (!style->fill.isNone()) { sp_print_fill (ctx, pathv, i2dt, style, pbox, dbox, bbox); @@ -717,26 +645,29 @@ sp_shape_print (SPItem *item, SPPrintContext *ctx) /** \todo make code prettier */ // START marker for (int i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START - if ( shape->_marker[i] ) { + if ( this->_marker[i] ) { Geom::Affine tr(sp_shape_marker_get_transform_at_start(pathv.begin()->front())); - sp_shape_print_invoke_marker_printing(shape->_marker[i], tr, style, ctx); + sp_shape_print_invoke_marker_printing(this->_marker[i], tr, style, ctx); } } + // MID marker for (int i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID - if (shape->_marker[i]) { + if (this->_marker[i]) { for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) { // START position if ( path_it != pathv.begin() && ! ((path_it == (pathv.end()-1)) && (path_it->size_default() == 0)) ) // if this is the last path and it is a moveto-only, there is no mid marker there { Geom::Affine tr(sp_shape_marker_get_transform_at_start(path_it->front())); - sp_shape_print_invoke_marker_printing(shape->_marker[i], tr, style, ctx); + sp_shape_print_invoke_marker_printing(this->_marker[i], tr, style, ctx); } + // MID position if ( path_it->size_default() > 1) { Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); // outgoing curve + while (curve_it2 != path_it->end_default()) { /* Put marker between curve_it1 and curve_it2. @@ -744,60 +675,56 @@ sp_shape_print (SPItem *item, SPPrintContext *ctx) * there should be a midpoint marker between last segment and closing straight line segment */ Geom::Affine tr(sp_shape_marker_get_transform(*curve_it1, *curve_it2)); - sp_shape_print_invoke_marker_printing(shape->_marker[i], tr, style, ctx); + sp_shape_print_invoke_marker_printing(this->_marker[i], tr, style, ctx); ++curve_it1; ++curve_it2; } } + if ( path_it != (pathv.end()-1) && !path_it->empty()) { Geom::Curve const &lastcurve = path_it->back_default(); Geom::Affine tr = sp_shape_marker_get_transform_at_end(lastcurve); - sp_shape_print_invoke_marker_printing(shape->_marker[i], tr, style, ctx); + sp_shape_print_invoke_marker_printing(this->_marker[i], tr, style, ctx); } } } } + // END marker - if ( shape->_marker[SP_MARKER_LOC_END] || shape->_marker[SP_MARKER_LOC]) { + if ( this->_marker[SP_MARKER_LOC_END] || this->_marker[SP_MARKER_LOC]) { /* Get reference to last curve in the path. * For moveto-only path, this returns the "closing line segment". */ Geom::Path const &path_last = pathv.back(); unsigned int index = path_last.size_default(); + if (index > 0) { index--; } + Geom::Curve const &lastcurve = path_last[index]; Geom::Affine tr = sp_shape_marker_get_transform_at_end(lastcurve); for (int i = 0; i < 4; i += 3) { // SP_MARKER_LOC and SP_MARKER_LOC_END - if (shape->_marker[i]) { - sp_shape_print_invoke_marker_printing(shape->_marker[i], tr, style, ctx); + if (this->_marker[i]) { + sp_shape_print_invoke_marker_printing(this->_marker[i], tr, style, ctx); } } } - if (add_comments) { - gchar * comment = g_strdup_printf("end '%s'", - item->defaultLabel()); - sp_print_comment(ctx, comment); - g_free(comment); - } + if (add_comments) { + gchar * comment = g_strdup_printf("end '%s'", + this->defaultLabel()); + sp_print_comment(ctx, comment); + g_free(comment); + } } -/** - * Sets style, path, and paintbox. Updates marker views, including dimensions. - */ -static Inkscape::DrawingItem* -sp_shape_show(SPItem *item, Inkscape::Drawing &drawing, unsigned int /*key*/, unsigned int /*flags*/) -{ - SPObject *object = item; - SPShape *shape = SP_SHAPE(item); - +Inkscape::DrawingItem* SPShape::show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { Inkscape::DrawingShape *s = new Inkscape::DrawingShape(drawing); - s->setStyle(object->style); - s->setPath(shape->_curve); + s->setStyle(this->style); + s->setPath(this->_curve); /* This stanza checks that an object's marker style agrees with * the marker objects it has allocated. sp_shape_set_marker ensures @@ -805,57 +732,45 @@ sp_shape_show(SPItem *item, Inkscape::Drawing &drawing, unsigned int /*key*/, un * match the style. */ for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) { - sp_shape_set_marker (object, i, object->style->marker[i].value); - } - - if (shape->hasMarkers ()) { + sp_shape_set_marker (this, i, this->style->marker[i].value); + } + if (this->hasMarkers ()) { /* provide key and dimension the marker views */ if (!s->key()) { s->setKey(SPItem::display_key_new (SP_MARKER_LOC_QTY)); } for (int i = 0; i < SP_MARKER_LOC_QTY; i++) { - if (shape->_marker[i]) { - sp_marker_show_dimension ((SPMarker *) shape->_marker[i], + if (this->_marker[i]) { + sp_marker_show_dimension ((SPMarker *) this->_marker[i], s->key() + i, - shape->numberOfMarkers (i)); + this->numberOfMarkers (i)); } } /* Update marker views */ - sp_shape_update_marker_view (shape, s); + sp_shape_update_marker_view (this, s); } return s; } /** - * Hides/removes marker views from the shape. + * Sets style, path, and paintbox. Updates marker views, including dimensions. */ -static void -sp_shape_hide(SPItem *item, unsigned int key) -{ - SPShape *shape; - SPItemView *v; - int i; - - shape = (SPShape *) item; - - for (i=0; i<SP_MARKER_LOC_QTY; i++) { - if (shape->_marker[i]) { - for (v = item->display; v != NULL; v = v->next) { - if (key == v->key) { - sp_marker_hide ((SPMarker *) shape->_marker[i], - v->arenaitem->key() + i); - } - } - } - } - - if (((SPItemClass *) sp_shape_parent_class)->hide) { - ((SPItemClass *) sp_shape_parent_class)->hide (item, key); - } +void SPShape::hide(unsigned int key) { + for (int i=0; i<SP_MARKER_LOC_QTY; i++) { + if (this->_marker[i]) { + for (SPItemView* v = this->display; v != NULL; v = v->next) { + if (key == v->key) { + sp_marker_hide ((SPMarker *) this->_marker[i], v->arenaitem->key() + i); + } + } + } + } + + //SPLPEItem::onHide(key); } /** @@ -893,6 +808,7 @@ int SPShape::hasMarkers() const int SPShape::numberOfMarkers(int type) { Geom::PathVector const & pathv = this->_curve->get_pathvector(); + if (pathv.size() == 0) { return 0; } @@ -1021,19 +937,16 @@ sp_shape_set_marker (SPObject *object, unsigned int key, const gchar *value) } } - +// CPPIFY: make pure virtual +void SPShape::set_shape() { + //throw; +} /* Shape section */ /** * Calls any registered handlers for the set_shape action */ -void SPShape::setShape() -{ - if (SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (this))->set_shape) { - SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (this))->set_shape (this); - } -} /** * Adds a curve to the shape. If owner is specified, a reference @@ -1046,6 +959,7 @@ void SPShape::setCurve(SPCurve *new_curve, unsigned int owner) if (_curve) { _curve = _curve->unref(); } + if (new_curve) { if (owner) { _curve = new_curve->ref(); @@ -1053,6 +967,7 @@ void SPShape::setCurve(SPCurve *new_curve, unsigned int owner) _curve = new_curve->copy(); } } + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } @@ -1065,6 +980,7 @@ SPShape::setCurveBeforeLPE (SPCurve *new_curve) if (_curve_before_lpe) { _curve_before_lpe = _curve_before_lpe->unref(); } + if (new_curve) { _curve_before_lpe = new_curve->ref(); } @@ -1078,6 +994,7 @@ SPCurve * SPShape::getCurve() const if (_curve) { return _curve->copy(); } + return NULL; } @@ -1095,6 +1012,7 @@ SPCurve * SPShape::getCurveBeforeLPE() const return _curve->copy(); } } + return NULL; } @@ -1106,6 +1024,7 @@ void SPShape::setCurveInsync(SPCurve *new_curve, unsigned int owner) if (_curve) { _curve = _curve->unref(); } + if (new_curve) { if (owner) { _curve = new_curve->ref(); @@ -1115,28 +1034,22 @@ void SPShape::setCurveInsync(SPCurve *new_curve, unsigned int owner) } } -/** - * Return all nodes in a path that are to be considered for snapping - */ -static void -sp_shape_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) -{ - g_assert(item != NULL); - g_assert(SP_IS_SHAPE(item)); - - SPShape const *shape = SP_SHAPE(item); - if (shape->_curve == NULL) { +void SPShape::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) { + if (this->_curve == NULL) { return; } - Geom::PathVector const &pathv = shape->_curve->get_pathvector(); - if (pathv.empty()) + Geom::PathVector const &pathv = this->_curve->get_pathvector(); + + if (pathv.empty()) { return; + } - Geom::Affine const i2dt (item->i2dt_affine ()); + Geom::Affine const i2dt (this->i2dt_affine ()); if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_OBJECT_MIDPOINT)) { - Geom::OptRect bbox = item->desktopVisualBounds(); + Geom::OptRect bbox = this->desktopVisualBounds(); + if (bbox) { p.push_back(Inkscape::SnapCandidatePoint(bbox->midpoint(), Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT)); } @@ -1150,6 +1063,7 @@ sp_shape_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); // outgoing curve + while (curve_it1 != path_it->end_default()) { // For each path: consider midpoints of line segments for snapping @@ -1177,6 +1091,7 @@ sp_shape_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint if (c1 || c2) { Inkscape::SnapSourceType sst; Inkscape::SnapTargetType stt; + switch (nodetype) { case Geom::NODE_CUSP: sst = Inkscape::SNAPSOURCE_NODE_CUSP; @@ -1192,6 +1107,7 @@ sp_shape_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint stt = Inkscape::SNAPTARGET_UNDEFINED; break; } + p.push_back(Inkscape::SnapCandidatePoint(curve_it1->finalPoint() * i2dt, sst, stt)); } } @@ -1204,8 +1120,10 @@ sp_shape_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint // (using "Method 1" as described in Inkscape::ObjectSnapper::_collectNodes()) if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_PATH_INTERSECTION) || snapprefs->isSourceSnappable(Inkscape::SNAPSOURCE_PATH_INTERSECTION)) { Geom::Crossings cs; + try { cs = self_crossings(*path_it); // This can be slow! + if (!cs.empty()) { // There might be multiple intersections... for (Geom::Crossings::const_iterator i = cs.begin(); i != cs.end(); ++i) { Geom::Point p_ix = (*path_it).pointAt((*i).ta); @@ -1219,7 +1137,6 @@ sp_shape_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint } } - } /* diff --git a/src/sp-shape.h b/src/sp-shape.h index 422281cae..bc51f3d45 100644 --- a/src/sp-shape.h +++ b/src/sp-shape.h @@ -22,24 +22,22 @@ #include <stddef.h> #include <sigc++/connection.h> -#define SP_TYPE_SHAPE (sp_shape_get_type ()) -#define SP_SHAPE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_SHAPE, SPShape)) -#define SP_SHAPE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_SHAPE, SPShapeClass)) -#define SP_IS_SHAPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_SHAPE)) -#define SP_IS_SHAPE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_SHAPE)) +#define SP_SHAPE(obj) (dynamic_cast<SPShape*>((SPObject*)obj)) +#define SP_IS_SHAPE(obj) (dynamic_cast<const SPShape*>((SPObject*)obj) != NULL) #define SP_SHAPE_WRITE_PATH (1 << 2) class SPDesktop; namespace Inkscape { class DrawingItem; } -GType sp_shape_get_type (void) G_GNUC_CONST; /** * Base class for shapes, including <path> element */ class SPShape : public SPLPEItem { public: - void setShape (); + SPShape(); + virtual ~SPShape(); + SPCurve * getCurve () const; SPCurve * getCurveBeforeLPE () const; void setCurve (SPCurve *curve, unsigned int owner); @@ -57,21 +55,26 @@ public: sigc::connection _release_connect [SP_MARKER_LOC_QTY]; sigc::connection _modified_connect [SP_MARKER_LOC_QTY]; -private: - friend class SPShapeClass; -}; + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void release(); + virtual void update(SPCtx* ctx, guint flags); + virtual void modified(unsigned int flags); -class SPShapeClass { -public: - SPLPEItemClass item_class; + virtual void set(unsigned int key, gchar const* value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); - /* Build bpath from extra shape attributes */ - void (* set_shape) (SPShape *shape); + virtual Geom::OptRect bbox(Geom::Affine const &transform, SPItem::BBoxType bboxtype); + virtual void print(SPPrintContext* ctx); -private: - friend class SPShape; + virtual Inkscape::DrawingItem* show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); + virtual void hide(unsigned int key); + + virtual void snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); + + virtual void set_shape(); }; + void sp_shape_set_marker (SPObject *object, unsigned int key, const gchar *value); Geom::Affine sp_shape_marker_get_transform(Geom::Curve const & c1, Geom::Curve const & c2); diff --git a/src/sp-skeleton.cpp b/src/sp-skeleton.cpp deleted file mode 100644 index b0f5bc91f..000000000 --- a/src/sp-skeleton.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/** \file - * SVG <skeleton> implementation, used as an example for a base starting class - * when implementing new sp-objects. - * - * In vi, three global search-and-replaces will let you rename everything - * in this and the .h file: - * - * :%s/SKELETON/YOURNAME/g - * :%s/Skeleton/Yourname/g - * :%s/skeleton/yourname/g - */ -/* - * Authors: - * Kees Cook <kees@outflux.net> - * Abhishek Sharma - * - * Copyright (C) 2004 Kees Cook - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "attributes.h" -#include "sp-skeleton.h" -#include "xml/repr.h" - -#define DEBUG_SKELETON -#ifdef DEBUG_SKELETON -# define debug(f, a...) { g_print("%s(%d) %s:", \ - __FILE__,__LINE__,__FUNCTION__); \ - g_print(f, ## a); \ - g_print("\n"); \ - } -#else -# define debug(f, a...) /**/ -#endif - -/* Skeleton base class */ -static void sp_skeleton_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_skeleton_release(SPObject *object); -static void sp_skeleton_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_skeleton_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_skeleton_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -G_DEFINE_TYPE(SPSkeleton, sp_skeleton, SP_TYPE_OBJECT); - -static void -sp_skeleton_class_init(SPSkeletonClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *)klass; - - sp_object_class->build = sp_skeleton_build; - sp_object_class->release = sp_skeleton_release; - sp_object_class->write = sp_skeleton_write; - sp_object_class->set = sp_skeleton_set; - sp_object_class->update = sp_skeleton_update; -} - -static void -sp_skeleton_init(SPSkeleton *skeleton) -{ - debug("0x%p",skeleton); -} - -/** - * Reads the Inkscape::XML::Node, and initializes SPSkeleton variables. For this to get called, - * our name must be associated with a repr via "sp_object_type_register". Best done through - * sp-object-repr.cpp's repr_name_entries array. - */ -static void -sp_skeleton_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - debug("0x%p",object); - if (((SPObjectClass *) sp_skeleton_parent_class)->build) { - ((SPObjectClass *) sp_skeleton_parent_class)->build(object, document, repr); - } - - /* - Pay attention to certain settings here - - object->readAttr( "xlink:href" ); - object->readAttr( "attributeName" ); - object->readAttr( "attributeType" ); - object->readAttr( "begin" ); - object->readAttr( "dur" ); - object->readAttr( "end" ); - object->readAttr( "min" ); - object->readAttr( "max" ); - object->readAttr( "restart" ); - object->readAttr( "repeatCount" ); - object->readAttr( "repeatDur" ); - object->readAttr( "fill" ); - */ -} - -/** - * Drops any allocated memory. - */ -static void -sp_skeleton_release(SPObject *object) -{ - debug("0x%p",object); - - /* deal with our children and our selves here */ - - if (((SPObjectClass *) sp_skeleton_parent_class)->release) - ((SPObjectClass *) sp_skeleton_parent_class)->release(object); -} - -/** - * Sets a specific value in the SPSkeleton. - */ -static void -sp_skeleton_set(SPObject *object, unsigned int key, gchar const *value) -{ - debug("0x%p %s(%u): '%s'",object, - sp_attribute_name(key),key,value ? value : "<no value>"); - //SPSkeleton *skeleton = SP_SKELETON(object); - - /* See if any parents need this value. */ - if (((SPObjectClass *) sp_skeleton_parent_class)->set) { - ((SPObjectClass *) sp_skeleton_parent_class)->set(object, key, value); - } -} - -/** - * Receives update notifications. - */ -static void -sp_skeleton_update(SPObject *object, SPCtx *ctx, guint flags) -{ - debug("0x%p",object); - //SPSkeleton *skeleton = SP_SKELETON(object); - - if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | - SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - - /* do something to trigger redisplay, updates? */ - - } - - if (((SPObjectClass *) sp_skeleton_parent_class)->update) { - ((SPObjectClass *) sp_skeleton_parent_class)->update(object, ctx, flags); - } -} - -/** - * Writes its settings to an incoming repr object, if any. - */ -static Inkscape::XML::Node * -sp_skeleton_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ - debug("0x%p",object); - //SPSkeleton *skeleton = SP_SKELETON(object); - - // Inkscape-only object, not copied during an "plain SVG" dump: - if (flags & SP_OBJECT_WRITE_EXT) { - if (repr) { - // is this sane? - repr->mergeFrom(object->getRepr(), "id"); - } else { - repr = object->getRepr()->duplicate(doc); - } - } - - if (((SPObjectClass *) sp_skeleton_parent_class)->write) { - ((SPObjectClass *) sp_skeleton_parent_class)->write(object, doc, repr, flags); - } - - return repr; -} - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-skeleton.h b/src/sp-skeleton.h deleted file mode 100644 index d01cbcada..000000000 --- a/src/sp-skeleton.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef SP_SKELETON_H_SEEN -#define SP_SKELETON_H_SEEN - -/** \file - * SVG <skeleton> implementation, see sp-skeleton.cpp. - */ -/* - * Authors: - * Kees Cook <kees@outflux.net> - * - * Copyright (C) 2004 Kees Cook - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "sp-object.h" - -/* Skeleton base class */ - -#define SP_TYPE_SKELETON (sp_skeleton_get_type()) -#define SP_SKELETON(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_SKELETON, SPSkeleton)) -#define SP_IS_SKELETON(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_SKELETON)) - -class SPSkeleton; -class SPSkeletonClass; - -struct SPSkeleton : public SPObject { -}; - -struct SPSkeletonClass { - SPObjectClass parent_class; -}; - -GType sp_skeleton_get_type(); - - -#endif /* !SP_SKELETON_H_SEEN */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-spiral.cpp b/src/sp-spiral.cpp index 43e552d68..8d2954c6e 100644 --- a/src/sp-spiral.cpp +++ b/src/sp-spiral.cpp @@ -28,85 +28,43 @@ #include "sp-spiral.h" -static void sp_spiral_build (SPObject * object, SPDocument * document, Inkscape::XML::Node * repr); -static Inkscape::XML::Node *sp_spiral_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_spiral_set (SPObject *object, unsigned int key, const gchar *value); -static void sp_spiral_update (SPObject *object, SPCtx *ctx, guint flags); -static gchar * sp_spiral_description (SPItem * item); -static void sp_spiral_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); +#include "sp-factory.h" -static void sp_spiral_set_shape (SPShape *shape); -static void sp_spiral_update_patheffect (SPLPEItem *lpeitem, bool write); +namespace { + SPObject* createSpiral() { + return new SPSpiral(); + } -static Geom::Point sp_spiral_get_tangent (SPSpiral const *spiral, gdouble t); - -G_DEFINE_TYPE(SPSpiral, sp_spiral, SP_TYPE_SHAPE); - -/** - * SPSpiral vtable initialization. - */ -static void sp_spiral_class_init(SPSpiralClass *klass) -{ - SPObjectClass *sp_object_class = reinterpret_cast<SPObjectClass *>(klass); - SPItemClass *item_class = reinterpret_cast<SPItemClass *>(klass); - SPLPEItemClass *lpe_item_class = reinterpret_cast<SPLPEItemClass *>(klass); - SPShapeClass *shape_class = reinterpret_cast<SPShapeClass *>(klass); - - sp_object_class->build = sp_spiral_build; - sp_object_class->write = sp_spiral_write; - sp_object_class->set = sp_spiral_set; - sp_object_class->update = sp_spiral_update; - - item_class->description = sp_spiral_description; - item_class->snappoints = sp_spiral_snappoints; - - lpe_item_class->update_patheffect = sp_spiral_update_patheffect; + bool spiralRegistered = SPFactory::instance().registerObject("spiral", createSpiral); +} - shape_class->set_shape = sp_spiral_set_shape; +SPSpiral::SPSpiral() : SPShape() { + this->cx = 0.0; + this->cy = 0.0; + this->exp = 1.0; + this->revo = 3.0; + this->rad = 1.0; + this->arg = 0.0; + this->t0 = 0.0; } -/** - * Callback for SPSpiral object initialization. - */ -static void -sp_spiral_init (SPSpiral * spiral) -{ - spiral->cx = 0.0; - spiral->cy = 0.0; - spiral->exp = 1.0; - spiral->revo = 3.0; - spiral->rad = 1.0; - spiral->arg = 0.0; - spiral->t0 = 0.0; +SPSpiral::~SPSpiral() { } -/** - * Virtual build: set spiral properties from corresponding repr. - */ -static void sp_spiral_build(SPObject * object, SPDocument * document, Inkscape::XML::Node * repr) -{ - if (reinterpret_cast<SPObjectClass *>(sp_spiral_parent_class)->build) { - reinterpret_cast<SPObjectClass *>(sp_spiral_parent_class)->build(object, document, repr); - } +void SPSpiral::build(SPDocument * document, Inkscape::XML::Node * repr) { + SPShape::build(document, repr); - object->readAttr( "sodipodi:cx" ); - object->readAttr( "sodipodi:cy" ); - object->readAttr( "sodipodi:expansion" ); - object->readAttr( "sodipodi:revolution" ); - object->readAttr( "sodipodi:radius" ); - object->readAttr( "sodipodi:argument" ); - object->readAttr( "sodipodi:t0" ); + this->readAttr("sodipodi:cx"); + this->readAttr("sodipodi:cy"); + this->readAttr("sodipodi:expansion"); + this->readAttr("sodipodi:revolution"); + this->readAttr("sodipodi:radius"); + this->readAttr("sodipodi:argument"); + this->readAttr("sodipodi:t0"); } -/** - * Virtual write: write spiral attributes to corresponding repr. - */ -static Inkscape::XML::Node * -sp_spiral_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPSpiral *spiral = SP_SPIRAL (object); - +Inkscape::XML::Node* SPSpiral::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:path"); } @@ -116,55 +74,51 @@ sp_spiral_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::X * sodipodi:spiral="cx cy exp revo rad arg t0" */ repr->setAttribute("sodipodi:type", "spiral"); - sp_repr_set_svg_double(repr, "sodipodi:cx", spiral->cx); - sp_repr_set_svg_double(repr, "sodipodi:cy", spiral->cy); - sp_repr_set_svg_double(repr, "sodipodi:expansion", spiral->exp); - sp_repr_set_svg_double(repr, "sodipodi:revolution", spiral->revo); - sp_repr_set_svg_double(repr, "sodipodi:radius", spiral->rad); - sp_repr_set_svg_double(repr, "sodipodi:argument", spiral->arg); - sp_repr_set_svg_double(repr, "sodipodi:t0", spiral->t0); + sp_repr_set_svg_double(repr, "sodipodi:cx", this->cx); + sp_repr_set_svg_double(repr, "sodipodi:cy", this->cy); + sp_repr_set_svg_double(repr, "sodipodi:expansion", this->exp); + sp_repr_set_svg_double(repr, "sodipodi:revolution", this->revo); + sp_repr_set_svg_double(repr, "sodipodi:radius", this->rad); + sp_repr_set_svg_double(repr, "sodipodi:argument", this->arg); + sp_repr_set_svg_double(repr, "sodipodi:t0", this->t0); } // make sure the curve is rebuilt with all up-to-date parameters - sp_spiral_set_shape(spiral); + this->set_shape(); //Nulls might be possible if this called iteratively - if ( !spiral->_curve ) { + if (!this->_curve) { //g_warning("sp_spiral_write(): No path to copy\n"); return NULL; } - char *d = sp_svg_write_path ( spiral->_curve->get_pathvector() ); + char *d = sp_svg_write_path(this->_curve->get_pathvector()); repr->setAttribute("d", d); - g_free (d); + g_free(d); - if (reinterpret_cast<SPObjectClass *>(sp_spiral_parent_class)->write) { - reinterpret_cast<SPObjectClass *>(sp_spiral_parent_class)->write(object, xml_doc, repr, flags | SP_SHAPE_WRITE_PATH); - } + SPShape::write(xml_doc, repr, flags | SP_SHAPE_WRITE_PATH); return repr; } -/** - * Virtual set: change spiral object attribute. - */ -static void sp_spiral_set(SPObject *object, unsigned int key, const gchar *value) -{ - SPSpiral *spiral = SP_SPIRAL(object); - +void SPSpiral::set(unsigned int key, gchar const* value) { /// \todo fixme: we should really collect updates switch (key) { case SP_ATTR_SODIPODI_CX: - if (!sp_svg_length_read_computed_absolute (value, &spiral->cx)) { - spiral->cx = 0.0; + if (!sp_svg_length_read_computed_absolute (value, &this->cx)) { + this->cx = 0.0; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_CY: - if (!sp_svg_length_read_computed_absolute (value, &spiral->cy)) { - spiral->cy = 0.0; + if (!sp_svg_length_read_computed_absolute (value, &this->cy)) { + this->cy = 0.0; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_EXPANSION: if (value) { /** \todo @@ -174,31 +128,37 @@ static void sp_spiral_set(SPObject *object, unsigned int key, const gchar *value * N.B. atof/sscanf/strtod consider "nan" and "inf" * to be valid numbers. */ - spiral->exp = g_ascii_strtod (value, NULL); - spiral->exp = CLAMP (spiral->exp, 0.0, 1000.0); + this->exp = g_ascii_strtod (value, NULL); + this->exp = CLAMP (this->exp, 0.0, 1000.0); } else { - spiral->exp = 1.0; + this->exp = 1.0; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_REVOLUTION: if (value) { - spiral->revo = g_ascii_strtod (value, NULL); - spiral->revo = CLAMP (spiral->revo, 0.05, 1024.0); + this->revo = g_ascii_strtod (value, NULL); + this->revo = CLAMP (this->revo, 0.05, 1024.0); } else { - spiral->revo = 3.0; + this->revo = 3.0; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_RADIUS: - if (!sp_svg_length_read_computed_absolute (value, &spiral->rad)) { - spiral->rad = MAX (spiral->rad, 0.001); + if (!sp_svg_length_read_computed_absolute (value, &this->rad)) { + this->rad = MAX (this->rad, 0.001); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_ARGUMENT: if (value) { - spiral->arg = g_ascii_strtod (value, NULL); + this->arg = g_ascii_strtod (value, NULL); /** \todo * FIXME: We still need some bounds on arg, for * numerical reasons. E.g., we don't want inf or NaN, @@ -208,14 +168,16 @@ static void sp_spiral_set(SPObject *object, unsigned int key, const gchar *value * results in very negative arg. */ } else { - spiral->arg = 0.0; + this->arg = 0.0; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_T0: if (value) { - spiral->t0 = g_ascii_strtod (value, NULL); - spiral->t0 = CLAMP (spiral->t0, 0.0, 0.999); + this->t0 = g_ascii_strtod (value, NULL); + this->t0 = CLAMP (this->t0, 0.0, 0.999); /** \todo * Have shared constants for the allowable bounds for * attributes. There was a bug here where we used -1.0 @@ -224,36 +186,32 @@ static void sp_spiral_set(SPObject *object, unsigned int key, const gchar *value * requirements. */ } else { - spiral->t0 = 0.0; + this->t0 = 0.0; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + default: - if (reinterpret_cast<SPObjectClass *>(sp_spiral_parent_class)->set) { - reinterpret_cast<SPObjectClass *>(sp_spiral_parent_class)->set(object, key, value); - } + SPShape::set(key, value); break; } } -/** - * Virtual update callback. - */ -static void sp_spiral_update(SPObject *object, SPCtx *ctx, guint flags) -{ +void SPSpiral::update(SPCtx *ctx, guint flags) { + SPSpiral* object = this; + if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - reinterpret_cast<SPShape *>(object)->setShape(); + reinterpret_cast<SPShape *>(object)->set_shape(); } - if (reinterpret_cast<SPObjectClass *>(sp_spiral_parent_class)->update) { - reinterpret_cast<SPObjectClass *>(sp_spiral_parent_class)->update(object, ctx, flags); - } + SPShape::update(ctx, flags); } -static void sp_spiral_update_patheffect(SPLPEItem *lpeitem, bool write) -{ - SPShape *shape = static_cast<SPShape *>(lpeitem); - sp_spiral_set_shape(shape); +void SPSpiral::update_patheffect(bool write) { + SPSpiral* shape = this; + + this->set_shape(); if (write) { Inkscape::XML::Node *repr = shape->getRepr(); @@ -269,17 +227,14 @@ static void sp_spiral_update_patheffect(SPLPEItem *lpeitem, bool write) shape->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } -/** - * Return textual description of spiral. - */ -static gchar *sp_spiral_description(SPItem * item) -{ - // TRANSLATORS: since turn count isn't an integer, please adjust the +gchar* SPSpiral::description() { + SPSpiral* item = this; + + // TRANSLATORS: since turn count isn't an integer, please adjust the // string as needed to deal with an localized plural forms. - return g_strdup_printf (_("<b>Spiral</b> with %3f turns"), SP_SPIRAL(item)->revo); + return g_strdup_printf (_("<b>Spiral</b> with %3f turns"), SP_SPIRAL(item)->revo); } - /** * Fit beziers together to spiral and draw it. * @@ -287,18 +242,11 @@ static gchar *sp_spiral_description(SPItem * item) * \pre is_unit_vector(*hat1). * \post is_unit_vector(*hat2). **/ -static void -sp_spiral_fit_and_draw (SPSpiral const *spiral, - SPCurve *c, - double dstep, - Geom::Point darray[], - Geom::Point const &hat1, - Geom::Point &hat2, - double *t) -{ +void SPSpiral::fitAndDraw(SPCurve* c, double dstep, Geom::Point darray[], Geom::Point const& hat1, Geom::Point& hat2, double* t) const { #define BEZIER_SIZE 4 #define FITTING_MAX_BEZIERS 4 #define BEZIER_LENGTH (BEZIER_SIZE * FITTING_MAX_BEZIERS) + g_assert (dstep > 0); g_assert (is_unit_vector (hat1)); @@ -307,13 +255,11 @@ sp_spiral_fit_and_draw (SPSpiral const *spiral, int depth, i; for (d = *t, i = 0; i <= SAMPLE_SIZE; d += dstep, i++) { - darray[i] = sp_spiral_get_xy(spiral, d); + darray[i] = this->getXY(d); /* Avoid useless adjacent dups. (Otherwise we can have all of darray filled with the same value, which upsets chord_length_parameterize.) */ - if ((i != 0) - && (darray[i] == darray[i - 1]) - && (d < 1.0)) { + if ((i != 0) && (darray[i] == darray[i - 1]) && (d < 1.0)) { i--; d += dstep; /** We mustn't increase dstep for subsequent values of @@ -338,7 +284,7 @@ sp_spiral_fit_and_draw (SPSpiral const *spiral, double const next_t = d - 2 * dstep; /* == t + (SAMPLE_SIZE - 1) * dstep, in absence of dups. */ - hat2 = -sp_spiral_get_tangent (spiral, next_t); + hat2 = -this->getTangent(next_t); /** \todo * We should use better algorithm to specify maximum error. @@ -347,12 +293,15 @@ sp_spiral_fit_and_draw (SPSpiral const *spiral, hat1, hat2, SPIRAL_TOLERANCE*SPIRAL_TOLERANCE, FITTING_MAX_BEZIERS); + g_assert(depth * BEZIER_SIZE <= gint(G_N_ELEMENTS(bezier))); + #ifdef SPIRAL_DEBUG if (*t == spiral->t0 || *t == 1.0) g_print ("[%s] depth=%d, dstep=%g, t0=%g, t=%g, arg=%g\n", debug_state, depth, dstep, spiral->t0, *t, spiral->arg); #endif + if (depth != -1) { for (i = 0; i < 4*depth; i += 4) { c->curveto(bezier[i + 1], @@ -366,17 +315,19 @@ sp_spiral_fit_and_draw (SPSpiral const *spiral, for (i = 1; i < SAMPLE_SIZE; i++) c->lineto(darray[i]); } + *t = next_t; + g_assert (is_unit_vector (hat2)); } -static void -sp_spiral_set_shape (SPShape *shape) -{ - SPSpiral *spiral = SP_SPIRAL(shape); +void SPSpiral::set_shape() { + SPSpiral *spiral = this; + SPSpiral* shape = spiral; if (sp_lpe_item_has_broken_path_effect(SP_LPE_ITEM(shape))) { g_warning ("The spiral shape has unknown LPE on it! Convert to path to make it editable preserving the appearance; editing it as spiral will remove the bad LPE"); + if (shape->getRepr()->attribute("d")) { // unconditionally read the curve from d, if any, to preserve appearance Geom::PathVector pv = sp_svg_read_pathv(shape->getRepr()->attribute("d")); @@ -385,6 +336,7 @@ sp_spiral_set_shape (SPShape *shape) shape->setCurveBeforeLPE( cold ); cold->unref(); } + return; } @@ -407,86 +359,74 @@ sp_spiral_set_shape (SPShape *shape) #endif /* Initial moveto. */ - c->moveto(sp_spiral_get_xy(spiral, spiral->t0)); + c->moveto(spiral->getXY(spiral->t0)); double const tstep = SAMPLE_STEP / spiral->revo; double const dstep = tstep / (SAMPLE_SIZE - 1); - Geom::Point hat1 = sp_spiral_get_tangent (spiral, spiral->t0); + Geom::Point hat1 = spiral->getTangent(spiral->t0); Geom::Point hat2; + for (t = spiral->t0; t < (1.0 - tstep);) { - sp_spiral_fit_and_draw (spiral, c, dstep, darray, hat1, hat2, &t); + spiral->fitAndDraw(c, dstep, darray, hat1, hat2, &t); hat1 = -hat2; } - if ((1.0 - t) > SP_EPSILON) - sp_spiral_fit_and_draw (spiral, c, (1.0 - t)/(SAMPLE_SIZE - 1.0), - darray, hat1, hat2, &t); + + if ((1.0 - t) > SP_EPSILON) { + spiral->fitAndDraw(c, (1.0 - t) / (SAMPLE_SIZE - 1.0), darray, hat1, hat2, &t); + } /* Reset the shape'scurve to the "original_curve" * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ shape->setCurveInsync( c, TRUE); shape->setCurveBeforeLPE( c ); + if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(shape)) && sp_lpe_item_path_effects_enabled(SP_LPE_ITEM(shape))) { SPCurve *c_lpe = c->copy(); bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM (shape), c_lpe); + if (success) { shape->setCurveInsync( c_lpe, TRUE); } + c_lpe->unref(); } + c->unref(); } /** * Set spiral properties and update display. */ -void -sp_spiral_position_set (SPSpiral *spiral, - gdouble cx, - gdouble cy, - gdouble exp, - gdouble revo, - gdouble rad, - gdouble arg, - gdouble t0) -{ - g_return_if_fail (spiral != NULL); - g_return_if_fail (SP_IS_SPIRAL (spiral)); - +void SPSpiral::setPosition(gdouble cx, gdouble cy, gdouble exp, gdouble revo, gdouble rad, gdouble arg, gdouble t0) { /** \todo * Consider applying CLAMP or adding in-bounds assertions for * some of these parameters. */ - spiral->cx = cx; - spiral->cy = cy; - spiral->exp = exp; - spiral->revo = revo; - spiral->rad = MAX (rad, 0.0); - spiral->arg = arg; - spiral->t0 = CLAMP(t0, 0.0, 0.999); - - (static_cast<SPObject *>(spiral))->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->cx = cx; + this->cy = cy; + this->exp = exp; + this->revo = revo; + this->rad = MAX (rad, 0.0); + this->arg = arg; + this->t0 = CLAMP(t0, 0.0, 0.999); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } -/** - * Virtual snappoints callback. - */ -static void sp_spiral_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) -{ +void SPSpiral::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) { // We will determine the spiral's midpoint ourselves, instead of trusting on the base class // Therefore snapping to object midpoints is temporarily disabled Inkscape::SnapPreferences local_snapprefs = *snapprefs; local_snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_OBJECT_MIDPOINT, false); - if ((reinterpret_cast<SPItemClass *>(sp_spiral_parent_class))->snappoints) { - (reinterpret_cast<SPItemClass *>(sp_spiral_parent_class))->snappoints (item, p, &local_snapprefs); - } + SPShape::snappoints(p, &local_snapprefs); if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_OBJECT_MIDPOINT)) { - Geom::Affine const i2dt (item->i2dt_affine ()); - SPSpiral *spiral = SP_SPIRAL(item); - p.push_back(Inkscape::SnapCandidatePoint(Geom::Point(spiral->cx, spiral->cy) * i2dt, Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT)); + Geom::Affine const i2dt (this->i2dt_affine ()); + + p.push_back(Inkscape::SnapCandidatePoint(Geom::Point(this->cx, this->cy) * i2dt, Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT)); // This point is the start-point of the spiral, which is also returned when _snap_to_itemnode has been set // in the object snapper. In that case we will get a duplicate! } @@ -500,22 +440,18 @@ static void sp_spiral_snappoints(SPItem const *item, std::vector<Inkscape::SnapC * than 1.0, though some callers go slightly beyond 1.0 for curve-fitting * purposes.) */ -Geom::Point sp_spiral_get_xy (SPSpiral const *spiral, gdouble t) -{ - g_assert (spiral != NULL); - g_assert (SP_IS_SPIRAL(spiral)); - g_assert (spiral->exp >= 0.0); +Geom::Point SPSpiral::getXY(gdouble t) const { + g_assert (this->exp >= 0.0); /* Otherwise we get NaN for t==0. */ - g_assert (spiral->exp <= 1000.0); + g_assert (this->exp <= 1000.0); /* Anything much more results in infinities. Even allowing 1000 is somewhat overkill. */ g_assert (t >= 0.0); /* Any callers passing -ve t will have a bug for non-integral values of exp. */ - double const rad = spiral->rad * pow(t, (double) spiral->exp); - double const arg = 2.0 * M_PI * spiral->revo * t + spiral->arg; + double const rad = this->rad * pow(t, (double)this->exp); + double const arg = 2.0 * M_PI * this->revo * t + this->arg; - return Geom::Point(rad * cos (arg) + spiral->cx, - rad * sin (arg) + spiral->cy); + return Geom::Point(rad * cos(arg) + this->cx, rad * sin(arg) + this->cy); } @@ -528,28 +464,24 @@ Geom::Point sp_spiral_get_xy (SPSpiral const *spiral, gdouble t) * \pre p != NULL. * \post is_unit_vector(*p). */ -static Geom::Point -sp_spiral_get_tangent (SPSpiral const *spiral, gdouble t) -{ +Geom::Point SPSpiral::getTangent(gdouble t) const { Geom::Point ret(1.0, 0.0); - g_return_val_if_fail (( ( spiral != NULL ) - && SP_IS_SPIRAL(spiral) ), - ret); + g_assert (t >= 0.0); - g_assert (spiral->exp >= 0.0); + g_assert (this->exp >= 0.0); /* See above for comments on these assertions. */ - double const t_scaled = 2.0 * M_PI * spiral->revo * t; - double const arg = t_scaled + spiral->arg; - double const s = sin (arg); - double const c = cos (arg); + double const t_scaled = 2.0 * M_PI * this->revo * t; + double const arg = t_scaled + this->arg; + double const s = sin(arg); + double const c = cos(arg); - if (spiral->exp == 0.0) { + if (this->exp == 0.0) { ret = Geom::Point(-s, c); } else if (t_scaled == 0.0) { ret = Geom::Point(c, s); } else { - Geom::Point unrotated(spiral->exp, t_scaled); + Geom::Point unrotated(this->exp, t_scaled); double const s_len = L2 (unrotated); g_assert (s_len != 0); /** \todo @@ -581,43 +513,43 @@ sp_spiral_get_tangent (SPSpiral const *spiral, gdouble t) /* Proof that ret length is non-zero: see above. (Should be near 1.) */ } - g_assert (is_unit_vector (ret)); + g_assert (is_unit_vector(ret)); return ret; } /** * Compute rad and/or arg for point on spiral. */ -void -sp_spiral_get_polar (SPSpiral const *spiral, gdouble t, gdouble *rad, gdouble *arg) -{ - g_return_if_fail (spiral != NULL); - g_return_if_fail (SP_IS_SPIRAL(spiral)); - - if (rad) - *rad = spiral->rad * pow(t, (double) spiral->exp); - if (arg) - *arg = 2.0 * M_PI * spiral->revo * t + spiral->arg; +void SPSpiral::getPolar(gdouble t, gdouble* rad, gdouble* arg) const { + if (rad) { + *rad = this->rad * pow(t, (double)this->exp); + } + + if (arg) { + *arg = 2.0 * M_PI * this->revo * t + this->arg; + } } /** * Return true if spiral has properties that make it invalid. */ -bool -sp_spiral_is_invalid (SPSpiral const *spiral) -{ +bool SPSpiral::isInvalid() const { gdouble rad; - sp_spiral_get_polar (spiral, 0.0, &rad, NULL); + this->getPolar(0.0, &rad, NULL); + if (rad < 0.0 || rad > SP_HUGE) { - g_print ("rad(t=0)=%g\n", rad); + g_print("rad(t=0)=%g\n", rad); return TRUE; } - sp_spiral_get_polar (spiral, 1.0, &rad, NULL); + + this->getPolar(1.0, &rad, NULL); + if (rad < 0.0 || rad > SP_HUGE) { - g_print ("rad(t=1)=%g\n", rad); + g_print("rad(t=1)=%g\n", rad); return TRUE; } + return FALSE; } diff --git a/src/sp-spiral.h b/src/sp-spiral.h index 64cb8521b..1e9c2d2b4 100644 --- a/src/sp-spiral.h +++ b/src/sp-spiral.h @@ -23,11 +23,9 @@ #define SAMPLE_STEP (1.0/4.0) ///< step per 2PI #define SAMPLE_SIZE 8 ///< sample size per one bezier -#define SP_TYPE_SPIRAL (sp_spiral_get_type ()) -#define SP_SPIRAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_SPIRAL, SPSpiral)) -#define SP_SPIRAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_SPIRAL, SPSpiralClass)) -#define SP_IS_SPIRAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_SPIRAL)) -#define SP_IS_SPIRAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_SPIRAL)) + +#define SP_SPIRAL(obj) (dynamic_cast<SPSpiral*>((SPObject*)obj)) +#define SP_IS_SPIRAL(obj) (dynamic_cast<const SPSpiral*>((SPObject*)obj) != NULL) /** * A spiral Shape. @@ -41,45 +39,42 @@ * * \todo Should I remove these attributes? */ -struct SPSpiral : public SPShape { +class SPSpiral : public SPShape { +public: + SPSpiral(); + virtual ~SPSpiral(); + float cx, cy; float exp; ///< Spiral expansion factor float revo; ///< Spiral revolution factor float rad; ///< Spiral radius float arg; ///< Spiral argument float t0; -}; - -/// The SPSpiral vtable. -struct SPSpiralClass { - SPShapeClass parent_class; -}; + /* Lowlevel interface */ + void setPosition(gdouble cx, gdouble cy, gdouble exp, gdouble revo, gdouble rad, gdouble arg, gdouble t0); -/* Standard Gtk function */ -GType sp_spiral_get_type (void); + Geom::Point getXY(gdouble t) const; -/* Lowlevel interface */ -void sp_spiral_position_set (SPSpiral *spiral, - gdouble cx, - gdouble cy, - gdouble exp, - gdouble revo, - gdouble rad, - gdouble arg, - gdouble t0); + void getPolar(gdouble t, gdouble* rad, gdouble* arg) const; -Geom::Point sp_spiral_get_xy (SPSpiral const *spiral, - gdouble t); + bool isInvalid() const; -void sp_spiral_get_polar (SPSpiral const *spiral, - gdouble t, - gdouble *rad, - gdouble *arg); +//private: + Geom::Point getTangent(gdouble t) const; -bool sp_spiral_is_invalid (SPSpiral const *spiral); + void fitAndDraw(SPCurve* c, double dstep, Geom::Point darray[], Geom::Point const& hat1, Geom::Point& hat2, double* t) const; + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + virtual void update(SPCtx *ctx, guint flags); + virtual void set(unsigned int key, gchar const* value); + virtual void snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); + virtual gchar* description(); + virtual void set_shape(); + virtual void update_patheffect(bool write); +}; #endif // SEEN_SP_SPIRAL_H diff --git a/src/sp-star.cpp b/src/sp-star.cpp index af2420340..4a3a8cbe3 100644 --- a/src/sp-star.cpp +++ b/src/sp-star.cpp @@ -32,227 +32,215 @@ #include "sp-star.h" -static void sp_star_build (SPObject * object, SPDocument * document, Inkscape::XML::Node * repr); -static Inkscape::XML::Node *sp_star_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_star_set (SPObject *object, unsigned int key, const gchar *value); -static void sp_star_update (SPObject *object, SPCtx *ctx, guint flags); +#include "sp-factory.h" -static gchar * sp_star_description (SPItem * item); -static void sp_star_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); +namespace { + SPObject* createStar() { + return new SPStar(); + } -static void sp_star_set_shape (SPShape *shape); -static void sp_star_update_patheffect (SPLPEItem *lpeitem, bool write); - -G_DEFINE_TYPE(SPStar, sp_star, SP_TYPE_SHAPE); - -static void sp_star_class_init(SPStarClass *klass) -{ - SPObjectClass *sp_object_class = SP_OBJECT_CLASS(klass); - SPItemClass *item_class = SP_ITEM_CLASS(klass); - SPLPEItemClass *lpe_item_class = SP_LPE_ITEM_CLASS(klass); - SPShapeClass *shape_class = SP_SHAPE_CLASS(klass); - - sp_object_class->build = sp_star_build; - sp_object_class->write = sp_star_write; - sp_object_class->set = sp_star_set; - sp_object_class->update = sp_star_update; - - item_class->description = sp_star_description; - item_class->snappoints = sp_star_snappoints; - - lpe_item_class->update_patheffect = sp_star_update_patheffect; - - shape_class->set_shape = sp_star_set_shape; + bool starRegistered = SPFactory::instance().registerObject("star", createStar); } -static void -sp_star_init (SPStar * star) -{ - star->sides = 5; - star->center = Geom::Point(0, 0); - star->r[0] = 1.0; - star->r[1] = 0.001; - star->arg[0] = star->arg[1] = 0.0; - star->flatsided = 0; - star->rounded = 0.0; - star->randomized = 0.0; +SPStar::SPStar() : SPPolygon() { + this->sides = 5; + this->center = Geom::Point(0, 0); + this->r[0] = 1.0; + this->r[1] = 0.001; + this->arg[0] = this->arg[1] = 0.0; + this->flatsided = 0; + this->rounded = 0.0; + this->randomized = 0.0; } -static void -sp_star_build (SPObject * object, SPDocument * document, Inkscape::XML::Node * repr) -{ - if (((SPObjectClass *) sp_star_parent_class)->build) - ((SPObjectClass *) sp_star_parent_class)->build (object, document, repr); - - object->readAttr( "sodipodi:cx" ); - object->readAttr( "sodipodi:cy" ); - object->readAttr( "sodipodi:sides" ); - object->readAttr( "sodipodi:r1" ); - object->readAttr( "sodipodi:r2" ); - object->readAttr( "sodipodi:arg1" ); - object->readAttr( "sodipodi:arg2" ); - object->readAttr( "inkscape:flatsided" ); - object->readAttr( "inkscape:rounded" ); - object->readAttr( "inkscape:randomized" ); +SPStar::~SPStar() { } -static Inkscape::XML::Node * -sp_star_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPStar *star = SP_STAR (object); +void SPStar::build(SPDocument * document, Inkscape::XML::Node * repr) { + // CPPIFY: see header file + SPShape::build(document, repr); + + this->readAttr( "sodipodi:cx" ); + this->readAttr( "sodipodi:cy" ); + this->readAttr( "sodipodi:sides" ); + this->readAttr( "sodipodi:r1" ); + this->readAttr( "sodipodi:r2" ); + this->readAttr( "sodipodi:arg1" ); + this->readAttr( "sodipodi:arg2" ); + this->readAttr( "inkscape:flatsided" ); + this->readAttr( "inkscape:rounded" ); + this->readAttr( "inkscape:randomized" ); +} +Inkscape::XML::Node* SPStar::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:path"); } if (flags & SP_OBJECT_WRITE_EXT) { repr->setAttribute("sodipodi:type", "star"); - sp_repr_set_int (repr, "sodipodi:sides", star->sides); - sp_repr_set_svg_double(repr, "sodipodi:cx", star->center[Geom::X]); - sp_repr_set_svg_double(repr, "sodipodi:cy", star->center[Geom::Y]); - sp_repr_set_svg_double(repr, "sodipodi:r1", star->r[0]); - sp_repr_set_svg_double(repr, "sodipodi:r2", star->r[1]); - sp_repr_set_svg_double(repr, "sodipodi:arg1", star->arg[0]); - sp_repr_set_svg_double(repr, "sodipodi:arg2", star->arg[1]); - sp_repr_set_boolean (repr, "inkscape:flatsided", star->flatsided); - sp_repr_set_svg_double(repr, "inkscape:rounded", star->rounded); - sp_repr_set_svg_double(repr, "inkscape:randomized", star->randomized); + sp_repr_set_int (repr, "sodipodi:sides", this->sides); + sp_repr_set_svg_double(repr, "sodipodi:cx", this->center[Geom::X]); + sp_repr_set_svg_double(repr, "sodipodi:cy", this->center[Geom::Y]); + sp_repr_set_svg_double(repr, "sodipodi:r1", this->r[0]); + sp_repr_set_svg_double(repr, "sodipodi:r2", this->r[1]); + sp_repr_set_svg_double(repr, "sodipodi:arg1", this->arg[0]); + sp_repr_set_svg_double(repr, "sodipodi:arg2", this->arg[1]); + sp_repr_set_boolean (repr, "inkscape:flatsided", this->flatsided); + sp_repr_set_svg_double(repr, "inkscape:rounded", this->rounded); + sp_repr_set_svg_double(repr, "inkscape:randomized", this->randomized); } - sp_star_set_shape ((SPShape *) star); - char *d = sp_svg_write_path (star->_curve->get_pathvector()); + this->set_shape(); + + char *d = sp_svg_write_path (this->_curve->get_pathvector()); repr->setAttribute("d", d); - g_free (d); + g_free(d); - if (((SPObjectClass *) (sp_star_parent_class))->write) - ((SPObjectClass *) (sp_star_parent_class))->write (object, xml_doc, repr, flags); + // CPPIFY: see header file + SPShape::write(xml_doc, repr, flags); return repr; } -static void -sp_star_set (SPObject *object, unsigned int key, const gchar *value) -{ +void SPStar::set(unsigned int key, const gchar* value) { SVGLength::Unit unit; - SPStar *star = SP_STAR (object); - /* fixme: we should really collect updates */ switch (key) { case SP_ATTR_SODIPODI_SIDES: if (value) { - star->sides = atoi (value); - star->sides = CLAMP(star->sides, 3, 1024); + this->sides = atoi (value); + this->sides = CLAMP(this->sides, 3, 1024); } else { - star->sides = 5; + this->sides = 5; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_CX: - if (!sp_svg_length_read_ldd (value, &unit, NULL, &star->center[Geom::X]) || + if (!sp_svg_length_read_ldd (value, &unit, NULL, &this->center[Geom::X]) || (unit == SVGLength::EM) || (unit == SVGLength::EX) || (unit == SVGLength::PERCENT)) { - star->center[Geom::X] = 0.0; + this->center[Geom::X] = 0.0; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_CY: - if (!sp_svg_length_read_ldd (value, &unit, NULL, &star->center[Geom::Y]) || + if (!sp_svg_length_read_ldd (value, &unit, NULL, &this->center[Geom::Y]) || (unit == SVGLength::EM) || (unit == SVGLength::EX) || (unit == SVGLength::PERCENT)) { - star->center[Geom::Y] = 0.0; + this->center[Geom::Y] = 0.0; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_R1: - if (!sp_svg_length_read_ldd (value, &unit, NULL, &star->r[0]) || + if (!sp_svg_length_read_ldd (value, &unit, NULL, &this->r[0]) || (unit == SVGLength::EM) || (unit == SVGLength::EX) || (unit == SVGLength::PERCENT)) { - star->r[0] = 1.0; + this->r[0] = 1.0; } + /* fixme: Need CLAMP (Lauris) */ - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_R2: - if (!sp_svg_length_read_ldd (value, &unit, NULL, &star->r[1]) || + if (!sp_svg_length_read_ldd (value, &unit, NULL, &this->r[1]) || (unit == SVGLength::EM) || (unit == SVGLength::EX) || (unit == SVGLength::PERCENT)) { - star->r[1] = 0.0; + this->r[1] = 0.0; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); return; + case SP_ATTR_SODIPODI_ARG1: if (value) { - star->arg[0] = g_ascii_strtod (value, NULL); + this->arg[0] = g_ascii_strtod (value, NULL); } else { - star->arg[0] = 0.0; + this->arg[0] = 0.0; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_SODIPODI_ARG2: if (value) { - star->arg[1] = g_ascii_strtod (value, NULL); + this->arg[1] = g_ascii_strtod (value, NULL); } else { - star->arg[1] = 0.0; + this->arg[1] = 0.0; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_INKSCAPE_FLATSIDED: - if (value && !strcmp (value, "true")) - star->flatsided = true; - else star->flatsided = false; - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + if (value && !strcmp(value, "true")) { + this->flatsided = true; + } else { + this->flatsided = false; + } + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_INKSCAPE_ROUNDED: if (value) { - star->rounded = g_ascii_strtod (value, NULL); + this->rounded = g_ascii_strtod (value, NULL); } else { - star->rounded = 0.0; + this->rounded = 0.0; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_INKSCAPE_RANDOMIZED: if (value) { - star->randomized = g_ascii_strtod (value, NULL); + this->randomized = g_ascii_strtod (value, NULL); } else { - star->randomized = 0.0; + this->randomized = 0.0; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + default: - if (((SPObjectClass *) sp_star_parent_class)->set) - ((SPObjectClass *) sp_star_parent_class)->set (object, key, value); + // CPPIFY: see header file + SPShape::set(key, value); break; } } -static void -sp_star_update (SPObject *object, SPCtx *ctx, guint flags) -{ +void SPStar::update(SPCtx *ctx, guint flags) { if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - ((SPShape *) object)->setShape (); + + this->set_shape(); } - if (((SPObjectClass *) sp_star_parent_class)->update) - ((SPObjectClass *) sp_star_parent_class)->update (object, ctx, flags); + // CPPIFY: see header file + SPShape::update(ctx, flags); } -static void -sp_star_update_patheffect(SPLPEItem *lpeitem, bool write) -{ - SPShape *shape = (SPShape *) lpeitem; - sp_star_set_shape(shape); +void SPStar::update_patheffect(bool write) { + this->set_shape(); if (write) { - Inkscape::XML::Node *repr = shape->getRepr(); - if ( shape->_curve != NULL ) { - gchar *str = sp_svg_write_path(shape->_curve->get_pathvector()); + Inkscape::XML::Node *repr = this->getRepr(); + + if ( this->_curve != NULL ) { + gchar *str = sp_svg_write_path(this->_curve->get_pathvector()); repr->setAttribute("d", str); g_free(str); } else { @@ -260,25 +248,22 @@ sp_star_update_patheffect(SPLPEItem *lpeitem, bool write) } } - ((SPObject *)shape)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } -static gchar * -sp_star_description (SPItem *item) -{ - SPStar *star = SP_STAR (item); - +gchar* SPStar::description() { // while there will never be less than 3 vertices, we still need to // make calls to ngettext because the pluralization may be different // for various numbers >=3. The singular form is used as the index. - if (star->flatsided == false ) - return g_strdup_printf (ngettext("<b>Star</b> with %d vertex", + if (this->flatsided == false) { + return g_strdup_printf (ngettext("<b>Star</b> with %d vertex", "<b>Star</b> with %d vertices", - star->sides), star->sides); - else + this->sides), this->sides); + } else { return g_strdup_printf (ngettext("<b>Polygon</b> with %d vertex", "<b>Polygon</b> with %d vertices", - star->sides), star->sides); + this->sides), this->sides); + } } /** @@ -387,105 +372,107 @@ sp_star_get_curvepoint (SPStar *star, SPStarPoint point, gint index, bool previ) } } - #define NEXT false #define PREV true -static void -sp_star_set_shape (SPShape *shape) -{ - SPStar *star = SP_STAR (shape); - +void SPStar::set_shape() { // perhaps we should convert all our shapes into LPEs without source path // and with knotholders for parameters, then this situation will be handled automatically // by disabling the entire stack (including the shape LPE) - if (sp_lpe_item_has_broken_path_effect(SP_LPE_ITEM(shape))) { + if (sp_lpe_item_has_broken_path_effect(SP_LPE_ITEM(this))) { g_warning ("The star shape has unknown LPE on it! Convert to path to make it editable preserving the appearance; editing it as star will remove the bad LPE"); - if (shape->getRepr()->attribute("d")) { + + if (this->getRepr()->attribute("d")) { // unconditionally read the curve from d, if any, to preserve appearance - Geom::PathVector pv = sp_svg_read_pathv(shape->getRepr()->attribute("d")); + Geom::PathVector pv = sp_svg_read_pathv(this->getRepr()->attribute("d")); SPCurve *cold = new SPCurve(pv); - shape->setCurveInsync( cold, TRUE); - shape->setCurveBeforeLPE(cold); + this->setCurveInsync( cold, TRUE); + this->setCurveBeforeLPE(cold); cold->unref(); } + return; } SPCurve *c = new SPCurve (); - gint sides = star->sides; - bool not_rounded = (fabs (star->rounded) < 1e-4); + gint sides = this->sides; + bool not_rounded = (fabs (this->rounded) < 1e-4); // note that we pass randomized=true to sp_star_get_xy, because the curve must be randomized; // other places that call that function (e.g. the knotholder) need the exact point // draw 1st segment - c->moveto(sp_star_get_xy (star, SP_STAR_POINT_KNOT1, 0, true)); - if (star->flatsided == false) { + c->moveto(sp_star_get_xy (this, SP_STAR_POINT_KNOT1, 0, true)); + + if (this->flatsided == false) { if (not_rounded) { - c->lineto(sp_star_get_xy (star, SP_STAR_POINT_KNOT2, 0, true)); + c->lineto(sp_star_get_xy (this, SP_STAR_POINT_KNOT2, 0, true)); } else { - c->curveto(sp_star_get_curvepoint (star, SP_STAR_POINT_KNOT1, 0, NEXT), - sp_star_get_curvepoint (star, SP_STAR_POINT_KNOT2, 0, PREV), - sp_star_get_xy (star, SP_STAR_POINT_KNOT2, 0, true)); + c->curveto(sp_star_get_curvepoint (this, SP_STAR_POINT_KNOT1, 0, NEXT), + sp_star_get_curvepoint (this, SP_STAR_POINT_KNOT2, 0, PREV), + sp_star_get_xy (this, SP_STAR_POINT_KNOT2, 0, true)); } } // draw all middle segments for (gint i = 1; i < sides; i++) { if (not_rounded) { - c->lineto(sp_star_get_xy (star, SP_STAR_POINT_KNOT1, i, true)); + c->lineto(sp_star_get_xy (this, SP_STAR_POINT_KNOT1, i, true)); } else { - if (star->flatsided == false) { - c->curveto(sp_star_get_curvepoint (star, SP_STAR_POINT_KNOT2, i - 1, NEXT), - sp_star_get_curvepoint (star, SP_STAR_POINT_KNOT1, i, PREV), - sp_star_get_xy (star, SP_STAR_POINT_KNOT1, i, true)); + if (this->flatsided == false) { + c->curveto(sp_star_get_curvepoint (this, SP_STAR_POINT_KNOT2, i - 1, NEXT), + sp_star_get_curvepoint (this, SP_STAR_POINT_KNOT1, i, PREV), + sp_star_get_xy (this, SP_STAR_POINT_KNOT1, i, true)); } else { - c->curveto(sp_star_get_curvepoint (star, SP_STAR_POINT_KNOT1, i - 1, NEXT), - sp_star_get_curvepoint (star, SP_STAR_POINT_KNOT1, i, PREV), - sp_star_get_xy (star, SP_STAR_POINT_KNOT1, i, true)); + c->curveto(sp_star_get_curvepoint (this, SP_STAR_POINT_KNOT1, i - 1, NEXT), + sp_star_get_curvepoint (this, SP_STAR_POINT_KNOT1, i, PREV), + sp_star_get_xy (this, SP_STAR_POINT_KNOT1, i, true)); } } - if (star->flatsided == false) { + if (this->flatsided == false) { if (not_rounded) { - c->lineto(sp_star_get_xy (star, SP_STAR_POINT_KNOT2, i, true)); + c->lineto(sp_star_get_xy (this, SP_STAR_POINT_KNOT2, i, true)); } else { - c->curveto(sp_star_get_curvepoint (star, SP_STAR_POINT_KNOT1, i, NEXT), - sp_star_get_curvepoint (star, SP_STAR_POINT_KNOT2, i, PREV), - sp_star_get_xy (star, SP_STAR_POINT_KNOT2, i, true)); + c->curveto(sp_star_get_curvepoint (this, SP_STAR_POINT_KNOT1, i, NEXT), + sp_star_get_curvepoint (this, SP_STAR_POINT_KNOT2, i, PREV), + sp_star_get_xy (this, SP_STAR_POINT_KNOT2, i, true)); } } } // draw last segment - if (!not_rounded) { - if (star->flatsided == false) { - c->curveto(sp_star_get_curvepoint (star, SP_STAR_POINT_KNOT2, sides - 1, NEXT), - sp_star_get_curvepoint (star, SP_STAR_POINT_KNOT1, 0, PREV), - sp_star_get_xy (star, SP_STAR_POINT_KNOT1, 0, true)); - } else { - c->curveto(sp_star_get_curvepoint (star, SP_STAR_POINT_KNOT1, sides - 1, NEXT), - sp_star_get_curvepoint (star, SP_STAR_POINT_KNOT1, 0, PREV), - sp_star_get_xy (star, SP_STAR_POINT_KNOT1, 0, true)); - } - } + if (!not_rounded) { + if (this->flatsided == false) { + c->curveto(sp_star_get_curvepoint (this, SP_STAR_POINT_KNOT2, sides - 1, NEXT), + sp_star_get_curvepoint (this, SP_STAR_POINT_KNOT1, 0, PREV), + sp_star_get_xy (this, SP_STAR_POINT_KNOT1, 0, true)); + } else { + c->curveto(sp_star_get_curvepoint (this, SP_STAR_POINT_KNOT1, sides - 1, NEXT), + sp_star_get_curvepoint (this, SP_STAR_POINT_KNOT1, 0, PREV), + sp_star_get_xy (this, SP_STAR_POINT_KNOT1, 0, true)); + } + } c->closepath(); /* Reset the shape'scurve to the "original_curve" * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ - shape->setCurveInsync( c, TRUE); - shape->setCurveBeforeLPE( c ); - if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(shape)) && sp_lpe_item_path_effects_enabled(SP_LPE_ITEM(shape))) { + this->setCurveInsync( c, TRUE); + this->setCurveBeforeLPE( c ); + + if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(this)) && sp_lpe_item_path_effects_enabled(SP_LPE_ITEM(this))) { SPCurve *c_lpe = c->copy(); - bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM (shape), c_lpe); + bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM (this), c_lpe); + if (success) { - shape->setCurveInsync( c_lpe, TRUE); + this->setCurveInsync( c_lpe, TRUE); } + c_lpe->unref(); } + c->unref(); } @@ -498,11 +485,13 @@ sp_star_position_set (SPStar *star, gint sides, Geom::Point center, gdouble r1, star->sides = CLAMP(sides, 3, 1024); star->center = center; star->r[0] = MAX (r1, 0.001); + if (isflat == false) { star->r[1] = CLAMP(r2, 0.0, star->r[0]); } else { star->r[1] = CLAMP( r1*cos(M_PI/sides) ,0.0, star->r[0] ); } + star->arg[0] = arg1; star->arg[1] = arg2; star->flatsided = isflat; @@ -511,20 +500,18 @@ sp_star_position_set (SPStar *star, gint sides, Geom::Point center, gdouble r1, star->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } -static void sp_star_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) -{ +void SPStar::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) { // We will determine the star's midpoint ourselves, instead of trusting on the base class // Therefore snapping to object midpoints is temporarily disabled Inkscape::SnapPreferences local_snapprefs = *snapprefs; local_snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_OBJECT_MIDPOINT, false); - if (((SPItemClass *) sp_star_parent_class)->snappoints) { - ((SPItemClass *) sp_star_parent_class)->snappoints (item, p, &local_snapprefs); - } + // CPPIFY: see header file + SPShape::snappoints(p, &local_snapprefs); if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_OBJECT_MIDPOINT)) { - Geom::Affine const i2dt (item->i2dt_affine ()); - p.push_back(Inkscape::SnapCandidatePoint(SP_STAR(item)->center * i2dt,Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT)); + Geom::Affine const i2dt (this->i2dt_affine ()); + p.push_back(Inkscape::SnapCandidatePoint(this->center * i2dt,Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT)); } } @@ -538,7 +525,6 @@ static void sp_star_snappoints(SPItem const *item, std::vector<Inkscape::SnapCan * * Initial item coordinate system is same as document coordinate system. */ - Geom::Point sp_star_get_xy (SPStar const *star, SPStarPoint point, gint index, bool randomized) { diff --git a/src/sp-star.h b/src/sp-star.h index 888eeb8d2..0f1280139 100644 --- a/src/sp-star.h +++ b/src/sp-star.h @@ -16,18 +16,20 @@ #include "sp-polygon.h" -#define SP_TYPE_STAR (sp_star_get_type ()) -#define SP_STAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_STAR, SPStar)) -#define SP_STAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_STAR, SPStarClass)) -#define SP_IS_STAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_STAR)) -#define SP_IS_STAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_STAR)) + +#define SP_STAR(obj) (dynamic_cast<SPStar*>((SPObject*)obj)) +#define SP_IS_STAR(obj) (dynamic_cast<const SPStar*>((SPObject*)obj) != NULL) typedef enum { SP_STAR_POINT_KNOT1, SP_STAR_POINT_KNOT2 } SPStarPoint; -struct SPStar : public SPPolygon { +class SPStar : public SPPolygon { +public: + SPStar(); + virtual ~SPStar(); + gint sides; Geom::Point center; @@ -37,13 +39,23 @@ struct SPStar : public SPPolygon { double rounded; double randomized; -}; -struct SPStarClass { - SPPolygonClass parent_class; -}; +// CPPIFY: This derivation is a bit weird. +// parent_class = reinterpret_cast<SPShapeClass *>(g_type_class_ref(SP_TYPE_SHAPE)); +// So shouldn't star be derived from shape instead of polygon? +// What does polygon have that shape doesn't? -GType sp_star_get_type (void); + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + virtual void set(unsigned int key, gchar const* value); + virtual void update(SPCtx* ctx, guint flags); + + virtual gchar* description(); + virtual void snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); + + virtual void update_patheffect(bool write); + virtual void set_shape(); +}; void sp_star_position_set (SPStar *star, gint sides, Geom::Point center, gdouble r1, gdouble r2, gdouble arg1, gdouble arg2, bool isflat, double rounded, double randomized); diff --git a/src/sp-stop.cpp b/src/sp-stop.cpp index 0c0a3b03a..d644a9b4b 100644 --- a/src/sp-stop.cpp +++ b/src/sp-stop.cpp @@ -17,9 +17,166 @@ #include "sp-stop.h" #include "style.h" +#include "attributes.h" +#include "streq.h" +#include "svg/svg.h" +#include "svg/svg-color.h" +#include "svg/css-ostringstream.h" +#include "xml/repr.h" + +#include "sp-factory.h" + +namespace { + SPObject* createStop() { + return new SPStop(); + } + + bool stopRegistered = SPFactory::instance().registerObject("svg:stop", createStop); +} + +SPStop::SPStop() : SPObject() { + this->path_string = NULL; + + this->offset = 0.0; + this->currentColor = false; + this->specified_color.set( 0x000000ff ); + this->opacity = 1.0; +} + +SPStop::~SPStop() { +} + +void SPStop::build(SPDocument* doc, Inkscape::XML::Node* repr) { + SPObject::build(doc, repr); + + this->readAttr( "offset" ); + this->readAttr( "stop-color" ); + this->readAttr( "stop-opacity" ); + this->readAttr( "style" ); + this->readAttr( "path" ); // For mesh +} + +/** + * Virtual build: set stop attributes from its associated XML node. + */ + +void SPStop::set(unsigned int key, const gchar* value) { + switch (key) { + case SP_ATTR_STYLE: { + /** \todo + * fixme: We are reading simple values 3 times during build (Lauris). + * \par + * We need presentation attributes etc. + * \par + * remove the hackish "style reading" from here: see comments in + * sp_object_get_style_property about the bugs in our current + * approach. However, note that SPStyle doesn't currently have + * stop-color and stop-opacity properties. + */ + { + gchar const *p = this->getStyleProperty( "stop-color", "black"); + if (streq(p, "currentColor")) { + this->currentColor = true; + } else { + this->specified_color = SPStop::readStopColor( p ); + } + } + { + gchar const *p = this->getStyleProperty( "stop-opacity", "1"); + gdouble opacity = sp_svg_read_percentage(p, this->opacity); + this->opacity = opacity; + } + this->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + break; + } + case SP_PROP_STOP_COLOR: { + { + gchar const *p = this->getStyleProperty( "stop-color", "black"); + if (streq(p, "currentColor")) { + this->currentColor = true; + } else { + this->currentColor = false; + this->specified_color = SPStop::readStopColor( p ); + } + } + this->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + break; + } + case SP_PROP_STOP_OPACITY: { + { + gchar const *p = this->getStyleProperty( "stop-opacity", "1"); + gdouble opacity = sp_svg_read_percentage(p, this->opacity); + this->opacity = opacity; + } + this->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + break; + } + case SP_ATTR_OFFSET: { + this->offset = sp_svg_read_percentage(value, 0.0); + this->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + break; + } + case SP_PROP_STOP_PATH: { + if (value) { + this->path_string = new Glib::ustring( value ); + //Geom::PathVector pv = sp_svg_read_pathv(value); + //SPCurve *curve = new SPCurve(pv); + //if( curve ) { + // std::cout << "Got Curve" << std::endl; + //curve->unref(); + //} + } + break; + } + default: { + SPObject::set(key, value); + break; + } + } +} + +/** + * Virtual set: set attribute to value. + */ + +Inkscape::XML::Node* SPStop::write(Inkscape::XML::Document* xml_doc, Inkscape::XML::Node* repr, guint flags) { + if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { + repr = xml_doc->createElement("svg:stop"); + } + + Glib::ustring colorStr = this->specified_color.toString(); + gfloat opacity = this->opacity; + + SPObject::write(xml_doc, repr, flags); + + // Since we do a hackish style setting here (because SPStyle does not support stop-color and + // stop-opacity), we must do it AFTER calling the parent write method; otherwise + // sp_object_write would clear our style= attribute (bug 1695287) + + Inkscape::CSSOStringStream os; + os << "stop-color:"; + if (this->currentColor) { + os << "currentColor"; + } else { + os << colorStr; + } + os << ";stop-opacity:" << opacity; + repr->setAttribute("style", os.str().c_str()); + repr->setAttribute("stop-color", NULL); + repr->setAttribute("stop-opacity", NULL); + sp_repr_set_css_double(repr, "offset", this->offset); + /* strictly speaking, offset an SVG <number> rather than a CSS one, but exponents make no sense + * for offset proportions. */ + + return repr; +} + +/** + * Virtual write: write object attributes to repr. + */ + // A stop might have some non-stop siblings -SPStop* SPStop::getNextStop() -{ +SPStop* SPStop::getNextStop() { SPStop *result = 0; for (SPObject* obj = getNext(); obj && !result; obj = obj->getNext()) { @@ -31,8 +188,7 @@ SPStop* SPStop::getNextStop() return result; } -SPStop* SPStop::getPrevStop() -{ +SPStop* SPStop::getPrevStop() { SPStop *result = 0; for (SPObject* obj = getPrev(); obj; obj = obj->getPrev()) { @@ -52,22 +208,24 @@ SPStop* SPStop::getPrevStop() return result; } -SPColor SPStop::readStopColor( Glib::ustring const &styleStr, guint32 dfl ) -{ +SPColor SPStop::readStopColor(Glib::ustring const &styleStr, guint32 dfl) { SPColor color(dfl); SPStyle* style = sp_style_new(0); SPIPaint paint; paint.read( styleStr.c_str(), *style ); + if ( paint.isColor() ) { color = paint.value.color; } + sp_style_unref(style); + return color; } -SPColor SPStop::getEffectiveColor() const -{ +SPColor SPStop::getEffectiveColor() const { SPColor ret; + if (currentColor) { char const *str = getStyleProperty("color", NULL); /* Default value: arbitrarily black. (SVG1.1 and CSS2 both say that the initial @@ -77,10 +235,35 @@ SPColor SPStop::getEffectiveColor() const } else { ret = specified_color; } + return ret; } +/** + * Return stop's color as 32bit value. + */ +guint32 SPStop::get_rgba32() const { + guint32 rgb0 = 0; + + /* Default value: arbitrarily black. (SVG1.1 and CSS2 both say that the initial + * value depends on user agent, and don't give any further restrictions that I can + * see.) */ + if (this->currentColor) { + char const *str = this->getStyleProperty("color", NULL); + if (str) { + rgb0 = sp_svg_read_color(str, rgb0); + } + + unsigned const alpha = static_cast<unsigned>(this->opacity * 0xff + 0.5); + + g_return_val_if_fail((alpha & ~0xff) == 0, rgb0 | 0xff); + + return rgb0 | alpha; + } else { + return this->specified_color.toRGBA32(this->opacity); + } +} /* Local Variables: diff --git a/src/sp-stop.h b/src/sp-stop.h index d22e86e00..b1996e054 100644 --- a/src/sp-stop.h +++ b/src/sp-stop.h @@ -16,16 +16,15 @@ namespace Glib { class ustring; } -#define SP_TYPE_STOP (sp_stop_get_type()) -#define SP_STOP(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_STOP, SPStop)) -#define SP_STOP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_STOP, SPStopClass)) -#define SP_IS_STOP(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_STOP)) -#define SP_IS_STOP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_STOP)) - -GType sp_stop_get_type(); +#define SP_STOP(obj) (dynamic_cast<SPStop*>((SPObject*)obj)) +#define SP_IS_STOP(obj) (dynamic_cast<const SPStop*>((SPObject*)obj) != NULL) /** Gradient stop. */ -struct SPStop : public SPObject { +class SPStop : public SPObject { +public: + SPStop(); + virtual ~SPStop(); + /// \todo fixme: Should be SPSVGPercentage gfloat offset; @@ -50,15 +49,14 @@ struct SPStop : public SPObject { SPColor getEffectiveColor() const; -}; + guint32 get_rgba32() const; -/// The SPStop vtable. -struct SPStopClass { - SPObjectClass parent_class; +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void set(unsigned int key, const gchar* value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); }; -guint32 sp_stop_get_rgba32(SPStop const *); - #endif /* !SEEN_SP_STOP_H */ diff --git a/src/sp-string.cpp b/src/sp-string.cpp index 457c248bc..be450b248 100644 --- a/src/sp-string.cpp +++ b/src/sp-string.cpp @@ -32,60 +32,42 @@ #include "sp-string.h" #include "xml/repr.h" +#include "sp-factory.h" + +namespace { + SPObject* createString() { + return new SPString(); + } + + bool stringRegistered = SPFactory::instance().registerObject("string", createString); +} /*##################################################### # SPSTRING #####################################################*/ -static void sp_string_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_string_release(SPObject *object); -static void sp_string_read_content(SPObject *object); -static void sp_string_update(SPObject *object, SPCtx *ctx, unsigned flags); - -G_DEFINE_TYPE(SPString, sp_string, SP_TYPE_OBJECT); - -static void -sp_string_class_init(SPStringClass *classname) -{ - SPObjectClass *sp_object_class; - - sp_object_class = (SPObjectClass *) classname; - - sp_object_class->build = sp_string_build; - sp_object_class->release = sp_string_release; - sp_object_class->read_content = sp_string_read_content; - sp_object_class->update = sp_string_update; +SPString::SPString() : SPObject() { + //new (&this->string) Glib::ustring(); } -static void -sp_string_init(SPString *string) -{ - new (&string->string) Glib::ustring(); +SPString::~SPString() { } -static void -sp_string_build(SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr) -{ - sp_string_read_content(object); +void SPString::build(SPDocument *doc, Inkscape::XML::Node *repr) { + SPString* object = this; + object->read_content(); - if (((SPObjectClass *) sp_string_parent_class)->build) - ((SPObjectClass *) sp_string_parent_class)->build(object, doc, repr); + SPObject::build(doc, repr); } -static void -sp_string_release(SPObject *object) -{ - SPString *string = SP_STRING(object); +void SPString::release() { + SPObject::release(); +} - string->string.~ustring(); - if (((SPObjectClass *) sp_string_parent_class)->release) - ((SPObjectClass *) sp_string_parent_class)->release(object); -} +void SPString::read_content() { + SPString* object = this; -static void -sp_string_read_content(SPObject *object) -{ SPString *string = SP_STRING(object); string->string.clear(); @@ -126,11 +108,8 @@ sp_string_read_content(SPObject *object) object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } -static void -sp_string_update(SPObject *object, SPCtx *ctx, unsigned flags) -{ - if (((SPObjectClass *) sp_string_parent_class)->update) - ((SPObjectClass *) sp_string_parent_class)->update(object, ctx, flags); +void SPString::update(SPCtx *ctx, unsigned flags) { +// SPObject::onUpdate(ctx, flags); // if (flags & (SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_MODIFIED_FLAG)) { // /* Parent style or we ourselves changed, so recalculate */ diff --git a/src/sp-string.h b/src/sp-string.h index 7242589c6..eabf76353 100644 --- a/src/sp-string.h +++ b/src/sp-string.h @@ -10,21 +10,22 @@ #include "sp-object.h" -#define SP_TYPE_STRING (sp_string_get_type ()) -#define SP_STRING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_STRING, SPString)) -#define SP_STRING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_STRING, SPStringClass)) -#define SP_IS_STRING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_STRING)) -#define SP_IS_STRING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_STRING)) +#define SP_STRING(obj) (dynamic_cast<SPString*>((SPObject*)obj)) +#define SP_IS_STRING(obj) (dynamic_cast<const SPString*>((SPObject*)obj) != NULL) +class SPString : public SPObject { +public: + SPString(); + virtual ~SPString(); -struct SPString : public SPObject { Glib::ustring string; -}; -struct SPStringClass { - SPObjectClass parent_class; -}; + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); -GType sp_string_get_type (); + virtual void read_content(); + + virtual void update(SPCtx* ctx, unsigned int flags); +}; #endif diff --git a/src/sp-style-elem.cpp b/src/sp-style-elem.cpp index da7a575b7..84f110134 100644 --- a/src/sp-style-elem.cpp +++ b/src/sp-style-elem.cpp @@ -7,34 +7,27 @@ #include "style.h" using Inkscape::XML::TEXT_NODE; -static void sp_style_elem_build(SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr); -static void sp_style_elem_set(SPObject *object, unsigned const key, gchar const *const value); -static void sp_style_elem_read_content(SPObject *); -static Inkscape::XML::Node *sp_style_elem_write(SPObject *, Inkscape::XML::Document *, Inkscape::XML::Node *, guint flags); +#include "sp-factory.h" -G_DEFINE_TYPE(SPStyleElem, sp_style_elem, SP_TYPE_OBJECT); +namespace { + SPObject* createStyle() { + return new SPStyleElem(); + } -static void -sp_style_elem_class_init(SPStyleElemClass *klass) -{ - /* FIXME */ + bool styleRegistered = SPFactory::instance().registerObject("svg:style", createStyle); +} - klass->build = sp_style_elem_build; - klass->set = sp_style_elem_set; - klass->read_content = sp_style_elem_read_content; - klass->write = sp_style_elem_write; +SPStyleElem::SPStyleElem() : SPObject() { + media_set_all(this->media); + this->is_css = false; } -static void -sp_style_elem_init(SPStyleElem *style_elem) -{ - media_set_all(style_elem->media); - style_elem->is_css = false; +SPStyleElem::~SPStyleElem() { } -static void -sp_style_elem_set(SPObject *object, unsigned const key, gchar const *const value) -{ +void SPStyleElem::set(unsigned int key, const gchar* value) { + SPStyleElem* object = this; + g_return_if_fail(object); SPStyleElem &style_elem = *SP_STYLE_ELEM(object); @@ -63,26 +56,25 @@ sp_style_elem_set(SPObject *object, unsigned const key, gchar const *const value /* title is ignored. */ default: { - if (SP_OBJECT_CLASS(sp_style_elem_parent_class)->set) { - SP_OBJECT_CLASS(sp_style_elem_parent_class)->set(object, key, value); - } + SPObject::set(key, value); break; } } } + static void child_add_rm_cb(Inkscape::XML::Node *, Inkscape::XML::Node *, Inkscape::XML::Node *, void *const data) { - sp_style_elem_read_content(static_cast<SPObject *>(data)); + static_cast<SPObject *>(data)->read_content(); } static void content_changed_cb(Inkscape::XML::Node *, gchar const *, gchar const *, void *const data) { - sp_style_elem_read_content(static_cast<SPObject *>(data)); + static_cast<SPObject *>(data)->read_content(); } static void @@ -90,12 +82,12 @@ child_order_changed_cb(Inkscape::XML::Node *, Inkscape::XML::Node *, Inkscape::XML::Node *, Inkscape::XML::Node *, void *const data) { - sp_style_elem_read_content(static_cast<SPObject *>(data)); + static_cast<SPObject *>(data)->read_content(); } -static Inkscape::XML::Node * -sp_style_elem_write(SPObject *const object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint const flags) -{ +Inkscape::XML::Node* SPStyleElem::write(Inkscape::XML::Document* xml_doc, Inkscape::XML::Node* repr, guint flags) { + SPStyleElem* object = this; + if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:style"); } @@ -112,8 +104,7 @@ sp_style_elem_write(SPObject *const object, Inkscape::XML::Document *xml_doc, In } /* todo: media */ - if (((SPObjectClass *) sp_style_elem_parent_class)->write) - ((SPObjectClass *) sp_style_elem_parent_class)->write(object, xml_doc, repr, flags); + SPObject::write(xml_doc, repr, flags); return repr; } @@ -271,9 +262,9 @@ property_cb(CRDocHandler *const a_handler, g_return_if_fail(append_status == CR_OK); } -static void -sp_style_elem_read_content(SPObject *const object) -{ +void SPStyleElem::read_content() { + SPStyleElem* object = this; + SPStyleElem &style_elem = *SP_STYLE_ELEM(object); /* fixme: If there's more than one <style> element in a document, then the document stylesheet @@ -359,10 +350,10 @@ rec_add_listener(Inkscape::XML::Node &repr, } } -static void -sp_style_elem_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - sp_style_elem_read_content(object); +void SPStyleElem::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPStyleElem* object = this; + + object->read_content(); object->readAttr( "type" ); object->readAttr( "media" ); @@ -376,12 +367,11 @@ sp_style_elem_build(SPObject *object, SPDocument *document, Inkscape::XML::Node }; rec_add_listener(*repr, &nodeEventVector, object); - if (((SPObjectClass *) sp_style_elem_parent_class)->build) { - ((SPObjectClass *) sp_style_elem_parent_class)->build(object, document, repr); - } + SPObject::build(document, repr); } + /* Local Variables: mode:c++ diff --git a/src/sp-style-elem.h b/src/sp-style-elem.h index e6823442b..8e8a2b3a8 100644 --- a/src/sp-style-elem.h +++ b/src/sp-style-elem.h @@ -4,23 +4,23 @@ #include "sp-object.h" #include "media.h" -#define SP_TYPE_STYLE_ELEM (sp_style_elem_get_type()) -#define SP_STYLE_ELEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_STYLE_ELEM, SPStyleElem)) -#define SP_STYLE_ELEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_STYLE_ELEM, SPStyleElemClass)) -#define SP_IS_STYLE_ELEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_STYLE_ELEM)) -#define SP_IS_STYLE_ELEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_STYLE_ELEM)) +#define SP_STYLE_ELEM(obj) (dynamic_cast<SPStyleElem*>((SPObject*)obj)) +#define SP_IS_STYLE_ELEM(obj) (dynamic_cast<const SPStyleElem*>((SPObject*)obj) != NULL) class SPStyleElem : public SPObject { public: + SPStyleElem(); + virtual ~SPStyleElem(); + Media media; bool is_css; -}; -class SPStyleElemClass : public SPObjectClass { + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void set(unsigned int key, gchar const* value); + virtual void read_content(); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); }; -GType sp_style_elem_get_type(); - #endif /* !INKSCAPE_SP_STYLE_ELEM_H */ diff --git a/src/sp-switch.cpp b/src/sp-switch.cpp index be9866e16..cc50a8fef 100644 --- a/src/sp-switch.cpp +++ b/src/sp-switch.cpp @@ -25,75 +25,74 @@ #include <sigc++/functors/ptr_fun.h> #include <sigc++/adaptors/bind.h> -G_DEFINE_TYPE(SPSwitch, sp_switch, SP_TYPE_GROUP); +#include "sp-factory.h" -static void -sp_switch_class_init (SPSwitchClass *) -{ -} - -static void sp_switch_init (SPSwitch *group) -{ - if (group->group) - delete group->group; +namespace { + SPObject* createSwitch() { + return new SPSwitch(); + } - group->group = new CSwitch(group); + bool switchRegistered = SPFactory::instance().registerObject("svg:switch", createSwitch); } -CSwitch::CSwitch(SPGroup *group) : CGroup(group), _cached_item(NULL) { +SPSwitch::SPSwitch() : SPGroup() { + this->_cached_item = 0; } -CSwitch::~CSwitch() { - _releaseLastItem(_cached_item); +SPSwitch::~SPSwitch() { } -SPObject *CSwitch::_evaluateFirst() { +SPObject *SPSwitch::_evaluateFirst() { SPObject *first = 0; - for (SPObject *child = _group->firstChild() ; child && !first ; child = child->getNext() ) { + + for (SPObject *child = this->firstChild() ; child && !first ; child = child->getNext() ) { if (SP_IS_ITEM(child) && sp_item_evaluate(SP_ITEM(child))) { - first = child; - } + first = child; + } } + return first; } -GSList *CSwitch::_childList(bool add_ref, SPObject::Action action) { +GSList *SPSwitch::_childList(bool add_ref, SPObject::Action action) { if ( action != SPObject::ActionGeneral ) { - return _group->childList(add_ref, action); + return this->childList(add_ref, action); } SPObject *child = _evaluateFirst(); if (NULL == child) return NULL; - if (add_ref) - g_object_ref (G_OBJECT (child)); + if (add_ref) { + //g_object_ref (G_OBJECT (child)); + sp_object_ref(child); + } return g_slist_prepend (NULL, child); } -gchar *CSwitch::getDescription() { - gint len = getItemCount(); +gchar *SPSwitch::description() { + gint len = this->getItemCount(); return g_strdup_printf( ngettext("<b>Conditional group</b> of <b>%d</b> object", "<b>Conditional group</b> of <b>%d</b> objects", len), len); } -void CSwitch::onChildAdded(Inkscape::XML::Node *) { - _reevaluate(true); +void SPSwitch::child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref) { + this->_reevaluate(true); } -void CSwitch::onChildRemoved(Inkscape::XML::Node *) { - _reevaluate(); +void SPSwitch::remove_child(Inkscape::XML::Node *) { + this->_reevaluate(); } -void CSwitch::onOrderChanged (Inkscape::XML::Node *, Inkscape::XML::Node *, Inkscape::XML::Node *) +void SPSwitch::order_changed (Inkscape::XML::Node *, Inkscape::XML::Node *, Inkscape::XML::Node *) { - _reevaluate(); + this->_reevaluate(); } -void CSwitch::_reevaluate(bool /*add_to_drawing*/) { +void SPSwitch::_reevaluate(bool /*add_to_drawing*/) { SPObject *evaluated_child = _evaluateFirst(); if (!evaluated_child || _cached_item == evaluated_child) { return; @@ -114,39 +113,43 @@ void CSwitch::_reevaluate(bool /*add_to_drawing*/) { } _cached_item = evaluated_child; - _release_connection = evaluated_child->connectRelease(sigc::bind(sigc::ptr_fun(&CSwitch::_releaseItem), this)); + _release_connection = evaluated_child->connectRelease(sigc::bind(sigc::ptr_fun(&SPSwitch::_releaseItem), this)); - _group->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); } -void CSwitch::_releaseItem(SPObject *obj, CSwitch *selection) +void SPSwitch::_releaseItem(SPObject *obj, SPSwitch *selection) { selection->_releaseLastItem(obj); } -void CSwitch::_releaseLastItem(SPObject *obj) +void SPSwitch::_releaseLastItem(SPObject *obj) { - if (NULL == _cached_item || _cached_item != obj) + if (NULL == this->_cached_item || this->_cached_item != obj) return; - _release_connection.disconnect(); - _cached_item = NULL; + this->_release_connection.disconnect(); + this->_cached_item = NULL; } -void CSwitch::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) { - SPObject *evaluated_child = _evaluateFirst(); +void SPSwitch::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) { + SPObject *evaluated_child = this->_evaluateFirst(); + + GSList *l = this->_childList(false, SPObject::ActionShow); - GSList *l = _childList(false, SPObject::ActionShow); while (l) { SPObject *o = SP_OBJECT (l->data); + if (SP_IS_ITEM (o)) { SPItem * child = SP_ITEM(o); child->setEvaluated(o == evaluated_child); Inkscape::DrawingItem *ac = child->invoke_show (drawing, key, flags); + if (ac) { ai->appendChild(ac); } } + l = g_slist_remove (l, o); } } diff --git a/src/sp-switch.h b/src/sp-switch.h index 24a204731..210cd0ddc 100644 --- a/src/sp-switch.h +++ b/src/sp-switch.h @@ -17,52 +17,31 @@ #include <stddef.h> #include <sigc++/connection.h> -G_BEGIN_DECLS +#define SP_SWITCH(obj) (dynamic_cast<SPSwitch*>((SPObject*)obj)) +#define SP_IS_SWITCH(obj) (dynamic_cast<const SPSwitch*>((SPObject*)obj) != NULL) -#define SP_TYPE_SWITCH (sp_switch_get_type()) -#define SP_SWITCH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_SWITCH, SPSwitch)) -#define SP_SWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_SWITCH, SPSwitchClass)) -#define SP_IS_SWITCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_SWITCH)) -#define SP_IS_SWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_SWITCH)) - -GType sp_switch_get_type() G_GNUC_CONST; - -/* - * Virtual methods of SPSwitch - */ -class CSwitch : public CGroup { +class SPSwitch : public SPGroup { public: - CSwitch(SPGroup *group); - virtual ~CSwitch(); + SPSwitch(); + virtual ~SPSwitch(); + + void resetChildEvaluated() { _reevaluate(); } - friend struct SPSwitch; - - virtual void onChildAdded(Inkscape::XML::Node *child); - virtual void onChildRemoved(Inkscape::XML::Node *child); - virtual void onOrderChanged(Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref); - virtual gchar *getDescription(); + GSList *_childList(bool add_ref, SPObject::Action action); + void _showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags); -protected: - virtual GSList *_childList(bool add_ref, SPObject::Action action); - virtual void _showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags); - SPObject *_evaluateFirst(); void _reevaluate(bool add_to_arena = false); - static void _releaseItem(SPObject *obj, CSwitch *selection); + static void _releaseItem(SPObject *obj, SPSwitch *selection); void _releaseLastItem(SPObject *obj); -private: SPObject *_cached_item; sigc::connection _release_connection; -}; - -struct SPSwitch : public SPGroup { - void resetChildEvaluated() { (static_cast<CSwitch *>(group))->_reevaluate(); } -}; -struct SPSwitchClass : public SPGroupClass { + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node *child); + virtual void order_changed(Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref); + virtual gchar *description(); }; -G_END_DECLS - #endif diff --git a/src/sp-symbol.cpp b/src/sp-symbol.cpp index a56de2e5a..b2346ac91 100644 --- a/src/sp-symbol.cpp +++ b/src/sp-symbol.cpp @@ -26,116 +26,125 @@ #include "sp-symbol.h" #include "document.h" -static void sp_symbol_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_symbol_release (SPObject *object); -static void sp_symbol_set (SPObject *object, unsigned int key, const gchar *value); -static void sp_symbol_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref); -static void sp_symbol_update (SPObject *object, SPCtx *ctx, guint flags); -static void sp_symbol_modified (SPObject *object, guint flags); -static Inkscape::XML::Node *sp_symbol_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -static Inkscape::DrawingItem *sp_symbol_show (SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); -static void sp_symbol_hide (SPItem *item, unsigned int key); -static Geom::OptRect sp_symbol_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type); -static void sp_symbol_print (SPItem *item, SPPrintContext *ctx); - -G_DEFINE_TYPE(SPSymbol, sp_symbol, SP_TYPE_GROUP); - -static void sp_symbol_class_init(SPSymbolClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPItemClass *sp_item_class = (SPItemClass *) klass; - - sp_object_class->build = sp_symbol_build; - sp_object_class->release = sp_symbol_release; - sp_object_class->set = sp_symbol_set; - sp_object_class->child_added = sp_symbol_child_added; - sp_object_class->update = sp_symbol_update; - sp_object_class->modified = sp_symbol_modified; - sp_object_class->write = sp_symbol_write; - - sp_item_class->show = sp_symbol_show; - sp_item_class->hide = sp_symbol_hide; - sp_item_class->bbox = sp_symbol_bbox; - sp_item_class->print = sp_symbol_print; -} +#include "sp-factory.h" -static void sp_symbol_init(SPSymbol *symbol) -{ - symbol->viewBox_set = FALSE; +namespace { + SPObject* createSymbol() { + return new SPSymbol(); + } - symbol->c2p = Geom::identity(); + bool symbolRegistered = SPFactory::instance().registerObject("svg:symbol", createSymbol); } -static void sp_symbol_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - object->readAttr( "viewBox" ); - object->readAttr( "preserveAspectRatio" ); +SPSymbol::SPSymbol() : SPGroup() { + this->aspect_align = 0; + this->aspect_clip = 0; + this->aspect_set = 0; - if (((SPObjectClass *) sp_symbol_parent_class)->build) { - ((SPObjectClass *) sp_symbol_parent_class)->build (object, document, repr); - } + this->viewBox_set = FALSE; + this->c2p = Geom::identity(); } -static void sp_symbol_release(SPObject *object) -{ - if (((SPObjectClass *) sp_symbol_parent_class)->release) { - ((SPObjectClass *) sp_symbol_parent_class)->release (object); - } +SPSymbol::~SPSymbol() { } -static void sp_symbol_set(SPObject *object, unsigned int key, const gchar *value) -{ - SPSymbol *symbol = SP_SYMBOL(object); +void SPSymbol::build(SPDocument *document, Inkscape::XML::Node *repr) { + this->readAttr( "viewBox" ); + this->readAttr( "preserveAspectRatio" ); + + SPGroup::build(document, repr); +} + +void SPSymbol::release() { + SPGroup::release(); +} +void SPSymbol::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_VIEWBOX: if (value) { double x, y, width, height; char *eptr; + /* fixme: We have to take original item affine into account */ /* fixme: Think (Lauris) */ eptr = (gchar *) value; x = g_ascii_strtod (eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + y = g_ascii_strtod (eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + width = g_ascii_strtod (eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + height = g_ascii_strtod (eptr, &eptr); - while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++; + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + if ((width > 0) && (height > 0)) { /* Set viewbox */ - symbol->viewBox = Geom::Rect::from_xywh(x, y, width, height); - symbol->viewBox_set = TRUE; + this->viewBox = Geom::Rect::from_xywh(x, y, width, height); + this->viewBox_set = TRUE; } else { - symbol->viewBox_set = FALSE; + this->viewBox_set = FALSE; } } else { - symbol->viewBox_set = FALSE; + this->viewBox_set = FALSE; } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); break; + case SP_ATTR_PRESERVEASPECTRATIO: /* Do setup before, so we can use break to escape */ - symbol->aspect_set = FALSE; - symbol->aspect_align = SP_ASPECT_NONE; - symbol->aspect_clip = SP_ASPECT_MEET; - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + this->aspect_set = FALSE; + this->aspect_align = SP_ASPECT_NONE; + this->aspect_clip = SP_ASPECT_MEET; + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + if (value) { int len; gchar c[256]; const gchar *p, *e; unsigned int align, clip; p = value; - while (*p && *p == 32) p += 1; - if (!*p) break; + + while (*p && *p == 32) { + p += 1; + } + + if (!*p) { + break; + } + e = p; - while (*e && *e != 32) e += 1; + + while (*e && *e != 32) { + e += 1; + } + len = e - p; - if (len > 8) break; + + if (len > 8) { + break; + } + memcpy (c, value, len); + c[len] = 0; + /* Now the actual part */ if (!strcmp (c, "none")) { align = SP_ASPECT_NONE; @@ -160,8 +169,13 @@ static void sp_symbol_set(SPObject *object, unsigned int key, const gchar *value } else { break; } + clip = SP_ASPECT_MEET; - while (*e && *e == 32) e += 1; + + while (*e && *e == 32) { + e += 1; + } + if (*e) { if (!strcmp (e, "meet")) { clip = SP_ASPECT_MEET; @@ -171,32 +185,29 @@ static void sp_symbol_set(SPObject *object, unsigned int key, const gchar *value break; } } - symbol->aspect_set = TRUE; - symbol->aspect_align = align; - symbol->aspect_clip = clip; + + this->aspect_set = TRUE; + this->aspect_align = align; + this->aspect_clip = clip; } break; + default: - if (((SPObjectClass *) sp_symbol_parent_class)->set) - ((SPObjectClass *) sp_symbol_parent_class)->set (object, key, value); + SPGroup::set(key, value); break; } } -static void sp_symbol_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) -{ - if (((SPObjectClass *) (sp_symbol_parent_class))->child_added) { - ((SPObjectClass *) (sp_symbol_parent_class))->child_added (object, child, ref); - } +void SPSymbol::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { + SPGroup::child_added(child, ref); } -static void sp_symbol_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPSymbol *symbol = SP_SYMBOL(object); + +void SPSymbol::update(SPCtx *ctx, guint flags) { SPItemCtx *ictx = (SPItemCtx *) ctx; SPItemCtx rctx; - if (object->cloned) { + if (this->cloned) { /* Cloned <symbol> is actually renderable */ /* fixme: We have to set up clip here too */ @@ -206,12 +217,13 @@ static void sp_symbol_update(SPObject *object, SPCtx *ctx, guint flags) /* Calculate child to parent transformation */ /* Apply parent <use> translation (set up as vewport) */ - symbol->c2p = Geom::Translate(rctx.viewport.min()); + this->c2p = Geom::Translate(rctx.viewport.min()); - if (symbol->viewBox_set) { + if (this->viewBox_set) { double x, y, width, height; + /* Determine actual viewbox in viewport coordinates */ - if (symbol->aspect_align == SP_ASPECT_NONE) { + if (this->aspect_align == SP_ASPECT_NONE) { x = 0.0; y = 0.0; width = rctx.viewport.width(); @@ -219,13 +231,14 @@ static void sp_symbol_update(SPObject *object, SPCtx *ctx, guint flags) } else { double scalex, scaley, scale; /* Things are getting interesting */ - scalex = rctx.viewport.width() / symbol->viewBox.width(); - scaley = rctx.viewport.height() / symbol->viewBox.height(); - scale = (symbol->aspect_clip == SP_ASPECT_MEET) ? MIN (scalex, scaley) : MAX (scalex, scaley); - width = symbol->viewBox.width() * scale; - height = symbol->viewBox.height() * scale; + scalex = rctx.viewport.width() / this->viewBox.width(); + scaley = rctx.viewport.height() / this->viewBox.height(); + scale = (this->aspect_clip == SP_ASPECT_MEET) ? MIN (scalex, scaley) : MAX (scalex, scaley); + width = this->viewBox.width() * scale; + height = this->viewBox.height() * scale; + /* Now place viewbox to requested position */ - switch (symbol->aspect_align) { + switch (this->aspect_align) { case SP_ASPECT_XMIN_YMIN: x = 0.0; y = 0.0; @@ -268,133 +281,108 @@ static void sp_symbol_update(SPObject *object, SPCtx *ctx, guint flags) break; } } + /* Compose additional transformation from scale and position */ Geom::Affine q; - q[0] = width / symbol->viewBox.width(); + q[0] = width / this->viewBox.width(); q[1] = 0.0; q[2] = 0.0; - q[3] = height / symbol->viewBox.height(); - q[4] = -symbol->viewBox.left() * q[0] + x; - q[5] = -symbol->viewBox.top() * q[3] + y; + q[3] = height / this->viewBox.height(); + q[4] = -this->viewBox.left() * q[0] + x; + q[5] = -this->viewBox.top() * q[3] + y; + /* Append viewbox transformation */ - symbol->c2p = q * symbol->c2p; + this->c2p = q * this->c2p; } - rctx.i2doc = symbol->c2p * (Geom::Affine)rctx.i2doc; + rctx.i2doc = this->c2p * (Geom::Affine)rctx.i2doc; /* If viewBox is set initialize child viewport */ /* Otherwise <use> has set it up already */ - if (symbol->viewBox_set) { - rctx.viewport = symbol->viewBox; + if (this->viewBox_set) { + rctx.viewport = this->viewBox; rctx.i2vp = Geom::identity(); } // And invoke parent method - if (((SPObjectClass *) (sp_symbol_parent_class))->update) { - ((SPObjectClass *) (sp_symbol_parent_class))->update (object, (SPCtx *) &rctx, flags); - } + SPGroup::update((SPCtx *) &rctx, flags); // As last step set additional transform of drawing group - for (SPItemView *v = symbol->display; v != NULL; v = v->next) { + for (SPItemView *v = this->display; v != NULL; v = v->next) { Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); - g->setChildTransform(symbol->c2p); + g->setChildTransform(this->c2p); } } else { // No-op - if (((SPObjectClass *) (sp_symbol_parent_class))->update) { - ((SPObjectClass *) (sp_symbol_parent_class))->update (object, ctx, flags); - } + SPGroup::update(ctx, flags); } } -static void -sp_symbol_modified(SPObject *object, - guint flags) -{ - SP_OBJECT_CLASS(sp_symbol_parent_class)->modified (object, flags); +void SPSymbol::modified(unsigned int flags) { + SPGroup::modified(flags); } -static Inkscape::XML::Node * -sp_symbol_write(SPObject *object, - Inkscape::XML::Document *xml_doc, - Inkscape::XML::Node *repr, - guint flags) -{ + +Inkscape::XML::Node* SPSymbol::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:symbol"); } //XML Tree being used directly here while it shouldn't be. - repr->setAttribute("viewBox", object->getRepr()->attribute("viewBox")); + repr->setAttribute("viewBox", this->getRepr()->attribute("viewBox")); //XML Tree being used directly here while it shouldn't be. - repr->setAttribute("preserveAspectRatio", object->getRepr()->attribute("preserveAspectRatio")); + repr->setAttribute("preserveAspectRatio", this->getRepr()->attribute("preserveAspectRatio")); - SP_OBJECT_CLASS(sp_symbol_parent_class)->write (object, xml_doc, repr, flags); + SPGroup::write(xml_doc, repr, flags); return repr; } -static Inkscape::DrawingItem *sp_symbol_show(SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) -{ - SPSymbol *symbol = SP_SYMBOL(item); +Inkscape::DrawingItem* SPSymbol::show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { Inkscape::DrawingItem *ai = 0; - if (symbol->cloned) { + if (this->cloned) { // Cloned <symbol> is actually renderable - if (((SPItemClass *) (sp_symbol_parent_class))->show) { - ai = ((SPItemClass *) (sp_symbol_parent_class))->show (item, drawing, key, flags); - Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(ai); - if (g) { - g->setChildTransform(symbol->c2p); - } - } + ai = SPGroup::show(drawing, key, flags); + Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(ai); + + if (g) { + g->setChildTransform(this->c2p); + } } return ai; } -static void sp_symbol_hide(SPItem *item, unsigned int key) -{ - SPSymbol *symbol = SP_SYMBOL(item); - - if (symbol->cloned) { +void SPSymbol::hide(unsigned int key) { + if (this->cloned) { /* Cloned <symbol> is actually renderable */ - if (((SPItemClass *) (sp_symbol_parent_class))->hide) { - ((SPItemClass *) (sp_symbol_parent_class))->hide (item, key); - } + SPGroup::hide(key); } } -static Geom::OptRect sp_symbol_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type) -{ - SPSymbol const *symbol = SP_SYMBOL(item); + +Geom::OptRect SPSymbol::bbox(Geom::Affine const &transform, SPItem::BBoxType type) { Geom::OptRect bbox; // We don't need a bounding box for Symbols dialog when selecting // symbols. They have no canvas location. But cloned symbols are. - if (symbol->cloned) { - // Cloned <symbol> is actually renderable - - if (((SPItemClass *) (sp_symbol_parent_class))->bbox) { - Geom::Affine const a( symbol->c2p * transform ); - bbox = ((SPItemClass *) (sp_symbol_parent_class))->bbox(item, a, type); - } + if (this->cloned) { + Geom::Affine const a( this->c2p * transform ); + bbox = SPGroup::bbox(a, type); } + return bbox; } -static void sp_symbol_print(SPItem *item, SPPrintContext *ctx) -{ - SPSymbol *symbol = SP_SYMBOL(item); - if (symbol->cloned) { +void SPSymbol::print(SPPrintContext* ctx) { + if (this->cloned) { // Cloned <symbol> is actually renderable - sp_print_bind(ctx, symbol->c2p, 1.0); + sp_print_bind(ctx, this->c2p, 1.0); - if (((SPItemClass *) (sp_symbol_parent_class))->print) { - ((SPItemClass *) (sp_symbol_parent_class))->print (item, ctx); - } + SPGroup::print(ctx); sp_print_release (ctx); } diff --git a/src/sp-symbol.h b/src/sp-symbol.h index 10d642e8b..952ba00df 100644 --- a/src/sp-symbol.h +++ b/src/sp-symbol.h @@ -18,15 +18,19 @@ */ #define SP_TYPE_SYMBOL (sp_symbol_get_type ()) -#define SP_SYMBOL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_SYMBOL, SPSymbol)) -#define SP_IS_SYMBOL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_SYMBOL)) +#define SP_SYMBOL(obj) (dynamic_cast<SPSymbol*>((SPObject*)obj)) +#define SP_IS_SYMBOL(obj) (dynamic_cast<const SPSymbol*>((SPObject*)obj) != NULL) #include <2geom/affine.h> #include "svg/svg-length.h" #include "enums.h" #include "sp-item-group.h" -struct SPSymbol : public SPGroup { +class SPSymbol : public SPGroup { +public: + SPSymbol(); + virtual ~SPSymbol(); + /* viewBox; */ unsigned int viewBox_set : 1; Geom::Rect viewBox; @@ -38,12 +42,20 @@ struct SPSymbol : public SPGroup { /* Child to parent additional transform */ Geom::Affine c2p; -}; -struct SPSymbolClass { - SPGroupClass parent_class; -}; + virtual void build(SPDocument *document, Inkscape::XML::Node *repr); + virtual void release(); + virtual void set(unsigned int key, gchar const* value); + virtual void update(SPCtx *ctx, guint flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); -GType sp_symbol_get_type (void); + virtual void modified(unsigned int flags); + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + + virtual Inkscape::DrawingItem* show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); + virtual void print(SPPrintContext *ctx); + virtual Geom::OptRect bbox(Geom::Affine const &transform, SPItem::BBoxType type); + virtual void hide (unsigned int key); +}; #endif diff --git a/src/sp-text.cpp b/src/sp-text.cpp index 2e2bf15bc..85137e58d 100644 --- a/src/sp-text.cpp +++ b/src/sp-text.cpp @@ -56,164 +56,115 @@ #include "text-editing.h" -/*##################################################### -# SPTEXT -#####################################################*/ - -static void sp_text_release (SPObject *object); - -static void sp_text_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_text_set (SPObject *object, unsigned key, gchar const *value); -static void sp_text_child_added (SPObject *object, Inkscape::XML::Node *rch, Inkscape::XML::Node *ref); -static void sp_text_remove_child (SPObject *object, Inkscape::XML::Node *rch); -static void sp_text_update (SPObject *object, SPCtx *ctx, guint flags); -static void sp_text_modified (SPObject *object, guint flags); -static Inkscape::XML::Node *sp_text_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -static Geom::OptRect sp_text_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type); -static Inkscape::DrawingItem *sp_text_show (SPItem *item, Inkscape::Drawing &drawing, unsigned key, unsigned flags); -static void sp_text_hide (SPItem *item, unsigned key); -static char *sp_text_description (SPItem *item); -static void sp_text_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); -static Geom::Affine sp_text_set_transform(SPItem *item, Geom::Affine const &xform); -static void sp_text_print (SPItem *item, SPPrintContext *gpc); - -G_DEFINE_TYPE(SPText, sp_text, SP_TYPE_ITEM); - -static void -sp_text_class_init (SPTextClass *classname) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) classname; - SPItemClass *item_class = (SPItemClass *) classname; +#include "sp-factory.h" - sp_object_class->release = sp_text_release; - sp_object_class->build = sp_text_build; - sp_object_class->set = sp_text_set; - sp_object_class->child_added = sp_text_child_added; - sp_object_class->remove_child = sp_text_remove_child; - sp_object_class->update = sp_text_update; - sp_object_class->modified = sp_text_modified; - sp_object_class->write = sp_text_write; +namespace { + SPObject* createText() { + return new SPText(); + } - item_class->bbox = sp_text_bbox; - item_class->show = sp_text_show; - item_class->hide = sp_text_hide; - item_class->description = sp_text_description; - item_class->snappoints = sp_text_snappoints; - item_class->set_transform = sp_text_set_transform; - item_class->print = sp_text_print; + bool textRegistered = SPFactory::instance().registerObject("svg:text", createText); } -static void -sp_text_init (SPText *text) -{ - new (&text->layout) Inkscape::Text::Layout; - new (&text->attributes) TextTagAttributes; +/*##################################################### +# SPTEXT +#####################################################*/ +SPText::SPText() : SPItem() { + //new (&this->layout) Inkscape::Text::Layout; + //new (&this->attributes) TextTagAttributes; } -static void -sp_text_release (SPObject *object) -{ - SPText *text = SP_TEXT(object); - text->attributes.~TextTagAttributes(); - text->layout.~Layout(); - - if ((SP_OBJECT_CLASS(sp_text_parent_class))->release) - (SP_OBJECT_CLASS(sp_text_parent_class))->release(object); +SPText::~SPText() { } -static void -sp_text_build (SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr) -{ - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "dx" ); - object->readAttr( "dy" ); - object->readAttr( "rotate" ); +void SPText::build(SPDocument *doc, Inkscape::XML::Node *repr) { + this->readAttr( "x" ); + this->readAttr( "y" ); + this->readAttr( "dx" ); + this->readAttr( "dy" ); + this->readAttr( "rotate" ); - if ((SP_OBJECT_CLASS(sp_text_parent_class))->build) - (SP_OBJECT_CLASS(sp_text_parent_class))->build(object, doc, repr); + SPItem::build(doc, repr); - object->readAttr( "sodipodi:linespacing" ); // has to happen after the styles are read + this->readAttr( "sodipodi:linespacing" ); // has to happen after the styles are read } -static void -sp_text_set(SPObject *object, unsigned key, gchar const *value) -{ - SPText *text = SP_TEXT (object); +void SPText::release() { + //this->attributes.~TextTagAttributes(); + //this->layout.~Layout(); + + SPItem::release(); +} - if (text->attributes.readSingleAttribute(key, value)) { - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); +void SPText::set(unsigned int key, const gchar* value) { + if (this->attributes.readSingleAttribute(key, value)) { + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } else { switch (key) { case SP_ATTR_SODIPODI_LINESPACING: // convert deprecated tag to css if (value) { - text->style->line_height.set = TRUE; - text->style->line_height.inherit = FALSE; - text->style->line_height.normal = FALSE; - text->style->line_height.unit = SP_CSS_UNIT_PERCENT; - text->style->line_height.value = text->style->line_height.computed = sp_svg_read_percentage (value, 1.0); + this->style->line_height.set = TRUE; + this->style->line_height.inherit = FALSE; + this->style->line_height.normal = FALSE; + this->style->line_height.unit = SP_CSS_UNIT_PERCENT; + this->style->line_height.value = this->style->line_height.computed = sp_svg_read_percentage (value, 1.0); } - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_TEXT_LAYOUT_MODIFIED_FLAG); + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_TEXT_LAYOUT_MODIFIED_FLAG); break; + default: - if ((SP_OBJECT_CLASS(sp_text_parent_class))->set) - (SP_OBJECT_CLASS(sp_text_parent_class))->set (object, key, value); + SPItem::set(key, value); break; } } } -static void -sp_text_child_added (SPObject *object, Inkscape::XML::Node *rch, Inkscape::XML::Node *ref) -{ - SPText *text = SP_TEXT (object); - - if ((SP_OBJECT_CLASS(sp_text_parent_class))->child_added) - (SP_OBJECT_CLASS(sp_text_parent_class))->child_added (object, rch, ref); +void SPText::child_added(Inkscape::XML::Node *rch, Inkscape::XML::Node *ref) { + SPItem::child_added(rch, ref); - text->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_TEXT_CONTENT_MODIFIED_FLAG | SP_TEXT_LAYOUT_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_TEXT_CONTENT_MODIFIED_FLAG | SP_TEXT_LAYOUT_MODIFIED_FLAG); } -static void -sp_text_remove_child (SPObject *object, Inkscape::XML::Node *rch) -{ - SPText *text = SP_TEXT (object); - - if ((SP_OBJECT_CLASS(sp_text_parent_class))->remove_child) - (SP_OBJECT_CLASS(sp_text_parent_class))->remove_child (object, rch); +void SPText::remove_child(Inkscape::XML::Node *rch) { + SPItem::remove_child(rch); - text->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_TEXT_CONTENT_MODIFIED_FLAG | SP_TEXT_LAYOUT_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_TEXT_CONTENT_MODIFIED_FLAG | SP_TEXT_LAYOUT_MODIFIED_FLAG); } -static void sp_text_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPText *text = SP_TEXT (object); - if ((SP_OBJECT_CLASS(sp_text_parent_class))->update) - (SP_OBJECT_CLASS(sp_text_parent_class))->update (object, ctx, flags); +void SPText::update(SPCtx *ctx, guint flags) { + SPItem::update(ctx, flags); guint cflags = (flags & SP_OBJECT_MODIFIED_CASCADE); - if (flags & SP_OBJECT_MODIFIED_FLAG) cflags |= SP_OBJECT_PARENT_MODIFIED_FLAG; + if (flags & SP_OBJECT_MODIFIED_FLAG) { + cflags |= SP_OBJECT_PARENT_MODIFIED_FLAG; + } // Create temporary list of children GSList *l = NULL; - for (SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { - sp_object_ref(child, object); + + for (SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { + sp_object_ref(child, this); l = g_slist_prepend (l, child); } + l = g_slist_reverse (l); + while (l) { SPObject *child = reinterpret_cast<SPObject*>(l->data); // We just built this list, so cast is safe. l = g_slist_remove (l, child); + if (cflags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { /* fixme: Do we need transform? */ child->updateDisplay(ctx, cflags); } - sp_object_unref(child, object); + + sp_object_unref(child, this); } + if (flags & ( SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG | SP_TEXT_LAYOUT_MODIFIED_FLAG ) ) @@ -221,95 +172,103 @@ static void sp_text_update(SPObject *object, SPCtx *ctx, guint flags) /* fixme: It is not nice to have it here, but otherwise children content changes does not work */ /* fixme: Even now it may not work, as we are delayed */ /* fixme: So check modification flag everywhere immediate state is used */ - text->rebuildLayout(); + this->rebuildLayout(); - Geom::OptRect paintbox = text->geometricBounds(); - for (SPItemView* v = text->display; v != NULL; v = v->next) { + Geom::OptRect paintbox = this->geometricBounds(); + + for (SPItemView* v = this->display; v != NULL; v = v->next) { Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); - text->_clearFlow(g); - g->setStyle(object->style); - // pass the bbox of the text object as paintbox (used for paintserver fills) - text->layout.show(g, paintbox); + this->_clearFlow(g); + g->setStyle(this->style); + // pass the bbox of the this this as paintbox (used for paintserver fills) + this->layout.show(g, paintbox); } } } -static void sp_text_modified(SPObject *object, guint flags) -{ - if ((SP_OBJECT_CLASS(sp_text_parent_class))->modified) { - (SP_OBJECT_CLASS(sp_text_parent_class))->modified (object, flags); - } +void SPText::modified(guint flags) { +// SPItem::onModified(flags); guint cflags = (flags & SP_OBJECT_MODIFIED_CASCADE); + if (flags & SP_OBJECT_MODIFIED_FLAG) { cflags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } // FIXME: all that we need to do here is to call setStyle, to set the changed // style, but there's no easy way to access the drawing glyphs or texts corresponding to a - // text object. Therefore we do here the same as in _update, that is, destroy all items + // text this. Therefore we do here the same as in _update, that is, destroy all items // and create new ones. This is probably quite wasteful. if (flags & ( SP_OBJECT_STYLE_MODIFIED_FLAG )) { - SPText *text = SP_TEXT (object); - Geom::OptRect paintbox = text->geometricBounds(); - for (SPItemView* v = text->display; v != NULL; v = v->next) { + Geom::OptRect paintbox = this->geometricBounds(); + + for (SPItemView* v = this->display; v != NULL; v = v->next) { Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); - text->_clearFlow(g); - g->setStyle(object->style); - text->layout.show(g, paintbox); + this->_clearFlow(g); + g->setStyle(this->style); + this->layout.show(g, paintbox); } } // Create temporary list of children GSList *l = NULL; - for (SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { - sp_object_ref(child, object); + + for (SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { + sp_object_ref(child, this); l = g_slist_prepend (l, child); } + l = g_slist_reverse (l); + while (l) { SPObject *child = reinterpret_cast<SPObject*>(l->data); // We just built this list, so cast is safe. l = g_slist_remove (l, child); + if (cflags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->emitModified(cflags); } - sp_object_unref(child, object); + + sp_object_unref(child, this); } } -static Inkscape::XML::Node *sp_text_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPText *text = SP_TEXT (object); - +Inkscape::XML::Node *SPText::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if (flags & SP_OBJECT_WRITE_BUILD) { if (!repr) { - repr = xml_doc->createElement("svg:text"); + repr = xml_doc->createElement("svg:this"); } + GSList *l = NULL; - for (SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { + + for (SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { if (SP_IS_TITLE(child) || SP_IS_DESC(child)) { continue; } + Inkscape::XML::Node *crepr = NULL; + if (SP_IS_STRING(child)) { crepr = xml_doc->createTextNode(SP_STRING(child)->string.c_str()); } else { crepr = child->updateRepr(xml_doc, NULL, flags); } + if (crepr) { l = g_slist_prepend (l, crepr); } } + while (l) { repr->addChild((Inkscape::XML::Node *) l->data, NULL); Inkscape::GC::release((Inkscape::XML::Node *) l->data); l = g_slist_remove (l, l->data); } } else { - for (SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { + for (SPObject *child = this->firstChild() ; child ; child = child->getNext() ) { if (SP_IS_TITLE(child) || SP_IS_DESC(child)) { continue; } + if (SP_IS_STRING(child)) { child->getRepr()->setContent(SP_STRING(child)->string.c_str()); } else { @@ -318,68 +277,58 @@ static Inkscape::XML::Node *sp_text_write(SPObject *object, Inkscape::XML::Docum } } - text->attributes.writeTo(repr); + this->attributes.writeTo(repr); // deprecated attribute, but keep it around for backwards compatibility - if (text->style->line_height.set && !text->style->line_height.inherit && !text->style->line_height.normal && text->style->line_height.unit == SP_CSS_UNIT_PERCENT) { + if (this->style->line_height.set && !this->style->line_height.inherit && !this->style->line_height.normal && this->style->line_height.unit == SP_CSS_UNIT_PERCENT) { Inkscape::SVGOStringStream os; - os << (text->style->line_height.value * 100.0) << "%"; - text->getRepr()->setAttribute("sodipodi:linespacing", os.str().c_str()); + os << (this->style->line_height.value * 100.0) << "%"; + this->getRepr()->setAttribute("sodipodi:linespacing", os.str().c_str()); } else { - text->getRepr()->setAttribute("sodipodi:linespacing", NULL); + this->getRepr()->setAttribute("sodipodi:linespacing", NULL); } - if ((SP_OBJECT_CLASS(sp_text_parent_class))->write) { - (SP_OBJECT_CLASS(sp_text_parent_class))->write (object, xml_doc, repr, flags); - } + SPItem::write(xml_doc, repr, flags); return repr; } -static Geom::OptRect -sp_text_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type) -{ - Geom::OptRect bbox = SP_TEXT(item)->layout.bounds(transform); +Geom::OptRect SPText::bbox(Geom::Affine const &transform, SPItem::BBoxType type) { + Geom::OptRect bbox = SP_TEXT(this)->layout.bounds(transform); // FIXME this code is incorrect - if (bbox && type == SPItem::VISUAL_BBOX && !item->style->stroke.isNone()) { + if (bbox && type == SPItem::VISUAL_BBOX && !this->style->stroke.isNone()) { double scale = transform.descrim(); - bbox->expandBy(0.5 * item->style->stroke_width.computed * scale); + bbox->expandBy(0.5 * this->style->stroke_width.computed * scale); } + return bbox; } - -static Inkscape::DrawingItem * -sp_text_show(SPItem *item, Inkscape::Drawing &drawing, unsigned /* key*/, unsigned /*flags*/) -{ - SPText *group = (SPText *) item; - +Inkscape::DrawingItem* SPText::show(Inkscape::Drawing &drawing, unsigned key, unsigned flags) { Inkscape::DrawingGroup *flowed = new Inkscape::DrawingGroup(drawing); flowed->setPickChildren(false); - flowed->setStyle(group->style); + flowed->setStyle(this->style); // pass the bbox of the text object as paintbox (used for paintserver fills) - group->layout.show(flowed, group->geometricBounds()); + this->layout.show(flowed, this->geometricBounds()); return flowed; } -static void -sp_text_hide(SPItem *item, unsigned key) -{ - if ((SP_ITEM_CLASS(sp_text_parent_class))->hide) - (SP_ITEM_CLASS(sp_text_parent_class))->hide (item, key); + +void SPText::hide(unsigned int key) { +// SPItem::onHide(key); } -static char * sp_text_description(SPItem *item) -{ - SPText *text = reinterpret_cast<SPText *>(item); - SPStyle *style = text->style; + +gchar* SPText::description() { + SPStyle *style = this->style; font_instance *tf = font_factory::Default()->FaceFromStyle(style); char *n; + if (tf) { char name_buf[256]; tf->Family(name_buf, sizeof(name_buf)); @@ -394,40 +343,38 @@ static char * sp_text_description(SPItem *item) GString *xs = g_string_new(q.string(*sp_desktop_namedview(SP_ACTIVE_DESKTOP)->doc_units).c_str()); char const *trunc = ""; - Inkscape::Text::Layout const *layout = te_get_layout((SPItem *) item); + Inkscape::Text::Layout const *layout = te_get_layout((SPItem *) this); + if (layout && layout->inputTruncated()) { trunc = _(" [truncated]"); } - char *ret = ( SP_IS_TEXT_TEXTPATH(item) + char *ret = ( SP_IS_TEXT_TEXTPATH(this) ? g_strdup_printf(_("<b>Text on path</b>%s (%s, %s)"), trunc, n, xs->str) : g_strdup_printf(_("<b>Text</b>%s (%s, %s)"), trunc, n, xs->str) ); g_free(n); return ret; } -static void sp_text_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) -{ +void SPText::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) { if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_TEXT_BASELINE)) { // Choose a point on the baseline for snapping from or to, with the horizontal position // of this point depending on the text alignment (left vs. right) - Inkscape::Text::Layout const *layout = te_get_layout((SPItem *) item); + Inkscape::Text::Layout const *layout = te_get_layout(this); + if (layout != NULL && layout->outputExists()) { boost::optional<Geom::Point> pt = layout->baselineAnchorPoint(); + if (pt) { - p.push_back(Inkscape::SnapCandidatePoint((*pt) * item->i2dt_affine(), Inkscape::SNAPSOURCE_TEXT_ANCHOR, Inkscape::SNAPTARGET_TEXT_ANCHOR)); + p.push_back(Inkscape::SnapCandidatePoint((*pt) * this->i2dt_affine(), Inkscape::SNAPSOURCE_TEXT_ANCHOR, Inkscape::SNAPTARGET_TEXT_ANCHOR)); } } } } -static Geom::Affine -sp_text_set_transform (SPItem *item, Geom::Affine const &xform) -{ - SPText *text = SP_TEXT(item); - +Geom::Affine SPText::set_transform(Geom::Affine const &xform) { // we cannot optimize textpath because changing its fontsize will break its match to the path - if (SP_IS_TEXT_TEXTPATH (text)) + if (SP_IS_TEXT_TEXTPATH (this)) return xform; /* This function takes care of scaling & translation only, we return whatever parts we can't @@ -451,37 +398,34 @@ sp_text_set_transform (SPItem *item, Geom::Affine const &xform) ret[3] /= ex; // Adjust x/y, dx/dy - text->_adjustCoordsRecursive (item, xform * ret.inverse(), ex); + this->_adjustCoordsRecursive (this, xform * ret.inverse(), ex); // Adjust font size - text->_adjustFontsizeRecursive (item, ex); + this->_adjustFontsizeRecursive (this, ex); // Adjust stroke width - item->adjust_stroke_width_recursive (ex); + this->adjust_stroke_width_recursive (ex); // Adjust pattern fill - item->adjust_pattern(xform * ret.inverse()); + this->adjust_pattern(xform * ret.inverse()); // Adjust gradient fill - item->adjust_gradient(xform * ret.inverse()); + this->adjust_gradient(xform * ret.inverse()); - item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_TEXT_LAYOUT_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_TEXT_LAYOUT_MODIFIED_FLAG); return ret; } -static void -sp_text_print (SPItem *item, SPPrintContext *ctx) -{ - SPText *group = SP_TEXT (item); +void SPText::print(SPPrintContext *ctx) { Geom::OptRect pbox, bbox, dbox; + pbox = this->geometricBounds(); + bbox = this->desktopVisualBounds(); + dbox = Geom::Rect::from_xywh(Geom::Point(0,0), this->document->getDimensions()); - pbox = item->geometricBounds(); - bbox = item->desktopVisualBounds(); - dbox = Geom::Rect::from_xywh(Geom::Point(0,0), item->document->getDimensions()); - Geom::Affine const ctm (item->i2dt_affine()); + Geom::Affine const ctm (this->i2dt_affine()); - group->layout.print(ctx,pbox,dbox,bbox,ctm); + this->layout.print(ctx,pbox,dbox,bbox,ctm); } /* diff --git a/src/sp-text.h b/src/sp-text.h index 457f11f06..12f773ded 100644 --- a/src/sp-text.h +++ b/src/sp-text.h @@ -21,12 +21,8 @@ #include "text-tag-attributes.h" #include "libnrtype/Layout-TNG.h" - -#define SP_TYPE_TEXT (sp_text_get_type()) -#define SP_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_TEXT, SPText)) -#define SP_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_TEXT, SPTextClass)) -#define SP_IS_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_TEXT)) -#define SP_IS_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_TEXT)) +#define SP_TEXT(obj) (dynamic_cast<SPText*>((SPObject*)obj)) +#define SP_IS_TEXT(obj) (dynamic_cast<const SPText*>((SPObject*)obj) != NULL) /* Text specific flags */ #define SP_TEXT_CONTENT_MODIFIED_FLAG SP_OBJECT_USER_MODIFIED_FLAG_A @@ -34,8 +30,11 @@ /* SPText */ +class SPText : public SPItem { +public: + SPText(); + virtual ~SPText(); -struct SPText : public SPItem { /** Converts the text object to its component curves */ SPCurve *getNormalizedBpath() const {return layout.convertToCurves();} @@ -66,13 +65,25 @@ private: breaks and makes sure both that they are assigned the correct SPObject and that we don't get a spurious extra one at the end of the flow. */ unsigned _buildLayoutInput(SPObject *root, Inkscape::Text::Layout::OptionalTextTagAttrs const &parent_optional_attrs, unsigned parent_attrs_offset, bool in_textpath); -}; -struct SPTextClass { - SPItemClass parent_class; -}; +public: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node* child); + virtual void set(unsigned int key, const gchar* value); + virtual void update(SPCtx* ctx, unsigned int flags); + virtual void modified(unsigned int flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); -GType sp_text_get_type(); + virtual Geom::OptRect bbox(Geom::Affine const &transform, SPItem::BBoxType type); + virtual void print(SPPrintContext *ctx); + virtual gchar* description(); + virtual Inkscape::DrawingItem* show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); + virtual void hide(unsigned int key); + virtual void snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); + virtual Geom::Affine set_transform(Geom::Affine const &transform); +}; #endif diff --git a/src/sp-textpath.h b/src/sp-textpath.h index d79f4d346..075743d8e 100644 --- a/src/sp-textpath.h +++ b/src/sp-textpath.h @@ -9,28 +9,29 @@ class SPUsePath; class Path; -#define SP_TYPE_TEXTPATH (sp_textpath_get_type()) -#define SP_TEXTPATH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_TEXTPATH, SPTextPath)) -#define SP_TEXTPATH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_TEXTPATH, SPTextPathClass)) -#define SP_IS_TEXTPATH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_TEXTPATH)) -#define SP_IS_TEXTPATH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_TEXTPATH)) +#define SP_TEXTPATH(obj) (dynamic_cast<SPTextPath*>((SPObject*)obj)) +#define SP_IS_TEXTPATH(obj) (dynamic_cast<const SPTextPath*>((SPObject*)obj) != NULL) +class SPTextPath : public SPItem { +public: + SPTextPath(); + virtual ~SPTextPath(); -struct SPTextPath : public SPItem { TextTagAttributes attributes; SVGLength startOffset; Path *originalPath; bool isUpdating; SPUsePath *sourcePath; -}; -struct SPTextPathClass { - SPItemClass parent_class; + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + virtual void set(unsigned int key, const gchar* value); + virtual void update(SPCtx* ctx, unsigned int flags); + virtual void modified(unsigned int flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); }; -GType sp_textpath_get_type(); - #define SP_IS_TEXT_TEXTPATH(obj) (SP_IS_TEXT(obj) && obj->firstChild() && SP_IS_TEXTPATH(obj->firstChild())) SPItem *sp_textpath_get_path_item(SPTextPath *tp); diff --git a/src/sp-title.cpp b/src/sp-title.cpp index 489a6f448..4ecfcfa8e 100644 --- a/src/sp-title.cpp +++ b/src/sp-title.cpp @@ -16,35 +16,31 @@ #include "sp-title.h" #include "xml/repr.h" -static Inkscape::XML::Node *sp_title_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); +#include "sp-factory.h" -G_DEFINE_TYPE(SPTitle, sp_title, SP_TYPE_OBJECT); +namespace { + SPObject* createTitle() { + return new SPTitle(); + } -static void -sp_title_class_init(SPTitleClass *klass) -{ - SPObjectClass *sp_object_class = (SPObjectClass *) klass; + bool titleRegistered = SPFactory::instance().registerObject("svg:title", createTitle); +} - sp_object_class->write = sp_title_write; +SPTitle::SPTitle() : SPObject() { } -static void -sp_title_init(SPTitle */*desc*/) -{ +SPTitle::~SPTitle() { } -/** - * Writes it's settings to an incoming repr object, if any. - */ -static Inkscape::XML::Node *sp_title_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) -{ +Inkscape::XML::Node* SPTitle::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { + SPTitle* object = this; + if (!repr) { - repr = object->getRepr()->duplicate(doc); + repr = object->getRepr()->duplicate(xml_doc); } - if (((SPObjectClass *) sp_title_parent_class)->write) { - ((SPObjectClass *) sp_title_parent_class)->write(object, doc, repr, flags); - } + SPObject::write(xml_doc, repr, flags); return repr; } + diff --git a/src/sp-title.h b/src/sp-title.h index d10d58188..14faf4b0a 100644 --- a/src/sp-title.h +++ b/src/sp-title.h @@ -14,16 +14,15 @@ #include "sp-object.h" -#define SP_TYPE_TITLE (sp_title_get_type ()) -#define SP_IS_TITLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_TITLE)) +#define SP_TITLE(obj) (dynamic_cast<SPTitle*>((SPObject*)obj)) +#define SP_IS_TITLE(obj) (dynamic_cast<const SPTitle*>((SPObject*)obj) != NULL) -struct SPTitle : public SPObject { -}; +class SPTitle : public SPObject { +public: + SPTitle(); + virtual ~SPTitle(); -struct SPTitleClass { - SPObjectClass parent_class; + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); }; -GType sp_title_get_type (void); - #endif diff --git a/src/sp-tref.cpp b/src/sp-tref.cpp index deee590af..1872cdf7c 100644 --- a/src/sp-tref.cpp +++ b/src/sp-tref.cpp @@ -24,7 +24,7 @@ #include "attributes.h" #include "document.h" -#include "sp-object-repr.h" +#include "sp-factory.h" #include "sp-text.h" #include "sp-tspan.h" #include "sp-tref.h" @@ -35,6 +35,13 @@ #include "xml/node.h" #include "xml/repr.h" +namespace { + SPObject* createTRef() { + return new SPTRef(); + } + + bool trefRegistered = SPFactory::instance().registerObject("svg:tref", createTRef); +} //#define DEBUG_TREF #ifdef DEBUG_TREF @@ -51,176 +58,97 @@ static void build_string_from_root(Inkscape::XML::Node *root, Glib::ustring *retString); /* TRef base class */ - -static void sp_tref_finalize(GObject *obj); - -static void sp_tref_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_tref_release(SPObject *object); -static void sp_tref_set(SPObject *object, unsigned int key, gchar const *value); -static void sp_tref_update(SPObject *object, SPCtx *ctx, guint flags); -static void sp_tref_modified(SPObject *object, guint flags); -static Inkscape::XML::Node *sp_tref_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - -static Geom::OptRect sp_tref_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type); -static gchar *sp_tref_description(SPItem *item); - static void sp_tref_href_changed(SPObject *old_ref, SPObject *ref, SPTRef *tref); static void sp_tref_delete_self(SPObject *deleted, SPTRef *self); -G_DEFINE_TYPE(SPTRef, sp_tref, SP_TYPE_ITEM); - -static void -sp_tref_class_init(SPTRefClass *tref_class) -{ - GObjectClass *gobject_class = (GObjectClass *) tref_class; - SPObjectClass *sp_object_class = (SPObjectClass *)tref_class; - - sp_object_class->build = sp_tref_build; - sp_object_class->release = sp_tref_release; - sp_object_class->write = sp_tref_write; - sp_object_class->set = sp_tref_set; - sp_object_class->update = sp_tref_update; - sp_object_class->modified = sp_tref_modified; +SPTRef::SPTRef() : SPItem() { + this->stringChild = NULL; - gobject_class->finalize = sp_tref_finalize; + //new (&this->attributes) TextTagAttributes; - SPItemClass *item_class = (SPItemClass *) tref_class; + this->href = NULL; + this->uriOriginalRef = new SPTRefReference(this); + //new (&this->_delete_connection) sigc::connection(); + //new (&this->_changed_connection) sigc::connection(); - item_class->bbox = sp_tref_bbox; - item_class->description = sp_tref_description; + this->_changed_connection = + this->uriOriginalRef->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_tref_href_changed), this)); } -static void -sp_tref_init(SPTRef *tref) -{ - new (&tref->attributes) TextTagAttributes; - - tref->href = NULL; - tref->uriOriginalRef = new SPTRefReference(tref); - new (&tref->_delete_connection) sigc::connection(); - new (&tref->_changed_connection) sigc::connection(); - - tref->_changed_connection = - tref->uriOriginalRef->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_tref_href_changed), tref)); -} - - -static void -sp_tref_finalize(GObject *obj) -{ - SPTRef *tref = (SPTRef *) obj; - - delete tref->uriOriginalRef; +SPTRef::~SPTRef() { + delete this->uriOriginalRef; - tref->_delete_connection.~connection(); - tref->_changed_connection.~connection(); + //this->_delete_connection.~connection(); + //this->_changed_connection.~connection(); } +void SPTRef::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPItem::build(document, repr); -/** - * Reads the Inkscape::XML::Node, and initializes SPTRef variables. - */ -static void -sp_tref_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_tref_parent_class)->build) { - ((SPObjectClass *) sp_tref_parent_class)->build(object, document, repr); - } - - object->readAttr( "xlink:href" ); - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "dx" ); - object->readAttr( "dy" ); - object->readAttr( "rotate" ); + this->readAttr( "xlink:href" ); + this->readAttr( "x" ); + this->readAttr( "y" ); + this->readAttr( "dx" ); + this->readAttr( "dy" ); + this->readAttr( "rotate" ); } -/** - * Drops any allocated memory. - */ -static void -sp_tref_release(SPObject *object) -{ - SPTRef *tref = SP_TREF(object); - - tref->attributes.~TextTagAttributes(); +void SPTRef::release() { + //this->attributes.~TextTagAttributes(); - tref->_delete_connection.disconnect(); - tref->_changed_connection.disconnect(); + this->_delete_connection.disconnect(); + this->_changed_connection.disconnect(); - g_free(tref->href); - tref->href = NULL; + g_free(this->href); + this->href = NULL; - tref->uriOriginalRef->detach(); + this->uriOriginalRef->detach(); - if (((SPObjectClass *) sp_tref_parent_class)->release) - ((SPObjectClass *) sp_tref_parent_class)->release(object); + SPItem::release(); } -/** - * Sets a specific value in the SPTRef. - */ -static void -sp_tref_set(SPObject *object, unsigned int key, gchar const *value) -{ - debug("0x%p %s(%u): '%s'",object, +void SPTRef::set(unsigned int key, const gchar* value) { + debug("0x%p %s(%u): '%s'",this, sp_attribute_name(key),key,value ? value : "<no value>"); - SPTRef *tref = SP_TREF(object); - - if (tref->attributes.readSingleAttribute(key, value)) { // x, y, dx, dy, rotate - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + if (this->attributes.readSingleAttribute(key, value)) { // x, y, dx, dy, rotate + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } else if (key == SP_ATTR_XLINK_HREF) { // xlink:href if ( !value ) { // No value - g_free(tref->href); - tref->href = NULL; - tref->uriOriginalRef->detach(); - } else if ((tref->href && strcmp(value, tref->href) != 0) || (!tref->href)) { - + g_free(this->href); + this->href = NULL; + this->uriOriginalRef->detach(); + } else if ((this->href && strcmp(value, this->href) != 0) || (!this->href)) { // Value has changed - if ( tref->href ) { - g_free(tref->href); - tref->href = NULL; + if ( this->href ) { + g_free(this->href); + this->href = NULL; } - tref->href = g_strdup(value); + this->href = g_strdup(value); try { - tref->uriOriginalRef->attach(Inkscape::URI(value)); - tref->uriOriginalRef->updateObserver(); + this->uriOriginalRef->attach(Inkscape::URI(value)); + this->uriOriginalRef->updateObserver(); } catch ( Inkscape::BadURIException &e ) { g_warning("%s", e.what()); - tref->uriOriginalRef->detach(); + this->uriOriginalRef->detach(); } // No matter what happened, an update should be in order - tref->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } - } else { // default - if (((SPObjectClass *) sp_tref_parent_class)->set) { - ((SPObjectClass *) sp_tref_parent_class)->set(object, key, value); - } + SPItem::set(key, value); } - - } -/** - * Receives update notifications. Code based on sp_use_update and sp_tspan_update. - */ -static void -sp_tref_update(SPObject *object, SPCtx *ctx, guint flags) -{ - debug("0x%p",object); - - SPTRef *tref = SP_TREF(object); +void SPTRef::update(SPCtx *ctx, guint flags) { + debug("0x%p",this); - if (((SPObjectClass *) sp_tref_parent_class)->update) { - ((SPObjectClass *) sp_tref_parent_class)->update(object, ctx, flags); - } + SPItem::update(ctx, flags); if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; @@ -228,123 +156,104 @@ sp_tref_update(SPObject *object, SPCtx *ctx, guint flags) flags &= SP_OBJECT_MODIFIED_CASCADE; - SPObject *child = tref->stringChild; + SPObject *child = this->stringChild; + if (child) { if ( flags || ( child->uflags & SP_OBJECT_MODIFIED_FLAG )) { child->updateDisplay(ctx, flags); } } - - } -static void -sp_tref_modified(SPObject *object, guint flags) -{ - SPTRef *tref_obj = SP_TREF(object); - +void SPTRef::modified(unsigned int flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } flags &= SP_OBJECT_MODIFIED_CASCADE; - SPObject *child = tref_obj->stringChild; + SPObject *child = this->stringChild; + if (child) { - g_object_ref(G_OBJECT(child)); + sp_object_ref(child); + if (flags || (child->mflags & SP_OBJECT_MODIFIED_FLAG)) { child->emitModified(flags); } - g_object_unref(G_OBJECT(child)); + + sp_object_unref(child); } } -/** - * Writes its settings to an incoming repr object, if any. - */ -static Inkscape::XML::Node * -sp_tref_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - debug("0x%p",object); - - SPTRef *tref = SP_TREF(object); +Inkscape::XML::Node* SPTRef::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { + debug("0x%p",this); if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:tref"); } - tref->attributes.writeTo(repr); + this->attributes.writeTo(repr); - if (tref->uriOriginalRef->getURI()) { - gchar *uri_string = tref->uriOriginalRef->getURI()->toString(); + if (this->uriOriginalRef->getURI()) { + gchar *uri_string = this->uriOriginalRef->getURI()->toString(); debug("uri_string=%s", uri_string); repr->setAttribute("xlink:href", uri_string); g_free(uri_string); } - if (((SPObjectClass *) sp_tref_parent_class)->write) { - ((SPObjectClass *) sp_tref_parent_class)->write(object, xml_doc, repr, flags); - } + SPItem::write(xml_doc, repr, flags); return repr; } -/* - * The code for this function is swiped from the tspan bbox code, since tref should work pretty much the same way - */ -static Geom::OptRect -sp_tref_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type) -{ +Geom::OptRect SPTRef::bbox(Geom::Affine const &transform, SPItem::BBoxType type) { Geom::OptRect bbox; // find out the ancestor text which holds our layout - SPObject const *parent_text = item; + SPObject const *parent_text = this; + while ( parent_text && !SP_IS_TEXT(parent_text) ) { parent_text = parent_text->parent; } + if (parent_text == NULL) { return bbox; } // get the bbox of our portion of the layout bbox = SP_TEXT(parent_text)->layout.bounds(transform, - sp_text_get_length_upto(parent_text, item), sp_text_get_length_upto(item, NULL) - 1); + sp_text_get_length_upto(parent_text, this), sp_text_get_length_upto(this, NULL) - 1); // Add stroke width // FIXME this code is incorrect - if (bbox && type == SPItem::VISUAL_BBOX && !item->style->stroke.isNone()) { + if (bbox && type == SPItem::VISUAL_BBOX && !this->style->stroke.isNone()) { double scale = transform.descrim(); - bbox->expandBy(0.5 * item->style->stroke_width.computed * scale); + bbox->expandBy(0.5 * this->style->stroke_width.computed * scale); } + return bbox; } +gchar* SPTRef::description() { + SPObject *referred = this->getObjectReferredTo(); + + if (this->getObjectReferredTo()) { + char *child_desc; + + if (SP_IS_ITEM(referred)) { + child_desc = SP_ITEM(referred)->getDetailedDescription(); + } else { + child_desc = g_strdup(""); + } + + char *ret = g_strdup_printf( + _("<b>Cloned character data</b>%s%s"), + (SP_IS_ITEM(referred) ? _(" from ") : ""), + child_desc); + g_free(child_desc); + + return ret; + } -static gchar * -sp_tref_description(SPItem *item) -{ - SPTRef *tref = SP_TREF(item); - - if (tref) - { - SPObject *referred = tref->getObjectReferredTo(); - - if (tref->getObjectReferredTo()) { - char *child_desc; - - if (SP_IS_ITEM(referred)) { - child_desc = SP_ITEM(referred)->description(); - } else { - child_desc = g_strdup(""); - } - - char *ret = g_strdup_printf( - _("<b>Cloned character data</b>%s%s"), - (SP_IS_ITEM(referred) ? _(" from ") : ""), - child_desc); - g_free(child_desc); - return ret; - } - } return g_strdup(_("<b>Orphaned cloned character data</b>")); } @@ -496,7 +405,7 @@ void sp_tref_update_text(SPTRef *tref) Inkscape::XML::Document *xml_doc = tref->document->getReprDoc(); Inkscape::XML::Node *newStringRepr = xml_doc->createTextNode(charData.c_str()); - tref->stringChild = SP_OBJECT(g_object_new(sp_repr_type_lookup(newStringRepr), NULL)); + tref->stringChild = SPFactory::instance().createObject(NodeTraits::get_type_string(*newStringRepr)); // Add this SPString as a child of the tref tref->attach(tref->stringChild, tref->lastChild()); diff --git a/src/sp-tref.h b/src/sp-tref.h index 33a8138d1..451c6cb58 100644 --- a/src/sp-tref.h +++ b/src/sp-tref.h @@ -22,13 +22,14 @@ /* tref base class */ -#define SP_TYPE_TREF (sp_tref_get_type()) -#define SP_TREF(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_TREF, SPTRef)) -#define SP_TREF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_TREF, SPTSpanClass)) -#define SP_IS_TREF(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_TREF)) -#define SP_IS_TREF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_TREF)) +#define SP_TREF(obj) (dynamic_cast<SPTRef*>((SPObject*)obj)) +#define SP_IS_TREF(obj) (dynamic_cast<const SPTRef*>((SPObject*)obj) != NULL) + +class SPTRef : public SPItem { +public: + SPTRef(); + virtual ~SPTRef(); -struct SPTRef : public SPItem { // Attributes that are used in the same way they would be in a tspan TextTagAttributes attributes; @@ -48,13 +49,17 @@ struct SPTRef : public SPItem { sigc::connection _changed_connection; SPObject * getObjectReferredTo(); -}; -struct SPTRefClass { - SPItemClass parent_class; -}; + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + virtual void set(unsigned int key, const gchar* value); + virtual void update(SPCtx* ctx, unsigned int flags); + virtual void modified(unsigned int flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); -GType sp_tref_get_type(); + virtual Geom::OptRect bbox(Geom::Affine const &transform, SPItem::BBoxType type); + virtual gchar* description(); +}; void sp_tref_update_text(SPTRef *tref); bool sp_tref_reference_allowed(SPTRef *tref, SPObject *possible_ref); diff --git a/src/sp-tspan.cpp b/src/sp-tspan.cpp index 6f0b6ac39..63dcd07d8 100644 --- a/src/sp-tspan.cpp +++ b/src/sp-tspan.cpp @@ -43,172 +43,144 @@ #include "xml/repr.h" #include "document.h" +#include "sp-factory.h" -/*##################################################### -# SPTSPAN -#####################################################*/ +namespace { + SPObject* createTSpan() { + return new SPTSpan(); + } -static void sp_tspan_build(SPObject * object, SPDocument * document, Inkscape::XML::Node * repr); -static void sp_tspan_release(SPObject *object); -static void sp_tspan_set(SPObject *object, unsigned key, gchar const *value); -static void sp_tspan_update(SPObject *object, SPCtx *ctx, guint flags); -static void sp_tspan_modified(SPObject *object, unsigned flags); -static Geom::OptRect sp_tspan_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type); -static Inkscape::XML::Node *sp_tspan_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static char *sp_tspan_description (SPItem *item); + SPObject* createTextPath() { + return new SPTextPath(); + } -G_DEFINE_TYPE(SPTSpan, sp_tspan, SP_TYPE_ITEM); - -static void -sp_tspan_class_init(SPTSpanClass *classname) -{ - SPObjectClass *sp_object_class = SP_OBJECT_CLASS(classname); - SPItemClass *item_class = SP_ITEM_CLASS(classname); - - sp_object_class->build = sp_tspan_build; - sp_object_class->release = sp_tspan_release; - sp_object_class->set = sp_tspan_set; - sp_object_class->update = sp_tspan_update; - sp_object_class->modified = sp_tspan_modified; - sp_object_class->write = sp_tspan_write; - - item_class->bbox = sp_tspan_bbox; - item_class->description = sp_tspan_description; + bool tspanRegistered = SPFactory::instance().registerObject("svg:tspan", createTSpan); + bool textPathRegistered = SPFactory::instance().registerObject("svg:textPath", createTextPath); } -static void -sp_tspan_init(SPTSpan *tspan) -{ - tspan->role = SP_TSPAN_ROLE_UNSPECIFIED; - new (&tspan->attributes) TextTagAttributes; +/*##################################################### +# SPTSPAN +#####################################################*/ +SPTSpan::SPTSpan() : SPItem() { + this->role = SP_TSPAN_ROLE_UNSPECIFIED; + //new (&this->attributes) TextTagAttributes; } -static void -sp_tspan_release(SPObject *object) -{ - SPTSpan *tspan = SP_TSPAN(object); +SPTSpan::~SPTSpan() { +} - tspan->attributes.~TextTagAttributes(); +void SPTSpan::build(SPDocument *doc, Inkscape::XML::Node *repr) { + this->readAttr( "x" ); + this->readAttr( "y" ); + this->readAttr( "dx" ); + this->readAttr( "dy" ); + this->readAttr( "rotate" ); + this->readAttr( "sodipodi:role" ); - if ((SP_OBJECT_CLASS(sp_tspan_parent_class))->release) - (SP_OBJECT_CLASS(sp_tspan_parent_class))->release(object); + SPItem::build(doc, repr); } -static void -sp_tspan_build(SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr) -{ - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "dx" ); - object->readAttr( "dy" ); - object->readAttr( "rotate" ); - object->readAttr( "sodipodi:role" ); - - if ((SP_OBJECT_CLASS(sp_tspan_parent_class))->build) - (SP_OBJECT_CLASS(sp_tspan_parent_class))->build(object, doc, repr); -} +void SPTSpan::release() { + //this->attributes.~TextTagAttributes(); -static void -sp_tspan_set(SPObject *object, unsigned key, gchar const *value) -{ - SPTSpan *tspan = SP_TSPAN(object); + SPItem::release(); +} - if (tspan->attributes.readSingleAttribute(key, value)) { - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); +void SPTSpan::set(unsigned int key, const gchar* value) { + if (this->attributes.readSingleAttribute(key, value)) { + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } else { switch (key) { case SP_ATTR_SODIPODI_ROLE: if (value && (!strcmp(value, "line") || !strcmp(value, "paragraph"))) { - tspan->role = SP_TSPAN_ROLE_LINE; + this->role = SP_TSPAN_ROLE_LINE; } else { - tspan->role = SP_TSPAN_ROLE_UNSPECIFIED; + this->role = SP_TSPAN_ROLE_UNSPECIFIED; } break; + default: - if ((SP_OBJECT_CLASS(sp_tspan_parent_class))->set) - (SP_OBJECT_CLASS(sp_tspan_parent_class))->set(object, key, value); + SPItem::set(key, value); break; } } } -static void sp_tspan_update(SPObject *object, SPCtx *ctx, guint flags) -{ - if ((SP_OBJECT_CLASS(sp_tspan_parent_class))->update) { - (SP_OBJECT_CLASS(sp_tspan_parent_class))->update(object, ctx, flags); - } +void SPTSpan::update(SPCtx *ctx, guint flags) { + SPItem::update(ctx, flags); if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; - for ( SPObject *ochild = object->firstChild() ; ochild ; ochild = ochild->getNext() ) { + for ( SPObject *ochild = this->firstChild() ; ochild ; ochild = ochild->getNext() ) { if ( flags || ( ochild->uflags & SP_OBJECT_MODIFIED_FLAG )) { - ochild->updateDisplay(ctx, flags); + ochild->updateDisplay(ctx, flags); } } } -static void sp_tspan_modified(SPObject *object, unsigned flags) -{ - if ((SP_OBJECT_CLASS(sp_tspan_parent_class))->modified) { - (SP_OBJECT_CLASS(sp_tspan_parent_class))->modified(object, flags); - } +void SPTSpan::modified(unsigned int flags) { +// SPItem::onModified(flags); if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; - for ( SPObject *ochild = object->firstChild() ; ochild ; ochild = ochild->getNext() ) { + for ( SPObject *ochild = this->firstChild() ; ochild ; ochild = ochild->getNext() ) { if (flags || (ochild->mflags & SP_OBJECT_MODIFIED_FLAG)) { ochild->emitModified(flags); } } } -static Geom::OptRect -sp_tspan_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type) -{ +Geom::OptRect SPTSpan::bbox(Geom::Affine const &transform, SPItem::BBoxType type) { Geom::OptRect bbox; // find out the ancestor text which holds our layout - SPObject const *parent_text = item; + SPObject const *parent_text = this; + while (parent_text && !SP_IS_TEXT(parent_text)) { parent_text = parent_text->parent; } + if (parent_text == NULL) { return bbox; } // get the bbox of our portion of the layout - bbox = SP_TEXT(parent_text)->layout.bounds(transform, sp_text_get_length_upto(parent_text, item), sp_text_get_length_upto(item, NULL) - 1); - if (!bbox) return bbox; + bbox = SP_TEXT(parent_text)->layout.bounds(transform, sp_text_get_length_upto(parent_text, this), sp_text_get_length_upto(this, NULL) - 1); + + if (!bbox) { + return bbox; + } // Add stroke width // FIXME this code is incorrect - if (type == SPItem::VISUAL_BBOX && !item->style->stroke.isNone()) { + if (type == SPItem::VISUAL_BBOX && !this->style->stroke.isNone()) { double scale = transform.descrim(); - bbox->expandBy(0.5 * item->style->stroke_width.computed * scale); + bbox->expandBy(0.5 * this->style->stroke_width.computed * scale); } + return bbox; } -static Inkscape::XML::Node * -sp_tspan_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPTSpan *tspan = SP_TSPAN(object); - +Inkscape::XML::Node* SPTSpan::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:tspan"); } - tspan->attributes.writeTo(repr); + this->attributes.writeTo(repr); if ( flags&SP_OBJECT_WRITE_BUILD ) { GSList *l = NULL; - for (SPObject* child = object->firstChild() ; child ; child = child->getNext() ) { + + for (SPObject* child = this->firstChild() ; child ; child = child->getNext() ) { Inkscape::XML::Node* c_repr=NULL; + if ( SP_IS_TSPAN(child) || SP_IS_TREF(child) ) { c_repr = child->updateRepr(xml_doc, NULL, flags); } else if ( SP_IS_TEXTPATH(child) ) { @@ -216,17 +188,19 @@ sp_tspan_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML } else if ( SP_IS_STRING(child) ) { c_repr = xml_doc->createTextNode(SP_STRING(child)->string.c_str()); } + if ( c_repr ) { l = g_slist_prepend(l, c_repr); } } + while ( l ) { repr->addChild((Inkscape::XML::Node *) l->data, NULL); Inkscape::GC::release((Inkscape::XML::Node *) l->data); l = g_slist_remove(l, l->data); } } else { - for (SPObject* child = object->firstChild() ; child ; child = child->getNext() ) { + for (SPObject* child = this->firstChild() ; child ; child = child->getNext() ) { if ( SP_IS_TSPAN(child) || SP_IS_TREF(child) ) { child->updateRepr(flags); } else if ( SP_IS_TEXTPATH(child) ) { @@ -237,18 +211,12 @@ sp_tspan_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML } } - if ((SP_OBJECT_CLASS(sp_tspan_parent_class))->write) { - (SP_OBJECT_CLASS(sp_tspan_parent_class))->write(object, xml_doc, repr, flags); - } + SPItem::write(xml_doc, repr, flags); return repr; } -static char * -sp_tspan_description(SPItem *item) -{ - g_return_val_if_fail(SP_IS_TSPAN(item), NULL); - +gchar* SPTSpan::description() { return g_strdup(_("<b>Text span</b>")); } @@ -256,79 +224,35 @@ sp_tspan_description(SPItem *item) /*##################################################### # SPTEXTPATH #####################################################*/ - -static void sp_textpath_finalize(GObject *obj); - -static void sp_textpath_build(SPObject * object, SPDocument * document, Inkscape::XML::Node * repr); -static void sp_textpath_release(SPObject *object); -static void sp_textpath_set(SPObject *object, unsigned key, gchar const *value); -static void sp_textpath_update(SPObject *object, SPCtx *ctx, guint flags); -static void sp_textpath_modified(SPObject *object, unsigned flags); -static Inkscape::XML::Node *sp_textpath_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - void refresh_textpath_source(SPTextPath* offset); -G_DEFINE_TYPE(SPTextPath, sp_textpath, SP_TYPE_ITEM); - -static void sp_textpath_class_init(SPTextPathClass *classname) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS(classname); - SPObjectClass *sp_object_class = SP_OBJECT_CLASS(classname); - - gobject_class->finalize = sp_textpath_finalize; +SPTextPath::SPTextPath() : SPItem() { + //new (&this->attributes) TextTagAttributes; - sp_object_class->build = sp_textpath_build; - sp_object_class->release = sp_textpath_release; - sp_object_class->set = sp_textpath_set; - sp_object_class->update = sp_textpath_update; - sp_object_class->modified = sp_textpath_modified; - sp_object_class->write = sp_textpath_write; -} - -static void -sp_textpath_init(SPTextPath *textpath) -{ - new (&textpath->attributes) TextTagAttributes; + this->startOffset._set = false; + this->originalPath = NULL; + this->isUpdating=false; - textpath->startOffset._set = false; - textpath->originalPath = NULL; - textpath->isUpdating=false; // set up the uri reference - textpath->sourcePath = new SPUsePath(textpath); - textpath->sourcePath->user_unlink = sp_textpath_to_text; -} - -static void sp_textpath_finalize(GObject *obj) -{ - SPTextPath *textpath = static_cast<SPTextPath *>(obj); - - delete textpath->sourcePath; + this->sourcePath = new SPUsePath(this); + this->sourcePath->user_unlink = sp_textpath_to_text; } -static void sp_textpath_release(SPObject *object) -{ - SPTextPath *textpath = SP_TEXTPATH(object); - - textpath->attributes.~TextTagAttributes(); - - if (textpath->originalPath) delete textpath->originalPath; - textpath->originalPath = NULL; - - if ((SP_OBJECT_CLASS(sp_textpath_parent_class))->release) - (SP_OBJECT_CLASS(sp_textpath_parent_class))->release(object); +SPTextPath::~SPTextPath() { + delete this->sourcePath; } -static void sp_textpath_build(SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr) -{ - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "dx" ); - object->readAttr( "dy" ); - object->readAttr( "rotate" ); - object->readAttr( "startOffset" ); - object->readAttr( "xlink:href" ); +void SPTextPath::build(SPDocument *doc, Inkscape::XML::Node *repr) { + this->readAttr( "x" ); + this->readAttr( "y" ); + this->readAttr( "dx" ); + this->readAttr( "dy" ); + this->readAttr( "rotate" ); + this->readAttr( "startOffset" ); + this->readAttr( "xlink:href" ); bool no_content = true; + for (Inkscape::XML::Node* rch = repr->firstChild() ; rch != NULL; rch = rch->next()) { if ( rch->type() == Inkscape::XML::TEXT_NODE ) { @@ -343,54 +267,58 @@ static void sp_textpath_build(SPObject *object, SPDocument *doc, Inkscape::XML:: repr->addChild(rch, NULL); } - if ((SP_OBJECT_CLASS(sp_textpath_parent_class))->build) { - (SP_OBJECT_CLASS(sp_textpath_parent_class))->build(object, doc, repr); - } + SPItem::build(doc, repr); } -static void sp_textpath_set(SPObject *object, unsigned key, gchar const *value) -{ - SPTextPath *textpath = SP_TEXTPATH(object); +void SPTextPath::release() { + //this->attributes.~TextTagAttributes(); - if (textpath->attributes.readSingleAttribute(key, value)) { - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + if (this->originalPath) { + delete this->originalPath; + } + + this->originalPath = NULL; + + SPItem::release(); +} + +void SPTextPath::set(unsigned int key, const gchar* value) { + if (this->attributes.readSingleAttribute(key, value)) { + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } else { switch (key) { case SP_ATTR_XLINK_HREF: - textpath->sourcePath->link((char*)value); + this->sourcePath->link((char*)value); break; case SP_ATTR_STARTOFFSET: - textpath->startOffset.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->startOffset.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; default: - if ((SP_OBJECT_CLASS(sp_textpath_parent_class))->set) - (SP_OBJECT_CLASS(sp_textpath_parent_class))->set(object, key, value); + SPItem::set(key, value); break; } } } -static void sp_textpath_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPTextPath *textpath = SP_TEXTPATH(object); +void SPTextPath::update(SPCtx *ctx, guint flags) { + this->isUpdating = true; - textpath->isUpdating = true; - if ( textpath->sourcePath->sourceDirty ) { - refresh_textpath_source(textpath); + if ( this->sourcePath->sourceDirty ) { + refresh_textpath_source(this); } - textpath->isUpdating = false; - if ((SP_OBJECT_CLASS(sp_textpath_parent_class))->update) { - (SP_OBJECT_CLASS(sp_textpath_parent_class))->update(object, ctx, flags); - } + this->isUpdating = false; + + SPItem::update(ctx, flags); if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; - for ( SPObject *ochild = object->firstChild() ; ochild ; ochild = ochild->getNext() ) { + for ( SPObject *ochild = this->firstChild() ; ochild ; ochild = ochild->getNext() ) { if ( flags || ( ochild->uflags & SP_OBJECT_MODIFIED_FLAG )) { ochild->updateDisplay(ctx, flags); } @@ -400,7 +328,10 @@ static void sp_textpath_update(SPObject *object, SPCtx *ctx, guint flags) void refresh_textpath_source(SPTextPath* tp) { - if ( tp == NULL ) return; + if ( tp == NULL ) { + return; + } + tp->sourcePath->refresh_source(); tp->sourcePath->sourceDirty=false; @@ -409,61 +340,59 @@ void refresh_textpath_source(SPTextPath* tp) if (tp->originalPath) { delete tp->originalPath; } + tp->originalPath = NULL; tp->originalPath = new Path; tp->originalPath->Copy(tp->sourcePath->originalPath); tp->originalPath->ConvertWithBackData(0.01); - } } -static void sp_textpath_modified(SPObject *object, unsigned flags) -{ - if ((SP_OBJECT_CLASS(sp_textpath_parent_class))->modified) { - (SP_OBJECT_CLASS(sp_textpath_parent_class))->modified(object, flags); - } +void SPTextPath::modified(unsigned int flags) { +// SPItem::onModified(flags); if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; - for ( SPObject *ochild = object->firstChild() ; ochild ; ochild = ochild->getNext() ) { + for ( SPObject *ochild = this->firstChild() ; ochild ; ochild = ochild->getNext() ) { if (flags || (ochild->mflags & SP_OBJECT_MODIFIED_FLAG)) { ochild->emitModified(flags); } } } -static Inkscape::XML::Node * -sp_textpath_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPTextPath *textpath = SP_TEXTPATH(object); - +Inkscape::XML::Node* SPTextPath::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:textPath"); } - textpath->attributes.writeTo(repr); - if (textpath->startOffset._set) { - if (textpath->startOffset.unit == SVGLength::PERCENT) { - Inkscape::SVGOStringStream os; - os << (textpath->startOffset.computed * 100.0) << "%"; - textpath->getRepr()->setAttribute("startOffset", os.str().c_str()); + this->attributes.writeTo(repr); + if (this->startOffset._set) { + if (this->startOffset.unit == SVGLength::PERCENT) { + Inkscape::SVGOStringStream os; + os << (this->startOffset.computed * 100.0) << "%"; + this->getRepr()->setAttribute("startOffset", os.str().c_str()); } else { /* FIXME: This logic looks rather undesirable if e.g. startOffset is to be in ems. */ - sp_repr_set_svg_double(repr, "startOffset", textpath->startOffset.computed); + sp_repr_set_svg_double(repr, "startOffset", this->startOffset.computed); } } - if ( textpath->sourcePath->sourceHref ) repr->setAttribute("xlink:href", textpath->sourcePath->sourceHref); + if ( this->sourcePath->sourceHref ) { + repr->setAttribute("xlink:href", this->sourcePath->sourceHref); + } - if ( flags&SP_OBJECT_WRITE_BUILD ) { + if ( flags & SP_OBJECT_WRITE_BUILD ) { GSList *l = NULL; - for (SPObject* child = object->firstChild() ; child ; child = child->getNext() ) { + + for (SPObject* child = this->firstChild() ; child ; child = child->getNext() ) { Inkscape::XML::Node* c_repr=NULL; + if ( SP_IS_TSPAN(child) || SP_IS_TREF(child) ) { c_repr = child->updateRepr(xml_doc, NULL, flags); } else if ( SP_IS_TEXTPATH(child) ) { @@ -471,17 +400,19 @@ sp_textpath_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape:: } else if ( SP_IS_STRING(child) ) { c_repr = xml_doc->createTextNode(SP_STRING(child)->string.c_str()); } + if ( c_repr ) { l = g_slist_prepend(l, c_repr); } } + while ( l ) { repr->addChild((Inkscape::XML::Node *) l->data, NULL); Inkscape::GC::release((Inkscape::XML::Node *) l->data); l = g_slist_remove(l, l->data); } } else { - for (SPObject* child = object->firstChild() ; child ; child = child->getNext() ) { + for (SPObject* child = this->firstChild() ; child ; child = child->getNext() ) { if ( SP_IS_TSPAN(child) || SP_IS_TREF(child) ) { child->updateRepr(flags); } else if ( SP_IS_TEXTPATH(child) ) { @@ -492,9 +423,7 @@ sp_textpath_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape:: } } - if ((SP_OBJECT_CLASS(sp_textpath_parent_class))->write) { - (SP_OBJECT_CLASS(sp_textpath_parent_class))->write(object, xml_doc, repr, flags); - } + SPItem::write(xml_doc, repr, flags); return repr; } @@ -504,8 +433,10 @@ SPItem *sp_textpath_get_path_item(SPTextPath *tp) { if (tp && tp->sourcePath) { SPItem *refobj = tp->sourcePath->getObject(); - if (SP_IS_ITEM(refobj)) + + if (SP_IS_ITEM(refobj)) { return refobj; + } } return NULL; } @@ -515,11 +446,16 @@ void sp_textpath_to_text(SPObject *tp) SPObject *text = tp->parent; Geom::OptRect bbox = SP_ITEM(text)->geometricBounds(SP_ITEM(text)->i2doc_affine()); - if (!bbox) return; + + if (!bbox) { + return; + } + Geom::Point xy = bbox->min(); // make a list of textpath children GSList *tp_reprs = NULL; + for (SPObject *o = tp->firstChild() ; o != NULL; o = o->next) { tp_reprs = g_slist_prepend(tp_reprs, o->getRepr()); } diff --git a/src/sp-tspan.h b/src/sp-tspan.h index 794e71039..d1c6ec4bc 100644 --- a/src/sp-tspan.h +++ b/src/sp-tspan.h @@ -9,13 +9,8 @@ #include "sp-item.h" #include "text-tag-attributes.h" -G_BEGIN_DECLS - -#define SP_TYPE_TSPAN (sp_tspan_get_type()) -#define SP_TSPAN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_TSPAN, SPTSpan)) -#define SP_TSPAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_TSPAN, SPTSpanClass)) -#define SP_IS_TSPAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SP_TYPE_TSPAN)) -#define SP_IS_TSPAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_TSPAN)) +#define SP_TSPAN(obj) (dynamic_cast<SPTSpan*>((SPObject*)obj)) +#define SP_IS_TSPAN(obj) (dynamic_cast<const SPTSpan*>((SPObject*)obj) != NULL) enum { SP_TSPAN_ROLE_UNSPECIFIED, @@ -23,18 +18,24 @@ enum { SP_TSPAN_ROLE_LINE }; -struct SPTSpan : public SPItem { +class SPTSpan : public SPItem { +public: + SPTSpan(); + virtual ~SPTSpan(); + guint role : 2; TextTagAttributes attributes; -}; -struct SPTSpanClass { - SPItemClass parent_class; -}; - -GType sp_tspan_get_type() G_GNUC_CONST; + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + virtual void set(unsigned int key, const gchar* value); + virtual void update(SPCtx* ctx, unsigned int flags); + virtual void modified(unsigned int flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); -G_END_DECLS + virtual Geom::OptRect bbox(Geom::Affine const &transform, SPItem::BBoxType type); + virtual gchar* description(); +}; #endif /* !INKSCAPE_SP_TSPAN_H */ diff --git a/src/sp-use.cpp b/src/sp-use.cpp index 5ec1f2523..44935e61d 100644 --- a/src/sp-use.cpp +++ b/src/sp-use.cpp @@ -25,7 +25,7 @@ #include "display/drawing-group.h" #include "attributes.h" #include "document.h" -#include "sp-object-repr.h" +#include "sp-factory.h" #include "sp-flowregion.h" #include "uri.h" #include "print.h" @@ -38,213 +38,153 @@ #include "sp-use-reference.h" /* fixme: */ - -static void sp_use_finalize(GObject *obj); - -static void sp_use_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); -static void sp_use_release(SPObject *object); -static void sp_use_set(SPObject *object, unsigned key, gchar const *value); -static Inkscape::XML::Node *sp_use_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_use_update(SPObject *object, SPCtx *ctx, guint flags); -static void sp_use_modified(SPObject *object, guint flags); - -static Geom::OptRect sp_use_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type); -static void sp_use_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); -static void sp_use_print(SPItem *item, SPPrintContext *ctx); -static gchar *sp_use_description(SPItem *item); -static Inkscape::DrawingItem *sp_use_show(SPItem *item, Inkscape::Drawing &drawing, unsigned key, unsigned flags); -static void sp_use_hide(SPItem *item, unsigned key); - static void sp_use_href_changed(SPObject *old_ref, SPObject *ref, SPUse *use); - static void sp_use_delete_self(SPObject *deleted, SPUse *self); -//void m_print(gchar *say, Geom::Affine m) -//{ g_print("%s %g %g %g %g %g %g\n", say, m[0], m[1], m[2], m[3], m[4], m[5]); } +#include "sp-factory.h" -G_DEFINE_TYPE(SPUse, sp_use, SP_TYPE_ITEM); +namespace { + SPObject* createUse() { + return new SPUse(); + } -static void -sp_use_class_init(SPUseClass *classname) -{ - GObjectClass *gobject_class = (GObjectClass *) classname; - SPObjectClass *sp_object_class = (SPObjectClass *) classname; - SPItemClass *item_class = (SPItemClass *) classname; - - gobject_class->finalize = sp_use_finalize; - - sp_object_class->build = sp_use_build; - sp_object_class->release = sp_use_release; - sp_object_class->set = sp_use_set; - sp_object_class->write = sp_use_write; - sp_object_class->update = sp_use_update; - sp_object_class->modified = sp_use_modified; - - item_class->bbox = sp_use_bbox; - item_class->description = sp_use_description; - item_class->print = sp_use_print; - item_class->show = sp_use_show; - item_class->hide = sp_use_hide; - item_class->snappoints = sp_use_snappoints; + bool useRegistered = SPFactory::instance().registerObject("svg:use", createUse); } -static void -sp_use_init(SPUse *use) -{ - use->x.unset(); - use->y.unset(); - use->width.unset(SVGLength::PERCENT, 1.0, 1.0); - use->height.unset(SVGLength::PERCENT, 1.0, 1.0); - use->href = NULL; +SPUse::SPUse() : SPItem() { + this->child = NULL; - new (&use->_delete_connection) sigc::connection(); - new (&use->_changed_connection) sigc::connection(); + this->x.unset(); + this->y.unset(); + this->width.unset(SVGLength::PERCENT, 1.0, 1.0); + this->height.unset(SVGLength::PERCENT, 1.0, 1.0); + this->href = NULL; - new (&use->_transformed_connection) sigc::connection(); + //new (&this->_delete_connection) sigc::connection(); + //new (&this->_changed_connection) sigc::connection(); - use->ref = new SPUseReference(use); + //new (&this->_transformed_connection) sigc::connection(); - use->_changed_connection = use->ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_use_href_changed), use)); -} + this->ref = new SPUseReference(this); -static void -sp_use_finalize(GObject *obj) -{ - SPUse *use = reinterpret_cast<SPUse *>(obj); + this->_changed_connection = this->ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_use_href_changed), this)); +} - if (use->child) { - use->detach(use->child); - use->child = NULL; +SPUse::~SPUse() { + if (this->child) { + this->detach(this->child); + this->child = NULL; } - use->ref->detach(); - delete use->ref; - use->ref = 0; + this->ref->detach(); + delete this->ref; + this->ref = 0; - use->_delete_connection.~connection(); - use->_changed_connection.~connection(); + //this->_delete_connection.~connection(); + //this->_changed_connection.~connection(); - use->_transformed_connection.~connection(); + //this->_transformed_connection.~connection(); } -static void -sp_use_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_use_parent_class)->build) { - (* ((SPObjectClass *) sp_use_parent_class)->build)(object, document, repr); - } +void SPUse::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPItem::build(document, repr); - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "width" ); - object->readAttr( "height" ); - object->readAttr( "xlink:href" ); + this->readAttr( "x" ); + this->readAttr( "y" ); + this->readAttr( "width" ); + this->readAttr( "height" ); + this->readAttr( "xlink:href" ); // We don't need to create child here: // reading xlink:href will attach ref, and that will cause the changed signal to be emitted, // which will call sp_use_href_changed, and that will take care of the child } -static void -sp_use_release(SPObject *object) -{ - SPUse *use = SP_USE(object); - - if (use->child) { - object->detach(use->child); - use->child = NULL; +void SPUse::release() { + if (this->child) { + this->detach(this->child); + this->child = NULL; } - use->_delete_connection.disconnect(); - use->_changed_connection.disconnect(); - use->_transformed_connection.disconnect(); + this->_delete_connection.disconnect(); + this->_changed_connection.disconnect(); + this->_transformed_connection.disconnect(); - g_free(use->href); - use->href = NULL; + g_free(this->href); + this->href = NULL; - use->ref->detach(); + this->ref->detach(); - if (((SPObjectClass *) sp_use_parent_class)->release) { - ((SPObjectClass *) sp_use_parent_class)->release(object); - } + SPItem::release(); } -static void -sp_use_set(SPObject *object, unsigned key, gchar const *value) -{ - SPUse *use = SP_USE(object); - +void SPUse::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_X: - use->x.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->x.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_Y: - use->y.readOrUnset(value); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->y.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_WIDTH: - use->width.readOrUnset(value, SVGLength::PERCENT, 1.0, 1.0); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->width.readOrUnset(value, SVGLength::PERCENT, 1.0, 1.0); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_HEIGHT: - use->height.readOrUnset(value, SVGLength::PERCENT, 1.0, 1.0); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->height.readOrUnset(value, SVGLength::PERCENT, 1.0, 1.0); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_XLINK_HREF: { - if ( value && use->href && ( strcmp(value, use->href) == 0 ) ) { + if ( value && this->href && ( strcmp(value, this->href) == 0 ) ) { /* No change, do nothing. */ } else { - g_free(use->href); - use->href = NULL; + g_free(this->href); + this->href = NULL; + if (value) { // First, set the href field, because sp_use_href_changed will need it. - use->href = g_strdup(value); + this->href = g_strdup(value); // Now do the attaching, which emits the changed signal. try { - use->ref->attach(Inkscape::URI(value)); + this->ref->attach(Inkscape::URI(value)); } catch (Inkscape::BadURIException &e) { g_warning("%s", e.what()); - use->ref->detach(); + this->ref->detach(); } } else { - use->ref->detach(); + this->ref->detach(); } } break; } default: - if (((SPObjectClass *) sp_use_parent_class)->set) { - ((SPObjectClass *) sp_use_parent_class)->set(object, key, value); - } + SPItem::set(key, value); break; } } -static Inkscape::XML::Node * -sp_use_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPUse *use = SP_USE(object); - +Inkscape::XML::Node* SPUse::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:use"); } - if (((SPObjectClass *) (sp_use_parent_class))->write) { - ((SPObjectClass *) (sp_use_parent_class))->write(object, xml_doc, repr, flags); - } - - sp_repr_set_svg_double(repr, "x", use->x.computed); - sp_repr_set_svg_double(repr, "y", use->y.computed); + SPItem::write(xml_doc, repr, flags); - repr->setAttribute("width", sp_svg_length_write_with_units(use->width).c_str()); - repr->setAttribute("height", sp_svg_length_write_with_units(use->height).c_str()); + sp_repr_set_svg_double(repr, "x", this->x.computed); + sp_repr_set_svg_double(repr, "y", this->y.computed); + repr->setAttribute("width", sp_svg_length_write_with_units(this->width).c_str()); + repr->setAttribute("height", sp_svg_length_write_with_units(this->height).c_str()); - if (use->ref->getURI()) { - gchar *uri_string = use->ref->getURI()->toString(); + if (this->ref->getURI()) { + gchar *uri_string = this->ref->getURI()->toString(); repr->setAttribute("xlink:href", uri_string); g_free(uri_string); } @@ -252,35 +192,33 @@ sp_use_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML:: return repr; } -static Geom::OptRect sp_use_bbox(SPItem const *item, Geom::Affine const &transform, SPItem::BBoxType type) -{ - SPUse const *use = SP_USE(item); +Geom::OptRect SPUse::bbox(Geom::Affine const &transform, SPItem::BBoxType bboxtype) { Geom::OptRect bbox; - if (use->child && SP_IS_ITEM(use->child)) { - SPItem *child = SP_ITEM(use->child); + if (this->child && SP_IS_ITEM(this->child)) { + SPItem *child = SP_ITEM(this->child); Geom::Affine const ct( child->transform - * Geom::Translate(use->x.computed, - use->y.computed) + * Geom::Translate(this->x.computed, + this->y.computed) * transform ); - bbox = child->bounds(type, ct); + + bbox = child->bounds(bboxtype, ct); } + return bbox; } -static void sp_use_print(SPItem *item, SPPrintContext *ctx) -{ +void SPUse::print(SPPrintContext* ctx) { bool translated = false; - SPUse *use = SP_USE(item); - if ((use->x._set && use->x.computed != 0) || (use->y._set && use->y.computed != 0)) { - Geom::Affine tp(Geom::Translate(use->x.computed, use->y.computed)); + if ((this->x._set && this->x.computed != 0) || (this->y._set && this->y.computed != 0)) { + Geom::Affine tp(Geom::Translate(this->x.computed, this->y.computed)); sp_print_bind(ctx, tp, 1.0); translated = true; } - if (use->child && SP_IS_ITEM(use->child)) { - SP_ITEM(use->child)->invoke_print(ctx); + if (this->child && SP_IS_ITEM(this->child)) { + SP_ITEM(this->child)->invoke_print(ctx); } if (translated) { @@ -288,19 +226,16 @@ static void sp_use_print(SPItem *item, SPPrintContext *ctx) } } -static gchar *sp_use_description(SPItem *item) -{ - SPUse *use = SP_USE(item); - - if (use->child) { - - if( SP_IS_SYMBOL( use->child ) ) { - char *symbol_desc = SP_ITEM(use->child)->title(); +gchar* SPUse::description() { + if (this->child) { + if( SP_IS_SYMBOL( this->child ) ) { + char *symbol_desc = SP_ITEM(this->child)->title(); return g_strdup_printf(_("<b>'%s' Symbol</b>"), symbol_desc ); g_free(symbol_desc); } static unsigned recursion_depth = 0; + if (recursion_depth >= 4) { /* TRANSLATORS: Used for statusbar description for long <use> chains: * "Clone of: Clone of: ... in Layer 1". */ @@ -308,54 +243,47 @@ static gchar *sp_use_description(SPItem *item) /* We could do better, e.g. chasing the href chain until we reach something other than * a <use>, and giving its description. */ } + ++recursion_depth; - char *child_desc = SP_ITEM(use->child)->description(); + char *child_desc = SP_ITEM(this->child)->getDetailedDescription(); --recursion_depth; char *ret = g_strdup_printf(_("<b>Clone</b> of: %s"), child_desc); g_free(child_desc); + return ret; } else { return g_strdup(_("<b>Orphaned clone</b>")); } } -static Inkscape::DrawingItem * -sp_use_show(SPItem *item, Inkscape::Drawing &drawing, unsigned key, unsigned flags) -{ - SPUse *use = SP_USE(item); - +Inkscape::DrawingItem* SPUse::show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { Inkscape::DrawingGroup *ai = new Inkscape::DrawingGroup(drawing); ai->setPickChildren(false); - ai->setStyle(item->style); + ai->setStyle(this->style); - if (use->child) { - Inkscape::DrawingItem *ac = SP_ITEM(use->child)->invoke_show(drawing, key, flags); + if (this->child) { + Inkscape::DrawingItem *ac = SP_ITEM(this->child)->invoke_show(drawing, key, flags); if (ac) { ai->prependChild(ac); } - Geom::Translate t(use->x.computed, - use->y.computed); + + Geom::Translate t(this->x.computed, this->y.computed); ai->setChildTransform(t); } return ai; } -static void -sp_use_hide(SPItem *item, unsigned key) -{ - SPUse *use = SP_USE(item); - - if (use->child) { - SP_ITEM(use->child)->invoke_hide(key); +void SPUse::hide(unsigned int key) { + if (this->child) { + SP_ITEM(this->child)->invoke_hide(key); } - if (((SPItemClass *) sp_use_parent_class)->hide) { - ((SPItemClass *) sp_use_parent_class)->hide(item, key); - } +// SPItem::onHide(key); } + /** * Returns the ultimate original of a SPUse (i.e. the first object in the chain of its originals * which is not an SPUse). If no original is found, NULL is returned (it is the responsibility @@ -505,10 +433,28 @@ sp_use_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPUse *use) SPItem *refobj = use->ref->getObject(); if (refobj) { Inkscape::XML::Node *childrepr = refobj->getRepr(); - GType type = sp_repr_type_lookup(childrepr); - g_return_if_fail(type > G_TYPE_NONE); - if (g_type_is_a(type, SP_TYPE_ITEM)) { - use->child = (SPObject*) g_object_new(type, 0); + +// GType type = sp_repr_type_lookup(childrepr); +// g_return_if_fail(type > G_TYPE_NONE); +// if (g_type_is_a(type, SP_TYPE_ITEM)) { +// use->child = (SPObject*) g_object_new(type, 0); +// use->attach(use->child, use->lastChild()); +// sp_object_unref(use->child, use); +// (use->child)->invoke_build(use->document, childrepr, TRUE); +// +// for (SPItemView *v = item->display; v != NULL; v = v->next) { +// Inkscape::DrawingItem *ai; +// ai = SP_ITEM(use->child)->invoke_show(v->arenaitem->drawing(), v->key, v->flags); +// if (ai) { +// v->arenaitem->prependChild(ai); +// } +// } +// } + + SPObject* obj = SPFactory::instance().createObject(NodeTraits::get_type_string(*childrepr)); + if (SP_IS_ITEM(obj)) { + use->child = obj; + use->attach(use->child, use->lastChild()); sp_object_unref(use->child, use); (use->child)->invoke_build(use->document, childrepr, TRUE); @@ -520,8 +466,10 @@ sp_use_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPUse *use) v->arenaitem->prependChild(ai); } } - + } else { + delete obj; } + use->_delete_connection = refobj->connectDelete(sigc::bind(sigc::ptr_fun(&sp_use_delete_self), use)); use->_transformed_connection = SP_ITEM(refobj)->connectTransformed(sigc::bind(sigc::ptr_fun(&sp_use_move_compensate), use)); } @@ -548,93 +496,95 @@ sp_use_delete_self(SPObject */*deleted*/, SPUse *self) } } -static void -sp_use_update(SPObject *object, SPCtx *ctx, unsigned flags) -{ - SPItem *item = SP_ITEM(object); - SPUse *use = SP_USE(object); +void SPUse::update(SPCtx *ctx, unsigned flags) { SPItemCtx *ictx = (SPItemCtx *) ctx; SPItemCtx cctx = *ictx; - if (((SPObjectClass *) (sp_use_parent_class))->update) - ((SPObjectClass *) (sp_use_parent_class))->update(object, ctx, flags); + SPItem::update(ctx, flags); if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { - for (SPItemView *v = SP_ITEM(object)->display; v != NULL; v = v->next) { + for (SPItemView *v = SP_ITEM(this)->display; v != NULL; v = v->next) { Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); - g->setStyle(object->style); + g->setStyle(this->style); } } /* Set up child viewport */ - if (use->x.unit == SVGLength::PERCENT) { - use->x.computed = use->x.value * ictx->viewport.width(); + if (this->x.unit == SVGLength::PERCENT) { + this->x.computed = this->x.value * ictx->viewport.width(); } - if (use->y.unit == SVGLength::PERCENT) { - use->y.computed = use->y.value * ictx->viewport.height(); + + if (this->y.unit == SVGLength::PERCENT) { + this->y.computed = this->y.value * ictx->viewport.height(); } - if (use->width.unit == SVGLength::PERCENT) { - use->width.computed = use->width.value * ictx->viewport.width(); + + if (this->width.unit == SVGLength::PERCENT) { + this->width.computed = this->width.value * ictx->viewport.width(); } - if (use->height.unit == SVGLength::PERCENT) { - use->height.computed = use->height.value * ictx->viewport.height(); + + if (this->height.unit == SVGLength::PERCENT) { + this->height.computed = this->height.value * ictx->viewport.height(); } - cctx.viewport = Geom::Rect::from_xywh(0, 0, use->width.computed, use->height.computed); + + cctx.viewport = Geom::Rect::from_xywh(0, 0, this->width.computed, this->height.computed); cctx.i2vp = Geom::identity(); flags&=~SP_OBJECT_USER_MODIFIED_FLAG_B; - if (use->child) { - g_object_ref(G_OBJECT(use->child)); - if (flags || (use->child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { - if (SP_IS_ITEM(use->child)) { - SPItem const &chi = *SP_ITEM(use->child); + if (this->child) { + sp_object_ref(this->child); + + if (flags || (this->child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { + if (SP_IS_ITEM(this->child)) { + SPItem const &chi = *SP_ITEM(this->child); cctx.i2doc = chi.transform * ictx->i2doc; cctx.i2vp = chi.transform * ictx->i2vp; - use->child->updateDisplay((SPCtx *)&cctx, flags); + this->child->updateDisplay((SPCtx *)&cctx, flags); } else { - use->child->updateDisplay(ctx, flags); + this->child->updateDisplay(ctx, flags); } } - g_object_unref(G_OBJECT(use->child)); + + sp_object_unref(this->child); } /* As last step set additional transform of arena group */ - for (SPItemView *v = item->display; v != NULL; v = v->next) { + for (SPItemView *v = this->display; v != NULL; v = v->next) { Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); - Geom::Affine t(Geom::Translate(use->x.computed, use->y.computed)); + Geom::Affine t(Geom::Translate(this->x.computed, this->y.computed)); g->setChildTransform(t); } } -static void -sp_use_modified(SPObject *object, guint flags) -{ - SPUse *use_obj = SP_USE(object); - +void SPUse::modified(unsigned int flags) { if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } + flags &= SP_OBJECT_MODIFIED_CASCADE; if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { - for (SPItemView *v = SP_ITEM(object)->display; v != NULL; v = v->next) { + for (SPItemView *v = SP_ITEM(this)->display; v != NULL; v = v->next) { Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); - g->setStyle(object->style); + g->setStyle(this->style); } } - SPObject *child = use_obj->child; + SPObject *child = this->child; + if (child) { - g_object_ref(G_OBJECT(child)); + sp_object_ref(child); + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->emitModified(flags); } - g_object_unref(G_OBJECT(child)); + + sp_object_unref(child); } } @@ -655,6 +605,7 @@ SPItem *sp_use_unlink(SPUse *use) // Track the ultimate source of a chain of uses. SPItem *orig = sp_use_root(use); + if (!orig) { return NULL; } @@ -663,8 +614,10 @@ SPItem *sp_use_unlink(SPUse *use) Geom::Affine t = sp_use_get_root_transform(use); Inkscape::XML::Node *copy = NULL; + if (SP_IS_SYMBOL(orig)) { // make a group, copy children copy = xml_doc->createElement("svg:g"); + for (Inkscape::XML::Node *child = orig->getRepr()->firstChild() ; child != NULL; child = child->next()) { Inkscape::XML::Node *newchild = child->duplicate(xml_doc); copy->appendChild(newchild); @@ -717,36 +670,31 @@ SPItem *sp_use_unlink(SPUse *use) // Advertise ourselves as not moving. item->doWriteTransform(item->getRepr(), t, &nomove); } + return item; } SPItem *sp_use_get_original(SPUse *use) { SPItem *ref = NULL; - if (use){ + + if (use) { if (use->ref){ ref = use->ref->getObject(); } } + return ref; } -static void -sp_use_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) -{ - g_assert (item != NULL); - g_assert (SP_IS_ITEM(item)); - g_assert (SP_IS_USE(item)); +void SPUse::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) { + SPItem *root = sp_use_root(this); - SPUse *use = SP_USE(item); - SPItem *root = sp_use_root(use); - if (!root) + if (!root) { return; - - SPItemClass const &item_class = *(SPItemClass const *) G_OBJECT_GET_CLASS(root); - if (item_class.snappoints) { - item_class.snappoints(root, p, snapprefs); } + + root->snappoints(p, snapprefs); } diff --git a/src/sp-use.h b/src/sp-use.h index 3dd0726aa..37ff2cf66 100644 --- a/src/sp-use.h +++ b/src/sp-use.h @@ -18,16 +18,16 @@ #include "svg/svg-length.h" #include "sp-item.h" - -#define SP_TYPE_USE (sp_use_get_type ()) -#define SP_USE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_USE, SPUse)) -#define SP_USE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_USE, SPUseClass)) -#define SP_IS_USE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_USE)) -#define SP_IS_USE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_USE)) +#define SP_USE(obj) (dynamic_cast<SPUse*>((SPObject*)obj)) +#define SP_IS_USE(obj) (dynamic_cast<const SPUse*>((SPObject*)obj) != NULL) class SPUseReference; -struct SPUse : public SPItem { +class SPUse : public SPItem { +public: + SPUse(); + virtual ~SPUse(); + // item built from the original's repr (the visible clone) // relative to the SPUse itself, it is treated as a child, similar to a grouped item relative to its group SPObject *child; @@ -48,13 +48,21 @@ struct SPUse : public SPItem { // a sigc connection for transformed signal, used to do move compensation sigc::connection _transformed_connection; -}; -struct SPUseClass { - SPItemClass parent_class; -}; + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + virtual void set(unsigned key, gchar const *value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); + virtual void update(SPCtx* ctx, unsigned int flags); + virtual void modified(unsigned int flags); -GType sp_use_get_type (void); + virtual Geom::OptRect bbox(Geom::Affine const &transform, SPItem::BBoxType bboxtype); + virtual gchar* description(); + virtual void print(SPPrintContext *ctx); + virtual Inkscape::DrawingItem* show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); + virtual void hide(unsigned int key); + virtual void snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); +}; SPItem *sp_use_unlink (SPUse *use); SPItem *sp_use_get_original (SPUse *use); diff --git a/src/spiral-context.cpp b/src/spiral-context.cpp index a6cdc6bc4..f841fe6d6 100644 --- a/src/spiral-context.cpp +++ b/src/spiral-context.cpp @@ -45,182 +45,138 @@ using Inkscape::DocumentUndo; -static void sp_spiral_context_dispose(GObject *object); -static void sp_spiral_context_setup(SPEventContext *ec); -static void sp_spiral_context_finish(SPEventContext *ec); -static void sp_spiral_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val); +#include "tool-factory.h" -static gint sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event); +namespace { + SPEventContext* createSpiralContext() { + return new SPSpiralContext(); + } -static void sp_spiral_drag(SPSpiralContext *sc, Geom::Point const &p, guint state); -static void sp_spiral_finish(SPSpiralContext *sc); -static void sp_spiral_cancel(SPSpiralContext *sc); - -G_DEFINE_TYPE(SPSpiralContext, sp_spiral_context, SP_TYPE_EVENT_CONTEXT); - -static void -sp_spiral_context_class_init(SPSpiralContextClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - SPEventContextClass *event_context_class = SP_EVENT_CONTEXT_CLASS(klass); - - object_class->dispose = sp_spiral_context_dispose; - - event_context_class->setup = sp_spiral_context_setup; - event_context_class->finish = sp_spiral_context_finish; - event_context_class->set = sp_spiral_context_set; - event_context_class->root_handler = sp_spiral_context_root_handler; + bool spiralContextRegistered = ToolFactory::instance().registerObject("/tools/shapes/spiral", createSpiralContext); } -static void -sp_spiral_context_init(SPSpiralContext *spiral_context) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(spiral_context); +const std::string& SPSpiralContext::getPrefsPath() { + return SPSpiralContext::prefsPath; +} - event_context->cursor_shape = cursor_spiral_xpm; - event_context->hot_x = 4; - event_context->hot_y = 4; - event_context->xp = 0; - event_context->yp = 0; - event_context->tolerance = 0; - event_context->within_tolerance = false; - event_context->item_to_select = NULL; +const std::string SPSpiralContext::prefsPath = "/tools/shapes/spiral"; - spiral_context->item = NULL; +SPSpiralContext::SPSpiralContext() : SPEventContext() { + this->cursor_shape = cursor_spiral_xpm; + this->hot_x = 4; + this->hot_y = 4; + this->xp = 0; + this->yp = 0; + this->tolerance = 0; + this->within_tolerance = false; + this->item_to_select = NULL; - spiral_context->revo = 3.0; - spiral_context->exp = 1.0; - spiral_context->t0 = 0.0; + this->spiral = NULL; - new (&spiral_context->sel_changed_connection) sigc::connection(); + this->revo = 3.0; + this->exp = 1.0; + this->t0 = 0.0; } -static void sp_spiral_context_finish(SPEventContext *ec) -{ - SPSpiralContext *sc = SP_SPIRAL_CONTEXT(ec); - SPDesktop *desktop = ec->desktop; +void SPSpiralContext::finish() { + SPDesktop *desktop = this->desktop; sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), GDK_CURRENT_TIME); - sp_spiral_finish(sc); - sc->sel_changed_connection.disconnect(); - if ((SP_EVENT_CONTEXT_CLASS(sp_spiral_context_parent_class))->finish) { - (SP_EVENT_CONTEXT_CLASS(sp_spiral_context_parent_class))->finish(ec); - } -} + this->finishItem(); + this->sel_changed_connection.disconnect(); -static void -sp_spiral_context_dispose(GObject *object) -{ - SPSpiralContext *sc = SP_SPIRAL_CONTEXT(object); - SPEventContext *ec = SP_EVENT_CONTEXT(object); + SPEventContext::finish(); +} - ec->enableGrDrag(false); +SPSpiralContext::~SPSpiralContext() { + this->enableGrDrag(false); - sc->sel_changed_connection.disconnect(); - sc->sel_changed_connection.~connection(); + this->sel_changed_connection.disconnect(); - delete ec->shape_editor; - ec->shape_editor = NULL; + delete this->shape_editor; + this->shape_editor = NULL; /* fixme: This is necessary because we do not grab */ - if (sc->item) sp_spiral_finish(sc); - - if (sc->_message_context) { - delete sc->_message_context; + if (this->spiral) { + this->finishItem(); } - - G_OBJECT_CLASS(sp_spiral_context_parent_class)->dispose(object); } /** * Callback that processes the "changed" signal on the selection; * destroys old and creates new knotholder. */ -static void sp_spiral_context_selection_changed(Inkscape::Selection *selection, gpointer data) -{ - SPSpiralContext *sc = SP_SPIRAL_CONTEXT(data); - SPEventContext *ec = SP_EVENT_CONTEXT(sc); - - ec->shape_editor->unset_item(SH_KNOTHOLDER); - SPItem *item = selection->singleItem(); - ec->shape_editor->set_item(item, SH_KNOTHOLDER); +void SPSpiralContext::selection_changed(Inkscape::Selection *selection) { + this->shape_editor->unset_item(SH_KNOTHOLDER); + this->shape_editor->set_item(selection->singleItem(), SH_KNOTHOLDER); } -static void -sp_spiral_context_setup(SPEventContext *ec) -{ - SPSpiralContext *sc = SP_SPIRAL_CONTEXT(ec); - - if ((SP_EVENT_CONTEXT_CLASS(sp_spiral_context_parent_class))->setup) - (SP_EVENT_CONTEXT_CLASS(sp_spiral_context_parent_class))->setup(ec); +void SPSpiralContext::setup() { + SPEventContext::setup(); - sp_event_context_read(ec, "expansion"); - sp_event_context_read(ec, "revolution"); - sp_event_context_read(ec, "t0"); + sp_event_context_read(this, "expansion"); + sp_event_context_read(this, "revolution"); + sp_event_context_read(this, "t0"); - ec->shape_editor = new ShapeEditor(ec->desktop); + this->shape_editor = new ShapeEditor(this->desktop); - SPItem *item = sp_desktop_selection(ec->desktop)->singleItem(); + SPItem *item = sp_desktop_selection(this->desktop)->singleItem(); if (item) { - ec->shape_editor->set_item(item, SH_KNOTHOLDER); + this->shape_editor->set_item(item, SH_KNOTHOLDER); } - Inkscape::Selection *selection = sp_desktop_selection(ec->desktop); - sc->sel_changed_connection.disconnect(); - sc->sel_changed_connection = selection->connectChanged(sigc::bind(sigc::ptr_fun(&sp_spiral_context_selection_changed), (gpointer)sc)); + Inkscape::Selection *selection = sp_desktop_selection(this->desktop); + this->sel_changed_connection.disconnect(); + + this->sel_changed_connection = selection->connectChanged(sigc::mem_fun(this, &SPSpiralContext::selection_changed)); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/tools/shapes/selcue")) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } + if (prefs->getBool("/tools/shapes/gradientdrag")) { - ec->enableGrDrag(); + this->enableGrDrag(); } - - sc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack()); } -static void -sp_spiral_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val) -{ - SPSpiralContext *sc = SP_SPIRAL_CONTEXT(ec); - Glib::ustring name = val->getEntryName(); +void SPSpiralContext::set(const Inkscape::Preferences::Entry& val) { + Glib::ustring name = val.getEntryName(); if (name == "expansion") { - sc->exp = CLAMP(val->getDouble(), 0.0, 1000.0); + this->exp = CLAMP(val.getDouble(), 0.0, 1000.0); } else if (name == "revolution") { - sc->revo = CLAMP(val->getDouble(3.0), 0.05, 40.0); + this->revo = CLAMP(val.getDouble(3.0), 0.05, 40.0); } else if (name == "t0") { - sc->t0 = CLAMP(val->getDouble(), 0.0, 0.999); + this->t0 = CLAMP(val.getDouble(), 0.0, 0.999); } } -static gint -sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event) -{ +bool SPSpiralContext::root_handler(GdkEvent* event) { static gboolean dragging; - SPDesktop *desktop = event_context->desktop; + SPDesktop *desktop = this->desktop; Inkscape::Selection *selection = sp_desktop_selection (desktop); - SPSpiralContext *sc = SP_SPIRAL_CONTEXT(event_context); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - event_context->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); + this->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); gint ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { - + if (event->button.button == 1 && !this->space_panning) { dragging = TRUE; - sc->center = Inkscape::setup_for_drag_start(desktop, event_context, event); + + this->center = Inkscape::setup_for_drag_start(desktop, this, event); SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); - m.freeSnapReturnByRef(sc->center, Inkscape::SNAPSOURCE_NODE_HANDLE); + m.freeSnapReturnByRef(this->center, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), ( GDK_KEY_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | @@ -231,32 +187,33 @@ sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event) ret = TRUE; } break; - case GDK_MOTION_NOTIFY: - if (dragging && (event->motion.state & GDK_BUTTON1_MASK) && !event_context->space_panning) { - if ( event_context->within_tolerance - && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance ) - && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) { + case GDK_MOTION_NOTIFY: + if (dragging && (event->motion.state & GDK_BUTTON1_MASK) && !this->space_panning) { + if ( this->within_tolerance + && ( abs( (gint) event->motion.x - this->xp ) < this->tolerance ) + && ( abs( (gint) event->motion.y - this->yp ) < this->tolerance ) ) { break; // do not drag if we're within tolerance from origin } // Once the user has moved farther than tolerance from the original location // (indicating they intend to draw, not click), then always process the // motion notify coordinates as given (no snapping back to origin) - event_context->within_tolerance = false; + this->within_tolerance = false; Geom::Point const motion_w(event->motion.x, event->motion.y); - Geom::Point motion_dt(event_context->desktop->w2d(motion_w)); + Geom::Point motion_dt(this->desktop->w2d(motion_w)); SnapManager &m = desktop->namedview->snap_manager; - m.setup(desktop, true, sc->item); + m.setup(desktop, true, this->spiral); m.freeSnapReturnByRef(motion_dt, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); - sp_spiral_drag(sc, motion_dt, event->motion.state); + + this->drag(motion_dt, event->motion.state); gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; - } else if (!sp_event_context_knot_mouseover(sc)) { + } else if (!sp_event_context_knot_mouseover(this)) { SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); Geom::Point const motion_w(event->motion.x, event->motion.y); @@ -265,31 +222,34 @@ sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event) m.unSetup(); } break; + case GDK_BUTTON_RELEASE: - event_context->xp = event_context->yp = 0; - if (event->button.button == 1 && !event_context->space_panning) { + this->xp = this->yp = 0; + if (event->button.button == 1 && !this->space_panning) { dragging = FALSE; - sp_event_context_discard_delayed_snap_event(event_context); - if (!event_context->within_tolerance) { + sp_event_context_discard_delayed_snap_event(this); + + if (!this->within_tolerance) { // we've been dragging, finish the spiral - sp_spiral_finish(sc); - } else if (event_context->item_to_select) { + this->finishItem(); + } else if (this->item_to_select) { // no dragging, select clicked item if any if (event->button.state & GDK_SHIFT_MASK) { - selection->toggle(event_context->item_to_select); + selection->toggle(this->item_to_select); } else { - selection->set(event_context->item_to_select); + selection->set(this->item_to_select); } } else { // click in an empty space selection->clear(); } - event_context->item_to_select = NULL; + this->item_to_select = NULL; ret = TRUE; sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); } break; + case GDK_KEY_PRESS: switch (get_group0_keyval(&event->key)) { case GDK_KEY_Alt_R: @@ -299,7 +259,7 @@ sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_Shift_R: case GDK_KEY_Meta_L: // Meta is when you press Shift+Alt (at least on my machine) case GDK_KEY_Meta_R: - sp_event_show_modifier_tip(event_context->defaultMessageContext(), event, + sp_event_show_modifier_tip(this->defaultMessageContext(), event, _("<b>Ctrl</b>: snap angle"), NULL, _("<b>Alt</b>: lock spiral radius")); @@ -312,6 +272,7 @@ sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event) if (!MOD__CTRL_ONLY(event)) ret = TRUE; break; + case GDK_KEY_x: case GDK_KEY_X: if (MOD__ALT_ONLY(event)) { @@ -319,12 +280,13 @@ sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event) ret = TRUE; } break; + case GDK_KEY_Escape: if (dragging) { dragging = false; - sp_event_context_discard_delayed_snap_event(event_context); + sp_event_context_discard_delayed_snap_event(this); // if drawing, cancel, otherwise pass it up for deselecting - sp_spiral_cancel(sc); + this->cancel(); ret = TRUE; } break; @@ -334,24 +296,27 @@ sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event) sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); dragging = false; - sp_event_context_discard_delayed_snap_event(event_context); - if (!event_context->within_tolerance) { + sp_event_context_discard_delayed_snap_event(this); + + if (!this->within_tolerance) { // we've been dragging, finish the spiral - sp_spiral_finish(sc); + this->finish(); } // do not return true, so that space would work switching to selector } break; + case GDK_KEY_Delete: case GDK_KEY_KP_Delete: case GDK_KEY_BackSpace: - ret = event_context->deleteSelectedDrag(MOD__CTRL_ONLY(event)); + ret = this->deleteSelectedDrag(MOD__CTRL_ONLY(event)); break; default: break; } break; + case GDK_KEY_RELEASE: switch (get_group0_keyval(&event->key)) { case GDK_KEY_Alt_L: @@ -362,135 +327,123 @@ sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event) case GDK_KEY_Shift_R: case GDK_KEY_Meta_L: // Meta is when you press Shift+Alt case GDK_KEY_Meta_R: - event_context->defaultMessageContext()->clear(); + this->defaultMessageContext()->clear(); break; + default: break; } break; + default: break; } if (!ret) { - if ((SP_EVENT_CONTEXT_CLASS(sp_spiral_context_parent_class))->root_handler) - ret = (SP_EVENT_CONTEXT_CLASS(sp_spiral_context_parent_class))->root_handler(event_context, event); + ret = SPEventContext::root_handler(event); } return ret; } -static void sp_spiral_drag(SPSpiralContext *sc, Geom::Point const &p, guint state) -{ - SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; +void SPSpiralContext::drag(Geom::Point const &p, guint state) { + SPDesktop *desktop = SP_EVENT_CONTEXT(this)->desktop; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int const snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12); - if (!sc->item) { - - if (Inkscape::have_viable_layer(desktop, sc->_message_context) == false) { + if (!this->spiral) { + if (Inkscape::have_viable_layer(desktop, this->message_context) == false) { return; } // Create object - Inkscape::XML::Document *xml_doc = SP_EVENT_CONTEXT_DOCUMENT(sc)->getReprDoc(); + Inkscape::XML::Document *xml_doc = SP_EVENT_CONTEXT_DOCUMENT(this)->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); repr->setAttribute("sodipodi:type", "spiral"); // Set style sp_desktop_apply_style_tool(desktop, repr, "/tools/shapes/spiral", false); - sc->item = SP_ITEM(desktop->currentLayer()->appendChildRepr(repr)); + this->spiral = SP_SPIRAL(desktop->currentLayer()->appendChildRepr(repr)); Inkscape::GC::release(repr); - sc->item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); - sc->item->updateRepr(); + this->spiral->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); + this->spiral->updateRepr(); desktop->canvas->forceFullRedrawAfterInterruptions(5); } SnapManager &m = desktop->namedview->snap_manager; - m.setup(desktop, true, sc->item); + m.setup(desktop, true, this->spiral); Geom::Point pt2g = p; m.freeSnapReturnByRef(pt2g, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); - Geom::Point const p0 = desktop->dt2doc(sc->center); + Geom::Point const p0 = desktop->dt2doc(this->center); Geom::Point const p1 = desktop->dt2doc(pt2g); - SPSpiral *spiral = SP_SPIRAL(sc->item); - Geom::Point const delta = p1 - p0; gdouble const rad = Geom::L2(delta); - gdouble arg = Geom::atan2(delta) - 2.0*M_PI*spiral->revo; + gdouble arg = Geom::atan2(delta) - 2.0*M_PI*this->spiral->revo; if (state & GDK_CONTROL_MASK) { arg = sp_round(arg, M_PI/snaps); } /* Fixme: these parameters should be got from dialog box */ - sp_spiral_position_set(spiral, p0[Geom::X], p0[Geom::Y], - /*expansion*/ sc->exp, - /*revolution*/ sc->revo, + this->spiral->setPosition(p0[Geom::X], p0[Geom::Y], + /*expansion*/ this->exp, + /*revolution*/ this->revo, rad, arg, - /*t0*/ sc->t0); + /*t0*/ this->t0); /* status text */ Inkscape::Util::Quantity q = Inkscape::Util::Quantity(rad, "px"); GString *rads = g_string_new(q.string(*desktop->namedview->doc_units).c_str()); - sc->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, + this->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Spiral</b>: radius %s, angle %5g°; with <b>Ctrl</b> to snap angle"), - rads->str, sp_round((arg + 2.0*M_PI*spiral->revo)*180/M_PI, 0.0001)); + rads->str, sp_round((arg + 2.0*M_PI*this->spiral->revo)*180/M_PI, 0.0001)); g_string_free(rads, FALSE); } -static void -sp_spiral_finish(SPSpiralContext *sc) -{ - sc->_message_context->clear(); +void SPSpiralContext::finishItem() { + this->message_context->clear(); - if (sc->item != NULL) { - SPSpiral *spiral = SP_SPIRAL(sc->item); - if (spiral->rad == 0) { - sp_spiral_cancel(sc); // Don't allow the creating of zero sized spiral, for example when the start and and point snap to the snap grid point + if (this->spiral != NULL) { + if (this->spiral->rad == 0) { + this->cancel(); // Don't allow the creating of zero sized spiral, for example when the start and and point snap to the snap grid point return; } - SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; + spiral->set_shape(); + spiral->updateRepr(SP_OBJECT_WRITE_EXT); - SP_SHAPE(spiral)->setShape(); - SP_OBJECT(spiral)->updateRepr(SP_OBJECT_WRITE_EXT); + this->desktop->canvas->endForcedFullRedraws(); - desktop->canvas->endForcedFullRedraws(); + sp_desktop_selection(this->desktop)->set(this->spiral); + DocumentUndo::done(sp_desktop_document(this->desktop), SP_VERB_CONTEXT_SPIRAL, _("Create spiral")); - sp_desktop_selection(desktop)->set(sc->item); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL, - _("Create spiral")); - - sc->item = NULL; + this->spiral = NULL; } } -static void sp_spiral_cancel(SPSpiralContext *sc) -{ - SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; - - sp_desktop_selection(desktop)->clear(); - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0); +void SPSpiralContext::cancel() { + sp_desktop_selection(this->desktop)->clear(); + sp_canvas_item_ungrab(SP_CANVAS_ITEM(this->desktop->acetate), 0); - if (sc->item != NULL) { - SP_OBJECT(sc->item)->deleteObject(); - sc->item = NULL; + if (this->spiral != NULL) { + this->spiral->deleteObject(); + this->spiral = NULL; } - sc->within_tolerance = false; - sc->xp = 0; - sc->yp = 0; - sc->item_to_select = NULL; + this->within_tolerance = false; + this->xp = 0; + this->yp = 0; + this->item_to_select = NULL; - desktop->canvas->endForcedFullRedraws(); + this->desktop->canvas->endForcedFullRedraws(); - DocumentUndo::cancel(sp_desktop_document(desktop)); + DocumentUndo::cancel(sp_desktop_document(this->desktop)); } /* diff --git a/src/spiral-context.h b/src/spiral-context.h index 7f696dfa2..d5bd15941 100644 --- a/src/spiral-context.h +++ b/src/spiral-context.h @@ -21,14 +21,27 @@ #include <2geom/point.h> #include "event-context.h" -#define SP_TYPE_SPIRAL_CONTEXT (sp_spiral_context_get_type ()) -#define SP_SPIRAL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_SPIRAL_CONTEXT, SPSpiralContext)) -#define SP_SPIRAL_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_SPIRAL_CONTEXT, SPSpiralContextClass)) -#define SP_IS_SPIRAL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_SPIRAL_CONTEXT)) -#define SP_IS_SPIRAL_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_SPIRAL_CONTEXT)) - -struct SPSpiralContext : public SPEventContext { - SPItem * item; +#include "sp-spiral.h" + +#define SP_SPIRAL_CONTEXT(obj) (dynamic_cast<SPSpiralContext*>((SPEventContext*)obj)) +#define SP_IS_SPIRAL_CONTEXT(obj) (dynamic_cast<const SPSpiralContext*>((const SPEventContext*)obj) != NULL) + +class SPSpiralContext : public SPEventContext { +public: + SPSpiralContext(); + virtual ~SPSpiralContext(); + + static const std::string prefsPath; + + virtual void setup(); + virtual void finish(); + virtual void set(const Inkscape::Preferences::Entry& val); + virtual bool root_handler(GdkEvent* event); + + virtual const std::string& getPrefsPath(); + +private: + SPSpiral * spiral; Geom::Point center; gdouble revo; gdouble exp; @@ -36,15 +49,10 @@ struct SPSpiralContext : public SPEventContext { sigc::connection sel_changed_connection; - Inkscape::MessageContext *_message_context; -}; - -struct SPSpiralContextClass { - SPEventContextClass parent_class; + void drag(Geom::Point const &p, guint state); + void finishItem(); + void cancel(); + void selection_changed(Inkscape::Selection *selection); }; -/* Standard Gtk function */ - -GType sp_spiral_context_get_type (void); - #endif diff --git a/src/spray-context.cpp b/src/spray-context.cpp index 7690d0373..51fdab6ff 100644 --- a/src/spray-context.cpp +++ b/src/spray-context.cpp @@ -78,13 +78,21 @@ using namespace std; #define DDC_RED_RGBA 0xff0000ff #define DYNA_MIN_WIDTH 1.0e-6 -static void sp_spray_context_dispose(GObject *object); +#include "tool-factory.h" -static void sp_spray_context_setup(SPEventContext *ec); -static void sp_spray_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val); -static gint sp_spray_context_root_handler(SPEventContext *ec, GdkEvent *event); +namespace { + SPEventContext* createSprayContext() { + return new SPSprayContext(); + } -G_DEFINE_TYPE(SPSprayContext, sp_spray_context, SP_TYPE_EVENT_CONTEXT); + bool sprayContextRegistered = ToolFactory::instance().registerObject("/tools/spray", createSprayContext); +} + +const std::string& SPSprayContext::getPrefsPath() { + return SPSprayContext::prefsPath; +} + +const std::string SPSprayContext::prefsPath = "/tools/spray"; /** * This function returns pseudo-random numbers from a normal distribution @@ -97,18 +105,6 @@ inline double NormalDistribution(double mu, double sigma) return mu + sigma * sqrt( -2.0 * log(g_random_double_range(0, 1)) ) * cos( 2.0*M_PI*g_random_double_range(0, 1) ); } -static void sp_spray_context_class_init(SPSprayContextClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - SPEventContextClass *event_context_class = SP_EVENT_CONTEXT_CLASS(klass); - - object_class->dispose = sp_spray_context_dispose; - - event_context_class->setup = sp_spray_context_setup; - event_context_class->set = sp_spray_context_set; - event_context_class->root_handler = sp_spray_context_root_handler; -} - /* Method to rotate items */ static void sp_spray_rotate_rel(Geom::Point c, SPDesktop */*desktop*/, SPItem *item, Geom::Rotate const &rotation) { @@ -133,54 +129,45 @@ static void sp_spray_scale_rel(Geom::Point c, SPDesktop */*desktop*/, SPItem *it item->doWriteTransform(item->getRepr(), item->transform); } -static void sp_spray_context_init(SPSprayContext *tc) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(tc); +SPSprayContext::SPSprayContext() : SPEventContext() { + this->usetilt = 0; + this->dilate_area = 0; + this->usetext = false; + this->population = 0; + this->is_drawing = false; + this->mode = 0; + this->usepressure = 0; - event_context->cursor_shape = cursor_spray_xpm; - event_context->hot_x = 4; - event_context->hot_y = 4; + this->cursor_shape = cursor_spray_xpm; + this->hot_x = 4; + this->hot_y = 4; /* attributes */ - tc->dragging = FALSE; - tc->distrib = 1; - tc->width = 0.2; - tc->force = 0.2; - tc->ratio = 0; - tc->tilt = 0; - tc->mean = 0.2; - tc->rotation_variation = 0; - tc->standard_deviation = 0.2; - tc->scale = 1; - tc->scale_variation = 1; - tc->pressure = TC_DEFAULT_PRESSURE; - - tc->is_dilating = false; - tc->has_dilated = false; - - new (&tc->style_set_connection) sigc::connection(); + this->dragging = FALSE; + this->distrib = 1; + this->width = 0.2; + this->force = 0.2; + this->ratio = 0; + this->tilt = 0; + this->mean = 0.2; + this->rotation_variation = 0; + this->standard_deviation = 0.2; + this->scale = 1; + this->scale_variation = 1; + this->pressure = TC_DEFAULT_PRESSURE; + + this->is_dilating = false; + this->has_dilated = false; } -static void sp_spray_context_dispose(GObject *object) -{ - SPSprayContext *tc = SP_SPRAY_CONTEXT(object); - SPEventContext *ec = SP_EVENT_CONTEXT(object); - - ec->enableGrDrag(false); - - tc->style_set_connection.disconnect(); - tc->style_set_connection.~connection(); - - if (tc->dilate_area) { - sp_canvas_item_destroy(tc->dilate_area); - tc->dilate_area = NULL; - } +SPSprayContext::~SPSprayContext() { + this->enableGrDrag(false); + this->style_set_connection.disconnect(); - if (tc->_message_context) { - delete tc->_message_context; + if (this->dilate_area) { + sp_canvas_item_destroy(this->dilate_area); + this->dilate_area = NULL; } - - G_OBJECT_CLASS(sp_spray_context_parent_class)->dispose(object); } static bool is_transform_modes(gint mode) @@ -191,13 +178,10 @@ static bool is_transform_modes(gint mode) mode == SPRAY_OPTION); } -static void sp_spray_update_cursor(SPSprayContext *tc, bool /*with_shift*/) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(tc); - SPDesktop *desktop = event_context->desktop; - +void SPSprayContext::update_cursor(bool /*with_shift*/) { guint num = 0; gchar *sel_message = NULL; + if (!desktop->selection->isEmpty()) { num = g_slist_length(const_cast<GSList *>(desktop->selection->itemList())); sel_message = g_strdup_printf(ngettext("<b>%i</b> object selected","<b>%i</b> objects selected",num), num); @@ -205,31 +189,26 @@ static void sp_spray_update_cursor(SPSprayContext *tc, bool /*with_shift*/) sel_message = g_strdup_printf(_("<b>Nothing</b> selected")); } - - switch (tc->mode) { - case SPRAY_MODE_COPY: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or click and scroll to spray <b>copies</b> of the initial selection."), sel_message); - break; - case SPRAY_MODE_CLONE: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or click and scroll to spray <b>clones</b> of the initial selection."), sel_message); - break; - case SPRAY_MODE_SINGLE_PATH: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or click and scroll to spray in a <b>single path</b> of the initial selection."), sel_message); - break; - default: - break; - } - sp_event_context_update_cursor(event_context); - g_free(sel_message); + switch (this->mode) { + case SPRAY_MODE_COPY: + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or click and scroll to spray <b>copies</b> of the initial selection."), sel_message); + break; + case SPRAY_MODE_CLONE: + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or click and scroll to spray <b>clones</b> of the initial selection."), sel_message); + break; + case SPRAY_MODE_SINGLE_PATH: + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or click and scroll to spray in a <b>single path</b> of the initial selection."), sel_message); + break; + default: + break; + } + + this->sp_event_context_update_cursor(); + g_free(sel_message); } -static void sp_spray_context_setup(SPEventContext *ec) -{ - SPSprayContext *tc = SP_SPRAY_CONTEXT(ec); - - if ((SP_EVENT_CONTEXT_CLASS(sp_spray_context_parent_class))->setup) { - (SP_EVENT_CONTEXT_CLASS(sp_spray_context_parent_class))->setup(ec); - } +void SPSprayContext::setup() { + SPEventContext::setup(); { /* TODO: have a look at sp_dyna_draw_context_setup where the same is done.. generalize? at least make it an arcto! */ @@ -241,71 +220,67 @@ static void sp_spray_context_setup(SPEventContext *ec) c->curveto(1, -C1, C1, -1, 0, -1 ); c->curveto(-C1, -1, -1, -C1, -1, 0 ); c->closepath(); - tc->dilate_area = sp_canvas_bpath_new(sp_desktop_controls(ec->desktop), c); + this->dilate_area = sp_canvas_bpath_new(sp_desktop_controls(this->desktop), c); c->unref(); - sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(tc->dilate_area), 0x00000000,(SPWindRule)0); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(tc->dilate_area), 0xff9900ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - sp_canvas_item_hide(tc->dilate_area); + sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(this->dilate_area), 0x00000000,(SPWindRule)0); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->dilate_area), 0xff9900ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); + sp_canvas_item_hide(this->dilate_area); } - tc->is_drawing = false; - - tc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack()); - - sp_event_context_read(ec, "distrib"); - sp_event_context_read(ec, "width"); - sp_event_context_read(ec, "ratio"); - sp_event_context_read(ec, "tilt"); - sp_event_context_read(ec, "rotation_variation"); - sp_event_context_read(ec, "scale_variation"); - sp_event_context_read(ec, "mode"); - sp_event_context_read(ec, "population"); - sp_event_context_read(ec, "force"); - sp_event_context_read(ec, "mean"); - sp_event_context_read(ec, "standard_deviation"); - sp_event_context_read(ec, "usepressure"); - sp_event_context_read(ec, "Scale"); + this->is_drawing = false; + + sp_event_context_read(this, "distrib"); + sp_event_context_read(this, "width"); + sp_event_context_read(this, "ratio"); + sp_event_context_read(this, "tilt"); + sp_event_context_read(this, "rotation_variation"); + sp_event_context_read(this, "scale_variation"); + sp_event_context_read(this, "mode"); + sp_event_context_read(this, "population"); + sp_event_context_read(this, "force"); + sp_event_context_read(this, "mean"); + sp_event_context_read(this, "standard_deviation"); + sp_event_context_read(this, "usepressure"); + sp_event_context_read(this, "Scale"); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/tools/spray/selcue")) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } if (prefs->getBool("/tools/spray/gradientdrag")) { - ec->enableGrDrag(); + this->enableGrDrag(); } } -static void sp_spray_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val) -{ - SPSprayContext *tc = SP_SPRAY_CONTEXT(ec); - Glib::ustring path = val->getEntryName(); +void SPSprayContext::set(const Inkscape::Preferences::Entry& val) { + Glib::ustring path = val.getEntryName(); if (path == "mode") { - tc->mode = val->getInt(); - sp_spray_update_cursor(tc, false); + this->mode = val.getInt(); + this->update_cursor(false); } else if (path == "width") { - tc->width = 0.01 * CLAMP(val->getInt(10), 1, 100); + this->width = 0.01 * CLAMP(val.getInt(10), 1, 100); } else if (path == "usepressure") { - tc->usepressure = val->getBool(); + this->usepressure = val.getBool(); } else if (path == "population") { - tc->population = 0.01 * CLAMP(val->getInt(10), 1, 100); + this->population = 0.01 * CLAMP(val.getInt(10), 1, 100); } else if (path == "rotation_variation") { - tc->rotation_variation = CLAMP(val->getDouble(0.0), 0, 100.0); + this->rotation_variation = CLAMP(val.getDouble(0.0), 0, 100.0); } else if (path == "scale_variation") { - tc->scale_variation = CLAMP(val->getDouble(1.0), 0, 100.0); + this->scale_variation = CLAMP(val.getDouble(1.0), 0, 100.0); } else if (path == "standard_deviation") { - tc->standard_deviation = 0.01 * CLAMP(val->getInt(10), 1, 100); + this->standard_deviation = 0.01 * CLAMP(val.getInt(10), 1, 100); } else if (path == "mean") { - tc->mean = 0.01 * CLAMP(val->getInt(10), 1, 100); + this->mean = 0.01 * CLAMP(val.getInt(10), 1, 100); // Not implemented in the toolbar and preferences yet } else if (path == "distribution") { - tc->distrib = val->getInt(1); + this->distrib = val.getInt(1); } else if (path == "tilt") { - tc->tilt = CLAMP(val->getDouble(0.1), 0, 1000.0); + this->tilt = CLAMP(val.getDouble(0.1), 0, 1000.0); } else if (path == "ratio") { - tc->ratio = CLAMP(val->getDouble(), 0.0, 0.9); + this->ratio = CLAMP(val.getDouble(), 0.0, 0.9); } else if (path == "force") { - tc->force = CLAMP(val->getDouble(1.0), 0, 1.0); + this->force = CLAMP(val.getDouble(1.0), 0, 1.0); } } @@ -607,45 +582,41 @@ static void sp_spray_switch_mode(SPSprayContext *tc, gint mode, bool with_shift) SP_EVENT_CONTEXT(tc)->desktop->setToolboxSelectOneValue("spray_tool_mode", mode); // need to set explicitly, because the prefs may not have changed by the previous tc->mode = mode; - sp_spray_update_cursor(tc, with_shift); + tc->update_cursor(with_shift); } -gint sp_spray_context_root_handler(SPEventContext *event_context, GdkEvent *event) -{ - SPSprayContext *tc = SP_SPRAY_CONTEXT(event_context); - SPDesktop *desktop = event_context->desktop; - +bool SPSprayContext::root_handler(GdkEvent* event) { gint ret = FALSE; switch (event->type) { case GDK_ENTER_NOTIFY: - sp_canvas_item_show(tc->dilate_area); + sp_canvas_item_show(this->dilate_area); break; case GDK_LEAVE_NOTIFY: - sp_canvas_item_hide(tc->dilate_area); + sp_canvas_item_hide(this->dilate_area); break; case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { - if (Inkscape::have_viable_layer(desktop, tc->_message_context) == false) { + if (event->button.button == 1 && !this->space_panning) { + if (Inkscape::have_viable_layer(desktop, this->message_context) == false) { return TRUE; } Geom::Point const motion_w(event->button.x, event->button.y); Geom::Point const motion_dt(desktop->w2d(motion_w)); - tc->last_push = desktop->dt2doc(motion_dt); + this->last_push = desktop->dt2doc(motion_dt); - sp_spray_extinput(tc, event); + sp_spray_extinput(this, event); desktop->canvas->forceFullRedrawAfterInterruptions(3); - tc->is_drawing = true; - tc->is_dilating = true; - tc->has_dilated = false; + this->is_drawing = true; + this->is_dilating = true; + this->has_dilated = false; - if(tc->is_dilating && event->button.button == 1 && !event_context->space_panning) { - sp_spray_dilate(tc, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT(event)); + if(this->is_dilating && event->button.button == 1 && !this->space_panning) { + sp_spray_dilate(this, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT(event)); } - tc->has_dilated = true; + this->has_dilated = true; ret = TRUE; } break; @@ -654,27 +625,27 @@ gint sp_spray_context_root_handler(SPEventContext *event_context, GdkEvent *even event->motion.y); Geom::Point motion_dt(desktop->w2d(motion_w)); Geom::Point motion_doc(desktop->dt2doc(motion_dt)); - sp_spray_extinput(tc, event); + sp_spray_extinput(this, event); // draw the dilating cursor - double radius = get_dilate_radius(tc); - Geom::Affine const sm (Geom::Scale(radius/(1-tc->ratio), radius/(1+tc->ratio)) ); - sp_canvas_item_affine_absolute(tc->dilate_area, (sm*Geom::Rotate(tc->tilt))*Geom::Translate(desktop->w2d(motion_w))); - sp_canvas_item_show(tc->dilate_area); + double radius = get_dilate_radius(this); + Geom::Affine const sm (Geom::Scale(radius/(1-this->ratio), radius/(1+this->ratio)) ); + sp_canvas_item_affine_absolute(this->dilate_area, (sm*Geom::Rotate(this->tilt))*Geom::Translate(desktop->w2d(motion_w))); + sp_canvas_item_show(this->dilate_area); guint num = 0; if (!desktop->selection->isEmpty()) { num = g_slist_length(const_cast<GSList *>(desktop->selection->itemList())); } if (num == 0) { - tc->_message_context->flash(Inkscape::ERROR_MESSAGE, _("<b>Nothing selected!</b> Select objects to spray.")); + this->message_context->flash(Inkscape::ERROR_MESSAGE, _("<b>Nothing selected!</b> Select objects to spray.")); } // dilating: - if (tc->is_drawing && ( event->motion.state & GDK_BUTTON1_MASK )) { - sp_spray_dilate(tc, motion_w, motion_doc, motion_doc - tc->last_push, event->button.state & GDK_SHIFT_MASK? true : false); - //tc->last_push = motion_doc; - tc->has_dilated = true; + if (this->is_drawing && ( event->motion.state & GDK_BUTTON1_MASK )) { + sp_spray_dilate(this, motion_w, motion_doc, motion_doc - this->last_push, event->button.state & GDK_SHIFT_MASK? true : false); + //this->last_push = motion_doc; + this->has_dilated = true; // it's slow, so prevent clogging up with events gobble_motion_events(GDK_BUTTON1_MASK); @@ -686,31 +657,31 @@ gint sp_spray_context_root_handler(SPEventContext *event_context, GdkEvent *even case GDK_SCROLL: { if (event->scroll.state & GDK_BUTTON1_MASK) { double temp ; - temp = tc->population; - tc->population = 1.0; - desktop->setToolboxAdjustmentValue("population", tc->population * 100); + temp = this->population; + this->population = 1.0; + desktop->setToolboxAdjustmentValue("population", this->population * 100); Geom::Point const scroll_w(event->button.x, event->button.y); Geom::Point const scroll_dt = desktop->point();; Geom::Point motion_doc(desktop->dt2doc(scroll_dt)); switch (event->scroll.direction) { case GDK_SCROLL_DOWN: case GDK_SCROLL_UP: { - if (Inkscape::have_viable_layer(desktop, tc->_message_context) == false) { + if (Inkscape::have_viable_layer(desktop, this->message_context) == false) { return TRUE; } - tc->last_push = desktop->dt2doc(scroll_dt); - sp_spray_extinput(tc, event); + this->last_push = desktop->dt2doc(scroll_dt); + sp_spray_extinput(this, event); desktop->canvas->forceFullRedrawAfterInterruptions(3); - tc->is_drawing = true; - tc->is_dilating = true; - tc->has_dilated = false; - if(tc->is_dilating && !event_context->space_panning) { - sp_spray_dilate(tc, scroll_w, desktop->dt2doc(scroll_dt), Geom::Point(0,0), false); + this->is_drawing = true; + this->is_dilating = true; + this->has_dilated = false; + if(this->is_dilating && !this->space_panning) { + sp_spray_dilate(this, scroll_w, desktop->dt2doc(scroll_dt), Geom::Point(0,0), false); } - tc->has_dilated = true; + this->has_dilated = true; - tc->population = temp; - desktop->setToolboxAdjustmentValue("population", tc->population * 100); + this->population = temp; + desktop->setToolboxAdjustmentValue("population", this->population * 100); ret = TRUE; } @@ -729,27 +700,27 @@ gint sp_spray_context_root_handler(SPEventContext *event_context, GdkEvent *even Geom::Point const motion_dt(desktop->w2d(motion_w)); desktop->canvas->endForcedFullRedraws(); - tc->is_drawing = false; + this->is_drawing = false; - if (tc->is_dilating && event->button.button == 1 && !event_context->space_panning) { - if (!tc->has_dilated) { + if (this->is_dilating && event->button.button == 1 && !this->space_panning) { + if (!this->has_dilated) { // if we did not rub, do a light tap - tc->pressure = 0.03; - sp_spray_dilate(tc, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT(event)); + this->pressure = 0.03; + sp_spray_dilate(this, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT(event)); } - tc->is_dilating = false; - tc->has_dilated = false; - switch (tc->mode) { + this->is_dilating = false; + this->has_dilated = false; + switch (this->mode) { case SPRAY_MODE_COPY: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_SPRAY, _("Spray with copies")); break; case SPRAY_MODE_CLONE: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_SPRAY, _("Spray with clones")); break; case SPRAY_MODE_SINGLE_PATH: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_SPRAY, _("Spray in single path")); break; } @@ -762,83 +733,83 @@ gint sp_spray_context_root_handler(SPEventContext *event_context, GdkEvent *even case GDK_KEY_j: case GDK_KEY_J: if (MOD__SHIFT_ONLY(event)) { - sp_spray_switch_mode(tc, SPRAY_MODE_COPY, MOD__SHIFT(event)); + sp_spray_switch_mode(this, SPRAY_MODE_COPY, MOD__SHIFT(event)); ret = TRUE; } break; case GDK_KEY_k: case GDK_KEY_K: if (MOD__SHIFT_ONLY(event)) { - sp_spray_switch_mode(tc, SPRAY_MODE_CLONE, MOD__SHIFT(event)); + sp_spray_switch_mode(this, SPRAY_MODE_CLONE, MOD__SHIFT(event)); ret = TRUE; } break; case GDK_KEY_l: case GDK_KEY_L: if (MOD__SHIFT_ONLY(event)) { - sp_spray_switch_mode(tc, SPRAY_MODE_SINGLE_PATH, MOD__SHIFT(event)); + sp_spray_switch_mode(this, SPRAY_MODE_SINGLE_PATH, MOD__SHIFT(event)); ret = TRUE; } break; case GDK_KEY_Up: case GDK_KEY_KP_Up: if (!MOD__CTRL_ONLY(event)) { - tc->population += 0.01; - if (tc->population > 1.0) { - tc->population = 1.0; + this->population += 0.01; + if (this->population > 1.0) { + this->population = 1.0; } - desktop->setToolboxAdjustmentValue("spray-population", tc->population * 100); + desktop->setToolboxAdjustmentValue("spray-population", this->population * 100); ret = TRUE; } break; case GDK_KEY_Down: case GDK_KEY_KP_Down: if (!MOD__CTRL_ONLY(event)) { - tc->population -= 0.01; - if (tc->population < 0.0) { - tc->population = 0.0; + this->population -= 0.01; + if (this->population < 0.0) { + this->population = 0.0; } - desktop->setToolboxAdjustmentValue("spray-population", tc->population * 100); + desktop->setToolboxAdjustmentValue("spray-population", this->population * 100); ret = TRUE; } break; case GDK_KEY_Right: case GDK_KEY_KP_Right: if (!MOD__CTRL_ONLY(event)) { - tc->width += 0.01; - if (tc->width > 1.0) { - tc->width = 1.0; + this->width += 0.01; + if (this->width > 1.0) { + this->width = 1.0; } // the same spinbutton is for alt+x - desktop->setToolboxAdjustmentValue("altx-spray", tc->width * 100); - sp_spray_update_area(tc); + desktop->setToolboxAdjustmentValue("altx-spray", this->width * 100); + sp_spray_update_area(this); ret = TRUE; } break; case GDK_KEY_Left: case GDK_KEY_KP_Left: if (!MOD__CTRL_ONLY(event)) { - tc->width -= 0.01; - if (tc->width < 0.01) { - tc->width = 0.01; + this->width -= 0.01; + if (this->width < 0.01) { + this->width = 0.01; } - desktop->setToolboxAdjustmentValue("altx-spray", tc->width * 100); - sp_spray_update_area(tc); + desktop->setToolboxAdjustmentValue("altx-spray", this->width * 100); + sp_spray_update_area(this); ret = TRUE; } break; case GDK_KEY_Home: case GDK_KEY_KP_Home: - tc->width = 0.01; - desktop->setToolboxAdjustmentValue("altx-spray", tc->width * 100); - sp_spray_update_area(tc); + this->width = 0.01; + desktop->setToolboxAdjustmentValue("altx-spray", this->width * 100); + sp_spray_update_area(this); ret = TRUE; break; case GDK_KEY_End: case GDK_KEY_KP_End: - tc->width = 1.0; - desktop->setToolboxAdjustmentValue("altx-spray", tc->width * 100); - sp_spray_update_area(tc); + this->width = 1.0; + desktop->setToolboxAdjustmentValue("altx-spray", this->width * 100); + sp_spray_update_area(this); ret = TRUE; break; case GDK_KEY_x: @@ -850,7 +821,7 @@ gint sp_spray_context_root_handler(SPEventContext *event_context, GdkEvent *even break; case GDK_KEY_Shift_L: case GDK_KEY_Shift_R: - sp_spray_update_cursor(tc, true); + this->update_cursor(true); break; case GDK_KEY_Control_L: case GDK_KEY_Control_R: @@ -858,7 +829,7 @@ gint sp_spray_context_root_handler(SPEventContext *event_context, GdkEvent *even case GDK_KEY_Delete: case GDK_KEY_KP_Delete: case GDK_KEY_BackSpace: - ret = event_context->deleteSelectedDrag(MOD__CTRL_ONLY(event)); + ret = this->deleteSelectedDrag(MOD__CTRL_ONLY(event)); break; default: @@ -871,15 +842,15 @@ gint sp_spray_context_root_handler(SPEventContext *event_context, GdkEvent *even switch (get_group0_keyval(&event->key)) { case GDK_KEY_Shift_L: case GDK_KEY_Shift_R: - sp_spray_update_cursor(tc, false); + this->update_cursor(false); break; case GDK_KEY_Control_L: case GDK_KEY_Control_R: - sp_spray_switch_mode (tc, prefs->getInt("/tools/spray/mode"), MOD__SHIFT(event)); - tc->_message_context->clear(); + sp_spray_switch_mode (this, prefs->getInt("/tools/spray/mode"), MOD__SHIFT(event)); + this->message_context->clear(); break; default: - sp_spray_switch_mode (tc, prefs->getInt("/tools/spray/mode"), MOD__SHIFT(event)); + sp_spray_switch_mode (this, prefs->getInt("/tools/spray/mode"), MOD__SHIFT(event)); break; } } @@ -889,9 +860,10 @@ gint sp_spray_context_root_handler(SPEventContext *event_context, GdkEvent *even } if (!ret) { - if ((SP_EVENT_CONTEXT_CLASS(sp_spray_context_parent_class))->root_handler) { - ret = (SP_EVENT_CONTEXT_CLASS(sp_spray_context_parent_class))->root_handler(event_context, event); - } +// if ((SP_EVENT_CONTEXT_CLASS(sp_spray_context_parent_class))->root_handler) { +// ret = (SP_EVENT_CONTEXT_CLASS(sp_spray_context_parent_class))->root_handler(event_context, event); +// } + ret = SPEventContext::root_handler(event); } return ret; diff --git a/src/spray-context.h b/src/spray-context.h index 781bbcce8..4e1ab9dc0 100644 --- a/src/spray-context.h +++ b/src/spray-context.h @@ -21,11 +21,8 @@ #include <2geom/point.h> #include "event-context.h" -#define SP_TYPE_SPRAY_CONTEXT (sp_spray_context_get_type()) -#define SP_SPRAY_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_SPRAY_CONTEXT, SPSprayContext)) -#define SP_SPRAY_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_SPRAY_CONTEXT, SPSprayContextClass)) -#define SP_IS_SPRAY_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_SPRAY_CONTEXT)) -#define SP_IS_SPRAY_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_SPRAY_CONTEXT)) +#define SP_SPRAY_CONTEXT(obj) (dynamic_cast<SPSprayContext*>((SPEventContext*)obj)) +#define SP_IS_SPRAY_CONTEXT(obj) (dynamic_cast<const SPSprayContext*>((const SPEventContext*)obj) != NULL) namespace Inkscape { namespace UI { @@ -49,9 +46,12 @@ enum { SPRAY_OPTION, }; -struct SPSprayContext -{ - SPEventContext event_context; +class SPSprayContext : public SPEventContext { +public: + SPSprayContext(); + virtual ~SPSprayContext(); + + //SPEventContext event_context; //Inkscape::UI::Dialog::Dialog *dialog_option;//Attribut de type SprayOptionClass, localisé dans scr/ui/dialog /* extended input data */ gdouble pressure; @@ -77,8 +77,6 @@ struct SPSprayContext gint mode; - Inkscape::MessageContext *_message_context; - bool is_drawing; bool is_dilating; @@ -87,15 +85,18 @@ struct SPSprayContext SPCanvasItem *dilate_area; sigc::connection style_set_connection; -}; -struct SPSprayContextClass -{ - SPEventContextClass parent_class; -}; + static const std::string prefsPath; -GType sp_spray_context_get_type(void); + virtual void setup(); + virtual void set(const Inkscape::Preferences::Entry& val); + virtual bool root_handler(GdkEvent* event); + virtual const std::string& getPrefsPath(); + + + void update_cursor(bool /*with_shift*/); +}; #endif diff --git a/src/star-context.cpp b/src/star-context.cpp index d4996e189..1a04f823f 100644 --- a/src/star-context.cpp +++ b/src/star-context.cpp @@ -49,94 +49,64 @@ using Inkscape::DocumentUndo; -static void sp_star_context_dispose (GObject *object); +#include "tool-factory.h" -static void sp_star_context_setup (SPEventContext *ec); -static void sp_star_context_finish(SPEventContext *ec); -static void sp_star_context_set (SPEventContext *ec, Inkscape::Preferences::Entry *val); -static gint sp_star_context_root_handler (SPEventContext *ec, GdkEvent *event); +namespace { + SPEventContext* createStarContext() { + return new SPStarContext(); + } -static void sp_star_drag (SPStarContext * sc, Geom::Point p, guint state); -static void sp_star_finish (SPStarContext * sc); -static void sp_star_cancel(SPStarContext * sc); - -G_DEFINE_TYPE(SPStarContext, sp_star_context, SP_TYPE_EVENT_CONTEXT); - -static void -sp_star_context_class_init (SPStarContextClass * klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - SPEventContextClass *event_context_class = SP_EVENT_CONTEXT_CLASS(klass); - - object_class->dispose = sp_star_context_dispose; + bool starContextRegistered = ToolFactory::instance().registerObject("/tools/shapes/star", createStarContext); +} - event_context_class->setup = sp_star_context_setup; - event_context_class->finish = sp_star_context_finish; - event_context_class->set = sp_star_context_set; - event_context_class->root_handler = sp_star_context_root_handler; +const std::string& SPStarContext::getPrefsPath() { + return SPStarContext::prefsPath; } -static void -sp_star_context_init (SPStarContext * star_context) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT (star_context); +const std::string SPStarContext::prefsPath = "/tools/shapes/star"; - event_context->cursor_shape = cursor_star_xpm; - event_context->hot_x = 4; - event_context->hot_y = 4; - event_context->xp = 0; - event_context->yp = 0; - event_context->tolerance = 0; - event_context->within_tolerance = false; - event_context->item_to_select = NULL; - event_context->tool_url = "/tools/shapes/star"; +SPStarContext::SPStarContext() : SPEventContext() { + this->randomized = 0; + this->rounded = 0; - star_context->item = NULL; + this->cursor_shape = cursor_star_xpm; + this->hot_x = 4; + this->hot_y = 4; + this->xp = 0; + this->yp = 0; + this->tolerance = 0; + this->within_tolerance = false; + this->item_to_select = NULL; + //this->tool_url = "/tools/shapes/star"; - star_context->magnitude = 5; - star_context->proportion = 0.5; - star_context->isflatsided = false; + this->star = NULL; - new (&star_context->sel_changed_connection) sigc::connection(); + this->magnitude = 5; + this->proportion = 0.5; + this->isflatsided = false; } -static void sp_star_context_finish(SPEventContext *ec) -{ - SPStarContext *sc = SP_STAR_CONTEXT(ec); - SPDesktop *desktop = ec->desktop; - +void SPStarContext::finish() { sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), GDK_CURRENT_TIME); - sp_star_finish(sc); - sc->sel_changed_connection.disconnect(); - - if ((SP_EVENT_CONTEXT_CLASS(sp_star_context_parent_class))->finish) { - (SP_EVENT_CONTEXT_CLASS(sp_star_context_parent_class))->finish(ec); - } -} + this->finishItem(); + this->sel_changed_connection.disconnect(); -static void -sp_star_context_dispose (GObject *object) -{ - SPEventContext *ec = SP_EVENT_CONTEXT (object); - SPStarContext *sc = SP_STAR_CONTEXT (object); + SPEventContext::finish(); +} - ec->enableGrDrag(false); +SPStarContext::~SPStarContext() { + this->enableGrDrag(false); - sc->sel_changed_connection.disconnect(); - sc->sel_changed_connection.~connection(); + this->sel_changed_connection.disconnect(); - delete ec->shape_editor; - ec->shape_editor = NULL; + delete this->shape_editor; + this->shape_editor = NULL; /* fixme: This is necessary because we do not grab */ - if (sc->item) sp_star_finish (sc); - - if (sc->_message_context) { - delete sc->_message_context; + if (this->star) { + this->finishItem(); } - - G_OBJECT_CLASS (sp_star_context_parent_class)->dispose (object); } /** @@ -145,101 +115,85 @@ sp_star_context_dispose (GObject *object) * * @param selection Should not be NULL. */ -static void sp_star_context_selection_changed (Inkscape::Selection * selection, gpointer data) -{ +void SPStarContext::selection_changed(Inkscape::Selection* selection) { g_assert (selection != NULL); - SPStarContext *sc = SP_STAR_CONTEXT (data); - SPEventContext *ec = SP_EVENT_CONTEXT (sc); - - ec->shape_editor->unset_item(SH_KNOTHOLDER); - SPItem *item = selection->singleItem(); - ec->shape_editor->set_item(item, SH_KNOTHOLDER); + this->shape_editor->unset_item(SH_KNOTHOLDER); + this->shape_editor->set_item(selection->singleItem(), SH_KNOTHOLDER); } -static void -sp_star_context_setup (SPEventContext *ec) -{ - SPStarContext *sc = SP_STAR_CONTEXT (ec); +void SPStarContext::setup() { + SPEventContext::setup(); - if ((SP_EVENT_CONTEXT_CLASS(sp_star_context_parent_class))->setup) - (SP_EVENT_CONTEXT_CLASS(sp_star_context_parent_class))->setup (ec); + sp_event_context_read(this, "magnitude"); + sp_event_context_read(this, "proportion"); + sp_event_context_read(this, "isflatsided"); + sp_event_context_read(this, "rounded"); + sp_event_context_read(this, "randomized"); - sp_event_context_read (ec, "magnitude"); - sp_event_context_read (ec, "proportion"); - sp_event_context_read (ec, "isflatsided"); - sp_event_context_read (ec, "rounded"); - sp_event_context_read (ec, "randomized"); + this->shape_editor = new ShapeEditor(this->desktop); - ec->shape_editor = new ShapeEditor(ec->desktop); + SPItem *item = sp_desktop_selection(this->desktop)->singleItem(); + if (item) { + this->shape_editor->set_item(item, SH_KNOTHOLDER); + } - SPItem *item = sp_desktop_selection(ec->desktop)->singleItem(); - if (item) { - ec->shape_editor->set_item(item, SH_KNOTHOLDER); - } - - Inkscape::Selection *selection = sp_desktop_selection(ec->desktop); - sc->sel_changed_connection.disconnect(); - sc->sel_changed_connection = selection->connectChanged(sigc::bind(sigc::ptr_fun(&sp_star_context_selection_changed), (gpointer)sc)); + Inkscape::Selection *selection = sp_desktop_selection(this->desktop); + + this->sel_changed_connection.disconnect(); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (prefs->getBool("/tools/shapes/selcue")) { - ec->enableSelectionCue(); - } + this->sel_changed_connection = selection->connectChanged(sigc::mem_fun(this, &SPStarContext::selection_changed)); - if (prefs->getBool("/tools/shapes/gradientdrag")) { - ec->enableGrDrag(); - } + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/tools/shapes/selcue")) { + this->enableSelectionCue(); + } - sc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack()); + if (prefs->getBool("/tools/shapes/gradientdrag")) { + this->enableGrDrag(); + } } -static void -sp_star_context_set (SPEventContext *ec, Inkscape::Preferences::Entry *val) -{ - SPStarContext *sc = SP_STAR_CONTEXT (ec); - Glib::ustring path = val->getEntryName(); +void SPStarContext::set(const Inkscape::Preferences::Entry& val) { + Glib::ustring path = val.getEntryName(); if (path == "magnitude") { - sc->magnitude = CLAMP(val->getInt(5), 3, 1024); + this->magnitude = CLAMP(val.getInt(5), 3, 1024); } else if (path == "proportion") { - sc->proportion = CLAMP(val->getDouble(0.5), 0.01, 2.0); + this->proportion = CLAMP(val.getDouble(0.5), 0.01, 2.0); } else if (path == "isflatsided") { - sc->isflatsided = val->getBool(); + this->isflatsided = val.getBool(); } else if (path == "rounded") { - sc->rounded = val->getDouble(); + this->rounded = val.getDouble(); } else if (path == "randomized") { - sc->randomized = val->getDouble(); + this->randomized = val.getDouble(); } } -static gint sp_star_context_root_handler(SPEventContext *event_context, GdkEvent *event) -{ - static gboolean dragging; +bool SPStarContext::root_handler(GdkEvent* event) { + static bool dragging; - SPDesktop *desktop = event_context->desktop; + SPDesktop *desktop = this->desktop; Inkscape::Selection *selection = sp_desktop_selection (desktop); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - SPStarContext *sc = SP_STAR_CONTEXT (event_context); - - event_context->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); + this->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); gint ret = FALSE; switch (event->type) { case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { - - dragging = TRUE; + if (event->button.button == 1 && !this->space_panning) { + dragging = true; - sc->center = Inkscape::setup_for_drag_start(desktop, event_context, event); + this->center = Inkscape::setup_for_drag_start(desktop, this, event); /* Snap center */ SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop, true); - m.freeSnapReturnByRef(sc->center, Inkscape::SNAPSOURCE_NODE_HANDLE); + m.freeSnapReturnByRef(this->center, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), GDK_KEY_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | @@ -249,28 +203,28 @@ static gint sp_star_context_root_handler(SPEventContext *event_context, GdkEvent ret = TRUE; } break; - case GDK_MOTION_NOTIFY: - if (dragging && (event->motion.state & GDK_BUTTON1_MASK) && !event_context->space_panning) { - if ( event_context->within_tolerance - && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance ) - && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) { + case GDK_MOTION_NOTIFY: + if (dragging && (event->motion.state & GDK_BUTTON1_MASK) && !this->space_panning) { + if ( this->within_tolerance + && ( abs( (gint) event->motion.x - this->xp ) < this->tolerance ) + && ( abs( (gint) event->motion.y - this->yp ) < this->tolerance ) ) { break; // do not drag if we're within tolerance from origin } // Once the user has moved farther than tolerance from the original location // (indicating they intend to draw, not click), then always process the // motion notify coordinates as given (no snapping back to origin) - event_context->within_tolerance = false; + this->within_tolerance = false; Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point motion_dt(desktop->w2d(motion_w)); - sp_star_drag (sc, motion_dt, event->motion.state); + this->drag(motion_dt, event->motion.state); gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; - } else if (!sp_event_context_knot_mouseover(event_context)) { + } else if (!sp_event_context_knot_mouseover(this)) { SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); @@ -282,30 +236,34 @@ static gint sp_star_context_root_handler(SPEventContext *event_context, GdkEvent } break; case GDK_BUTTON_RELEASE: - event_context->xp = event_context->yp = 0; - if (event->button.button == 1 && !event_context->space_panning) { - dragging = FALSE; - sp_event_context_discard_delayed_snap_event(event_context); - if (!event_context->within_tolerance) { + this->xp = this->yp = 0; + + if (event->button.button == 1 && !this->space_panning) { + dragging = false; + + sp_event_context_discard_delayed_snap_event(this); + + if (!this->within_tolerance) { // we've been dragging, finish the star - sp_star_finish (sc); - } else if (event_context->item_to_select) { + this->finishItem(); + } else if (this->item_to_select) { // no dragging, select clicked item if any if (event->button.state & GDK_SHIFT_MASK) { - selection->toggle(event_context->item_to_select); + selection->toggle(this->item_to_select); } else { - selection->set(event_context->item_to_select); + selection->set(this->item_to_select); } } else { // click in an empty space selection->clear(); } - event_context->item_to_select = NULL; + this->item_to_select = NULL; ret = TRUE; sp_canvas_item_ungrab(SP_CANVAS_ITEM (desktop->acetate), event->button.time); } break; + case GDK_KEY_PRESS: switch (get_group0_keyval(&event->key)) { case GDK_KEY_Alt_R: @@ -315,11 +273,12 @@ static gint sp_star_context_root_handler(SPEventContext *event_context, GdkEvent case GDK_KEY_Shift_R: case GDK_KEY_Meta_L: // Meta is when you press Shift+Alt (at least on my machine) case GDK_KEY_Meta_R: - sp_event_show_modifier_tip(event_context->defaultMessageContext(), event, + sp_event_show_modifier_tip(this->defaultMessageContext(), event, _("<b>Ctrl</b>: snap angle; keep rays radial"), NULL, NULL); break; + case GDK_KEY_Up: case GDK_KEY_Down: case GDK_KEY_KP_Up: @@ -328,6 +287,7 @@ static gint sp_star_context_root_handler(SPEventContext *event_context, GdkEvent if (!MOD__CTRL_ONLY(event)) ret = TRUE; break; + case GDK_KEY_x: case GDK_KEY_X: if (MOD__ALT_ONLY(event)) { @@ -335,38 +295,44 @@ static gint sp_star_context_root_handler(SPEventContext *event_context, GdkEvent ret = TRUE; } break; + case GDK_KEY_Escape: if (dragging) { dragging = false; - sp_event_context_discard_delayed_snap_event(event_context); + sp_event_context_discard_delayed_snap_event(this); // if drawing, cancel, otherwise pass it up for deselecting - sp_star_cancel(sc); + this->cancel(); ret = TRUE; } break; + case GDK_KEY_space: if (dragging) { - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), - event->button.time); + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); + dragging = false; - sp_event_context_discard_delayed_snap_event(event_context); - if (!event_context->within_tolerance) { + + sp_event_context_discard_delayed_snap_event(this); + + if (!this->within_tolerance) { // we've been dragging, finish the star - sp_star_finish(sc); + this->finishItem(); } // do not return true, so that space would work switching to selector } break; + case GDK_KEY_Delete: case GDK_KEY_KP_Delete: case GDK_KEY_BackSpace: - ret = event_context->deleteSelectedDrag(MOD__CTRL_ONLY(event)); + ret = this->deleteSelectedDrag(MOD__CTRL_ONLY(event)); break; default: break; } break; + case GDK_KEY_RELEASE: switch (get_group0_keyval (&event->key)) { case GDK_KEY_Alt_L: @@ -377,65 +343,66 @@ static gint sp_star_context_root_handler(SPEventContext *event_context, GdkEvent case GDK_KEY_Shift_R: case GDK_KEY_Meta_L: // Meta is when you press Shift+Alt case GDK_KEY_Meta_R: - event_context->defaultMessageContext()->clear(); + this->defaultMessageContext()->clear(); break; + default: break; } break; + default: break; } if (!ret) { - if ((SP_EVENT_CONTEXT_CLASS(sp_star_context_parent_class))->root_handler) - ret = (SP_EVENT_CONTEXT_CLASS(sp_star_context_parent_class))->root_handler (event_context, event); + ret = SPEventContext::root_handler(event); } return ret; } -static void sp_star_drag(SPStarContext *sc, Geom::Point p, guint state) +void SPStarContext::drag(Geom::Point p, guint state) { - SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; + SPDesktop *desktop = this->desktop; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int const snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12); - if (!sc->item) { - - if (Inkscape::have_viable_layer(desktop, sc->_message_context) == false) { + if (!this->star) { + if (Inkscape::have_viable_layer(desktop, this->message_context) == false) { return; } // Create object - Inkscape::XML::Document *xml_doc = SP_EVENT_CONTEXT_DOCUMENT(sc)->getReprDoc(); + Inkscape::XML::Document *xml_doc = this->desktop->doc()->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); repr->setAttribute("sodipodi:type", "star"); // Set style sp_desktop_apply_style_tool(desktop, repr, "/tools/shapes/star", false); - sc->item = SP_ITEM(desktop->currentLayer()->appendChildRepr(repr)); + this->star = SP_STAR(desktop->currentLayer()->appendChildRepr(repr)); + Inkscape::GC::release(repr); - sc->item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); - sc->item->updateRepr(); + this->star->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); + this->star->updateRepr(); desktop->canvas->forceFullRedrawAfterInterruptions(5); } /* Snap corner point with no constraints */ SnapManager &m = desktop->namedview->snap_manager; - m.setup(desktop, true, sc->item); + + m.setup(desktop, true, this->star); Geom::Point pt2g = p; m.freeSnapReturnByRef(pt2g, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); - Geom::Point const p0 = desktop->dt2doc(sc->center); - Geom::Point const p1 = desktop->dt2doc(pt2g); - SPStar *star = SP_STAR(sc->item); + Geom::Point const p0 = desktop->dt2doc(this->center); + Geom::Point const p1 = desktop->dt2doc(pt2g); - double const sides = (gdouble) sc->magnitude; + double const sides = (gdouble) this->magnitude; Geom::Point const d = p1 - p0; Geom::Coord const r1 = Geom::L2(d); double arg1 = atan2(d); @@ -445,14 +412,14 @@ static void sp_star_drag(SPStarContext *sc, Geom::Point p, guint state) arg1 = sp_round(arg1, M_PI / snaps); } - sp_star_position_set(star, sc->magnitude, p0, r1, r1 * sc->proportion, - arg1, arg1 + M_PI / sides, sc->isflatsided, sc->rounded, sc->randomized); + sp_star_position_set(this->star, this->magnitude, p0, r1, r1 * this->proportion, + arg1, arg1 + M_PI / sides, this->isflatsided, this->rounded, this->randomized); /* status text */ Inkscape::Util::Quantity q = Inkscape::Util::Quantity(r1, "px"); GString *rads = g_string_new(q.string(*desktop->namedview->doc_units).c_str()); - sc->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, - ( sc->isflatsided? + this->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, + ( this->isflatsided? _("<b>Polygon</b>: radius %s, angle %5g°; with <b>Ctrl</b> to snap angle") : _("<b>Star</b>: radius %s, angle %5g°; with <b>Ctrl</b> to snap angle") ), rads->str, sp_round((arg1) * 180 / M_PI, 0.0001)); @@ -460,55 +427,46 @@ static void sp_star_drag(SPStarContext *sc, Geom::Point p, guint state) g_string_free(rads, FALSE); } -static void -sp_star_finish (SPStarContext * sc) -{ - sc->_message_context->clear(); +void SPStarContext::finishItem() { + this->message_context->clear(); - if (sc->item != NULL) { - SPStar *star = SP_STAR(sc->item); - if (star->r[1] == 0) { - sp_star_cancel(sc); // Don't allow the creating of zero sized arc, for example when the start and and point snap to the snap grid point + if (this->star != NULL) { + if (this->star->r[1] == 0) { + // Don't allow the creating of zero sized arc, for example + // when the start and and point snap to the snap grid point + this->cancel(); return; } // Set transform center, so that odd stars rotate correctly // LP #462157 - sc->item->setCenter(sc->center); - - SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; - SPObject *object = SP_OBJECT(sc->item); - - (SP_SHAPE(sc->item))->setShape(); - - object->updateRepr(SP_OBJECT_WRITE_EXT); + this->star->setCenter(this->center); + this->star->set_shape(); + this->star->updateRepr(SP_OBJECT_WRITE_EXT); desktop->canvas->endForcedFullRedraws(); - sp_desktop_selection(desktop)->set(sc->item); + sp_desktop_selection(desktop)->set(this->star); DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, _("Create star")); - sc->item = NULL; + this->star = NULL; } } -static void sp_star_cancel(SPStarContext *sc) -{ - SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; - +void SPStarContext::cancel() { sp_desktop_selection(desktop)->clear(); sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0); - if (sc->item != NULL) { - SP_OBJECT(sc->item)->deleteObject(); - sc->item = NULL; + if (this->star != NULL) { + this->star->deleteObject(); + this->star = NULL; } - sc->within_tolerance = false; - sc->xp = 0; - sc->yp = 0; - sc->item_to_select = NULL; + this->within_tolerance = false; + this->xp = 0; + this->yp = 0; + this->item_to_select = NULL; desktop->canvas->endForcedFullRedraws(); diff --git a/src/star-context.h b/src/star-context.h index 4daafb3e4..af66f3201 100644 --- a/src/star-context.h +++ b/src/star-context.h @@ -19,36 +19,48 @@ #include <2geom/point.h> #include "event-context.h" -#define SP_TYPE_STAR_CONTEXT (sp_star_context_get_type ()) -#define SP_STAR_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_STAR_CONTEXT, SPStarContext)) -#define SP_STAR_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_STAR_CONTEXT, SPStarContextClass)) -#define SP_IS_STAR_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_STAR_CONTEXT)) -#define SP_IS_STAR_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_STAR_CONTEXT)) +#include "sp-star.h" -struct SPStarContext : public SPEventContext { - SPItem *item; - Geom::Point center; +class SPStarContext : public SPEventContext { +public: + SPStarContext(); + virtual ~SPStarContext(); + + static const std::string prefsPath; + + virtual void setup(); + virtual void finish(); + virtual void set(const Inkscape::Preferences::Entry& val); + virtual bool root_handler(GdkEvent* event); + + virtual const std::string& getPrefsPath(); + +private: + SPStar* star; + + Geom::Point center; /* Number of corners */ gint magnitude; + /* Outer/inner radius ratio */ gdouble proportion; + /* flat sides or not? */ bool isflatsided; + /* rounded corners ratio */ gdouble rounded; + // randomization gdouble randomized; sigc::connection sel_changed_connection; - Inkscape::MessageContext *_message_context; + void drag(Geom::Point p, guint state); + void finishItem(); + void cancel(); + void selection_changed(Inkscape::Selection* selection); }; -struct SPStarContextClass { - SPEventContextClass parent_class; -}; - -GType sp_star_context_get_type (void); - #endif diff --git a/src/style.cpp b/src/style.cpp index db05a748f..e9cf22891 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -3170,7 +3170,10 @@ sp_style_clear(SPStyle *style) style->color_interpolation.value = style->color_interpolation.computed = SP_CSS_COLOR_INTERPOLATION_SRGB; style->color_interpolation_filters.set = FALSE; style->color_interpolation_filters.inherit = FALSE; - style->color_interpolation_filters.value = style->color_interpolation_filters.computed = SP_CSS_COLOR_INTERPOLATION_LINEARRGB; + style->color_interpolation_filters.value = style->color_interpolation_filters.computed = SP_CSS_COLOR_INTERPOLATION_SRGB; + //this line changed because rendering issues: Bug lp:1127103 + //style->color_interpolation_filters.value = style->color_interpolation_filters.computed = SP_CSS_COLOR_INTERPOLATION_LINEARRGB; + style->fill.clear(); style->fill.setColor(0.0, 0.0, 0.0); diff --git a/src/svg/CMakeLists.txt b/src/svg/CMakeLists.txt index 943c3088f..968287895 100644 --- a/src/svg/CMakeLists.txt +++ b/src/svg/CMakeLists.txt @@ -1,10 +1,7 @@ set(svg_SRC css-ostringstream.cpp - #ftos.cpp - itos.cpp path-string.cpp - round.cpp sp-svg.def stringstream.cpp strip-trailing-zeros.cpp diff --git a/src/svg/Makefile_insert b/src/svg/Makefile_insert index 265210a45..cf9bf3fbb 100644 --- a/src/svg/Makefile_insert +++ b/src/svg/Makefile_insert @@ -3,10 +3,8 @@ ink_common_sources += \ svg/css-ostringstream.h \ svg/css-ostringstream.cpp \ - svg/itos.cpp \ svg/path-string.h \ svg/path-string.cpp \ - svg/round.cpp \ svg/stringstream.h \ svg/stringstream.cpp \ svg/strip-trailing-zeros.h \ diff --git a/src/svg/itos.cpp b/src/svg/itos.cpp deleted file mode 100644 index 78726d068..000000000 --- a/src/svg/itos.cpp +++ /dev/null @@ -1,81 +0,0 @@ -///////////////////////////////////////////////////////////////////////// -// ftoa.cpp -// -// Copyright (c) 1996-2003 Bryce W. Harrington [bryce at osdl dot org] -// -//----------------------------------------------------------------------- -// License: This code may be used by anyone for any purpose -// so long as the copyright notices and this license -// statement remains attached. -//----------------------------------------------------------------------- -// -// This routine converts an integer into a string -// -///////////////////////////////////////////////////////////////////////// - -// Standard include files -#include <algorithm> -#include <string> // for string -#include <cstring> - -#include "../io/ftos.h" /* own include */ /* note - why in different dirs? */ - -using std::string; - -string itos(int n) -{ - int sign; - string s; - - if ((sign = n) < 0) // record sign - n = -n; // make n positive - do { // generate digits in reverse order - s += (char(n % 10) + '0'); // get next digit - } while ((n/=10) > 0); // delete it - - if (sign < 0) - s += '-'; - - reverse(s.begin(), s.end()); // This is what the code should look like - // if the string class is compatible with - // the standard C++ string class -#ifdef DUMB_OS_LIKE_WINDOWS - // In Windows, we'll use this hack... - for (int i=0, j=s.GetLength()-1; i<j; i++, j--) - { - char c = s[i]; -// s[i] = s[j]; -// s[j] = c; - s.SetAt(i, s[j]); - s.SetAt(j, c); - } -#endif - - return s; -} - -string ultos(unsigned long n) -{ - string s; - - do { // generate digits in reverse order - s += (char(n % 10) + '0'); // get next digit - } while ((n/=10) > 0); // delete it - - reverse(s.begin(), s.end()); // This is what the code should look like - // if the string class is compatible with - // the standard C++ string class -#ifdef DUMB_OS_LIKE_WINDOWS - // In Windows, we'll use this hack... - for (int i=0, j=s.GetLength()-1; i<j; i++, j--) - { - char c = s[i]; -// s[i] = s[j]; -// s[j] = c; - s.SetAt(i, s[j]); - s.SetAt(j, c); - } -#endif - - return s; -} diff --git a/src/svg/round.cpp b/src/svg/round.cpp deleted file mode 100644 index 0a4ca9d05..000000000 --- a/src/svg/round.cpp +++ /dev/null @@ -1,48 +0,0 @@ -///////////////////////////////////////////////////////////////////////// -// ftos.cc -// -// Copyright (c) 1996-2003 Bryce W. Harrington [bryce at osdl dot org] -// -//----------------------------------------------------------------------- -// License: This code may be used by anyone for any purpose -// so long as the copyright notices and this license -// statement remains attached. -//----------------------------------------------------------------------- -// This routine rounds a double using the "rounding rule", as expressed -// in _Advanced Engineering Mathematics_ by Erwin Kreyszig, 6th ed., -// John Wiley & Sons, Inc., 1988, page 945. -// -// Discard the (k+1)th and all subsequent decimals. -// (a) If the number thus discarded is less than half a unit in the -// kth place, leave the kth decimal unchanged ("rounding down") -// (b) If it is greater than half a unit in the kth place, add one -// to the kth decimal ("rounding up") -// (c) If it is exactly half a unit, round off to the nearest *even* -// decimal. -// Example: Rounding off 3.45 and 3.55 by one decimal gives 3.4 and -// 3.6, respectively. -// Rule (c) is to ensure that in discarding exactly half a decimal, -// rounding up and rounding down happens about equally often, -// on the average. -/////////////////////////////////////////////////////////////////////// -#include <math.h> -#include "../io/ftos.h" /* own include */ /* note - why in different dirs? */ - -double rround(double x) -{ - double xlow = floor(x); - if (x - xlow != 0.5000) - return floor(x + 0.5000); - else if ( floor(x/2.0) == xlow/2.0) - return xlow; - else - return xlow++; -} - -// This version allows rounding to a specific digit -double rround(double x, int k) -{ - if (k==0) return rround(x); - else return rround(x*pow(10,k)) / pow(10,k); -} - diff --git a/src/svg/svg-length.h b/src/svg/svg-length.h index 6c8f1e1dd..3832a4eb5 100644 --- a/src/svg/svg-length.h +++ b/src/svg/svg-length.h @@ -37,9 +37,16 @@ public: LAST_UNIT = PERCENT }; + // The object's value is valid / exists in SVG. bool _set; + + // The unit of value. Unit unit; + + // The value of this SVGLength as found in the SVG. float value; + + // The value in pixels (value * pixels/unit). float computed; float operator=(float v) { diff --git a/src/text-context.cpp b/src/text-context.cpp index 719a82156..502973633 100644 --- a/src/text-context.cpp +++ b/src/text-context.cpp @@ -56,13 +56,6 @@ using Inkscape::ControlManager; using Inkscape::DocumentUndo; -static void sp_text_context_dispose(GObject *obj); - -static void sp_text_context_setup(SPEventContext *ec); -static void sp_text_context_finish(SPEventContext *ec); -static gint sp_text_context_root_handler(SPEventContext *event_context, GdkEvent *event); -static gint sp_text_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event); - static void sp_text_context_selection_changed(Inkscape::Selection *selection, SPTextContext *tc); static void sp_text_context_selection_modified(Inkscape::Selection *selection, guint flags, SPTextContext *tc); static bool sp_text_context_style_set(SPCSSAttr const *css, SPTextContext *tc); @@ -78,119 +71,98 @@ static gint sptc_focus_in(GtkWidget *widget, GdkEventFocus *event, SPTextContext static gint sptc_focus_out(GtkWidget *widget, GdkEventFocus *event, SPTextContext *tc); static void sptc_commit(GtkIMContext *imc, gchar *string, SPTextContext *tc); -G_DEFINE_TYPE(SPTextContext, sp_text_context, SP_TYPE_EVENT_CONTEXT); -static void sp_text_context_class_init(SPTextContextClass *klass) -{ - GObjectClass *object_class=G_OBJECT_CLASS(klass); - SPEventContextClass *event_context_class = SP_EVENT_CONTEXT_CLASS(klass); +#include "tool-factory.h" - object_class->dispose = sp_text_context_dispose; +namespace { + SPEventContext* createTextContext() { + return new SPTextContext(); + } - event_context_class->setup = sp_text_context_setup; - event_context_class->finish = sp_text_context_finish; - event_context_class->root_handler = sp_text_context_root_handler; - event_context_class->item_handler = sp_text_context_item_handler; + bool textContextRegistered = ToolFactory::instance().registerObject("/tools/text", createTextContext); } -static void sp_text_context_init(SPTextContext *tc) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(tc); +const std::string& SPTextContext::getPrefsPath() { + return SPTextContext::prefsPath; +} - event_context->cursor_shape = cursor_text_xpm; - event_context->hot_x = 7; - event_context->hot_y = 7; +const std::string SPTextContext::prefsPath = "/tools/text"; - event_context->xp = 0; - event_context->yp = 0; - event_context->tolerance = 0; - event_context->within_tolerance = false; - tc->imc = NULL; +SPTextContext::SPTextContext() : SPEventContext() { + this->preedit_string = 0; + this->unipos = 0; - tc->text = NULL; - tc->pdoc = Geom::Point(0, 0); - new (&tc->text_sel_start) Inkscape::Text::Layout::iterator(); - new (&tc->text_sel_end) Inkscape::Text::Layout::iterator(); - new (&tc->text_selection_quads) std::vector<SPCanvasItem*>(); - - tc->unimode = false; - - tc->cursor = NULL; - tc->indicator = NULL; - tc->frame = NULL; - tc->grabbed = NULL; - tc->timeout = 0; - tc->show = FALSE; - tc->phase = 0; - tc->nascent_object = 0; - tc->over_text = 0; - tc->dragging = 0; - tc->creating = 0; - - new (&tc->sel_changed_connection) sigc::connection(); - new (&tc->sel_modified_connection) sigc::connection(); - new (&tc->style_set_connection) sigc::connection(); - new (&tc->style_query_connection) sigc::connection(); + this->cursor_shape = cursor_text_xpm; + this->hot_x = 7; + this->hot_y = 7; + + this->xp = 0; + this->yp = 0; + this->tolerance = 0; + this->within_tolerance = false; + + this->imc = NULL; + + this->text = NULL; + this->pdoc = Geom::Point(0, 0); + + this->unimode = false; + + this->cursor = NULL; + this->indicator = NULL; + this->frame = NULL; + this->grabbed = NULL; + this->timeout = 0; + this->show = FALSE; + this->phase = 0; + this->nascent_object = 0; + this->over_text = 0; + this->dragging = 0; + this->creating = 0; } -static void sp_text_context_dispose(GObject *obj) -{ - SPTextContext *tc = SP_TEXT_CONTEXT(obj); - SPEventContext *ec = SP_EVENT_CONTEXT(tc); - tc->style_query_connection.~connection(); - tc->style_set_connection.~connection(); - tc->sel_changed_connection.~connection(); - tc->sel_modified_connection.~connection(); - - delete ec->shape_editor; - ec->shape_editor = NULL; - - tc->text_sel_end.~iterator(); - tc->text_sel_start.~iterator(); - tc->text_selection_quads.~vector(); - if (G_OBJECT_CLASS(sp_text_context_parent_class)->dispose) { - G_OBJECT_CLASS(sp_text_context_parent_class)->dispose(obj); - } - if (tc->grabbed) { - sp_canvas_item_ungrab(tc->grabbed, GDK_CURRENT_TIME); - tc->grabbed = NULL; +SPTextContext::~SPTextContext() { + delete this->shape_editor; + this->shape_editor = NULL; + + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, GDK_CURRENT_TIME); + this->grabbed = NULL; } - Inkscape::Rubberband::get(ec->desktop)->stop(); + Inkscape::Rubberband::get(this->desktop)->stop(); } -static void sp_text_context_setup(SPEventContext *ec) -{ - SPTextContext *tc = SP_TEXT_CONTEXT(ec); - SPDesktop *desktop = ec->desktop; +void SPTextContext::setup() { GtkSettings* settings = gtk_settings_get_default(); gint timeout = 0; g_object_get( settings, "gtk-cursor-blink-time", &timeout, NULL ); + if (timeout < 0) { timeout = 200; } else { timeout /= 2; } - tc->cursor = ControlManager::getManager().createControlLine(sp_desktop_controls(desktop), Geom::Point(100, 0), Geom::Point(100, 100)); - tc->cursor->setRgba32(0x000000ff); - sp_canvas_item_hide(tc->cursor); + this->cursor = ControlManager::getManager().createControlLine(sp_desktop_controls(desktop), Geom::Point(100, 0), Geom::Point(100, 100)); + this->cursor->setRgba32(0x000000ff); + sp_canvas_item_hide(this->cursor); - tc->indicator = sp_canvas_item_new(sp_desktop_controls(desktop), SP_TYPE_CTRLRECT, NULL); - SP_CTRLRECT(tc->indicator)->setRectangle(Geom::Rect(Geom::Point(0, 0), Geom::Point(100, 100))); - SP_CTRLRECT(tc->indicator)->setColor(0x0000ff7f, false, 0); - sp_canvas_item_hide(tc->indicator); + this->indicator = sp_canvas_item_new(sp_desktop_controls(desktop), SP_TYPE_CTRLRECT, NULL); + SP_CTRLRECT(this->indicator)->setRectangle(Geom::Rect(Geom::Point(0, 0), Geom::Point(100, 100))); + SP_CTRLRECT(this->indicator)->setColor(0x0000ff7f, false, 0); + sp_canvas_item_hide(this->indicator); - tc->frame = sp_canvas_item_new(sp_desktop_controls(desktop), SP_TYPE_CTRLRECT, NULL); - SP_CTRLRECT(tc->frame)->setRectangle(Geom::Rect(Geom::Point(0, 0), Geom::Point(100, 100))); - SP_CTRLRECT(tc->frame)->setColor(0x0000ff7f, false, 0); - sp_canvas_item_hide(tc->frame); + this->frame = sp_canvas_item_new(sp_desktop_controls(desktop), SP_TYPE_CTRLRECT, NULL); + SP_CTRLRECT(this->frame)->setRectangle(Geom::Rect(Geom::Point(0, 0), Geom::Point(100, 100))); + SP_CTRLRECT(this->frame)->setColor(0x0000ff7f, false, 0); + sp_canvas_item_hide(this->frame); - tc->timeout = g_timeout_add(timeout, (GSourceFunc) sp_text_context_timeout, ec); + this->timeout = g_timeout_add(timeout, (GSourceFunc) sp_text_context_timeout, this); - tc->imc = gtk_im_multicontext_new(); - if (tc->imc) { + this->imc = gtk_im_multicontext_new(); + if (this->imc) { GtkWidget *canvas = GTK_WIDGET(sp_desktop_canvas(desktop)); /* im preedit handling is very broken in inkscape for @@ -199,201 +171,194 @@ static void sp_text_context_setup(SPEventContext *ec) * just take in the characters when they're finished being * entered. */ - gtk_im_context_set_use_preedit(tc->imc, FALSE); - gtk_im_context_set_client_window(tc->imc, + gtk_im_context_set_use_preedit(this->imc, FALSE); + gtk_im_context_set_client_window(this->imc, gtk_widget_get_window (canvas)); - g_signal_connect(G_OBJECT(canvas), "focus_in_event", G_CALLBACK(sptc_focus_in), tc); - g_signal_connect(G_OBJECT(canvas), "focus_out_event", G_CALLBACK(sptc_focus_out), tc); - g_signal_connect(G_OBJECT(tc->imc), "commit", G_CALLBACK(sptc_commit), tc); + g_signal_connect(G_OBJECT(canvas), "focus_in_event", G_CALLBACK(sptc_focus_in), this); + g_signal_connect(G_OBJECT(canvas), "focus_out_event", G_CALLBACK(sptc_focus_out), this); + g_signal_connect(G_OBJECT(this->imc), "commit", G_CALLBACK(sptc_commit), this); if (gtk_widget_has_focus(canvas)) { - sptc_focus_in(canvas, NULL, tc); + sptc_focus_in(canvas, NULL, this); } } - if ((SP_EVENT_CONTEXT_CLASS(sp_text_context_parent_class))->setup) - (SP_EVENT_CONTEXT_CLASS(sp_text_context_parent_class))->setup(ec); + SPEventContext::setup(); - ec->shape_editor = new ShapeEditor(ec->desktop); + this->shape_editor = new ShapeEditor(this->desktop); - SPItem *item = sp_desktop_selection(ec->desktop)->singleItem(); + SPItem *item = sp_desktop_selection(this->desktop)->singleItem(); if (item && SP_IS_FLOWTEXT(item) && SP_FLOWTEXT(item)->has_internal_frame()) { - ec->shape_editor->set_item(item, SH_KNOTHOLDER); + this->shape_editor->set_item(item, SH_KNOTHOLDER); } - tc->sel_changed_connection = sp_desktop_selection(desktop)->connectChanged( - sigc::bind(sigc::ptr_fun(&sp_text_context_selection_changed), tc) - ); - tc->sel_modified_connection = sp_desktop_selection(desktop)->connectModified( - sigc::bind(sigc::ptr_fun(&sp_text_context_selection_modified), tc) - ); - tc->style_set_connection = desktop->connectSetStyle( - sigc::bind(sigc::ptr_fun(&sp_text_context_style_set), tc) - ); - tc->style_query_connection = desktop->connectQueryStyle( - sigc::bind(sigc::ptr_fun(&sp_text_context_style_query), tc) - ); - - sp_text_context_selection_changed(sp_desktop_selection(desktop), tc); + this->sel_changed_connection = sp_desktop_selection(desktop)->connectChanged( + sigc::bind(sigc::ptr_fun(&sp_text_context_selection_changed), this) + ); + this->sel_modified_connection = sp_desktop_selection(desktop)->connectModified( + sigc::bind(sigc::ptr_fun(&sp_text_context_selection_modified), this) + ); + this->style_set_connection = desktop->connectSetStyle( + sigc::bind(sigc::ptr_fun(&sp_text_context_style_set), this) + ); + this->style_query_connection = desktop->connectQueryStyle( + sigc::bind(sigc::ptr_fun(&sp_text_context_style_query), this) + ); + + sp_text_context_selection_changed(sp_desktop_selection(desktop), this); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/tools/text/selcue")) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } if (prefs->getBool("/tools/text/gradientdrag")) { - ec->enableGrDrag(); + this->enableGrDrag(); } } -static void sp_text_context_finish(SPEventContext *ec) -{ - SPTextContext *tc = SP_TEXT_CONTEXT(ec); - - if (ec->desktop) { - sp_signal_disconnect_by_data(sp_desktop_canvas(ec->desktop), tc); +void SPTextContext::finish() { + if (this->desktop) { + sp_signal_disconnect_by_data(sp_desktop_canvas(this->desktop), this); } - ec->enableGrDrag(false); + this->enableGrDrag(false); - tc->style_set_connection.disconnect(); - tc->style_query_connection.disconnect(); - tc->sel_changed_connection.disconnect(); - tc->sel_modified_connection.disconnect(); + this->style_set_connection.disconnect(); + this->style_query_connection.disconnect(); + this->sel_changed_connection.disconnect(); + this->sel_modified_connection.disconnect(); - sp_text_context_forget_text(SP_TEXT_CONTEXT(ec)); + sp_text_context_forget_text(SP_TEXT_CONTEXT(this)); - if (tc->imc) { - g_object_unref(G_OBJECT(tc->imc)); - tc->imc = NULL; + if (this->imc) { + g_object_unref(G_OBJECT(this->imc)); + this->imc = NULL; } - if (tc->timeout) { - g_source_remove(tc->timeout); - tc->timeout = 0; + if (this->timeout) { + g_source_remove(this->timeout); + this->timeout = 0; } - if (tc->cursor) { - sp_canvas_item_destroy(tc->cursor); - tc->cursor = NULL; + if (this->cursor) { + sp_canvas_item_destroy(this->cursor); + this->cursor = NULL; } - if (tc->indicator) { - sp_canvas_item_destroy(tc->indicator); - tc->indicator = NULL; + if (this->indicator) { + sp_canvas_item_destroy(this->indicator); + this->indicator = NULL; } - if (tc->frame) { - sp_canvas_item_destroy(tc->frame); - tc->frame = NULL; + if (this->frame) { + sp_canvas_item_destroy(this->frame); + this->frame = NULL; } - for (std::vector<SPCanvasItem*>::iterator it = tc->text_selection_quads.begin() ; - it != tc->text_selection_quads.end() ; ++it) { + for (std::vector<SPCanvasItem*>::iterator it = this->text_selection_quads.begin() ; + it != this->text_selection_quads.end() ; ++it) { sp_canvas_item_hide(*it); sp_canvas_item_destroy(*it); } - tc->text_selection_quads.clear(); + + this->text_selection_quads.clear(); } - -static gint sp_text_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event) -{ - SPTextContext *tc = SP_TEXT_CONTEXT(event_context); - SPDesktop *desktop = event_context->desktop; +bool SPTextContext::item_handler(SPItem* item, GdkEvent* event) { SPItem *item_ungrouped; gint ret = FALSE; - sp_text_context_validate_cursor_iterators(tc); - Inkscape::Text::Layout::iterator old_start = tc->text_sel_start; + sp_text_context_validate_cursor_iterators(this); + Inkscape::Text::Layout::iterator old_start = this->text_sel_start; switch (event->type) { case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { + if (event->button.button == 1 && !this->space_panning) { // find out clicked item, disregarding groups item_ungrouped = desktop->getItemAtPoint(Geom::Point(event->button.x, event->button.y), TRUE); if (SP_IS_TEXT(item_ungrouped) || SP_IS_FLOWTEXT(item_ungrouped)) { sp_desktop_selection(desktop)->set(item_ungrouped); - if (tc->text) { + if (this->text) { // find out click point in document coordinates Geom::Point p = desktop->w2d(Geom::Point(event->button.x, event->button.y)); // set the cursor closest to that point if (event->button.state & GDK_SHIFT_MASK) { - tc->text_sel_start = old_start; - tc->text_sel_end = sp_te_get_position_by_coords(tc->text, p); + this->text_sel_start = old_start; + this->text_sel_end = sp_te_get_position_by_coords(this->text, p); } else { - tc->text_sel_start = tc->text_sel_end = sp_te_get_position_by_coords(tc->text, p); + this->text_sel_start = this->text_sel_end = sp_te_get_position_by_coords(this->text, p); } // update display - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); - tc->dragging = 1; + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); + this->dragging = 1; } ret = TRUE; } } break; case GDK_2BUTTON_PRESS: - if (event->button.button == 1 && tc->text) { - Inkscape::Text::Layout const *layout = te_get_layout(tc->text); + if (event->button.button == 1 && this->text) { + Inkscape::Text::Layout const *layout = te_get_layout(this->text); if (layout) { - if (!layout->isStartOfWord(tc->text_sel_start)) - tc->text_sel_start.prevStartOfWord(); - if (!layout->isEndOfWord(tc->text_sel_end)) - tc->text_sel_end.nextEndOfWord(); - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); - tc->dragging = 2; + if (!layout->isStartOfWord(this->text_sel_start)) + this->text_sel_start.prevStartOfWord(); + if (!layout->isEndOfWord(this->text_sel_end)) + this->text_sel_end.nextEndOfWord(); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); + this->dragging = 2; ret = TRUE; } } break; case GDK_3BUTTON_PRESS: - if (event->button.button == 1 && tc->text) { - tc->text_sel_start.thisStartOfLine(); - tc->text_sel_end.thisEndOfLine(); - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); - tc->dragging = 3; + if (event->button.button == 1 && this->text) { + this->text_sel_start.thisStartOfLine(); + this->text_sel_end.thisEndOfLine(); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); + this->dragging = 3; ret = TRUE; } break; case GDK_BUTTON_RELEASE: - if (event->button.button == 1 && tc->dragging && !event_context->space_panning) { - tc->dragging = 0; - sp_event_context_discard_delayed_snap_event(event_context); + if (event->button.button == 1 && this->dragging && !this->space_panning) { + this->dragging = 0; + sp_event_context_discard_delayed_snap_event(this); ret = TRUE; } break; case GDK_MOTION_NOTIFY: - if (event->motion.state & GDK_BUTTON1_MASK && tc->dragging && !event_context->space_panning) { - Inkscape::Text::Layout const *layout = te_get_layout(tc->text); + if ((event->motion.state & GDK_BUTTON1_MASK) && this->dragging && !this->space_panning) { + Inkscape::Text::Layout const *layout = te_get_layout(this->text); if (!layout) break; // find out click point in document coordinates Geom::Point p = desktop->w2d(Geom::Point(event->button.x, event->button.y)); // set the cursor closest to that point - Inkscape::Text::Layout::iterator new_end = sp_te_get_position_by_coords(tc->text, p); - if (tc->dragging == 2) { + Inkscape::Text::Layout::iterator new_end = sp_te_get_position_by_coords(this->text, p); + if (this->dragging == 2) { // double-click dragging: go by word - if (new_end < tc->text_sel_start) { + if (new_end < this->text_sel_start) { if (!layout->isStartOfWord(new_end)) new_end.prevStartOfWord(); } else if (!layout->isEndOfWord(new_end)) new_end.nextEndOfWord(); - } else if (tc->dragging == 3) { + } else if (this->dragging == 3) { // triple-click dragging: go by line - if (new_end < tc->text_sel_start) + if (new_end < this->text_sel_start) new_end.thisStartOfLine(); else new_end.thisEndOfLine(); } // update display - if (tc->text_sel_end != new_end) { - tc->text_sel_end = new_end; - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + if (this->text_sel_end != new_end) { + this->text_sel_end = new_end; + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); } gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; @@ -405,21 +370,21 @@ static gint sp_text_context_item_handler(SPEventContext *event_context, SPItem * Inkscape::Text::Layout const *layout = te_get_layout(item_ungrouped); if (layout->inputTruncated()) { - SP_CTRLRECT(tc->indicator)->setColor(0xff0000ff, false, 0); + SP_CTRLRECT(this->indicator)->setColor(0xff0000ff, false, 0); } else { - SP_CTRLRECT(tc->indicator)->setColor(0x0000ff7f, false, 0); + SP_CTRLRECT(this->indicator)->setColor(0x0000ff7f, false, 0); } Geom::OptRect ibbox = item_ungrouped->desktopVisualBounds(); if (ibbox) { - SP_CTRLRECT(tc->indicator)->setRectangle(*ibbox); + SP_CTRLRECT(this->indicator)->setRectangle(*ibbox); } - sp_canvas_item_show(tc->indicator); + sp_canvas_item_show(this->indicator); - event_context->cursor_shape = cursor_text_insert_xpm; - event_context->hot_x = 7; - event_context->hot_y = 10; - sp_event_context_update_cursor(event_context); - sp_text_context_update_text_selection(tc); + this->cursor_shape = cursor_text_insert_xpm; + this->hot_x = 7; + this->hot_y = 10; + this->sp_event_context_update_cursor(); + sp_text_context_update_text_selection(this); if (SP_IS_TEXT (item_ungrouped)) { desktop->event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> to edit the text, <b>drag</b> to select part of the text.")); @@ -427,7 +392,7 @@ static gint sp_text_context_item_handler(SPEventContext *event_context, SPItem * desktop->event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> to edit the flowed text, <b>drag</b> to select part of the text.")); } - tc->over_text = true; + this->over_text = true; ret = TRUE; } @@ -437,8 +402,7 @@ static gint sp_text_context_item_handler(SPEventContext *event_context, SPItem * } if (!ret) { - if ((SP_EVENT_CONTEXT_CLASS(sp_text_context_parent_class))->item_handler) - ret = (SP_EVENT_CONTEXT_CLASS(sp_text_context_parent_class))->item_handler(event_context, item, event); + ret = SPEventContext::item_handler(item, event); } return ret; @@ -559,31 +523,26 @@ static void show_curr_uni_char(SPTextContext *const tc) } } -static gint sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *const event) -{ - SPTextContext *const tc = SP_TEXT_CONTEXT(event_context); - - SPDesktop *desktop = event_context->desktop; +bool SPTextContext::root_handler(GdkEvent* event) { + sp_canvas_item_hide(this->indicator); - sp_canvas_item_hide(tc->indicator); - - sp_text_context_validate_cursor_iterators(tc); + sp_text_context_validate_cursor_iterators(this); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - event_context->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); + this->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); switch (event->type) { case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { + if (event->button.button == 1 && !this->space_panning) { if (Inkscape::have_viable_layer(desktop, desktop->messageStack()) == false) { return TRUE; } // save drag origin - event_context->xp = (gint) event->button.x; - event_context->yp = (gint) event->button.y; - event_context->within_tolerance = true; + this->xp = (gint) event->button.x; + this->yp = (gint) event->button.y; + this->within_tolerance = true; Geom::Point const button_pt(event->button.x, event->button.y); Geom::Point button_dt(desktop->w2d(button_pt)); @@ -593,39 +552,39 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd m.freeSnapReturnByRef(button_dt, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); - tc->p0 = button_dt; - Inkscape::Rubberband::get(desktop)->start(desktop, tc->p0); + this->p0 = button_dt; + Inkscape::Rubberband::get(desktop)->start(desktop, this->p0); sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), GDK_KEY_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK, NULL, event->button.time); - tc->grabbed = SP_CANVAS_ITEM(desktop->acetate); - tc->creating = 1; + this->grabbed = SP_CANVAS_ITEM(desktop->acetate); + this->creating = 1; /* Processed */ return TRUE; } break; case GDK_MOTION_NOTIFY: - if (tc->over_text) { - tc->over_text = 0; + if (this->over_text) { + this->over_text = 0; // update cursor and statusbar: we are not over a text object now - event_context->cursor_shape = cursor_text_xpm; - event_context->hot_x = 7; - event_context->hot_y = 7; - sp_event_context_update_cursor(event_context); + this->cursor_shape = cursor_text_xpm; + this->hot_x = 7; + this->hot_y = 7; + this->sp_event_context_update_cursor(); desktop->event_context->defaultMessageContext()->clear(); } - if (tc->creating && event->motion.state & GDK_BUTTON1_MASK && !event_context->space_panning) { - if ( event_context->within_tolerance - && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance ) - && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) { + if (this->creating && (event->motion.state & GDK_BUTTON1_MASK) && !this->space_panning) { + if ( this->within_tolerance + && ( abs( (gint) event->motion.x - this->xp ) < this->tolerance ) + && ( abs( (gint) event->motion.y - this->yp ) < this->tolerance ) ) { break; // do not drag if we're within tolerance from origin } // Once the user has moved farther than tolerance from the original location // (indicating they intend to draw, not click), then always process the // motion notify coordinates as given (no snapping back to origin) - event_context->within_tolerance = false; + this->within_tolerance = false; Geom::Point const motion_pt(event->motion.x, event->motion.y); Geom::Point p = desktop->w2d(motion_pt); @@ -639,15 +598,16 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd gobble_motion_events(GDK_BUTTON1_MASK); // status text - Inkscape::Util::Quantity x_q = Inkscape::Util::Quantity(fabs((p - tc->p0)[Geom::X]), "px"); - Inkscape::Util::Quantity y_q = Inkscape::Util::Quantity(fabs((p - tc->p0)[Geom::Y]), "px"); + Inkscape::Util::Quantity x_q = Inkscape::Util::Quantity(fabs((p - this->p0)[Geom::X]), "px"); + Inkscape::Util::Quantity y_q = Inkscape::Util::Quantity(fabs((p - this->p0)[Geom::Y]), "px"); GString *xs = g_string_new(x_q.string(*desktop->namedview->doc_units).c_str()); GString *ys = g_string_new(y_q.string(*desktop->namedview->doc_units).c_str()); - event_context->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Flowed text frame</b>: %s × %s"), xs->str, ys->str); + this->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Flowed text frame</b>: %s × %s"), xs->str, ys->str); + g_string_free(xs, FALSE); g_string_free(ys, FALSE); - } else if (!sp_event_context_knot_mouseover(event_context)) { + } else if (!sp_event_context_knot_mouseover(this)) { SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); @@ -658,8 +618,8 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd } break; case GDK_BUTTON_RELEASE: - if (event->button.button == 1 && !event_context->space_panning) { - sp_event_context_discard_delayed_snap_event(event_context); + if (event->button.button == 1 && !this->space_panning) { + sp_event_context_discard_delayed_snap_event(this); Geom::Point p1 = desktop->w2d(Geom::Point(event->button.x, event->button.y)); @@ -668,46 +628,46 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd m.freeSnapReturnByRef(p1, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); - if (tc->grabbed) { - sp_canvas_item_ungrab(tc->grabbed, GDK_CURRENT_TIME); - tc->grabbed = NULL; + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, GDK_CURRENT_TIME); + this->grabbed = NULL; } Inkscape::Rubberband::get(desktop)->stop(); - if (tc->creating && event_context->within_tolerance) { + if (this->creating && this->within_tolerance) { /* Button 1, set X & Y & new item */ sp_desktop_selection(desktop)->clear(); - tc->pdoc = desktop->dt2doc(p1); - tc->show = TRUE; - tc->phase = 1; - tc->nascent_object = 1; // new object was just created + this->pdoc = desktop->dt2doc(p1); + this->show = TRUE; + this->phase = 1; + this->nascent_object = 1; // new object was just created /* Cursor */ - sp_canvas_item_show(tc->cursor); + sp_canvas_item_show(this->cursor); // Cursor height is defined by the new text object's font size; it needs to be set // artificially here, for the text object does not exist yet: double cursor_height = sp_desktop_get_font_size_tool(desktop); - tc->cursor->setCoords(p1, p1 + Geom::Point(0, cursor_height)); - if (tc->imc) { + this->cursor->setCoords(p1, p1 + Geom::Point(0, cursor_height)); + if (this->imc) { GdkRectangle im_cursor; - Geom::Point const top_left = SP_EVENT_CONTEXT(tc)->desktop->get_display_area().corner(3); + Geom::Point const top_left = SP_EVENT_CONTEXT(this)->desktop->get_display_area().corner(3); Geom::Point const cursor_size(0, cursor_height); - Geom::Point const im_position = SP_EVENT_CONTEXT(tc)->desktop->d2w(p1 + cursor_size - top_left); + Geom::Point const im_position = SP_EVENT_CONTEXT(this)->desktop->d2w(p1 + cursor_size - top_left); im_cursor.x = (int) floor(im_position[Geom::X]); im_cursor.y = (int) floor(im_position[Geom::Y]); im_cursor.width = 0; - im_cursor.height = (int) -floor(SP_EVENT_CONTEXT(tc)->desktop->d2w(cursor_size)[Geom::Y]); - gtk_im_context_set_cursor_location(tc->imc, &im_cursor); + im_cursor.height = (int) -floor(SP_EVENT_CONTEXT(this)->desktop->d2w(cursor_size)[Geom::Y]); + gtk_im_context_set_cursor_location(this->imc, &im_cursor); } - event_context->_message_context->set(Inkscape::NORMAL_MESSAGE, _("Type text; <b>Enter</b> to start new line.")); // FIXME:: this is a copy of a string from _update_cursor below, do not desync + this->message_context->set(Inkscape::NORMAL_MESSAGE, _("Type text; <b>Enter</b> to start new line.")); // FIXME:: this is a copy of a string from _update_cursor below, do not desync - event_context->within_tolerance = false; - } else if (tc->creating) { + this->within_tolerance = false; + } else if (this->creating) { double cursor_height = sp_desktop_get_font_size_tool(desktop); - if (fabs(p1[Geom::Y] - tc->p0[Geom::Y]) > cursor_height) { + if (fabs(p1[Geom::Y] - this->p0[Geom::Y]) > cursor_height) { // otherwise even one line won't fit; most probably a slip of hand (even if bigger than tolerance) - SPItem *ft = create_flowtext_with_internal_frame (desktop, tc->p0, p1); + SPItem *ft = create_flowtext_with_internal_frame (desktop, this->p0, p1); /* Set style */ sp_desktop_apply_style_tool(desktop, ft->getRepr(), "/tools/text", true); sp_desktop_selection(desktop)->set(ft); @@ -718,7 +678,7 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("The frame is <b>too small</b> for the current font size. Flowed text not created.")); } } - tc->creating = false; + this->creating = false; return TRUE; } break; @@ -731,16 +691,16 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd break; // otherwise pass on keypad +/- so they can zoom } - if ((tc->text) || (tc->nascent_object)) { + if ((this->text) || (this->nascent_object)) { // there is an active text object in this context, or a new object was just created - if (tc->unimode || !tc->imc + if (this->unimode || !this->imc || (MOD__CTRL(event) && MOD__SHIFT(event)) // input methods tend to steal this for unimode, // but we have our own so make sure they don't swallow it - || !gtk_im_context_filter_keypress(tc->imc, (GdkEventKey*) event)) { + || !gtk_im_context_filter_keypress(this->imc, (GdkEventKey*) event)) { //IM did not consume the key, or we're in unimode - if (!MOD__CTRL_ONLY(event) && tc->unimode) { + if (!MOD__CTRL_ONLY(event) && this->unimode) { /* TODO: ISO 14755 (section 3 Definitions) says that we should also accept the first 6 characters of alphabets other than the latin alphabet "if the Latin alphabet is not used". The below is also @@ -751,39 +711,39 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd switch (group0_keyval) { case GDK_KEY_space: case GDK_KEY_KP_Space: { - if (tc->unipos) { - insert_uni_char(tc); + if (this->unipos) { + insert_uni_char(this); } /* Stay in unimode. */ - show_curr_uni_char(tc); + show_curr_uni_char(this); return TRUE; } case GDK_KEY_BackSpace: { - g_return_val_if_fail(tc->unipos < sizeof(tc->uni), TRUE); - if (tc->unipos) { - tc->uni[--tc->unipos] = '\0'; + g_return_val_if_fail(this->unipos < sizeof(this->uni), TRUE); + if (this->unipos) { + this->uni[--this->unipos] = '\0'; } - show_curr_uni_char(tc); + show_curr_uni_char(this); return TRUE; } case GDK_KEY_Return: case GDK_KEY_KP_Enter: { - if (tc->unipos) { - insert_uni_char(tc); + if (this->unipos) { + insert_uni_char(this); } /* Exit unimode. */ - tc->unimode = false; - event_context->defaultMessageContext()->clear(); + this->unimode = false; + this->defaultMessageContext()->clear(); return TRUE; } case GDK_KEY_Escape: { // Cancel unimode. - tc->unimode = false; - gtk_im_context_reset(tc->imc); - event_context->defaultMessageContext()->clear(); + this->unimode = false; + gtk_im_context_reset(this->imc); + this->defaultMessageContext()->clear(); return TRUE; } @@ -793,10 +753,10 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd default: { if (g_ascii_isxdigit(group0_keyval)) { - g_return_val_if_fail(tc->unipos < sizeof(tc->uni) - 1, TRUE); - tc->uni[tc->unipos++] = group0_keyval; - tc->uni[tc->unipos] = '\0'; - if (tc->unipos == 8) { + g_return_val_if_fail(this->unipos < sizeof(this->uni) - 1, TRUE); + this->uni[this->unipos++] = group0_keyval; + this->uni[this->unipos] = '\0'; + if (this->unipos == 8) { /* This behaviour is partly to allow us to continue to use a fixed-length buffer for tc->uni. Reason for choosing the number 8 is that it's the length of @@ -804,9 +764,9 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd An advantage over choosing 6 is that it allows using backspace for typos & misremembering when entering a 6-digit number. */ - insert_uni_char(tc); + insert_uni_char(this); } - show_curr_uni_char(tc); + show_curr_uni_char(this); return TRUE; } else { /* The intent is to ignore but consume characters that could be @@ -820,12 +780,12 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd } } - Inkscape::Text::Layout::iterator old_start = tc->text_sel_start; - Inkscape::Text::Layout::iterator old_end = tc->text_sel_end; + Inkscape::Text::Layout::iterator old_start = this->text_sel_start; + Inkscape::Text::Layout::iterator old_end = this->text_sel_end; bool cursor_moved = false; int screenlines = 1; - if (tc->text) { - double spacing = sp_te_get_average_linespacing(tc->text); + if (this->text) { + double spacing = sp_te_get_average_linespacing(this->text); Geom::Rect const d = desktop->get_display_area(); screenlines = (int) floor(fabs(d.min()[Geom::Y] - d.max()[Geom::Y])/spacing) - 1; if (screenlines <= 0) @@ -844,13 +804,13 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd case GDK_KEY_space: if (MOD__CTRL_ONLY(event)) { /* No-break space */ - if (!tc->text) { // printable key; create text if none (i.e. if nascent_object) - sp_text_context_setup_text(tc); - tc->nascent_object = 0; // we don't need it anymore, having created a real <text> + if (!this->text) { // printable key; create text if none (i.e. if nascent_object) + sp_text_context_setup_text(this); + this->nascent_object = 0; // we don't need it anymore, having created a real <text> } - tc->text_sel_start = tc->text_sel_end = sp_te_replace(tc->text, tc->text_sel_start, tc->text_sel_end, "\302\240"); - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + this->text_sel_start = this->text_sel_end = sp_te_replace(this->text, this->text_sel_start, this->text_sel_end, "\302\240"); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("No-break space")); DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Insert no-break space")); @@ -860,24 +820,24 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd case GDK_KEY_U: case GDK_KEY_u: if (MOD__CTRL_ONLY(event) || (MOD__CTRL(event) && MOD__SHIFT(event))) { - if (tc->unimode) { - tc->unimode = false; - event_context->defaultMessageContext()->clear(); + if (this->unimode) { + this->unimode = false; + this->defaultMessageContext()->clear(); } else { - tc->unimode = true; - tc->unipos = 0; - event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("Unicode (<b>Enter</b> to finish): ")); + this->unimode = true; + this->unipos = 0; + this->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("Unicode (<b>Enter</b> to finish): ")); } - if (tc->imc) { - gtk_im_context_reset(tc->imc); + if (this->imc) { + gtk_im_context_reset(this->imc); } return TRUE; } break; case GDK_KEY_B: case GDK_KEY_b: - if (MOD__CTRL_ONLY(event) && tc->text) { - SPStyle const *style = sp_te_style_at_position(tc->text, std::min(tc->text_sel_start, tc->text_sel_end)); + if (MOD__CTRL_ONLY(event) && this->text) { + SPStyle const *style = sp_te_style_at_position(this->text, std::min(this->text_sel_start, this->text_sel_end)); SPCSSAttr *css = sp_repr_css_attr_new(); if (style->font_weight.computed == SP_CSS_FONT_WEIGHT_NORMAL || style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 @@ -887,43 +847,43 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd sp_repr_css_set_property(css, "font-weight", "bold"); else sp_repr_css_set_property(css, "font-weight", "normal"); - sp_te_apply_style(tc->text, tc->text_sel_start, tc->text_sel_end, css); + sp_te_apply_style(this->text, this->text_sel_start, this->text_sel_end, css); sp_repr_css_attr_unref(css); DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Make bold")); - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); return TRUE; } break; case GDK_KEY_I: case GDK_KEY_i: - if (MOD__CTRL_ONLY(event) && tc->text) { - SPStyle const *style = sp_te_style_at_position(tc->text, std::min(tc->text_sel_start, tc->text_sel_end)); + if (MOD__CTRL_ONLY(event) && this->text) { + SPStyle const *style = sp_te_style_at_position(this->text, std::min(this->text_sel_start, this->text_sel_end)); SPCSSAttr *css = sp_repr_css_attr_new(); if (style->font_style.computed != SP_CSS_FONT_STYLE_NORMAL) sp_repr_css_set_property(css, "font-style", "normal"); else sp_repr_css_set_property(css, "font-style", "italic"); - sp_te_apply_style(tc->text, tc->text_sel_start, tc->text_sel_end, css); + sp_te_apply_style(this->text, this->text_sel_start, this->text_sel_end, css); sp_repr_css_attr_unref(css); DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Make italic")); - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); return TRUE; } break; case GDK_KEY_A: case GDK_KEY_a: - if (MOD__CTRL_ONLY(event) && tc->text) { - Inkscape::Text::Layout const *layout = te_get_layout(tc->text); + if (MOD__CTRL_ONLY(event) && this->text) { + Inkscape::Text::Layout const *layout = te_get_layout(this->text); if (layout) { - tc->text_sel_start = layout->begin(); - tc->text_sel_end = layout->end(); - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + this->text_sel_start = layout->begin(); + this->text_sel_end = layout->end(); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); return TRUE; } } @@ -932,101 +892,101 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd case GDK_KEY_Return: case GDK_KEY_KP_Enter: { - if (!tc->text) { // printable key; create text if none (i.e. if nascent_object) - sp_text_context_setup_text(tc); - tc->nascent_object = 0; // we don't need it anymore, having created a real <text> + if (!this->text) { // printable key; create text if none (i.e. if nascent_object) + sp_text_context_setup_text(this); + this->nascent_object = 0; // we don't need it anymore, having created a real <text> } iterator_pair enter_pair; - bool success = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, enter_pair); + bool success = sp_te_delete(this->text, this->text_sel_start, this->text_sel_end, enter_pair); (void)success; // TODO cleanup - tc->text_sel_start = tc->text_sel_end = enter_pair.first; + this->text_sel_start = this->text_sel_end = enter_pair.first; - tc->text_sel_start = tc->text_sel_end = sp_te_insert_line(tc->text, tc->text_sel_start); + this->text_sel_start = this->text_sel_end = sp_te_insert_line(this->text, this->text_sel_start); - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("New line")); return TRUE; } case GDK_KEY_BackSpace: - if (tc->text) { // if nascent_object, do nothing, but return TRUE; same for all other delete and move keys + if (this->text) { // if nascent_object, do nothing, but return TRUE; same for all other delete and move keys bool noSelection = false; if (MOD__CTRL(event)) { - tc->text_sel_start = tc->text_sel_end; + this->text_sel_start = this->text_sel_end; } - if (tc->text_sel_start == tc->text_sel_end) { + if (this->text_sel_start == this->text_sel_end) { if (MOD__CTRL(event)) { - tc->text_sel_start.prevStartOfWord(); + this->text_sel_start.prevStartOfWord(); } else { - tc->text_sel_start.prevCursorPosition(); + this->text_sel_start.prevCursorPosition(); } noSelection = true; } iterator_pair bspace_pair; - bool success = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, bspace_pair); + bool success = sp_te_delete(this->text, this->text_sel_start, this->text_sel_end, bspace_pair); if (noSelection) { if (success) { - tc->text_sel_start = tc->text_sel_end = bspace_pair.first; + this->text_sel_start = this->text_sel_end = bspace_pair.first; } else { // nothing deleted - tc->text_sel_start = tc->text_sel_end = bspace_pair.second; + this->text_sel_start = this->text_sel_end = bspace_pair.second; } } else { if (success) { - tc->text_sel_start = tc->text_sel_end = bspace_pair.first; + this->text_sel_start = this->text_sel_end = bspace_pair.first; } else { // nothing deleted - tc->text_sel_start = bspace_pair.first; - tc->text_sel_end = bspace_pair.second; + this->text_sel_start = bspace_pair.first; + this->text_sel_end = bspace_pair.second; } } - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Backspace")); } return TRUE; case GDK_KEY_Delete: case GDK_KEY_KP_Delete: - if (tc->text) { + if (this->text) { bool noSelection = false; if (MOD__CTRL(event)) { - tc->text_sel_start = tc->text_sel_end; + this->text_sel_start = this->text_sel_end; } - if (tc->text_sel_start == tc->text_sel_end) { + if (this->text_sel_start == this->text_sel_end) { if (MOD__CTRL(event)) { - tc->text_sel_end.nextEndOfWord(); + this->text_sel_end.nextEndOfWord(); } else { - tc->text_sel_end.nextCursorPosition(); + this->text_sel_end.nextCursorPosition(); } noSelection = true; } iterator_pair del_pair; - bool success = sp_te_delete(tc->text, tc->text_sel_start, tc->text_sel_end, del_pair); + bool success = sp_te_delete(this->text, this->text_sel_start, this->text_sel_end, del_pair); if (noSelection) { - tc->text_sel_start = tc->text_sel_end = del_pair.first; + this->text_sel_start = this->text_sel_end = del_pair.first; } else { if (success) { - tc->text_sel_start = tc->text_sel_end = del_pair.first; + this->text_sel_start = this->text_sel_end = del_pair.first; } else { // nothing deleted - tc->text_sel_start = del_pair.first; - tc->text_sel_end = del_pair.second; + this->text_sel_start = del_pair.first; + this->text_sel_end = del_pair.second; } } - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Delete")); } @@ -1034,23 +994,23 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd case GDK_KEY_Left: case GDK_KEY_KP_Left: case GDK_KEY_KP_4: - if (tc->text) { + if (this->text) { if (MOD__ALT(event)) { gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__SHIFT(event)) - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(mul*-10, 0)); + sp_te_adjust_kerning_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, Geom::Point(mul*-10, 0)); else - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(mul*-1, 0)); - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + sp_te_adjust_kerning_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, Geom::Point(mul*-1, 0)); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); DocumentUndo::maybeDone(sp_desktop_document(desktop), "kern:left", SP_VERB_CONTEXT_TEXT, _("Kern to the left")); } else { if (MOD__CTRL(event)) - tc->text_sel_end.cursorLeftWithControl(); + this->text_sel_end.cursorLeftWithControl(); else - tc->text_sel_end.cursorLeft(); + this->text_sel_end.cursorLeft(); cursor_moved = true; break; } @@ -1059,23 +1019,23 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd case GDK_KEY_Right: case GDK_KEY_KP_Right: case GDK_KEY_KP_6: - if (tc->text) { + if (this->text) { if (MOD__ALT(event)) { gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__SHIFT(event)) - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(mul*10, 0)); + sp_te_adjust_kerning_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, Geom::Point(mul*10, 0)); else - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(mul*1, 0)); - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + sp_te_adjust_kerning_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, Geom::Point(mul*1, 0)); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); DocumentUndo::maybeDone(sp_desktop_document(desktop), "kern:right", SP_VERB_CONTEXT_TEXT, _("Kern to the right")); } else { if (MOD__CTRL(event)) - tc->text_sel_end.cursorRightWithControl(); + this->text_sel_end.cursorRightWithControl(); else - tc->text_sel_end.cursorRight(); + this->text_sel_end.cursorRight(); cursor_moved = true; break; } @@ -1084,23 +1044,23 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd case GDK_KEY_Up: case GDK_KEY_KP_Up: case GDK_KEY_KP_8: - if (tc->text) { + if (this->text) { if (MOD__ALT(event)) { gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__SHIFT(event)) - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(0, mul*-10)); + sp_te_adjust_kerning_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, Geom::Point(0, mul*-10)); else - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(0, mul*-1)); - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + sp_te_adjust_kerning_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, Geom::Point(0, mul*-1)); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); DocumentUndo::maybeDone(sp_desktop_document(desktop), "kern:up", SP_VERB_CONTEXT_TEXT, _("Kern up")); } else { if (MOD__CTRL(event)) - tc->text_sel_end.cursorUpWithControl(); + this->text_sel_end.cursorUpWithControl(); else - tc->text_sel_end.cursorUp(); + this->text_sel_end.cursorUp(); cursor_moved = true; break; } @@ -1109,23 +1069,23 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd case GDK_KEY_Down: case GDK_KEY_KP_Down: case GDK_KEY_KP_2: - if (tc->text) { + if (this->text) { if (MOD__ALT(event)) { gint mul = 1 + gobble_key_events( get_group0_keyval(&event->key), 0); // with any mask if (MOD__SHIFT(event)) - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(0, mul*10)); + sp_te_adjust_kerning_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, Geom::Point(0, mul*10)); else - sp_te_adjust_kerning_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, Geom::Point(0, mul*1)); - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + sp_te_adjust_kerning_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, Geom::Point(0, mul*1)); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); DocumentUndo::maybeDone(sp_desktop_document(desktop), "kern:down", SP_VERB_CONTEXT_TEXT, _("Kern down")); } else { if (MOD__CTRL(event)) - tc->text_sel_end.cursorDownWithControl(); + this->text_sel_end.cursorDownWithControl(); else - tc->text_sel_end.cursorDown(); + this->text_sel_end.cursorDown(); cursor_moved = true; break; } @@ -1133,143 +1093,143 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd return TRUE; case GDK_KEY_Home: case GDK_KEY_KP_Home: - if (tc->text) { + if (this->text) { if (MOD__CTRL(event)) - tc->text_sel_end.thisStartOfShape(); + this->text_sel_end.thisStartOfShape(); else - tc->text_sel_end.thisStartOfLine(); + this->text_sel_end.thisStartOfLine(); cursor_moved = true; break; } return TRUE; case GDK_KEY_End: case GDK_KEY_KP_End: - if (tc->text) { + if (this->text) { if (MOD__CTRL(event)) - tc->text_sel_end.nextStartOfShape(); + this->text_sel_end.nextStartOfShape(); else - tc->text_sel_end.thisEndOfLine(); + this->text_sel_end.thisEndOfLine(); cursor_moved = true; break; } return TRUE; case GDK_KEY_Page_Down: case GDK_KEY_KP_Page_Down: - if (tc->text) { - tc->text_sel_end.cursorDown(screenlines); + if (this->text) { + this->text_sel_end.cursorDown(screenlines); cursor_moved = true; break; } return TRUE; case GDK_KEY_Page_Up: case GDK_KEY_KP_Page_Up: - if (tc->text) { - tc->text_sel_end.cursorUp(screenlines); + if (this->text) { + this->text_sel_end.cursorUp(screenlines); cursor_moved = true; break; } return TRUE; case GDK_KEY_Escape: - if (tc->creating) { - tc->creating = 0; - if (tc->grabbed) { - sp_canvas_item_ungrab(tc->grabbed, GDK_CURRENT_TIME); - tc->grabbed = NULL; + if (this->creating) { + this->creating = 0; + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, GDK_CURRENT_TIME); + this->grabbed = NULL; } Inkscape::Rubberband::get(desktop)->stop(); } else { sp_desktop_selection(desktop)->clear(); } - tc->nascent_object = FALSE; + this->nascent_object = FALSE; return TRUE; case GDK_KEY_bracketleft: - if (tc->text) { + if (this->text) { if (MOD__ALT(event) || MOD__CTRL(event)) { if (MOD__ALT(event)) { if (MOD__SHIFT(event)) { // FIXME: alt+shift+[] does not work, don't know why - sp_te_adjust_rotation_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -10); + sp_te_adjust_rotation_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, -10); } else { - sp_te_adjust_rotation_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -1); + sp_te_adjust_rotation_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, -1); } } else { - sp_te_adjust_rotation(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -90); + sp_te_adjust_rotation(this->text, this->text_sel_start, this->text_sel_end, desktop, -90); } DocumentUndo::maybeDone(sp_desktop_document(desktop), "textrot:ccw", SP_VERB_CONTEXT_TEXT, _("Rotate counterclockwise")); - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); return TRUE; } } break; case GDK_KEY_bracketright: - if (tc->text) { + if (this->text) { if (MOD__ALT(event) || MOD__CTRL(event)) { if (MOD__ALT(event)) { if (MOD__SHIFT(event)) { // FIXME: alt+shift+[] does not work, don't know why - sp_te_adjust_rotation_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 10); + sp_te_adjust_rotation_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, 10); } else { - sp_te_adjust_rotation_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 1); + sp_te_adjust_rotation_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, 1); } } else { - sp_te_adjust_rotation(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 90); + sp_te_adjust_rotation(this->text, this->text_sel_start, this->text_sel_end, desktop, 90); } DocumentUndo::maybeDone(sp_desktop_document(desktop), "textrot:cw", SP_VERB_CONTEXT_TEXT, _("Rotate clockwise")); - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); return TRUE; } } break; case GDK_KEY_less: case GDK_KEY_comma: - if (tc->text) { + if (this->text) { if (MOD__ALT(event)) { if (MOD__CTRL(event)) { if (MOD__SHIFT(event)) - sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -10); + sp_te_adjust_linespacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, -10); else - sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -1); + sp_te_adjust_linespacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, -1); DocumentUndo::maybeDone(sp_desktop_document(desktop), "linespacing:dec", SP_VERB_CONTEXT_TEXT, _("Contract line spacing")); } else { if (MOD__SHIFT(event)) - sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -10); + sp_te_adjust_tspan_letterspacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, -10); else - sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, -1); + sp_te_adjust_tspan_letterspacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, -1); DocumentUndo::maybeDone(sp_desktop_document(desktop), "letterspacing:dec", SP_VERB_CONTEXT_TEXT, _("Contract letter spacing")); } - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); return TRUE; } } break; case GDK_KEY_greater: case GDK_KEY_period: - if (tc->text) { + if (this->text) { if (MOD__ALT(event)) { if (MOD__CTRL(event)) { if (MOD__SHIFT(event)) - sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 10); + sp_te_adjust_linespacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, 10); else - sp_te_adjust_linespacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 1); + sp_te_adjust_linespacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, 1); DocumentUndo::maybeDone(sp_desktop_document(desktop), "linespacing:inc", SP_VERB_CONTEXT_TEXT, _("Expand line spacing")); } else { if (MOD__SHIFT(event)) - sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 10); + sp_te_adjust_tspan_letterspacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, 10); else - sp_te_adjust_tspan_letterspacing_screen(tc->text, tc->text_sel_start, tc->text_sel_end, desktop, 1); + sp_te_adjust_tspan_letterspacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, 1); DocumentUndo::maybeDone(sp_desktop_document(desktop), "letterspacing:inc", SP_VERB_CONTEXT_TEXT, _("Expand letter spacing"));\ } - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); return TRUE; } } @@ -1280,10 +1240,10 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd if (cursor_moved) { if (!MOD__SHIFT(event)) - tc->text_sel_start = tc->text_sel_end; - if (old_start != tc->text_sel_start || old_end != tc->text_sel_end) { - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + this->text_sel_start = this->text_sel_end; + if (old_start != this->text_sel_start || old_end != this->text_sel_end) { + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); } return TRUE; } @@ -1298,11 +1258,11 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd && !MOD__CTRL_ONLY(event)) { return TRUE; } else if (group0_keyval == GDK_KEY_Escape) { // cancel rubberband - if (tc->creating) { - tc->creating = 0; - if (tc->grabbed) { - sp_canvas_item_ungrab(tc->grabbed, GDK_CURRENT_TIME); - tc->grabbed = NULL; + if (this->creating) { + this->creating = 0; + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, GDK_CURRENT_TIME); + this->grabbed = NULL; } Inkscape::Rubberband::get(desktop)->stop(); } @@ -1315,7 +1275,7 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd } case GDK_KEY_RELEASE: - if (!tc->unimode && tc->imc && gtk_im_context_filter_keypress(tc->imc, (GdkEventKey*) event)) { + if (!this->unimode && this->imc && gtk_im_context_filter_keypress(this->imc, (GdkEventKey*) event)) { return TRUE; } break; @@ -1324,11 +1284,13 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd } // if nobody consumed it so far - if ((SP_EVENT_CONTEXT_CLASS(sp_text_context_parent_class))->root_handler) { // and there's a handler in parent context, - return (SP_EVENT_CONTEXT_CLASS(sp_text_context_parent_class))->root_handler(event_context, event); // send event to parent - } else { - return FALSE; // return "I did nothing" value so that global shortcuts can be activated - } +// if ((SP_EVENT_CONTEXT_CLASS(sp_text_context_parent_class))->root_handler) { // and there's a handler in parent context, +// return (SP_EVENT_CONTEXT_CLASS(sp_text_context_parent_class))->root_handler(event_context, event); // send event to parent +// } else { +// return FALSE; // return "I did nothing" value so that global shortcuts can be activated +// } + return SPEventContext::root_handler(event); + } /** @@ -1645,9 +1607,9 @@ static void sp_text_context_update_cursor(SPTextContext *tc, bool scroll_to_see } } - SP_EVENT_CONTEXT(tc)->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("Type or edit flowed text (%d characters%s); <b>Enter</b> to start new paragraph."), nChars, trunc); + SP_EVENT_CONTEXT(tc)->message_context->setF(Inkscape::NORMAL_MESSAGE, _("Type or edit flowed text (%d characters%s); <b>Enter</b> to start new paragraph."), nChars, trunc); } else { - SP_EVENT_CONTEXT(tc)->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("Type or edit text (%d characters%s); <b>Enter</b> to start new line."), nChars, trunc); + SP_EVENT_CONTEXT(tc)->message_context->setF(Inkscape::NORMAL_MESSAGE, _("Type or edit text (%d characters%s); <b>Enter</b> to start new line."), nChars, trunc); } } else { @@ -1655,7 +1617,7 @@ static void sp_text_context_update_cursor(SPTextContext *tc, bool scroll_to_see sp_canvas_item_hide(tc->frame); tc->show = FALSE; if (!tc->nascent_object) { - SP_EVENT_CONTEXT(tc)->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> to select or create text, <b>drag</b> to create flowed text; then type.")); // FIXME: this is a copy of string from tools-switch, do not desync + SP_EVENT_CONTEXT(tc)->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> to select or create text, <b>drag</b> to create flowed text; then type.")); // FIXME: this is a copy of string from tools-switch, do not desync } } diff --git a/src/text-context.h b/src/text-context.h index a33c69e0a..95b812c2b 100644 --- a/src/text-context.h +++ b/src/text-context.h @@ -23,15 +23,15 @@ #include <2geom/point.h> #include "libnrtype/Layout-TNG.h" -#define SP_TYPE_TEXT_CONTEXT (sp_text_context_get_type ()) -#define SP_TEXT_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_TEXT_CONTEXT, SPTextContext)) -#define SP_TEXT_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_TEXT_CONTEXT, SPTextContextClass)) -#define SP_IS_TEXT_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_TEXT_CONTEXT)) -#define SP_IS_TEXT_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_TEXT_CONTEXT)) +#define SP_TEXT_CONTEXT(obj) (dynamic_cast<SPTextContext*>((SPEventContext*)obj)) +#define SP_IS_TEXT_CONTEXT(obj) (dynamic_cast<const SPTextContext*>((const SPEventContext*)obj) != NULL) struct SPCtrlLine; -struct SPTextContext : public SPEventContext { +class SPTextContext : public SPEventContext { +public: + SPTextContext(); + virtual ~SPTextContext(); sigc::connection sel_changed_connection; sigc::connection sel_modified_connection; @@ -71,14 +71,16 @@ struct SPTextContext : public SPEventContext { /* Preedit String */ gchar* preedit_string; -}; -struct SPTextContextClass { - SPEventContextClass parent_class; -}; + static const std::string prefsPath; -/* Standard Gtk function */ -GType sp_text_context_get_type (void); + virtual void setup(); + virtual void finish(); + virtual bool root_handler(GdkEvent* event); + virtual bool item_handler(SPItem* item, GdkEvent* event); + + virtual const std::string& getPrefsPath(); +}; bool sp_text_paste_inline(SPEventContext *ec); Glib::ustring sp_text_get_selected_text(SPEventContext const *ec); diff --git a/src/tool-factory.h b/src/tool-factory.h new file mode 100644 index 000000000..d8aeb5f04 --- /dev/null +++ b/src/tool-factory.h @@ -0,0 +1,31 @@ +/** @file + * Factory for SPEventContext tree + *//* + * Authors: + * Markus Engel + * + * Copyright (C) 2013 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef TOOL_FACTORY_SEEN +#define TOOL_FACTORY_SEEN + +#include "factory.h" + +class SPEventContext; +typedef Singleton< Factory<SPEventContext> > ToolFactory; + + +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/tools-switch.cpp b/src/tools-switch.cpp index 9e7dfa3f9..fd160e518 100644 --- a/src/tools-switch.cpp +++ b/src/tools-switch.cpp @@ -122,136 +122,138 @@ tools_switch(SPDesktop *dt, int num) dt->_tool_changed.emit(num); } + dt->set_event_context2(tool_names[num]); + switch (num) { case TOOLS_SELECT: - dt->set_event_context(SP_TYPE_SELECT_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_SELECT_CONTEXT, tool_names[num]); /* fixme: This is really ugly hack. We should bind and unbind class methods */ dt->activate_guides(true); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); break; case TOOLS_NODES: - dt->set_event_context(INK_TYPE_NODE_TOOL, tool_names[num]); + //dt->set_event_context(INK_TYPE_NODE_TOOL, tool_names[num]); dt->activate_guides(true); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); break; case TOOLS_TWEAK: - dt->set_event_context(SP_TYPE_TWEAK_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_TWEAK_CONTEXT, tool_names[num]); dt->activate_guides(true); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("To tweak a path by pushing, select it and drag over it.")); break; case TOOLS_SPRAY: - dt->set_event_context(SP_TYPE_SPRAY_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_SPRAY_CONTEXT, tool_names[num]); dt->activate_guides(true); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b>, <b>click</b> or <b>click and scroll</b> to spray the selected objects.")); break; case TOOLS_SHAPES_RECT: - dt->set_event_context(SP_TYPE_RECT_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_RECT_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b> to create a rectangle. <b>Drag controls</b> to round corners and resize. <b>Click</b> to select.")); break; case TOOLS_SHAPES_3DBOX: - dt->set_event_context(SP_TYPE_BOX3D_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_BOX3D_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b> to create a 3D box. <b>Drag controls</b> to resize in perspective. <b>Click</b> to select (with <b>Ctrl+Alt</b> for single faces).")); break; case TOOLS_SHAPES_ARC: - dt->set_event_context(SP_TYPE_ARC_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_ARC_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b> to create an ellipse. <b>Drag controls</b> to make an arc or segment. <b>Click</b> to select.")); break; case TOOLS_SHAPES_STAR: - dt->set_event_context(SP_TYPE_STAR_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_STAR_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b> to create a star. <b>Drag controls</b> to edit the star shape. <b>Click</b> to select.")); break; case TOOLS_SHAPES_SPIRAL: - dt->set_event_context(SP_TYPE_SPIRAL_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_SPIRAL_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b> to create a spiral. <b>Drag controls</b> to edit the spiral shape. <b>Click</b> to select.")); break; case TOOLS_FREEHAND_PENCIL: - dt->set_event_context(SP_TYPE_PENCIL_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_PENCIL_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b> to create a freehand line. <b>Shift</b> appends to selected path, <b>Alt</b> activates sketch mode.")); break; case TOOLS_FREEHAND_PEN: - dt->set_event_context(SP_TYPE_PEN_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_PEN_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>click and drag</b> to start a path; with <b>Shift</b> to append to selected path. <b>Ctrl+click</b> to create single dots (straight line modes only).")); break; case TOOLS_CALLIGRAPHIC: - dt->set_event_context(SP_TYPE_DYNA_DRAW_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_DYNA_DRAW_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b> to draw a calligraphic stroke; with <b>Ctrl</b> to track a guide path. <b>Arrow keys</b> adjust width (left/right) and angle (up/down).")); break; case TOOLS_TEXT: - dt->set_event_context(SP_TYPE_TEXT_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_TEXT_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> to select or create text, <b>drag</b> to create flowed text; then type.")); break; case TOOLS_GRADIENT: - dt->set_event_context(SP_TYPE_GRADIENT_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_GRADIENT_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b> or <b>double click</b> to create a gradient on selected objects, <b>drag handles</b> to adjust gradients.")); break; case TOOLS_MESH: - dt->set_event_context(SP_TYPE_MESH_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_MESH_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b> or <b>double click</b> to create a mesh on selected objects, <b>drag handles</b> to adjust meshes.")); break; case TOOLS_ZOOM: - dt->set_event_context(SP_TYPE_ZOOM_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_ZOOM_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>drag around an area</b> to zoom in, <b>Shift+click</b> to zoom out.")); break; case TOOLS_MEASURE: - dt->set_event_context(SP_TYPE_MEASURE_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_MEASURE_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b> to measure the dimensions of objects.")); break; case TOOLS_DROPPER: - dt->set_event_context(SP_TYPE_DROPPER_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_DROPPER_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> to set fill, <b>Shift+click</b> to set stroke; <b>drag</b> to average color in area; with <b>Alt</b> to pick inverse color; <b>Ctrl+C</b> to copy the color under mouse to clipboard")); break; case TOOLS_CONNECTOR: - dt->set_event_context(SP_TYPE_CONNECTOR_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_CONNECTOR_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Click and drag</b> between shapes to create a connector.")); break; case TOOLS_PAINTBUCKET: - dt->set_event_context(SP_TYPE_FLOOD_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_FLOOD_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> to paint a bounded area, <b>Shift+click</b> to union the new fill with the current selection, <b>Ctrl+click</b> to change the clicked object's fill and stroke to the current setting.")); break; case TOOLS_ERASER: - dt->set_event_context(SP_TYPE_ERASER_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_ERASER_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b> to erase.")); break; case TOOLS_LPETOOL: - dt->set_event_context(SP_TYPE_LPETOOL_CONTEXT, tool_names[num]); + //dt->set_event_context(SP_TYPE_LPETOOL_CONTEXT, tool_names[num]); dt->activate_guides(false); - inkscape_eventcontext_set(sp_desktop_event_context(dt)); + inkscape_eventcontext_set(dt->getEventContext()); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("Choose a subtool from the toolbar")); break; } diff --git a/src/tools-switch.h b/src/tools-switch.h index 77fe370c6..280837e87 100644 --- a/src/tools-switch.h +++ b/src/tools-switch.h @@ -18,6 +18,7 @@ namespace Geom { class Point; } + enum { TOOLS_INVALID, TOOLS_SELECT, diff --git a/src/trace/imagemap-gdk.cpp b/src/trace/imagemap-gdk.cpp index 7c7139002..298414074 100644 --- a/src/trace/imagemap-gdk.cpp +++ b/src/trace/imagemap-gdk.cpp @@ -152,9 +152,9 @@ RgbMap *gdkPixbufToRgbMap(GdkPixbuf *buf) { int alpha = (int)p[3]; int white = 255 - alpha; - int r = (int)p[2]; r = r * alpha / 256 + white; + int r = (int)p[0]; r = r * alpha / 256 + white; int g = (int)p[1]; g = g * alpha / 256 + white; - int b = (int)p[0]; b = b * alpha / 256 + white; + int b = (int)p[2]; b = b * alpha / 256 + white; rgbMap->setPixel(rgbMap, x, y, r, g, b); p += n_channels; diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp index cad8ea9be..e2cda6247 100644 --- a/src/trace/trace.cpp +++ b/src/trace/trace.cpp @@ -31,6 +31,7 @@ #include <2geom/transforms.h> #include "verbs.h" +#include "display/cairo-utils.h" #include "display/drawing.h" #include "display/drawing-shape.h" @@ -336,8 +337,17 @@ Glib::RefPtr<Gdk::Pixbuf> Tracer::getSelectedImage() if (!img->pixbuf) return Glib::RefPtr<Gdk::Pixbuf>(NULL); - Glib::RefPtr<Gdk::Pixbuf> pixbuf = - Glib::wrap(img->pixbuf, true); + GdkPixbuf *raw_pb = img->pixbuf->getPixbufRaw(false); + GdkPixbuf *trace_pb = gdk_pixbuf_copy(raw_pb); + if (img->pixbuf->pixelFormat() == Inkscape::Pixbuf::PF_CAIRO) { + convert_pixels_argb32_to_pixbuf( + gdk_pixbuf_get_pixels(trace_pb), + gdk_pixbuf_get_width(trace_pb), + gdk_pixbuf_get_height(trace_pb), + gdk_pixbuf_get_rowstride(trace_pb)); + } + + Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(trace_pb, false); if (sioxEnabled) { @@ -410,7 +420,16 @@ void Tracer::traceThread() return; } - Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(img->pixbuf, true); + GdkPixbuf *trace_pb = gdk_pixbuf_copy(img->pixbuf->getPixbufRaw(false)); + if (img->pixbuf->pixelFormat() == Inkscape::Pixbuf::PF_CAIRO) { + convert_pixels_argb32_to_pixbuf( + gdk_pixbuf_get_pixels(trace_pb), + gdk_pixbuf_get_width(trace_pb), + gdk_pixbuf_get_height(trace_pb), + gdk_pixbuf_get_rowstride(trace_pb)); + } + + Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(trace_pb, false); pixbuf = sioxProcessImage(img, pixbuf); diff --git a/src/trace/trace.h b/src/trace/trace.h index 9f9f44b14..662b2537e 100644 --- a/src/trace/trace.h +++ b/src/trace/trace.h @@ -26,7 +26,7 @@ #include <vector> #include <sp-shape.h> -struct SPImage; +class SPImage; class SPItem; namespace Inkscape { diff --git a/src/tweak-context.cpp b/src/tweak-context.cpp index 58b6f2b54..2171ecbe4 100644 --- a/src/tweak-context.cpp +++ b/src/tweak-context.cpp @@ -90,75 +90,59 @@ using Inkscape::DocumentUndo; #define DYNA_MIN_WIDTH 1.0e-6 -static void sp_tweak_context_dispose(GObject *object); +#include "tool-factory.h" -static void sp_tweak_context_setup(SPEventContext *ec); -static void sp_tweak_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val); -static gint sp_tweak_context_root_handler(SPEventContext *ec, GdkEvent *event); +namespace { + SPEventContext* createTweakContext() { + return new SPTweakContext(); + } -G_DEFINE_TYPE(SPTweakContext, sp_tweak_context, SP_TYPE_EVENT_CONTEXT); - -static void -sp_tweak_context_class_init(SPTweakContextClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - SPEventContextClass *event_context_class = SP_EVENT_CONTEXT_CLASS(klass); - - object_class->dispose = sp_tweak_context_dispose; + bool tweakContextRegistered = ToolFactory::instance().registerObject("/tools/tweak", createTweakContext); +} - event_context_class->setup = sp_tweak_context_setup; - event_context_class->set = sp_tweak_context_set; - event_context_class->root_handler = sp_tweak_context_root_handler; +const std::string& SPTweakContext::getPrefsPath() { + return SPTweakContext::prefsPath; } -static void -sp_tweak_context_init(SPTweakContext *tc) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(tc); +const std::string SPTweakContext::prefsPath = "/tools/tweak"; - event_context->cursor_shape = cursor_push_xpm; - event_context->hot_x = 4; - event_context->hot_y = 4; +SPTweakContext::SPTweakContext() : SPEventContext() { + this->mode = 0; + this->dilate_area = 0; + this->usetilt = 0; + this->usepressure = 0; + this->is_drawing = false; + this->fidelity = 0; - /* attributes */ - tc->dragging = FALSE; + this->cursor_shape = cursor_push_xpm; + this->hot_x = 4; + this->hot_y = 4; - tc->width = 0.2; - tc->force = 0.2; - tc->pressure = TC_DEFAULT_PRESSURE; + /* attributes */ + this->dragging = FALSE; - tc->is_dilating = false; - tc->has_dilated = false; + this->width = 0.2; + this->force = 0.2; + this->pressure = TC_DEFAULT_PRESSURE; - tc->do_h = true; - tc->do_s = true; - tc->do_l = true; - tc->do_o = false; + this->is_dilating = false; + this->has_dilated = false; - new (&tc->style_set_connection) sigc::connection(); + this->do_h = true; + this->do_s = true; + this->do_l = true; + this->do_o = false; } -static void -sp_tweak_context_dispose(GObject *object) -{ - SPTweakContext *tc = SP_TWEAK_CONTEXT(object); - SPEventContext *ec = SP_EVENT_CONTEXT(object); - - ec->enableGrDrag(false); +SPTweakContext::~SPTweakContext() { + this->enableGrDrag(false); - tc->style_set_connection.disconnect(); - tc->style_set_connection.~connection(); - - if (tc->dilate_area) { - sp_canvas_item_destroy(tc->dilate_area); - tc->dilate_area = NULL; - } + this->style_set_connection.disconnect(); - if (tc->_message_context) { - delete tc->_message_context; + if (this->dilate_area) { + sp_canvas_item_destroy(this->dilate_area); + this->dilate_area = NULL; } - - G_OBJECT_CLASS(sp_tweak_context_parent_class)->dispose(object); } static bool is_transform_mode (gint mode) @@ -176,14 +160,10 @@ static bool is_color_mode (gint mode) return (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER || mode == TWEAK_MODE_BLUR); } -static void -sp_tweak_update_cursor (SPTweakContext *tc, bool with_shift) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(tc); - SPDesktop *desktop = event_context->desktop; - +void SPTweakContext::update_cursor (bool with_shift) { guint num = 0; gchar *sel_message = NULL; + if (!desktop->selection->isEmpty()) { num = g_slist_length(const_cast<GSList *>(desktop->selection->itemList())); sel_message = g_strdup_printf(ngettext("<b>%i</b> object selected","<b>%i</b> objects selected",num), num); @@ -191,109 +171,103 @@ sp_tweak_update_cursor (SPTweakContext *tc, bool with_shift) sel_message = g_strdup_printf(_("<b>Nothing</b> selected")); } - switch (tc->mode) { + switch (this->mode) { case TWEAK_MODE_MOVE: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag to <b>move</b>."), sel_message); - event_context->cursor_shape = cursor_tweak_move_xpm; + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag to <b>move</b>."), sel_message); + this->cursor_shape = cursor_tweak_move_xpm; break; case TWEAK_MODE_MOVE_IN_OUT: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>move in</b>; with Shift to <b>move out</b>."), sel_message); + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>move in</b>; with Shift to <b>move out</b>."), sel_message); if (with_shift) { - event_context->cursor_shape = cursor_tweak_move_out_xpm; + this->cursor_shape = cursor_tweak_move_out_xpm; } else { - event_context->cursor_shape = cursor_tweak_move_in_xpm; + this->cursor_shape = cursor_tweak_move_in_xpm; } break; case TWEAK_MODE_MOVE_JITTER: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>move randomly</b>."), sel_message); - event_context->cursor_shape = cursor_tweak_move_jitter_xpm; + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>move randomly</b>."), sel_message); + this->cursor_shape = cursor_tweak_move_jitter_xpm; break; case TWEAK_MODE_SCALE: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>scale down</b>; with Shift to <b>scale up</b>."), sel_message); + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>scale down</b>; with Shift to <b>scale up</b>."), sel_message); if (with_shift) { - event_context->cursor_shape = cursor_tweak_scale_up_xpm; + this->cursor_shape = cursor_tweak_scale_up_xpm; } else { - event_context->cursor_shape = cursor_tweak_scale_down_xpm; + this->cursor_shape = cursor_tweak_scale_down_xpm; } break; case TWEAK_MODE_ROTATE: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>rotate clockwise</b>; with Shift, <b>counterclockwise</b>."), sel_message); + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>rotate clockwise</b>; with Shift, <b>counterclockwise</b>."), sel_message); if (with_shift) { - event_context->cursor_shape = cursor_tweak_rotate_counterclockwise_xpm; + this->cursor_shape = cursor_tweak_rotate_counterclockwise_xpm; } else { - event_context->cursor_shape = cursor_tweak_rotate_clockwise_xpm; + this->cursor_shape = cursor_tweak_rotate_clockwise_xpm; } break; case TWEAK_MODE_MORELESS: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>duplicate</b>; with Shift, <b>delete</b>."), sel_message); + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>duplicate</b>; with Shift, <b>delete</b>."), sel_message); if (with_shift) { - event_context->cursor_shape = cursor_tweak_less_xpm; + this->cursor_shape = cursor_tweak_less_xpm; } else { - event_context->cursor_shape = cursor_tweak_more_xpm; + this->cursor_shape = cursor_tweak_more_xpm; } break; case TWEAK_MODE_PUSH: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag to <b>push paths</b>."), sel_message); - event_context->cursor_shape = cursor_push_xpm; + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag to <b>push paths</b>."), sel_message); + this->cursor_shape = cursor_push_xpm; break; case TWEAK_MODE_SHRINK_GROW: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>inset paths</b>; with Shift to <b>outset</b>."), sel_message); + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>inset paths</b>; with Shift to <b>outset</b>."), sel_message); if (with_shift) { - event_context->cursor_shape = cursor_thicken_xpm; + this->cursor_shape = cursor_thicken_xpm; } else { - event_context->cursor_shape = cursor_thin_xpm; + this->cursor_shape = cursor_thin_xpm; } break; case TWEAK_MODE_ATTRACT_REPEL: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>attract paths</b>; with Shift to <b>repel</b>."), sel_message); + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>attract paths</b>; with Shift to <b>repel</b>."), sel_message); if (with_shift) { - event_context->cursor_shape = cursor_repel_xpm; + this->cursor_shape = cursor_repel_xpm; } else { - event_context->cursor_shape = cursor_attract_xpm; + this->cursor_shape = cursor_attract_xpm; } break; case TWEAK_MODE_ROUGHEN: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>roughen paths</b>."), sel_message); - event_context->cursor_shape = cursor_roughen_xpm; + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>roughen paths</b>."), sel_message); + this->cursor_shape = cursor_roughen_xpm; break; case TWEAK_MODE_COLORPAINT: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>paint objects</b> with color."), sel_message); - event_context->cursor_shape = cursor_color_xpm; + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>paint objects</b> with color."), sel_message); + this->cursor_shape = cursor_color_xpm; break; case TWEAK_MODE_COLORJITTER: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>randomize colors</b>."), sel_message); - event_context->cursor_shape = cursor_color_xpm; + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>randomize colors</b>."), sel_message); + this->cursor_shape = cursor_color_xpm; break; case TWEAK_MODE_BLUR: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>increase blur</b>; with Shift to <b>decrease</b>."), sel_message); - event_context->cursor_shape = cursor_color_xpm; + this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>increase blur</b>; with Shift to <b>decrease</b>."), sel_message); + this->cursor_shape = cursor_color_xpm; break; } - sp_event_context_update_cursor(event_context); + + this->sp_event_context_update_cursor(); g_free(sel_message); } -static bool -sp_tweak_context_style_set(SPCSSAttr const *css, SPTweakContext *tc) -{ - if (tc->mode == TWEAK_MODE_COLORPAINT) { // intercept color setting only in this mode +bool SPTweakContext::set_style(const SPCSSAttr* css) { + if (this->mode == TWEAK_MODE_COLORPAINT) { // intercept color setting only in this mode // we cannot store properties with uris - css = sp_css_attr_unset_uris (const_cast<SPCSSAttr *>(css)); + css = sp_css_attr_unset_uris(const_cast<SPCSSAttr *>(css)); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setStyle("/tools/tweak/style", const_cast<SPCSSAttr*>(css)); + prefs->setStyle("/tools/tweak/style", const_cast<SPCSSAttr *>(css)); return true; } + return false; } -static void -sp_tweak_context_setup(SPEventContext *ec) -{ - SPTweakContext *tc = SP_TWEAK_CONTEXT(ec); - - if ((SP_EVENT_CONTEXT_CLASS(sp_tweak_context_parent_class))->setup) { - (SP_EVENT_CONTEXT_CLASS(sp_tweak_context_parent_class))->setup(ec); - } +void SPTweakContext::setup() { + SPEventContext::setup(); { /* TODO: have a look at sp_dyna_draw_context_setup where the same is done.. generalize? at least make it an arcto! */ @@ -305,65 +279,61 @@ sp_tweak_context_setup(SPEventContext *ec) c->curveto(1, -C1, C1, -1, 0, -1 ); c->curveto(-C1, -1, -1, -C1, -1, 0 ); c->closepath(); - tc->dilate_area = sp_canvas_bpath_new(sp_desktop_controls(ec->desktop), c); + this->dilate_area = sp_canvas_bpath_new(sp_desktop_controls(this->desktop), c); c->unref(); - sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(tc->dilate_area), 0x00000000,(SPWindRule)0); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(tc->dilate_area), 0xff9900ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - sp_canvas_item_hide(tc->dilate_area); + sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(this->dilate_area), 0x00000000,(SPWindRule)0); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->dilate_area), 0xff9900ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); + sp_canvas_item_hide(this->dilate_area); } - tc->is_drawing = false; - - tc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack()); - - sp_event_context_read(ec, "width"); - sp_event_context_read(ec, "mode"); - sp_event_context_read(ec, "fidelity"); - sp_event_context_read(ec, "force"); - sp_event_context_read(ec, "usepressure"); - sp_event_context_read(ec, "doh"); - sp_event_context_read(ec, "dol"); - sp_event_context_read(ec, "dos"); - sp_event_context_read(ec, "doo"); - - tc->style_set_connection = ec->desktop->connectSetStyle( // catch style-setting signal in this tool - sigc::bind(sigc::ptr_fun(&sp_tweak_context_style_set), tc) + this->is_drawing = false; + + sp_event_context_read(this, "width"); + sp_event_context_read(this, "mode"); + sp_event_context_read(this, "fidelity"); + sp_event_context_read(this, "force"); + sp_event_context_read(this, "usepressure"); + sp_event_context_read(this, "doh"); + sp_event_context_read(this, "dol"); + sp_event_context_read(this, "dos"); + sp_event_context_read(this, "doo"); + + this->style_set_connection = this->desktop->connectSetStyle( // catch style-setting signal in this tool + //sigc::bind(sigc::ptr_fun(&sp_tweak_context_style_set), this) + sigc::mem_fun(this, &SPTweakContext::set_style) ); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/tools/tweak/selcue")) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } if (prefs->getBool("/tools/tweak/gradientdrag")) { - ec->enableGrDrag(); + this->enableGrDrag(); } } -static void -sp_tweak_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val) -{ - SPTweakContext *tc = SP_TWEAK_CONTEXT(ec); - Glib::ustring path = val->getEntryName(); +void SPTweakContext::set(const Inkscape::Preferences::Entry& val) { + Glib::ustring path = val.getEntryName(); if (path == "width") { - tc->width = CLAMP(val->getDouble(0.1), -1000.0, 1000.0); + this->width = CLAMP(val.getDouble(0.1), -1000.0, 1000.0); } else if (path == "mode") { - tc->mode = val->getInt(); - sp_tweak_update_cursor(tc, false); + this->mode = val.getInt(); + this->update_cursor(false); } else if (path == "fidelity") { - tc->fidelity = CLAMP(val->getDouble(), 0.0, 1.0); + this->fidelity = CLAMP(val.getDouble(), 0.0, 1.0); } else if (path == "force") { - tc->force = CLAMP(val->getDouble(1.0), 0, 1.0); + this->force = CLAMP(val.getDouble(1.0), 0, 1.0); } else if (path == "usepressure") { - tc->usepressure = val->getBool(); + this->usepressure = val.getBool(); } else if (path == "doh") { - tc->do_h = val->getBool(); + this->do_h = val.getBool(); } else if (path == "dos") { - tc->do_s = val->getBool(); + this->do_s = val.getBool(); } else if (path == "dol") { - tc->do_l = val->getBool(); + this->do_l = val.getBool(); } else if (path == "doo") { - tc->do_o = val->getBool(); + this->do_o = val.getBool(); } } @@ -1157,7 +1127,7 @@ sp_tweak_switch_mode (SPTweakContext *tc, gint mode, bool with_shift) SP_EVENT_CONTEXT(tc)->desktop->setToolboxSelectOneValue ("tweak_tool_mode", mode); // need to set explicitly, because the prefs may not have changed by the previous tc->mode = mode; - sp_tweak_update_cursor (tc, with_shift); + tc->update_cursor(with_shift); } static void @@ -1171,43 +1141,37 @@ sp_tweak_switch_mode_temporarily (SPTweakContext *tc, gint mode, bool with_shift prefs->setInt("/tools/tweak/mode", now_mode); // changing prefs changed tc->mode, restore back :) tc->mode = mode; - sp_tweak_update_cursor (tc, with_shift); + tc->update_cursor(with_shift); } -gint -sp_tweak_context_root_handler(SPEventContext *event_context, - GdkEvent *event) -{ - SPTweakContext *tc = SP_TWEAK_CONTEXT(event_context); - SPDesktop *desktop = event_context->desktop; - +bool SPTweakContext::root_handler(GdkEvent* event) { gint ret = FALSE; switch (event->type) { case GDK_ENTER_NOTIFY: - sp_canvas_item_show(tc->dilate_area); + sp_canvas_item_show(this->dilate_area); break; case GDK_LEAVE_NOTIFY: - sp_canvas_item_hide(tc->dilate_area); + sp_canvas_item_hide(this->dilate_area); break; case GDK_BUTTON_PRESS: - if (event->button.button == 1 && !event_context->space_panning) { + if (event->button.button == 1 && !this->space_panning) { - if (Inkscape::have_viable_layer(desktop, tc->_message_context) == false) { + if (Inkscape::have_viable_layer(desktop, this->message_context) == false) { return TRUE; } Geom::Point const button_w(event->button.x, event->button.y); Geom::Point const button_dt(desktop->w2d(button_w)); - tc->last_push = desktop->dt2doc(button_dt); + this->last_push = desktop->dt2doc(button_dt); - sp_tweak_extinput(tc, event); + sp_tweak_extinput(this, event); desktop->canvas->forceFullRedrawAfterInterruptions(3); - tc->is_drawing = true; - tc->is_dilating = true; - tc->has_dilated = false; + this->is_drawing = true; + this->is_dilating = true; + this->has_dilated = false; ret = TRUE; } @@ -1218,27 +1182,27 @@ sp_tweak_context_root_handler(SPEventContext *event_context, event->motion.y); Geom::Point motion_dt(desktop->w2d(motion_w)); Geom::Point motion_doc(desktop->dt2doc(motion_dt)); - sp_tweak_extinput(tc, event); + sp_tweak_extinput(this, event); // draw the dilating cursor - double radius = get_dilate_radius(tc); + double radius = get_dilate_radius(this); Geom::Affine const sm (Geom::Scale(radius, radius) * Geom::Translate(desktop->w2d(motion_w))); - sp_canvas_item_affine_absolute(tc->dilate_area, sm); - sp_canvas_item_show(tc->dilate_area); + sp_canvas_item_affine_absolute(this->dilate_area, sm); + sp_canvas_item_show(this->dilate_area); guint num = 0; if (!desktop->selection->isEmpty()) { num = g_slist_length(const_cast<GSList *>(desktop->selection->itemList())); } if (num == 0) { - tc->_message_context->flash(Inkscape::ERROR_MESSAGE, _("<b>Nothing selected!</b> Select objects to tweak.")); + this->message_context->flash(Inkscape::ERROR_MESSAGE, _("<b>Nothing selected!</b> Select objects to tweak.")); } // dilating: - if (tc->is_drawing && ( event->motion.state & GDK_BUTTON1_MASK )) { - sp_tweak_dilate (tc, motion_w, motion_doc, motion_doc - tc->last_push, event->button.state & GDK_SHIFT_MASK? true : false); - //tc->last_push = motion_doc; - tc->has_dilated = true; + if (this->is_drawing && ( event->motion.state & GDK_BUTTON1_MASK )) { + sp_tweak_dilate (this, motion_w, motion_doc, motion_doc - this->last_push, event->button.state & GDK_SHIFT_MASK? true : false); + //this->last_push = motion_doc; + this->has_dilated = true; // it's slow, so prevent clogging up with events gobble_motion_events(GDK_BUTTON1_MASK); return TRUE; @@ -1252,67 +1216,67 @@ sp_tweak_context_root_handler(SPEventContext *event_context, Geom::Point const motion_dt(desktop->w2d(motion_w)); desktop->canvas->endForcedFullRedraws(); - tc->is_drawing = false; + this->is_drawing = false; - if (tc->is_dilating && event->button.button == 1 && !event_context->space_panning) { - if (!tc->has_dilated) { + if (this->is_dilating && event->button.button == 1 && !this->space_panning) { + if (!this->has_dilated) { // if we did not rub, do a light tap - tc->pressure = 0.03; - sp_tweak_dilate (tc, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT(event)); + this->pressure = 0.03; + sp_tweak_dilate (this, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT(event)); } - tc->is_dilating = false; - tc->has_dilated = false; - switch (tc->mode) { + this->is_dilating = false; + this->has_dilated = false; + switch (this->mode) { case TWEAK_MODE_MOVE: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_TWEAK, _("Move tweak")); break; case TWEAK_MODE_MOVE_IN_OUT: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_TWEAK, _("Move in/out tweak")); break; case TWEAK_MODE_MOVE_JITTER: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_TWEAK, _("Move jitter tweak")); break; case TWEAK_MODE_SCALE: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_TWEAK, _("Scale tweak")); break; case TWEAK_MODE_ROTATE: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_TWEAK, _("Rotate tweak")); break; case TWEAK_MODE_MORELESS: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_TWEAK, _("Duplicate/delete tweak")); break; case TWEAK_MODE_PUSH: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_TWEAK, _("Push path tweak")); break; case TWEAK_MODE_SHRINK_GROW: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_TWEAK, _("Shrink/grow path tweak")); break; case TWEAK_MODE_ATTRACT_REPEL: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_TWEAK, _("Attract/repel path tweak")); break; case TWEAK_MODE_ROUGHEN: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_TWEAK, _("Roughen path tweak")); break; case TWEAK_MODE_COLORPAINT: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_TWEAK, _("Color paint tweak")); break; case TWEAK_MODE_COLORJITTER: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_TWEAK, _("Color jitter tweak")); break; case TWEAK_MODE_BLUR: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(this)->desktop), SP_VERB_CONTEXT_TWEAK, _("Blur tweak")); break; } @@ -1326,7 +1290,7 @@ sp_tweak_context_root_handler(SPEventContext *event_context, case GDK_KEY_M: case GDK_KEY_0: if (MOD__SHIFT_ONLY(event)) { - sp_tweak_switch_mode(tc, TWEAK_MODE_MOVE, MOD__SHIFT(event)); + sp_tweak_switch_mode(this, TWEAK_MODE_MOVE, MOD__SHIFT(event)); ret = TRUE; } break; @@ -1334,7 +1298,7 @@ sp_tweak_context_root_handler(SPEventContext *event_context, case GDK_KEY_I: case GDK_KEY_1: if (MOD__SHIFT_ONLY(event)) { - sp_tweak_switch_mode(tc, TWEAK_MODE_MOVE_IN_OUT, MOD__SHIFT(event)); + sp_tweak_switch_mode(this, TWEAK_MODE_MOVE_IN_OUT, MOD__SHIFT(event)); ret = TRUE; } break; @@ -1342,7 +1306,7 @@ sp_tweak_context_root_handler(SPEventContext *event_context, case GDK_KEY_Z: case GDK_KEY_2: if (MOD__SHIFT_ONLY(event)) { - sp_tweak_switch_mode(tc, TWEAK_MODE_MOVE_JITTER, MOD__SHIFT(event)); + sp_tweak_switch_mode(this, TWEAK_MODE_MOVE_JITTER, MOD__SHIFT(event)); ret = TRUE; } break; @@ -1352,7 +1316,7 @@ sp_tweak_context_root_handler(SPEventContext *event_context, case GDK_KEY_period: case GDK_KEY_3: if (MOD__SHIFT_ONLY(event)) { - sp_tweak_switch_mode(tc, TWEAK_MODE_SCALE, MOD__SHIFT(event)); + sp_tweak_switch_mode(this, TWEAK_MODE_SCALE, MOD__SHIFT(event)); ret = TRUE; } break; @@ -1360,7 +1324,7 @@ sp_tweak_context_root_handler(SPEventContext *event_context, case GDK_KEY_bracketleft: case GDK_KEY_4: if (MOD__SHIFT_ONLY(event)) { - sp_tweak_switch_mode(tc, TWEAK_MODE_ROTATE, MOD__SHIFT(event)); + sp_tweak_switch_mode(this, TWEAK_MODE_ROTATE, MOD__SHIFT(event)); ret = TRUE; } break; @@ -1368,7 +1332,7 @@ sp_tweak_context_root_handler(SPEventContext *event_context, case GDK_KEY_D: case GDK_KEY_5: if (MOD__SHIFT_ONLY(event)) { - sp_tweak_switch_mode(tc, TWEAK_MODE_MORELESS, MOD__SHIFT(event)); + sp_tweak_switch_mode(this, TWEAK_MODE_MORELESS, MOD__SHIFT(event)); ret = TRUE; } break; @@ -1376,7 +1340,7 @@ sp_tweak_context_root_handler(SPEventContext *event_context, case GDK_KEY_P: case GDK_KEY_6: if (MOD__SHIFT_ONLY(event)) { - sp_tweak_switch_mode(tc, TWEAK_MODE_PUSH, MOD__SHIFT(event)); + sp_tweak_switch_mode(this, TWEAK_MODE_PUSH, MOD__SHIFT(event)); ret = TRUE; } break; @@ -1384,7 +1348,7 @@ sp_tweak_context_root_handler(SPEventContext *event_context, case GDK_KEY_S: case GDK_KEY_7: if (MOD__SHIFT_ONLY(event)) { - sp_tweak_switch_mode(tc, TWEAK_MODE_SHRINK_GROW, MOD__SHIFT(event)); + sp_tweak_switch_mode(this, TWEAK_MODE_SHRINK_GROW, MOD__SHIFT(event)); ret = TRUE; } break; @@ -1392,7 +1356,7 @@ sp_tweak_context_root_handler(SPEventContext *event_context, case GDK_KEY_A: case GDK_KEY_8: if (MOD__SHIFT_ONLY(event)) { - sp_tweak_switch_mode(tc, TWEAK_MODE_ATTRACT_REPEL, MOD__SHIFT(event)); + sp_tweak_switch_mode(this, TWEAK_MODE_ATTRACT_REPEL, MOD__SHIFT(event)); ret = TRUE; } break; @@ -1400,28 +1364,28 @@ sp_tweak_context_root_handler(SPEventContext *event_context, case GDK_KEY_R: case GDK_KEY_9: if (MOD__SHIFT_ONLY(event)) { - sp_tweak_switch_mode(tc, TWEAK_MODE_ROUGHEN, MOD__SHIFT(event)); + sp_tweak_switch_mode(this, TWEAK_MODE_ROUGHEN, MOD__SHIFT(event)); ret = TRUE; } break; case GDK_KEY_c: case GDK_KEY_C: if (MOD__SHIFT_ONLY(event)) { - sp_tweak_switch_mode(tc, TWEAK_MODE_COLORPAINT, MOD__SHIFT(event)); + sp_tweak_switch_mode(this, TWEAK_MODE_COLORPAINT, MOD__SHIFT(event)); ret = TRUE; } break; case GDK_KEY_j: case GDK_KEY_J: if (MOD__SHIFT_ONLY(event)) { - sp_tweak_switch_mode(tc, TWEAK_MODE_COLORJITTER, MOD__SHIFT(event)); + sp_tweak_switch_mode(this, TWEAK_MODE_COLORJITTER, MOD__SHIFT(event)); ret = TRUE; } break; case GDK_KEY_b: case GDK_KEY_B: if (MOD__SHIFT_ONLY(event)) { - sp_tweak_switch_mode(tc, TWEAK_MODE_BLUR, MOD__SHIFT(event)); + sp_tweak_switch_mode(this, TWEAK_MODE_BLUR, MOD__SHIFT(event)); ret = TRUE; } break; @@ -1429,61 +1393,61 @@ sp_tweak_context_root_handler(SPEventContext *event_context, case GDK_KEY_Up: case GDK_KEY_KP_Up: if (!MOD__CTRL_ONLY(event)) { - tc->force += 0.05; - if (tc->force > 1.0) { - tc->force = 1.0; + this->force += 0.05; + if (this->force > 1.0) { + this->force = 1.0; } - desktop->setToolboxAdjustmentValue ("tweak-force", tc->force * 100); + desktop->setToolboxAdjustmentValue ("tweak-force", this->force * 100); ret = TRUE; } break; case GDK_KEY_Down: case GDK_KEY_KP_Down: if (!MOD__CTRL_ONLY(event)) { - tc->force -= 0.05; - if (tc->force < 0.0) { - tc->force = 0.0; + this->force -= 0.05; + if (this->force < 0.0) { + this->force = 0.0; } - desktop->setToolboxAdjustmentValue ("tweak-force", tc->force * 100); + desktop->setToolboxAdjustmentValue ("tweak-force", this->force * 100); ret = TRUE; } break; case GDK_KEY_Right: case GDK_KEY_KP_Right: if (!MOD__CTRL_ONLY(event)) { - tc->width += 0.01; - if (tc->width > 1.0) { - tc->width = 1.0; + this->width += 0.01; + if (this->width > 1.0) { + this->width = 1.0; } - desktop->setToolboxAdjustmentValue ("altx-tweak", tc->width * 100); // the same spinbutton is for alt+x - sp_tweak_update_area(tc); + desktop->setToolboxAdjustmentValue ("altx-tweak", this->width * 100); // the same spinbutton is for alt+x + sp_tweak_update_area(this); ret = TRUE; } break; case GDK_KEY_Left: case GDK_KEY_KP_Left: if (!MOD__CTRL_ONLY(event)) { - tc->width -= 0.01; - if (tc->width < 0.01) { - tc->width = 0.01; + this->width -= 0.01; + if (this->width < 0.01) { + this->width = 0.01; } - desktop->setToolboxAdjustmentValue ("altx-tweak", tc->width * 100); - sp_tweak_update_area(tc); + desktop->setToolboxAdjustmentValue ("altx-tweak", this->width * 100); + sp_tweak_update_area(this); ret = TRUE; } break; case GDK_KEY_Home: case GDK_KEY_KP_Home: - tc->width = 0.01; - desktop->setToolboxAdjustmentValue ("altx-tweak", tc->width * 100); - sp_tweak_update_area(tc); + this->width = 0.01; + desktop->setToolboxAdjustmentValue ("altx-tweak", this->width * 100); + sp_tweak_update_area(this); ret = TRUE; break; case GDK_KEY_End: case GDK_KEY_KP_End: - tc->width = 1.0; - desktop->setToolboxAdjustmentValue ("altx-tweak", tc->width * 100); - sp_tweak_update_area(tc); + this->width = 1.0; + desktop->setToolboxAdjustmentValue ("altx-tweak", this->width * 100); + sp_tweak_update_area(this); ret = TRUE; break; case GDK_KEY_x: @@ -1496,17 +1460,17 @@ sp_tweak_context_root_handler(SPEventContext *event_context, case GDK_KEY_Shift_L: case GDK_KEY_Shift_R: - sp_tweak_update_cursor(tc, true); + this->update_cursor(true); break; case GDK_KEY_Control_L: case GDK_KEY_Control_R: - sp_tweak_switch_mode_temporarily(tc, TWEAK_MODE_SHRINK_GROW, MOD__SHIFT(event)); + sp_tweak_switch_mode_temporarily(this, TWEAK_MODE_SHRINK_GROW, MOD__SHIFT(event)); break; case GDK_KEY_Delete: case GDK_KEY_KP_Delete: case GDK_KEY_BackSpace: - ret = event_context->deleteSelectedDrag(MOD__CTRL_ONLY(event)); + ret = this->deleteSelectedDrag(MOD__CTRL_ONLY(event)); break; default: @@ -1519,15 +1483,15 @@ sp_tweak_context_root_handler(SPEventContext *event_context, switch (get_group0_keyval(&event->key)) { case GDK_KEY_Shift_L: case GDK_KEY_Shift_R: - sp_tweak_update_cursor(tc, false); + this->update_cursor(false); break; case GDK_KEY_Control_L: case GDK_KEY_Control_R: - sp_tweak_switch_mode (tc, prefs->getInt("/tools/tweak/mode"), MOD__SHIFT(event)); - tc->_message_context->clear(); + sp_tweak_switch_mode (this, prefs->getInt("/tools/tweak/mode"), MOD__SHIFT(event)); + this->message_context->clear(); break; default: - sp_tweak_switch_mode (tc, prefs->getInt("/tools/tweak/mode"), MOD__SHIFT(event)); + sp_tweak_switch_mode (this, prefs->getInt("/tools/tweak/mode"), MOD__SHIFT(event)); break; } } @@ -1536,9 +1500,7 @@ sp_tweak_context_root_handler(SPEventContext *event_context, } if (!ret) { - if ((SP_EVENT_CONTEXT_CLASS(sp_tweak_context_parent_class))->root_handler) { - ret = (SP_EVENT_CONTEXT_CLASS(sp_tweak_context_parent_class))->root_handler(event_context, event); - } + ret = SPEventContext::root_handler(event); } return ret; diff --git a/src/tweak-context.h b/src/tweak-context.h index a4567ce6f..da1a50a79 100644 --- a/src/tweak-context.h +++ b/src/tweak-context.h @@ -15,12 +15,6 @@ #include "event-context.h" #include <2geom/point.h> -#define SP_TYPE_TWEAK_CONTEXT (sp_tweak_context_get_type()) -#define SP_TWEAK_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_TWEAK_CONTEXT, SPTweakContext)) -#define SP_TWEAK_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_TWEAK_CONTEXT, SPTweakContextClass)) -#define SP_IS_TWEAK_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_TWEAK_CONTEXT)) -#define SP_IS_TWEAK_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_TWEAK_CONTEXT)) - #define SAMPLING_SIZE 8 /* fixme: ?? */ #define TC_MIN_PRESSURE 0.0 @@ -43,9 +37,10 @@ enum { TWEAK_MODE_BLUR }; -struct SPTweakContext -{ - SPEventContext event_context; +class SPTweakContext : public SPEventContext { +public: + SPTweakContext(); + virtual ~SPTweakContext(); /* extended input data */ gdouble pressure; @@ -61,8 +56,6 @@ struct SPTweakContext gint mode; - Inkscape::MessageContext *_message_context; - bool is_drawing; bool is_dilating; @@ -76,14 +69,20 @@ struct SPTweakContext bool do_o; sigc::connection style_set_connection; -}; -struct SPTweakContextClass -{ - SPEventContextClass parent_class; -}; + static const std::string prefsPath; -GType sp_tweak_context_get_type(void); + virtual void setup(); + virtual void set(const Inkscape::Preferences::Entry& val); + virtual bool root_handler(GdkEvent* event); + + virtual const std::string& getPrefsPath(); + + void update_cursor(bool with_shift); + +private: + bool set_style(const SPCSSAttr* css); +}; #endif diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index c95dd35cc..24324c874 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -71,6 +71,7 @@ set(ui_SRC dialog/text-edit.cpp dialog/tile.cpp dialog/tracedialog.cpp + dialog/pixelartdialog.cpp dialog/transformation.cpp dialog/undo-history.cpp # dialog/whiteboard-connect.cpp @@ -174,6 +175,7 @@ set(ui_SRC dialog/object-properties.h dialog/ocaldialogs.h dialog/panel-dialog.h + dialog/pixelartdialog.h dialog/print-colors-preview-dialog.h dialog/print.h @@ -182,7 +184,7 @@ set(ui_SRC dialog/swatches.h dialog/symbols.h dialog/template-load-tab.h - dialog/template-widget.h + dialog/template-widget.h dialog/text-edit.h dialog/tile.h dialog/tracedialog.h diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index aeb977078..8a7812494 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -61,9 +61,8 @@ #include "sp-shape.h" #include "sp-gradient.h" #include "sp-gradient-reference.h" -#include "sp-gradient-fns.h" -#include "sp-linear-gradient-fns.h" -#include "sp-radial-gradient-fns.h" +#include "sp-linear-gradient.h" +#include "sp-radial-gradient.h" #include "sp-clippath.h" #include "sp-mask.h" #include "sp-textpath.h" @@ -238,7 +237,8 @@ void ClipboardManagerImpl::copy(SPDesktop *desktop) // Special case for when the color picker ("dropper") is active - copies color under cursor if (tools_isactive(desktop, TOOLS_DROPPER)) { - _setClipboardColor(sp_dropper_context_get_color(desktop->event_context)); + //_setClipboardColor(sp_dropper_context_get_color(desktop->event_context)); + _setClipboardColor(SP_DROPPER_CONTEXT(desktop->event_context)->get_color()); _discardInternalClipboard(); return; } diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert index 09a7ef573..c37767a08 100644 --- a/src/ui/dialog/Makefile_insert +++ b/src/ui/dialog/Makefile_insert @@ -101,6 +101,8 @@ ink_common_sources += \ ui/dialog/tile.h \ ui/dialog/tracedialog.cpp \ ui/dialog/tracedialog.h \ + ui/dialog/pixelartdialog.cpp \ + ui/dialog/pixelartdialog.h \ ui/dialog/transformation.cpp \ ui/dialog/transformation.h \ ui/dialog/undo-history.cpp \ diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp index 8845b60e5..38f10c59c 100644 --- a/src/ui/dialog/align-and-distribute.cpp +++ b/src/ui/dialog/align-and-distribute.cpp @@ -47,6 +47,7 @@ #include "widgets/icon.h" #include "sp-root.h" #include "document-undo.h" +#include "desktop.h" #include <glibmm/i18n.h> @@ -367,19 +368,25 @@ public : private : Geom::Dim2 _orientation; bool _distribute; - virtual void on_button_click() - { - if (!_dialog.getDesktop()) return; - SPEventContext *event_context = sp_desktop_event_context(_dialog.getDesktop()); - if (!INK_IS_NODE_TOOL (event_context)) return; + virtual void on_button_click() { + if (!_dialog.getDesktop()) { + return; + } + + SPEventContext *event_context = _dialog.getDesktop()->getEventContext(); + + if (!INK_IS_NODE_TOOL(event_context)) { + return; + } + InkNodeTool *nt = INK_NODE_TOOL(event_context); - if (_distribute) + if (_distribute) { nt->_multipath->distributeNodes(_orientation); - else + } else { nt->_multipath->alignNodes(_orientation); - + } } }; @@ -825,7 +832,7 @@ private : static void on_tool_changed(Inkscape::Application */*inkscape*/, SPEventContext */*context*/, AlignAndDistribute *daad) { SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if (desktop && sp_desktop_event_context(desktop)) + if (desktop && desktop->getEventContext()) daad->setMode(tools_active(desktop) == TOOLS_NODES); } diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp index 0ce74f54e..17f6ae74d 100644 --- a/src/ui/dialog/dialog-manager.cpp +++ b/src/ui/dialog/dialog-manager.cpp @@ -35,6 +35,7 @@ #include "ui/dialog/symbols.h" #include "ui/dialog/tile.h" #include "ui/dialog/tracedialog.h" +#include "ui/dialog/pixelartdialog.h" #include "ui/dialog/transformation.h" #include "ui/dialog/undo-history.h" #include "ui/dialog/panel-dialog.h" @@ -118,6 +119,7 @@ DialogManager::DialogManager() { registerFactory("Symbols", &create<SymbolsDialog, FloatingBehavior>); registerFactory("TileDialog", &create<TileDialog, FloatingBehavior>); registerFactory("Trace", &create<TraceDialog, FloatingBehavior>); + registerFactory("PixelArt", &create<PixelArtDialog, FloatingBehavior>); registerFactory("Transformation", &create<Transformation, FloatingBehavior>); registerFactory("UndoHistory", &create<UndoHistory, FloatingBehavior>); registerFactory("InputDevices", &create<InputDialog, FloatingBehavior>); @@ -151,6 +153,7 @@ DialogManager::DialogManager() { registerFactory("Symbols", &create<SymbolsDialog, DockBehavior>); registerFactory("TileDialog", &create<TileDialog, DockBehavior>); registerFactory("Trace", &create<TraceDialog, DockBehavior>); + registerFactory("PixelArt", &create<PixelArtDialog, DockBehavior>); registerFactory("Transformation", &create<Transformation, DockBehavior>); registerFactory("UndoHistory", &create<UndoHistory, DockBehavior>); registerFactory("InputDevices", &create<InputDialog, DockBehavior>); diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp index 77fb182e5..511e63d02 100644 --- a/src/ui/dialog/document-properties.cpp +++ b/src/ui/dialog/document-properties.cpp @@ -32,7 +32,6 @@ #include "io/sys.h" #include "preferences.h" #include "sp-namedview.h" -#include "sp-object-repr.h" #include "sp-root.h" #include "sp-script.h" #include "ui/widget/color-picker.h" diff --git a/src/ui/dialog/object-attributes.cpp b/src/ui/dialog/object-attributes.cpp index 027c9ae56..9a7b91c57 100644 --- a/src/ui/dialog/object-attributes.cpp +++ b/src/ui/dialog/object-attributes.cpp @@ -124,16 +124,20 @@ void ObjectAttributes::widget_setup (void) } blocked = true; + + // CPPIFY SPObject *obj = SP_OBJECT(item); //to get the selected item - GObjectClass *klass = G_OBJECT_GET_CLASS(obj); //to deduce the object's type - GType type = G_TYPE_FROM_CLASS(klass); +// GObjectClass *klass = G_OBJECT_GET_CLASS(obj); //to deduce the object's type +// GType type = G_TYPE_FROM_CLASS(klass); const SPAttrDesc *desc; - if (type == SP_TYPE_ANCHOR) +// if (type == SP_TYPE_ANCHOR) + if (SP_IS_ANCHOR(item)) { desc = anchor_desc; } - else if (type == SP_TYPE_IMAGE) +// else if (type == SP_TYPE_IMAGE) + else if (SP_IS_IMAGE(item)) { Inkscape::XML::Node *ir = obj->getRepr(); const gchar *href = ir->attribute("xlink:href"); diff --git a/src/ui/dialog/pixelartdialog.cpp b/src/ui/dialog/pixelartdialog.cpp new file mode 100644 index 000000000..e07cbccb5 --- /dev/null +++ b/src/ui/dialog/pixelartdialog.cpp @@ -0,0 +1,500 @@ +/** + * @file + * Pixel art tracing settings dialog - implementation. + */ +/* Authors: + * Bob Jamison <rjamison@titan.com> + * Stéphane Gimenez <dev@gim.name> + * VinÃcius dos Santos Oliveira <vini.ipsmaker@gmail.com> + * Other dudes from The Inkscape Organization + * + * Copyright (C) 2004-2013 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "pixelartdialog.h" +#include <gtkmm/radiobutton.h> +#include <gtkmm/stock.h> +#include <gtkmm/messagedialog.h> + +#include <gtk/gtk.h> //for GTK_RESPONSE* types +#include <glibmm/i18n.h> + +#include "ui/widget/spinbutton.h" +#include "ui/widget/frame.h" + +#include "desktop.h" +#include "desktop-tracker.h" +#include "message-stack.h" +#include "selection.h" +#include "preferences.h" + +#include "sp-image.h" +#include "display/cairo-utils.h" +#include "libdepixelize/kopftracer2011.h" +#include <algorithm> +#include "document.h" +#include "xml/repr.h" +#include "xml/document.h" +#include "svg/svg.h" +#include "svg/svg-color.h" +#include "color.h" +#include "svg/css-ostringstream.h" +#include "document-undo.h" + +#ifdef HAVE_OPENMP +#include <omp.h> +#endif // HAVE_OPENMP + +namespace Inkscape { +namespace UI { +namespace Dialog { + +template<class T> +T move(T &obj) +{ +#ifdef LIBDEPIXELIZE_ENABLE_CPP11 + return std::move(obj); +#else + T ret; + std::swap(obj, ret); + return ret; +#endif // LIBDEPIXELIZE_ENABLE_CPP11 +} + +/** + * A dialog for adjusting pixel art -> vector tracing parameters + */ +class PixelArtDialogImpl : public PixelArtDialog +{ +public: + PixelArtDialogImpl(); + + ~PixelArtDialogImpl(); + +private: + void setDesktop(SPDesktop *desktop); + void setTargetDesktop(SPDesktop *desktop); + + //############ Events + + void responseCallback(int response_id); + + //############ UI Logic + + Tracer::Kopf2011::Options options(); + + void vectorize(); + void processLibdepixelize(SPImage *img); + void setDefaults(); + void updatePreview(); + + bool ignorePreview; + bool pendingPreview; + + //############ UI + + Gtk::HBox buttonsHBox; + + Gtk::Button *mainOkButton; + Gtk::Button *mainCancelButton; + Gtk::Button *mainResetButton; + + Gtk::VBox heuristicsVBox; + UI::Widget::Frame heuristicsFrame; + + Gtk::HBox curvesMultiplierHBox; + Gtk::Label curvesMultiplierLabel; + Inkscape::UI::Widget::SpinButton curvesMultiplierSpinner; + + Gtk::HBox islandsWeightHBox; + Gtk::Label islandsWeightLabel; + Inkscape::UI::Widget::SpinButton islandsWeightSpinner; + + Gtk::HBox sparsePixelsMultiplierHBox; + Gtk::Label sparsePixelsMultiplierLabel; + Inkscape::UI::Widget::SpinButton sparsePixelsMultiplierSpinner; + + Gtk::HBox sparsePixelsRadiusHBox; + Gtk::Label sparsePixelsRadiusLabel; + Inkscape::UI::Widget::SpinButton sparsePixelsRadiusSpinner; + + Gtk::VBox outputVBox; + UI::Widget::Frame outputFrame; + Gtk::RadioButtonGroup outputGroup; + + Gtk::RadioButton voronoiRadioButton; + Gtk::RadioButton noOptimizeRadioButton; + Gtk::RadioButton optimizeRadioButton; + + SPDesktop *desktop; + DesktopTracker deskTrack; + sigc::connection desktopChangeConn; +}; + +void PixelArtDialogImpl::setDesktop(SPDesktop *desktop) +{ + Panel::setDesktop(desktop); + deskTrack.setBase(desktop); +} + +void PixelArtDialogImpl::setTargetDesktop(SPDesktop *desktop) +{ + this->desktop = desktop; +} + +PixelArtDialogImpl::PixelArtDialogImpl() : + PixelArtDialog(), + ignorePreview(false), + pendingPreview(false) +{ + + Gtk::Box *contents = _getContents(); + + // Heuristics + { + curvesMultiplierLabel.set_label(_("_Curves (multiplier)")); + curvesMultiplierLabel.set_use_underline(true); + curvesMultiplierLabel.set_mnemonic_widget(curvesMultiplierSpinner); + curvesMultiplierLabel.set_tooltip_text(_("Favors connections that are part of a long curve")); + curvesMultiplierSpinner.set_increments(0.125, 0); + curvesMultiplierSpinner.set_digits(3); + curvesMultiplierSpinner.set_range(-10, 10); + curvesMultiplierSpinner.get_adjustment()->signal_value_changed() + .connect(sigc::mem_fun(*this, &PixelArtDialogImpl::updatePreview)); + + curvesMultiplierHBox.pack_start(curvesMultiplierLabel, false, false); + curvesMultiplierHBox.pack_end(curvesMultiplierSpinner, false, false); + heuristicsVBox.pack_start(curvesMultiplierHBox, false, false); + + islandsWeightLabel.set_label(_("_Islands (weight)")); + islandsWeightLabel.set_use_underline(true); + islandsWeightLabel.set_mnemonic_widget(islandsWeightSpinner); + islandsWeightLabel.set_tooltip_text(_("Avoid single disconnected pixels")); + + islandsWeightSpinner.set_tooltip_text(_("A constant vote value")); + islandsWeightSpinner.set_increments(1, 0); + islandsWeightSpinner.set_range(-20, 20); + islandsWeightSpinner.get_adjustment()->signal_value_changed() + .connect(sigc::mem_fun(*this, &PixelArtDialogImpl::updatePreview)); + + islandsWeightHBox.pack_start(islandsWeightLabel, false, false); + islandsWeightHBox.pack_end(islandsWeightSpinner, false, false); + heuristicsVBox.pack_start(islandsWeightHBox, false, false); + + sparsePixelsRadiusLabel.set_label(_("Sparse pixels (window _radius)")); + sparsePixelsRadiusLabel.set_use_underline(true); + sparsePixelsRadiusLabel.set_mnemonic_widget(sparsePixelsRadiusSpinner); + + sparsePixelsRadiusSpinner.set_increments(1, 0); + sparsePixelsRadiusSpinner.set_range(2, 8); + sparsePixelsRadiusSpinner.get_adjustment()->signal_value_changed() + .connect(sigc::mem_fun(*this, &PixelArtDialogImpl::updatePreview)); + + sparsePixelsRadiusSpinner.set_tooltip_text(_("The radius of the window analyzed")); + sparsePixelsMultiplierLabel.set_label(_("Sparse pixels (_multiplier)")); + sparsePixelsMultiplierLabel.set_use_underline(true); + sparsePixelsMultiplierLabel.set_mnemonic_widget(sparsePixelsMultiplierSpinner); + + sparsePixelsMultiplierSpinner.set_increments(0.125, 0); + sparsePixelsMultiplierSpinner.set_digits(3); + sparsePixelsMultiplierSpinner.set_range(-10, 10); + sparsePixelsMultiplierSpinner.get_adjustment()->signal_value_changed() + .connect(sigc::mem_fun(*this, &PixelArtDialogImpl::updatePreview)); + + { + char const *str = _("Favors connections that are part of foreground color"); + sparsePixelsRadiusLabel.set_tooltip_text(str); + sparsePixelsMultiplierLabel.set_tooltip_text(str); + } + + { + char const *str = _("The heuristic computed vote will be multiplied by this value"); + curvesMultiplierSpinner.set_tooltip_text(str); + sparsePixelsMultiplierSpinner.set_tooltip_text(str); + } + + sparsePixelsRadiusHBox.pack_start(sparsePixelsRadiusLabel, false, false); + sparsePixelsRadiusHBox.pack_end(sparsePixelsRadiusSpinner, false, false); + heuristicsVBox.pack_start(sparsePixelsRadiusHBox, false, false); + + sparsePixelsMultiplierHBox.pack_start(sparsePixelsMultiplierLabel, false, false); + sparsePixelsMultiplierHBox.pack_end(sparsePixelsMultiplierSpinner, false, false); + heuristicsVBox.pack_start(sparsePixelsMultiplierHBox, false, false); + + heuristicsFrame.set_label(_("Heuristics")); + heuristicsFrame.add(heuristicsVBox); + contents->pack_start(heuristicsFrame, false, false); + } + + // Output + { + voronoiRadioButton.set_label(_("_Voronoi diagram")); + voronoiRadioButton.set_tooltip_text(_("Output composed of straight lines")); + voronoiRadioButton.set_use_underline(true); + outputGroup = voronoiRadioButton.get_group(); + + outputVBox.pack_start(voronoiRadioButton, false, false); + + noOptimizeRadioButton.set_label(_("Convert to _B-spline curves")); + noOptimizeRadioButton.set_tooltip_text(_("Preserve staircasing artifacts")); + noOptimizeRadioButton.set_use_underline(true); + noOptimizeRadioButton.set_group(outputGroup); + + outputVBox.pack_start(noOptimizeRadioButton, false, false); + + optimizeRadioButton.set_label(_("_Smooth curves")); + optimizeRadioButton.set_tooltip_text(_("The Kopf-Lischinski algorithm")); + optimizeRadioButton.set_use_underline(true); + optimizeRadioButton.set_group(outputGroup); + + outputVBox.pack_start(optimizeRadioButton, false, false); + + outputFrame.set_label(_("Output")); + outputFrame.add(outputVBox); + contents->pack_start(outputFrame, true, false); + } + + // Buttons + { + mainResetButton = addResponseButton(_("Reset"), GTK_RESPONSE_HELP, true); + mainResetButton ->set_tooltip_text(_("Reset all settings to defaults")); + + //## The OK button + mainCancelButton = addResponseButton(Gtk::Stock::STOP, GTK_RESPONSE_CANCEL); + if (mainCancelButton) { + mainCancelButton->set_tooltip_text(_("Abort a trace in progress")); + mainCancelButton->set_sensitive(false); + } + mainOkButton = addResponseButton(Gtk::Stock::OK, GTK_RESPONSE_OK); + mainOkButton->set_tooltip_text(_("Execute the trace")); + + contents->pack_start(buttonsHBox); + } + + setDefaults(); + + show_all_children(); + + desktopChangeConn = deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &PixelArtDialogImpl::setTargetDesktop) ); + deskTrack.connect(GTK_WIDGET(gobj())); + + signalResponse().connect(sigc::mem_fun(*this, &PixelArtDialogImpl::responseCallback)); +} + +void PixelArtDialogImpl::responseCallback(int response_id) +{ + if (response_id == GTK_RESPONSE_OK) { + vectorize(); + } else if (response_id == GTK_RESPONSE_CANCEL) { + // TODO + } else if (response_id == GTK_RESPONSE_HELP) { + setDefaults(); + } else { + hide(); + return; + } +} + +Tracer::Kopf2011::Options PixelArtDialogImpl::options() +{ + Tracer::Kopf2011::Options options; + + options.curvesMultiplier = curvesMultiplierSpinner.get_value(); + options.islandsWeight = islandsWeightSpinner.get_value_as_int(); + options.sparsePixelsMultiplier = sparsePixelsMultiplierSpinner.get_value(); + options.sparsePixelsRadius = sparsePixelsRadiusSpinner.get_value_as_int(); + options.optimize = optimizeRadioButton.get_active(); + + options.nthreads = Inkscape::Preferences::get() + ->getIntLimited("/options/threading/numthreads", +#ifdef HAVE_OPENMP + omp_get_num_procs(), +#else + 1, +#endif // HAVE_OPENMP + 1, 256); + + return options; +} + +void PixelArtDialogImpl::vectorize() +{ + Inkscape::MessageStack *msgStack = desktop->messageStack(); + + if ( !desktop->selection ) { + char *msg = _("Select an <b>image</b> to trace"); + msgStack->flash(Inkscape::ERROR_MESSAGE, msg); + return; + } + + bool found = false; + + for ( GSList const *list = desktop->selection->itemList() ; list + ; list = list->next ) { + if ( !SP_IS_IMAGE(list->data) ) + continue; + + found = true; + + processLibdepixelize(SP_IMAGE(list->data)); + } + + if ( !found ) { + char *msg = _("Select an <b>image</b> to trace"); + msgStack->flash(Inkscape::ERROR_MESSAGE, msg); + return; + } + + DocumentUndo::done(desktop->doc(), SP_VERB_SELECTION_PIXEL_ART, + _("Trace pixel art")); + + // Flush pending updates + desktop->doc()->ensureUpToDate(); +} + +void PixelArtDialogImpl::processLibdepixelize(SPImage *img) +{ + Tracer::Splines out; + + Glib::RefPtr<Gdk::Pixbuf> pixbuf + = Glib::wrap(img->pixbuf->getPixbufRaw(), true); + + if ( pixbuf->get_width() > 256 || pixbuf->get_height() > 256 ) { + char *msg = _("Image looks too big. Process may take a while and is" + " wise to save your document before continue." + "\n\nContinue the procedure (without saving)?"); + Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_WARNING, + Gtk::BUTTONS_OK_CANCEL, true); + + if ( dialog.run() != Gtk::RESPONSE_OK ) + return; + } + + if ( voronoiRadioButton.get_active() ) { + out = Tracer::Kopf2011::to_voronoi(pixbuf, options()); + } else { + out = Tracer::Kopf2011::to_splines(pixbuf, options()); + } + + Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); + Inkscape::XML::Node *group = xml_doc->createElement("svg:g"); + + for ( Tracer::Splines::iterator it = out.begin(), end = out.end() + ; it != end ; ++it ) { + Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); + + { + SPCSSAttr *css = sp_repr_css_attr_new(); + + { + gchar b[64]; + sp_svg_write_color(b, sizeof(b), + SP_RGBA32_U_COMPOSE(unsigned(it->rgba[0]), + unsigned(it->rgba[1]), + unsigned(it->rgba[2]), + unsigned(it->rgba[3]))); + + sp_repr_css_set_property(css, "fill", b); + } + + { + Inkscape::CSSOStringStream osalpha; + osalpha << float(it->rgba[3]) / 255.; + sp_repr_css_set_property(css, "fill-opacity", + osalpha.str().c_str()); + } + + sp_repr_css_set(repr, css, "style"); + sp_repr_css_attr_unref(css); + } + + gchar *str = sp_svg_write_path(move(it->pathVector)); + repr->setAttribute("d", str); + g_free(str); + + group->appendChild(repr); + + Inkscape::GC::release(repr); + } + + { + group->setAttribute("transform", + (std::string("translate(") + + sp_svg_length_write_with_units(img->x) + + ' ' + sp_svg_length_write_with_units(img->y) + + ')').c_str()); + } + + desktop->currentLayer()->appendChildRepr(group); + + Inkscape::GC::release(group); +} + +void PixelArtDialogImpl::setDefaults() +{ + ignorePreview = true; + + curvesMultiplierSpinner.set_value(Tracer::Kopf2011::Options + ::CURVES_MULTIPLIER); + + islandsWeightSpinner.set_value(Tracer::Kopf2011::Options::ISLANDS_WEIGHT); + + sparsePixelsRadiusSpinner.set_value(Tracer::Kopf2011::Options + ::SPARSE_PIXELS_RADIUS); + + sparsePixelsMultiplierSpinner.set_value(Tracer::Kopf2011::Options + ::SPARSE_PIXELS_MULTIPLIER); + + optimizeRadioButton.set_active(); + + ignorePreview = false; + + if ( pendingPreview ) + updatePreview(); +} + +void PixelArtDialogImpl::updatePreview() +{ + if ( ignorePreview ) { + pendingPreview = true; + return; + } + + // TODO: update preview + pendingPreview = false; +} + +/** + * Factory method. Use this to create a new PixelArtDialog + */ +PixelArtDialog &PixelArtDialog::getInstance() +{ + PixelArtDialog *dialog = new PixelArtDialogImpl(); + return *dialog; +} + +PixelArtDialogImpl::~PixelArtDialogImpl() +{ + desktopChangeConn.disconnect(); +} + + +} //namespace Dialog +} //namespace UI +} //namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/pixelartdialog.h b/src/ui/dialog/pixelartdialog.h new file mode 100644 index 000000000..165cb8699 --- /dev/null +++ b/src/ui/dialog/pixelartdialog.h @@ -0,0 +1,58 @@ +/** @file + * @brief Bitmap tracing settings dialog + */ +/* Authors: + * Bob Jamison + * VinÃcius dos Santos Oliveira <vini.ipsmaker@gmail.com> + * Other dudes from The Inkscape Organization + * + * Copyright (C) 2004, 2005 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef __PIXELARTDIALOG_H__ +#define __PIXELARTDIALOG_H__ + +#include "ui/widget/panel.h" +#include "verbs.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + + +/** + * A dialog that displays log messages + */ +class PixelArtDialog : public UI::Widget::Panel +{ + +public: + + PixelArtDialog() : + UI::Widget::Panel("", "/dialogs/pixelart", SP_VERB_SELECTION_PIXEL_ART) + {} + + + static PixelArtDialog &getInstance(); + + virtual ~PixelArtDialog() {}; +}; + + +} //namespace Dialog +} //namespace UI +} //namespace Inkscape + +#endif /* __PIXELARTDIALOGDIALOG_H__ */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/svg-fonts-dialog.h b/src/ui/dialog/svg-fonts-dialog.h index 01f70654a..e5c4631e4 100644 --- a/src/ui/dialog/svg-fonts-dialog.h +++ b/src/ui/dialog/svg-fonts-dialog.h @@ -34,8 +34,8 @@ class HScale; #endif } -struct SPGlyph; -struct SPGlyphKerning; +class SPGlyph; +class SPGlyphKerning; class SvgFont; class SvgFontDrawingArea : Gtk::DrawingArea{ @@ -52,7 +52,7 @@ private: bool on_expose_event (GdkEventExpose *event); }; -struct SPFont; +class SPFont; namespace Inkscape { namespace UI { diff --git a/src/ui/dialog/swatches.cpp b/src/ui/dialog/swatches.cpp index 094a6fa6a..d4d80c9b1 100644 --- a/src/ui/dialog/swatches.cpp +++ b/src/ui/dialog/swatches.cpp @@ -42,7 +42,6 @@ #include "path-prefix.h" #include "preferences.h" #include "sp-item.h" -#include "sp-gradient-fns.h" #include "sp-gradient.h" #include "sp-gradient-vector.h" #include "style.h" diff --git a/src/ui/tool/control-point.h b/src/ui/tool/control-point.h index 27a0f8074..30efe8a27 100644 --- a/src/ui/tool/control-point.h +++ b/src/ui/tool/control-point.h @@ -23,7 +23,7 @@ #include "enums.h" class SPDesktop; -struct SPEventContext; +class SPEventContext; namespace Inkscape { namespace UI { diff --git a/src/ui/tool/node-tool.cpp b/src/ui/tool/node-tool.cpp index e743e0efc..4b236e94c 100644 --- a/src/ui/tool/node-tool.cpp +++ b/src/ui/tool/node-tool.cpp @@ -104,64 +104,49 @@ using Inkscape::ControlManager; -namespace { - SPCanvasGroup *create_control_group(SPDesktop *d); -void ink_node_tool_dispose(GObject *object); - -void ink_node_tool_setup(SPEventContext *ec); -gint ink_node_tool_root_handler(SPEventContext *event_context, GdkEvent *event); -gint ink_node_tool_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event); -void ink_node_tool_set(SPEventContext *ec, Inkscape::Preferences::Entry *value); - -void ink_node_tool_update_tip(InkNodeTool *nt, GdkEvent *event); -void ink_node_tool_selection_changed(InkNodeTool *nt, Inkscape::Selection *sel); -void ink_node_tool_select_area(InkNodeTool *nt, Geom::Rect const &, GdkEventButton *); -void ink_node_tool_select_point(InkNodeTool *nt, Geom::Point const &, GdkEventButton *); -void ink_node_tool_mouseover_changed(InkNodeTool *nt, Inkscape::UI::ControlPoint *p); - -void handleControlUiStyleChange(InkNodeTool *nt); - -} // anonymous namespace -G_DEFINE_TYPE(InkNodeTool, ink_node_tool, SP_TYPE_EVENT_CONTEXT); +#include "tool-factory.h" -static void -ink_node_tool_class_init(InkNodeToolClass *klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - SPEventContextClass *event_context_class = (SPEventContextClass *) klass; - - object_class->dispose = ink_node_tool_dispose; +namespace { + SPEventContext* createNodesContext() { + return new InkNodeTool(); + } - event_context_class->setup = ink_node_tool_setup; - event_context_class->set = ink_node_tool_set; - event_context_class->root_handler = ink_node_tool_root_handler; - event_context_class->item_handler = ink_node_tool_item_handler; + bool nodesContextRegistered = ToolFactory::instance().registerObject("/tools/nodes", createNodesContext); } -static void -ink_node_tool_init(InkNodeTool *nt) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(nt); - - event_context->cursor_shape = cursor_node_xpm; - event_context->hot_x = 1; - event_context->hot_y = 1; - - new (&nt->_selection_changed_connection) sigc::connection(); - new (&nt->_selection_modified_connection) sigc::connection(); - new (&nt->_mouseover_changed_connection) sigc::connection(); - new (&nt->_sizeUpdatedConn) sigc::connection(); - //new (&nt->_mgroup) Inkscape::UI::ManipulatorGroup(nt->desktop); - new (&nt->_selected_nodes) CSelPtr(); - new (&nt->_multipath) MultiPathPtr(); - new (&nt->_selector) SelectorPtr(); - new (&nt->_path_data) PathSharedDataPtr(); - new (&nt->_shape_editors) ShapeEditors(); +const std::string& InkNodeTool::getPrefsPath() { + return InkNodeTool::prefsPath; } -namespace { +const std::string InkNodeTool::prefsPath = "/tools/nodes"; + +InkNodeTool::InkNodeTool() : SPEventContext() { + this->show_handles = false; + this->single_node_transform_handles = false; + this->show_transform_handles = false; + this->cursor_drag = false; + this->live_objects = false; + this->edit_clipping_paths = false; + this->live_outline = false; + this->flashed_item = 0; + this->_transform_handle_group = 0; + this->show_path_direction = false; + this->_last_over = 0; + this->edit_masks = false; + this->show_outline = false; + this->flash_tempitem = 0; + + this->cursor_shape = cursor_node_xpm; + this->hot_x = 1; + this->hot_y = 1; + + this->_selected_nodes = 0; + this->_multipath = 0; + this->_selector = 0; + this->_path_data = 0; +} SPCanvasGroup *create_control_group(SPDesktop *d) { @@ -174,189 +159,160 @@ void destroy_group(SPCanvasGroup *g) sp_canvas_item_destroy(SP_CANVAS_ITEM(g)); } -void ink_node_tool_dispose(GObject *object) -{ - InkNodeTool *nt = INK_NODE_TOOL(object); - - nt->enableGrDrag(false); +InkNodeTool::~InkNodeTool() { + this->enableGrDrag(false); - if (nt->flash_tempitem) { - nt->desktop->remove_temporary_canvasitem(nt->flash_tempitem); + if (this->flash_tempitem) { + this->desktop->remove_temporary_canvasitem(this->flash_tempitem); } - nt->_selection_changed_connection.disconnect(); - nt->_selection_modified_connection.disconnect(); - nt->_mouseover_changed_connection.disconnect(); - nt->_sizeUpdatedConn.disconnect(); - nt->_multipath.~MultiPathPtr(); - nt->_selected_nodes.~CSelPtr(); - nt->_selector.~SelectorPtr(); - nt->_shape_editors.~ShapeEditors(); - - Inkscape::UI::PathSharedData &data = *nt->_path_data; + this->_selection_changed_connection.disconnect(); + //this->_selection_modified_connection.disconnect(); + this->_mouseover_changed_connection.disconnect(); + this->_sizeUpdatedConn.disconnect(); + + delete this->_multipath; + delete this->_selected_nodes; + delete this->_selector; + + Inkscape::UI::PathSharedData &data = *this->_path_data; destroy_group(data.node_data.node_group); destroy_group(data.node_data.handle_group); destroy_group(data.node_data.handle_line_group); destroy_group(data.outline_group); destroy_group(data.dragpoint_group); - destroy_group(nt->_transform_handle_group); - - nt->_path_data.~PathSharedDataPtr(); - nt->_selection_changed_connection.~connection(); - nt->_selection_modified_connection.~connection(); - nt->_mouseover_changed_connection.~connection(); - nt->_sizeUpdatedConn.~connection(); - - if (nt->_node_message_context) { - delete nt->_node_message_context; - } - - G_OBJECT_CLASS(ink_node_tool_parent_class)->dispose(object); + destroy_group(this->_transform_handle_group); } -void ink_node_tool_setup(SPEventContext *ec) -{ - InkNodeTool *nt = INK_NODE_TOOL(ec); - - if (SP_EVENT_CONTEXT_CLASS(ink_node_tool_parent_class)->setup) - SP_EVENT_CONTEXT_CLASS(ink_node_tool_parent_class)->setup(ec); +void InkNodeTool::setup() { + SPEventContext::setup(); - nt->_node_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack()); + this->_path_data = new Inkscape::UI::PathSharedData(); - nt->_path_data.reset(new Inkscape::UI::PathSharedData()); - Inkscape::UI::PathSharedData &data = *nt->_path_data; - data.node_data.desktop = nt->desktop; + Inkscape::UI::PathSharedData &data = *this->_path_data; + data.node_data.desktop = this->desktop; // selector has to be created here, so that its hidden control point is on the bottom - nt->_selector.reset(new Inkscape::UI::Selector(nt->desktop)); + this->_selector = new Inkscape::UI::Selector(this->desktop); // Prepare canvas groups for controls. This guarantees correct z-order, so that // for example a dragpoint won't obscure a node - data.outline_group = create_control_group(nt->desktop); - data.node_data.handle_line_group = create_control_group(nt->desktop); - data.dragpoint_group = create_control_group(nt->desktop); - nt->_transform_handle_group = create_control_group(nt->desktop); - data.node_data.node_group = create_control_group(nt->desktop); - data.node_data.handle_group = create_control_group(nt->desktop); - - Inkscape::Selection *selection = sp_desktop_selection (ec->desktop); - nt->_selection_changed_connection.disconnect(); - nt->_selection_changed_connection = - selection->connectChanged( - sigc::bind<0>( - sigc::ptr_fun(&ink_node_tool_selection_changed), - nt)); - /*nt->_selection_modified_connection.disconnect(); - nt->_selection_modified_connection = - selection->connectModified( - sigc::hide(sigc::bind<0>( - sigc::ptr_fun(&ink_node_tool_selection_modified), - nt)));*/ - nt->_mouseover_changed_connection.disconnect(); - nt->_mouseover_changed_connection = - Inkscape::UI::ControlPoint::signal_mouseover_change.connect( - sigc::bind<0>( - sigc::ptr_fun(&ink_node_tool_mouseover_changed), - nt)); - - nt->_sizeUpdatedConn = ControlManager::getManager().connectCtrlSizeChanged(sigc::bind(sigc::ptr_fun(&handleControlUiStyleChange), nt)); + data.outline_group = create_control_group(this->desktop); + data.node_data.handle_line_group = create_control_group(this->desktop); + data.dragpoint_group = create_control_group(this->desktop); + this->_transform_handle_group = create_control_group(this->desktop); + data.node_data.node_group = create_control_group(this->desktop); + data.node_data.handle_group = create_control_group(this->desktop); + + Inkscape::Selection *selection = sp_desktop_selection (this->desktop); + + this->_selection_changed_connection.disconnect(); + this->_selection_changed_connection = + selection->connectChanged(sigc::mem_fun(this, &InkNodeTool::selection_changed)); + + this->_mouseover_changed_connection.disconnect(); + this->_mouseover_changed_connection = + Inkscape::UI::ControlPoint::signal_mouseover_change.connect(sigc::mem_fun(this, &InkNodeTool::mouseover_changed)); + + this->_sizeUpdatedConn = ControlManager::getManager().connectCtrlSizeChanged( + sigc::mem_fun(this, &InkNodeTool::handleControlUiStyleChange) + ); - nt->_selected_nodes.reset( - new Inkscape::UI::ControlPointSelection(nt->desktop, nt->_transform_handle_group)); - data.node_data.selection = nt->_selected_nodes.get(); - nt->_multipath.reset(new Inkscape::UI::MultiPathManipulator(data, - nt->_selection_changed_connection)); - - nt->_selector->signal_point.connect( - sigc::bind<0>( - sigc::ptr_fun(&ink_node_tool_select_point), - nt)); - nt->_selector->signal_area.connect( - sigc::bind<0>( - sigc::ptr_fun(&ink_node_tool_select_area), - nt)); - - nt->_multipath->signal_coords_changed.connect( + this->_selected_nodes = new Inkscape::UI::ControlPointSelection(this->desktop, this->_transform_handle_group); + + data.node_data.selection = this->_selected_nodes; + + this->_multipath = new Inkscape::UI::MultiPathManipulator(data, this->_selection_changed_connection); + + this->_selector->signal_point.connect(sigc::mem_fun(this, &InkNodeTool::select_point)); + this->_selector->signal_area.connect(sigc::mem_fun(this, &InkNodeTool::select_area)); + + this->_multipath->signal_coords_changed.connect( sigc::bind( - sigc::mem_fun(*nt->desktop, &SPDesktop::emitToolSubselectionChanged), - (void*) 0)); - nt->_selected_nodes->signal_point_changed.connect( - sigc::hide( sigc::hide( - sigc::bind( - sigc::bind( - sigc::ptr_fun(ink_node_tool_update_tip), - (GdkEvent*)0), - nt)))); - - nt->cursor_drag = false; - nt->show_transform_handles = true; - nt->single_node_transform_handles = false; - nt->flash_tempitem = NULL; - nt->flashed_item = NULL; - nt->_last_over = NULL; + sigc::mem_fun(*this->desktop, &SPDesktop::emitToolSubselectionChanged), + (void*)NULL + ) + ); + + this->_selected_nodes->signal_point_changed.connect( + // Hide both signal parameters and bind the function parameter to 0 + // sigc::signal<void, SelectableControlPoint *, bool> + // <=> + // void update_tip(GdkEvent *event) + sigc::hide(sigc::hide(sigc::bind( + sigc::mem_fun(this, &InkNodeTool::update_tip), + (GdkEvent*)NULL + ))) + ); + + this->cursor_drag = false; + this->show_transform_handles = true; + this->single_node_transform_handles = false; + this->flash_tempitem = NULL; + this->flashed_item = NULL; + this->_last_over = NULL; // read prefs before adding items to selection to prevent momentarily showing the outline - sp_event_context_read(nt, "show_handles"); - sp_event_context_read(nt, "show_outline"); - sp_event_context_read(nt, "live_outline"); - sp_event_context_read(nt, "live_objects"); - sp_event_context_read(nt, "show_path_direction"); - sp_event_context_read(nt, "show_transform_handles"); - sp_event_context_read(nt, "single_node_transform_handles"); - sp_event_context_read(nt, "edit_clipping_paths"); - sp_event_context_read(nt, "edit_masks"); - - ink_node_tool_selection_changed(nt, selection); - ink_node_tool_update_tip(nt, NULL); + sp_event_context_read(this, "show_handles"); + sp_event_context_read(this, "show_outline"); + sp_event_context_read(this, "live_outline"); + sp_event_context_read(this, "live_objects"); + sp_event_context_read(this, "show_path_direction"); + sp_event_context_read(this, "show_transform_handles"); + sp_event_context_read(this, "single_node_transform_handles"); + sp_event_context_read(this, "edit_clipping_paths"); + sp_event_context_read(this, "edit_masks"); + + this->selection_changed(selection); + this->update_tip(NULL); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/tools/nodes/selcue")) { - ec->enableSelectionCue(); + this->enableSelectionCue(); } + if (prefs->getBool("/tools/nodes/gradientdrag")) { - ec->enableGrDrag(); + this->enableGrDrag(); } - nt->desktop->emitToolSubselectionChanged(NULL); // sets the coord entry fields to inactive + this->desktop->emitToolSubselectionChanged(NULL); // sets the coord entry fields to inactive } -void ink_node_tool_set(SPEventContext *ec, Inkscape::Preferences::Entry *value) -{ - InkNodeTool *nt = INK_NODE_TOOL(ec); - Glib::ustring entry_name = value->getEntryName(); +void InkNodeTool::set(const Inkscape::Preferences::Entry& value) { + Glib::ustring entry_name = value.getEntryName(); if (entry_name == "show_handles") { - nt->show_handles = value->getBool(true); - nt->_multipath->showHandles(nt->show_handles); + this->show_handles = value.getBool(true); + this->_multipath->showHandles(this->show_handles); } else if (entry_name == "show_outline") { - nt->show_outline = value->getBool(); - nt->_multipath->showOutline(nt->show_outline); + this->show_outline = value.getBool(); + this->_multipath->showOutline(this->show_outline); } else if (entry_name == "live_outline") { - nt->live_outline = value->getBool(); - nt->_multipath->setLiveOutline(nt->live_outline); + this->live_outline = value.getBool(); + this->_multipath->setLiveOutline(this->live_outline); } else if (entry_name == "live_objects") { - nt->live_objects = value->getBool(); - nt->_multipath->setLiveObjects(nt->live_objects); + this->live_objects = value.getBool(); + this->_multipath->setLiveObjects(this->live_objects); } else if (entry_name == "show_path_direction") { - nt->show_path_direction = value->getBool(); - nt->_multipath->showPathDirection(nt->show_path_direction); + this->show_path_direction = value.getBool(); + this->_multipath->showPathDirection(this->show_path_direction); } else if (entry_name == "show_transform_handles") { - nt->show_transform_handles = value->getBool(true); - nt->_selected_nodes->showTransformHandles( - nt->show_transform_handles, nt->single_node_transform_handles); + this->show_transform_handles = value.getBool(true); + this->_selected_nodes->showTransformHandles( + this->show_transform_handles, this->single_node_transform_handles); } else if (entry_name == "single_node_transform_handles") { - nt->single_node_transform_handles = value->getBool(); - nt->_selected_nodes->showTransformHandles( - nt->show_transform_handles, nt->single_node_transform_handles); + this->single_node_transform_handles = value.getBool(); + this->_selected_nodes->showTransformHandles( + this->show_transform_handles, this->single_node_transform_handles); } else if (entry_name == "edit_clipping_paths") { - nt->edit_clipping_paths = value->getBool(); - ink_node_tool_selection_changed(nt, nt->desktop->selection); + this->edit_clipping_paths = value.getBool(); + this->selection_changed(this->desktop->selection); } else if (entry_name == "edit_masks") { - nt->edit_masks = value->getBool(); - ink_node_tool_selection_changed(nt, nt->desktop->selection); + this->edit_masks = value.getBool(); + this->selection_changed(this->desktop->selection); } else { - if (SP_EVENT_CONTEXT_CLASS(ink_node_tool_parent_class)->set) - SP_EVENT_CONTEXT_CLASS(ink_node_tool_parent_class)->set(ec, value); + SPEventContext::set(value); } } @@ -365,7 +321,10 @@ void gather_items(InkNodeTool *nt, SPItem *base, SPObject *obj, Inkscape::UI::Sh std::set<Inkscape::UI::ShapeRecord> &s) { using namespace Inkscape::UI; - if (!obj) return; + + if (!obj) { + return; + } //XML Tree being used directly here while it shouldn't be. if (SP_IS_PATH(obj) && obj->getRepr()->attribute("inkscape:original-d") != NULL) { @@ -385,11 +344,13 @@ void gather_items(InkNodeTool *nt, SPItem *base, SPObject *obj, Inkscape::UI::Sh // TODO add support for objectBoundingBox r.edit_transform = base ? base->i2doc_affine() : Geom::identity(); r.role = role; + if (s.insert(r).second) { // this item was encountered the first time if (nt->edit_clipping_paths && item->clip_ref) { gather_items(nt, item, item->clip_ref->getObject(), SHAPE_ROLE_CLIPPING_PATH, s); } + if (nt->edit_masks && item->mask_ref) { gather_items(nt, item, item->mask_ref->getObject(), SHAPE_ROLE_MASK, s); } @@ -397,8 +358,7 @@ void gather_items(InkNodeTool *nt, SPItem *base, SPObject *obj, Inkscape::UI::Sh } } -void ink_node_tool_selection_changed(InkNodeTool *nt, Inkscape::Selection *sel) -{ +void InkNodeTool::selection_changed(Inkscape::Selection *sel) { using namespace Inkscape::UI; std::set<ShapeRecord> shapes; @@ -407,20 +367,22 @@ void ink_node_tool_selection_changed(InkNodeTool *nt, Inkscape::Selection *sel) for (GSList *i = const_cast<GSList*>(ilist); i; i = i->next) { SPObject *obj = static_cast<SPObject*>(i->data); + if (SP_IS_ITEM(obj)) { - gather_items(nt, NULL, static_cast<SPItem*>(obj), SHAPE_ROLE_NORMAL, shapes); + gather_items(this, NULL, static_cast<SPItem*>(obj), SHAPE_ROLE_NORMAL, shapes); } } // use multiple ShapeEditors for now, to allow editing many shapes at once // needs to be rethought - for (ShapeEditors::iterator i = nt->_shape_editors.begin(); - i != nt->_shape_editors.end(); ) + for (boost::ptr_map<SPItem*, ShapeEditor>::iterator i = this->_shape_editors.begin(); + i != this->_shape_editors.end(); ) { ShapeRecord s; s.item = i->first; + if (shapes.find(s) == shapes.end()) { - nt->_shape_editors.erase(i++); + this->_shape_editors.erase(i++); } else { ++i; } @@ -428,22 +390,22 @@ void ink_node_tool_selection_changed(InkNodeTool *nt, Inkscape::Selection *sel) for (std::set<ShapeRecord>::iterator i = shapes.begin(); i != shapes.end(); ++i) { ShapeRecord const &r = *i; + if ((SP_IS_SHAPE(r.item) || SP_IS_TEXT(r.item)) && - nt->_shape_editors.find(r.item) == nt->_shape_editors.end()) + this->_shape_editors.find(r.item) == this->_shape_editors.end()) { - ShapeEditor *si = new ShapeEditor(nt->desktop); + ShapeEditor *si = new ShapeEditor(this->desktop); si->set_item(r.item, SH_KNOTHOLDER); - nt->_shape_editors.insert(const_cast<SPItem*&>(r.item), si); + this->_shape_editors.insert(const_cast<SPItem*&>(r.item), si); } } - nt->_multipath->setItems(shapes); - ink_node_tool_update_tip(nt, NULL); - nt->desktop->updateNow(); + this->_multipath->setItems(shapes); + this->update_tip(NULL); + this->desktop->updateNow(); } -gint ink_node_tool_root_handler(SPEventContext *event_context, GdkEvent *event) -{ +bool InkNodeTool::root_handler(GdkEvent* event) { /* things to handle here: * 1. selection of items * 2. passing events to manipulators @@ -451,14 +413,20 @@ gint ink_node_tool_root_handler(SPEventContext *event_context, GdkEvent *event) */ using namespace Inkscape::UI; // pull in event helpers - SPDesktop *desktop = event_context->desktop; Inkscape::Selection *selection = desktop->selection; - InkNodeTool *nt = static_cast<InkNodeTool*>(event_context); static Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (nt->_multipath->event(event_context, event)) return true; - if (nt->_selector->event(event_context, event)) return true; - if (nt->_selected_nodes->event(event_context, event)) return true; + if (this->_multipath->event(this, event)) { + return true; + } + + if (this->_selector->event(this, event)) { + return true; + } + + if (this->_selected_nodes->event(this, event)) { + return true; + } switch (event->type) { @@ -466,33 +434,52 @@ gint ink_node_tool_root_handler(SPEventContext *event_context, GdkEvent *event) combine_motion_events(desktop->canvas, event->motion, 0); SPItem *over_item = sp_event_context_find_item (desktop, event_point(event->button), FALSE, TRUE); - if (over_item != nt->_last_over) { - nt->_last_over = over_item; - ink_node_tool_update_tip(nt, event); + + if (over_item != this->_last_over) { + this->_last_over = over_item; + //ink_node_tool_update_tip(nt, event); + this->update_tip(event); } // create pathflash outline if (prefs->getBool("/tools/nodes/pathflash_enabled")) { - if (over_item == nt->flashed_item) break; - if (!prefs->getBool("/tools/nodes/pathflash_selected") && selection->includes(over_item)) break; - if (nt->flash_tempitem) { - desktop->remove_temporary_canvasitem(nt->flash_tempitem); - nt->flash_tempitem = NULL; - nt->flashed_item = NULL; + if (over_item == this->flashed_item) { + break; } - if (!SP_IS_SHAPE(over_item)) break; // for now, handle only shapes - nt->flashed_item = over_item; + if (!prefs->getBool("/tools/nodes/pathflash_selected") && selection->includes(over_item)) { + break; + } + + if (this->flash_tempitem) { + desktop->remove_temporary_canvasitem(this->flash_tempitem); + this->flash_tempitem = NULL; + this->flashed_item = NULL; + } + + if (!SP_IS_SHAPE(over_item)) { + break; // for now, handle only shapes + } + + this->flashed_item = over_item; SPCurve *c = SP_SHAPE(over_item)->getCurveBeforeLPE(); - if (!c) break; // break out when curve doesn't exist + + if (!c) { + break; // break out when curve doesn't exist + } + c->transform(over_item->i2dt_affine()); SPCanvasItem *flash = sp_canvas_bpath_new(sp_desktop_tempgroup(desktop), c); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(flash), prefs->getInt("/tools/nodes/highlight_color", 0xff0000ff), 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); + sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(flash), 0, SP_WIND_RULE_NONZERO); - nt->flash_tempitem = desktop->add_temporary_canvasitem(flash, + + this->flash_tempitem = desktop->add_temporary_canvasitem(flash, prefs->getInt("/tools/nodes/pathflash_timeout", 500)); + c->unref(); } } break; // do not return true, because we need to pass this event to the parent context @@ -502,136 +489,162 @@ gint ink_node_tool_root_handler(SPEventContext *event_context, GdkEvent *event) switch (get_group0_keyval(&event->key)) { case GDK_KEY_Escape: // deselect everything - if (nt->_selected_nodes->empty()) { + if (this->_selected_nodes->empty()) { Inkscape::SelectionHelper::selectNone(desktop); } else { - nt->_selected_nodes->clear(); + this->_selected_nodes->clear(); } - ink_node_tool_update_tip(nt, event); + //ink_node_tool_update_tip(nt, event); + this->update_tip(event); return TRUE; + case GDK_KEY_a: case GDK_KEY_A: if (held_control(event->key) && held_alt(event->key)) { - nt->_selected_nodes->selectAll(); + this->_selected_nodes->selectAll(); // Ctrl+A is handled in selection-chemistry.cpp via verb - ink_node_tool_update_tip(nt, event); + //ink_node_tool_update_tip(nt, event); + this->update_tip(event); return TRUE; } break; + case GDK_KEY_h: case GDK_KEY_H: if (held_only_control(event->key)) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/tools/nodes/show_handles", !nt->show_handles); + prefs->setBool("/tools/nodes/show_handles", !this->show_handles); return TRUE; } break; + default: break; } - ink_node_tool_update_tip(nt, event); + //ink_node_tool_update_tip(nt, event); + this->update_tip(event); break; + case GDK_KEY_RELEASE: - ink_node_tool_update_tip(nt, event); + //ink_node_tool_update_tip(nt, event); + this->update_tip(event); break; - default: break; + + default: + break; } - if (SP_EVENT_CONTEXT_CLASS(ink_node_tool_parent_class)->root_handler) - return SP_EVENT_CONTEXT_CLASS(ink_node_tool_parent_class)->root_handler(event_context, event); +// if (SP_EVENT_CONTEXT_CLASS(ink_node_tool_parent_class)->root_handler) +// return SP_EVENT_CONTEXT_CLASS(ink_node_tool_parent_class)->root_handler(event_context, event); + SPEventContext::root_handler(event); return FALSE; } -void ink_node_tool_update_tip(InkNodeTool *nt, GdkEvent *event) -{ +void InkNodeTool::update_tip(GdkEvent *event) { using namespace Inkscape::UI; + if (event && (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE)) { unsigned new_state = state_after_event(event); - if (new_state == event->key.state) return; + + if (new_state == event->key.state) { + return; + } + if (state_held_shift(new_state)) { - if (nt->_last_over) { - nt->_node_message_context->set(Inkscape::NORMAL_MESSAGE, + if (this->_last_over) { + this->message_context->set(Inkscape::NORMAL_MESSAGE, C_("Node tool tip", "<b>Shift</b>: drag to add nodes to the selection, " "click to toggle object selection")); } else { - nt->_node_message_context->set(Inkscape::NORMAL_MESSAGE, + this->message_context->set(Inkscape::NORMAL_MESSAGE, C_("Node tool tip", "<b>Shift</b>: drag to add nodes to the selection")); } + return; } } - unsigned sz = nt->_selected_nodes->size(); - unsigned total = nt->_selected_nodes->allPoints().size(); + + unsigned sz = this->_selected_nodes->size(); + unsigned total = this->_selected_nodes->allPoints().size(); + if (sz != 0) { char *nodestring = g_strdup_printf( ngettext("<b>%u of %u</b> node selected.", "<b>%u of %u</b> nodes selected.", total), sz, total); - if (nt->_last_over) { + + if (this->_last_over) { // TRANSLATORS: The %s below is where the "%u of %u nodes selected" sentence gets put char *dyntip = g_strdup_printf(C_("Node tool tip", "%s Drag to select nodes, click to edit only this object (more: Shift)"), nodestring); - nt->_node_message_context->set(Inkscape::NORMAL_MESSAGE, dyntip); + this->message_context->set(Inkscape::NORMAL_MESSAGE, dyntip); g_free(dyntip); } else { char *dyntip = g_strdup_printf(C_("Node tool tip", "%s Drag to select nodes, click clear the selection"), nodestring); - nt->_node_message_context->set(Inkscape::NORMAL_MESSAGE, dyntip); + this->message_context->set(Inkscape::NORMAL_MESSAGE, dyntip); g_free(dyntip); } g_free(nodestring); - } else if (!nt->_multipath->empty()) { - if (nt->_last_over) { - nt->_node_message_context->set(Inkscape::NORMAL_MESSAGE, C_("Node tool tip", + } else if (!this->_multipath->empty()) { + if (this->_last_over) { + this->message_context->set(Inkscape::NORMAL_MESSAGE, C_("Node tool tip", "Drag to select nodes, click to edit only this object")); } else { - nt->_node_message_context->set(Inkscape::NORMAL_MESSAGE, C_("Node tool tip", + this->message_context->set(Inkscape::NORMAL_MESSAGE, C_("Node tool tip", "Drag to select nodes, click to clear the selection")); } } else { - if (nt->_last_over) { - nt->_node_message_context->set(Inkscape::NORMAL_MESSAGE, C_("Node tool tip", + if (this->_last_over) { + this->message_context->set(Inkscape::NORMAL_MESSAGE, C_("Node tool tip", "Drag to select objects to edit, click to edit this object (more: Shift)")); } else { - nt->_node_message_context->set(Inkscape::NORMAL_MESSAGE, C_("Node tool tip", + this->message_context->set(Inkscape::NORMAL_MESSAGE, C_("Node tool tip", "Drag to select objects to edit")); } } } -gint ink_node_tool_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event) -{ - if (SP_EVENT_CONTEXT_CLASS(ink_node_tool_parent_class)->item_handler) - return SP_EVENT_CONTEXT_CLASS(ink_node_tool_parent_class)->item_handler(event_context, item, event); +bool InkNodeTool::item_handler(SPItem* item, GdkEvent* event) { + SPEventContext::item_handler(item, event); return FALSE; } -void ink_node_tool_select_area(InkNodeTool *nt, Geom::Rect const &sel, GdkEventButton *event) -{ +void InkNodeTool::select_area(Geom::Rect const &sel, GdkEventButton *event) { using namespace Inkscape::UI; - if (nt->_multipath->empty()) { + + if (this->_multipath->empty()) { // if multipath is empty, select rubberbanded items rather than nodes - Inkscape::Selection *selection = nt->desktop->selection; - GSList *items = sp_desktop_document(nt->desktop)->getItemsInBox(nt->desktop->dkey, sel); + Inkscape::Selection *selection = this->desktop->selection; + GSList *items = sp_desktop_document(this->desktop)->getItemsInBox(this->desktop->dkey, sel); selection->setList(items); g_slist_free(items); } else { - if (!held_shift(*event)) nt->_selected_nodes->clear(); - nt->_selected_nodes->selectArea(sel); + if (!held_shift(*event)) { + this->_selected_nodes->clear(); + } + + this->_selected_nodes->selectArea(sel); } } -void ink_node_tool_select_point(InkNodeTool *nt, Geom::Point const &/*sel*/, GdkEventButton *event) -{ + +void InkNodeTool::select_point(Geom::Point const &sel, GdkEventButton *event) { using namespace Inkscape::UI; // pull in event helpers - if (!event) return; - if (event->button != 1) return; - Inkscape::Selection *selection = nt->desktop->selection; + if (!event) { + return; + } + + if (event->button != 1) { + return; + } + + Inkscape::Selection *selection = this->desktop->selection; - SPItem *item_clicked = sp_event_context_find_item (nt->desktop, event_point(*event), + SPItem *item_clicked = sp_event_context_find_item (this->desktop, event_point(*event), (event->state & GDK_MOD1_MASK) && !(event->state & GDK_CONTROL_MASK), TRUE); if (item_clicked == NULL) { // nothing under cursor @@ -639,10 +652,10 @@ void ink_node_tool_select_point(InkNodeTool *nt, Geom::Point const &/*sel*/, Gdk // if there are nodes selected, the first click should deselect the nodes // and the second should deselect the items if (!state_held_shift(event->state)) { - if (nt->_selected_nodes->empty()) { + if (this->_selected_nodes->empty()) { selection->clear(); } else { - nt->_selected_nodes->clear(); + this->_selected_nodes->clear(); } } } else { @@ -651,35 +664,36 @@ void ink_node_tool_select_point(InkNodeTool *nt, Geom::Point const &/*sel*/, Gdk } else { selection->set(item_clicked); } - nt->desktop->updateNow(); + + this->desktop->updateNow(); } } -void ink_node_tool_mouseover_changed(InkNodeTool *nt, Inkscape::UI::ControlPoint *p) -{ +void InkNodeTool::mouseover_changed(Inkscape::UI::ControlPoint *p) { using Inkscape::UI::CurveDragPoint; + CurveDragPoint *cdp = dynamic_cast<CurveDragPoint*>(p); - if (cdp && !nt->cursor_drag) { - nt->cursor_shape = cursor_node_d_xpm; - nt->hot_x = 1; - nt->hot_y = 1; - sp_event_context_update_cursor(nt); - nt->cursor_drag = true; - } else if (!cdp && nt->cursor_drag) { - nt->cursor_shape = cursor_node_xpm; - nt->hot_x = 1; - nt->hot_y = 1; - sp_event_context_update_cursor(nt); - nt->cursor_drag = false; + + if (cdp && !this->cursor_drag) { + this->cursor_shape = cursor_node_d_xpm; + this->hot_x = 1; + this->hot_y = 1; + this->sp_event_context_update_cursor(); + this->cursor_drag = true; + } else if (!cdp && this->cursor_drag) { + this->cursor_shape = cursor_node_xpm; + this->hot_x = 1; + this->hot_y = 1; + this->sp_event_context_update_cursor(); + this->cursor_drag = false; } } -void handleControlUiStyleChange(InkNodeTool *nt) -{ - nt->_multipath->updateHandles(); +void InkNodeTool::handleControlUiStyleChange() { + this->_multipath->updateHandles(); } -} // anonymous namespace +//} // anonymous namespace /* Local Variables: diff --git a/src/ui/tool/node-tool.h b/src/ui/tool/node-tool.h index 341faf329..ce022cec6 100644 --- a/src/ui/tool/node-tool.h +++ b/src/ui/tool/node-tool.h @@ -11,70 +11,78 @@ #ifndef SEEN_UI_TOOL_NODE_TOOL_H #define SEEN_UI_TOOL_NODE_TOOL_H -#include <memory> #include <boost/ptr_container/ptr_map.hpp> #include <glib.h> #include "event-context.h" -#define INK_TYPE_NODE_TOOL (ink_node_tool_get_type ()) -#define INK_NODE_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INK_TYPE_NODE_TOOL, InkNodeTool)) -#define INK_NODE_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INK_TYPE_NODE_TOOL, InkNodeToolClass)) -#define INK_IS_NODE_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INK_TYPE_NODE_TOOL)) -#define INK_IS_NODE_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INK_TYPE_NODE_TOOL)) - namespace Inkscape { + namespace Display { + class TemporaryItem; + } + + namespace UI { + class MultiPathManipulator; + class ControlPointSelection; + class Selector; + class ControlPoint; + + struct PathSharedData; + } +} + +#define INK_NODE_TOOL(obj) (dynamic_cast<InkNodeTool*>((SPEventContext*)obj)) +#define INK_IS_NODE_TOOL(obj) (dynamic_cast<const InkNodeTool*>((const SPEventContext*)obj)) + +class InkNodeTool : public SPEventContext { +public: + InkNodeTool(); + virtual ~InkNodeTool(); + + Inkscape::UI::ControlPointSelection* _selected_nodes; + Inkscape::UI::MultiPathManipulator* _multipath; + + bool edit_clipping_paths; + bool edit_masks; + + static const std::string prefsPath; -namespace Display { -class TemporaryItem; -} // namespace Display -namespace UI { -class MultiPathManipulator; -class ControlPointSelection; -class Selector; -struct PathSharedData; -} // namespace UI -} // namespace Inkscape - -typedef std::auto_ptr<Inkscape::UI::MultiPathManipulator> MultiPathPtr; -typedef std::auto_ptr<Inkscape::UI::ControlPointSelection> CSelPtr; -typedef std::auto_ptr<Inkscape::UI::Selector> SelectorPtr; -typedef std::auto_ptr<Inkscape::UI::PathSharedData> PathSharedDataPtr; -typedef boost::ptr_map<SPItem*, ShapeEditor> ShapeEditors; - -struct InkNodeTool : public SPEventContext -{ - sigc::connection _selection_changed_connection; + virtual void setup(); + virtual void set(const Inkscape::Preferences::Entry& val); + virtual bool root_handler(GdkEvent* event); + virtual bool item_handler(SPItem* item, GdkEvent* event); + + virtual const std::string& getPrefsPath(); + +private: + sigc::connection _selection_changed_connection; sigc::connection _mouseover_changed_connection; - sigc::connection _selection_modified_connection; sigc::connection _sizeUpdatedConn; - Inkscape::MessageContext *_node_message_context; + SPItem *flashed_item; Inkscape::Display::TemporaryItem *flash_tempitem; - CSelPtr _selected_nodes; - MultiPathPtr _multipath; - SelectorPtr _selector; - PathSharedDataPtr _path_data; + Inkscape::UI::Selector* _selector; + Inkscape::UI::PathSharedData* _path_data; SPCanvasGroup *_transform_handle_group; SPItem *_last_over; - ShapeEditors _shape_editors; - - unsigned cursor_drag : 1; - unsigned show_handles : 1; - unsigned show_outline : 1; - unsigned live_outline : 1; - unsigned live_objects : 1; - unsigned show_path_direction : 1; - unsigned show_transform_handles : 1; - unsigned single_node_transform_handles : 1; - unsigned edit_clipping_paths : 1; - unsigned edit_masks : 1; -}; + boost::ptr_map<SPItem*, ShapeEditor> _shape_editors; -struct InkNodeToolClass { - SPEventContextClass parent_class; -}; + bool cursor_drag; + bool show_handles; + bool show_outline; + bool live_outline; + bool live_objects; + bool show_path_direction; + bool show_transform_handles; + bool single_node_transform_handles; + + void selection_changed(Inkscape::Selection *sel); -GType ink_node_tool_get_type (void); + void select_area(Geom::Rect const &sel, GdkEventButton *event); + void select_point(Geom::Point const &sel, GdkEventButton *event); + void mouseover_changed(Inkscape::UI::ControlPoint *p); + void update_tip(GdkEvent *event); + void handleControlUiStyleChange(); +}; #endif diff --git a/src/ui/tool/transform-handle-set.cpp b/src/ui/tool/transform-handle-set.cpp index 30963cabd..daed3a523 100644 --- a/src/ui/tool/transform-handle-set.cpp +++ b/src/ui/tool/transform-handle-set.cpp @@ -129,7 +129,8 @@ bool TransformHandle::grabbed(GdkEventMotion *) // Collect the snap-candidates, one for each selected node. These will be stored in the _snap_points vector. InkNodeTool *nt = INK_NODE_TOOL(_th._desktop->event_context); - ControlPointSelection *selection = nt->_selected_nodes.get(); + //ControlPointSelection *selection = nt->_selected_nodes.get(); + ControlPointSelection* selection = nt->_selected_nodes; selection->setOriginalPoints(); selection->getOriginalPoints(_snap_points); @@ -293,7 +294,7 @@ protected: private: static Glib::RefPtr<Gdk::Pixbuf> _corner_to_pixbuf(unsigned c) { - sp_select_context_get_type(); + //sp_select_context_get_type(); switch (c % 2) { case 0: return Glib::wrap(handles[1], true); @@ -376,7 +377,7 @@ protected: } private: static Glib::RefPtr<Gdk::Pixbuf> _side_to_pixbuf(unsigned c) { - sp_select_context_get_type(); + //sp_select_context_get_type(); switch (c % 2) { case 0: return Glib::wrap(handles[3], true); default: return Glib::wrap(handles[2], true); @@ -456,7 +457,7 @@ protected: private: static Glib::RefPtr<Gdk::Pixbuf> _corner_to_pixbuf(unsigned c) { - sp_select_context_get_type(); + //sp_select_context_get_type(); switch (c % 4) { case 0: return Glib::wrap(handles[7], true); case 1: return Glib::wrap(handles[6], true); @@ -603,7 +604,7 @@ protected: private: static Glib::RefPtr<Gdk::Pixbuf> _side_to_pixbuf(unsigned s) { - sp_select_context_get_type(); + //sp_select_context_get_type(); switch (s % 4) { case 0: return Glib::wrap(handles[10], true); case 1: return Glib::wrap(handles[9], true); @@ -658,7 +659,7 @@ protected: private: static Glib::RefPtr<Gdk::Pixbuf> _get_pixbuf() { - sp_select_context_get_type(); + //sp_select_context_get_type(); return Glib::wrap(handles[12], true); } diff --git a/src/ui/view/view-widget.h b/src/ui/view/view-widget.h index 295e7932b..668f9d19a 100644 --- a/src/ui/view/view-widget.h +++ b/src/ui/view/view-widget.h @@ -23,7 +23,7 @@ class View; } // namespace Inkscape class SPViewWidget; -struct SPNamedView; +class SPNamedView; #define SP_TYPE_VIEW_WIDGET (sp_view_widget_get_type ()) #define SP_VIEW_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_VIEW_WIDGET, SPViewWidget)) diff --git a/src/ui/widget/selected-style.cpp b/src/ui/widget/selected-style.cpp index 388a0bcea..894700046 100644 --- a/src/ui/widget/selected-style.cpp +++ b/src/ui/widget/selected-style.cpp @@ -24,8 +24,8 @@ #include "style.h" #include "desktop-style.h" #include "sp-namedview.h" -#include "sp-linear-gradient-fns.h" -#include "sp-radial-gradient-fns.h" +#include "sp-linear-gradient.h" +#include "sp-radial-gradient.h" #include "sp-pattern.h" #include "ui/dialog/dialog-manager.h" #include "ui/dialog/fill-and-stroke.h" @@ -1356,25 +1356,25 @@ RotateableSwatch::do_motion(double by, guint modifier) { DocumentUndo::maybeDone(sp_desktop_document(parent->getDesktop()), undokey, SP_VERB_DIALOG_FILL_STROKE, (_("Adjust alpha"))); double ch = hsla[3]; - parent->getDesktop()->event_context->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>alpha</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Ctrl</b> to adjust lightness, with <b>Shift</b> to adjust saturation, without modifiers to adjust hue"), ch - diff, ch, diff); + parent->getDesktop()->event_context->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>alpha</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Ctrl</b> to adjust lightness, with <b>Shift</b> to adjust saturation, without modifiers to adjust hue"), ch - diff, ch, diff); } else if (modifier == 2) { // saturation DocumentUndo::maybeDone(sp_desktop_document(parent->getDesktop()), undokey, SP_VERB_DIALOG_FILL_STROKE, (_("Adjust saturation"))); double ch = hsla[1]; - parent->getDesktop()->event_context->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>saturation</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Ctrl</b> to adjust lightness, with <b>Alt</b> to adjust alpha, without modifiers to adjust hue"), ch - diff, ch, diff); + parent->getDesktop()->event_context->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>saturation</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Ctrl</b> to adjust lightness, with <b>Alt</b> to adjust alpha, without modifiers to adjust hue"), ch - diff, ch, diff); } else if (modifier == 1) { // lightness DocumentUndo::maybeDone(sp_desktop_document(parent->getDesktop()), undokey, SP_VERB_DIALOG_FILL_STROKE, (_("Adjust lightness"))); double ch = hsla[2]; - parent->getDesktop()->event_context->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>lightness</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Shift</b> to adjust saturation, with <b>Alt</b> to adjust alpha, without modifiers to adjust hue"), ch - diff, ch, diff); + parent->getDesktop()->event_context->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>lightness</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Shift</b> to adjust saturation, with <b>Alt</b> to adjust alpha, without modifiers to adjust hue"), ch - diff, ch, diff); } else { // hue DocumentUndo::maybeDone(sp_desktop_document(parent->getDesktop()), undokey, SP_VERB_DIALOG_FILL_STROKE, (_("Adjust hue"))); double ch = hsla[0]; - parent->getDesktop()->event_context->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>hue</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Shift</b> to adjust saturation, with <b>Alt</b> to adjust alpha, with <b>Ctrl</b> to adjust lightness"), ch - diff, ch, diff); + parent->getDesktop()->event_context->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>hue</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Shift</b> to adjust saturation, with <b>Alt</b> to adjust alpha, with <b>Ctrl</b> to adjust lightness"), ch - diff, ch, diff); } } @@ -1429,7 +1429,7 @@ RotateableSwatch::do_release(double by, guint modifier) { undokey = "ssrot1"; } - parent->getDesktop()->event_context->_message_context->clear(); + parent->getDesktop()->event_context->message_context->clear(); startcolor_set = false; } @@ -1495,7 +1495,7 @@ RotateableStrokeWidth::do_motion(double by, guint modifier) { double diff = value_adjust(startvalue, by, modifier, false); DocumentUndo::maybeDone(sp_desktop_document(parent->getDesktop()), undokey, SP_VERB_DIALOG_FILL_STROKE, (_("Adjust stroke width"))); - parent->getDesktop()->event_context->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>stroke width</b>: was %.3g, now <b>%.3g</b> (diff %.3g)"), startvalue, startvalue + diff, diff); + parent->getDesktop()->event_context->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>stroke width</b>: was %.3g, now <b>%.3g</b> (diff %.3g)"), startvalue, startvalue + diff, diff); } } @@ -1516,7 +1516,7 @@ RotateableStrokeWidth::do_release(double by, guint modifier) { } else { undokey = "swrot1"; } - parent->getDesktop()->event_context->_message_context->clear(); + parent->getDesktop()->event_context->message_context->clear(); } void diff --git a/src/ui/widget/style-swatch.cpp b/src/ui/widget/style-swatch.cpp index 682457bed..49466ce54 100644 --- a/src/ui/widget/style-swatch.cpp +++ b/src/ui/widget/style-swatch.cpp @@ -20,8 +20,8 @@ #include "ui/widget/color-preview.h" #include "style.h" -#include "sp-linear-gradient-fns.h" -#include "sp-radial-gradient-fns.h" +#include "sp-linear-gradient.h" +#include "sp-radial-gradient.h" #include "sp-pattern.h" #include "xml/repr.h" #include "xml/sp-css-attr.h" diff --git a/src/verbs.cpp b/src/verbs.cpp index 737d9e150..23a560423 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -1173,6 +1173,10 @@ void SelectionVerb::perform(SPAction *action, void *data) inkscape_dialogs_unhide(); dt->_dlg_mgr->showDialog("Trace"); break; + case SP_VERB_SELECTION_PIXEL_ART: + inkscape_dialogs_unhide(); + dt->_dlg_mgr->showDialog("PixelArt"); + break; case SP_VERB_SELECTION_CREATE_BITMAP: sp_selection_create_bitmap_copy(dt); break; @@ -2545,6 +2549,8 @@ Verb *Verb::_base_verbs[] = { // TRANSLATORS: "to trace" means "to convert a bitmap to vector graphics" (to vectorize) new SelectionVerb(SP_VERB_SELECTION_TRACE, "SelectionTrace", N_("_Trace Bitmap..."), N_("Create one or more paths from a bitmap by tracing it"), INKSCAPE_ICON("bitmap-trace")), + new SelectionVerb(SP_VERB_SELECTION_PIXEL_ART, "SelectionPixelArt", N_("Trace Pixel Art..."), + N_("Create paths using Kopf-Lischinski algorithm to vectorize pixel art"), INKSCAPE_ICON("pixelart-trace")), new SelectionVerb(SP_VERB_SELECTION_CREATE_BITMAP, "SelectionCreateBitmap", N_("Make a _Bitmap Copy"), N_("Export selection to a bitmap and insert it into document"), INKSCAPE_ICON("selection-make-bitmap-copy") ), new SelectionVerb(SP_VERB_SELECTION_COMBINE, "SelectionCombine", N_("_Combine"), diff --git a/src/verbs.h b/src/verbs.h index c4b01dfbf..40292745a 100644 --- a/src/verbs.h +++ b/src/verbs.h @@ -134,6 +134,7 @@ enum { SP_VERB_SELECTION_SIMPLIFY, SP_VERB_SELECTION_REVERSE, SP_VERB_SELECTION_TRACE, + SP_VERB_SELECTION_PIXEL_ART, SP_VERB_SELECTION_CREATE_BITMAP, SP_VERB_SELECTION_COMBINE, SP_VERB_SELECTION_BREAK_APART, diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index 6493da84d..e9c2e6ef3 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -1809,7 +1809,10 @@ sp_desktop_widget_adjustment_value_changed (GtkAdjustment */*adj*/, SPDesktopWid sp_desktop_widget_update_rulers (dtw); /* update perspective lines if we are in the 3D box tool (so that infinite ones are shown correctly) */ - sp_box3d_context_update_lines(dtw->desktop->event_context); + //sp_box3d_context_update_lines(dtw->desktop->event_context); + if (SP_IS_BOX3D_CONTEXT(dtw->desktop->event_context)) { + SP_BOX3D_CONTEXT(dtw->desktop->event_context)->_vpdrag->updateLines(); + } dtw->update = 0; } diff --git a/src/widgets/gradient-image.cpp b/src/widgets/gradient-image.cpp index 9a5dd4996..64b058f62 100644 --- a/src/widgets/gradient-image.cpp +++ b/src/widgets/gradient-image.cpp @@ -16,7 +16,6 @@ #include "display/cairo-utils.h" #include "gradient-image.h" #include "sp-gradient.h" -#include "sp-gradient-fns.h" #include <sigc++/functors/ptr_fun.h> #include <sigc++/adaptors/bind.h> diff --git a/src/widgets/gradient-toolbar.cpp b/src/widgets/gradient-toolbar.cpp index c1eb13ceb..5f29e8ed8 100644 --- a/src/widgets/gradient-toolbar.cpp +++ b/src/widgets/gradient-toolbar.cpp @@ -91,7 +91,8 @@ void gr_apply_gradient_to_item( SPItem *item, SPGradient *gr, SPGradientType ini bool isFill = (mode == Inkscape::FOR_FILL); if (style && (isFill ? style->fill.isPaintserver() : style->stroke.isPaintserver()) - && SP_IS_GRADIENT(isFill ? style->getFillPaintServer() : style->getStrokePaintServer()) ) { + //&& SP_IS_GRADIENT(isFill ? style->getFillPaintServer() : style->getStrokePaintServer()) ) { + && (isFill ? SP_IS_GRADIENT(style->getFillPaintServer()) : SP_IS_GRADIENT(style->getStrokePaintServer())) ) { SPPaintServer *server = isFill ? style->getFillPaintServer() : style->getStrokePaintServer(); if ( SP_IS_LINEARGRADIENT(server) ) { sp_item_set_gradient(item, gr, SP_GRADIENT_TYPE_LINEAR, mode); @@ -372,7 +373,7 @@ static void gr_tb_selection_changed(Inkscape::Selection * /*selection*/, gpointe Inkscape::Selection *selection = sp_desktop_selection(desktop); // take from desktop, not from args if (selection) { - SPEventContext *ev = sp_desktop_event_context(desktop); + SPEventContext *ev = desktop->getEventContext(); GrDrag *drag = NULL; if (ev) { drag = ev->get_drag(); @@ -584,7 +585,7 @@ static void gr_add_stop(GtkWidget * /*button*/, GtkWidget *vb) return; } - SPEventContext *ev = sp_desktop_event_context(desktop); + SPEventContext *ev = desktop->getEventContext(); SPGradientContext *rc = SP_GRADIENT_CONTEXT(ev); if (rc) { @@ -606,7 +607,7 @@ static void gr_remove_stop(GtkWidget * /*button*/, GtkWidget *vb) return; } - SPEventContext *ev = sp_desktop_event_context(desktop); + SPEventContext *ev = desktop->getEventContext(); GrDrag *drag = NULL; if (ev) { drag = ev->get_drag(); @@ -799,7 +800,7 @@ static gboolean update_stop_list( GtkWidget *stop_combo, SPGradient *gradient, S if (SP_IS_STOP(sl->data)){ SPStop *stop = SP_STOP(sl->data); Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(sl->data)->getRepr(); - Inkscape::UI::Widget::ColorPreview *cpv = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(sp_stop_get_rgba32(stop))); + Inkscape::UI::Widget::ColorPreview *cpv = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(stop->get_rgba32())); GdkPixbuf *pb = cpv->toPixbuf(32, 16); Glib::ustring label = gr_ellipsize_text(repr->attribute("id"), 25); @@ -938,7 +939,7 @@ static void gr_gradient_combo_changed(EgeSelectOneAction *act, gpointer data) SPDesktop *desktop = static_cast<SPDesktop *>(data); Inkscape::Selection *selection = sp_desktop_selection(desktop); - SPEventContext *ev = sp_desktop_event_context(desktop); + SPEventContext *ev = desktop->getEventContext(); gr_apply_gradient(selection, ev? ev->get_drag() : NULL, gr); @@ -980,7 +981,7 @@ static void gr_stop_combo_changed(GtkComboBox * /*widget*/, GtkWidget *data) } SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(G_OBJECT(data), "desktop")); - SPEventContext *ev = sp_desktop_event_context(desktop); + SPEventContext *ev = desktop->getEventContext(); SPGradient *gr = gr_get_selected_gradient(data); select_drag_by_stop(data, gr, ev); diff --git a/src/widgets/gradient-vector.cpp b/src/widgets/gradient-vector.cpp index 118d8a68a..e9fc426f6 100644 --- a/src/widgets/gradient-vector.cpp +++ b/src/widgets/gradient-vector.cpp @@ -369,7 +369,7 @@ static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs) unsigned long sp_gradient_to_hhssll(SPGradient *gr) { SPStop *stop = gr->getFirstStop(); - unsigned long rgba = sp_stop_get_rgba32(stop); + unsigned long rgba = stop->get_rgba32(); float hsl[3]; sp_color_rgb_to_hsl_floatv (hsl, SP_RGBA32_R_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_B_F(rgba)); @@ -635,7 +635,7 @@ static void update_stop_list( GtkWidget *vb, SPGradient *gradient, SPStop *new_s if (SP_IS_STOP(sl->data)){ SPStop *stop = SP_STOP(sl->data); Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(sl->data)->getRepr(); - Inkscape::UI::Widget::ColorPreview *cpv = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(sp_stop_get_rgba32(stop))); + Inkscape::UI::Widget::ColorPreview *cpv = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(stop->get_rgba32())); GdkPixbuf *pb = cpv->toPixbuf(64, 16); gtk_list_store_append (store, &iter); @@ -791,8 +791,8 @@ static void sp_grd_ed_add_stop(GtkWidget */*widget*/, GtkWidget *vb) newstop->offset = (stop->offset + next->offset) * 0.5 ; - guint32 const c1 = sp_stop_get_rgba32(stop); - guint32 const c2 = sp_stop_get_rgba32(next); + guint32 const c1 = stop->get_rgba32(); + guint32 const c2 = next->get_rgba32(); guint32 cnew = sp_average_color(c1, c2); Inkscape::CSSOStringStream os; @@ -1315,7 +1315,7 @@ static void sp_gradient_vector_color_changed(SPColorSelector *csel, GObject *obj if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX(combo_box), &iter)) { GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combo_box))); - Inkscape::UI::Widget::ColorPreview *cp = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(sp_stop_get_rgba32(stop))); + Inkscape::UI::Widget::ColorPreview *cp = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(stop->get_rgba32())); GdkPixbuf *pb = cp->toPixbuf(64, 16); gtk_list_store_set (store, &iter, 0, pb, /*1, repr->attribute("id"),*/ 2, stop, -1); diff --git a/src/widgets/gradient-vector.h b/src/widgets/gradient-vector.h index 64e40a35b..b63120a6e 100644 --- a/src/widgets/gradient-vector.h +++ b/src/widgets/gradient-vector.h @@ -40,7 +40,7 @@ class SPDocument; class SPObject; class SPGradient; -struct SPStop; +class SPStop; struct SPGradientVectorSelector { GtkVBox vbox; diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index cd987cc87..9466c875e 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -36,8 +36,8 @@ #include "xml/repr.h" #include "sp-color-notebook.h" -#include "sp-linear-gradient-fns.h" -#include "sp-radial-gradient-fns.h" +#include "sp-linear-gradient.h" +#include "sp-radial-gradient.h" /* fixme: Move it from dialogs to here */ #include "gradient-selector.h" #include <inkscape.h> diff --git a/src/widgets/paint-selector.h b/src/widgets/paint-selector.h index a66758434..d3b3f4116 100644 --- a/src/widgets/paint-selector.h +++ b/src/widgets/paint-selector.h @@ -22,7 +22,7 @@ class SPGradient; class SPDesktop; -struct SPPattern; +class SPPattern; struct SPStyle; #define SP_TYPE_PAINT_SELECTOR (sp_paint_selector_get_type ()) diff --git a/src/widgets/paintbucket-toolbar.cpp b/src/widgets/paintbucket-toolbar.cpp index 7c23379cd..1d8ae7ae9 100644 --- a/src/widgets/paintbucket-toolbar.cpp +++ b/src/widgets/paintbucket-toolbar.cpp @@ -79,7 +79,8 @@ using Inkscape::Util::unit_table; static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* /*tbl*/) { gint channels = ege_select_one_action_get_active( act ); - flood_channels_set_channels( channels ); + //flood_channels_set_channels( channels ); + SPFloodContext::set_channels(channels); } static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject * /*tbl*/) diff --git a/src/widgets/rect-toolbar.cpp b/src/widgets/rect-toolbar.cpp index 6dfd9cfcb..fb64ae14b 100644 --- a/src/widgets/rect-toolbar.cpp +++ b/src/widgets/rect-toolbar.cpp @@ -88,7 +88,7 @@ static void sp_rtb_sensitivize( GObject *tbl ) static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, - void (*setter)(SPRect *, gdouble)) + void (SPRect::*setter)(gdouble)) { SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); @@ -114,8 +114,7 @@ static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const * for (GSList const *items = selection->itemList(); items != NULL; items = items->next) { if (SP_IS_RECT(items->data)) { if (gtk_adjustment_get_value(adj) != 0) { - setter(SP_RECT(items->data), - Quantity::convert(gtk_adjustment_get_value(adj), unit, "px")); + (SP_RECT(items->data)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, "px")); } else { SP_OBJECT(items->data)->getRepr()->setAttribute(value_name, NULL); } @@ -135,22 +134,22 @@ static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const * static void sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl) { - sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx); + sp_rtb_value_changed(adj, tbl, "rx", &SPRect::setVisibleRx); } static void sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl) { - sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry); + sp_rtb_value_changed(adj, tbl, "ry", &SPRect::setVisibleRy); } static void sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl) { - sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width); + sp_rtb_value_changed(adj, tbl, "width", &SPRect::setVisibleWidth); } static void sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl) { - sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height); + sp_rtb_value_changed(adj, tbl, "height", &SPRect::setVisibleHeight); } @@ -192,25 +191,29 @@ static void rect_tb_event_attr_changed(Inkscape::XML::Node * /*repr*/, gchar con if (item && SP_IS_RECT(item)) { { GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) ); - gdouble rx = sp_rect_get_visible_rx(SP_RECT(item)); + + gdouble rx = SP_RECT(item)->getVisibleRx(); gtk_adjustment_set_value(adj, Quantity::convert(rx, "px", unit)); } { GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) ); - gdouble ry = sp_rect_get_visible_ry(SP_RECT(item)); + + gdouble ry = SP_RECT(item)->getVisibleRy(); gtk_adjustment_set_value(adj, Quantity::convert(ry, "px", unit)); } { GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) ); - gdouble width = sp_rect_get_visible_width (SP_RECT(item)); + + gdouble width = SP_RECT(item)->getVisibleWidth(); gtk_adjustment_set_value(adj, Quantity::convert(width, "px", unit)); } { GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) ); - gdouble height = sp_rect_get_visible_height (SP_RECT(item)); + + gdouble height = SP_RECT(item)->getVisibleHeight(); gtk_adjustment_set_value(adj, Quantity::convert(height, "px", unit)); } } diff --git a/src/widgets/sp-color-icc-selector.h b/src/widgets/sp-color-icc-selector.h index 404bc7265..3eb12222c 100644 --- a/src/widgets/sp-color-icc-selector.h +++ b/src/widgets/sp-color-icc-selector.h @@ -8,7 +8,7 @@ #include "sp-color-selector.h" namespace Inkscape { -struct ColorProfile; +class ColorProfile; } struct SPColorICCSelector; diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index 12d4002b8..31f4bb2e5 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -707,7 +707,7 @@ StrokeStyle::getItemColorForMarker(SPItem *item, Inkscape::PaintTarget fill_or_s stop = sp_last_stop(vector); } if (stop) { - guint32 const c1 = sp_stop_get_rgba32(stop); + guint32 const c1 = stop->get_rgba32(); gchar c[64]; sp_svg_write_color(c, sizeof(c), c1); color = g_strdup(c); diff --git a/src/widgets/swatch-selector.cpp b/src/widgets/swatch-selector.cpp index ad59e0dc3..7178ad072 100644 --- a/src/widgets/swatch-selector.cpp +++ b/src/widgets/swatch-selector.cpp @@ -172,7 +172,7 @@ void SwatchSelector::setVector(SPDocument */*doc*/, SPGradient *vector) if ( vector && vector->isSolid() ) { SPStop* stop = vector->getFirstStop(); - guint32 const colorVal = sp_stop_get_rgba32(stop); + guint32 const colorVal = stop->get_rgba32(); _csel->base->setAlpha(SP_RGBA32_A_F(colorVal)); SPColor color( SP_RGBA32_R_F(colorVal), SP_RGBA32_G_F(colorVal), SP_RGBA32_B_F(colorVal) ); // set its color, from the stored array diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index 340359ca7..a171ce29b 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -96,6 +96,8 @@ #include "toolbox.h" #include <gtk/gtk.h> +#include "event-context.h" + //#define DEBUG_TEXT using Inkscape::UI::UXManager; @@ -136,29 +138,29 @@ static struct { sp_verb_t verb; sp_verb_t doubleclick_verb; } const tools[] = { - { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS}, - { "InkNodeTool", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS }, - { "SPTweakContext", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS }, - { "SPSprayContext", "spray_tool", SP_VERB_CONTEXT_SPRAY, SP_VERB_CONTEXT_SPRAY_PREFS }, - { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS }, - { "SPMeasureContext", "measure_tool", SP_VERB_CONTEXT_MEASURE, SP_VERB_CONTEXT_MEASURE_PREFS }, - { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS }, - { "Box3DContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS }, - { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS }, - { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS }, - { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS }, - { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS }, - { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS }, - { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS }, - { "SPLPEToolContext", "lpetool_tool", SP_VERB_CONTEXT_LPETOOL, SP_VERB_CONTEXT_LPETOOL_PREFS }, - { "SPEraserContext", "eraser_tool", SP_VERB_CONTEXT_ERASER, SP_VERB_CONTEXT_ERASER_PREFS }, - { "SPFloodContext", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS }, - { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS }, - { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS }, - { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS }, - { "SPMeshContext", "mesh_tool", SP_VERB_CONTEXT_MESH, SP_VERB_CONTEXT_MESH_PREFS }, - { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS }, - { NULL, NULL, 0, 0 } + { "/tools/select", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS}, + { "/tools/nodes", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS }, + { "/tools/tweak", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS }, + { "/tools/spray", "spray_tool", SP_VERB_CONTEXT_SPRAY, SP_VERB_CONTEXT_SPRAY_PREFS }, + { "/tools/zoom", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS }, + { "/tools/measure", "measure_tool", SP_VERB_CONTEXT_MEASURE, SP_VERB_CONTEXT_MEASURE_PREFS }, + { "/tools/shapes/rect", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS }, + { "/tools/shapes/3dbox", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS }, + { "/tools/shapes/arc", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS }, + { "/tools/shapes/star", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS }, + { "/tools/shapes/spiral", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS }, + { "/tools/freehand/pencil", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS }, + { "/tools/freehand/pen", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS }, + { "/tools/calligraphic", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS }, + { "/tools/lpetool", "lpetool_tool", SP_VERB_CONTEXT_LPETOOL, SP_VERB_CONTEXT_LPETOOL_PREFS }, + { "/tools/eraser", "eraser_tool", SP_VERB_CONTEXT_ERASER, SP_VERB_CONTEXT_ERASER_PREFS }, + { "/tools/paintbucket", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS }, + { "/tools/text", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS }, + { "/tools/connector","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS }, + { "/tools/gradient", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS }, + { "/tools/mesh", "mesh_tool", SP_VERB_CONTEXT_MESH, SP_VERB_CONTEXT_MESH_PREFS }, + { "/tools/dropper", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS }, + { NULL, NULL, 0, 0 } }; static struct { @@ -171,49 +173,49 @@ static struct { gchar const *swatch_tool; gchar const *swatch_tip; } const aux_toolboxes[] = { - { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar", + { "/tools/select", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar", SP_VERB_INVALID, 0, 0}, - { "InkNodeTool", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar", + { "/tools/nodes", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar", SP_VERB_INVALID, 0, 0}, - { "SPTweakContext", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar", + { "/tools/tweak", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar", SP_VERB_CONTEXT_TWEAK_PREFS, "/tools/tweak", N_("Color/opacity used for color tweaking")}, - { "SPSprayContext", "spray_toolbox", 0, sp_spray_toolbox_prep, "SprayToolbar", + { "/tools/spray", "spray_toolbox", 0, sp_spray_toolbox_prep, "SprayToolbar", SP_VERB_INVALID, 0, 0}, - { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar", + { "/tools/zoom", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar", SP_VERB_INVALID, 0, 0}, - { "SPMeasureContext", "measure_toolbox", 0, sp_measure_toolbox_prep, "MeasureToolbar", + { "/tools/measure", "measure_toolbox", 0, sp_measure_toolbox_prep, "MeasureToolbar", SP_VERB_INVALID, 0, 0}, - { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar", + { "/tools/shapes/star", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar", SP_VERB_CONTEXT_STAR_PREFS, "/tools/shapes/star", N_("Style of new stars")}, - { "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar", + { "/tools/shapes/rect", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar", SP_VERB_CONTEXT_RECT_PREFS, "/tools/shapes/rect", N_("Style of new rectangles")}, - { "Box3DContext", "3dbox_toolbox", 0, box3d_toolbox_prep, "3DBoxToolbar", + { "/tools/shapes/3dbox", "3dbox_toolbox", 0, box3d_toolbox_prep, "3DBoxToolbar", SP_VERB_CONTEXT_3DBOX_PREFS, "/tools/shapes/3dbox", N_("Style of new 3D boxes")}, - { "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar", + { "/tools/shapes/arc", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar", SP_VERB_CONTEXT_ARC_PREFS, "/tools/shapes/arc", N_("Style of new ellipses")}, - { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar", + { "/tools/shapes/spiral", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar", SP_VERB_CONTEXT_SPIRAL_PREFS, "/tools/shapes/spiral", N_("Style of new spirals")}, - { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar", + { "/tools/freehand/pencil", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar", SP_VERB_CONTEXT_PENCIL_PREFS, "/tools/freehand/pencil", N_("Style of new paths created by Pencil")}, - { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar", + { "/tools/freehand/pen", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar", SP_VERB_CONTEXT_PEN_PREFS, "/tools/freehand/pen", N_("Style of new paths created by Pen")}, - { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar", + { "/tools/calligraphic", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar", SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "/tools/calligraphic", N_("Style of new calligraphic strokes")}, - { "SPEraserContext", "eraser_toolbox", 0, sp_eraser_toolbox_prep,"EraserToolbar", + { "/tools/eraser", "eraser_toolbox", 0, sp_eraser_toolbox_prep,"EraserToolbar", SP_VERB_CONTEXT_ERASER_PREFS, "/tools/eraser", _("TBD")}, - { "SPLPEToolContext", "lpetool_toolbox", 0, sp_lpetool_toolbox_prep, "LPEToolToolbar", + { "/tools/lpetool", "lpetool_toolbox", 0, sp_lpetool_toolbox_prep, "LPEToolToolbar", SP_VERB_CONTEXT_LPETOOL_PREFS, "/tools/lpetool", _("TBD")}, - { "SPTextContext", "text_toolbox", 0, sp_text_toolbox_prep, "TextToolbar", + { "/tools/text", "text_toolbox", 0, sp_text_toolbox_prep, "TextToolbar", SP_VERB_INVALID, 0, 0}, - { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar", + { "/tools/dropper", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar", SP_VERB_INVALID, 0, 0}, - { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar", + { "/tools/connector", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar", SP_VERB_INVALID, 0, 0}, - { "SPGradientContext", "gradient_toolbox", 0, sp_gradient_toolbox_prep, "GradientToolbar", + { "/tools/gradient", "gradient_toolbox", 0, sp_gradient_toolbox_prep, "GradientToolbar", SP_VERB_INVALID, 0, 0}, - { "SPMeshContext", "mesh_toolbox", 0, sp_mesh_toolbox_prep, "MeshToolbar", + { "/tools/mesh", "mesh_toolbox", 0, sp_mesh_toolbox_prep, "MeshToolbar", SP_VERB_INVALID, 0, 0}, - { "SPFloodContext", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar", + { "/tools/paintbucket", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar", SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "/tools/paintbucket", N_("Style of Paint Bucket fill objects")}, { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL } }; @@ -1309,7 +1311,7 @@ void setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop) void update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget * /*toolbox*/ ) { gchar const *const tname = ( eventcontext - ? g_type_name(G_OBJECT_TYPE(eventcontext)) + ? eventcontext->getPrefsPath().c_str() //g_type_name(G_OBJECT_TYPE(eventcontext)) : NULL ); Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop ); @@ -1431,7 +1433,7 @@ void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop) void update_aux_toolbox(SPDesktop * /*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox) { gchar const *tname = ( eventcontext - ? g_type_name(G_OBJECT_TYPE(eventcontext)) + ? eventcontext->getPrefsPath().c_str() //g_type_name(G_OBJECT_TYPE(eventcontext)) : NULL ); for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) { GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name)); diff --git a/src/widgets/toolbox.h b/src/widgets/toolbox.h index 197f0fb5e..0ae4d4630 100644 --- a/src/widgets/toolbox.h +++ b/src/widgets/toolbox.h @@ -23,7 +23,7 @@ #define TOOLBAR_SLIDER_HINT "full" class SPDesktop; -struct SPEventContext; +class SPEventContext; namespace Inkscape { namespace UI { diff --git a/src/zoom-context.cpp b/src/zoom-context.cpp index 8b06c3e08..6efc122f7 100644 --- a/src/zoom-context.cpp +++ b/src/zoom-context.cpp @@ -25,96 +25,71 @@ #include "selection-chemistry.h" #include "zoom-context.h" +#include "tool-factory.h" -static void sp_zoom_context_setup(SPEventContext *ec); -static void sp_zoom_context_finish (SPEventContext *ec); +namespace { + SPEventContext* createZoomContext() { + return new SPZoomContext(); + } -static gint sp_zoom_context_root_handler(SPEventContext *event_context, GdkEvent *event); -static gint sp_zoom_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event); - -static gint xp = 0, yp = 0; // where drag started -static gint tolerance = 0; -static bool within_tolerance = false; -static bool escaped; - -G_DEFINE_TYPE(SPZoomContext, sp_zoom_context, SP_TYPE_EVENT_CONTEXT); + bool zoomContextRegistered = ToolFactory::instance().registerObject("/tools/zoom", createZoomContext); +} -static void sp_zoom_context_class_init(SPZoomContextClass *klass) -{ - SPEventContextClass *event_context_class = SP_EVENT_CONTEXT_CLASS(klass); +const std::string& SPZoomContext::getPrefsPath() { + return SPZoomContext::prefsPath; +} - event_context_class->setup = sp_zoom_context_setup; - event_context_class->finish = sp_zoom_context_finish; +const std::string SPZoomContext::prefsPath = "/tools/zoom"; - event_context_class->root_handler = sp_zoom_context_root_handler; - event_context_class->item_handler = sp_zoom_context_item_handler; +SPZoomContext::SPZoomContext() : SPEventContext() { + this->grabbed = 0; + this->cursor_shape = cursor_zoom_xpm; + this->hot_x = 6; + this->hot_y = 6; + this->escaped = false; } -static void sp_zoom_context_init (SPZoomContext *zoom_context) -{ - SPEventContext *event_context = SP_EVENT_CONTEXT(zoom_context); - - event_context->cursor_shape = cursor_zoom_xpm; - event_context->hot_x = 6; - event_context->hot_y = 6; +SPZoomContext::~SPZoomContext() { } -static void -sp_zoom_context_finish (SPEventContext *ec) -{ - SPZoomContext *zc = SP_ZOOM_CONTEXT(ec); - - ec->enableGrDrag(false); +void SPZoomContext::finish() { + this->enableGrDrag(false); - if (zc->grabbed) { - sp_canvas_item_ungrab(zc->grabbed, GDK_CURRENT_TIME); - zc->grabbed = NULL; + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, GDK_CURRENT_TIME); + this->grabbed = NULL; } } -static void sp_zoom_context_setup(SPEventContext *ec) -{ +void SPZoomContext::setup() { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (prefs->getBool("/tools/zoom/selcue")) { - ec->enableSelectionCue(); - } - if (prefs->getBool("/tools/zoom/gradientdrag")) { - ec->enableGrDrag(); - } - if ((SP_EVENT_CONTEXT_CLASS(sp_zoom_context_parent_class))->setup) { - (SP_EVENT_CONTEXT_CLASS(sp_zoom_context_parent_class))->setup(ec); + if (prefs->getBool("/tools/zoom/selcue")) { + this->enableSelectionCue(); } -} -static gint sp_zoom_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event) -{ - gint ret = FALSE; - - if ((SP_EVENT_CONTEXT_CLASS(sp_zoom_context_parent_class))->item_handler) { - ret = (SP_EVENT_CONTEXT_CLASS(sp_zoom_context_parent_class))->item_handler (event_context, item, event); + if (prefs->getBool("/tools/zoom/gradientdrag")) { + this->enableGrDrag(); } - return ret; + SPEventContext::setup(); } -static gint sp_zoom_context_root_handler(SPEventContext *event_context, GdkEvent *event) -{ - SPDesktop *desktop = event_context->desktop; +bool SPZoomContext::root_handler(GdkEvent* event) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - SPZoomContext *zc = SP_ZOOM_CONTEXT(event_context); tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); double const zoom_inc = prefs->getDoubleLimited("/options/zoomincrement/value", M_SQRT2, 1.01, 10); - gint ret = FALSE; + bool ret = false; switch (event->type) { case GDK_BUTTON_PRESS: { Geom::Point const button_w(event->button.x, event->button.y); Geom::Point const button_dt(desktop->w2d(button_w)); - if (event->button.button == 1 && !event_context->space_panning) { + + if (event->button.button == 1 && !this->space_panning) { // save drag origin xp = (gint) event->button.x; yp = (gint) event->button.y; @@ -124,26 +99,27 @@ static gint sp_zoom_context_root_handler(SPEventContext *event_context, GdkEvent escaped = false; - ret = TRUE; + ret = true; } else if (event->button.button == 3) { double const zoom_rel( (event->button.state & GDK_SHIFT_MASK) ? zoom_inc : 1 / zoom_inc ); + desktop->zoom_relative_keep_point(button_dt, zoom_rel); - ret = TRUE; + ret = true; } sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK, NULL, event->button.time); - zc->grabbed = SP_CANVAS_ITEM(desktop->acetate); - + + this->grabbed = SP_CANVAS_ITEM(desktop->acetate); break; } case GDK_MOTION_NOTIFY: - if (event->motion.state & GDK_BUTTON1_MASK && !event_context->space_panning) { - ret = TRUE; + if ((event->motion.state & GDK_BUTTON1_MASK) && !this->space_panning) { + ret = true; if ( within_tolerance && ( abs( (gint) event->motion.x - xp ) < tolerance ) @@ -166,23 +142,28 @@ static gint sp_zoom_context_root_handler(SPEventContext *event_context, GdkEvent { Geom::Point const button_w(event->button.x, event->button.y); Geom::Point const button_dt(desktop->w2d(button_w)); - if ( event->button.button == 1 && !event_context->space_panning) { + + if ( event->button.button == 1 && !this->space_panning) { Geom::OptRect const b = Inkscape::Rubberband::get(desktop)->getRectangle(); + if (b && !within_tolerance) { desktop->set_display_area(*b, 10); } else if (!escaped) { double const zoom_rel( (event->button.state & GDK_SHIFT_MASK) ? 1 / zoom_inc : zoom_inc ); + desktop->zoom_relative_keep_point(button_dt, zoom_rel); } - ret = TRUE; - } + + ret = true; + } + Inkscape::Rubberband::get(desktop)->stop(); - if (zc->grabbed) { - sp_canvas_item_ungrab(zc->grabbed, event->button.time); - zc->grabbed = NULL; + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, event->button.time); + this->grabbed = NULL; } xp = yp = 0; @@ -195,28 +176,32 @@ static gint sp_zoom_context_root_handler(SPEventContext *event_context, GdkEvent if (!Inkscape::Rubberband::get(desktop)->is_started()) { Inkscape::SelectionHelper::selectNone(desktop); } + Inkscape::Rubberband::get(desktop)->stop(); xp = yp = 0; escaped = true; - ret = TRUE; + ret = true; break; + case GDK_KEY_Up: case GDK_KEY_Down: case GDK_KEY_KP_Up: case GDK_KEY_KP_Down: // prevent the zoom field from activation if (!MOD__CTRL_ONLY(event)) - ret = TRUE; + ret = true; break; + case GDK_KEY_Shift_L: case GDK_KEY_Shift_R: - event_context->cursor_shape = cursor_zoom_out_xpm; - sp_event_context_update_cursor(event_context); + this->cursor_shape = cursor_zoom_out_xpm; + this->sp_event_context_update_cursor(); break; + case GDK_KEY_Delete: case GDK_KEY_KP_Delete: case GDK_KEY_BackSpace: - ret = event_context->deleteSelectedDrag(MOD__CTRL_ONLY(event)); + ret = this->deleteSelectedDrag(MOD__CTRL_ONLY(event)); break; default: @@ -225,23 +210,21 @@ static gint sp_zoom_context_root_handler(SPEventContext *event_context, GdkEvent break; case GDK_KEY_RELEASE: switch (get_group0_keyval (&event->key)) { - case GDK_KEY_Shift_L: - case GDK_KEY_Shift_R: - event_context->cursor_shape = cursor_zoom_xpm; - sp_event_context_update_cursor(event_context); + case GDK_KEY_Shift_L: + case GDK_KEY_Shift_R: + this->cursor_shape = cursor_zoom_xpm; + this->sp_event_context_update_cursor(); break; - default: + default: break; - } + } break; default: break; } if (!ret) { - if ((SP_EVENT_CONTEXT_CLASS(sp_zoom_context_parent_class))->root_handler) { - ret = (SP_EVENT_CONTEXT_CLASS(sp_zoom_context_parent_class))->root_handler(event_context, event); - } + ret = SPEventContext::root_handler(event); } return ret; diff --git a/src/zoom-context.h b/src/zoom-context.h index c09b5a1b3..3e98915af 100644 --- a/src/zoom-context.h +++ b/src/zoom-context.h @@ -15,19 +15,25 @@ #include "event-context.h" -#define SP_TYPE_ZOOM_CONTEXT (sp_zoom_context_get_type ()) -#define SP_ZOOM_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_ZOOM_CONTEXT, SPZoomContext)) -#define SP_IS_ZOOM_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_ZOOM_CONTEXT)) +#define SP_ZOOM_CONTEXT(obj) (dynamic_cast<SPZoomContext*>((SPEventContext*)obj)) +#define SP_IS_ZOOM_CONTEXT(obj) (dynamic_cast<const SPZoomContext*>((const SPEventContext*)obj) != NULL) -struct SPZoomContext { - SPEventContext event_context; - SPCanvasItem *grabbed; -}; +class SPZoomContext : public SPEventContext { +public: + SPZoomContext(); + virtual ~SPZoomContext(); -struct SPZoomContextClass { - SPEventContextClass parent_class; -}; + static const std::string prefsPath; + + virtual void setup(); + virtual void finish(); + virtual bool root_handler(GdkEvent* event); -GType sp_zoom_context_get_type (void); + virtual const std::string& getPrefsPath(); + +private: + SPCanvasItem *grabbed; + bool escaped; +}; #endif |
