summaryrefslogtreecommitdiffstats
path: root/src/ui
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2014-11-23 23:36:49 +0000
committerJabiertxof <jtx@jtx.marker.es>2014-11-23 23:36:49 +0000
commit0969085ddf607a7a98cf7fd6d9b10da5fbebe62d (patch)
tree59b2bc9ed3412ab2de4c703ef30342dfe2401704 /src/ui
parentrefactor from lastApplied (diff)
parentFixed a bug pointed by suv running from comand line, also removed another des... (diff)
downloadinkscape-0969085ddf607a7a98cf7fd6d9b10da5fbebe62d.tar.gz
inkscape-0969085ddf607a7a98cf7fd6d9b10da5fbebe62d.zip
fixing to trunk
(bzr r12588.1.34)
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/CMakeLists.txt19
-rw-r--r--src/ui/Makefile_insert13
-rw-r--r--src/ui/clipboard.cpp150
-rw-r--r--src/ui/dialog-events.cpp255
-rw-r--r--src/ui/dialog-events.h76
-rw-r--r--src/ui/dialog/Makefile_insert8
-rw-r--r--src/ui/dialog/aboutbox.cpp40
-rw-r--r--src/ui/dialog/aboutbox.h6
-rw-r--r--src/ui/dialog/align-and-distribute.cpp8
-rw-r--r--src/ui/dialog/calligraphic-profile-rename.h2
-rw-r--r--src/ui/dialog/clonetiler.cpp51
-rw-r--r--src/ui/dialog/clonetiler.h5
-rw-r--r--src/ui/dialog/color-item.cpp2
-rw-r--r--src/ui/dialog/desktop-tracker.cpp2
-rw-r--r--src/ui/dialog/desktop-tracker.h5
-rw-r--r--src/ui/dialog/dialog-manager.cpp25
-rw-r--r--src/ui/dialog/dialog.cpp20
-rw-r--r--src/ui/dialog/dialog.h4
-rw-r--r--src/ui/dialog/dock-behavior.cpp4
-rw-r--r--src/ui/dialog/document-metadata.cpp4
-rw-r--r--src/ui/dialog/document-metadata.h4
-rw-r--r--src/ui/dialog/document-properties.cpp65
-rw-r--r--src/ui/dialog/document-properties.h4
-rw-r--r--src/ui/dialog/export.cpp6
-rw-r--r--src/ui/dialog/export.h9
-rw-r--r--src/ui/dialog/extension-editor.cpp2
-rw-r--r--src/ui/dialog/filedialog.cpp2
-rw-r--r--src/ui/dialog/filedialog.h1
-rw-r--r--src/ui/dialog/filedialogimpl-gtkmm.cpp47
-rw-r--r--src/ui/dialog/filedialogimpl-win32.cpp14
-rw-r--r--src/ui/dialog/filedialogimpl-win32.h11
-rw-r--r--src/ui/dialog/fill-and-stroke.h2
-rw-r--r--src/ui/dialog/filter-effects-dialog.cpp2
-rw-r--r--src/ui/dialog/find.cpp97
-rw-r--r--src/ui/dialog/floating-behavior.cpp4
-rw-r--r--src/ui/dialog/font-substitution.cpp20
-rw-r--r--src/ui/dialog/grid-arrange-tab.cpp4
-rw-r--r--src/ui/dialog/grid-arrange-tab.h8
-rw-r--r--src/ui/dialog/guides.cpp23
-rw-r--r--src/ui/dialog/inkscape-preferences.cpp42
-rw-r--r--src/ui/dialog/inkscape-preferences.h6
-rw-r--r--src/ui/dialog/input.cpp2
-rw-r--r--src/ui/dialog/layers.cpp12
-rw-r--r--src/ui/dialog/livepatheffect-add.cpp14
-rw-r--r--src/ui/dialog/livepatheffect-add.h4
-rw-r--r--src/ui/dialog/livepatheffect-editor.cpp127
-rw-r--r--src/ui/dialog/lpe-fillet-chamfer-properties.cpp301
-rw-r--r--src/ui/dialog/lpe-fillet-chamfer-properties.h115
-rw-r--r--src/ui/dialog/lpe-powerstroke-properties.cpp211
-rw-r--r--src/ui/dialog/lpe-powerstroke-properties.h99
-rw-r--r--src/ui/dialog/new-from-template.cpp15
-rw-r--r--src/ui/dialog/objects.cpp2144
-rw-r--r--src/ui/dialog/objects.h263
-rw-r--r--src/ui/dialog/ocaldialogs.cpp4
-rw-r--r--src/ui/dialog/ocaldialogs.h3
-rw-r--r--src/ui/dialog/panel-dialog.h12
-rw-r--r--src/ui/dialog/pixelartdialog.cpp4
-rw-r--r--src/ui/dialog/polar-arrange-tab.cpp32
-rw-r--r--src/ui/dialog/polar-arrange-tab.h19
-rw-r--r--src/ui/dialog/print.cpp12
-rw-r--r--src/ui/dialog/spellcheck.cpp78
-rw-r--r--src/ui/dialog/swatches.cpp103
-rw-r--r--src/ui/dialog/swatches.h2
-rw-r--r--src/ui/dialog/symbols.cpp121
-rw-r--r--src/ui/dialog/symbols.h9
-rw-r--r--src/ui/dialog/tags.cpp1166
-rw-r--r--src/ui/dialog/tags.h181
-rw-r--r--src/ui/dialog/template-load-tab.cpp2
-rw-r--r--src/ui/dialog/template-widget.cpp8
-rw-r--r--src/ui/dialog/text-edit.cpp17
-rw-r--r--src/ui/dialog/transformation.cpp4
-rw-r--r--src/ui/dialog/xml-tree.cpp5
-rw-r--r--src/ui/draw-anchor.cpp105
-rw-r--r--src/ui/draw-anchor.h52
-rw-r--r--src/ui/interface.cpp2230
-rw-r--r--src/ui/interface.h277
-rw-r--r--src/ui/object-edit.cpp1452
-rw-r--r--src/ui/object-edit.h84
-rw-r--r--src/ui/shape-editor.cpp177
-rw-r--r--src/ui/shape-editor.h71
-rw-r--r--src/ui/tool-factory.h40
-rw-r--r--src/ui/tool/control-point-selection.cpp49
-rw-r--r--src/ui/tool/control-point-selection.h13
-rw-r--r--src/ui/tool/curve-drag-point.cpp17
-rw-r--r--src/ui/tool/multi-path-manipulator.cpp21
-rw-r--r--src/ui/tool/multi-path-manipulator.h5
-rw-r--r--src/ui/tool/node.cpp248
-rw-r--r--src/ui/tool/node.h15
-rw-r--r--src/ui/tool/path-manipulator.cpp170
-rw-r--r--src/ui/tool/path-manipulator.h12
-rw-r--r--src/ui/tool/selectable-control-point.h1
-rw-r--r--src/ui/tools-switch.cpp201
-rw-r--r--src/ui/tools-switch.h64
-rw-r--r--src/ui/tools/arc-tool.cpp10
-rw-r--r--src/ui/tools/arc-tool.h2
-rw-r--r--src/ui/tools/box3d-tool.cpp10
-rw-r--r--src/ui/tools/calligraphic-tool.cpp2
-rw-r--r--src/ui/tools/connector-tool.cpp2
-rw-r--r--src/ui/tools/dropper-tool.cpp2
-rw-r--r--src/ui/tools/eraser-tool.cpp2
-rw-r--r--src/ui/tools/flood-tool.cpp10
-rw-r--r--src/ui/tools/flood-tool.h4
-rw-r--r--src/ui/tools/freehand-base.cpp232
-rw-r--r--src/ui/tools/freehand-base.h6
-rw-r--r--src/ui/tools/gradient-tool.cpp19
-rw-r--r--src/ui/tools/lpe-tool.cpp11
-rw-r--r--src/ui/tools/measure-tool.cpp61
-rw-r--r--src/ui/tools/mesh-tool.cpp2
-rw-r--r--src/ui/tools/node-tool.cpp74
-rw-r--r--src/ui/tools/node-tool.h5
-rw-r--r--src/ui/tools/pen-tool.cpp1034
-rw-r--r--src/ui/tools/pen-tool.h31
-rw-r--r--src/ui/tools/pencil-tool.cpp48
-rw-r--r--src/ui/tools/rect-tool.cpp10
-rw-r--r--src/ui/tools/rect-tool.h4
-rw-r--r--src/ui/tools/select-tool.cpp82
-rw-r--r--src/ui/tools/select-tool.h1
-rw-r--r--src/ui/tools/spiral-tool.cpp10
-rw-r--r--src/ui/tools/spiral-tool.h8
-rw-r--r--src/ui/tools/spray-tool.cpp36
-rw-r--r--src/ui/tools/star-tool.cpp10
-rw-r--r--src/ui/tools/text-tool.cpp10
-rw-r--r--src/ui/tools/text-tool.h7
-rw-r--r--src/ui/tools/tool-base.cpp20
-rw-r--r--src/ui/tools/tool-base.h4
-rw-r--r--src/ui/tools/tweak-tool.cpp88
-rw-r--r--src/ui/tools/zoom-tool.cpp2
-rw-r--r--src/ui/view/view-widget.cpp31
-rw-r--r--src/ui/widget/Makefile_insert13
-rw-r--r--src/ui/widget/addtoicon.cpp156
-rw-r--r--src/ui/widget/addtoicon.h98
-rw-r--r--src/ui/widget/anchor-selector.cpp16
-rw-r--r--src/ui/widget/anchor-selector.h20
-rw-r--r--src/ui/widget/button.cpp6
-rw-r--r--src/ui/widget/button.h6
-rw-r--r--src/ui/widget/clipmaskicon.cpp183
-rw-r--r--src/ui/widget/clipmaskicon.h102
-rw-r--r--src/ui/widget/color-picker.cpp2
-rw-r--r--src/ui/widget/entity-entry.cpp4
-rw-r--r--src/ui/widget/entity-entry.h4
-rw-r--r--src/ui/widget/filter-effect-chooser.cpp15
-rw-r--r--src/ui/widget/filter-effect-chooser.h4
-rw-r--r--src/ui/widget/highlight-picker.cpp206
-rw-r--r--src/ui/widget/highlight-picker.h90
-rw-r--r--src/ui/widget/insertordericon.cpp164
-rw-r--r--src/ui/widget/insertordericon.h100
-rw-r--r--src/ui/widget/layertypeicon.cpp174
-rw-r--r--src/ui/widget/layertypeicon.h108
-rw-r--r--src/ui/widget/licensor.cpp4
-rw-r--r--src/ui/widget/licensor.h4
-rw-r--r--src/ui/widget/notebook-page.cpp6
-rw-r--r--src/ui/widget/notebook-page.h6
-rw-r--r--src/ui/widget/object-composite-settings.cpp4
-rw-r--r--src/ui/widget/object-composite-settings.h6
-rw-r--r--src/ui/widget/page-sizer.cpp8
-rw-r--r--src/ui/widget/page-sizer.h4
-rw-r--r--src/ui/widget/panel.cpp4
-rw-r--r--src/ui/widget/panel.h12
-rw-r--r--src/ui/widget/preferences-widget.cpp8
-rw-r--r--src/ui/widget/preferences-widget.h4
-rw-r--r--src/ui/widget/registered-widget.cpp57
-rw-r--r--src/ui/widget/registered-widget.h29
-rw-r--r--src/ui/widget/registry.cpp4
-rw-r--r--src/ui/widget/registry.h4
-rw-r--r--src/ui/widget/rendering-options.cpp18
-rw-r--r--src/ui/widget/rotateable.cpp6
-rw-r--r--src/ui/widget/rotateable.h4
-rw-r--r--src/ui/widget/selected-style.cpp35
-rw-r--r--src/ui/widget/selected-style.h17
-rw-r--r--src/ui/widget/spin-scale.cpp6
-rw-r--r--src/ui/widget/spin-scale.h6
-rw-r--r--src/ui/widget/spin-slider.cpp6
-rw-r--r--src/ui/widget/spin-slider.h6
-rw-r--r--src/ui/widget/spinbutton.cpp6
-rw-r--r--src/ui/widget/spinbutton.h6
-rw-r--r--src/ui/widget/style-subject.h2
-rw-r--r--src/ui/widget/style-swatch.cpp6
-rw-r--r--src/ui/widget/style-swatch.h8
-rw-r--r--src/ui/widget/tolerance-slider.cpp4
-rw-r--r--src/ui/widget/tolerance-slider.h4
-rw-r--r--src/ui/widget/unit-menu.cpp6
-rw-r--r--src/ui/widget/unit-menu.h4
-rw-r--r--src/ui/widget/unit-tracker.cpp2
-rw-r--r--src/ui/widget/unit-tracker.h7
184 files changed, 14057 insertions, 1092 deletions
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 7d80f1e36..e5c605889 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -2,7 +2,13 @@
set(ui_SRC
clipboard.cpp
control-manager.cpp
+ dialog-events.cpp
+ draw-anchor.cpp
+ interface.cpp
+ object-edit.cpp
previewholder.cpp
+ shape-editor.cpp
+ tools-switch.cpp
uxmanager.cpp
cache/svg_preview_cache.cpp
@@ -78,6 +84,7 @@ set(ui_SRC
dialog/layers.cpp
dialog/livepatheffect-add.cpp
dialog/livepatheffect-editor.cpp
+ dialog/lpe-fillet-chamfer-properties.cpp
dialog/memory.cpp
dialog/messages.cpp
dialog/new-from-template.cpp
@@ -89,7 +96,6 @@ set(ui_SRC
dialog/print.cpp
dialog/symbols.cpp
dialog/xml-tree.cpp
- # dialog/session-player.cpp
dialog/spellcheck.cpp
dialog/svg-fonts-dialog.cpp
dialog/swatches.cpp
@@ -101,9 +107,6 @@ set(ui_SRC
dialog/pixelartdialog.cpp
dialog/transformation.cpp
dialog/undo-history.cpp
- # dialog/whiteboard-connect.cpp
- # dialog/whiteboard-sharewithchat.cpp
- # dialog/whiteboard-sharewithuser.cpp
widget/anchor-selector.cpp
widget/button.cpp
@@ -155,10 +158,17 @@ set(ui_SRC
clipboard.h
control-manager.h
control-types.h
+ dialog-events.h
+ draw-anchor.h
icon-names.h
+ interface.h
+ object-edit.h
previewable.h
previewfillable.h
previewholder.h
+ shape-editor.h
+ tool-factory.h
+ tools-switch.h
uxmanager.h
cache/svg_preview_cache.h
@@ -198,6 +208,7 @@ set(ui_SRC
dialog/layers.h
dialog/livepatheffect-add.h
dialog/livepatheffect-editor.h
+ dialog/lpe-fillet-chamfer-properties.h
dialog/memory.h
dialog/messages.h
dialog/new-from-template.h
diff --git a/src/ui/Makefile_insert b/src/ui/Makefile_insert
index 4081f86f8..7aeb4a83d 100644
--- a/src/ui/Makefile_insert
+++ b/src/ui/Makefile_insert
@@ -6,10 +6,23 @@ ink_common_sources += \
ui/control-manager.cpp \
ui/control-manager.h \
ui/control-types.h \
+ ui/dialog-events.cpp \
+ ui/dialog-events.h \
+ ui/draw-anchor.cpp \
+ ui/draw-anchor.h \
ui/icon-names.h \
+ ui/interface.cpp \
+ ui/interface.h \
+ ui/object-edit.cpp \
+ ui/object-edit.h \
ui/previewable.h \
ui/previewfillable.h \
ui/previewholder.cpp \
ui/previewholder.h \
+ ui/shape-editor.cpp \
+ ui/shape-editor.h \
+ ui/tool-factory.h \
+ ui/tools-switch.cpp \
+ ui/tools-switch.h \
ui/uxmanager.cpp \
ui/uxmanager.h
diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp
index 8e2502545..153ed9830 100644
--- a/src/ui/clipboard.cpp
+++ b/src/ui/clipboard.cpp
@@ -54,6 +54,7 @@
#include <2geom/transforms.h>
#include "box3d.h"
#include "gradient-drag.h"
+#include "sp-marker.h"
#include "sp-item.h"
#include "sp-item-transform.h" // for sp_item_scale_rel, used in _pasteSize
#include "sp-path.h"
@@ -76,7 +77,7 @@
#include "svg/css-ostringstream.h" // used in copy
#include "ui/tools/text-tool.h"
#include "text-editing.h"
-#include "tools-switch.h"
+#include "ui/tools-switch.h"
#include "path-chemistry.h"
#include "util/units.h"
#include "helper/png-write.h"
@@ -329,6 +330,13 @@ void ClipboardManagerImpl::copySymbol(Inkscape::XML::Node* symbol, gchar const*
use->setAttribute("xlink:href", id.c_str() );
// Set a default style in <use> rather than <symbol> so it can be changed.
use->setAttribute("style", style );
+
+ Inkscape::XML::Node *nv_repr = sp_desktop_namedview(inkscape_active_desktop())->getRepr();
+ gdouble scale_units = Inkscape::Util::Quantity::convert(1, nv_repr->attribute("inkscape:document-units"), "px");
+ gchar *transform_str = sp_svg_transform_write(Geom::Scale(scale_units, scale_units));
+ use->setAttribute("transform", transform_str);
+ g_free(transform_str);
+
_root->appendChild(use);
// This min and max sets offsets, we don't have any so set to zero.
@@ -505,12 +513,15 @@ bool ClipboardManagerImpl::pasteSize(SPDesktop *desktop, bool separately, bool a
// resize each object in the selection
if (separately) {
for (GSList *i = const_cast<GSList*>(selection->itemList()) ; i ; i = i->next) {
- SPItem *item = SP_ITEM(i->data);
- Geom::OptRect obj_size = item->desktopVisualBounds();
- if ( !obj_size ) {
- continue;
+ SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(i->data));
+ if (item) {
+ Geom::OptRect obj_size = item->desktopVisualBounds();
+ if ( obj_size ) {
+ sp_item_scale_rel(item, _getScale(desktop, min, max, *obj_size, apply_x, apply_y));
+ }
+ } else {
+ g_assert_not_reached();
}
- sp_item_scale_rel(item, _getScale(desktop, min, max, *obj_size, apply_x, apply_y));
}
}
// resize the selection as a whole
@@ -601,6 +612,12 @@ Glib::ustring ClipboardManagerImpl::getPathParameter(SPDesktop* desktop)
*/
Glib::ustring ClipboardManagerImpl::getShapeOrTextObjectId(SPDesktop *desktop)
{
+ // https://bugs.launchpad.net/inkscape/+bug/1293979
+ // basically, when we do a depth-first search, we're stopping
+ // at the first object to be <svg:path> or <svg:text>.
+ // but that could then return the id of the object's
+ // clip path or mask, not the original path!
+
SPDocument *tempdoc = _retrieveClipboard(); // any target will do here
if ( tempdoc == NULL ) {
_userWarn(desktop, _("Nothing on the clipboard."));
@@ -608,6 +625,9 @@ Glib::ustring ClipboardManagerImpl::getShapeOrTextObjectId(SPDesktop *desktop)
}
Inkscape::XML::Node *root = tempdoc->getReprRoot();
+ // 1293979: strip out the defs of the document
+ root->removeChild(tempdoc->getDefs()->getRepr());
+
Inkscape::XML::Node *repr = sp_repr_lookup_name(root, "svg:path", -1); // unlimited search depth
if ( repr == NULL ) {
repr = sp_repr_lookup_name(root, "svg:text", -1);
@@ -631,7 +651,12 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection)
GSList const *items = selection->itemList();
// copy the defs used by all items
for (GSList *i = const_cast<GSList *>(items) ; i != NULL ; i = i->next) {
- _copyUsedDefs(SP_ITEM (i->data));
+ SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(i->data));
+ if (item) {
+ _copyUsedDefs(item);
+ } else {
+ g_assert_not_reached();
+ }
}
// copy the representation of the items
@@ -639,36 +664,38 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection)
sorted_items = g_slist_sort(sorted_items, (GCompareFunc) sp_object_compare_position);
for (GSList *i = sorted_items ; i ; i = i->next) {
- if (!SP_IS_ITEM(i->data)) {
- continue;
+ SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(i->data));
+ if (item) {
+ Inkscape::XML::Node *obj = item->getRepr();
+ Inkscape::XML::Node *obj_copy = _copyNode(obj, _doc, _root);
+
+ // copy complete inherited style
+ SPCSSAttr *css = sp_repr_css_attr_inherited(obj, "style");
+ sp_repr_css_set(obj_copy, css, "style");
+ sp_repr_css_attr_unref(css);
+
+ // write the complete accumulated transform passed to us
+ // (we're dealing with unattached representations, so we write to their attributes
+ // instead of using sp_item_set_transform)
+ gchar *transform_str = sp_svg_transform_write(item->i2doc_affine());
+ obj_copy->setAttribute("transform", transform_str);
+ g_free(transform_str);
}
- Inkscape::XML::Node *obj = reinterpret_cast<SPObject *>(i->data)->getRepr();
- Inkscape::XML::Node *obj_copy = _copyNode(obj, _doc, _root);
-
- // copy complete inherited style
- SPCSSAttr *css = sp_repr_css_attr_inherited(obj, "style");
- sp_repr_css_set(obj_copy, css, "style");
- sp_repr_css_attr_unref(css);
-
- // write the complete accumulated transform passed to us
- // (we're dealing with unattached representations, so we write to their attributes
- // instead of using sp_item_set_transform)
- gchar *transform_str = sp_svg_transform_write(SP_ITEM(i->data)->i2doc_affine());
- obj_copy->setAttribute("transform", transform_str);
- g_free(transform_str);
}
// copy style for Paste Style action
if (sorted_items) {
- if (SP_IS_ITEM(sorted_items->data)) {
- SPCSSAttr *style = take_style_from_item((SPItem *) sorted_items->data);
+ SPObject *object = static_cast<SPObject *>(sorted_items->data);
+ SPItem *item = dynamic_cast<SPItem *>(object);
+ if (item) {
+ SPCSSAttr *style = take_style_from_item(item);
sp_repr_css_set(_clipnode, style, "style");
sp_repr_css_attr_unref(style);
}
// copy path effect from the first path
- if (SP_IS_OBJECT(sorted_items->data)) {
- gchar const *effect = reinterpret_cast<SPObject *>(sorted_items->data)->getRepr()->attribute("inkscape:path-effect");
+ if (object) {
+ gchar const *effect =object->getRepr()->attribute("inkscape:path-effect");
if (effect) {
_clipnode->setAttribute("inkscape:path-effect", effect);
}
@@ -695,35 +722,38 @@ void ClipboardManagerImpl::_copyUsedDefs(SPItem *item)
if (style && (style->fill.isPaintserver())) {
SPPaintServer *server = item->style->getFillPaintServer();
- if ( SP_IS_LINEARGRADIENT(server) || SP_IS_RADIALGRADIENT(server) ) {
- _copyGradient(SP_GRADIENT(server));
+ if ( dynamic_cast<SPLinearGradient *>(server) || dynamic_cast<SPRadialGradient *>(server) ) {
+ _copyGradient(dynamic_cast<SPGradient *>(server));
}
- if ( SP_IS_PATTERN(server) ) {
- _copyPattern(SP_PATTERN(server));
+ SPPattern *pattern = dynamic_cast<SPPattern *>(server);
+ if ( pattern ) {
+ _copyPattern(pattern);
}
}
if (style && (style->stroke.isPaintserver())) {
SPPaintServer *server = item->style->getStrokePaintServer();
- if ( SP_IS_LINEARGRADIENT(server) || SP_IS_RADIALGRADIENT(server) ) {
- _copyGradient(SP_GRADIENT(server));
+ if ( dynamic_cast<SPLinearGradient *>(server) || dynamic_cast<SPRadialGradient *>(server) ) {
+ _copyGradient(dynamic_cast<SPGradient *>(server));
}
- if ( SP_IS_PATTERN(server) ) {
- _copyPattern(SP_PATTERN(server));
+ SPPattern *pattern = dynamic_cast<SPPattern *>(server);
+ if ( pattern ) {
+ _copyPattern(pattern);
}
}
// For shapes, copy all of the shape's markers
- if (SP_IS_SHAPE(item)) {
- SPShape *shape = SP_SHAPE (item);
+ SPShape *shape = dynamic_cast<SPShape *>(item);
+ if (shape) {
for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
if (shape->_marker[i]) {
_copyNode(shape->_marker[i]->getRepr(), _doc, _defs);
}
}
}
+
// For lpe items, copy lpe stack if applicable
- if (SP_IS_LPE_ITEM(item)) {
- SPLPEItem *lpeitem = SP_LPE_ITEM (item);
+ SPLPEItem *lpeitem = dynamic_cast<SPLPEItem *>(item);
+ if (lpeitem) {
if (lpeitem->hasPathEffect()) {
for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
{
@@ -734,14 +764,24 @@ void ClipboardManagerImpl::_copyUsedDefs(SPItem *item)
}
}
}
+
// For 3D boxes, copy perspectives
- if (SP_IS_BOX3D(item)) {
- _copyNode(box3d_get_perspective(SP_BOX3D(item))->getRepr(), _doc, _defs);
+ {
+ SPBox3D *box = dynamic_cast<SPBox3D *>(item);
+ if (box) {
+ _copyNode(box3d_get_perspective(box)->getRepr(), _doc, _defs);
+ }
}
+
// Copy text paths
- if (SP_IS_TEXT_TEXTPATH(item)) {
- _copyTextPath(SP_TEXTPATH(item->firstChild()));
+ {
+ SPText *text = dynamic_cast<SPText *>(item);
+ SPTextPath *textpath = (text) ? dynamic_cast<SPTextPath *>(text->firstChild()) : NULL;
+ if (textpath) {
+ _copyTextPath(textpath);
+ }
}
+
// Copy clipping objects
if (item->clip_ref){
if (item->clip_ref->getObject()) {
@@ -755,8 +795,9 @@ void ClipboardManagerImpl::_copyUsedDefs(SPItem *item)
_copyNode(mask->getRepr(), _doc, _defs);
// recurse into the mask for its gradients etc.
for (SPObject *o = mask->children ; o != NULL ; o = o->next) {
- if (SP_IS_ITEM(o)) {
- _copyUsedDefs(SP_ITEM(o));
+ SPItem *childItem = dynamic_cast<SPItem *>(o);
+ if (childItem) {
+ _copyUsedDefs(childItem);
}
}
}
@@ -765,15 +806,16 @@ void ClipboardManagerImpl::_copyUsedDefs(SPItem *item)
// Copy filters
if (style->getFilter()) {
SPObject *filter = style->getFilter();
- if (SP_IS_FILTER(filter)) {
+ if (dynamic_cast<SPFilter *>(filter)) {
_copyNode(filter->getRepr(), _doc, _defs);
}
}
// recurse
for (SPObject *o = item->children ; o != NULL ; o = o->next) {
- if (SP_IS_ITEM(o)) {
- _copyUsedDefs(SP_ITEM(o));
+ SPItem *childItem = dynamic_cast<SPItem *>(o);
+ if (childItem) {
+ _copyUsedDefs(childItem);
}
}
}
@@ -808,10 +850,10 @@ void ClipboardManagerImpl::_copyPattern(SPPattern *pattern)
// items in the pattern may also use gradients and other patterns, so recurse
for ( SPObject *child = pattern->firstChild() ; child ; child = child->getNext() ) {
- if (!SP_IS_ITEM (child)) {
- continue;
+ SPItem *childItem = dynamic_cast<SPItem *>(child);
+ if (childItem) {
+ _copyUsedDefs(childItem);
}
- _copyUsedDefs(SP_ITEM(child));
}
if (pattern->ref){
pattern = pattern->ref->getObject();
@@ -930,13 +972,13 @@ void ClipboardManagerImpl::_applyPathEffect(SPItem *item, gchar const *effectsta
if ( item == NULL ) {
return;
}
- if ( SP_IS_RECT(item) ) {
+ if ( dynamic_cast<SPRect *>(item) ) {
return;
}
- if (SP_IS_LPE_ITEM(item))
+ SPLPEItem *lpeitem = dynamic_cast<SPLPEItem *>(item);
+ if (lpeitem)
{
- SPLPEItem *lpeitem = SP_LPE_ITEM(item);
// for each effect in the stack, check if we need to fork it before adding it to the item
lpeitem->forkPathEffectsIfNecessary(1);
diff --git a/src/ui/dialog-events.cpp b/src/ui/dialog-events.cpp
new file mode 100644
index 000000000..6bd93bbc3
--- /dev/null
+++ b/src/ui/dialog-events.cpp
@@ -0,0 +1,255 @@
+/**
+ * @file
+ * Event handler for dialog windows.
+ */
+/* Authors:
+ * bulia byak <bulia@dr.com>
+ * Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
+ *
+ * Copyright (C) 2003-2007 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
+#include <gtkmm/entry.h>
+#include <gtkmm/window.h>
+#include <gdk/gdkkeysyms.h>
+#include "macros.h"
+#include <gtk/gtk.h>
+#include "desktop.h"
+#include "inkscape-private.h"
+#include "preferences.h"
+#include "ui/tools/tool-base.h"
+
+#include "ui/dialog-events.h"
+
+
+/**
+ * Remove focus from window to whoever it is transient for.
+ */
+void sp_dialog_defocus_cpp(Gtk::Window *win)
+{
+ //find out the document window we're transient for
+ Gtk::Window *w = win->get_transient_for();
+
+ //switch to it
+ if (w) {
+ w->present();
+ }
+}
+
+void
+sp_dialog_defocus (GtkWindow *win)
+{
+ GtkWindow *w;
+ //find out the document window we're transient for
+ w = gtk_window_get_transient_for(GTK_WINDOW(win));
+ //switch to it
+
+ if (w) {
+ gtk_window_present (w);
+ }
+}
+
+
+/**
+ * Callback to defocus a widget's parent dialog.
+ */
+void sp_dialog_defocus_callback_cpp(Gtk::Entry *e)
+{
+ sp_dialog_defocus_cpp(dynamic_cast<Gtk::Window *>(e->get_toplevel()));
+}
+
+void
+sp_dialog_defocus_callback (GtkWindow * /*win*/, gpointer data)
+{
+ sp_dialog_defocus( GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(data))) );
+}
+
+
+
+void
+sp_dialog_defocus_on_enter_cpp (Gtk::Entry *e)
+{
+ e->signal_activate().connect(sigc::bind(sigc::ptr_fun(&sp_dialog_defocus_callback_cpp), e));
+}
+
+void
+sp_dialog_defocus_on_enter (GtkWidget *w)
+{
+ g_signal_connect ( G_OBJECT (w), "activate",
+ G_CALLBACK (sp_dialog_defocus_callback), w );
+}
+
+
+
+gboolean
+sp_dialog_event_handler (GtkWindow *win, GdkEvent *event, gpointer data)
+{
+
+// if the focus is inside the Text and Font textview, do nothing
+ GObject *dlg = G_OBJECT(data);
+ if (g_object_get_data (dlg, "eatkeys")) {
+ return FALSE;
+ }
+
+ gboolean ret = FALSE;
+
+ switch (event->type) {
+
+ case GDK_KEY_PRESS:
+
+ switch (Inkscape::UI::Tools::get_group0_keyval (&event->key)) {
+ case GDK_KEY_Escape:
+ sp_dialog_defocus (win);
+ ret = TRUE;
+ break;
+ case GDK_KEY_F4:
+ case GDK_KEY_w:
+ case GDK_KEY_W:
+ // close dialog
+ if (MOD__CTRL_ONLY(event)) {
+
+ /* this code sends a delete_event to the dialog,
+ * instead of just destroying it, so that the
+ * dialog can do some housekeeping, such as remember
+ * its position.
+ */
+ GdkEventAny event;
+ GtkWidget *widget = GTK_WIDGET(win);
+ event.type = GDK_DELETE;
+ event.window = gtk_widget_get_window (widget);
+ event.send_event = TRUE;
+ g_object_ref (G_OBJECT (event.window));
+ gtk_main_do_event(reinterpret_cast<GdkEvent*>(&event));
+ g_object_unref (G_OBJECT (event.window));
+
+ ret = TRUE;
+ }
+ break;
+ default: // pass keypress to the canvas
+ break;
+ }
+ default:
+ ;
+ }
+
+ return ret;
+
+}
+
+
+
+/**
+ * Make the argument dialog transient to the currently active document
+ * window.
+ */
+void sp_transientize(GtkWidget *dialog)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+#ifndef WIN32 // FIXME: Temporary Win32 special code to enable transient dialogs
+ // _set_skip_taskbar_hint makes transient dialogs NON-transient! When dialogs
+ // are made transient (_set_transient_for), they are already removed from
+ // the taskbar in Win32.
+ if (prefs->getBool( "/options/dialogsskiptaskbar/value")) {
+ gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), TRUE);
+ }
+#endif
+
+ gint transient_policy = prefs->getIntLimited("/options/transientpolicy/value", 1, 0, 2);
+
+#ifdef WIN32 // Win32 special code to enable transient dialogs
+ transient_policy = 2;
+#endif
+
+ if (transient_policy) {
+
+ // if there's an active document window, attach dialog to it as a transient:
+
+ if ( SP_ACTIVE_DESKTOP )
+ {
+ SP_ACTIVE_DESKTOP->setWindowTransient (dialog, transient_policy);
+ }
+ }
+} // end of sp_transientize()
+
+void on_transientize (SPDesktop *desktop, win_data *wd )
+{
+ sp_transientize_callback (0, desktop, wd);
+}
+
+void
+sp_transientize_callback ( InkscapeApplication * /*inkscape*/,
+ SPDesktop *desktop, win_data *wd )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gint transient_policy = prefs->getIntLimited( "/options/transientpolicy/value", 1, 0, 2);
+
+#ifdef WIN32 // Win32 special code to enable transient dialogs
+ transient_policy = 1;
+#endif
+
+ if (!transient_policy)
+ return;
+
+ if (wd->win)
+ {
+ desktop->setWindowTransient (wd->win, transient_policy);
+ }
+}
+
+void on_dialog_hide (GtkWidget *w)
+{
+ if (w)
+ gtk_widget_hide (w);
+}
+
+void on_dialog_unhide (GtkWidget *w)
+{
+ if (w)
+ gtk_widget_show (w);
+}
+
+gboolean
+sp_dialog_hide(GObject * /*object*/, gpointer data)
+{
+ GtkWidget *dlg = GTK_WIDGET(data);
+
+ if (dlg)
+ gtk_widget_hide (dlg);
+
+ return TRUE;
+}
+
+
+
+gboolean
+sp_dialog_unhide(GObject * /*object*/, gpointer data)
+{
+ GtkWidget *dlg = GTK_WIDGET(data);
+
+ if (dlg)
+ gtk_widget_show (dlg);
+
+ return TRUE;
+}
+
+
+/*
+ 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-events.h b/src/ui/dialog-events.h
new file mode 100644
index 000000000..b33eb3f38
--- /dev/null
+++ b/src/ui/dialog-events.h
@@ -0,0 +1,76 @@
+/** @file
+ * @brief Event handler for dialog windows
+ */
+/* Authors:
+ * bulia byak <bulia@dr.com>
+ *
+ * Copyright (C) 2003 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_DIALOG_EVENTS_H
+#define SEEN_DIALOG_EVENTS_H
+
+
+/*
+ * event callback can only accept one argument, but we need two,
+ * hence this struct.
+ * each dialog has a local static copy:
+ * win is the dialog window
+ * stop is the transientize semaphore: when 0, retransientizing this dialog
+ * is allowed
+ */
+
+namespace Gtk {
+class Window;
+class Entry;
+}
+
+class SPDesktop;
+
+struct InkscapeApplication;
+
+typedef struct {
+ GtkWidget *win;
+ guint stop;
+} win_data;
+
+
+gboolean sp_dialog_event_handler ( GtkWindow *win,
+ GdkEvent *event,
+ gpointer data );
+
+void sp_dialog_defocus_cpp (Gtk::Window *win);
+void sp_dialog_defocus_callback_cpp(Gtk::Entry *e);
+void sp_dialog_defocus_on_enter_cpp(Gtk::Entry *e);
+
+void sp_dialog_defocus ( GtkWindow *win );
+void sp_dialog_defocus_callback ( GtkWindow *win, gpointer data );
+void sp_dialog_defocus_on_enter ( GtkWidget *w );
+void sp_transientize ( GtkWidget *win );
+
+void on_transientize ( SPDesktop *desktop,
+ win_data *wd );
+
+void sp_transientize_callback ( InkscapeApplication *inkscape,
+ SPDesktop *desktop,
+ win_data *wd );
+
+void on_dialog_hide (GtkWidget *w);
+void on_dialog_unhide (GtkWidget *w);
+gboolean sp_dialog_hide (GObject *object, gpointer data);
+gboolean sp_dialog_unhide (GObject *object, gpointer data);
+
+#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/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert
index daa8aea22..cbdae1cb0 100644
--- a/src/ui/dialog/Makefile_insert
+++ b/src/ui/dialog/Makefile_insert
@@ -100,6 +100,8 @@ ink_common_sources += \
ui/dialog/template-load-tab.h \
ui/dialog/template-widget.cpp \
ui/dialog/template-widget.h \
+ ui/dialog/tags.cpp \
+ ui/dialog/tags.h \
ui/dialog/text-edit.cpp \
ui/dialog/text-edit.h \
ui/dialog/tile.cpp \
@@ -114,4 +116,10 @@ ink_common_sources += \
ui/dialog/undo-history.h \
ui/dialog/xml-tree.cpp \
ui/dialog/xml-tree.h \
+ ui/dialog/lpe-powerstroke-properties.cpp \
+ ui/dialog/lpe-powerstroke-properties.h \
+ ui/dialog/objects.cpp \
+ ui/dialog/objects.h \
+ ui/dialog/lpe-fillet-chamfer-properties.cpp \
+ ui/dialog/lpe-fillet-chamfer-properties.h \
$(inkboard_dialogs)
diff --git a/src/ui/dialog/aboutbox.cpp b/src/ui/dialog/aboutbox.cpp
index 121773b6d..50b35ca2f 100644
--- a/src/ui/dialog/aboutbox.cpp
+++ b/src/ui/dialog/aboutbox.cpp
@@ -254,6 +254,7 @@ void AboutBox::initStrings() {
"Nicholas Bishop\n"
"Joshua L. Blocher\n"
"Hanno Böck\n"
+"Tomasz Boczkowski\n"
"Henrik Bohre\n"
"Boldewyn\n"
"Daniel Borgmann\n"
@@ -270,6 +271,7 @@ void AboutBox::initStrings() {
"Gail Carmichael\n"
"Ed Catmur\n"
"Chema Celorio\n"
+"Jabiertxo Arraiza Cenoz\n"
"Johan Ceuppens\n"
"Zbigniew Chyla\n"
"Alexander Clausen\n"
@@ -311,6 +313,7 @@ void AboutBox::initStrings() {
"Hannes Hochreiner\n"
"Thomas Holder\n"
"Joel Holdsworth\n"
+"Christoffer Holmstedt\n"
"Alan Horkan\n"
"Karl Ove Hufthammer\n"
"Richard Hughes\n"
@@ -319,6 +322,7 @@ void AboutBox::initStrings() {
"Thomas Ingham\n"
"Jean-Olivier Irisson\n"
"Bob Jamison\n"
+"Ted Janeczko\n"
"jEsuSdA\n"
"Fernando Lucchesi Bastos Jurema\n"
"Lauris Kaplinski\n"
@@ -342,7 +346,9 @@ void AboutBox::initStrings() {
"Aurel-Aimé Marmion\n"
"Colin Marquardt\n"
"Craig Marshall\n"
+"Ivan Masár\n"
"Dmitry G. Mastrukov\n"
+"David Mathog\n"
"Matiphas\n"
"Michael Meeks\n"
"Federico Mena\n"
@@ -360,8 +366,10 @@ void AboutBox::initStrings() {
"Nick\n"
"Andreas Nilsson\n"
"Mitsuru Oka\n"
+"Vinícius dos Santos Oliveira\n"
"Martin Owens\n"
"Alvin Penner\n"
+"Matthew Petroff\n"
"Jon Phillips\n"
"Zdenko Podobny\n"
"Alexandre Prokoudine\n"
@@ -398,6 +406,8 @@ void AboutBox::initStrings() {
"Joakim Verona\n"
"Lucas Vieites\n"
"Daniel Wagenaar\n"
+"Liam P. White\n"
+"Sebastian Wüst\n"
"Michael Wybrow\n"
"Gellule Xg\n"
"Daniel Yacob\n"
@@ -442,13 +452,13 @@ void AboutBox::initStrings() {
*/
gchar const *allTranslators =
"3ARRANO.com <3arrano@3arrano.com>, 2005.\n"
-"Adib Taraben <theadib@googlemail.com>, 2004.\n"
+"Adib Taraben <theadib@gmail.com>, 2004-2014.\n"
"Alan Monfort <alan.monfort@free.fr>, 2009-2010.\n"
"Alastair McKinstry <mckinstry@computer.org>, 2000.\n"
"Aleksandar Urošević <urke@users.sourceforge.net>, 2004-2006.\n"
"Alessio Frusciante <algol@firenze.linux.it>, 2002, 2003.\n"
"Alexander Shopov <ash@contact.bg>, 2006.\n"
-"Alexandre Prokoudine <alexandre.prokoudine@gmail.com>, 2005, 2010-2013.\n"
+"Alexandre Prokoudine <alexandre.prokoudine@gmail.com>, 2005, 2010-2014.\n"
"Alexey Remizov <alexey@remizov.pp.ru>, 2004.\n"
"Ali Ghanavatian <ghanvatian.ali@gmail.com>, 2010.\n"
"Álvaro Lopes <alvieboy@alvie.com>, 2001, 2002.\n"
@@ -482,6 +492,7 @@ void AboutBox::initStrings() {
"Elias Norberg <elno0959 at student.su.se>, 2009.\n"
"Equipe de Tradução Inkscape Brasil <www.inkscapebrasil.org>, 2007.\n"
"Fatih Demir <kabalak@gtranslator.org>, 2000.\n"
+"Firas Hanife <FirasHanife@gmail.com>, 2014.\n"
"Foppe Benedictus <foppe.benedictus@gmail.com>, 2007-2009.\n"
"Francesc Dorca <f.dorca@filnet.es>, 2003. Traducció sodipodi.\n"
"Francisco Javier F. Serrador <serrador@arrakis.es>, 2003.\n"
@@ -492,9 +503,10 @@ void AboutBox::initStrings() {
"Hleb Valoshka <375gnu@gmail.com>, 2008-2009.\n"
"Hizkuntza Politikarako Sailburuordetza <hizkpol@ej-gv.es>, 2005.\n"
"Ilia Penev <lichopicho@gmail.com>, 2006.\n"
-"Ivan Masár <helix84@centrum.sk>, 2006-2010. \n"
+"Ivan Masár <helix84@centrum.sk>, 2006-2014. \n"
+"Ivan Řihošek <irihosek@seznam.cz>, 2014.\n"
"Iñaki Larrañaga <dooteo@euskalgnu.org>, 2006.\n"
-"Jānis Eisaks <jancs@dv.lv>, 2012, 2013.\n"
+"Jānis Eisaks <jancs@dv.lv>, 2012-2014.\n"
"Jeffrey Steve Borbón Sanabria <jeff_kerokid@yahoo.com>, 2005.\n"
"Jesper Öqvist <jesper@llbit.se>, 2010, 2011.\n"
"Joaquim Perez i Noguer <noguer@gmail.com>, 2008-2009.\n"
@@ -516,7 +528,7 @@ void AboutBox::initStrings() {
"Kingsley Turner <kingsley@maddogsbreakfast.com.au>, 2006.\n"
"Kitae <bluetux@gmail.com>, 2006.\n"
"Kjartan Maraas <kmaraas@gnome.org>, 2000-2002.\n"
-"Kris De Gussem <Kris.DeGussem@gmail.com>, 2008-2013.\n"
+"Kris De Gussem <Kris.DeGussem@gmail.com>, 2008-2014.\n"
"Lauris Kaplinski <lauris@ariman.ee>, 2000.\n"
"Leandro Regueiro <leandro.regueiro@gmail.com>, 2006-2008, 2010.\n"
"Liu Xiaoqin <liuxqsmile@gmail.com>, 2008.\n"
@@ -525,7 +537,7 @@ void AboutBox::initStrings() {
"Mahesh subedi <submanesh@hotmail.com>, 2006.\n"
"Martin Srebotnjak, <miles@filmsi.net>, 2005, 2010.\n"
"Masatake YAMATO <jet@gyve.org>, 2002.\n"
-"Masato Hashimoto <cabezon.hashimoto@gmail.com>, 2009-2012.\n"
+"Masato Hashimoto <cabezon.hashimoto@gmail.com>, 2009-2014.\n"
"Matiphas <matiphas _a_ free _point_ fr>, 2004-2006.\n"
"Mattias Hultgren <mattias_hultgren@tele2.se>, 2005, 2006.\n"
"Maxim Dziumanenko <mvd@mylinux.com.ua>, 2004.\n"
@@ -536,12 +548,12 @@ void AboutBox::initStrings() {
"Muhammad Bashir Al-Noimi <mhdbnoimi@gmail.com>, 2008.\n"
"Myckel Habets <myckel@sdf.lonestar.org>, 2008.\n"
"Nguyen Dinh Trung <nguyendinhtrung141@gmail.com>, 2007, 2008.\n"
-"Nicolas Dufour <nicoduf@yahoo.fr>, 2008-2013.\n"
+"Nicolas Dufour <nicoduf@yahoo.fr>, 2008-2014.\n"
"Pawan Chitrakar <pchitrakar@gmail.com>, 2006.\n"
"Przemysław Loesch <p_loesch@poczta.onet.pl>, 2005.\n"
"Quico Llach <quico@softcatala.org>, 2000. Traducció sodipodi.\n"
"Raymond Ostertag <raymond@linuxgraphic.org>, 2002, 2003.\n"
-"Riku Leino <tsoots@gmail.com>, 2006.\n"
+"Riku Leino <tsoots@gmail.com>, 2006-2011.\n"
"Rune Rønde Laursen <runerl@skjoldhoej.dk>, 2006.\n"
"Ruud Steltenpool <svg@steltenpower.com>, 2006.\n"
"Serdar Soytetir <sendirom@gmail.com>, 2005.\n"
@@ -557,9 +569,11 @@ void AboutBox::initStrings() {
"Thiago Pimentel <thiago.merces@gmail.com>, 2006.\n"
"Toshifumi Sato <sato@centrosystem.com>, 2005.\n"
"Jon South <striker@lunar-linux.org>, 2006. \n"
-"Uwe Schöler <oss@oss-marketplace.com>, 2006-2013.\n"
+"Uwe Schöler <oss@oss-marketplace.com>, 2006-2014.\n"
"Valek Filippov <frob@df.ru>, 2000, 2003.\n"
"Victor Dachev <vdachev@gmail.com>, 2006.\n"
+"Victor Westmann <victor.westmann@gmail.com>, 2011, 2014.\n"
+"Ville Pätsi, 2013.\n"
"Vincent van Adrighem <V.vanAdrighem@dirck.mine.nu>, 2003.\n"
"Vital Khilko <dojlid@mova.org>, 2003.\n"
"Vitaly Lipatov <lav@altlinux.ru>, 2002, 2004.\n"
@@ -572,7 +586,7 @@ void AboutBox::initStrings() {
"Yaron Shahrabani <sh.yaron@gmail.com>, 2009.\n"
"Yukihiro Nakai <nakai@gnome.gr.jp>, 2000, 2003.\n"
"Yuri Beznos <zhiz0id@gmail.com>, 2006.\n"
-"Yuri Chornoivan <yurchor@ukr.net>, 2007-2013.\n"
+"Yuri Chornoivan <yurchor@ukr.net>, 2007-2014.\n"
"Yuri Syrota <rasta@renome.rovno.ua>, 2000.\n"
"Yves Guillou <yvesguillou@users.sourceforge.net>, 2004.\n"
"Zdenko Podobný <zdpo@mailbox.sk>, 2003, 2004."
@@ -941,13 +955,13 @@ void AboutBox::initStrings() {
} // namespace UI
} // namespace Inkscape
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/dialog/aboutbox.h b/src/ui/dialog/aboutbox.h
index 7b3308672..015e344a1 100644
--- a/src/ui/dialog/aboutbox.h
+++ b/src/ui/dialog/aboutbox.h
@@ -55,13 +55,13 @@ private:
#endif // INKSCAPE_UI_DIALOG_ABOUTBOX_H
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp
index 6b4aeebb9..431da7ad1 100644
--- a/src/ui/dialog/align-and-distribute.cpp
+++ b/src/ui/dialog/align-and-distribute.cpp
@@ -38,7 +38,7 @@
#include "sp-item-transform.h"
#include "sp-text.h"
#include "text-editing.h"
-#include "tools-switch.h"
+#include "ui/tools-switch.h"
#include "ui/icon-names.h"
#include "ui/tools/node-tool.h"
#include "ui/tool/multi-path-manipulator.h"
@@ -829,14 +829,14 @@ private :
-static void on_tool_changed(Inkscape::Application */*inkscape*/, Inkscape::UI::Tools::ToolBase */*context*/, AlignAndDistribute *daad)
+static void on_tool_changed(InkscapeApplication */*inkscape*/, Inkscape::UI::Tools::ToolBase */*context*/, AlignAndDistribute *daad)
{
SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop && desktop->getEventContext())
daad->setMode(tools_active(desktop) == TOOLS_NODES);
}
-static void on_selection_changed(Inkscape::Application */*inkscape*/, Inkscape::Selection */*selection*/, AlignAndDistribute *daad)
+static void on_selection_changed(InkscapeApplication */*inkscape*/, Inkscape::Selection */*selection*/, AlignAndDistribute *daad)
{
daad->randomize_bbox = Geom::OptRect();
}
@@ -1002,7 +1002,7 @@ AlignAndDistribute::AlignAndDistribute()
_combo.append(_("Smallest object"));
_combo.append(_("Page"));
_combo.append(_("Drawing"));
- _combo.append(_("Selection"));
+ _combo.append(_("Selection Area"));
_combo.set_active(prefs->getInt("/dialogs/align/align-to", 6));
_combo.signal_changed().connect(sigc::mem_fun(*this, &AlignAndDistribute::on_ref_change));
diff --git a/src/ui/dialog/calligraphic-profile-rename.h b/src/ui/dialog/calligraphic-profile-rename.h
index 3256338eb..fa13db196 100644
--- a/src/ui/dialog/calligraphic-profile-rename.h
+++ b/src/ui/dialog/calligraphic-profile-rename.h
@@ -16,7 +16,7 @@
#endif
#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
-#include <glibmm/threads.h>
+# include <glibmm/threads.h>
#endif
#include <gtkmm/dialog.h>
diff --git a/src/ui/dialog/clonetiler.cpp b/src/ui/dialog/clonetiler.cpp
index fb131d8da..d1a675735 100644
--- a/src/ui/dialog/clonetiler.cpp
+++ b/src/ui/dialog/clonetiler.cpp
@@ -1,5 +1,6 @@
-/** @file
+/**
+ * @file
* Clone tiling dialog
*/
/* Authors:
@@ -38,7 +39,7 @@
#include "util/units.h"
#include "helper/window.h"
#include "inkscape.h"
-#include "interface.h"
+#include "ui/interface.h"
#include "macros.h"
#include "message-stack.h"
#include "preferences.h"
@@ -1349,7 +1350,7 @@ void CloneTiler::on_picker_color_changed(guint rgba)
is_updating = false;
}
-void CloneTiler::clonetiler_change_selection(Inkscape::Application * /*inkscape*/, Inkscape::Selection *selection, GtkWidget *dlg)
+void CloneTiler::clonetiler_change_selection(InkscapeApplication * /*inkscape*/, Inkscape::Selection *selection, GtkWidget *dlg)
{
GtkWidget *buttons = GTK_WIDGET(g_object_get_data (G_OBJECT(dlg), "buttons_on_tiles"));
GtkWidget *status = GTK_WIDGET(g_object_get_data (G_OBJECT(dlg), "status"));
@@ -1378,7 +1379,7 @@ void CloneTiler::clonetiler_change_selection(Inkscape::Application * /*inkscape*
}
}
-void CloneTiler::clonetiler_external_change(Inkscape::Application * /*inkscape*/, GtkWidget *dlg)
+void CloneTiler::clonetiler_external_change(InkscapeApplication * /*inkscape*/, GtkWidget *dlg)
{
clonetiler_change_selection (NULL, sp_desktop_selection(SP_ACTIVE_DESKTOP), dlg);
}
@@ -2002,7 +2003,7 @@ bool CloneTiler::clonetiler_is_a_clone_of(SPObject *tile, SPObject *obj)
id_href = g_strdup_printf("#%s", obj_repr->attribute("id"));
}
- if (SP_IS_USE(tile) &&
+ if (dynamic_cast<SPUse *>(tile) &&
tile->getRepr()->attribute("xlink:href") &&
(!id_href || !strcmp(id_href, tile->getRepr()->attribute("xlink:href"))) &&
tile->getRepr()->attribute("inkscape:tiled-clone-of") &&
@@ -2025,8 +2026,10 @@ void CloneTiler::clonetiler_trace_hide_tiled_clones_recursively(SPObject *from)
return;
for (SPObject *o = from->firstChild(); o != NULL; o = o->next) {
- if (SP_IS_ITEM(o) && clonetiler_is_a_clone_of (o, NULL))
- SP_ITEM(o)->invoke_hide(trace_visionkey); // FIXME: hide each tiled clone's original too!
+ SPItem *item = dynamic_cast<SPItem *>(o);
+ if (item && clonetiler_is_a_clone_of(o, NULL)) {
+ item->invoke_hide(trace_visionkey); // FIXME: hide each tiled clone's original too!
+ }
clonetiler_trace_hide_tiled_clones_recursively (o);
}
}
@@ -2160,7 +2163,9 @@ void CloneTiler::clonetiler_remove(GtkWidget */*widget*/, GtkWidget *dlg, bool d
}
}
for (GSList *i = to_delete; i; i = i->next) {
- SP_OBJECT(i->data)->deleteObject();
+ SPObject *obj = reinterpret_cast<SPObject *>(i->data);
+ g_assert(obj != NULL);
+ obj->deleteObject();
}
g_slist_free (to_delete);
@@ -2235,13 +2240,19 @@ void CloneTiler::clonetiler_apply(GtkWidget */*widget*/, GtkWidget *dlg)
gdk_window_process_all_updates();
SPObject *obj = selection->singleItem();
- SPItem *item = SP_IS_ITEM(obj) ? SP_ITEM(obj) : 0;
+ if (!obj) {
+ // Should never happen (empty selection checked above).
+ std::cerr << "CloneTiler::clonetile_apply(): No object in single item selection!!!" << std::endl;
+ return;
+ }
Inkscape::XML::Node *obj_repr = obj->getRepr();
const char *id_href = g_strdup_printf("#%s", obj_repr->attribute("id"));
SPObject *parent = obj->parent;
clonetiler_remove (NULL, dlg, false);
+ double scale_units = Inkscape::Util::Quantity::convert(1, "px", sp_desktop_document(desktop)->getDefaultUnit());
+
double shiftx_per_i = 0.01 * prefs->getDoubleLimited(prefs_path + "shiftx_per_i", 0, -10000, 10000);
double shifty_per_i = 0.01 * prefs->getDoubleLimited(prefs_path + "shifty_per_i", 0, -10000, 10000);
double shiftx_per_j = 0.01 * prefs->getDoubleLimited(prefs_path + "shiftx_per_j", 0, -10000, 10000);
@@ -2311,8 +2322,8 @@ void CloneTiler::clonetiler_apply(GtkWidget */*widget*/, GtkWidget *dlg)
int jmax = prefs->getInt(prefs_path + "jmax", 2);
bool fillrect = prefs->getBool(prefs_path + "fillrect");
- double fillwidth = prefs->getDoubleLimited(prefs_path + "fillwidth", 50, 0, 1e6);
- double fillheight = prefs->getDoubleLimited(prefs_path + "fillheight", 50, 0, 1e6);
+ double fillwidth = scale_units*prefs->getDoubleLimited(prefs_path + "fillwidth", 50, 0, 1e6);
+ double fillheight = scale_units*prefs->getDoubleLimited(prefs_path + "fillheight", 50, 0, 1e6);
bool dotrace = prefs->getBool(prefs_path + "dotrace");
int pick = prefs->getInt(prefs_path + "pick");
@@ -2324,6 +2335,7 @@ void CloneTiler::clonetiler_apply(GtkWidget */*widget*/, GtkWidget *dlg)
bool invert_picked = prefs->getBool(prefs_path + "invert_picked");
double gamma_picked = prefs->getDoubleLimited(prefs_path + "gamma_picked", 0, -10, 10);
+ SPItem *item = dynamic_cast<SPItem *>(obj);
if (dotrace) {
clonetiler_trace_setup (sp_desktop_document(desktop), 1.0, item);
}
@@ -2358,11 +2370,11 @@ void CloneTiler::clonetiler_apply(GtkWidget */*widget*/, GtkWidget *dlg)
SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX );
Geom::OptRect r = item->documentBounds(bbox_type);
if (r) {
- w = r->dimensions()[Geom::X];
- h = r->dimensions()[Geom::Y];
- x0 = r->min()[Geom::X];
- y0 = r->min()[Geom::Y];
- center = desktop->dt2doc(item->getCenter());
+ w = scale_units*r->dimensions()[Geom::X];
+ h = scale_units*r->dimensions()[Geom::Y];
+ x0 = scale_units*r->min()[Geom::X];
+ y0 = scale_units*r->min()[Geom::Y];
+ center = scale_units*desktop->dt2doc(item->getCenter());
sp_repr_set_svg_double(obj_repr, "inkscape:tile-cx", center[Geom::X]);
sp_repr_set_svg_double(obj_repr, "inkscape:tile-cy", center[Geom::Y]);
@@ -2578,7 +2590,7 @@ void CloneTiler::clonetiler_apply(GtkWidget */*widget*/, GtkWidget *dlg)
Geom::Point new_center;
bool center_set = false;
if (obj_repr->attribute("inkscape:transform-center-x") || obj_repr->attribute("inkscape:transform-center-y")) {
- new_center = desktop->dt2doc(item->getCenter()) * t;
+ new_center = scale_units*desktop->dt2doc(item->getCenter()) * t;
center_set = true;
}
@@ -2614,9 +2626,10 @@ void CloneTiler::clonetiler_apply(GtkWidget */*widget*/, GtkWidget *dlg)
if (center_set) {
SPObject *clone_object = sp_desktop_document(desktop)->getObjectByRepr(clone);
- if (clone_object && SP_IS_ITEM(clone_object)) {
+ SPItem *item = dynamic_cast<SPItem *>(clone_object);
+ if (clone_object && item) {
clone_object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
- SP_ITEM(clone_object)->setCenter(desktop->doc2dt(new_center));
+ item->setCenter(desktop->doc2dt(new_center));
clone_object->updateRepr();
}
}
diff --git a/src/ui/dialog/clonetiler.h b/src/ui/dialog/clonetiler.h
index e2a0240ee..70da86338 100644
--- a/src/ui/dialog/clonetiler.h
+++ b/src/ui/dialog/clonetiler.h
@@ -11,7 +11,6 @@
#define __SP_CLONE_TILER_H__
#include "ui/widget/panel.h"
-#include <gtk/gtk.h>
#include "ui/dialog/desktop-tracker.h"
#include "ui/widget/color-picker.h"
@@ -58,8 +57,8 @@ protected:
static void clonetiler_keep_bbox_toggled(GtkToggleButton *tb, gpointer /*data*/);
static void clonetiler_apply(GtkWidget */*widget*/, GtkWidget *dlg);
static void clonetiler_unclump(GtkWidget */*widget*/, void *);
- static void clonetiler_change_selection(Inkscape::Application * /*inkscape*/, Inkscape::Selection *selection, GtkWidget *dlg);
- static void clonetiler_external_change(Inkscape::Application * /*inkscape*/, GtkWidget *dlg);
+ static void clonetiler_change_selection(InkscapeApplication * /*inkscape*/, Inkscape::Selection *selection, GtkWidget *dlg);
+ static void clonetiler_external_change(InkscapeApplication * /*inkscape*/, GtkWidget *dlg);
static void clonetiler_disconnect_gsignal(GObject *widget, gpointer source);
static void clonetiler_reset(GtkWidget */*widget*/, GtkWidget *dlg);
static guint clonetiler_number_of_clones(SPObject *obj);
diff --git a/src/ui/dialog/color-item.cpp b/src/ui/dialog/color-item.cpp
index 7940c28ae..bab7e18e1 100644
--- a/src/ui/dialog/color-item.cpp
+++ b/src/ui/dialog/color-item.cpp
@@ -684,6 +684,7 @@ void ColorItem::buttonClicked(bool secondary)
descr = secondary? _("Set stroke color to none") : _("Set fill color to none");
break;
}
+//mark
case ege::PaintDef::RGB: {
Glib::ustring colorspec;
if ( _grad ){
@@ -696,6 +697,7 @@ void ColorItem::buttonClicked(bool secondary)
sp_svg_write_color(c, sizeof(c), rgba);
colorspec = c;
}
+//end mark
sp_repr_css_set_property( css, attrName, colorspec.c_str() );
descr = secondary? _("Set stroke color from swatch") : _("Set fill color from swatch");
break;
diff --git a/src/ui/dialog/desktop-tracker.cpp b/src/ui/dialog/desktop-tracker.cpp
index 8a359dd2d..3ed998252 100644
--- a/src/ui/dialog/desktop-tracker.cpp
+++ b/src/ui/dialog/desktop-tracker.cpp
@@ -94,7 +94,7 @@ sigc::connection DesktopTracker::connectDesktopChanged( const sigc::slot<void, S
return desktopChangedSig.connect(slot);
}
-gboolean DesktopTracker::activateDesktopCB(Inkscape::Application */*inkscape*/, SPDesktop *desktop, DesktopTracker *self )
+gboolean DesktopTracker::activateDesktopCB(InkscapeApplication */*inkscape*/, SPDesktop *desktop, DesktopTracker *self )
{
if (self && self->trackActive) {
self->setDesktop(desktop);
diff --git a/src/ui/dialog/desktop-tracker.h b/src/ui/dialog/desktop-tracker.h
index 7da55cf2f..7b944ddfa 100644
--- a/src/ui/dialog/desktop-tracker.h
+++ b/src/ui/dialog/desktop-tracker.h
@@ -12,11 +12,10 @@
typedef struct _GtkWidget GtkWidget;
class SPDesktop;
+struct InkscapeApplication;
namespace Inkscape {
-struct Application;
-
namespace UI {
namespace Dialog {
@@ -37,7 +36,7 @@ public:
sigc::connection connectDesktopChanged( const sigc::slot<void, SPDesktop*> & slot );
private:
- static gboolean activateDesktopCB(Inkscape::Application *inkscape, SPDesktop *desktop, DesktopTracker *self );
+ static gboolean activateDesktopCB(InkscapeApplication *inkscape, SPDesktop *desktop, DesktopTracker *self );
static bool hierarchyChangeCB(GtkWidget *widget, GtkWidget* prev, DesktopTracker *self);
void handleHierarchyChange();
diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp
index 47e1fdd30..7b1b36908 100644
--- a/src/ui/dialog/dialog-manager.cpp
+++ b/src/ui/dialog/dialog-manager.cpp
@@ -54,6 +54,8 @@
#include "ui/dialog/xml-tree.h"
#include "ui/dialog/clonetiler.h"
#include "ui/dialog/svg-fonts-dialog.h"
+#include "ui/dialog/objects.h"
+#include "ui/dialog/tags.h"
namespace Inkscape {
namespace UI {
@@ -70,13 +72,13 @@ inline Dialog *create() { return PanelDialog<B>::template create<T>(); }
/**
* This class is provided as a container for Inkscape's various
- * dialogs. This allows Inkscape::Application to treat the various
+ * dialogs. This allows InkscapeApplication to treat the various
* dialogs it invokes, as abstractions.
*
* DialogManager is essentially a cache of dialogs. It lets us
* initialize dialogs lazily - instead of constructing them during
* application startup, they're constructed the first time they're
- * actually invoked by Inkscape::Application. The constructed
+ * actually invoked by InkscapeApplication. The constructed
* dialog is held here after that, so future invokations of the
* dialog don't need to get re-constructed each time. The memory for
* the dialogs are then reclaimed when the DialogManager is destroyed.
@@ -96,6 +98,9 @@ DialogManager::DialogManager() {
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
int dialogs_type = prefs->getIntLimited("/options/dialogtype/value", DOCK, 0, 1);
+ // The preferences dialog is broken, the DockBehavior code resizes it's floating window to the smallest size
+ registerFactory("InkscapePreferences", &create<InkscapePreferences, FloatingBehavior>);
+
if (dialogs_type == FLOATING) {
registerFactory("AlignAndDistribute", &create<AlignAndDistribute, FloatingBehavior>);
registerFactory("DocumentMetadata", &create<DocumentMetadata, FloatingBehavior>);
@@ -106,8 +111,9 @@ DialogManager::DialogManager() {
registerFactory("Find", &create<Find, FloatingBehavior>);
registerFactory("Glyphs", &create<GlyphsPanel, FloatingBehavior>);
registerFactory("IconPreviewPanel", &create<IconPreviewPanel, FloatingBehavior>);
- registerFactory("InkscapePreferences", &create<InkscapePreferences, FloatingBehavior>);
registerFactory("LayersPanel", &create<LayersPanel, FloatingBehavior>);
+ registerFactory("ObjectsPanel", &create<ObjectsPanel, FloatingBehavior>);
+ registerFactory("TagsPanel", &create<TagsPanel, FloatingBehavior>);
registerFactory("LivePathEffect", &create<LivePathEffectEditor, FloatingBehavior>);
registerFactory("Memory", &create<Memory, FloatingBehavior>);
registerFactory("Messages", &create<Messages, FloatingBehavior>);
@@ -126,8 +132,8 @@ DialogManager::DialogManager() {
registerFactory("TextFont", &create<TextEdit, FloatingBehavior>);
registerFactory("SpellCheck", &create<SpellCheck, FloatingBehavior>);
registerFactory("Export", &create<Export, FloatingBehavior>);
- registerFactory("XmlTree", &create<XmlTree, FloatingBehavior>);
registerFactory("CloneTiler", &create<CloneTiler, FloatingBehavior>);
+ registerFactory("XmlTree", &create<XmlTree, FloatingBehavior>);
} else {
@@ -140,8 +146,9 @@ DialogManager::DialogManager() {
registerFactory("Find", &create<Find, DockBehavior>);
registerFactory("Glyphs", &create<GlyphsPanel, DockBehavior>);
registerFactory("IconPreviewPanel", &create<IconPreviewPanel, DockBehavior>);
- registerFactory("InkscapePreferences", &create<InkscapePreferences, DockBehavior>);
registerFactory("LayersPanel", &create<LayersPanel, DockBehavior>);
+ registerFactory("ObjectsPanel", &create<ObjectsPanel, DockBehavior>);
+ registerFactory("TagsPanel", &create<TagsPanel, DockBehavior>);
registerFactory("LivePathEffect", &create<LivePathEffectEditor, DockBehavior>);
registerFactory("Memory", &create<Memory, DockBehavior>);
registerFactory("Messages", &create<Messages, DockBehavior>);
@@ -160,8 +167,8 @@ DialogManager::DialogManager() {
registerFactory("TextFont", &create<TextEdit, DockBehavior>);
registerFactory("SpellCheck", &create<SpellCheck, DockBehavior>);
registerFactory("Export", &create<Export, DockBehavior>);
- registerFactory("XmlTree", &create<XmlTree, DockBehavior>);
registerFactory("CloneTiler", &create<CloneTiler, DockBehavior>);
+ registerFactory("XmlTree", &create<XmlTree, DockBehavior>);
}
}
@@ -250,7 +257,7 @@ void DialogManager::showDialog(gchar const *name, bool grabfocus) {
/**
* Shows the named dialog, creating it if necessary.
*/
-void DialogManager::showDialog(GQuark name, bool grabfocus) {
+void DialogManager::showDialog(GQuark name, bool /*grabfocus*/) {
bool wantTiming = Inkscape::Preferences::get()->getBool("/dialogs/debug/trackAppear", false);
GTimer *timer = (wantTiming) ? g_timer_new() : 0; // if needed, must be created/started before getDialog()
Dialog *dialog = getDialog(name);
@@ -261,8 +268,8 @@ void DialogManager::showDialog(GQuark name, bool grabfocus) {
tracker->setAutodelete(true);
timer = 0;
}
- if (grabfocus)
- dialog->present();
+ // should check for grabfocus, but lp:1348927 prevents it
+ dialog->present();
}
if ( timer ) {
diff --git a/src/ui/dialog/dialog.cpp b/src/ui/dialog/dialog.cpp
index 645294bb5..213965a18 100644
--- a/src/ui/dialog/dialog.cpp
+++ b/src/ui/dialog/dialog.cpp
@@ -28,7 +28,7 @@
#include "desktop-handles.h"
#include "shortcuts.h"
#include "preferences.h"
-#include "interface.h"
+#include "ui/interface.h"
#include "verbs.h"
#include "ui/tool/event-utils.h"
@@ -41,7 +41,7 @@ namespace Inkscape {
namespace UI {
namespace Dialog {
-void sp_retransientize(Inkscape::Application */*inkscape*/, SPDesktop *desktop, gpointer dlgPtr)
+void sp_retransientize(InkscapeApplication */*inkscape*/, SPDesktop *desktop, gpointer dlgPtr)
{
Dialog *dlg = static_cast<Dialog *>(dlgPtr);
dlg->onDesktopActivated (desktop);
@@ -317,20 +317,8 @@ void Dialog::_apply()
void Dialog::_close()
{
- GtkWidget *dlg = GTK_WIDGET(_behavior->gobj());
-
- GdkEventAny event;
- event.type = GDK_DELETE;
- event.window = gtk_widget_get_window(dlg);
- event.send_event = TRUE;
-
- if (event.window)
- g_object_ref(G_OBJECT(event.window));
-
- gtk_main_do_event ((GdkEvent*)&event);
-
- if (event.window)
- g_object_unref(G_OBJECT(event.window));
+ _behavior->hide();
+ _onDeleteEvent(NULL);
}
void Dialog::_defocus()
diff --git a/src/ui/dialog/dialog.h b/src/ui/dialog/dialog.h
index ec5d203bc..ccff43a56 100644
--- a/src/ui/dialog/dialog.h
+++ b/src/ui/dialog/dialog.h
@@ -18,10 +18,10 @@
#include "floating-behavior.h"
class SPDesktop;
+struct InkscapeApplication;
namespace Inkscape {
class Selection;
-struct Application;
}
namespace Inkscape {
@@ -30,7 +30,7 @@ namespace Dialog {
enum BehaviorType { FLOATING, DOCK };
-void sp_retransientize(Inkscape::Application *inkscape, SPDesktop *desktop, gpointer dlgPtr);
+void sp_retransientize(InkscapeApplication *inkscape, SPDesktop *desktop, gpointer dlgPtr);
gboolean sp_retransientize_again(gpointer dlgPtr);
void sp_dialog_shutdown(GObject *object, gpointer dlgPtr);
diff --git a/src/ui/dialog/dock-behavior.cpp b/src/ui/dialog/dock-behavior.cpp
index 9b216e841..50a6db208 100644
--- a/src/ui/dialog/dock-behavior.cpp
+++ b/src/ui/dialog/dock-behavior.cpp
@@ -18,13 +18,13 @@
#include "dock-behavior.h"
#include "inkscape.h"
#include "desktop.h"
-#include "interface.h"
+#include "ui/interface.h"
#include "widgets/icon.h"
#include "ui/widget/dock.h"
#include "verbs.h"
#include "dialog.h"
#include "preferences.h"
-#include "dialogs/dialog-events.h"
+#include "ui/dialog-events.h"
#include <gtkmm/invisible.h>
#include <gtkmm/label.h>
diff --git a/src/ui/dialog/document-metadata.cpp b/src/ui/dialog/document-metadata.cpp
index 09c505860..77ea175d9 100644
--- a/src/ui/dialog/document-metadata.cpp
+++ b/src/ui/dialog/document-metadata.cpp
@@ -223,7 +223,7 @@ DocumentMetadata::_handleDocumentReplaced(SPDesktop* desktop, SPDocument *)
}
void
-DocumentMetadata::_handleActivateDesktop(Inkscape::Application *, SPDesktop *desktop)
+DocumentMetadata::_handleActivateDesktop(InkscapeApplication *, SPDesktop *desktop)
{
Inkscape::XML::Node *repr = sp_desktop_namedview(desktop)->getRepr();
repr->addListener(&_repr_events, this);
@@ -231,7 +231,7 @@ DocumentMetadata::_handleActivateDesktop(Inkscape::Application *, SPDesktop *des
}
void
-DocumentMetadata::_handleDeactivateDesktop(Inkscape::Application *, SPDesktop *desktop)
+DocumentMetadata::_handleDeactivateDesktop(InkscapeApplication *, SPDesktop *desktop)
{
Inkscape::XML::Node *repr = sp_desktop_namedview(desktop)->getRepr();
repr->removeListenerByData(this);
diff --git a/src/ui/dialog/document-metadata.h b/src/ui/dialog/document-metadata.h
index 3b7ed1ec8..77084bc3d 100644
--- a/src/ui/dialog/document-metadata.h
+++ b/src/ui/dialog/document-metadata.h
@@ -56,8 +56,8 @@ protected:
void init();
void _handleDocumentReplaced(SPDesktop* desktop, SPDocument *document);
- void _handleActivateDesktop(Inkscape::Application *application, SPDesktop *desktop);
- void _handleDeactivateDesktop(Inkscape::Application *application, SPDesktop *desktop);
+ void _handleActivateDesktop(InkscapeApplication *application, SPDesktop *desktop);
+ void _handleDeactivateDesktop(InkscapeApplication *application, SPDesktop *desktop);
Gtk::Notebook _notebook;
diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp
index 67e788e21..6064c2a5e 100644
--- a/src/ui/dialog/document-properties.cpp
+++ b/src/ui/dialog/document-properties.cpp
@@ -31,13 +31,13 @@
#include "inkscape.h"
#include "io/sys.h"
#include "preferences.h"
-#include "shape-editor.h"
+#include "ui/shape-editor.h"
#include "sp-namedview.h"
#include "sp-root.h"
#include "sp-script.h"
#include "style.h"
#include "svg/stringstream.h"
-#include "tools-switch.h"
+#include "ui/tools-switch.h"
#include "ui/widget/color-picker.h"
#include "ui/widget/scalar-unit.h"
#include "ui/dialog/filedialog.h"
@@ -45,6 +45,7 @@
#include "widgets/icon.h"
#include "xml/node-event-vector.h"
#include "xml/repr.h"
+#include <algorithm> // std::min
#include "rdf.h"
#include "ui/widget/entity-entry.h"
@@ -596,6 +597,7 @@ void DocumentProperties::removeSelectedProfile(){
//XML Tree being used directly here while it shouldn't be.
sp_repr_unparent(obj->getRepr());
DocumentUndo::done(SP_ACTIVE_DOCUMENT, SP_VERB_EDIT_REMOVE_COLOR_PROFILE, _("Remove linked color profile"));
+ break; // removing the color profile likely invalidates part of the traversed list, stop traversing here.
}
current = g_slist_next(current);
}
@@ -1203,10 +1205,10 @@ void DocumentProperties::removeExternalScript(){
const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "script" );
while ( current ) {
- if (current->data && SP_IS_OBJECT(current->data)) {
- SPObject* obj = SP_OBJECT(current->data);
- SPScript* script = SP_SCRIPT(obj);
- if (name == script->xlinkhref){
+ SPObject* obj = reinterpret_cast<SPObject *>(current->data);
+ if (obj) {
+ SPScript* script = dynamic_cast<SPScript *>(obj);
+ if (script && (name == script->xlinkhref)) {
//XML Tree being used directly here while it shouldn't be.
Inkscape::XML::Node *repr = obj->getRepr();
@@ -1236,23 +1238,16 @@ void DocumentProperties::removeEmbeddedScript(){
}
}
- const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "script" );
- while ( current ) {
- if (current->data && SP_IS_OBJECT(current->data)) {
- SPObject* obj = SP_OBJECT(current->data);
- if (id == obj->getId()){
-
- //XML Tree being used directly here while it shouldn't be.
- Inkscape::XML::Node *repr = obj->getRepr();
- if (repr){
- sp_repr_unparent(repr);
+ SPObject* obj = SP_ACTIVE_DOCUMENT->getObjectById(id);
+ if (obj) {
+ //XML Tree being used directly here while it shouldn't be.
+ Inkscape::XML::Node *repr = obj->getRepr();
+ if (repr){
+ sp_repr_unparent(repr);
- // inform the document, so we can undo
- DocumentUndo::done(SP_ACTIVE_DOCUMENT, SP_VERB_EDIT_REMOVE_EMBEDDED_SCRIPT, _("Remove embedded script"));
- }
- }
+ // inform the document, so we can undo
+ DocumentUndo::done(SP_ACTIVE_DOCUMENT, SP_VERB_EDIT_REMOVE_EMBEDDED_SCRIPT, _("Remove embedded script"));
}
- current = g_slist_next(current);
}
populate_script_lists();
@@ -1359,10 +1354,15 @@ void DocumentProperties::populate_script_lists(){
_ExternalScriptsListStore->clear();
_EmbeddedScriptsListStore->clear();
const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "script" );
- if (current) _scripts_observer.set(SP_OBJECT(current->data)->parent);
+ if (current) {
+ SPObject *obj = reinterpret_cast<SPObject *>(current->data);
+ g_assert(obj != NULL);
+ _scripts_observer.set(obj->parent);
+ }
while ( current ) {
- SPObject* obj = SP_OBJECT(current->data);
- SPScript* script = SP_SCRIPT(obj);
+ SPObject* obj = reinterpret_cast<SPObject *>(current->data);
+ SPScript* script = dynamic_cast<SPScript *>(obj);
+ g_assert(script != NULL);
if (script->xlinkhref)
{
Gtk::TreeModel::Row row = *(_ExternalScriptsListStore->append());
@@ -1599,7 +1599,7 @@ void DocumentProperties::_handleDocumentReplaced(SPDesktop* desktop, SPDocument
update();
}
-void DocumentProperties::_handleActivateDesktop(Inkscape::Application *, SPDesktop *desktop)
+void DocumentProperties::_handleActivateDesktop(InkscapeApplication *, SPDesktop *desktop)
{
Inkscape::XML::Node *repr = sp_desktop_namedview(desktop)->getRepr();
repr->addListener(&_repr_events, this);
@@ -1608,7 +1608,7 @@ void DocumentProperties::_handleActivateDesktop(Inkscape::Application *, SPDeskt
update();
}
-void DocumentProperties::_handleDeactivateDesktop(Inkscape::Application *, SPDesktop *desktop)
+void DocumentProperties::_handleDeactivateDesktop(InkscapeApplication *, SPDesktop *desktop)
{
Inkscape::XML::Node *repr = sp_desktop_namedview(desktop)->getRepr();
repr->removeListenerByData(this);
@@ -1741,14 +1741,19 @@ void DocumentProperties::onDocUnitChange()
prefs->setBool("/options/transform/gradient", true);
{
ShapeEditor::blockSetItem(true);
- gdouble viewscale = doc->getWidth().value("px")/doc->getRoot()->viewBox.width();
- if (doc->getHeight().value("px")/doc->getRoot()->viewBox.height() < viewscale)
- viewscale = doc->getHeight().value("px")/doc->getRoot()->viewBox.height();
+ gdouble viewscale = 1.0;
+ Geom::Rect vb = doc->getRoot()->viewBox;
+ if ( !vb.hasZeroArea() ) {
+ gdouble viewscale_w = doc->getWidth().value("px") / vb.width();
+ gdouble viewscale_h = doc->getHeight().value("px")/ vb.height();
+ viewscale = std::min(viewscale_h, viewscale_w);
+ }
gdouble scale = Inkscape::Util::Quantity::convert(1, old_doc_unit, doc_unit);
doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(-viewscale*doc->getRoot()->viewBox.min()[Geom::X] +
(doc->getWidth().value("px") - viewscale*doc->getRoot()->viewBox.width())/2,
viewscale*doc->getRoot()->viewBox.min()[Geom::Y] +
- (doc->getHeight().value("px") + viewscale*doc->getRoot()->viewBox.height())/2));
+ (doc->getHeight().value("px") + viewscale*doc->getRoot()->viewBox.height())/2),
+ false);
ShapeEditor::blockSetItem(false);
}
prefs->setBool("/options/transform/stroke", transform_stroke);
diff --git a/src/ui/dialog/document-properties.h b/src/ui/dialog/document-properties.h
index 495f3177d..ee7e88b18 100644
--- a/src/ui/dialog/document-properties.h
+++ b/src/ui/dialog/document-properties.h
@@ -94,8 +94,8 @@ protected:
void save_default_metadata();
void _handleDocumentReplaced(SPDesktop* desktop, SPDocument *document);
- void _handleActivateDesktop(Inkscape::Application *application, SPDesktop *desktop);
- void _handleDeactivateDesktop(Inkscape::Application *application, SPDesktop *desktop);
+ void _handleActivateDesktop(InkscapeApplication *application, SPDesktop *desktop);
+ void _handleDeactivateDesktop(InkscapeApplication *application, SPDesktop *desktop);
Inkscape::XML::SignalObserver _emb_profiles_observer, _scripts_observer;
Gtk::Notebook _notebook;
diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp
index 913713e5c..b044a6e2c 100644
--- a/src/ui/dialog/export.cpp
+++ b/src/ui/dialog/export.cpp
@@ -62,10 +62,10 @@
#include "sp-namedview.h"
#include "selection-chemistry.h"
-#include "dialogs/dialog-events.h"
+#include "ui/dialog-events.h"
#include "preferences.h"
#include "verbs.h"
-#include "interface.h"
+#include "ui/interface.h"
#include "sp-root.h"
#include "extension/output.h"
@@ -537,7 +537,7 @@ Gtk::Adjustment * Export::createSpinbutton( gchar const * /*key*/, float val, fl
sb->set_sensitive (sensitive);
pos++;
- if (!ll.empty()) {
+ if (l) {
l->set_mnemonic_widget(*sb);
}
diff --git a/src/ui/dialog/export.h b/src/ui/dialog/export.h
index 6f3c0dfac..23af0109b 100644
--- a/src/ui/dialog/export.h
+++ b/src/ui/dialog/export.h
@@ -12,20 +12,11 @@
#ifndef SP_EXPORT_H
#define SP_EXPORT_H
-#include <gtk/gtk.h>
-#include <glibmm/i18n.h>
-
-#include <gtkmm/comboboxtext.h>
-#include <gtkmm/expander.h>
-#include <gtkmm/frame.h>
#include <gtkmm/progressbar.h>
-#include <gtkmm/textview.h>
-#include "desktop.h"
#include "ui/dialog/desktop-tracker.h"
#include "ui/widget/panel.h"
#include "ui/widget/button.h"
-#include "ui/widget/entry.h"
namespace Gtk {
class Dialog;
diff --git a/src/ui/dialog/extension-editor.cpp b/src/ui/dialog/extension-editor.cpp
index cd5491c24..9bdddc0e0 100644
--- a/src/ui/dialog/extension-editor.cpp
+++ b/src/ui/dialog/extension-editor.cpp
@@ -25,7 +25,7 @@
#include "verbs.h"
#include "preferences.h"
-#include "interface.h"
+#include "ui/interface.h"
#include "extension/extension.h"
#include "extension/db.h"
diff --git a/src/ui/dialog/filedialog.cpp b/src/ui/dialog/filedialog.cpp
index e71605739..00ed09551 100644
--- a/src/ui/dialog/filedialog.cpp
+++ b/src/ui/dialog/filedialog.cpp
@@ -20,7 +20,7 @@
#include "filedialog.h"
#include "gc-core.h"
-#include <dialogs/dialog-events.h>
+#include "ui/dialog-events.h"
#include "extension/output.h"
#include "preferences.h"
diff --git a/src/ui/dialog/filedialog.h b/src/ui/dialog/filedialog.h
index 8dfcf5dce..175031bcf 100644
--- a/src/ui/dialog/filedialog.h
+++ b/src/ui/dialog/filedialog.h
@@ -48,6 +48,7 @@ typedef enum {
IMPORT_TYPES,
EXPORT_TYPES,
EXE_TYPES,
+ SWATCH_TYPES,
CUSTOM_TYPE
} FileDialogType;
diff --git a/src/ui/dialog/filedialogimpl-gtkmm.cpp b/src/ui/dialog/filedialogimpl-gtkmm.cpp
index 8ba3ad684..5d330f7f0 100644
--- a/src/ui/dialog/filedialogimpl-gtkmm.cpp
+++ b/src/ui/dialog/filedialogimpl-gtkmm.cpp
@@ -21,9 +21,11 @@
#include <config.h>
#endif
+#include <iostream>
+
#include "filedialogimpl-gtkmm.h"
-#include "dialogs/dialog-events.h"
-#include "interface.h"
+#include "ui/dialog-events.h"
+#include "ui/interface.h"
#include "io/sys.h"
#include "path-prefix.h"
#include "preferences.h"
@@ -40,6 +42,9 @@
#include <glibmm/i18n.h>
#include <glibmm/miscutils.h>
+#include <glibmm/regex.h>
+
+#include "document.h"
#include "extension/input.h"
#include "extension/output.h"
#include "extension/db.h"
@@ -190,6 +195,40 @@ void SVGPreview::showImage(Glib::ustring &theFileName)
{
Glib::ustring fileName = theFileName;
+ // Let's get real width and height from SVG file. These are template
+ // files so we assume they are well formed.
+
+ // std::cout << "SVGPreview::showImage: " << theFileName << std::endl;
+ std::ifstream input(theFileName.c_str());
+
+ std::string width;
+ std::string height;
+
+ if( !input ) {
+ std::cerr << "SVGPreview::showImage: Failed to open file: " << theFileName << std::endl;
+ } else {
+
+ std::string token;
+
+ Glib::MatchInfo match_info;
+ Glib::RefPtr<Glib::Regex> regex1 = Glib::Regex::create("width=\"(.*)\"");
+ Glib::RefPtr<Glib::Regex> regex2 = Glib::Regex::create("height=\"(.*)\"");
+
+ while( !input.eof() && (height.empty() || width.empty()) ) {
+
+ input >> token;
+ // std::cout << "|" << token << "|" << std::endl;
+
+ if (regex1->match(token, match_info)) {
+ width = match_info.fetch(1).raw();
+ }
+
+ if (regex2->match(token, match_info)) {
+ height = match_info.fetch(1).raw();
+ }
+
+ }
+ }
/*#####################################
# LET'S HAVE SOME FUN WITH SVG!
@@ -269,7 +308,7 @@ void SVGPreview::showImage(Glib::ustring &theFileName)
" style=\"font-size:24.000000;font-style:normal;font-weight:normal;"
" fill:#000000;fill-opacity:1.0000000;stroke:none;"
" font-family:Sans\"\n"
- " x=\"10\" y=\"26\">%d x %d</text>\n" //# VALUES HERE
+ " x=\"10\" y=\"26\">%s x %s</text>\n" //# VALUES HERE
"</svg>\n\n";
// if (!Glib::get_charset()) //If we are not utf8
@@ -279,7 +318,7 @@ void SVGPreview::showImage(Glib::ustring &theFileName)
/* FIXME: Do proper XML quoting for fileName. */
gchar *xmlBuffer =
g_strdup_printf(xformat, previewWidth, previewHeight, imgX, imgY, scaledImgWidth, scaledImgHeight,
- fileName.c_str(), rectX, rectY, rectWidth, rectHeight, imgWidth, imgHeight);
+ fileName.c_str(), rectX, rectY, rectWidth, rectHeight, width.c_str(), height.c_str() );
// g_message("%s\n", xmlBuffer);
diff --git a/src/ui/dialog/filedialogimpl-win32.cpp b/src/ui/dialog/filedialogimpl-win32.cpp
index 9d91f5d56..ee6a0ef3a 100644
--- a/src/ui/dialog/filedialogimpl-win32.cpp
+++ b/src/ui/dialog/filedialogimpl-win32.cpp
@@ -31,7 +31,7 @@
//Inkscape includes
#include "inkscape.h"
-#include "dialogs/dialog-events.h"
+#include "ui/dialog-events.h"
#include "extension/input.h"
#include "extension/output.h"
#include "extension/db.h"
@@ -72,13 +72,6 @@ const unsigned long MaxPreviewFileSize = 10240; // kB
#define IDC_SHOW_PREVIEW 1000
-// Windows 2000 version of OPENFILENAMEW
-struct OPENFILENAMEEXW : public OPENFILENAMEW {
- void * pvReserved;
- DWORD dwReserved;
- DWORD FlagsEx;
-};
-
struct Filter
{
gunichar2* name;
@@ -483,7 +476,7 @@ void FileOpenDialogImplWin32::createFilterMenu()
void FileOpenDialogImplWin32::GetOpenFileName_thread()
{
- OPENFILENAMEEXW ofn;
+ OPENFILENAMEW ofn;
g_assert(this != NULL);
g_assert(_mutex != NULL);
@@ -1829,7 +1822,7 @@ void FileSaveDialogImplWin32::addFileType(Glib::ustring name, Glib::ustring patt
void FileSaveDialogImplWin32::GetSaveFileName_thread()
{
- OPENFILENAMEEXW ofn;
+ OPENFILENAMEW ofn;
g_assert(this != NULL);
g_assert(_main_loop != NULL);
@@ -1860,7 +1853,6 @@ void FileSaveDialogImplWin32::GetSaveFileName_thread()
ofn.nFilterIndex = _filter_index;
ofn.lpfnHook = GetSaveFileName_hookproc;
ofn.lCustData = (LPARAM)this;
-
_result = GetSaveFileNameW(&ofn) != 0;
g_assert(ofn.nFilterIndex >= 1 && ofn.nFilterIndex <= _filter_count);
diff --git a/src/ui/dialog/filedialogimpl-win32.h b/src/ui/dialog/filedialogimpl-win32.h
index 29bcb9a45..f77249abd 100644
--- a/src/ui/dialog/filedialogimpl-win32.h
+++ b/src/ui/dialog/filedialogimpl-win32.h
@@ -13,16 +13,23 @@
# include "config.h"
#endif
+#include <glibmm.h>
+
#ifdef WIN32
#if WITH_GLIBMM_2_32
#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
# include <glibmm/threads.h>
#endif
-
#endif
+
+#include "filedialogimpl-gtkmm.h"
+
#include "gc-core.h"
+ // define WINVER high enough so we get the correct OPENFILENAMEW size
+#ifndef WINVER
+#define WINVER 0x0500
+#endif
#include <windows.h>
-#include "filedialogimpl-gtkmm.h"
namespace Inkscape
diff --git a/src/ui/dialog/fill-and-stroke.h b/src/ui/dialog/fill-and-stroke.h
index 340cb860f..35c98ef9c 100644
--- a/src/ui/dialog/fill-and-stroke.h
+++ b/src/ui/dialog/fill-and-stroke.h
@@ -41,7 +41,7 @@ public:
virtual void setDesktop(SPDesktop *desktop);
- void selectionChanged(Inkscape::Application *inkscape,
+ void selectionChanged(InkscapeApplication *inkscape,
Inkscape::Selection *selection);
void showPageFill();
diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp
index c2367c2a2..bd44846a3 100644
--- a/src/ui/dialog/filter-effects-dialog.cpp
+++ b/src/ui/dialog/filter-effects-dialog.cpp
@@ -546,7 +546,7 @@ public:
_matrix(SP_ATTR_VALUES, _("This matrix determines a linear transform on color space. Each line affects one of the color components. Each column determines how much of each color component from the input is passed to the output. The last column does not depend on input colors, so can be used to adjust a constant component value.")),
_saturation("", 0, 0, 1, 0.1, 0.01, 2, SP_ATTR_VALUES),
_angle("", 0, 0, 360, 0.1, 0.01, 1, SP_ATTR_VALUES),
- _label(_("None"), Gtk::ALIGN_START),
+ _label(C_("Label", "None"), Gtk::ALIGN_START),
_use_stored(false),
_saturation_store(0),
_angle_store(0)
diff --git a/src/ui/dialog/find.cpp b/src/ui/dialog/find.cpp
index 37f2761df..1a7832688 100644
--- a/src/ui/dialog/find.cpp
+++ b/src/ui/dialog/find.cpp
@@ -31,9 +31,9 @@
#include "selection.h"
#include "desktop-handles.h"
-#include "dialogs/dialog-events.h"
+#include "ui/dialog-events.h"
#include "verbs.h"
-#include "interface.h"
+#include "ui/interface.h"
#include "preferences.h"
#include "sp-text.h"
#include "sp-flowtext.h"
@@ -241,7 +241,7 @@ Find::Find()
Inkscape::Selection *selection = sp_desktop_selection (SP_ACTIVE_DESKTOP);
SPItem *item = selection->singleItem();
if (item) {
- if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) {
+ if (dynamic_cast<SPText *>(item) || dynamic_cast<SPFlowtext *>(item)) {
gchar *str;
str = sp_te_get_string_multiline (item);
entry_find.getEntry()->set_text(str);
@@ -343,7 +343,7 @@ bool Find::item_text_match (SPItem *item, const gchar *find, bool exact, bool ca
return false;
}
- if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) {
+ if (dynamic_cast<SPText *>(item) || dynamic_cast<SPFlowtext *>(item)) {
const gchar *item_text = sp_te_get_string_multiline (item);
if (item_text == NULL) {
return false;
@@ -388,7 +388,7 @@ bool Find::item_id_match (SPItem *item, const gchar *id, bool exact, bool casema
return false;
}
- if (SP_IS_STRING(item)) { // SPStrings have "on demand" ids which are useless for searching
+ if (dynamic_cast<SPString *>(item)) { // SPStrings have "on demand" ids which are useless for searching
return false;
}
@@ -561,11 +561,14 @@ GSList *Find::filter_fields (GSList *l, bool exact, bool casematch)
if (check_searchin_text.get_active()) {
for (GSList *i = in; i != NULL; i = i->next) {
- if (item_text_match (SP_ITEM(i->data), text, exact, casematch)) {
+ SPObject *obj = reinterpret_cast<SPObject *>(i->data);
+ SPItem *item = dynamic_cast<SPItem *>(obj);
+ g_assert(item != NULL);
+ if (item_text_match(item, text, exact, casematch)) {
if (!g_slist_find(out, i->data)) {
out = g_slist_prepend (out, i->data);
if (_action_replace) {
- item_text_match (SP_ITEM(i->data), text, exact, casematch, _action_replace);
+ item_text_match(item, text, exact, casematch, _action_replace);
}
}
}
@@ -581,11 +584,13 @@ GSList *Find::filter_fields (GSList *l, bool exact, bool casematch)
if (ids) {
for (GSList *i = in; i != NULL; i = i->next) {
- if (item_id_match (SP_ITEM(i->data), text, exact, casematch)) {
+ SPObject *obj = reinterpret_cast<SPObject *>(i->data);
+ SPItem *item = dynamic_cast<SPItem *>(obj);
+ if (item_id_match(item, text, exact, casematch)) {
if (!g_slist_find(out, i->data)) {
out = g_slist_prepend (out, i->data);
if (_action_replace) {
- item_id_match (SP_ITEM(i->data), text, exact, casematch, _action_replace);
+ item_id_match(item, text, exact, casematch, _action_replace);
}
}
}
@@ -595,12 +600,15 @@ GSList *Find::filter_fields (GSList *l, bool exact, bool casematch)
if (style) {
for (GSList *i = in; i != NULL; i = i->next) {
- if (item_style_match (SP_ITEM(i->data), text, exact, casematch)) {
+ SPObject *obj = reinterpret_cast<SPObject *>(i->data);
+ SPItem *item = dynamic_cast<SPItem *>(obj);
+ g_assert(item != NULL);
+ if (item_style_match(item, text, exact, casematch)) {
if (!g_slist_find(out, i->data))
if (!g_slist_find(out, i->data)) {
out = g_slist_prepend (out, i->data);
if (_action_replace) {
- item_style_match (SP_ITEM(i->data), text, exact, casematch, _action_replace);
+ item_style_match(item, text, exact, casematch, _action_replace);
}
}
}
@@ -610,11 +618,14 @@ GSList *Find::filter_fields (GSList *l, bool exact, bool casematch)
if (attrname) {
for (GSList *i = in; i != NULL; i = i->next) {
- if (item_attr_match (SP_ITEM(i->data), text, exact, casematch)) {
+ SPObject *obj = reinterpret_cast<SPObject *>(i->data);
+ SPItem *item = dynamic_cast<SPItem *>(obj);
+ g_assert(item != NULL);
+ if (item_attr_match(item, text, exact, casematch)) {
if (!g_slist_find(out, i->data)) {
out = g_slist_prepend (out, i->data);
if (_action_replace) {
- item_attr_match (SP_ITEM(i->data), text, exact, casematch, _action_replace);
+ item_attr_match(item, text, exact, casematch, _action_replace);
}
}
}
@@ -624,11 +635,14 @@ GSList *Find::filter_fields (GSList *l, bool exact, bool casematch)
if (attrvalue) {
for (GSList *i = in; i != NULL; i = i->next) {
- if (item_attrvalue_match (SP_ITEM(i->data), text, exact, casematch)) {
+ SPObject *obj = reinterpret_cast<SPObject *>(i->data);
+ SPItem *item = dynamic_cast<SPItem *>(obj);
+ g_assert(item != NULL);
+ if (item_attrvalue_match(item, text, exact, casematch)) {
if (!g_slist_find(out, i->data)) {
out = g_slist_prepend (out, i->data);
if (_action_replace) {
- item_attrvalue_match (SP_ITEM(i->data), text, exact, casematch, _action_replace);
+ item_attrvalue_match(item, text, exact, casematch, _action_replace);
}
}
}
@@ -638,11 +652,14 @@ GSList *Find::filter_fields (GSList *l, bool exact, bool casematch)
if (font) {
for (GSList *i = in; i != NULL; i = i->next) {
- if (item_font_match (SP_ITEM(i->data), text, exact, casematch)) {
+ SPObject *obj = reinterpret_cast<SPObject *>(i->data);
+ SPItem *item = dynamic_cast<SPItem *>(obj);
+ g_assert(item != NULL);
+ if (item_font_match(item, text, exact, casematch)) {
if (!g_slist_find(out, i->data)) {
out = g_slist_prepend (out, i->data);
if (_action_replace) {
- item_font_match (SP_ITEM(i->data), text, exact, casematch, _action_replace);
+ item_font_match(item, text, exact, casematch, _action_replace);
}
}
}
@@ -661,34 +678,34 @@ bool Find::item_type_match (SPItem *item)
{
bool all =check_alltypes.get_active();
- if ( SP_IS_RECT(item)) {
+ if ( dynamic_cast<SPRect *>(item)) {
return ( all ||check_rects.get_active());
- } else if (SP_IS_GENERICELLIPSE(item)) {
+ } else if (dynamic_cast<SPGenericEllipse *>(item)) {
return ( all || check_ellipses.get_active());
- } else if (SP_IS_STAR(item) || SP_IS_POLYGON(item)) {
+ } else if (dynamic_cast<SPStar *>(item) || dynamic_cast<SPPolygon *>(item)) {
return ( all || check_stars.get_active());
- } else if (SP_IS_SPIRAL(item)) {
+ } else if (dynamic_cast<SPSpiral *>(item)) {
return ( all || check_spirals.get_active());
- } else if (SP_IS_PATH(item) || SP_IS_LINE(item) || SP_IS_POLYLINE(item)) {
+ } else if (dynamic_cast<SPPath *>(item) || dynamic_cast<SPLine *>(item) || dynamic_cast<SPPolyLine *>(item)) {
return (all || check_paths.get_active());
- } else if (SP_IS_TEXT(item) || SP_IS_TSPAN(item) || SP_IS_TREF(item) || SP_IS_STRING(item)) {
+ } else if (dynamic_cast<SPText *>(item) || dynamic_cast<SPTSpan *>(item) || dynamic_cast<SPTRef *>(item) || dynamic_cast<SPString *>(item)) {
return (all || check_texts.get_active());
- } else if (SP_IS_GROUP(item) && !desktop->isLayer(item) ) { // never select layers!
+ } else if (dynamic_cast<SPGroup *>(item) && !desktop->isLayer(item) ) { // never select layers!
return (all || check_groups.get_active());
- } else if (SP_IS_USE(item)) {
+ } else if (dynamic_cast<SPUse *>(item)) {
return (all || check_clones.get_active());
- } else if (SP_IS_IMAGE(item)) {
+ } else if (dynamic_cast<SPImage *>(item)) {
return (all || check_images.get_active());
- } else if (SP_IS_OFFSET(item)) {
+ } else if (dynamic_cast<SPOffset *>(item)) {
return (all || check_offsets.get_active());
}
@@ -699,7 +716,10 @@ GSList *Find::filter_types (GSList *l)
{
GSList *n = NULL;
for (GSList *i = l; i != NULL; i = i->next) {
- if (item_type_match (SP_ITEM(i->data))) {
+ SPObject *obj = reinterpret_cast<SPObject *>(i->data);
+ SPItem *item = dynamic_cast<SPItem *>(obj);
+ g_assert(item != NULL);
+ if (item_type_match(item)) {
n = g_slist_prepend (n, i->data);
}
}
@@ -716,7 +736,7 @@ GSList *Find::filter_list (GSList *l, bool exact, bool casematch)
GSList *Find::all_items (SPObject *r, GSList *l, bool hidden, bool locked)
{
- if (SP_IS_DEFS(r)) {
+ if (dynamic_cast<SPDefs *>(r)) {
return l; // we're not interested in items in defs
}
@@ -725,8 +745,8 @@ GSList *Find::all_items (SPObject *r, GSList *l, bool hidden, bool locked)
}
for (SPObject *child = r->firstChild(); child; child = child->getNext()) {
- if (SP_IS_ITEM(child) && !child->cloned && !desktop->isLayer(SP_ITEM(child))) {
- SPItem *item = reinterpret_cast<SPItem *>(child);
+ SPItem *item = dynamic_cast<SPItem *>(child);
+ if (item && !child->cloned && !desktop->isLayer(item)) {
if ((hidden || !desktop->itemIsHidden(item)) && (locked || !item->isLocked())) {
l = g_slist_prepend (l, child);
}
@@ -739,16 +759,18 @@ GSList *Find::all_items (SPObject *r, GSList *l, bool hidden, bool locked)
GSList *Find::all_selection_items (Inkscape::Selection *s, GSList *l, SPObject *ancestor, bool hidden, bool locked)
{
for (GSList *i = (GSList *) s->itemList(); i != NULL; i = i->next) {
- if (SP_IS_ITEM (i->data) && !reinterpret_cast<SPItem *>(i->data)->cloned && !desktop->isLayer(SP_ITEM(i->data))) {
- SPItem *item = reinterpret_cast<SPItem *>(i->data);
+ SPObject *obj = reinterpret_cast<SPObject *>(i->data);
+ SPItem *item = dynamic_cast<SPItem *>(obj);
+ g_assert(item != NULL);
+ if (item && !item->cloned && !desktop->isLayer(item)) {
if (!ancestor || ancestor->isAncestorOf(item)) {
if ((hidden || !desktop->itemIsHidden(item)) && (locked || !item->isLocked())) {
l = g_slist_prepend (l, i->data);
}
}
}
- if (!ancestor || ancestor->isAncestorOf(SP_OBJECT (i->data))) {
- l = all_items (SP_OBJECT (i->data), l, hidden, locked);
+ if (!ancestor || ancestor->isAncestorOf(item)) {
+ l = all_items(item, l, hidden, locked);
}
}
return l;
@@ -831,7 +853,10 @@ void Find::onAction()
Inkscape::Selection *selection = sp_desktop_selection (desktop);
selection->clear();
selection->setList(n);
- scroll_to_show_item (desktop, SP_ITEM(n->data));
+ SPObject *obj = reinterpret_cast<SPObject *>(n->data);
+ SPItem *item = dynamic_cast<SPItem *>(obj);
+ g_assert(item != NULL);
+ scroll_to_show_item(desktop, item);
if (_action_replace) {
DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Replace text or property"));
diff --git a/src/ui/dialog/floating-behavior.cpp b/src/ui/dialog/floating-behavior.cpp
index dd07f009a..11db14801 100644
--- a/src/ui/dialog/floating-behavior.cpp
+++ b/src/ui/dialog/floating-behavior.cpp
@@ -28,8 +28,8 @@
#include "inkscape.h"
#include "desktop.h"
-#include "dialogs/dialog-events.h"
-#include "interface.h"
+#include "ui/dialog-events.h"
+#include "ui/interface.h"
#include "preferences.h"
#include "verbs.h"
diff --git a/src/ui/dialog/font-substitution.cpp b/src/ui/dialog/font-substitution.cpp
index bf9133086..db7bdf222 100644
--- a/src/ui/dialog/font-substitution.cpp
+++ b/src/ui/dialog/font-substitution.cpp
@@ -27,7 +27,7 @@
#include "document.h"
#include "selection.h"
-#include "dialogs/dialog-events.h"
+#include "ui/dialog-events.h"
#include "desktop-handles.h"
#include "selection-chemistry.h"
#include "preferences.h"
@@ -200,16 +200,16 @@ GSList * FontSubstitution::getFontReplacedItems(SPDocument* doc, Glib::ustring *
}
}
- if (style && style->text) {
+ if (style) {
gchar const *style_font = NULL;
- if (style->text->font_family.set)
- style_font = style->text->font_family.value;
- else if (style->text->font_specification.set)
- style_font = style->text->font_specification.value;
- else if (style->text->font_family.value)
- style_font = style->text->font_family.value;
- else if (style->text->font_specification.value)
- style_font = style->text->font_specification.value;
+ if (style->font_family.set)
+ style_font = style->font_family.value;
+ else if (style->font_specification.set)
+ style_font = style->font_specification.value;
+ else if (style->font_family.value)
+ style_font = style->font_family.value;
+ else if (style->font_specification.value)
+ style_font = style->font_specification.value;
if (style_font) {
if (has_visible_text(item)) {
diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp
index 8c0a4dc66..1417b39fa 100644
--- a/src/ui/dialog/grid-arrange-tab.cpp
+++ b/src/ui/dialog/grid-arrange-tab.cpp
@@ -572,7 +572,7 @@ void GridArrangeTab::updateSelection()
## Experimental
##########################*/
-static void updateSelectionCallback(Inkscape::Application */*inkscape*/, Inkscape::Selection */*selection*/, GridArrangeTab *dlg)
+static void updateSelectionCallback(InkscapeApplication */*inkscape*/, Inkscape::Selection */*selection*/, GridArrangeTab *dlg)
{
dlg->updateSelection();
}
@@ -708,7 +708,7 @@ GridArrangeTab::GridArrangeTab(ArrangeDialog *parent)
HorizAlign = prefs->getInt("/dialogs/gridtiler/HorizAlign", 1);
// Anchor selection widget
- AlignLabel.set_label("Alignment:");
+ AlignLabel.set_label(_("Alignment:"));
AlignLabel.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
AlignmentSelector.setAlignment(HorizAlign, VertAlign);
AlignmentSelector.on_selectionChanged().connect(sigc::mem_fun(*this, &GridArrangeTab::Align_changed));
diff --git a/src/ui/dialog/grid-arrange-tab.h b/src/ui/dialog/grid-arrange-tab.h
index 9d6700b39..a137d1694 100644
--- a/src/ui/dialog/grid-arrange-tab.h
+++ b/src/ui/dialog/grid-arrange-tab.h
@@ -17,14 +17,16 @@
#ifndef INKSCAPE_UI_DIALOG_GRID_ARRANGE_TAB_H
#define INKSCAPE_UI_DIALOG_GRID_ARRANGE_TAB_H
-#include <gtkmm.h>
-
+#include "ui/widget/scalar-unit.h"
#include "ui/dialog/arrange-tab.h"
#include "ui/widget/anchor-selector.h"
-#include "ui/widget/scalar-unit.h"
#include "ui/widget/spinbutton.h"
+#include <gtkmm/checkbutton.h>
+#include <gtkmm/radiobutton.h>
+#include <gtkmm/radiobuttongroup.h>
+
namespace Inkscape {
namespace UI {
namespace Dialog {
diff --git a/src/ui/dialog/guides.cpp b/src/ui/dialog/guides.cpp
index 80740113c..4519a905f 100644
--- a/src/ui/dialog/guides.cpp
+++ b/src/ui/dialog/guides.cpp
@@ -28,7 +28,7 @@
#include "ui/tools/tool-base.h"
#include "widgets/desktop-widget.h"
#include <glibmm/i18n.h>
-#include "dialogs/dialog-events.h"
+#include "ui/dialog-events.h"
#include "message-context.h"
#include "xml/repr.h"
#include "verbs.h"
@@ -100,7 +100,7 @@ void GuidelinePropertiesDialog::_onOK()
double rad_angle = Geom::deg_to_rad( deg_angle );
normal = Geom::rot90(Geom::Point::polar(rad_angle, 1.0));
}
- sp_guide_set_normal(*_guide, normal, true);
+ _guide->set_normal(normal, true);
double const points_x = _spin_button_x.getValue("px");
double const points_y = _spin_button_y.getValue("px");
@@ -108,11 +108,11 @@ void GuidelinePropertiesDialog::_onOK()
if (!_mode)
newpos += _oldpos;
- sp_guide_moveto(*_guide, newpos, true);
+ _guide->moveto(newpos, true);
const gchar* name = g_strdup( _label_entry.getEntry()->get_text().c_str() );
- sp_guide_set_label(*_guide, name, true);
+ _guide->set_label(name, true);
g_free((gpointer) name);
#if WITH_GTKMM_3_0
@@ -124,7 +124,7 @@ void GuidelinePropertiesDialog::_onOK()
#endif
//TODO: why 257? verify this!
- sp_guide_set_color(*_guide, r, g, b, true);
+ _guide->set_color(r, g, b, true);
DocumentUndo::done(_guide->document, SP_VERB_NONE,
_("Set guide properties"));
@@ -295,16 +295,17 @@ void GuidelinePropertiesDialog::_setup() {
signal_response().connect(sigc::mem_fun(*this, &GuidelinePropertiesDialog::_response));
// initialize dialog
- _oldpos = _guide->point_on_line;
+ _oldpos = _guide->getPoint();
if (_guide->isVertical()) {
_oldangle = 90;
} else if (_guide->isHorizontal()) {
_oldangle = 0;
} else {
- _oldangle = Geom::rad_to_deg( std::atan2( - _guide->normal_to_line[Geom::X], _guide->normal_to_line[Geom::Y] ) );
+ _oldangle = Geom::rad_to_deg( std::atan2( - _guide->getNormal()[Geom::X], _guide->getNormal()[Geom::Y] ) );
}
{
+ // FIXME holy crap!!!
Inkscape::XML::Node *repr = _guide->getRepr();
const gchar *guide_id = repr->attribute("id");
gchar *label = g_strdup_printf(_("Guideline ID: %s"), guide_id);
@@ -312,7 +313,7 @@ void GuidelinePropertiesDialog::_setup() {
g_free(label);
}
{
- gchar *guide_description = sp_guide_description(_guide, false);
+ gchar *guide_description = _guide->description(false);
gchar *label = g_strdup_printf(_("Current: %s"), guide_description);
g_free(guide_description);
_label_descr.set_markup(label);
@@ -320,15 +321,15 @@ void GuidelinePropertiesDialog::_setup() {
}
// init name entry
- _label_entry.getEntry()->set_text(_guide->label ? _guide->label : "");
+ _label_entry.getEntry()->set_text(_guide->getLabel() ? _guide->getLabel() : "");
#if WITH_GTKMM_3_0
Gdk::RGBA c;
- c.set_rgba(((_guide->color>>24)&0xff) / 255.0, ((_guide->color>>16)&0xff) / 255.0, ((_guide->color>>8)&0xff) / 255.0);
+ c.set_rgba(((_guide->getColor()>>24)&0xff) / 255.0, ((_guide->getColor()>>16)&0xff) / 255.0, ((_guide->getColor()>>8)&0xff) / 255.0);
_color.set_rgba(c);
#else
Gdk::Color c;
- c.set_rgb_p(((_guide->color>>24)&0xff) / 255.0, ((_guide->color>>16)&0xff) / 255.0, ((_guide->color>>8)&0xff) / 255.0);
+ c.set_rgb_p(((_guide->getColor()>>24)&0xff) / 255.0, ((_guide->getColor()>>16)&0xff) / 255.0, ((_guide->getColor()>>8)&0xff) / 255.0);
_color.set_color(c);
#endif
diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp
index d826ece09..75cfe5bfe 100644
--- a/src/ui/dialog/inkscape-preferences.cpp
+++ b/src/ui/dialog/inkscape-preferences.cpp
@@ -19,6 +19,7 @@
#include "inkscape-preferences.h"
#include <glibmm/i18n.h>
+#include <glibmm/markup.h>
#include <glibmm/miscutils.h>
#include <gtkmm/main.h>
#include <gtkmm/frame.h>
@@ -76,7 +77,8 @@ InkscapePreferences::InkscapePreferences()
: UI::Widget::Panel ("", "/dialogs/preferences", SP_VERB_DIALOG_DISPLAY),
_max_dialog_width(0),
_max_dialog_height(0),
- _current_page(0)
+ _current_page(0),
+ _init(true)
{
//get the width of a spinbutton
Inkscape::UI::Widget::SpinButton* sb = new Inkscape::UI::Widget::SpinButton;
@@ -232,6 +234,9 @@ static void StyleFromSelectionToTool(Glib::ustring const &prefs_path, StyleSwatc
if (!css) return;
+ // remove black-listed properties
+ css = sp_css_attr_unset_blacklist (css);
+
// only store text style for the text tool
if (prefs_path != "/tools/text") {
css = sp_css_attr_unset_text (css);
@@ -329,7 +334,7 @@ void InkscapePreferences::initPageTools()
_page_selector.add_line( true, "", _t_sel_trans_outl, "",
_("Show only a box outline of the objects when moving or transforming"));
_page_selector.add_group_header( _("Per-object selection cue"));
- _t_sel_cue_none.init ( _("None"), "/options/selcue/value", Inkscape::SelCue::NONE, false, 0);
+ _t_sel_cue_none.init ( C_("Selection cue", "None"), "/options/selcue/value", Inkscape::SelCue::NONE, false, 0);
_page_selector.add_line( true, "", _t_sel_cue_none, "",
_("No per-object selection indication"));
_t_sel_cue_mark.init ( _("Mark"), "/options/selcue/value", Inkscape::SelCue::MARK, true, &_t_sel_cue_none);
@@ -500,10 +505,12 @@ void InkscapePreferences::initPageTools()
_page_connector.add_line(false, "", _connector_ignore_text, "",
_("If on, connector attachment points will not be shown for text objects"));
+#ifdef WITH_LPETOOL
//LPETool
- // commented out, because the LPETool is not finished yet.
- //this->AddPage(_page_lpetool, _("LPE Tool"), iter_tools, PREFS_PAGE_TOOLS_LPETOOL);
- //this->AddNewObjectsStyle(_page_lpetool, "/tools/lpetool");
+ //disabled, because the LPETool is not finished yet.
+ this->AddPage(_page_lpetool, _("LPE Tool"), iter_tools, PREFS_PAGE_TOOLS_LPETOOL);
+ this->AddNewObjectsStyle(_page_lpetool, "/tools/lpetool");
+#endif // WITH_LPETOOL
}
void InkscapePreferences::initPageUI()
@@ -522,11 +529,11 @@ void InkscapePreferences::initPageUI()
_("Mongolian (mn)"), _("Nepali (ne)"), _("Norwegian Bokmål (nb)"), _("Norwegian Nynorsk (nn)"), _("Panjabi (pa)"),
_("Polish (pl)"), _("Portuguese (pt)"), _("Portuguese/Brazil (pt_BR)"), _("Romanian (ro)"), _("Russian (ru)"),
_("Serbian (sr)"), _("Serbian in Latin script (sr@latin)"), _("Slovak (sk)"), _("Slovenian (sl)"), _("Spanish (es)"), _("Spanish/Mexico (es_MX)"),
- _("Swedish (sv)"),_("Telugu (te_IN)"), _("Thai (th)"), _("Turkish (tr)"), _("Ukrainian (uk)"), _("Vietnamese (vi)")};
+ _("Swedish (sv)"),_("Telugu (te)"), _("Thai (th)"), _("Turkish (tr)"), _("Ukrainian (uk)"), _("Vietnamese (vi)")};
Glib::ustring langValues[] = {"", "sq", "am", "ar", "hy", "az", "eu", "be", "bg", "bn", "bn_BD", "br", "ca", "ca@valencia", "zh_CN", "zh_TW", "hr", "cs", "da", "nl",
"dz", "de", "el", "en", "en_AU", "en_CA", "en_GB", "en_US@piglatin", "eo", "et", "fa", "fi", "fr", "ga",
"gl", "he", "hu", "id", "it", "ja", "km", "rw", "ko", "lt", "lv", "mk", "mn", "ne", "nb", "nn", "pa",
- "pl", "pt", "pt_BR", "ro", "ru", "sr", "sr@latin", "sk", "sl", "es", "es_MX", "sv", "te_IN", "th", "tr", "uk", "vi" };
+ "pl", "pt", "pt_BR", "ro", "ru", "sr", "sr@latin", "sk", "sl", "es", "es_MX", "sv", "te", "th", "tr", "uk", "vi" };
{
// sorting languages according to translated name
@@ -638,7 +645,7 @@ void InkscapePreferences::initPageUI()
_win_save_viewport.init ( _("Save and restore documents viewport"), "/options/savedocviewport/value", true);
_win_zoom_resize.init ( _("Zoom when window is resized"), "/options/stickyzoom/value", false);
_win_show_close.init ( _("Show close button on dialogs"), "/dialogs/showclose", false);
- _win_ontop_none.init ( _("None"), "/options/transientpolicy/value", 0, false, 0);
+ _win_ontop_none.init ( C_("Dialog on top", "None"), "/options/transientpolicy/value", 0, false, 0);
_win_ontop_normal.init ( _("Normal"), "/options/transientpolicy/value", 1, true, &_win_ontop_none);
_win_ontop_agressive.init ( _("Aggressive"), "/options/transientpolicy/value", 2, false, &_win_ontop_none);
@@ -834,7 +841,7 @@ void InkscapePreferences::initPageIO()
_save_use_current_dir.init( _("Use current directory for \"Save As ...\""), "/dialogs/save_as/use_current_dir", true);
_page_io.add_line( false, "", _save_use_current_dir, "",
- _("When this option is on, the \"Save as...\" and \"Save a Copy\" dialogs will always open in the directory where the currently open document is; when it's off, each will open in the directory where you last saved a file using it"), true);
+ _("When this option is on, the \"Save as...\" and \"Save a Copy...\" dialogs will always open in the directory where the currently open document is; when it's off, each will open in the directory where you last saved a file using it"), true);
_misc_comment.init( _("Add label comments to printing output"), "/printing/debug/show-label-comments", false);
_page_io.add_line( false, "", _misc_comment, "",
@@ -1256,7 +1263,7 @@ void InkscapePreferences::initPageBehavior()
_page_steps.add_line( false, "", _steps_compass, "",
_("When on, angles are displayed with 0 at north, 0 to 360 range, positive clockwise; otherwise with 0 at east, -180 to 180 range, positive counterclockwise"));
int const num_items = 17;
- Glib::ustring labels[num_items] = {"90", "60", "45", "36", "30", "22.5", "18", "15", "12", "10", "7.5", "6", "3", "2", "1", "0.5", _("None")};
+ Glib::ustring labels[num_items] = {"90", "60", "45", "36", "30", "22.5", "18", "15", "12", "10", "7.5", "6", "3", "2", "1", "0.5", C_("Rotation angle", "None")};
int values[num_items] = {2, 3, 4, 5, 6, 8, 10, 12, 15, 18, 24, 30, 60, 90, 180, 360, 0};
_steps_rot_snap.set_size_request(_sb_width);
_steps_rot_snap.init("/options/rotationsnapsperpi/value", labels, values, num_items, 12);
@@ -1463,6 +1470,11 @@ void InkscapePreferences::initPageBitmaps()
_page_bitmaps.add_line( false, "", _importexport_import_res_override, "",
_("Use default bitmap resolution in favor of information from file"));
+ _page_bitmaps.add_group_header( _("Render"));
+ // rendering outlines for pixmap image tags
+ _rendering_image_outline.init( _("Images in Outline Mode"), "/options/rendering/imageinoutlinemode", false);
+ _page_bitmaps.add_line(false, "", _rendering_image_outline, "", _("When active will render images while in outline mode instead of a red box with an x. This is useful for manual tracing."));
+
this->AddPage(_page_bitmaps, _("Bitmaps"), PREFS_PAGE_BITMAPS);
}
@@ -1827,7 +1839,7 @@ void InkscapePreferences::initPageSpellcheck()
AspellDictInfoEnumeration *dels = aspell_dict_info_list_elements(dlist);
- languages.push_back(Glib::ustring(_("None")));
+ languages.push_back(Glib::ustring(C_("Spellchecker language", "None")));
langValues.push_back(Glib::ustring(""));
const AspellDictInfo *entry;
@@ -1993,6 +2005,7 @@ bool InkscapePreferences::PresentPage(const Gtk::TreeModel::iterator& iter)
Gtk::TreeModel::Row row = *iter;
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
int desired_page = prefs->getInt("/dialogs/preferences/page", 0);
+ _init = false;
if (desired_page == row[_page_list_columns._col_id])
{
if (desired_page >= PREFS_PAGE_TOOLS && desired_page <= PREFS_PAGE_TOOLS_CONNECTOR)
@@ -2042,8 +2055,11 @@ void InkscapePreferences::on_pagelist_selection_changed()
Gtk::TreeModel::Row row = *iter;
_current_page = row[_page_list_columns._col_page];
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- prefs->setInt("/dialogs/preferences/page", row[_page_list_columns._col_id]);
- _page_title.set_markup("<span size='large'><b>" + row[_page_list_columns._col_name] + "</b></span>");
+ if (!_init) {
+ prefs->setInt("/dialogs/preferences/page", row[_page_list_columns._col_id]);
+ }
+ Glib::ustring col_name_escaped = Glib::Markup::escape_text( row[_page_list_columns._col_name] );
+ _page_title.set_markup("<span size='large'><b>" + col_name_escaped + "</b></span>");
_page_frame.add(*_current_page);
_current_page->show();
while (Gtk::Main::events_pending())
diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h
index da85b805d..dcea91741 100644
--- a/src/ui/dialog/inkscape-preferences.h
+++ b/src/ui/dialog/inkscape-preferences.h
@@ -292,6 +292,7 @@ protected:
UI::Widget::PrefCheckButton _show_filters_info_box;
UI::Widget::PrefCombo _dockbar_style;
UI::Widget::PrefCombo _switcher_style;
+ UI::Widget::PrefCheckButton _rendering_image_outline;
UI::Widget::PrefSpinButton _rendering_cache_size;
UI::Widget::PrefSpinButton _filter_multi_threaded;
@@ -531,6 +532,7 @@ private:
InkscapePreferences();
InkscapePreferences(InkscapePreferences const &d);
InkscapePreferences operator=(InkscapePreferences const &d);
+ bool _init;
};
} // namespace Dialog
@@ -543,9 +545,9 @@ private:
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/dialog/input.cpp b/src/ui/dialog/input.cpp
index 4be6716a5..8343cd6fe 100644
--- a/src/ui/dialog/input.cpp
+++ b/src/ui/dialog/input.cpp
@@ -1622,7 +1622,7 @@ void InputDialogImpl::ConfPanel::setAxis(gint count)
if (barNum < count) {
row[axisColumns.value] = Glib::ustring::format(barNum+1);
} else {
- row[axisColumns.value] = _("None");
+ row[axisColumns.value] = C_("Input device axe", "None");
}
}
diff --git a/src/ui/dialog/layers.cpp b/src/ui/dialog/layers.cpp
index b5dac0595..65351cb68 100644
--- a/src/ui/dialog/layers.cpp
+++ b/src/ui/dialog/layers.cpp
@@ -926,9 +926,8 @@ LayersPanel::LayersPanel() :
// -------------------------------------------------------
{
- _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RENAME, 0, "Rename", (int)BUTTON_RENAME ) );
- _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_DUPLICATE, 0, "Duplicate", (int)BUTTON_DUPLICATE ) );
_watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_NEW, 0, "New", (int)BUTTON_NEW ) );
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RENAME, 0, "Rename", (int)BUTTON_RENAME ) );
_popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem()));
@@ -944,9 +943,14 @@ LayersPanel::LayersPanel() :
_popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem()));
- _watchingNonTop.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RAISE, INKSCAPE_ICON("go-up"), "Up", (int)BUTTON_UP ) );
- _watchingNonBottom.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOWER, INKSCAPE_ICON("go-down"), "Down", (int)BUTTON_DOWN ) );
+ _watchingNonTop.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RAISE, INKSCAPE_ICON("layer-raise"), "Up", (int)BUTTON_UP ) );
+ _watchingNonBottom.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOWER, INKSCAPE_ICON("layer-lower"), "Down", (int)BUTTON_DOWN ) );
+ _popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem()));
+
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_DUPLICATE, 0, "Duplicate", (int)BUTTON_DUPLICATE ) );
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_DELETE, 0, "Delete", (int)BUTTON_DELETE ) );
+
_popupMenu.show_all_children();
}
// -------------------------------------------------------
diff --git a/src/ui/dialog/livepatheffect-add.cpp b/src/ui/dialog/livepatheffect-add.cpp
index b5f51d81d..c558eddaf 100644
--- a/src/ui/dialog/livepatheffect-add.cpp
+++ b/src/ui/dialog/livepatheffect-add.cpp
@@ -38,6 +38,7 @@ LivePathEffectAdd::LivePathEffectAdd() :
scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
scrolled_window.set_shadow_type(Gtk::SHADOW_IN);
scrolled_window.set_size_request(250, 200);
+ scrolled_window.set_can_focus();
/**
* Effect Store and Tree
@@ -83,10 +84,12 @@ LivePathEffectAdd::LivePathEffectAdd() :
add_action_widget(close_button, Gtk::RESPONSE_CLOSE);
add_action_widget(add_button, Gtk::RESPONSE_APPLY);
+
/**
* Signal handlers
*/
effectlist_treeview.signal_button_press_event().connect_notify( sigc::mem_fun(*this, &LivePathEffectAdd::onButtonEvent) );
+ effectlist_treeview.signal_key_press_event().connect_notify(sigc::mem_fun(*this, &LivePathEffectAdd::onKeyEvent));
close_button.signal_clicked().connect(sigc::mem_fun(*this, &LivePathEffectAdd::onClose));
add_button.signal_clicked().connect(sigc::mem_fun(*this, &LivePathEffectAdd::onAdd));
signal_delete_event().connect( sigc::bind_return(sigc::hide(sigc::mem_fun(*this, &LivePathEffectAdd::onClose)), true ) );
@@ -107,6 +110,16 @@ void LivePathEffectAdd::onClose()
hide();
}
+void LivePathEffectAdd::onKeyEvent(GdkEventKey* evt)
+{
+ if (evt->keyval == GDK_KEY_Return) {
+ onAdd();
+ }
+ if (evt->keyval == GDK_KEY_Escape) {
+ onClose();
+ }
+}
+
void LivePathEffectAdd::onButtonEvent(GdkEventButton* evt)
{
// Double click on tree is same as clicking the add button
@@ -135,6 +148,7 @@ void LivePathEffectAdd::show(SPDesktop *desktop)
dial.set_modal(true);
desktop->setWindowTransient (dial.gobj());
dial.property_destroy_with_parent() = true;
+ dial.effectlist_treeview.grab_focus();
dial.run();
}
diff --git a/src/ui/dialog/livepatheffect-add.h b/src/ui/dialog/livepatheffect-add.h
index 7fa766272..99ead878c 100644
--- a/src/ui/dialog/livepatheffect-add.h
+++ b/src/ui/dialog/livepatheffect-add.h
@@ -74,6 +74,10 @@ protected:
*/
void onButtonEvent(GdkEventButton* evt);
+ /**
+ * Key event
+ */
+ void onKeyEvent(GdkEventKey* evt);
private:
Gtk::TreeView effectlist_treeview;
diff --git a/src/ui/dialog/livepatheffect-editor.cpp b/src/ui/dialog/livepatheffect-editor.cpp
index 9a569725c..eb3857ee7 100644
--- a/src/ui/dialog/livepatheffect-editor.cpp
+++ b/src/ui/dialog/livepatheffect-editor.cpp
@@ -295,9 +295,8 @@ LivePathEffectEditor::onSelectionChanged(Inkscape::Selection *sel)
if ( sel && !sel->isEmpty() ) {
SPItem *item = sel->singleItem();
if ( item ) {
- if ( SP_IS_LPE_ITEM(item) ) {
- SPLPEItem *lpeitem = SP_LPE_ITEM(item);
-
+ SPLPEItem *lpeitem = dynamic_cast<SPLPEItem *>(item);
+ if ( lpeitem ) {
effect_list_reload(lpeitem);
current_lpeitem = lpeitem;
@@ -318,25 +317,28 @@ LivePathEffectEditor::onSelectionChanged(Inkscape::Selection *sel)
button_up.set_sensitive(false);
button_down.set_sensitive(false);
}
- } else if ( SP_IS_USE(item) ) {
- // test whether linked object is supported by the CLONE_ORIGINAL LPE
- SPItem *orig = SP_USE(item)->get_original();
- if ( SP_IS_SHAPE(orig) ||
- SP_IS_TEXT(orig) )
- {
- // Note that an SP_USE cannot have an LPE applied, so we only need to worry about the "add effect" case.
- set_sensitize_all(true);
- showText(_("Click add button to convert clone"));
- button_remove.set_sensitive(false);
- button_up.set_sensitive(false);
- button_down.set_sensitive(false);
+ } else {
+ SPUse *use = dynamic_cast<SPUse *>(item);
+ if ( use ) {
+ // test whether linked object is supported by the CLONE_ORIGINAL LPE
+ SPItem *orig = use->get_original();
+ if ( dynamic_cast<SPShape *>(orig) ||
+ dynamic_cast<SPText *>(orig) )
+ {
+ // Note that an SP_USE cannot have an LPE applied, so we only need to worry about the "add effect" case.
+ set_sensitize_all(true);
+ showText(_("Click add button to convert clone"));
+ button_remove.set_sensitive(false);
+ button_up.set_sensitive(false);
+ button_down.set_sensitive(false);
+ } else {
+ showText(_("Select a path or shape"));
+ set_sensitize_all(false);
+ }
} else {
showText(_("Select a path or shape"));
set_sensitize_all(false);
}
- } else {
- showText(_("Select a path or shape"));
- set_sensitize_all(false);
}
} else {
showText(_("Only one item can be selected"));
@@ -423,7 +425,7 @@ LivePathEffectEditor::onAdd()
if ( sel && !sel->isEmpty() ) {
SPItem *item = sel->singleItem();
if (item) {
- if ( SP_IS_LPE_ITEM(item) ) {
+ if ( dynamic_cast<SPLPEItem *>(item) ) {
// show effectlist dialog
using Inkscape::UI::Dialog::LivePathEffectAdd;
LivePathEffectAdd::show(current_desktop);
@@ -439,7 +441,7 @@ LivePathEffectEditor::onAdd()
}
// If item is a SPRect, convert it to path first:
- if ( SP_IS_RECT(item) ) {
+ if ( dynamic_cast<SPRect *>(item) ) {
sp_selected_path_to_curves(sel, current_desktop, false);
item = sel->singleItem(); // get new item
}
@@ -451,41 +453,43 @@ LivePathEffectEditor::onAdd()
lpe_list_locked = false;
onSelectionChanged(sel);
- }
- else if ( SP_IS_USE(item) ) {
- // item is a clone. do not show effectlist dialog.
- // convert to path, apply CLONE_ORIGINAL LPE, link it to the cloned path
-
- // test whether linked object is supported by the CLONE_ORIGINAL LPE
- SPItem *orig = SP_USE(item)->get_original();
- if ( SP_IS_SHAPE(orig) ||
- SP_IS_TEXT(orig) )
- {
- // select original
- sel->set(orig);
-
- // delete clone but remember its id and transform
- gchar *id = g_strdup(item->getRepr()->attribute("id"));
- gchar *transform = g_strdup(item->getRepr()->attribute("transform"));
- item->deleteObject(false);
- item = NULL;
-
- // run sp_selection_clone_original_path_lpe
- sp_selection_clone_original_path_lpe(current_desktop);
- SPItem *new_item = sel->singleItem();
- new_item->getRepr()->setAttribute("id", id);
- new_item->getRepr()->setAttribute("transform", transform);
- g_free(id);
- g_free(transform);
-
- /// \todo Add the LPE stack of the original path?
-
- SPDocument *doc = current_desktop->doc();
- DocumentUndo::done(doc, SP_VERB_DIALOG_LIVE_PATH_EFFECT,
- _("Create and apply Clone original path effect"));
-
- lpe_list_locked = false;
- onSelectionChanged(sel);
+ } else {
+ SPUse *use = dynamic_cast<SPUse *>(item);
+ if ( use ) {
+ // item is a clone. do not show effectlist dialog.
+ // convert to path, apply CLONE_ORIGINAL LPE, link it to the cloned path
+
+ // test whether linked object is supported by the CLONE_ORIGINAL LPE
+ SPItem *orig = use->get_original();
+ if ( dynamic_cast<SPShape *>(orig) ||
+ dynamic_cast<SPText *>(orig) )
+ {
+ // select original
+ sel->set(orig);
+
+ // delete clone but remember its id and transform
+ gchar *id = g_strdup(item->getRepr()->attribute("id"));
+ gchar *transform = g_strdup(item->getRepr()->attribute("transform"));
+ item->deleteObject(false);
+ item = NULL;
+
+ // run sp_selection_clone_original_path_lpe
+ sp_selection_clone_original_path_lpe(current_desktop);
+ SPItem *new_item = sel->singleItem();
+ new_item->getRepr()->setAttribute("id", id);
+ new_item->getRepr()->setAttribute("transform", transform);
+ g_free(id);
+ g_free(transform);
+
+ /// \todo Add the LPE stack of the original path?
+
+ SPDocument *doc = current_desktop->doc();
+ DocumentUndo::done(doc, SP_VERB_DIALOG_LIVE_PATH_EFFECT,
+ _("Create and apply Clone original path effect"));
+
+ lpe_list_locked = false;
+ onSelectionChanged(sel);
+ }
}
}
}
@@ -498,13 +502,14 @@ LivePathEffectEditor::onRemove()
Inkscape::Selection *sel = _getSelection();
if ( sel && !sel->isEmpty() ) {
SPItem *item = sel->singleItem();
- if ( item && SP_IS_LPE_ITEM(item) ) {
- SP_LPE_ITEM(item)->removeCurrentPathEffect(false);
+ SPLPEItem *lpeitem = dynamic_cast<SPLPEItem *>(item);
+ if ( lpeitem ) {
+ lpeitem->removeCurrentPathEffect(false);
DocumentUndo::done( sp_desktop_document(current_desktop), SP_VERB_DIALOG_LIVE_PATH_EFFECT,
_("Remove path effect") );
- effect_list_reload(SP_LPE_ITEM(item));
+ effect_list_reload(lpeitem);
}
}
@@ -515,7 +520,8 @@ void LivePathEffectEditor::onUp()
Inkscape::Selection *sel = _getSelection();
if ( sel && !sel->isEmpty() ) {
SPItem *item = sel->singleItem();
- if ( SPLPEItem *lpeitem = SP_LPE_ITEM(item) ) {
+ SPLPEItem *lpeitem = dynamic_cast<SPLPEItem *>(item);
+ if ( lpeitem ) {
lpeitem->upCurrentPathEffect();
DocumentUndo::done( sp_desktop_document(current_desktop), SP_VERB_DIALOG_LIVE_PATH_EFFECT,
@@ -531,7 +537,8 @@ void LivePathEffectEditor::onDown()
Inkscape::Selection *sel = _getSelection();
if ( sel && !sel->isEmpty() ) {
SPItem *item = sel->singleItem();
- if ( SPLPEItem *lpeitem = SP_LPE_ITEM(item) ) {
+ SPLPEItem *lpeitem = dynamic_cast<SPLPEItem *>(item);
+ if ( lpeitem ) {
lpeitem->downCurrentPathEffect();
DocumentUndo::done( sp_desktop_document(current_desktop), SP_VERB_DIALOG_LIVE_PATH_EFFECT,
diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp
new file mode 100644
index 000000000..55a19fc51
--- /dev/null
+++ b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp
@@ -0,0 +1,301 @@
+/**
+ * From the code of Liam P.White from his Power Stroke Knot dialog
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if GLIBMM_DISABLE_DEPRECATED &&HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
+#include <gtkmm.h>
+#include "lpe-fillet-chamfer-properties.h"
+#include <boost/lexical_cast.hpp>
+#include <glibmm/main.h>
+#include <glibmm/i18n.h>
+#include "inkscape.h"
+#include "desktop.h"
+#include "document.h"
+#include "document-undo.h"
+#include "layer-manager.h"
+#include "message-stack.h"
+#include "desktop-handles.h"
+#include "sp-object.h"
+#include "sp-item.h"
+#include "verbs.h"
+#include "selection.h"
+#include "selection-chemistry.h"
+#include "ui/icon-names.h"
+#include "ui/widget/imagetoggler.h"
+#include "util/units.h"
+#include <cmath>
+
+//#include "event-context.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Dialogs {
+
+FilletChamferPropertiesDialog::FilletChamferPropertiesDialog()
+ : _desktop(NULL), _knotpoint(NULL), _position_visible(false)
+{
+ Gtk::Box *mainVBox = get_vbox();
+ mainVBox->set_homogeneous(false);
+ _layout_table.set_spacings(4);
+ _layout_table.resize(3, 3);
+
+ // Layer name widgets
+ _fillet_chamfer_position_numeric.set_digits(4);
+ _fillet_chamfer_position_numeric.set_increments(1,1);
+ //todo: get tha max aloable infinity freeze the widget
+ _fillet_chamfer_position_numeric.set_range(0., 999999999999999999.);
+
+ _fillet_chamfer_position_label.set_label(_("Radius (pixels):"));
+ _fillet_chamfer_position_label.set_alignment(1.0, 0.5);
+
+ _layout_table.attach(_fillet_chamfer_position_label, 0, 1, 0, 1, Gtk::FILL,
+ Gtk::FILL);
+ _layout_table.attach(_fillet_chamfer_position_numeric, 1, 2, 0, 1,
+ Gtk::FILL | Gtk::EXPAND, Gtk::FILL);
+ _fillet_chamfer_chamfer_subdivisions.set_digits(0);
+ _fillet_chamfer_chamfer_subdivisions.set_increments(1,1);
+ //todo: get tha max aloable infinity freeze the widget
+ _fillet_chamfer_chamfer_subdivisions.set_range(0, 999999999999999999.0);
+
+ _fillet_chamfer_chamfer_subdivisions_label.set_label(_("Chamfer subdivisions:"));
+ _fillet_chamfer_chamfer_subdivisions_label.set_alignment(1.0, 0.5);
+
+ _layout_table.attach(_fillet_chamfer_chamfer_subdivisions_label, 0, 1, 1, 2, Gtk::FILL,
+ Gtk::FILL);
+ _layout_table.attach(_fillet_chamfer_chamfer_subdivisions, 1, 2, 1, 2,
+ Gtk::FILL | Gtk::EXPAND, Gtk::FILL);
+ _fillet_chamfer_type_fillet.set_label(_("Fillet"));
+ _fillet_chamfer_type_fillet.set_group(_fillet_chamfer_type_group);
+ _fillet_chamfer_type_inverse_fillet.set_label(_("Inverse fillet"));
+ _fillet_chamfer_type_inverse_fillet.set_group(_fillet_chamfer_type_group);
+ _fillet_chamfer_type_chamfer.set_label(_("Chamfer"));
+ _fillet_chamfer_type_chamfer.set_group(_fillet_chamfer_type_group);
+ _fillet_chamfer_type_inverse_chamfer.set_label(_("Inverse chamfer"));
+ _fillet_chamfer_type_inverse_chamfer.set_group(_fillet_chamfer_type_group);
+
+
+ mainVBox->pack_start(_layout_table, true, true, 4);
+ mainVBox->pack_start(_fillet_chamfer_type_fillet, true, true, 4);
+ mainVBox->pack_start(_fillet_chamfer_type_inverse_fillet, true, true, 4);
+ mainVBox->pack_start(_fillet_chamfer_type_chamfer, true, true, 4);
+ mainVBox->pack_start(_fillet_chamfer_type_inverse_chamfer, true, true, 4);
+
+ // Buttons
+ _close_button.set_use_stock(true);
+ _close_button.set_label(Gtk::Stock::CANCEL.id);
+ _close_button.set_can_default();
+
+ _apply_button.set_use_underline(true);
+ _apply_button.set_can_default();
+
+ _close_button.signal_clicked()
+ .connect(sigc::mem_fun(*this, &FilletChamferPropertiesDialog::_close));
+ _apply_button.signal_clicked()
+ .connect(sigc::mem_fun(*this, &FilletChamferPropertiesDialog::_apply));
+
+ signal_delete_event().connect(sigc::bind_return(
+ sigc::hide(sigc::mem_fun(*this, &FilletChamferPropertiesDialog::_close)),
+ true));
+
+ add_action_widget(_close_button, Gtk::RESPONSE_CLOSE);
+ add_action_widget(_apply_button, Gtk::RESPONSE_APPLY);
+
+ _apply_button.grab_default();
+
+ show_all_children();
+
+ set_focus(_fillet_chamfer_position_numeric);
+}
+
+FilletChamferPropertiesDialog::~FilletChamferPropertiesDialog()
+{
+
+ _set_desktop(NULL);
+}
+
+void FilletChamferPropertiesDialog::showDialog(
+ SPDesktop *desktop, Geom::Point knotpoint,
+ const Inkscape::LivePathEffect::
+ FilletChamferPointArrayParamKnotHolderEntity *pt,
+ const gchar *unit,
+ bool use_distance,
+ bool aprox_radius,
+ Glib::ustring const * documentUnit)
+{
+ FilletChamferPropertiesDialog *dialog = new FilletChamferPropertiesDialog();
+
+ dialog->_set_desktop(desktop);
+ dialog->_set_unit(unit);
+ dialog->_set_use_distance(use_distance);
+ dialog->_set_aprox(aprox_radius);
+ dialog->_set_document_unit(documentUnit);
+ dialog->_set_knot_point(knotpoint);
+ dialog->_set_pt(pt);
+
+ dialog->set_title(_("Modify Fillet-Chamfer"));
+ dialog->_apply_button.set_label(_("_Modify"));
+
+ dialog->set_modal(true);
+ desktop->setWindowTransient(dialog->gobj());
+ dialog->property_destroy_with_parent() = true;
+
+ dialog->show();
+ dialog->present();
+}
+
+void FilletChamferPropertiesDialog::_apply()
+{
+ double d_width;
+ double d_pos = _fillet_chamfer_position_numeric.get_value();
+ if (d_pos) {
+ if (_fillet_chamfer_type_fillet.get_active() == true) {
+ d_width = 1;
+ } else if (_fillet_chamfer_type_inverse_fillet.get_active() == true) {
+ d_width = 2;
+ } else if (_fillet_chamfer_type_inverse_chamfer.get_active() == true) {
+ d_width = _fillet_chamfer_chamfer_subdivisions.get_value() + 4000;
+ } else {
+ d_width = _fillet_chamfer_chamfer_subdivisions.get_value() + 3000;
+ }
+ if (_flexible) {
+ if (d_pos > 99.99999 || d_pos < 0) {
+ d_pos = 0;
+ }
+ d_pos = _index + (d_pos / 100);
+ } else {
+ d_pos = Inkscape::Util::Quantity::convert(d_pos, unit, *document_unit);
+ d_pos = d_pos * -1;
+ }
+ _knotpoint->knot_set_offset(Geom::Point(d_pos, d_width));
+ }
+ _close();
+}
+
+void FilletChamferPropertiesDialog::_close()
+{
+ _set_desktop(NULL);
+ destroy_();
+ Glib::signal_idle().connect(
+ sigc::bind_return(
+ sigc::bind(sigc::ptr_fun(&::operator delete), this),
+ false
+ )
+ );
+}
+
+bool FilletChamferPropertiesDialog::_handleKeyEvent(GdkEventKey * /*event*/)
+{
+ return false;
+}
+
+void FilletChamferPropertiesDialog::_handleButtonEvent(GdkEventButton *event)
+{
+ if ((event->type == GDK_2BUTTON_PRESS) && (event->button == 1)) {
+ _apply();
+ }
+}
+
+void FilletChamferPropertiesDialog::_set_knot_point(Geom::Point knotpoint)
+{
+ double position;
+ std::string distance_or_radius = std::string(_("Radius "));
+ if(aprox){
+ distance_or_radius = std::string(_("Radius approximated "));
+ }
+ if(use_distance){
+ distance_or_radius = std::string(_("Knot distance "));
+ }
+ if (knotpoint.x() > 0) {
+ double intpart;
+ position = modf(knotpoint[Geom::X], &intpart) * 100;
+ _flexible = true;
+ _index = intpart;
+ _fillet_chamfer_position_label.set_label(_("Position (%):"));
+ } else {
+ _flexible = false;
+ std::string posConcat = distance_or_radius +
+ std::string(_("(")) + std::string(unit) + std::string(")");
+ _fillet_chamfer_position_label.set_label(_(posConcat.c_str()));
+ position = knotpoint[Geom::X] * -1;
+
+ position = Inkscape::Util::Quantity::convert(position, *document_unit, unit);
+ }
+ _fillet_chamfer_position_numeric.set_value(position);
+ if (knotpoint.y() == 1) {
+ _fillet_chamfer_type_fillet.set_active(true);
+ } else if (knotpoint.y() == 2) {
+ _fillet_chamfer_type_inverse_fillet.set_active(true);
+ } else if (knotpoint.y() >= 3000 && knotpoint.y() < 4000) {
+ _fillet_chamfer_chamfer_subdivisions.set_value(knotpoint.y() - 3000);
+ _fillet_chamfer_type_chamfer.set_active(true);
+ } else if (knotpoint.y() >= 4000 && knotpoint.y() < 5000) {
+ _fillet_chamfer_chamfer_subdivisions.set_value(knotpoint.y() - 4000);
+ _fillet_chamfer_type_inverse_chamfer.set_active(true);
+ }
+}
+
+void FilletChamferPropertiesDialog::_set_pt(
+ const Inkscape::LivePathEffect::
+ FilletChamferPointArrayParamKnotHolderEntity *pt)
+{
+ _knotpoint = const_cast<
+ Inkscape::LivePathEffect::FilletChamferPointArrayParamKnotHolderEntity *>(
+ pt);
+}
+
+void FilletChamferPropertiesDialog::_set_unit(const gchar *abbr)
+{
+ unit = abbr;
+}
+
+void FilletChamferPropertiesDialog::_set_document_unit(Glib::ustring const *abbr)
+{
+ document_unit = abbr;
+}
+
+void FilletChamferPropertiesDialog::_set_use_distance(bool use_knot_distance)
+{
+ use_distance = use_knot_distance;
+}
+
+void FilletChamferPropertiesDialog::_set_aprox(bool aprox_radius)
+{
+ aprox = aprox_radius;
+}
+
+void FilletChamferPropertiesDialog::_set_desktop(SPDesktop *desktop)
+{
+ if (desktop) {
+ Inkscape::GC::anchor(desktop);
+ }
+ if (_desktop) {
+ Inkscape::GC::release(_desktop);
+ }
+ _desktop = desktop;
+}
+
+} // namespace
+} // namespace
+} // namespace
+
+/*
+ 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/lpe-fillet-chamfer-properties.h b/src/ui/dialog/lpe-fillet-chamfer-properties.h
new file mode 100644
index 000000000..3807e98c8
--- /dev/null
+++ b/src/ui/dialog/lpe-fillet-chamfer-properties.h
@@ -0,0 +1,115 @@
+/**
+ *
+ * From the code of Liam P.White from his Power Stroke Knot dialog
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information
+ */
+
+#ifndef INKSCAPE_DIALOG_FILLET_CHAMFER_PROPERTIES_H
+#define INKSCAPE_DIALOG_FILLET_CHAMFER_PROPERTIES_H
+
+#include <2geom/point.h>
+#include <gtkmm.h>
+#include "live_effects/parameter/filletchamferpointarray.h"
+
+class SPDesktop;
+
+namespace Inkscape {
+namespace UI {
+namespace Dialogs {
+
+class FilletChamferPropertiesDialog : public Gtk::Dialog {
+public:
+ FilletChamferPropertiesDialog();
+ virtual ~FilletChamferPropertiesDialog();
+
+ Glib::ustring getName() const {
+ return "LayerPropertiesDialog";
+ }
+
+ static void showDialog(SPDesktop *desktop, Geom::Point knotpoint,
+ const Inkscape::LivePathEffect::
+ FilletChamferPointArrayParamKnotHolderEntity *pt,
+ const gchar *unit,
+ bool use_distance,
+ bool aprox_radius,
+ Glib::ustring const * documentUnit);
+
+protected:
+
+ SPDesktop *_desktop;
+ Inkscape::LivePathEffect::FilletChamferPointArrayParamKnotHolderEntity *
+ _knotpoint;
+
+ Gtk::Label _fillet_chamfer_position_label;
+ Gtk::SpinButton _fillet_chamfer_position_numeric;
+ Gtk::RadioButton::Group _fillet_chamfer_type_group;
+ Gtk::RadioButton _fillet_chamfer_type_fillet;
+ Gtk::RadioButton _fillet_chamfer_type_inverse_fillet;
+ Gtk::RadioButton _fillet_chamfer_type_chamfer;
+ Gtk::RadioButton _fillet_chamfer_type_inverse_chamfer;
+ Gtk::Label _fillet_chamfer_chamfer_subdivisions_label;
+ Gtk::SpinButton _fillet_chamfer_chamfer_subdivisions;
+
+ Gtk::Table _layout_table;
+ bool _position_visible;
+ double _index;
+
+ Gtk::Button _close_button;
+ Gtk::Button _apply_button;
+
+ sigc::connection _destroy_connection;
+
+ static FilletChamferPropertiesDialog &_instance() {
+ static FilletChamferPropertiesDialog instance;
+ return instance;
+ }
+
+ void _set_desktop(SPDesktop *desktop);
+ void _set_pt(const Inkscape::LivePathEffect::
+ FilletChamferPointArrayParamKnotHolderEntity *pt);
+ void _set_unit(const gchar *abbr);
+ void _set_document_unit(Glib::ustring const * abbr);
+ void _set_use_distance(bool use_knot_distance);
+ void _set_aprox(bool aprox_radius);
+ void _apply();
+ void _close();
+ bool _flexible;
+ const gchar *unit;
+ Glib::ustring const * document_unit;
+ bool use_distance;
+ bool aprox;
+ void _set_knot_point(Geom::Point knotpoint);
+ void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row);
+
+ bool _handleKeyEvent(GdkEventKey *event);
+ void _handleButtonEvent(GdkEventButton *event);
+
+ friend class Inkscape::LivePathEffect::
+ FilletChamferPointArrayParamKnotHolderEntity;
+
+private:
+ FilletChamferPropertiesDialog(
+ FilletChamferPropertiesDialog const &); // no copy
+ FilletChamferPropertiesDialog &operator=(
+ FilletChamferPropertiesDialog const &); // no assign
+};
+
+} // namespace
+} // namespace
+} // namespace
+
+#endif //INKSCAPE_DIALOG_LAYER_PROPERTIES_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/lpe-powerstroke-properties.cpp b/src/ui/dialog/lpe-powerstroke-properties.cpp
new file mode 100644
index 000000000..55f938a48
--- /dev/null
+++ b/src/ui/dialog/lpe-powerstroke-properties.cpp
@@ -0,0 +1,211 @@
+/**
+ * @file
+ * Dialog for renaming layers.
+ */
+/* Author:
+ * Bryce W. Harrington <bryce@bryceharrington.com>
+ * Andrius R. <knutux@gmail.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2004 Bryce Harrington
+ * Copyright (C) 2006 Andrius R.
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
+#include "lpe-powerstroke-properties.h"
+#include <boost/lexical_cast.hpp>
+#include <gtkmm/stock.h>
+#include <glibmm/main.h>
+#include <glibmm/i18n.h>
+#include "inkscape.h"
+#include "desktop.h"
+#include "document.h"
+#include "document-undo.h"
+#include "layer-manager.h"
+#include "message-stack.h"
+#include "desktop-handles.h"
+#include "sp-object.h"
+#include "sp-item.h"
+#include "verbs.h"
+#include "selection.h"
+#include "selection-chemistry.h"
+#include "ui/icon-names.h"
+#include "ui/widget/imagetoggler.h"
+//#include "event-context.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Dialogs {
+
+PowerstrokePropertiesDialog::PowerstrokePropertiesDialog()
+: _desktop(NULL), _knotpoint(NULL), _position_visible(false)
+{
+ Gtk::Box *mainVBox = get_vbox();
+
+ _layout_table.set_spacings(4);
+ _layout_table.resize (2, 2);
+
+ // Layer name widgets
+ _powerstroke_position_entry.set_activates_default(true);
+ _powerstroke_position_label.set_label(_("Position:"));
+ _powerstroke_position_label.set_alignment(1.0, 0.5);
+
+ _powerstroke_width_entry.set_activates_default(true);
+ _powerstroke_width_label.set_label(_("Width:"));
+ _powerstroke_width_label.set_alignment(1.0, 0.5);
+
+ _layout_table.attach(_powerstroke_position_label,
+ 0, 1, 0, 1, Gtk::FILL, Gtk::FILL);
+ _layout_table.attach(_powerstroke_position_entry,
+ 1, 2, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::FILL);
+
+ _layout_table.attach(_powerstroke_width_label, 0, 1, 1, 2, Gtk::FILL, Gtk::FILL);
+ _layout_table.attach(_powerstroke_width_entry, 1, 2, 1, 2, Gtk::FILL | Gtk::EXPAND, Gtk::FILL);
+
+ mainVBox->pack_start(_layout_table, true, true, 4);
+
+ // Buttons
+ _close_button.set_use_stock(true);
+ _close_button.set_label(Gtk::Stock::CANCEL.id);
+ _close_button.set_can_default();
+
+ _apply_button.set_use_underline(true);
+ _apply_button.set_can_default();
+
+ _close_button.signal_clicked()
+ .connect(sigc::mem_fun(*this, &PowerstrokePropertiesDialog::_close));
+ _apply_button.signal_clicked()
+ .connect(sigc::mem_fun(*this, &PowerstrokePropertiesDialog::_apply));
+
+ signal_delete_event().connect(
+ sigc::bind_return(
+ sigc::hide(sigc::mem_fun(*this, &PowerstrokePropertiesDialog::_close)),
+ true
+ )
+ );
+
+ add_action_widget(_close_button, Gtk::RESPONSE_CLOSE);
+ add_action_widget(_apply_button, Gtk::RESPONSE_APPLY);
+
+ _apply_button.grab_default();
+
+ show_all_children();
+
+ set_focus(_powerstroke_width_entry);
+}
+
+PowerstrokePropertiesDialog::~PowerstrokePropertiesDialog() {
+
+ _setDesktop(NULL);
+}
+
+void PowerstrokePropertiesDialog::showDialog(SPDesktop *desktop, Geom::Point knotpoint, const Inkscape::LivePathEffect::PowerStrokePointArrayParamKnotHolderEntity *pt)
+{
+ PowerstrokePropertiesDialog *dialog = new PowerstrokePropertiesDialog();
+
+ dialog->_setDesktop(desktop);
+ dialog->_setKnotPoint(knotpoint);
+ dialog->_setPt(pt);
+
+ dialog->set_title(_("Modify Node Position"));
+ dialog->_apply_button.set_label(_("_Move"));
+
+ dialog->set_modal(true);
+ desktop->setWindowTransient (dialog->gobj());
+ dialog->property_destroy_with_parent() = true;
+
+ dialog->show();
+ dialog->present();
+}
+
+void
+PowerstrokePropertiesDialog::_apply()
+{
+ std::istringstream i_pos(_powerstroke_position_entry.get_text());
+ std::istringstream i_width(_powerstroke_width_entry.get_text());
+ double d_pos, d_width;
+ if ((i_pos >> d_pos) && i_width >> d_width) {
+ _knotpoint->knot_set_offset(Geom::Point(d_pos, d_width));
+ }
+ _close();
+}
+
+void
+PowerstrokePropertiesDialog::_close()
+{
+ _setDesktop(NULL);
+ destroy_();
+ Glib::signal_idle().connect(
+ sigc::bind_return(
+ sigc::bind(sigc::ptr_fun(&::operator delete), this),
+ false
+ )
+ );
+}
+
+bool PowerstrokePropertiesDialog::_handleKeyEvent(GdkEventKey * /*event*/)
+{
+
+ /*switch (get_group0_keyval(event)) {
+ case GDK_KEY_Return:
+ case GDK_KEY_KP_Enter: {
+ _apply();
+ return true;
+ }
+ break;
+ }*/
+ return false;
+}
+
+void PowerstrokePropertiesDialog::_handleButtonEvent(GdkEventButton* event)
+{
+ if ( (event->type == GDK_2BUTTON_PRESS) && (event->button == 1) ) {
+ _apply();
+ }
+}
+
+void PowerstrokePropertiesDialog::_setKnotPoint(Geom::Point knotpoint)
+{
+ _powerstroke_position_entry.set_text(boost::lexical_cast<std::string>(knotpoint.x()));
+ _powerstroke_width_entry.set_text(boost::lexical_cast<std::string>(knotpoint.y()));
+}
+
+void PowerstrokePropertiesDialog::_setPt(const Inkscape::LivePathEffect::PowerStrokePointArrayParamKnotHolderEntity *pt)
+{
+ _knotpoint = const_cast<Inkscape::LivePathEffect::PowerStrokePointArrayParamKnotHolderEntity *>(pt);
+}
+
+void PowerstrokePropertiesDialog::_setDesktop(SPDesktop *desktop) {
+ if (desktop) {
+ Inkscape::GC::anchor (desktop);
+ }
+ if (_desktop) {
+ Inkscape::GC::release (_desktop);
+ }
+ _desktop = desktop;
+}
+
+} // namespace
+} // namespace
+} // namespace
+
+
+/*
+ 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/lpe-powerstroke-properties.h b/src/ui/dialog/lpe-powerstroke-properties.h
new file mode 100644
index 000000000..c53eac0d9
--- /dev/null
+++ b/src/ui/dialog/lpe-powerstroke-properties.h
@@ -0,0 +1,99 @@
+/** @file
+ * @brief Dialog for renaming layers
+ */
+/* Author:
+ * Bryce W. Harrington <bryce@bryceharrington.com>
+ *
+ * Copyright (C) 2004 Bryce Harrington
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information
+ */
+
+#ifndef INKSCAPE_DIALOG_POWERSTROKE_PROPERTIES_H
+#define INKSCAPE_DIALOG_POWERSTROKE_PROPERTIES_H
+
+#include <2geom/point.h>
+#include <gtkmm/dialog.h>
+#include <gtkmm/entry.h>
+#include <gtkmm/label.h>
+#include <gtkmm/table.h>
+#include <gtkmm/combobox.h>
+#include <gtkmm/liststore.h>
+#include <gtkmm/treeview.h>
+#include <gtkmm/treestore.h>
+#include <gtkmm/scrolledwindow.h>
+#include "live_effects/parameter/powerstrokepointarray.h"
+
+class SPDesktop;
+
+namespace Inkscape {
+namespace UI {
+namespace Dialogs {
+
+class PowerstrokePropertiesDialog : public Gtk::Dialog {
+ public:
+ PowerstrokePropertiesDialog();
+ virtual ~PowerstrokePropertiesDialog();
+
+ Glib::ustring getName() const { return "LayerPropertiesDialog"; }
+
+ static void showDialog(SPDesktop *desktop, Geom::Point knotpoint, const Inkscape::LivePathEffect::PowerStrokePointArrayParamKnotHolderEntity *pt);
+
+protected:
+
+ SPDesktop *_desktop;
+ Inkscape::LivePathEffect::PowerStrokePointArrayParamKnotHolderEntity *_knotpoint;
+
+ Gtk::Label _powerstroke_position_label;
+ Gtk::Entry _powerstroke_position_entry;
+ Gtk::Label _powerstroke_width_label;
+ Gtk::Entry _powerstroke_width_entry;
+ Gtk::Table _layout_table;
+ bool _position_visible;
+
+ Gtk::Button _close_button;
+ Gtk::Button _apply_button;
+
+ sigc::connection _destroy_connection;
+
+ static PowerstrokePropertiesDialog &_instance() {
+ static PowerstrokePropertiesDialog instance;
+ return instance;
+ }
+
+ void _setDesktop(SPDesktop *desktop);
+ void _setPt(const Inkscape::LivePathEffect::PowerStrokePointArrayParamKnotHolderEntity *pt);
+
+ void _apply();
+ void _close();
+
+ void _setKnotPoint(Geom::Point knotpoint);
+ void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row);
+
+ bool _handleKeyEvent(GdkEventKey *event);
+ void _handleButtonEvent(GdkEventButton* event);
+
+ friend class Inkscape::LivePathEffect::PowerStrokePointArrayParamKnotHolderEntity;
+
+private:
+ PowerstrokePropertiesDialog(PowerstrokePropertiesDialog const &); // no copy
+ PowerstrokePropertiesDialog &operator=(PowerstrokePropertiesDialog const &); // no assign
+};
+
+} // namespace
+} // namespace
+} // namespace
+
+
+#endif //INKSCAPE_DIALOG_LAYER_PROPERTIES_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/new-from-template.cpp b/src/ui/dialog/new-from-template.cpp
index f326bb3ee..e30b148bb 100644
--- a/src/ui/dialog/new-from-template.cpp
+++ b/src/ui/dialog/new-from-template.cpp
@@ -8,6 +8,9 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#if HAVE_CONFIG_H
+ #include "config.h"
+#endif
#include "new-from-template.h"
#include "file.h"
@@ -25,12 +28,22 @@ NewFromTemplate::NewFromTemplate()
{
set_title(_("New From Template"));
resize(400, 400);
-
+
+#if WITH_GTKMM_3_0
+ get_content_area()->pack_start(_main_widget);
+#else
get_vbox()->pack_start(_main_widget);
+#endif
Gtk::Alignment *align;
align = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_END, Gtk::ALIGN_CENTER, 0.0, 0.0));
+
+#if WITH_GTKMM_3_0
+ get_content_area()->pack_end(*align, Gtk::PACK_SHRINK);
+#else
get_vbox()->pack_end(*align, Gtk::PACK_SHRINK);
+#endif
+
align->set_padding(0, 0, 0, 15);
align->add(_create_template_button);
diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp
new file mode 100644
index 000000000..c95529a56
--- /dev/null
+++ b/src/ui/dialog/objects.cpp
@@ -0,0 +1,2144 @@
+/*
+ * A simple panel for objects
+ *
+ * Authors:
+ * Theodore Janeczko
+ * Tweaked by Liam P White for use in Inkscape
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "objects.h"
+#include <gtkmm/widget.h>
+#include <gtkmm/icontheme.h>
+#include <gtkmm/imagemenuitem.h>
+#include <gtkmm/separatormenuitem.h>
+#include <gtkmm/stock.h>
+
+#include <glibmm/i18n.h>
+#include <glibmm/main.h>
+
+#include "desktop.h"
+#include "desktop-style.h"
+#include "ui/dialog-events.h"
+#include "document.h"
+#include "document-undo.h"
+#include "filter-chemistry.h"
+#include "filters/blend.h"
+#include "filters/gaussian-blur.h"
+#include "helper/action.h"
+#include "inkscape.h"
+#include "layer-manager.h"
+#include "preferences.h"
+#include "selection.h"
+#include "sp-clippath.h"
+#include "sp-mask.h"
+#include "sp-item.h"
+#include "sp-object.h"
+#include "sp-root.h"
+#include "sp-shape.h"
+#include "style.h"
+#include "ui/tools-switch.h"
+#include "ui/icon-names.h"
+#include "ui/widget/imagetoggler.h"
+#include "ui/widget/layertypeicon.h"
+#include "ui/widget/insertordericon.h"
+#include "ui/widget/clipmaskicon.h"
+#include "ui/widget/highlight-picker.h"
+#include "ui/tools/node-tool.h"
+#include "ui/tools/tool-base.h"
+#include "verbs.h"
+#include "widgets/sp-color-notebook.h"
+#include "widgets/icon.h"
+#include "xml/node.h"
+#include "xml/node-observer.h"
+#include "xml/repr.h"
+
+//#define DUMP_LAYERS 1
+
+namespace Inkscape {
+namespace UI {
+namespace Dialog {
+
+using Inkscape::XML::Node;
+
+/**
+ * Gets an instance of the Objects panel
+ */
+ObjectsPanel& ObjectsPanel::getInstance()
+{
+ return *new ObjectsPanel();
+}
+
+/**
+ * Column enumeration
+ */
+enum {
+ COL_VISIBLE = 1,
+ COL_LOCKED,
+ COL_TYPE,
+// COL_INSERTORDER,
+ COL_CLIPMASK,
+ COL_HIGHLIGHT
+};
+
+/**
+ * Button enumeration
+ */
+enum {
+ BUTTON_NEW = 0,
+ BUTTON_RENAME,
+ BUTTON_TOP,
+ BUTTON_BOTTOM,
+ BUTTON_UP,
+ BUTTON_DOWN,
+ BUTTON_DUPLICATE,
+ BUTTON_DELETE,
+ BUTTON_SOLO,
+ BUTTON_SHOW_ALL,
+ BUTTON_HIDE_ALL,
+ BUTTON_LOCK_OTHERS,
+ BUTTON_LOCK_ALL,
+ BUTTON_UNLOCK_ALL,
+ BUTTON_SETCLIP,
+ BUTTON_CLIPGROUP,
+// BUTTON_SETINVCLIP,
+ BUTTON_UNSETCLIP,
+ BUTTON_SETMASK,
+ BUTTON_UNSETMASK,
+ BUTTON_GROUP,
+ BUTTON_UNGROUP,
+ BUTTON_COLLAPSE_ALL,
+ DRAGNDROP
+};
+
+/**
+ * Xml node observer for observing objects in the document
+ */
+class ObjectsPanel::ObjectWatcher : public Inkscape::XML::NodeObserver {
+public:
+ /**
+ * Creates a new object watcher
+ * @param pnl The panel to which the object watcher belongs
+ * @param obj The object to watch
+ */
+ ObjectWatcher(ObjectsPanel* pnl, SPObject* obj) :
+ _pnl(pnl),
+ _obj(obj),
+ _repr(obj->getRepr()),
+ _highlightAttr(g_quark_from_string("inkscape:highlight-color")),
+ _lockedAttr(g_quark_from_string("sodipodi:insensitive")),
+ _labelAttr(g_quark_from_string("inkscape:label")),
+ _groupAttr(g_quark_from_string("inkscape:groupmode")),
+ _styleAttr(g_quark_from_string("style")),
+ _clipAttr(g_quark_from_string("clip-path")),
+ _maskAttr(g_quark_from_string("mask"))
+ {}
+
+ virtual void notifyChildAdded( Node &/*node*/, Node &/*child*/, Node */*prev*/ )
+ {
+ if ( _pnl && _obj ) {
+ _pnl->_objectsChanged( _obj );
+ }
+ }
+ virtual void notifyChildRemoved( Node &/*node*/, Node &/*child*/, Node */*prev*/ )
+ {
+ if ( _pnl && _obj ) {
+ _pnl->_objectsChanged( _obj );
+ }
+ }
+ virtual void notifyChildOrderChanged( Node &/*node*/, Node &/*child*/, Node */*old_prev*/, Node */*new_prev*/ )
+ {
+ if ( _pnl && _obj ) {
+ _pnl->_objectsChanged( _obj );
+ }
+ }
+ virtual void notifyContentChanged( Node &/*node*/, Util::ptr_shared<char> /*old_content*/, Util::ptr_shared<char> /*new_content*/ ) {}
+ virtual void notifyAttributeChanged( Node &/*node*/, GQuark name, Util::ptr_shared<char> /*old_value*/, Util::ptr_shared<char> /*new_value*/ ) {
+ if ( _pnl && _obj ) {
+ if ( name == _lockedAttr || name == _labelAttr || name == _highlightAttr || name == _groupAttr || name == _styleAttr || name == _clipAttr || name == _maskAttr ) {
+ _pnl->_updateObject(_obj, name == _highlightAttr);
+ if ( name == _styleAttr ) {
+ _pnl->_updateComposite();
+ }
+ }
+ }
+ }
+
+ /**
+ * Objects panel to which this watcher belongs
+ */
+ ObjectsPanel* _pnl;
+
+ /**
+ * The object that is being observed
+ */
+ SPObject* _obj;
+
+ /**
+ * The xml representation of the object that is being observed
+ */
+ Inkscape::XML::Node* _repr;
+
+ /* These are quarks which define the attributes that we are observing */
+ GQuark _highlightAttr;
+ GQuark _lockedAttr;
+ GQuark _labelAttr;
+ GQuark _groupAttr;
+ GQuark _styleAttr;
+ GQuark _clipAttr;
+ GQuark _maskAttr;
+};
+
+class ObjectsPanel::InternalUIBounce
+{
+public:
+ int _actionCode;
+};
+
+class ObjectsPanel::ModelColumns : public Gtk::TreeModel::ColumnRecord
+{
+public:
+
+ ModelColumns()
+ {
+ add(_colObject);
+ add(_colVisible);
+ add(_colLocked);
+ add(_colLabel);
+ add(_colType);
+ add(_colHighlight);
+ add(_colClipMask);
+ //add(_colInsertOrder);
+ }
+ virtual ~ModelColumns() {}
+
+ Gtk::TreeModelColumn<SPItem*> _colObject;
+ Gtk::TreeModelColumn<Glib::ustring> _colLabel;
+ Gtk::TreeModelColumn<bool> _colVisible;
+ Gtk::TreeModelColumn<bool> _colLocked;
+ Gtk::TreeModelColumn<int> _colType;
+ Gtk::TreeModelColumn<guint32> _colHighlight;
+ Gtk::TreeModelColumn<int> _colClipMask;
+ //Gtk::TreeModelColumn<int> _colInsertOrder;
+};
+
+/**
+ * Stylizes a button using the given icon name and tooltip
+ */
+void ObjectsPanel::_styleButton( Gtk::Button& btn, char const* iconName, char const* tooltip )
+{
+ GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, iconName );
+ gtk_widget_show( child );
+ btn.add( *Gtk::manage(Glib::wrap(child)) );
+ btn.set_relief(Gtk::RELIEF_NONE);
+
+ btn.set_tooltip_text (tooltip);
+
+}
+
+/**
+ * Adds an item to the pop-up (right-click) menu
+ * @param desktop The active destktop
+ * @param code Action code
+ * @param iconName Icon name
+ * @param fallback Fallback text
+ * @param id Button id for callback function
+ * @return The generated menu item
+ */
+Gtk::MenuItem& ObjectsPanel::_addPopupItem( SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback, int id )
+{
+ GtkWidget* iconWidget = 0;
+ const char* label = 0;
+
+ if ( iconName ) {
+ iconWidget = sp_icon_new( Inkscape::ICON_SIZE_MENU, iconName );
+ }
+
+ if ( desktop ) {
+ Verb *verb = Verb::get( code );
+ if ( verb ) {
+ SPAction *action = verb->get_action(desktop);
+ if ( !iconWidget && action && action->image ) {
+ iconWidget = sp_icon_new( Inkscape::ICON_SIZE_MENU, action->image );
+ }
+
+ if ( action ) {
+ // label = action->name;
+ }
+ }
+ }
+
+ if ( !label && fallback ) {
+ label = fallback;
+ }
+
+ Gtk::Widget* wrapped = 0;
+ if ( iconWidget ) {
+ wrapped = Gtk::manage(Glib::wrap(iconWidget));
+ wrapped->show();
+ }
+
+
+ Gtk::MenuItem* item = 0;
+
+ if (wrapped) {
+ item = Gtk::manage(new Gtk::ImageMenuItem(*wrapped, label, true));
+ } else {
+ item = Gtk::manage(new Gtk::MenuItem(label, true));
+ }
+
+ item->signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &ObjectsPanel::_takeAction), id));
+ _popupMenu.append(*item);
+
+ return *item;
+}
+
+/**
+ * Callback function for when an object changes. Essentially refreshes the entire tree
+ * @param obj Object which was changed (currently not used as the entire tree is recreated)
+ */
+void ObjectsPanel::_objectsChanged(SPObject */*obj*/)
+{
+ //First, unattach the watchers
+ while (!_objectWatchers.empty())
+ {
+ ObjectsPanel::ObjectWatcher *w = _objectWatchers.back();
+ w->_repr->removeObserver(*w);
+ _objectWatchers.pop_back();
+ delete w;
+ }
+
+ if (_desktop) {
+ //Get the current document's root and use that to enumerate the tree
+ SPDocument* document = _desktop->doc();
+ SPRoot* root = document->getRoot();
+ if ( root ) {
+ _selectedConnection.block();
+ //Clear the tree store
+ _store->clear();
+ //Add all items recursively
+ _addObject( root, 0 );
+ _selectedConnection.unblock();
+ //Set the tree selection
+ _objectsSelected(_desktop->selection);
+ //Handle button sensitivity
+ _checkTreeSelection();
+ }
+ }
+}
+
+/**
+ * Recursively adds the children of the given item to the tree
+ * @param obj Root object to add to the tree
+ * @param parentRow Parent tree row (or NULL if adding to tree root)
+ */
+void ObjectsPanel::_addObject(SPObject* obj, Gtk::TreeModel::Row* parentRow)
+{
+ if ( _desktop && obj ) {
+ for ( SPObject *child = obj->children; child != NULL; child = child->next) {
+
+ if (SP_IS_ITEM(child))
+ {
+ SPItem * item = SP_ITEM(child);
+ SPGroup * group = SP_IS_GROUP(child) ? SP_GROUP(child) : 0;
+
+ //Add the item to the tree and set the column information
+ Gtk::TreeModel::iterator iter = parentRow ? _store->prepend(parentRow->children()) : _store->prepend();
+ Gtk::TreeModel::Row row = *iter;
+ row[_model->_colObject] = item;
+ //this seems to crash on convert stroke to path then undo (probably no ID?)
+ try {
+ row[_model->_colLabel] = item->label() ? item->label() : item->getId();
+ } catch (...) {
+ row[_model->_colLabel] = Glib::ustring("getId_failure");
+ g_critical("item->getId() failed, using \"getId_failure\"");
+ }
+ row[_model->_colVisible] = !item->isHidden();
+ row[_model->_colLocked] = !item->isSensitive();
+ row[_model->_colType] = group ? (group->layerMode() == SPGroup::LAYER ? 2 : 1) : 0;
+ row[_model->_colHighlight] = item->isHighlightSet() ? item->highlight_color() : item->highlight_color() & 0xffffff00;
+ row[_model->_colClipMask] = item->clip_ref && item->clip_ref->getObject() ? 1 : (item->mask_ref && item->mask_ref->getObject() ? 2 : 0);
+ //row[_model->_colInsertOrder] = group ? (group->insertBottom() ? 2 : 1) : 0;
+
+ //If our parent object is a group and it's expanded, expand the tree
+ if (SP_IS_GROUP(obj) && SP_GROUP(obj)->expanded())
+ {
+ _tree.expand_to_path( _store->get_path(iter) );
+ }
+
+ //Add an object watcher to the item
+ ObjectsPanel::ObjectWatcher *w = new ObjectsPanel::ObjectWatcher(this, child);
+ child->getRepr()->addObserver(*w);
+ _objectWatchers.push_back(w);
+
+ //If the item is a group, recursively add its children
+ if (group)
+ {
+ _addObject( child, &row );
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Updates an item in the tree and optionally recursively updates the item's children
+ * @param obj The item to update in the tree
+ * @param recurse Whether to recurse through the item's children
+ */
+void ObjectsPanel::_updateObject( SPObject *obj, bool recurse ) {
+ //Find the object in the tree store and update it
+
+ //mark
+ _store->foreach_iter( sigc::bind<SPObject*>(sigc::mem_fun(*this, &ObjectsPanel::_checkForUpdated), obj) );
+ //end mark
+ if (recurse)
+ {
+ for (SPObject * iter = obj->children; iter != NULL; iter = iter->next)
+ {
+ _updateObject(iter, recurse);
+ }
+ }
+}
+
+/**
+ * Checks items in the tree store and updates the given item
+ * @param iter Current item being looked at in the tree
+ * @param obj Object to update
+ * @return
+ */
+bool ObjectsPanel::_checkForUpdated(const Gtk::TreeIter& iter, SPObject* obj)
+{
+ Gtk::TreeModel::Row row = *iter;
+ if ( obj == row[_model->_colObject] )
+ {
+ //We found our item in the tree!! Update it!
+ SPItem * item = SP_IS_ITEM(obj) ? SP_ITEM(obj) : 0;
+ SPGroup * group = SP_IS_GROUP(obj) ? SP_GROUP(obj) : 0;
+
+ row[_model->_colLabel] = obj->label() ? obj->label() : obj->getId();
+ row[_model->_colVisible] = item ? !item->isHidden() : false;
+ row[_model->_colLocked] = item ? !item->isSensitive() : false;
+ row[_model->_colType] = group ? (group->layerMode() == SPGroup::LAYER ? 2 : 1) : 0;
+ row[_model->_colHighlight] = item ? (item->isHighlightSet() ? item->highlight_color() : item->highlight_color() & 0xffffff00) : 0;
+ row[_model->_colClipMask] = item ? (item->clip_ref && item->clip_ref->getObject() ? 1 : (item->mask_ref && item->mask_ref->getObject() ? 2 : 0)) : 0;
+ //row[_model->_colInsertOrder] = group ? (group->insertBottom() ? 2 : 1) : 0;
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Updates the composite controls for the selected item
+ */
+void ObjectsPanel::_updateComposite() {
+ if (!_blockCompositeUpdate)
+ {
+ //Set the default values
+ bool setValues = true;
+
+ //Get/set the values
+ _tree.get_selection()->selected_foreach_iter(sigc::bind<bool *>(sigc::mem_fun(*this, &ObjectsPanel::_compositingChanged), &setValues));
+ }
+}
+
+/**
+ * Sets the compositing values for the first selected item in the tree
+ * @param iter Current tree item
+ * @param setValues Whether to set the compositing values
+ * @param blur Blur value to use
+ */
+void ObjectsPanel::_compositingChanged( const Gtk::TreeModel::iterator& iter, bool *setValues )
+{
+ if (iter) {
+ Gtk::TreeModel::Row row = *iter;
+ SPItem *item = row[_model->_colObject];
+ if (*setValues)
+ {
+ _setCompositingValues(item);
+ *setValues = false;
+ }
+ }
+}
+
+/**
+ * Occurs when the current desktop selection changes
+ * @param sel The current selection
+ */
+void ObjectsPanel::_objectsSelected( Selection *sel ) {
+
+ bool setOpacity = true;
+ _selectedConnection.block();
+ _tree.get_selection()->unselect_all();
+ SPItem *item = NULL;
+ for (const GSList * iter = sel->itemList(); iter != NULL; iter = iter->next)
+ {
+ item = reinterpret_cast<SPItem *>(iter->data);
+ if (setOpacity)
+ {
+ _setCompositingValues(item);
+ setOpacity = false;
+ }
+ _store->foreach(sigc::bind<SPItem *, bool>( sigc::mem_fun(*this, &ObjectsPanel::_checkForSelected), item, iter->next == NULL));
+ }
+ if (!item) {
+ if (_desktop->currentLayer() && SP_IS_ITEM(_desktop->currentLayer())) {
+ item = SP_ITEM(_desktop->currentLayer());
+ _setCompositingValues(item);
+ _store->foreach(sigc::bind<SPItem *, bool>( sigc::mem_fun(*this, &ObjectsPanel::_checkForSelected), item, true));
+ }
+ }
+ _selectedConnection.unblock();
+ _checkTreeSelection();
+}
+
+/**
+ * Helper function for setting the compositing values
+ * @param item Item to use for setting the compositing values
+ */
+void ObjectsPanel::_setCompositingValues(SPItem *item)
+{
+ //Block the connections to avoid interference
+ _opacityConnection.block();
+ _blendConnection.block();
+ _blurConnection.block();
+
+ //Set the opacity
+#if WITH_GTKMM_3_0
+ _opacity_adjustment->set_value((item->style->opacity.set ? SP_SCALE24_TO_FLOAT(item->style->opacity.value) : 1) * _opacity_adjustment->get_upper());
+#else
+ _opacity_adjustment.set_value((item->style->opacity.set ? SP_SCALE24_TO_FLOAT(item->style->opacity.value) : 1) * _opacity_adjustment.get_upper());
+#endif
+ SPFeBlend *spblend = NULL;
+ SPGaussianBlur *spblur = NULL;
+ if (item->style->getFilter())
+ {
+ for(SPObject *primitive_obj = item->style->getFilter()->children; primitive_obj && SP_IS_FILTER_PRIMITIVE(primitive_obj); primitive_obj = primitive_obj->next) {
+ if(SP_IS_FEBLEND(primitive_obj) && !spblend) {
+ //Get the blend mode
+ spblend = SP_FEBLEND(primitive_obj);
+ }
+
+ if(SP_IS_GAUSSIANBLUR(primitive_obj) && !spblur) {
+ //Get the blur value
+ spblur = SP_GAUSSIANBLUR(primitive_obj);
+ }
+ }
+ }
+
+ //Set the blend mode
+ _fe_cb.set_blend_mode(spblend ? spblend->blend_mode : Inkscape::Filters::BLEND_NORMAL);
+
+ //Set the blur value
+ Geom::OptRect bbox = item->bounds(SPItem::GEOMETRIC_BBOX);
+ if (bbox && spblur) {
+ double perimeter = bbox->dimensions()[Geom::X] + bbox->dimensions()[Geom::Y]; // fixme: this is only half the perimeter, is that correct?
+ _fe_blur.set_blur_value(spblur->stdDeviation.getNumber() * 400 / perimeter);
+ } else {
+ _fe_blur.set_blur_value(0);
+ }
+
+ //Unblock connections
+ _blurConnection.unblock();
+ _blendConnection.unblock();
+ _opacityConnection.unblock();
+}
+
+/**
+ * Checks the tree and selects the specified item, optionally scrolling to the item
+ * @param path Current tree path
+ * @param iter Current tree item
+ * @param item Item to select in the tree
+ * @param scrollto Whether to scroll to the item
+ * @return Whether to continue searching the tree
+ */
+bool ObjectsPanel::_checkForSelected(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPItem* item, bool scrollto)
+{
+ bool stopGoing = false;
+
+ Gtk::TreeModel::Row row = *iter;
+ if ( item == row[_model->_colObject] )
+ {
+ //We found the item! Expand to the path and select it in the tree.
+ _tree.expand_to_path( path );
+
+ Glib::RefPtr<Gtk::TreeSelection> select = _tree.get_selection();
+
+ select->select(iter);
+ if (scrollto) {
+ //Scroll to the item in the tree
+ _tree.scroll_to_row(path);
+ }
+
+ stopGoing = true;
+ }
+
+ return stopGoing;
+}
+
+/**
+ * Pushes the current tree selection to the canvas
+ */
+void ObjectsPanel::_pushTreeSelectionToCurrent()
+{
+ if ( _desktop && _desktop->currentRoot() ) {
+ //block connections for selection and compositing values to prevent interference
+ _selectionChangedConnection.block();
+
+ //Clear the selection and then iterate over the tree selection, pushing each item to the desktop
+ _desktop->selection->clear();
+ bool setOpacity = true;
+ _tree.get_selection()->selected_foreach_iter( sigc::bind<bool *>(sigc::mem_fun(*this, &ObjectsPanel::_selected_row_callback), &setOpacity));
+ //unblock connections
+ _selectionChangedConnection.unblock();
+
+ _checkTreeSelection();
+ }
+}
+
+/**
+ * Helper function for pushing the current tree selection to the current desktop
+ * @param iter Current tree item
+ * @param setCompositingValues Whether to set the compositing values
+ * @param blur
+ */
+void ObjectsPanel::_selected_row_callback( const Gtk::TreeModel::iterator& iter, bool *setCompositingValues )
+{
+ if (iter) {
+ Gtk::TreeModel::Row row = *iter;
+ SPItem *item = row[_model->_colObject];
+ if (!SP_IS_GROUP(item) || SP_GROUP(item)->layerMode() != SPGroup::LAYER)
+ {
+ //If the item is not a layer, then select it and set the current layer to its parent (if it's the first item)
+ if (_desktop->selection->isEmpty()) _desktop->setCurrentLayer(item->parent);
+ _desktop->selection->add(item);
+ }
+ else
+ {
+ //If the item is a layer, set the current layer
+ if (_desktop->selection->isEmpty()) _desktop->setCurrentLayer(item);
+ }
+ if (*setCompositingValues)
+ {
+ //Only set the compositing values for the first item
+ _setCompositingValues(item);
+ *setCompositingValues = false;
+ }
+ }
+}
+
+/**
+ * Handles button sensitivity
+ */
+void ObjectsPanel::_checkTreeSelection()
+{
+ bool sensitive = _tree.get_selection()->count_selected_rows() > 0;
+ //TODO: top/bottom sensitivity
+ bool sensitiveNonTop = true;
+ bool sensitiveNonBottom = true;
+
+ for ( std::vector<Gtk::Widget*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) {
+ (*it)->set_sensitive( sensitive );
+ }
+ for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonTop.begin(); it != _watchingNonTop.end(); ++it ) {
+ (*it)->set_sensitive( sensitiveNonTop );
+ }
+ for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonBottom.begin(); it != _watchingNonBottom.end(); ++it ) {
+ (*it)->set_sensitive( sensitiveNonBottom );
+ }
+}
+
+/**
+ * Sets visibility of items in the tree
+ * @param iter Current item in the tree
+ * @param visible Whether the item should be visible or not
+ */
+void ObjectsPanel::_setVisibleIter( const Gtk::TreeModel::iterator& iter, const bool visible )
+{
+ Gtk::TreeModel::Row row = *iter;
+ SPItem* item = row[_model->_colObject];
+ if (item)
+ {
+ item->setHidden( !visible );
+ row[_model->_colVisible] = visible;
+ item->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT);
+ }
+}
+
+/**
+ * Sets sensitivity of items in the tree
+ * @param iter Current item in the tree
+ * @param locked Whether the item should be locked
+ */
+void ObjectsPanel::_setLockedIter( const Gtk::TreeModel::iterator& iter, const bool locked )
+{
+ Gtk::TreeModel::Row row = *iter;
+ SPItem* item = row[_model->_colObject];
+ if (item)
+ {
+ item->setLocked( locked );
+ row[_model->_colLocked] = locked;
+ item->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT);
+ }
+}
+
+/**
+ * Handles keyboard events
+ * @param event Keyboard event passed in from GDK
+ * @return Whether the event should be eaten (om nom nom)
+ */
+bool ObjectsPanel::_handleKeyEvent(GdkEventKey *event)
+{
+
+ bool empty = _desktop->selection->isEmpty();
+
+ switch (Inkscape::UI::Tools::get_group0_keyval(event)) {
+ case GDK_KEY_Return:
+ case GDK_KEY_KP_Enter:
+ case GDK_KEY_F2:
+ {
+ Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected();
+ if (iter && !_text_renderer->property_editable()) {
+ //Rename item
+ Gtk::TreeModel::Path *path = new Gtk::TreeModel::Path(iter);
+ _text_renderer->property_editable() = true;
+ _tree.set_cursor(*path, *_name_column, true);
+ grab_focus();
+ return true;
+ }
+ }
+ break;
+ case GDK_KEY_Home:
+ //Move item(s) to top of containing group/layer
+ _fireAction( empty ? SP_VERB_LAYER_TO_TOP : SP_VERB_SELECTION_TO_FRONT );
+ break;
+ case GDK_KEY_End:
+ //Move item(s) to bottom of containing group/layer
+ _fireAction( empty ? SP_VERB_LAYER_TO_BOTTOM : SP_VERB_SELECTION_TO_BACK );
+ break;
+ case GDK_KEY_Page_Up:
+ {
+ //Move item(s) up in containing group/layer
+ int ch = event->state & GDK_SHIFT_MASK ? SP_VERB_LAYER_MOVE_TO_NEXT : SP_VERB_SELECTION_RAISE;
+ _fireAction( empty ? SP_VERB_LAYER_RAISE : ch );
+ break;
+ }
+ case GDK_KEY_Page_Down:
+ {
+ //Move item(s) down in containing group/layer
+ int ch = event->state & GDK_SHIFT_MASK ? SP_VERB_LAYER_MOVE_TO_PREV : SP_VERB_SELECTION_LOWER;
+ _fireAction( empty ? SP_VERB_LAYER_LOWER : ch );
+ break;
+ }
+
+ //TODO: Handle Ctrl-A, etc.
+ default:
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Handles mouse events
+ * @param event Mouse event from GDK
+ * @return whether to eat the event (om nom nom)
+ */
+bool ObjectsPanel::_handleButtonEvent(GdkEventButton* event)
+{
+ static unsigned doubleclick = 0;
+ static bool overVisible = false;
+
+ //Right mouse button was clicked, launch the pop-up menu
+ if ( (event->type == GDK_BUTTON_PRESS) && (event->button == 3) ) {
+ Gtk::TreeModel::Path path;
+ int x = static_cast<int>(event->x);
+ int y = static_cast<int>(event->y);
+ if ( _tree.get_path_at_pos( x, y, path ) ) {
+ _checkTreeSelection();
+ _popupMenu.popup(event->button, event->time);
+ if (_tree.get_selection()->is_selected(path)) {
+ return true;
+ }
+ }
+ }
+
+ //Left mouse button was pressed! In order to handle multiple item drag & drop,
+ //we need to defer selection by setting the select function so that the tree doesn't
+ //automatically select anything. In order to handle multiple item icon clicking,
+ //we need to eat the event. There might be a better way to do both of these...
+ if ( (event->type == GDK_BUTTON_PRESS) && (event->button == 1)) {
+ overVisible = false;
+ Gtk::TreeModel::Path path;
+ Gtk::TreeViewColumn* col = 0;
+ int x = static_cast<int>(event->x);
+ int y = static_cast<int>(event->y);
+ int x2 = 0;
+ int y2 = 0;
+ if ( _tree.get_path_at_pos( x, y, path, col, x2, y2 ) ) {
+ if (col == _tree.get_column(COL_VISIBLE-1)) {
+ //Click on visible column, eat this event to keep row selection
+ overVisible = true;
+ return true;
+ } else if (col == _tree.get_column(COL_LOCKED-1) ||
+ col == _tree.get_column(COL_TYPE-1) ||
+ //col == _tree.get_column(COL_INSERTORDER - 1) ||
+ col == _tree.get_column(COL_HIGHLIGHT-1)) {
+ //Click on an icon column, eat this event to keep row selection
+ return true;
+ } else if ( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) & _tree.get_selection()->is_selected(path) ) {
+ //Click on a selected item with no modifiers, defer selection to the mouse-up by
+ //setting the select function to _noSelection
+ _tree.get_selection()->set_select_function(sigc::mem_fun(*this, &ObjectsPanel::_noSelection));
+ _defer_target = path;
+ }
+ }
+ }
+
+ //Restore the selection function to allow tree selection on mouse button release
+ if ( event->type == GDK_BUTTON_RELEASE) {
+ _tree.get_selection()->set_select_function(sigc::mem_fun(*this, &ObjectsPanel::_rowSelectFunction));
+ }
+
+ //CellRenderers do not have good support for dealing with multiple items, so
+ //we handle all events on them here
+ if ( (event->type == GDK_BUTTON_RELEASE) && (event->button == 1)) {
+
+ Gtk::TreeModel::Path path;
+ Gtk::TreeViewColumn* col = 0;
+ int x = static_cast<int>(event->x);
+ int y = static_cast<int>(event->y);
+ int x2 = 0;
+ int y2 = 0;
+ if ( _tree.get_path_at_pos( x, y, path, col, x2, y2 ) ) {
+ if (_defer_target) {
+ //We had deferred a selection target, select it here (assuming no drag & drop)
+ if (_defer_target == path && !(event->x == 0 && event->y == 0))
+ {
+ _tree.set_cursor(path, *col, false);
+ }
+ _defer_target = Gtk::TreeModel::Path();
+ }
+ else {
+ if (event->state & GDK_SHIFT_MASK) {
+ // Shift left click on the visible/lock columns toggles "solo" mode
+ if (col == _tree.get_column(COL_VISIBLE - 1)) {
+ _takeAction(BUTTON_SOLO);
+ } else if (col == _tree.get_column(COL_LOCKED - 1)) {
+ _takeAction(BUTTON_LOCK_OTHERS);
+ }
+ } else if (event->state & GDK_MOD1_MASK) {
+ // Alt+left click on the visible/lock columns toggles "solo" mode and preserves selection
+ Gtk::TreeModel::iterator iter = _store->get_iter(path);
+ if (_store->iter_is_valid(iter)) {
+ Gtk::TreeModel::Row row = *iter;
+ SPItem *item = row[_model->_colObject];
+ if (col == _tree.get_column(COL_VISIBLE - 1)) {
+ _desktop->toggleLayerSolo( item );
+ DocumentUndo::maybeDone(_desktop->doc(), "layer:solo", SP_VERB_LAYER_SOLO, _("Toggle layer solo"));
+ } else if (col == _tree.get_column(COL_LOCKED - 1)) {
+ _desktop->toggleLockOtherLayers( item );
+ DocumentUndo::maybeDone(_desktop->doc(), "layer:lockothers", SP_VERB_LAYER_LOCK_OTHERS, _("Lock other layers"));
+ }
+ }
+ } else {
+ Gtk::TreeModel::Children::iterator iter = _tree.get_model()->get_iter(path);
+ Gtk::TreeModel::Row row = *iter;
+
+ SPItem* item = row[_model->_colObject];
+
+ if (col == _tree.get_column(COL_VISIBLE - 1)) {
+ if (overVisible) {
+ //Toggle visibility
+ bool newValue = !row[_model->_colVisible];
+ if (_tree.get_selection()->is_selected(path))
+ {
+ //If the current row is selected, toggle the visibility
+ //for all selected items
+ _tree.get_selection()->selected_foreach_iter(sigc::bind<bool>(sigc::mem_fun(*this, &ObjectsPanel::_setVisibleIter), newValue));
+ }
+ else
+ {
+ //If the current row is not selected, toggle just its visibility
+ row[_model->_colVisible] = newValue;
+ item->setHidden(!newValue);
+ item->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT);
+ }
+ DocumentUndo::done( _desktop->doc() , SP_VERB_DIALOG_OBJECTS,
+ newValue? _("Unhide objects") : _("Hide objects"));
+ overVisible = false;
+ }
+ } else if (col == _tree.get_column(COL_LOCKED - 1)) {
+ //Toggle locking
+ bool newValue = !row[_model->_colLocked];
+ if (_tree.get_selection()->is_selected(path))
+ {
+ //If the current row is selected, toggle the sensitivity for
+ //all selected items
+ _tree.get_selection()->selected_foreach_iter(sigc::bind<bool>(sigc::mem_fun(*this, &ObjectsPanel::_setLockedIter), newValue));
+ }
+ else
+ {
+ //If the current row is not selected, toggle just its sensitivity
+ row[_model->_colLocked] = newValue;
+ item->setLocked( newValue );
+ item->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT);
+ }
+ DocumentUndo::done( _desktop->doc() , SP_VERB_DIALOG_OBJECTS,
+ newValue? _("Lock objects") : _("Unlock objects"));
+
+ } else if (col == _tree.get_column(COL_TYPE - 1)) {
+ if (SP_IS_GROUP(item))
+ {
+ //Toggle the current item between a group and a layer
+ SPGroup * g = SP_GROUP(item);
+ bool newValue = g->layerMode() == SPGroup::LAYER;
+ row[_model->_colType] = newValue ? 1: 2;
+ g->setLayerMode(newValue ? SPGroup::GROUP : SPGroup::LAYER);
+ g->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT);
+ DocumentUndo::done( _desktop->doc() , SP_VERB_DIALOG_OBJECTS,
+ newValue? _("Layer to group") : _("Group to layer"));
+ }
+ } /*else if (col == _tree.get_column(COL_INSERTORDER - 1)) {
+ if (SP_IS_GROUP(item))
+ {
+ //Toggle the current item's insert order
+ SPGroup * g = SP_GROUP(item);
+ bool newValue = !g->insertBottom();
+ row[_model->_colInsertOrder] = newValue ? 2: 1;
+ g->setInsertBottom(newValue);
+ g->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT);
+ DocumentUndo::done( _desktop->doc() , SP_VERB_DIALOG_OBJECTS,
+ newValue? _("Set insert mode bottom") : _("Set insert mode top"));
+ }
+ }*/ else if (col == _tree.get_column(COL_HIGHLIGHT - 1)) {
+ //Clear the highlight targets
+ _highlight_target.clear();
+ if (_tree.get_selection()->is_selected(path))
+ {
+ //If the current item is selected, store all selected items
+ //in the highlight source
+ _tree.get_selection()->selected_foreach_iter(sigc::mem_fun(*this, &ObjectsPanel::_storeHighlightTarget));
+ } else {
+ //If the current item is not selected, store only it in the highlight source
+ _storeHighlightTarget(iter);
+ }
+ if (_colorSelector)
+ {
+ //Set up the color selector
+ SPColor color;
+ color.set( row[_model->_colHighlight] );
+ _colorSelector->base->setColorAlpha(color, SP_RGBA32_A_F(row[_model->_colHighlight]));
+ }
+ //Show the color selector dialog
+ _colorSelectorDialog.show();
+ }
+ }
+ }
+ }
+ }
+
+ //Second mouse button press, set double click status for when the mouse is released
+ if ( (event->type == GDK_2BUTTON_PRESS) && (event->button == 1) ) {
+ doubleclick = 1;
+ }
+
+ //Double click on mouse button release, if we're over the label column, edit
+ //the item name
+ if ( event->type == GDK_BUTTON_RELEASE && doubleclick) {
+ doubleclick = 0;
+ Gtk::TreeModel::Path path;
+ Gtk::TreeViewColumn* col = 0;
+ int x = static_cast<int>(event->x);
+ int y = static_cast<int>(event->y);
+ int x2 = 0;
+ int y2 = 0;
+ if ( _tree.get_path_at_pos( x, y, path, col, x2, y2 ) && col == _name_column) {
+ // Double click on the Layer name, enable editing
+ _text_renderer->property_editable() = true;
+ _tree.set_cursor (path, *_name_column, true);
+ grab_focus();
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Stores items in the highlight target vector to manipulate with the color selector
+ * @param iter Current tree item to store
+ */
+void ObjectsPanel::_storeHighlightTarget(const Gtk::TreeModel::iterator& iter)
+{
+ Gtk::TreeModel::Row row = *iter;
+ SPItem* item = row[_model->_colObject];
+ if (item)
+ {
+ _highlight_target.push_back(item);
+ }
+}
+
+/*
+ * Drap and drop within the tree
+ */
+bool ObjectsPanel::_handleDragDrop(const Glib::RefPtr<Gdk::DragContext>& /*context*/, int x, int y, guint /*time*/)
+{
+ int cell_x = 0, cell_y = 0;
+ Gtk::TreeModel::Path target_path;
+ Gtk::TreeView::Column *target_column;
+
+ //Set up our defaults and clear the source vector
+ _dnd_into = false;
+ _dnd_target = NULL;
+ _dnd_source.clear();
+
+ //Add all selected items to the source vector
+ _tree.get_selection()->selected_foreach_iter(sigc::mem_fun(*this, &ObjectsPanel::_storeDragSource));
+
+ if (_tree.get_path_at_pos (x, y, target_path, target_column, cell_x, cell_y)) {
+ // Are we before, inside or after the drop layer
+ Gdk::Rectangle rect;
+ _tree.get_background_area (target_path, *target_column, rect);
+ int cell_height = rect.get_height();
+ _dnd_into = (cell_y > (int)(cell_height * 1/4) && cell_y <= (int)(cell_height * 3/4));
+ if (cell_y > (int)(cell_height * 3/4)) {
+ Gtk::TreeModel::Path next_path = target_path;
+ next_path.next();
+ if (_store->iter_is_valid(_store->get_iter(next_path))) {
+ target_path = next_path;
+ } else {
+ // Dragging to the "end"
+ Gtk::TreeModel::Path up_path = target_path;
+ up_path.up();
+ if (_store->iter_is_valid(_store->get_iter(up_path))) {
+ // Drop into parent
+ target_path = up_path;
+ _dnd_into = true;
+ } else {
+ // Drop into the top level
+ _dnd_target = NULL;
+ }
+ }
+ }
+ Gtk::TreeModel::iterator iter = _store->get_iter(target_path);
+ if (_store->iter_is_valid(iter)) {
+ Gtk::TreeModel::Row row = *iter;
+ //Set the drop target. If we're not dropping into a group, we cannot
+ //drop into it, so set _dnd_into false.
+ _dnd_target = row[_model->_colObject];
+ if (!(SP_IS_GROUP(_dnd_target))) _dnd_into = false;
+ }
+ }
+
+ _takeAction(DRAGNDROP);
+
+ return false;
+}
+
+/**
+ * Stores all selected items as the drag source
+ * @param iter Current tree item
+ */
+void ObjectsPanel::_storeDragSource(const Gtk::TreeModel::iterator& iter)
+{
+ Gtk::TreeModel::Row row = *iter;
+ SPItem* item = row[_model->_colObject];
+ if (item)
+ {
+ _dnd_source.push_back(item);
+ }
+}
+
+/*
+ * Move a layer in response to a drag & drop action
+ */
+void ObjectsPanel::_doTreeMove( )
+{
+ g_assert(_desktop != NULL);
+ g_assert(_document != NULL);
+
+ std::vector<gchar *> idvector;
+
+ //Clear the desktop selection
+ _desktop->selection->clear();
+ while (!_dnd_source.empty())
+ {
+ SPItem *obj = _dnd_source.back();
+ _dnd_source.pop_back();
+
+ if (obj != _dnd_target) {
+ //Store the object id (for selection later) and move the object
+ idvector.push_back(g_strdup(obj->getId()));
+ obj->moveTo(_dnd_target, _dnd_into);
+ }
+ }
+
+ //Select items
+ while (!idvector.empty()) {
+ //Grab the id from the vector, get the item in the document and select it
+ gchar * id = idvector.back();
+ idvector.pop_back();
+ SPObject *obj = _document->getObjectById(id);
+ g_free(id);
+ if (obj && SP_IS_ITEM(obj)) {
+ SPItem *item = SP_ITEM(obj);
+ if (!SP_IS_GROUP(item) || SP_GROUP(item)->layerMode() != SPGroup::LAYER)
+ {
+ if (_desktop->selection->isEmpty()) _desktop->setCurrentLayer(item->parent);
+ _desktop->selection->add(item);
+ }
+ else
+ {
+ if (_desktop->selection->isEmpty()) _desktop->setCurrentLayer(item);
+ }
+ }
+ }
+
+ DocumentUndo::done( _desktop->doc() , SP_VERB_NONE,
+ _("Moved objects"));
+}
+
+/**
+ * Fires the action verb
+ */
+void ObjectsPanel::_fireAction( unsigned int code )
+{
+ if ( _desktop ) {
+ Verb *verb = Verb::get( code );
+ if ( verb ) {
+ SPAction *action = verb->get_action(_desktop);
+ if ( action ) {
+ sp_action_perform( action, NULL );
+ }
+ }
+ }
+}
+
+/**
+ * Executes the given button action during the idle time
+ */
+void ObjectsPanel::_takeAction( int val )
+{
+ if ( !_pending ) {
+ _pending = new InternalUIBounce();
+ _pending->_actionCode = val;
+ Glib::signal_timeout().connect( sigc::mem_fun(*this, &ObjectsPanel::_executeAction), 0 );
+ }
+}
+
+/**
+ * Executes the pending button action
+ */
+bool ObjectsPanel::_executeAction()
+{
+ // Make sure selected layer hasn't changed since the action was triggered
+ if ( _document && _pending)
+ {
+ int val = _pending->_actionCode;
+// SPObject* target = _pending->_target;
+
+ switch ( val ) {
+ case BUTTON_NEW:
+ {
+ _fireAction( SP_VERB_LAYER_NEW );
+ }
+ break;
+ case BUTTON_RENAME:
+ {
+ _fireAction( SP_VERB_LAYER_RENAME );
+ }
+ break;
+ case BUTTON_TOP:
+ {
+ if (_desktop->selection->isEmpty())
+ {
+ _fireAction( SP_VERB_LAYER_TO_TOP );
+ }
+ else
+ {
+ _fireAction( SP_VERB_SELECTION_TO_FRONT);
+ }
+ }
+ break;
+ case BUTTON_BOTTOM:
+ {
+ if (_desktop->selection->isEmpty())
+ {
+ _fireAction( SP_VERB_LAYER_TO_BOTTOM );
+ }
+ else
+ {
+ _fireAction( SP_VERB_SELECTION_TO_BACK);
+ }
+ }
+ break;
+ case BUTTON_UP:
+ {
+ if (_desktop->selection->isEmpty())
+ {
+ _fireAction( SP_VERB_LAYER_RAISE );
+ }
+ else
+ {
+ _fireAction( SP_VERB_SELECTION_RAISE );
+ }
+ }
+ break;
+ case BUTTON_DOWN:
+ {
+ if (_desktop->selection->isEmpty())
+ {
+ _fireAction( SP_VERB_LAYER_LOWER );
+ }
+ else
+ {
+ _fireAction( SP_VERB_SELECTION_LOWER );
+ }
+ }
+ break;
+ case BUTTON_DUPLICATE:
+ {
+ if (_desktop->selection->isEmpty())
+ {
+ _fireAction( SP_VERB_LAYER_DUPLICATE );
+ }
+ else
+ {
+ _fireAction( SP_VERB_EDIT_DUPLICATE );
+ }
+ }
+ break;
+ case BUTTON_DELETE:
+ {
+ if (_desktop->selection->isEmpty())
+ {
+ _fireAction( SP_VERB_LAYER_DELETE );
+ }
+ else
+ {
+ _fireAction( SP_VERB_EDIT_DELETE );
+ }
+ }
+ break;
+ case BUTTON_SOLO:
+ {
+ _fireAction( SP_VERB_LAYER_SOLO );
+ }
+ break;
+ case BUTTON_SHOW_ALL:
+ {
+ _fireAction( SP_VERB_LAYER_SHOW_ALL );
+ }
+ break;
+ case BUTTON_HIDE_ALL:
+ {
+ _fireAction( SP_VERB_LAYER_HIDE_ALL );
+ }
+ break;
+ case BUTTON_LOCK_OTHERS:
+ {
+ _fireAction( SP_VERB_LAYER_LOCK_OTHERS );
+ }
+ break;
+ case BUTTON_LOCK_ALL:
+ {
+ _fireAction( SP_VERB_LAYER_LOCK_ALL );
+ }
+ break;
+ case BUTTON_UNLOCK_ALL:
+ {
+ _fireAction( SP_VERB_LAYER_UNLOCK_ALL );
+ }
+ break;
+ case BUTTON_CLIPGROUP:
+ {
+ _fireAction ( SP_VERB_OBJECT_CREATE_CLIP_GROUP );
+ }
+ case BUTTON_SETCLIP:
+ {
+ _fireAction( SP_VERB_OBJECT_SET_CLIPPATH );
+ }
+ break;
+ case BUTTON_UNSETCLIP:
+ {
+ _fireAction( SP_VERB_OBJECT_UNSET_CLIPPATH );
+ }
+ break;
+ case BUTTON_SETMASK:
+ {
+ _fireAction( SP_VERB_OBJECT_SET_MASK );
+ }
+ break;
+ case BUTTON_UNSETMASK:
+ {
+ _fireAction( SP_VERB_OBJECT_UNSET_MASK );
+ }
+ break;
+ case BUTTON_GROUP:
+ {
+ _fireAction( SP_VERB_SELECTION_GROUP );
+ }
+ break;
+ case BUTTON_UNGROUP:
+ {
+ _fireAction( SP_VERB_SELECTION_UNGROUP );
+ }
+ break;
+ case BUTTON_COLLAPSE_ALL:
+ {
+ for (SPObject* obj = _document->getRoot()->firstChild(); obj != NULL; obj = obj->next) {
+ if (SP_IS_GROUP(obj)) {
+ _setCollapsed(SP_GROUP(obj));
+ }
+ }
+ _objectsChanged(_document->getRoot());
+ }
+ break;
+ case DRAGNDROP:
+ {
+ _doTreeMove( );
+ }
+ break;
+ }
+
+ delete _pending;
+ _pending = 0;
+ }
+
+ return false;
+}
+
+/**
+ * Handles an unsuccessful item label edit (escape pressed, etc.)
+ */
+void ObjectsPanel::_handleEditingCancelled()
+{
+ _text_renderer->property_editable() = false;
+}
+
+/**
+ * Handle a successful item label edit
+ * @param path Tree path of the item currently being edited
+ * @param new_text New label text
+ */
+void ObjectsPanel::_handleEdited(const Glib::ustring& path, const Glib::ustring& new_text)
+{
+ Gtk::TreeModel::iterator iter = _tree.get_model()->get_iter(path);
+ Gtk::TreeModel::Row row = *iter;
+
+ _renameObject(row, new_text);
+ _text_renderer->property_editable() = false;
+}
+
+/**
+ * Renames an item in the tree
+ * @param row Tree row
+ * @param name New label to give to the item
+ */
+void ObjectsPanel::_renameObject(Gtk::TreeModel::Row row, const Glib::ustring& name)
+{
+ if ( row && _desktop) {
+ SPItem* item = row[_model->_colObject];
+ if ( item ) {
+ gchar const* oldLabel = item->label();
+ if ( !name.empty() && (!oldLabel || name != oldLabel) ) {
+ item->setLabel(name.c_str());
+ DocumentUndo::done( _desktop->doc() , SP_VERB_NONE,
+ _("Rename object"));
+ }
+ }
+ }
+}
+
+/**
+ * A row selection function used by the tree that doesn't allow any new items to be selected.
+ * Currently, this is used to allow multi-item drag & drop.
+ */
+bool ObjectsPanel::_noSelection( Glib::RefPtr<Gtk::TreeModel> const & /*model*/, Gtk::TreeModel::Path const & /*path*/, bool /*currentlySelected*/ )
+{
+ return false;
+}
+
+/**
+ * Default row selection function taken from the layers dialog
+ */
+bool ObjectsPanel::_rowSelectFunction( Glib::RefPtr<Gtk::TreeModel> const & /*model*/, Gtk::TreeModel::Path const & /*path*/, bool currentlySelected )
+{
+ bool val = true;
+ if ( !currentlySelected && _toggleEvent )
+ {
+ GdkEvent* event = gtk_get_current_event();
+ if ( event ) {
+ // (keep these checks separate, so we know when to call gdk_event_free()
+ if ( event->type == GDK_BUTTON_PRESS ) {
+ GdkEventButton const* target = reinterpret_cast<GdkEventButton const*>(_toggleEvent);
+ GdkEventButton const* evtb = reinterpret_cast<GdkEventButton const*>(event);
+
+ if ( (evtb->window == target->window)
+ && (evtb->send_event == target->send_event)
+ && (evtb->time == target->time)
+ && (evtb->state == target->state)
+ )
+ {
+ // Ooooh! It's a magic one
+ val = false;
+ }
+ }
+ gdk_event_free(event);
+ }
+ }
+ return val;
+}
+
+/**
+ * Sets a group to be collapsed and recursively collapses its children
+ * @param group The group to collapse
+ */
+void ObjectsPanel::_setCollapsed(SPGroup * group)
+{
+ group->setExpanded(false);
+ group->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT);
+ for (SPObject *iter = group->children; iter != NULL; iter = iter->next)
+ {
+ if (SP_IS_GROUP(iter)) _setCollapsed(SP_GROUP(iter));
+ }
+}
+
+/**
+ * Sets a group to be expanded or collapsed
+ * @param iter Current tree item
+ * @param isexpanded Whether to expand or collapse
+ */
+void ObjectsPanel::_setExpanded(const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& /*path*/, bool isexpanded)
+{
+ Gtk::TreeModel::Row row = *iter;
+
+ SPItem* item = row[_model->_colObject];
+ if (item && SP_IS_GROUP(item))
+ {
+ if (isexpanded)
+ {
+ //If we're expanding, simply perform the expansion
+ SP_GROUP(item)->setExpanded(isexpanded);
+ item->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT);
+ }
+ else
+ {
+ //If we're collapsing, we need to recursively collapse, so call our helper function
+ _setCollapsed(SP_GROUP(item));
+ }
+ }
+}
+
+/**
+ * Callback for when the highlight color is changed
+ * @param csel Color selector
+ * @param cp Objects panel
+ */
+void sp_highlight_picker_color_mod(SPColorSelector *csel, GObject * cp)
+{
+ SPColor color;
+ float alpha = 0;
+ csel->base->getColorAlpha(color, alpha);
+ guint32 rgba = color.toRGBA32( alpha );
+
+ ObjectsPanel *ptr = reinterpret_cast<ObjectsPanel *>(cp);
+
+ //Set the highlight color for all items in the _highlight_target (all selected items)
+ for (std::vector<SPItem *>::iterator iter = ptr->_highlight_target.begin(); iter != ptr->_highlight_target.end(); ++iter)
+ {
+ SPItem * target = *iter;
+ target->setHighlightColor(rgba);
+ target->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT);
+ }
+ DocumentUndo::maybeDone(SP_ACTIVE_DOCUMENT, "highlight", SP_VERB_DIALOG_OBJECTS, _("Set object highlight color"));
+}
+
+/**
+ * Callback for when the opacity value is changed
+ */
+void ObjectsPanel::_opacityValueChanged()
+{
+ _blockCompositeUpdate = true;
+ _tree.get_selection()->selected_foreach_iter(sigc::mem_fun(*this, &ObjectsPanel::_opacityChangedIter));
+ DocumentUndo::maybeDone(_document, "opacity", SP_VERB_DIALOG_OBJECTS, _("Set object opacity"));
+ _blockCompositeUpdate = false;
+}
+
+/**
+ * Change the opacity of the selected items in the tree
+ * @param iter Current tree item
+ */
+void ObjectsPanel::_opacityChangedIter(const Gtk::TreeIter& iter)
+{
+ Gtk::TreeModel::Row row = *iter;
+ SPItem* item = row[_model->_colObject];
+ if (item)
+ {
+ item->style->opacity.set = TRUE;
+#if WITH_GTKMM_3_0
+ item->style->opacity.value = SP_SCALE24_FROM_FLOAT(_opacity_adjustment->get_value() / _opacity_adjustment->get_upper());
+#else
+ item->style->opacity.value = SP_SCALE24_FROM_FLOAT(_opacity_adjustment.get_value() / _opacity_adjustment.get_upper());
+#endif
+ item->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT);
+ }
+}
+
+/**
+ * Callback for when the blend mode is changed
+ */
+void ObjectsPanel::_blendValueChanged()
+{
+ _blockCompositeUpdate = true;
+ const Glib::ustring blendmode = _fe_cb.get_blend_mode();
+
+ _tree.get_selection()->selected_foreach_iter(sigc::bind<Glib::ustring>(sigc::mem_fun(*this, &ObjectsPanel::_blendChangedIter), blendmode));
+ DocumentUndo::done(_document, SP_VERB_DIALOG_OBJECTS, _("Set object blend mode"));
+ _blockCompositeUpdate = false;
+}
+
+/**
+ * Sets the blend mode of the selected tree items
+ * @param iter Current tree item
+ * @param blendmode Blend mode to set
+ */
+void ObjectsPanel::_blendChangedIter(const Gtk::TreeIter& iter, Glib::ustring blendmode)
+{
+ Gtk::TreeModel::Row row = *iter;
+ SPItem* item = row[_model->_colObject];
+ if (item)
+ {
+ //Since blur and blend are both filters, we need to set both at the same time
+ SPStyle *style = item->style;
+ g_assert(style != NULL);
+
+ if (blendmode != "normal") {
+ gdouble radius = 0;
+ if (item->style->getFilter()) {
+ for (SPObject *primitive = item->style->getFilter()->children; primitive && SP_IS_FILTER_PRIMITIVE(primitive); primitive = primitive->next) {
+ if (SP_IS_GAUSSIANBLUR(primitive)) {
+ Geom::OptRect bbox = item->bounds(SPItem::GEOMETRIC_BBOX);
+ if (bbox) {
+ radius = SP_GAUSSIANBLUR(primitive)->stdDeviation.getNumber();
+ }
+ }
+ }
+ }
+ SPFilter *filter = new_filter_simple_from_item(_document, item, blendmode.c_str(), radius);
+ sp_style_set_property_url(item, "filter", filter, false);
+ } else {
+ for (SPObject *primitive = item->style->getFilter()->children; primitive && SP_IS_FILTER_PRIMITIVE(primitive); primitive = primitive->next) {
+ if (SP_IS_FEBLEND(primitive)) {
+ primitive->deleteObject();
+ break;
+ }
+ }
+ if (!item->style->getFilter()->children) {
+ remove_filter(item, false);
+ }
+ }
+
+ item->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT);
+ }
+}
+
+/**
+ * Callback for when the blur value has changed
+ */
+void ObjectsPanel::_blurValueChanged()
+{
+ _blockCompositeUpdate = true;
+ _tree.get_selection()->selected_foreach_iter(sigc::bind<double>(sigc::mem_fun(*this, &ObjectsPanel::_blurChangedIter), _fe_blur.get_blur_value()));
+ DocumentUndo::maybeDone(_document, "blur", SP_VERB_DIALOG_OBJECTS, _("Set object blur"));
+ _blockCompositeUpdate = false;
+}
+
+/**
+ * Sets the blur value for the selected items in the tree
+ * @param iter Current tree item
+ * @param blur Blur value to set
+ */
+void ObjectsPanel::_blurChangedIter(const Gtk::TreeIter& iter, double blur)
+{
+ Gtk::TreeModel::Row row = *iter;
+ SPItem* item = row[_model->_colObject];
+ if (item)
+ {
+ //Since blur and blend are both filters, we need to set both at the same time
+ SPStyle *style = item->style;
+ if (style) {
+ Geom::OptRect bbox = item->bounds(SPItem::GEOMETRIC_BBOX);
+ double radius;
+ if (bbox) {
+ double perimeter = bbox->dimensions()[Geom::X] + bbox->dimensions()[Geom::Y]; // fixme: this is only half the perimeter, is that correct?
+ radius = blur * perimeter / 400;
+ } else {
+ radius = 0;
+ }
+
+ if (radius != 0) {
+ SPFilter *filter = modify_filter_gaussian_blur_from_item(_document, item, radius);
+ sp_style_set_property_url(item, "filter", filter, false);
+ } else if (item->style->filter.set && item->style->getFilter()) {
+ for (SPObject *primitive = item->style->getFilter()->children; primitive && SP_IS_FILTER_PRIMITIVE(primitive); primitive = primitive->next) {
+ if (SP_IS_GAUSSIANBLUR(primitive)) {
+ primitive->deleteObject();
+ break;
+ }
+ }
+ if (!item->style->getFilter()->children) {
+ remove_filter(item, false);
+ }
+ }
+ item->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT);
+ }
+ }
+}
+
+/**
+ * Constructor
+ */
+ObjectsPanel::ObjectsPanel() :
+ UI::Widget::Panel("", "/dialogs/objects", SP_VERB_DIALOG_OBJECTS),
+ _rootWatcher(0),
+ _deskTrack(),
+ _desktop(0),
+ _document(0),
+ _model(0),
+ _pending(0),
+ _toggleEvent(0),
+ _defer_target(),
+ _composite_vbox(false, 0),
+ _opacity_vbox(false, 0),
+ _opacity_label(_("Opacity:")),
+ _opacity_label_unit(_("%")),
+#if WITH_GTKMM_3_0
+ _opacity_adjustment(Gtk::Adjustment::create(100.0, 0.0, 100.0, 1.0, 1.0, 0.0)),
+#else
+ _opacity_adjustment(100.0, 0.0, 100.0, 1.0, 1.0, 0.0),
+#endif
+ _opacity_hscale(_opacity_adjustment),
+ _opacity_spin_button(_opacity_adjustment, 0.01, 1),
+ _fe_cb(UI::Widget::SimpleFilterModifier::BLEND),
+ _fe_vbox(false, 0),
+ _fe_alignment(1, 1, 1, 1),
+ _fe_blur(UI::Widget::SimpleFilterModifier::BLUR),
+ _blur_vbox(false, 0),
+ _blur_alignment(1, 1, 1, 1),
+ _colorSelectorDialog("dialogs.colorpickerwindow")
+{
+ //Create the tree model and store
+ ModelColumns *zoop = new ModelColumns();
+ _model = zoop;
+
+ _store = Gtk::TreeStore::create( *zoop );
+
+ //Set up the tree
+ _tree.set_model( _store );
+ _tree.set_headers_visible(false);
+ _tree.set_reorderable(true);
+ _tree.enable_model_drag_dest (Gdk::ACTION_MOVE);
+
+ //Create the column CellRenderers
+ //Visible
+ Inkscape::UI::Widget::ImageToggler *eyeRenderer = Gtk::manage( new Inkscape::UI::Widget::ImageToggler(
+ INKSCAPE_ICON("object-visible"), INKSCAPE_ICON("object-hidden")) );
+ int visibleColNum = _tree.append_column("vis", *eyeRenderer) - 1;
+ eyeRenderer->property_activatable() = true;
+ Gtk::TreeViewColumn* col = _tree.get_column(visibleColNum);
+ if ( col ) {
+ col->add_attribute( eyeRenderer->property_active(), _model->_colVisible );
+ }
+
+ //Locked
+ Inkscape::UI::Widget::ImageToggler * renderer = Gtk::manage( new Inkscape::UI::Widget::ImageToggler(
+ INKSCAPE_ICON("object-locked"), INKSCAPE_ICON("object-unlocked")) );
+ int lockedColNum = _tree.append_column("lock", *renderer) - 1;
+ renderer->property_activatable() = true;
+ col = _tree.get_column(lockedColNum);
+ if ( col ) {
+ col->add_attribute( renderer->property_active(), _model->_colLocked );
+ }
+
+ //Type
+ Inkscape::UI::Widget::LayerTypeIcon * typeRenderer = Gtk::manage( new Inkscape::UI::Widget::LayerTypeIcon());
+ int typeColNum = _tree.append_column("type", *typeRenderer) - 1;
+ typeRenderer->property_activatable() = true;
+ col = _tree.get_column(typeColNum);
+ if ( col ) {
+ col->add_attribute( typeRenderer->property_active(), _model->_colType );
+ }
+
+ //Insert order (LiamW: unused)
+ /*Inkscape::UI::Widget::InsertOrderIcon * insertRenderer = Gtk::manage( new Inkscape::UI::Widget::InsertOrderIcon());
+ int insertColNum = _tree.append_column("type", *insertRenderer) - 1;
+ col = _tree.get_column(insertColNum);
+ if ( col ) {
+ col->add_attribute( insertRenderer->property_active(), _model->_colInsertOrder );
+ }*/
+
+ //Clip/mask
+ Inkscape::UI::Widget::ClipMaskIcon * clipRenderer = Gtk::manage( new Inkscape::UI::Widget::ClipMaskIcon());
+ int clipColNum = _tree.append_column("clipmask", *clipRenderer) - 1;
+ col = _tree.get_column(clipColNum);
+ if ( col ) {
+ col->add_attribute( clipRenderer->property_active(), _model->_colClipMask );
+ }
+
+ //Highlight
+ Inkscape::UI::Widget::HighlightPicker * highlightRenderer = Gtk::manage( new Inkscape::UI::Widget::HighlightPicker());
+ int highlightColNum = _tree.append_column("highlight", *highlightRenderer) - 1;
+ col = _tree.get_column(highlightColNum);
+ if ( col ) {
+ col->add_attribute( highlightRenderer->property_active(), _model->_colHighlight );
+ }
+
+ //Label
+ _text_renderer = Gtk::manage(new Gtk::CellRendererText());
+ int nameColNum = _tree.append_column("Name", *_text_renderer) - 1;
+ _name_column = _tree.get_column(nameColNum);
+ _name_column->add_attribute(_text_renderer->property_text(), _model->_colLabel);
+
+ //Set the expander and search columns
+ _tree.set_expander_column( *_tree.get_column(nameColNum) );
+ _tree.set_search_column(_model->_colLabel);
+
+ //Set up the tree selection
+ _tree.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
+ _selectedConnection = _tree.get_selection()->signal_changed().connect( sigc::mem_fun(*this, &ObjectsPanel::_pushTreeSelectionToCurrent) );
+ _tree.get_selection()->set_select_function( sigc::mem_fun(*this, &ObjectsPanel::_rowSelectFunction) );
+
+ //Set up tree signals
+ _tree.signal_button_press_event().connect( sigc::mem_fun(*this, &ObjectsPanel::_handleButtonEvent), false );
+ _tree.signal_button_release_event().connect( sigc::mem_fun(*this, &ObjectsPanel::_handleButtonEvent), false );
+ _tree.signal_key_press_event().connect( sigc::mem_fun(*this, &ObjectsPanel::_handleKeyEvent), false );
+ _tree.signal_drag_drop().connect( sigc::mem_fun(*this, &ObjectsPanel::_handleDragDrop), false);
+ _tree.signal_row_collapsed().connect( sigc::bind<bool>(sigc::mem_fun(*this, &ObjectsPanel::_setExpanded), false));
+ _tree.signal_row_expanded().connect( sigc::bind<bool>(sigc::mem_fun(*this, &ObjectsPanel::_setExpanded), true));
+
+ //Set up the label editing signals
+ _text_renderer->signal_edited().connect( sigc::mem_fun(*this, &ObjectsPanel::_handleEdited) );
+ _text_renderer->signal_editing_canceled().connect( sigc::mem_fun(*this, &ObjectsPanel::_handleEditingCancelled) );
+
+ //Set up the scroller window and pack the page
+ _scroller.add( _tree );
+ _scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC );
+ _scroller.set_shadow_type(Gtk::SHADOW_IN);
+ Gtk::Requisition sreq;
+#if WITH_GTKMM_3_0
+ Gtk::Requisition sreq_natural;
+ _scroller.get_preferred_size(sreq_natural, sreq);
+#else
+ sreq = _scroller.size_request();
+#endif
+ int minHeight = 70;
+ if (sreq.height < minHeight) {
+ // Set a min height to see the layers when used with Ubuntu liboverlay-scrollbar
+ _scroller.set_size_request(sreq.width, minHeight);
+ }
+
+ _page.pack_start( _scroller, Gtk::PACK_EXPAND_WIDGET );
+
+ //Set up the compositing items
+ //Blend mode filter effect
+ _composite_vbox.pack_start(_fe_vbox, false, false, 2);
+ _fe_alignment.set_padding(0, 0, 4, 0);
+ _fe_alignment.add(_fe_cb);
+ _fe_vbox.pack_start(_fe_alignment, false, false, 0);
+ _blendConnection = _fe_cb.signal_blend_blur_changed().connect(sigc::mem_fun(*this, &ObjectsPanel::_blendValueChanged));
+
+ //Blur filter effect
+ _composite_vbox.pack_start(_blur_vbox, false, false, 2);
+ _blur_alignment.set_padding(0, 0, 4, 0);
+ _blur_alignment.add(_fe_blur);
+ _blur_vbox.pack_start(_blur_alignment, false, false, 0);
+ _blurConnection = _fe_blur.signal_blend_blur_changed().connect(sigc::mem_fun(*this, &ObjectsPanel::_blurValueChanged));
+
+ //Opacity
+ _composite_vbox.pack_start(_opacity_vbox, false, false, 2);
+ _opacity_label.set_alignment(Gtk::ALIGN_END, Gtk::ALIGN_CENTER);
+ _opacity_hbox.pack_start(_opacity_label, false, false, 3);
+ _opacity_vbox.pack_start(_opacity_hbox, false, false, 0);
+ _opacity_hbox.pack_start(_opacity_hscale, true, true, 0);
+ _opacity_hbox.pack_start(_opacity_spin_button, false, false, 0);
+ _opacity_hbox.pack_start(_opacity_label_unit, false, false, 3);
+ _opacity_hscale.set_draw_value(false);
+#if WITH_GTKMM_3_0
+ _opacityConnection = _opacity_adjustment->signal_value_changed().connect(sigc::mem_fun(*this, &ObjectsPanel::_opacityValueChanged));
+ _opacity_label.set_mnemonic_widget(_opacity_hscale);
+#else
+ _opacityConnection = _opacity_adjustment.signal_value_changed().connect(sigc::mem_fun(*this, &ObjectsPanel::_opacityValueChanged));
+ _opacity_label.set_mnemonic_widget(_opacity_hscale);
+#endif
+
+ //Keep the labels aligned
+ GtkSizeGroup *labels = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+ gtk_size_group_add_widget(labels, GTK_WIDGET(_opacity_label.gobj()));
+ gtk_size_group_add_widget(labels, GTK_WIDGET(_fe_cb.get_blur_label()->gobj()));
+ gtk_size_group_add_widget(labels, GTK_WIDGET(_fe_blur.get_blur_label()->gobj()));
+
+ //Pack the compositing functions and the button row
+ _page.pack_end(_composite_vbox, Gtk::PACK_SHRINK);
+ _page.pack_end(_buttonsRow, Gtk::PACK_SHRINK);
+
+ //Pack into the panel contents
+ _getContents()->pack_start(_page, Gtk::PACK_EXPAND_WIDGET);
+
+ SPDesktop* targetDesktop = getDesktop();
+
+ //Set up the button row
+
+
+ //Add object/layer
+ Gtk::Button* btn = Gtk::manage( new Gtk::Button() );
+ btn->set_tooltip_text(_("Add layer..."));
+#if GTK_CHECK_VERSION(3,10,0)
+ btn->set_image_from_icon_name(INKSCAPE_ICON("list-add"), Gtk::ICON_SIZE_SMALL_TOOLBAR);
+#else
+ Gtk::Image *image_add = Gtk::manage(new Gtk::Image());
+ image_add->set_from_icon_name(INKSCAPE_ICON("list-add"), Gtk::ICON_SIZE_SMALL_TOOLBAR);
+ btn->set_image(*image_add);
+#endif
+ btn->set_relief(Gtk::RELIEF_NONE);
+ btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_takeAction), (int)BUTTON_NEW) );
+ _buttonsSecondary.pack_start(*btn, Gtk::PACK_SHRINK);
+
+
+ //Remove object
+ btn = Gtk::manage( new Gtk::Button() );
+ btn->set_tooltip_text(_("Remove object"));
+#if GTK_CHECK_VERSION(3,10,0)
+ btn->set_image_from_icon_name(INKSCAPE_ICON("list-remove"), Gtk::ICON_SIZE_SMALL_TOOLBAR);
+#else
+ Gtk::Image *image_remove = Gtk::manage(new Gtk::Image());
+ image_remove->set_from_icon_name(INKSCAPE_ICON("list-remove"), Gtk::ICON_SIZE_SMALL_TOOLBAR);
+ btn->set_image(*image_remove);
+#endif
+ btn->set_relief(Gtk::RELIEF_NONE);
+ btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_takeAction), (int)BUTTON_DELETE) );
+ _watching.push_back( btn );
+ _buttonsSecondary.pack_start(*btn, Gtk::PACK_SHRINK);
+
+ //Move to bottom
+ btn = Gtk::manage( new Gtk::Button() );
+ btn->set_tooltip_text(_("Move To Bottom"));
+#if GTK_CHECK_VERSION(3,10,0)
+ btn->set_image_from_icon_name(INKSCAPE_ICON("go-bottom"), Gtk::ICON_SIZE_SMALL_TOOLBAR);
+#else
+ image_remove = Gtk::manage(new Gtk::Image());
+ image_remove->set_from_icon_name(INKSCAPE_ICON("go-bottom"), Gtk::ICON_SIZE_SMALL_TOOLBAR);
+ btn->set_image(*image_remove);
+#endif
+ btn->set_relief(Gtk::RELIEF_NONE);
+ btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_takeAction), (int)BUTTON_BOTTOM) );
+ _watchingNonBottom.push_back( btn );
+ _buttonsPrimary.pack_end(*btn, Gtk::PACK_SHRINK);
+
+ //Move down
+ btn = Gtk::manage( new Gtk::Button() );
+ btn->set_tooltip_text(_("Move Down"));
+#if GTK_CHECK_VERSION(3,10,0)
+ btn->set_image_from_icon_name(INKSCAPE_ICON("go-down"), Gtk::ICON_SIZE_SMALL_TOOLBAR);
+#else
+ image_remove = Gtk::manage(new Gtk::Image());
+ image_remove->set_from_icon_name(INKSCAPE_ICON("go-down"), Gtk::ICON_SIZE_SMALL_TOOLBAR);
+ btn->set_image(*image_remove);
+#endif
+ btn->set_relief(Gtk::RELIEF_NONE);
+ btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_takeAction), (int)BUTTON_DOWN) );
+ _watchingNonBottom.push_back( btn );
+ _buttonsPrimary.pack_end(*btn, Gtk::PACK_SHRINK);
+
+ //Move up
+ btn = Gtk::manage( new Gtk::Button() );
+ btn->set_tooltip_text(_("Move Up"));
+#if GTK_CHECK_VERSION(3,10,0)
+ btn->set_image_from_icon_name(INKSCAPE_ICON("go-up"), Gtk::ICON_SIZE_SMALL_TOOLBAR);
+#else
+ image_remove = Gtk::manage(new Gtk::Image());
+ image_remove->set_from_icon_name(INKSCAPE_ICON("go-up"), Gtk::ICON_SIZE_SMALL_TOOLBAR);
+ btn->set_image(*image_remove);
+#endif
+ btn->set_relief(Gtk::RELIEF_NONE);
+ btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_takeAction), (int)BUTTON_UP) );
+ _watchingNonTop.push_back( btn );
+ _buttonsPrimary.pack_end(*btn, Gtk::PACK_SHRINK);
+
+ //Move to top
+ btn = Gtk::manage( new Gtk::Button() );
+ btn->set_tooltip_text(_("Move To Top"));
+#if GTK_CHECK_VERSION(3,10,0)
+ btn->set_image_from_icon_name(INKSCAPE_ICON("go-top"), Gtk::ICON_SIZE_SMALL_TOOLBAR);
+#else
+ image_remove = Gtk::manage(new Gtk::Image());
+ image_remove->set_from_icon_name(INKSCAPE_ICON("go-top"), Gtk::ICON_SIZE_SMALL_TOOLBAR);
+ btn->set_image(*image_remove);
+#endif
+ btn->set_relief(Gtk::RELIEF_NONE);
+ btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_takeAction), (int)BUTTON_TOP) );
+ _watchingNonTop.push_back( btn );
+ _buttonsPrimary.pack_end(*btn, Gtk::PACK_SHRINK);
+
+ //Collapse all
+ btn = Gtk::manage( new Gtk::Button() );
+ btn->set_tooltip_text(_("Collapse All"));
+#if GTK_CHECK_VERSION(3,10,0)
+ btn->set_image_from_icon_name(INKSCAPE_ICON("gtk-unindent-ltr"), Gtk::ICON_SIZE_SMALL_TOOLBAR);
+#else
+ image_remove = Gtk::manage(new Gtk::Image());
+ image_remove->set_from_icon_name(INKSCAPE_ICON("gtk-unindent-ltr"), Gtk::ICON_SIZE_SMALL_TOOLBAR);
+ btn->set_image(*image_remove);
+#endif
+ btn->set_relief(Gtk::RELIEF_NONE);
+ btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_takeAction), (int)BUTTON_COLLAPSE_ALL) );
+ _watchingNonBottom.push_back( btn );
+ _buttonsPrimary.pack_end(*btn, Gtk::PACK_SHRINK);
+
+ _buttonsRow.pack_start(_buttonsSecondary, Gtk::PACK_EXPAND_WIDGET);
+ _buttonsRow.pack_end(_buttonsPrimary, Gtk::PACK_EXPAND_WIDGET);
+
+ _watching.push_back(&_composite_vbox);
+
+ //Set up the pop-up menu
+ // -------------------------------------------------------
+ {
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RENAME, 0, "Rename", (int)BUTTON_RENAME ) );
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_EDIT_DUPLICATE, 0, "Duplicate", (int)BUTTON_DUPLICATE ) );
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_NEW, 0, "New", (int)BUTTON_NEW ) );
+
+ _popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem()));
+
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_SOLO, 0, "Solo", (int)BUTTON_SOLO ) );
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_SHOW_ALL, 0, "Show All", (int)BUTTON_SHOW_ALL ) );
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_HIDE_ALL, 0, "Hide All", (int)BUTTON_HIDE_ALL ) );
+
+ _popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem()));
+
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOCK_OTHERS, 0, "Lock Others", (int)BUTTON_LOCK_OTHERS ) );
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOCK_ALL, 0, "Lock All", (int)BUTTON_LOCK_ALL ) );
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_UNLOCK_ALL, 0, "Unlock All", (int)BUTTON_UNLOCK_ALL ) );
+
+ _popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem()));
+
+ _watchingNonTop.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_RAISE, GTK_STOCK_GO_UP, "Up", (int)BUTTON_UP ) );
+ _watchingNonBottom.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_LOWER, GTK_STOCK_GO_DOWN, "Down", (int)BUTTON_DOWN ) );
+
+ _popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem()));
+
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_GROUP, 0, "Group", (int)BUTTON_GROUP ) );
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_UNGROUP, 0, "Ungroup", (int)BUTTON_UNGROUP ) );
+
+ _popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem()));
+
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_SET_CLIPPATH, 0, "Set Clip", (int)BUTTON_SETCLIP ) );
+
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_CREATE_CLIP_GROUP, 0, "Create Clip Group", (int)BUTTON_CLIPGROUP ) );
+
+ //will never be implemented
+ //_watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_SET_INVERSE_CLIPPATH, 0, "Set Inverse Clip", (int)BUTTON_SETINVCLIP ) );
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_UNSET_CLIPPATH, 0, "Unset Clip", (int)BUTTON_UNSETCLIP ) );
+
+ _popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem()));
+
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_SET_MASK, 0, "Set Mask", (int)BUTTON_SETMASK ) );
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_UNSET_MASK, 0, "Unset Mask", (int)BUTTON_UNSETMASK ) );
+
+ _popupMenu.show_all_children();
+ }
+ // -------------------------------------------------------
+
+ //Set initial sensitivity of buttons
+ for ( std::vector<Gtk::Widget*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) {
+ (*it)->set_sensitive( false );
+ }
+ for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonTop.begin(); it != _watchingNonTop.end(); ++it ) {
+ (*it)->set_sensitive( false );
+ }
+ for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonBottom.begin(); it != _watchingNonBottom.end(); ++it ) {
+ (*it)->set_sensitive( false );
+ }
+
+ //Set up the color selection dialog
+ GtkWidget *dlg = GTK_WIDGET(_colorSelectorDialog.gobj());
+ sp_transientize(dlg);
+
+ _colorSelectorDialog.hide();
+ _colorSelectorDialog.set_title (_("Select Highlight Color"));
+ _colorSelectorDialog.set_border_width (4);
+ _colorSelectorDialog.property_modal() = true;
+ _colorSelector = SP_COLOR_SELECTOR(sp_color_selector_new(SP_TYPE_COLOR_NOTEBOOK));
+ _colorSelectorDialog.get_vbox()->pack_start (
+ *Glib::wrap(&_colorSelector->vbox), true, true, 0);
+
+ g_signal_connect(G_OBJECT(_colorSelector), "dragged",
+ G_CALLBACK(sp_highlight_picker_color_mod), (void *)this);
+ g_signal_connect(G_OBJECT(_colorSelector), "released",
+ G_CALLBACK(sp_highlight_picker_color_mod), (void *)this);
+ g_signal_connect(G_OBJECT(_colorSelector), "changed",
+ G_CALLBACK(sp_highlight_picker_color_mod), (void *)this);
+
+ gtk_widget_show(GTK_WIDGET(_colorSelector));
+
+ setDesktop( targetDesktop );
+
+ show_all_children();
+
+ //Connect the desktop changed connection
+ desktopChangeConn = _deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &ObjectsPanel::setDesktop) );
+ _deskTrack.connect(GTK_WIDGET(gobj()));
+}
+
+/**
+ * Destructor
+ */
+ObjectsPanel::~ObjectsPanel()
+{
+ //Close the highlight selection dialog
+ _colorSelectorDialog.hide();
+ _colorSelector = NULL;
+
+ //Set the desktop to null, which will disconnect all object watchers
+ setDesktop(NULL);
+
+ if ( _model )
+ {
+ delete _model;
+ _model = 0;
+ }
+
+ if (_pending) {
+ delete _pending;
+ _pending = 0;
+ }
+
+ if ( _toggleEvent )
+ {
+ gdk_event_free( _toggleEvent );
+ _toggleEvent = 0;
+ }
+
+ desktopChangeConn.disconnect();
+ _deskTrack.disconnect();
+}
+
+/**
+ * Sets the current document
+ */
+void ObjectsPanel::setDocument(SPDesktop* /*desktop*/, SPDocument* document)
+{
+ //Clear all object watchers
+ while (!_objectWatchers.empty())
+ {
+ ObjectsPanel::ObjectWatcher *w = _objectWatchers.back();
+ w->_repr->removeObserver(*w);
+ _objectWatchers.pop_back();
+ delete w;
+ }
+
+ //Delete the root watcher
+ if (_rootWatcher)
+ {
+ _rootWatcher->_repr->removeObserver(*_rootWatcher);
+ delete _rootWatcher;
+ _rootWatcher = NULL;
+ }
+
+ _document = document;
+
+ if (document && document->getRoot() && document->getRoot()->getRepr())
+ {
+ //Create a new root watcher for the document and then call _objectsChanged to fill the tree
+ _rootWatcher = new ObjectsPanel::ObjectWatcher(this, document->getRoot());
+ document->getRoot()->getRepr()->addObserver(*_rootWatcher);
+ _objectsChanged(document->getRoot());
+ }
+}
+
+/**
+ * Set the current panel desktop
+ */
+void ObjectsPanel::setDesktop( SPDesktop* desktop )
+{
+ Panel::setDesktop(desktop);
+
+ if ( desktop != _desktop ) {
+ _documentChangedConnection.disconnect();
+ _selectionChangedConnection.disconnect();
+ if ( _desktop ) {
+ _desktop = 0;
+ }
+
+ _desktop = Panel::getDesktop();
+ if ( _desktop ) {
+ //Connect desktop signals
+ _documentChangedConnection = _desktop->connectDocumentReplaced( sigc::mem_fun(*this, &ObjectsPanel::setDocument));
+ _selectionChangedConnection = _desktop->selection->connectChanged( sigc::mem_fun(*this, &ObjectsPanel::_objectsSelected));
+
+ setDocument(_desktop, _desktop->doc());
+ } else {
+ setDocument(NULL, NULL);
+ }
+ }
+ _deskTrack.setBase(desktop);
+}
+} //namespace Dialogs
+} //namespace UI
+} //namespace Inkscape
+
+//should be okay to put these here because they are never referenced anywhere else
+using namespace Inkscape::UI::Tools;
+
+void SPItem::setHighlightColor(guint32 const color)
+{
+ g_free(_highlightColor);
+ if (color & 0x000000ff)
+ {
+ _highlightColor = g_strdup_printf("%u", color);
+ }
+ else
+ {
+ _highlightColor = NULL;
+ }
+
+ NodeTool *tool = 0;
+ if (SP_ACTIVE_DESKTOP ) {
+ Inkscape::UI::Tools::ToolBase *ec = SP_ACTIVE_DESKTOP->event_context;
+ if (INK_IS_NODE_TOOL(ec)) {
+ tool = static_cast<NodeTool*>(ec);
+ tools_switch(tool->desktop, TOOLS_NODES);
+ }
+ }
+}
+
+void SPItem::unsetHighlightColor()
+{
+ g_free(_highlightColor);
+ _highlightColor = NULL;
+ NodeTool *tool = 0;
+ if (SP_ACTIVE_DESKTOP ) {
+ Inkscape::UI::Tools::ToolBase *ec = SP_ACTIVE_DESKTOP->event_context;
+ if (INK_IS_NODE_TOOL(ec)) {
+ tool = static_cast<NodeTool*>(ec);
+ tools_switch(tool->desktop, TOOLS_NODES);
+ }
+ }
+}
+
+/*
+ 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/objects.h b/src/ui/dialog/objects.h
new file mode 100644
index 000000000..74c2382ac
--- /dev/null
+++ b/src/ui/dialog/objects.h
@@ -0,0 +1,263 @@
+/*
+ * A simple dialog for objects UI.
+ *
+ * Authors:
+ * Theodore Janeczko
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_OBJECTS_PANEL_H
+#define SEEN_OBJECTS_PANEL_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+# include <glibmm/threads.h>
+#endif
+
+#include <gtkmm/box.h>
+#include <gtkmm/treeview.h>
+#include <gtkmm/treestore.h>
+#include <gtkmm/scrolledwindow.h>
+#include <gtkmm/dialog.h>
+#include "ui/widget/spinbutton.h"
+#include "ui/widget/panel.h"
+#include "ui/widget/object-composite-settings.h"
+#include "desktop-tracker.h"
+#include "ui/widget/style-subject.h"
+#include "selection.h"
+#include "ui/widget/filter-effect-chooser.h"
+
+class SPObject;
+class SPGroup;
+struct SPColorSelector;
+
+namespace Inkscape {
+
+namespace UI {
+namespace Dialog {
+
+
+/**
+ * A panel that displays objects.
+ */
+class ObjectsPanel : public UI::Widget::Panel
+{
+public:
+ ObjectsPanel();
+ virtual ~ObjectsPanel();
+
+ static ObjectsPanel& getInstance();
+
+ void setDesktop( SPDesktop* desktop );
+ void setDocument( SPDesktop* desktop, SPDocument* document);
+
+private:
+ //Internal Classes:
+ class ModelColumns;
+ class InternalUIBounce;
+ class ObjectWatcher;
+
+ //Connections, Watchers, Trackers:
+
+ //Document root watcher
+ ObjectsPanel::ObjectWatcher* _rootWatcher;
+
+ //All object watchers
+ std::vector<ObjectsPanel::ObjectWatcher*> _objectWatchers;
+
+ //Connection for when the desktop changes
+ sigc::connection desktopChangeConn;
+
+ //Connection for when the document changes
+ sigc::connection _documentChangedConnection;
+
+ //Connection for when the active selection in the document changes
+ sigc::connection _selectionChangedConnection;
+
+ //Connection for when the selection in the dialog changes
+ sigc::connection _selectedConnection;
+
+ //Connections for when the opacity/blend/blur of the active selection in the document changes
+ sigc::connection _opacityConnection;
+ sigc::connection _blendConnection;
+ sigc::connection _blurConnection;
+
+ //Desktop tracker for grabbing the desktop changed connection
+ DesktopTracker _deskTrack;
+
+ //Members:
+
+ //The current desktop
+ SPDesktop* _desktop;
+
+ //The current document
+ SPDocument* _document;
+
+ //Tree data model
+ ModelColumns* _model;
+
+ //Prevents the composite controls from updating
+ bool _blockCompositeUpdate;
+
+ //
+ InternalUIBounce* _pending;
+
+ //Whether the drag & drop was dragged into an item
+ gboolean _dnd_into;
+
+ //List of drag & drop source items
+ std::vector<SPItem*> _dnd_source;
+
+ //Drag & drop target item
+ SPItem* _dnd_target;
+
+ //List of items to change the highlight on
+ std::vector<SPItem*> _highlight_target;
+
+ //GUI Members:
+
+ GdkEvent* _toggleEvent;
+
+ Gtk::TreeModel::Path _defer_target;
+
+ Glib::RefPtr<Gtk::TreeStore> _store;
+ std::vector<Gtk::Widget*> _watching;
+ std::vector<Gtk::Widget*> _watchingNonTop;
+ std::vector<Gtk::Widget*> _watchingNonBottom;
+
+ Gtk::TreeView _tree;
+ Gtk::CellRendererText *_text_renderer;
+ Gtk::TreeView::Column *_name_column;
+#if WITH_GTKMM_3_0
+ Gtk::Box _buttonsRow;
+ Gtk::Box _buttonsPrimary;
+ Gtk::Box _buttonsSecondary;
+#else
+ Gtk::HBox _buttonsRow;
+ Gtk::HBox _buttonsPrimary;
+ Gtk::HBox _buttonsSecondary;
+#endif
+ Gtk::ScrolledWindow _scroller;
+ Gtk::Menu _popupMenu;
+ Inkscape::UI::Widget::SpinButton _spinBtn;
+ Gtk::VBox _page;
+
+ /* Composite Settings */
+ Gtk::VBox _composite_vbox;
+ Gtk::VBox _opacity_vbox;
+ Gtk::HBox _opacity_hbox;
+ Gtk::Label _opacity_label;
+ Gtk::Label _opacity_label_unit;
+#if WITH_GTKMM_3_0
+ Glib::RefPtr<Gtk::Adjustment> _opacity_adjustment;
+#else
+ Gtk::Adjustment _opacity_adjustment;
+#endif
+ Gtk::HScale _opacity_hscale;
+ Inkscape::UI::Widget::SpinButton _opacity_spin_button;
+
+ Inkscape::UI::Widget::SimpleFilterModifier _fe_cb;
+ Gtk::VBox _fe_vbox;
+ Gtk::Alignment _fe_alignment;
+ Inkscape::UI::Widget::SimpleFilterModifier _fe_blur;
+ Gtk::VBox _blur_vbox;
+ Gtk::Alignment _blur_alignment;
+
+ Gtk::Dialog _colorSelectorDialog;
+ SPColorSelector *_colorSelector;
+
+
+ //Methods:
+
+ ObjectsPanel(ObjectsPanel const &); // no copy
+ ObjectsPanel &operator=(ObjectsPanel const &); // no assign
+
+ void _styleButton( Gtk::Button& btn, char const* iconName, char const* tooltip );
+ void _fireAction( unsigned int code );
+
+ Gtk::MenuItem& _addPopupItem( SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback, int id );
+
+ void _setVisibleIter( const Gtk::TreeModel::iterator& iter, const bool visible );
+ void _setLockedIter( const Gtk::TreeModel::iterator& iter, const bool locked );
+
+ bool _handleButtonEvent(GdkEventButton *event);
+ bool _handleKeyEvent(GdkEventKey *event);
+
+ void _storeHighlightTarget(const Gtk::TreeModel::iterator& iter);
+ void _storeDragSource(const Gtk::TreeModel::iterator& iter);
+ bool _handleDragDrop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time);
+ void _handleEdited(const Glib::ustring& path, const Glib::ustring& new_text);
+ void _handleEditingCancelled();
+
+ void _doTreeMove();
+ void _renameObject(Gtk::TreeModel::Row row, const Glib::ustring& name);
+
+ void _pushTreeSelectionToCurrent();
+ void _selected_row_callback( const Gtk::TreeModel::iterator& iter, bool *setOpacity );
+
+ void _checkTreeSelection();
+
+ void _takeAction( int val );
+ bool _executeAction();
+
+ void _setExpanded( const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path, bool isexpanded );
+ void _setCollapsed(SPGroup * group);
+
+ bool _noSelection( Glib::RefPtr<Gtk::TreeModel> const & model, Gtk::TreeModel::Path const & path, bool b );
+ bool _rowSelectFunction( Glib::RefPtr<Gtk::TreeModel> const & model, Gtk::TreeModel::Path const & path, bool b );
+
+ void _compositingChanged( const Gtk::TreeModel::iterator& iter, bool *setValues );
+ void _updateComposite();
+ void _setCompositingValues(SPItem *item);
+
+ void _updateObject(SPObject *obj, bool recurse);
+ bool _checkForUpdated(const Gtk::TreeIter& iter, SPObject* obj);
+
+ void _objectsSelected(Selection *sel);
+ bool _checkForSelected(const Gtk::TreePath& path, const Gtk::TreeIter& iter, SPItem* item, bool scrollto);
+
+ void _objectsChanged(SPObject *obj);
+ void _addObject( SPObject* obj, Gtk::TreeModel::Row* parentRow );
+
+ void _opacityChangedIter(const Gtk::TreeIter& iter);
+ void _opacityValueChanged();
+
+ void _blendChangedIter(const Gtk::TreeIter& iter, Glib::ustring blendmode);
+ void _blendValueChanged();
+
+ void _blurChangedIter(const Gtk::TreeIter& iter, double blur);
+ void _blurValueChanged();
+
+
+ void setupDialog(const Glib::ustring &title);
+
+ friend void sp_highlight_picker_color_mod(SPColorSelector *csel, GObject *cp);
+
+};
+
+
+
+} //namespace Dialogs
+} //namespace UI
+} //namespace Inkscape
+
+
+
+#endif // SEEN_OBJECTS_PANEL_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/ocaldialogs.cpp b/src/ui/dialog/ocaldialogs.cpp
index f676e75fd..c4dd9df98 100644
--- a/src/ui/dialog/ocaldialogs.cpp
+++ b/src/ui/dialog/ocaldialogs.cpp
@@ -25,9 +25,9 @@
#include "path-prefix.h"
#include "filedialogimpl-gtkmm.h"
-#include "interface.h"
+#include "ui/interface.h"
#include "gc-core.h"
-#include <dialogs/dialog-events.h>
+#include "ui/dialog-events.h"
#include "io/sys.h"
#include "preferences.h"
diff --git a/src/ui/dialog/ocaldialogs.h b/src/ui/dialog/ocaldialogs.h
index e21030bcd..bd028c145 100644
--- a/src/ui/dialog/ocaldialogs.h
+++ b/src/ui/dialog/ocaldialogs.h
@@ -38,8 +38,7 @@
//Inkscape includes
#include "ui/dialog/filedialog.h"
-
-#include <dialogs/dialog-events.h>
+#include "ui/dialog-events.h"
struct _xmlNode;
typedef _xmlNode xmlNode;
diff --git a/src/ui/dialog/panel-dialog.h b/src/ui/dialog/panel-dialog.h
index 1fefd811e..b4a355083 100644
--- a/src/ui/dialog/panel-dialog.h
+++ b/src/ui/dialog/panel-dialog.h
@@ -49,19 +49,19 @@ public:
virtual UI::Widget::Panel &getPanel() { return _panel; }
protected:
- static void handle_deactivate_desktop(Inkscape::Application *application, SPDesktop *desktop, void *data) {
+ static void handle_deactivate_desktop(InkscapeApplication *application, SPDesktop *desktop, void *data) {
g_return_if_fail(data != NULL);
static_cast<PanelDialogBase *>(data)->_propagateDesktopDeactivated(application, desktop);
}
- static void _handle_activate_desktop(Inkscape::Application *application, SPDesktop *desktop, void *data) {
+ static void _handle_activate_desktop(InkscapeApplication *application, SPDesktop *desktop, void *data) {
g_return_if_fail(data != NULL);
static_cast<PanelDialogBase *>(data)->_propagateDesktopActivated(application, desktop);
}
inline virtual void _propagateDocumentReplaced(SPDesktop* desktop, SPDocument *document);
- inline virtual void _propagateDesktopActivated(Inkscape::Application *, SPDesktop *);
- inline virtual void _propagateDesktopDeactivated(Inkscape::Application *, SPDesktop *);
+ inline virtual void _propagateDesktopActivated(InkscapeApplication *, SPDesktop *);
+ inline virtual void _propagateDesktopDeactivated(InkscapeApplication *, SPDesktop *);
UI::Widget::Panel &_panel;
sigc::connection _document_replaced_connection;
@@ -134,14 +134,14 @@ void PanelDialogBase::_propagateDocumentReplaced(SPDesktop *desktop, SPDocument
_panel.signalDocumentReplaced().emit(desktop, document);
}
-void PanelDialogBase::_propagateDesktopActivated(Inkscape::Application *application, SPDesktop *desktop)
+void PanelDialogBase::_propagateDesktopActivated(InkscapeApplication *application, SPDesktop *desktop)
{
_document_replaced_connection =
desktop->connectDocumentReplaced(sigc::mem_fun(*this, &PanelDialogBase::_propagateDocumentReplaced));
_panel.signalActivateDesktop().emit(application, desktop);
}
-void PanelDialogBase::_propagateDesktopDeactivated(Inkscape::Application *application, SPDesktop *desktop)
+void PanelDialogBase::_propagateDesktopDeactivated(InkscapeApplication *application, SPDesktop *desktop)
{
_document_replaced_connection.disconnect();
_panel.signalDeactiveDesktop().emit(application, desktop);
diff --git a/src/ui/dialog/pixelartdialog.cpp b/src/ui/dialog/pixelartdialog.cpp
index 2d25f54d7..5113f172a 100644
--- a/src/ui/dialog/pixelartdialog.cpp
+++ b/src/ui/dialog/pixelartdialog.cpp
@@ -385,8 +385,8 @@ void PixelArtDialogImpl::vectorize()
if ( input.pixbuf->get_width() > 256
|| input.pixbuf->get_height() > 256 ) {
- char *msg = _("Image looks too big. Process may take a while and is"
- " wise to save your document before continue."
+ char *msg = _("Image looks too big. Process may take a while and it is"
+ " wise to save your document before continuing."
"\n\nContinue the procedure (without saving)?");
Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_WARNING,
Gtk::BUTTONS_OK_CANCEL, true);
diff --git a/src/ui/dialog/polar-arrange-tab.cpp b/src/ui/dialog/polar-arrange-tab.cpp
index a00b8fc02..80579c9d3 100644
--- a/src/ui/dialog/polar-arrange-tab.cpp
+++ b/src/ui/dialog/polar-arrange-tab.cpp
@@ -25,6 +25,7 @@
#include "desktop.h"
#include "sp-ellipse.h"
#include "sp-item-transform.h"
+#include <gtkmm/messagedialog.h>
namespace Inkscape {
namespace UI {
@@ -32,7 +33,11 @@ namespace Dialog {
PolarArrangeTab::PolarArrangeTab(ArrangeDialog *parent_)
: parent(parent_),
+#if WITH_GTKMM_3_0
+ parametersTable(),
+#else
parametersTable(3, 3, false),
+#endif
centerY("", "Y coordinate of the center", UNIT_TYPE_LINEAR),
centerX("", "X coordinate of the center", centerY),
radiusY("", "Y coordinate of the radius", UNIT_TYPE_LINEAR),
@@ -76,7 +81,11 @@ PolarArrangeTab::PolarArrangeTab(ArrangeDialog *parent_)
pack_start(arrangeOnParametersRadio, false, false);
centerLabel.set_text(_("Center X/Y:"));
+#if WITH_GTKMM_3_0
+ parametersTable.attach(centerLabel, 0, 0, 1, 1);
+#else
parametersTable.attach(centerLabel, 0, 1, 0, 1, Gtk::FILL);
+#endif
centerX.setDigits(2);
centerX.setIncrements(0.2, 0);
centerX.setRange(-10000, 10000);
@@ -85,11 +94,20 @@ PolarArrangeTab::PolarArrangeTab(ArrangeDialog *parent_)
centerY.setIncrements(0.2, 0);
centerY.setRange(-10000, 10000);
centerY.setValue(0, "px");
+#if WITH_GTKMM_3_0
+ parametersTable.attach(centerX, 1, 0, 1, 1);
+ parametersTable.attach(centerY, 2, 0, 1, 1);
+#else
parametersTable.attach(centerX, 1, 2, 0, 1, Gtk::FILL);
parametersTable.attach(centerY, 2, 3, 0, 1, Gtk::FILL);
+#endif
radiusLabel.set_text(_("Radius X/Y:"));
+#if WITH_GTKMM_3_0
+ parametersTable.attach(radiusLabel, 0, 1, 1, 1);
+#else
parametersTable.attach(radiusLabel, 0, 1, 1, 2, Gtk::FILL);
+#endif
radiusX.setDigits(2);
radiusX.setIncrements(0.2, 0);
radiusX.setRange(0.001, 10000);
@@ -98,11 +116,20 @@ PolarArrangeTab::PolarArrangeTab(ArrangeDialog *parent_)
radiusY.setIncrements(0.2, 0);
radiusY.setRange(0.001, 10000);
radiusY.setValue(100, "px");
+#if WITH_GTKMM_3_0
+ parametersTable.attach(radiusX, 1, 1, 1, 1);
+ parametersTable.attach(radiusY, 2, 1, 1, 1);
+#else
parametersTable.attach(radiusX, 1, 2, 1, 2, Gtk::FILL);
parametersTable.attach(radiusY, 2, 3, 1, 2, Gtk::FILL);
+#endif
angleLabel.set_text(_("Angle X/Y:"));
+#if WITH_GTKMM_3_0
+ parametersTable.attach(angleLabel, 0, 2, 1, 1);
+#else
parametersTable.attach(angleLabel, 0, 1, 2, 3, Gtk::FILL);
+#endif
angleX.setDigits(2);
angleX.setIncrements(0.2, 0);
angleX.setRange(-10000, 10000);
@@ -111,8 +138,13 @@ PolarArrangeTab::PolarArrangeTab(ArrangeDialog *parent_)
angleY.setIncrements(0.2, 0);
angleY.setRange(-10000, 10000);
angleY.setValue(180, "°");
+#if WITH_GTKMM_3_0
+ parametersTable.attach(angleX, 1, 2, 1, 1);
+ parametersTable.attach(angleY, 2, 2, 1, 1);
+#else
parametersTable.attach(angleX, 1, 2, 2, 3, Gtk::FILL);
parametersTable.attach(angleY, 2, 3, 2, 3, Gtk::FILL);
+#endif
pack_start(parametersTable, false, false);
rotateObjectsCheckBox.set_label(_("Rotate objects"));
diff --git a/src/ui/dialog/polar-arrange-tab.h b/src/ui/dialog/polar-arrange-tab.h
index f6c3b2906..f7d7bf11f 100644
--- a/src/ui/dialog/polar-arrange-tab.h
+++ b/src/ui/dialog/polar-arrange-tab.h
@@ -10,9 +10,22 @@
#ifndef INKSCAPE_UI_DIALOG_POLAR_ARRANGE_TAB_H
#define INKSCAPE_UI_DIALOG_POLAR_ARRANGE_TAB_H
+#if HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include "ui/widget/scalar-unit.h"
#include "ui/widget/anchor-selector.h"
#include "ui/dialog/arrange-tab.h"
-#include "ui/widget/scalar-unit.h"
+
+#include <gtkmm/radiobutton.h>
+#include <gtkmm/radiobuttongroup.h>
+
+#if WITH_GTKMM_3_0
+ #include <gtkmm/grid.h>
+#else
+ #include <gtkmm/table.h>
+#endif
namespace Inkscape {
namespace UI {
@@ -62,7 +75,11 @@ private:
Gtk::RadioButton arrangeOnLastCircleRadio;
Gtk::RadioButton arrangeOnParametersRadio;
+#if WITH_GTKMM_3_0
+ Gtk::Grid parametersTable;
+#else
Gtk::Table parametersTable;
+#endif
Gtk::Label centerLabel;
Inkscape::UI::Widget::ScalarUnit centerY;
diff --git a/src/ui/dialog/print.cpp b/src/ui/dialog/print.cpp
index 03ac9dc64..a015d28f9 100644
--- a/src/ui/dialog/print.cpp
+++ b/src/ui/dialog/print.cpp
@@ -13,13 +13,16 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
+
+#include <gtkmm.h>
+
#ifdef WIN32
#include <io.h>
#include <windows.h>
#endif
+#include "preferences.h"
#include "print.h"
-#include <gtkmm/stock.h>
#include "extension/internal/cairo-render-context.h"
#include "extension/internal/cairo-renderer.h"
@@ -44,14 +47,18 @@ static void draw_page(
gint /*page_nr*/,
gpointer user_data)
{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
struct workaround_gtkmm *junk = (struct workaround_gtkmm*)user_data;
//printf("%s %d\n",__FUNCTION__, page_nr);
if (junk->_tab->as_bitmap()) {
// Render as exported PNG
+ prefs->setBool("/dialogs/printing/asbitmap", true);
gdouble width = (junk->_doc)->getWidth().value("px");
gdouble height = (junk->_doc)->getHeight().value("px");
gdouble dpi = junk->_tab->bitmap_dpi();
+ prefs->setDouble("/dialogs/printing/dpi", dpi);
+
std::string tmp_png;
std::string tmp_base = "inkscape-print-png-XXXXXX";
@@ -92,7 +99,7 @@ static void draw_page(
cairo_get_matrix(cr, &m);
cairo_scale(cr, Inkscape::Util::Quantity::convert(1, "in", "pt") / dpi, Inkscape::Util::Quantity::convert(1, "in", "pt") / dpi);
// FIXME: why is the origin offset??
- cairo_set_source_surface(cr, png->cobj(), -16.0, -16.0);
+ cairo_set_source_surface(cr, png->cobj(), 0, 0);
cairo_paint(cr);
cairo_set_matrix(cr, &m);
}
@@ -106,6 +113,7 @@ static void draw_page(
}
else {
// Render as vectors
+ prefs->setBool("/dialogs/printing/asbitmap", false);
Inkscape::Extension::Internal::CairoRenderer renderer;
Inkscape::Extension::Internal::CairoRenderContext *ctx = renderer.createContext();
diff --git a/src/ui/dialog/spellcheck.cpp b/src/ui/dialog/spellcheck.cpp
index 8a4ddc57e..9faa8a2cb 100644
--- a/src/ui/dialog/spellcheck.cpp
+++ b/src/ui/dialog/spellcheck.cpp
@@ -23,9 +23,9 @@
#include "selection.h"
#include "desktop.h"
#include "desktop-handles.h"
-#include "tools-switch.h"
+#include "ui/tools-switch.h"
#include "ui/tools/text-tool.h"
-#include "interface.h"
+#include "ui/interface.h"
#include "preferences.h"
#include "sp-text.h"
#include "sp-flowtext.h"
@@ -347,7 +347,7 @@ SpellCheck::init(SPDesktop *d)
char *slashPos = strrchr(exeName, '\\');
if (slashPos)
*slashPos = '\0';
- g_print ("%s\n", exeName);
+ //g_print ("Aspell prefix path: %s\n", exeName);
#endif
_stops = 0;
@@ -356,54 +356,54 @@ SpellCheck::init(SPDesktop *d)
#ifdef HAVE_ASPELL
{
- AspellConfig *config = new_aspell_config();
+ AspellConfig *config = new_aspell_config();
#ifdef WIN32
- aspell_config_replace(config, "prefix", exeName);
+ aspell_config_replace(config, "prefix", exeName);
#endif
- aspell_config_replace(config, "lang", _lang.c_str());
- aspell_config_replace(config, "encoding", "UTF-8");
- AspellCanHaveError *ret = new_aspell_speller(config);
- delete_aspell_config(config);
- if (aspell_error(ret) != 0) {
- g_warning("Error: %s\n", aspell_error_message(ret));
- delete_aspell_can_have_error(ret);
- return false;
- }
- _speller = to_aspell_speller(ret);
+ aspell_config_replace(config, "lang", _lang.c_str());
+ aspell_config_replace(config, "encoding", "UTF-8");
+ AspellCanHaveError *ret = new_aspell_speller(config);
+ delete_aspell_config(config);
+ if (aspell_error(ret) != 0) {
+ g_warning("Error: %s\n", aspell_error_message(ret));
+ delete_aspell_can_have_error(ret);
+ return false;
+ }
+ _speller = to_aspell_speller(ret);
}
if (_lang2 != "") {
- AspellConfig *config = new_aspell_config();
+ AspellConfig *config = new_aspell_config();
#ifdef WIN32
- aspell_config_replace(config, "prefix", exeName);
+ aspell_config_replace(config, "prefix", exeName);
#endif
- aspell_config_replace(config, "lang", _lang2.c_str());
- aspell_config_replace(config, "encoding", "UTF-8");
- AspellCanHaveError *ret = new_aspell_speller(config);
- delete_aspell_config(config);
- if (aspell_error(ret) != 0) {
- g_warning("Error: %s\n", aspell_error_message(ret));
- delete_aspell_can_have_error(ret);
- return false;
- }
- _speller2 = to_aspell_speller(ret);
+ aspell_config_replace(config, "lang", _lang2.c_str());
+ aspell_config_replace(config, "encoding", "UTF-8");
+ AspellCanHaveError *ret = new_aspell_speller(config);
+ delete_aspell_config(config);
+ if (aspell_error(ret) != 0) {
+ g_warning("Error: %s\n", aspell_error_message(ret));
+ delete_aspell_can_have_error(ret);
+ return false;
+ }
+ _speller2 = to_aspell_speller(ret);
}
if (_lang3 != "") {
- AspellConfig *config = new_aspell_config();
+ AspellConfig *config = new_aspell_config();
#ifdef WIN32
- aspell_config_replace(config, "prefix", exeName);
+ aspell_config_replace(config, "prefix", exeName);
#endif
- aspell_config_replace(config, "lang", _lang3.c_str());
- aspell_config_replace(config, "encoding", "UTF-8");
- AspellCanHaveError *ret = new_aspell_speller(config);
- delete_aspell_config(config);
- if (aspell_error(ret) != 0) {
- g_warning("Error: %s\n", aspell_error_message(ret));
- delete_aspell_can_have_error(ret);
- return false;
- }
- _speller3 = to_aspell_speller(ret);
+ aspell_config_replace(config, "lang", _lang3.c_str());
+ aspell_config_replace(config, "encoding", "UTF-8");
+ AspellCanHaveError *ret = new_aspell_speller(config);
+ delete_aspell_config(config);
+ if (aspell_error(ret) != 0) {
+ g_warning("Error: %s\n", aspell_error_message(ret));
+ delete_aspell_can_have_error(ret);
+ return false;
+ }
+ _speller3 = to_aspell_speller(ret);
}
#endif /* HAVE_ASPELL */
diff --git a/src/ui/dialog/swatches.cpp b/src/ui/dialog/swatches.cpp
index 4f0cb211a..a3cfeeba8 100644
--- a/src/ui/dialog/swatches.cpp
+++ b/src/ui/dialog/swatches.cpp
@@ -745,11 +745,10 @@ void SwatchesPanel::setDesktop( SPDesktop* desktop )
class DocTrack
{
public:
- DocTrack(SPDocument *doc, sigc::connection &docDestroy, sigc::connection &gradientRsrcChanged, sigc::connection &defsChanged, sigc::connection &defsModified) :
- doc(doc),
+ DocTrack(SPDocument *doc, sigc::connection &gradientRsrcChanged, sigc::connection &defsChanged, sigc::connection &defsModified) :
+ doc(doc->doRef()),
updatePending(false),
lastGradientUpdate(0.0),
- docDestroy(docDestroy),
gradientRsrcChanged(gradientRsrcChanged),
defsChanged(defsChanged),
defsModified(defsModified)
@@ -774,10 +773,10 @@ public:
}
}
if (doc) {
- docDestroy.disconnect();
gradientRsrcChanged.disconnect();
defsChanged.disconnect();
defsModified.disconnect();
+ doc->doUnref();
doc = NULL;
}
}
@@ -798,7 +797,6 @@ public:
SPDocument *doc;
bool updatePending;
double lastGradientUpdate;
- sigc::connection docDestroy;
sigc::connection gradientRsrcChanged;
sigc::connection defsChanged;
sigc::connection defsModified;
@@ -894,12 +892,11 @@ void SwatchesPanel::_trackDocument( SwatchesPanel *panel, SPDocument *document )
}
docPerPanel[panel] = document;
if (!found) {
- sigc::connection conn0 = document->connectDestroy(sigc::bind(sigc::ptr_fun(&SwatchesPanel::handleDocumentDestroy), document));
sigc::connection conn1 = document->connectResourcesChanged( "gradient", sigc::bind(sigc::ptr_fun(&SwatchesPanel::handleGradientsChange), document) );
sigc::connection conn2 = document->getDefs()->connectRelease( sigc::hide(sigc::bind(sigc::ptr_fun(&SwatchesPanel::handleDefsModified), document)) );
sigc::connection conn3 = document->getDefs()->connectModified( sigc::hide(sigc::hide(sigc::bind(sigc::ptr_fun(&SwatchesPanel::handleDefsModified), document))) );
- DocTrack *dt = new DocTrack(document, conn0, conn1, conn2, conn3);
+ DocTrack *dt = new DocTrack(document, conn1, conn2, conn3);
docTrackings.push_back(dt);
if (docPalettes.find(document) == docPalettes.end()) {
@@ -928,13 +925,11 @@ static void recalcSwatchContents(SPDocument* doc,
{
std::vector<SPGradient*> newList;
- if (doc) {
- const GSList *gradients = doc->getResourceList("gradient");
- for (const GSList *item = gradients; item; item = item->next) {
- SPGradient* grad = SP_GRADIENT(item->data);
- if ( grad->isSwatch() ) {
- newList.push_back(SP_GRADIENT(item->data));
- }
+ const GSList *gradients = doc->getResourceList("gradient");
+ for (const GSList *item = gradients; item; item = item->next) {
+ SPGradient* grad = SP_GRADIENT(item->data);
+ if ( grad->isSwatch() ) {
+ newList.push_back(SP_GRADIENT(item->data));
}
}
@@ -973,37 +968,6 @@ static void recalcSwatchContents(SPDocument* doc,
}
}
-void SwatchesPanel::handleDocumentDestroy(SPDocument *document)
-{
- if (document) {
- for (std::vector<DocTrack*>::iterator it = docTrackings.begin(); it != docTrackings.end(); ++it){
- if ((*it)->doc == document) {
- delete *it;
- docTrackings.erase(it);
- break;
- }
- }
-
- if (docPalettes.find(document) != docPalettes.end()) {
- docPalettes.erase(document);
- }
-
- for (std::map<SwatchesPanel*, SPDocument*>::iterator it = docPerPanel.begin(); it != docPerPanel.end(); ++it) {
- if (it->second == document) {
- SwatchesPanel* swp = it->first;
- std::vector<SwatchPage*> pages = swp->_getSwatchSets();
- if ((swp->_currentIndex >= static_cast<int>(pages.size())) && (pages.size() > 0))
- {
- swp->_setSelectedIndex(swp->_getSwatchSets().size() - 1);
- }
- swp->_rebuild();
- docPerPanel.erase(it);
- break;
- }
- }
- }
-}
-
void SwatchesPanel::handleGradientsChange(SPDocument *document)
{
SwatchPage *docPalette = (docPalettes.find(document) != docPalettes.end()) ? docPalettes[document] : 0;
@@ -1178,45 +1142,38 @@ void SwatchesPanel::_handleAction( int setId, int itemId )
switch( setId ) {
case 3:
{
- _setSelectedIndex(itemId);
- }
- break;
- }
-}
+ std::vector<SwatchPage*> pages = _getSwatchSets();
+ if ( itemId >= 0 && itemId < static_cast<int>(pages.size()) ) {
+ _currentIndex = itemId;
-void SwatchesPanel::_setSelectedIndex( int index )
-{
- std::vector<SwatchPage*> pages = _getSwatchSets();
- if ( index >= 0 && index < static_cast<int>(pages.size()) ) {
- _currentIndex = index;
+ if ( !_prefs_path.empty() ) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setString(_prefs_path + "/palette", pages[_currentIndex]->_name);
+ }
- if ( !_prefs_path.empty() ) {
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- prefs->setString(_prefs_path + "/palette", pages[_currentIndex]->_name);
+ _rebuild();
+ }
}
-
- _rebuild();
+ break;
}
}
void SwatchesPanel::_rebuild()
{
std::vector<SwatchPage*> pages = _getSwatchSets();
- if (_currentIndex < static_cast<int>(pages.size())) {
- SwatchPage* curr = pages[_currentIndex];
- _holder->clear();
+ SwatchPage* curr = pages[_currentIndex];
+ _holder->clear();
- if ( curr->_prefWidth > 0 ) {
- _holder->setColumnPref( curr->_prefWidth );
- }
- _holder->freezeUpdates();
- // TODO restore once 'clear' works _holder->addPreview(_clear);
- _holder->addPreview(_remove);
- for ( boost::ptr_vector<ColorItem>::iterator it = curr->_colors.begin(); it != curr->_colors.end(); ++it) {
- _holder->addPreview(&*it);
- }
- _holder->thawUpdates();
+ if ( curr->_prefWidth > 0 ) {
+ _holder->setColumnPref( curr->_prefWidth );
+ }
+ _holder->freezeUpdates();
+ // TODO restore once 'clear' works _holder->addPreview(_clear);
+ _holder->addPreview(_remove);
+ for ( boost::ptr_vector<ColorItem>::iterator it = curr->_colors.begin(); it != curr->_colors.end(); ++it) {
+ _holder->addPreview(&*it);
}
+ _holder->thawUpdates();
}
} //namespace Dialogs
diff --git a/src/ui/dialog/swatches.h b/src/ui/dialog/swatches.h
index 3abb81d98..ca4c1687d 100644
--- a/src/ui/dialog/swatches.h
+++ b/src/ui/dialog/swatches.h
@@ -43,13 +43,11 @@ public:
virtual int getSelectedIndex() {return _currentIndex;} // temporary
protected:
- static void handleDocumentDestroy(SPDocument *document);
static void handleGradientsChange(SPDocument *document);
virtual void _updateFromSelection();
virtual void _handleAction( int setId, int itemId );
virtual void _setDocument( SPDocument *document );
- virtual void _setSelectedIndex( int index );
virtual void _rebuild();
virtual std::vector<SwatchPage*> _getSwatchSets() const;
diff --git a/src/ui/dialog/symbols.cpp b/src/ui/dialog/symbols.cpp
index 8e0d085a4..a17a03861 100644
--- a/src/ui/dialog/symbols.cpp
+++ b/src/ui/dialog/symbols.cpp
@@ -62,8 +62,20 @@
#include "widgets/icon.h"
#ifdef WITH_LIBVISIO
-#include <libvisio/libvisio.h>
-#include <libwpd-stream/libwpd-stream.h>
+ #include <libvisio/libvisio.h>
+
+ // TODO: Drop this check when librevenge is widespread.
+ #if WITH_LIBVISIO01
+ #include <librevenge-stream/librevenge-stream.h>
+
+ using librevenge::RVNGFileStream;
+ using librevenge::RVNGStringVector;
+ #else
+ #include <libwpd-stream/libwpd-stream.h>
+
+ typedef WPXFileStream RVNGFileStream;
+ typedef libvisio::VSDStringVector RVNGStringVector;
+ #endif
#endif
#include "verbs.h"
@@ -219,25 +231,27 @@ SymbolsDialog::SymbolsDialog( gchar const* prefsPath ) :
Gtk::Label* spacer = Gtk::manage(new Gtk::Label(""));
tools->pack_start(* Gtk::manage(spacer));
- in_sizes = 2; // Default 32px
+ // Pack size (controls display area)
+ pack_size = 2; // Default 32px
button = Gtk::manage(new Gtk::Button());
button->add(*Gtk::manage(Glib::wrap(
- sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-bigger")))) );
- button->set_tooltip_text(_("Make Icons bigger by zooming in."));
+ sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("pack-more")))) );
+ button->set_tooltip_text(_("Display more icons in row."));
button->set_relief( Gtk::RELIEF_NONE );
button->set_focus_on_click( false );
- button->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::zoomin));
+ button->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::packmore));
tools->pack_start(* button, Gtk::PACK_SHRINK);
button = Gtk::manage(new Gtk::Button());
button->add(*Gtk::manage(Glib::wrap(
- sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-smaller")))) );
- button->set_tooltip_text(_("Make Icons smaller by zooming out."));
+ sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("pack-less")))) );
+ button->set_tooltip_text(_("Display fewer icons in row."));
button->set_relief( Gtk::RELIEF_NONE );
button->set_focus_on_click( false );
- button->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::zoomout));
+ button->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::packless));
tools->pack_start(* button, Gtk::PACK_SHRINK);
+ // Toggle scale to fit on/off
fitSymbol = Gtk::manage(new Gtk::ToggleButton());
fitSymbol->add(*Gtk::manage(Glib::wrap(
sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-fit")))) );
@@ -248,6 +262,28 @@ SymbolsDialog::SymbolsDialog( gchar const* prefsPath ) :
fitSymbol->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::rebuild));
tools->pack_start(* fitSymbol, Gtk::PACK_SHRINK);
+ // Render size (scales symbols within display area)
+ scale_factor = 0; // Default 1:1 * pack_size/pack_size default
+ zoomOut = Gtk::manage(new Gtk::Button());
+ zoomOut->add(*Gtk::manage(Glib::wrap(
+ sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-smaller")))) );
+ zoomOut->set_tooltip_text(_("Make symbols smaller by zooming out."));
+ zoomOut->set_relief( Gtk::RELIEF_NONE );
+ zoomOut->set_focus_on_click( false );
+ zoomOut->set_sensitive( false );
+ zoomOut->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::zoomout));
+ tools->pack_start(* zoomOut, Gtk::PACK_SHRINK);
+
+ zoomIn = Gtk::manage(new Gtk::Button());
+ zoomIn->add(*Gtk::manage(Glib::wrap(
+ sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-bigger")))) );
+ zoomIn->set_tooltip_text(_("Make symbols bigger by zooming in."));
+ zoomIn->set_relief( Gtk::RELIEF_NONE );
+ zoomIn->set_focus_on_click( false );
+ zoomIn->set_sensitive( false );
+ zoomIn->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::zoomin));
+ tools->pack_start(* zoomIn, Gtk::PACK_SHRINK);
+
++row;
/**********************************************************/
@@ -262,8 +298,7 @@ SymbolsDialog::SymbolsDialog( gchar const* prefsPath ) :
// This might need to be a global variable so setTargetDesktop can modify it
SPDefs *defs = currentDocument->getDefs();
- sigc::connection defsModifiedConn = (SP_OBJECT(defs))->connectModified(
- sigc::mem_fun(*this, &SymbolsDialog::defsModified));
+ sigc::connection defsModifiedConn = defs->connectModified(sigc::mem_fun(*this, &SymbolsDialog::defsModified));
instanceConns.push_back(defsModifiedConn);
sigc::connection selectionChangedConn = currentDesktop->selection->connectChanged(
@@ -298,22 +333,44 @@ SymbolsDialog& SymbolsDialog::getInstance()
return *new SymbolsDialog();
}
+void SymbolsDialog::packless() {
+ if(pack_size < 4) {
+ pack_size++;
+ rebuild();
+ }
+}
+
+void SymbolsDialog::packmore() {
+ if(pack_size > 0) {
+ pack_size--;
+ rebuild();
+ }
+}
+
void SymbolsDialog::zoomin() {
- if(in_sizes < 4) {
- in_sizes++;
+ if(scale_factor < 4) {
+ scale_factor++;
rebuild();
}
}
void SymbolsDialog::zoomout() {
- if(in_sizes > 0) {
- in_sizes--;
+ if(scale_factor > -8) {
+ scale_factor--;
rebuild();
}
}
void SymbolsDialog::rebuild() {
+ if( fitSymbol->get_active() ) {
+ zoomIn->set_sensitive( false );
+ zoomOut->set_sensitive( false );
+ } else {
+ zoomIn->set_sensitive( true);
+ zoomOut->set_sensitive( true );
+ }
+
store->clear();
Glib::ustring symbolSetString = symbolSet->get_active_text();
@@ -449,14 +506,20 @@ void SymbolsDialog::iconChanged() {
// Read Visio stencil files
SPDocument* read_vss( gchar* fullname, gchar* filename ) {
- WPXFileStream input(fullname);
+ RVNGFileStream input(fullname);
if (!libvisio::VisioDocument::isSupported(&input)) {
return NULL;
}
- libvisio::VSDStringVector output;
+ RVNGStringVector output;
+#if WITH_LIBVISIO01
+ librevenge::RVNGSVGDrawingGenerator generator(output, "svg");
+
+ if (!libvisio::VisioDocument::parseStencils(&input, &generator)) {
+#else
if (!libvisio::VisioDocument::generateSVGStencils(&input, output)) {
+#endif
return NULL;
}
@@ -594,11 +657,11 @@ GSList* SymbolsDialog::symbols_in_doc_recursive (SPObject *r, GSList *l)
g_return_val_if_fail(r != NULL, l);
// Stop multiple counting of same symbol
- if( SP_IS_USE(r) ) {
+ if ( dynamic_cast<SPUse *>(r) ) {
return l;
}
- if( SP_IS_SYMBOL(r) ) {
+ if ( dynamic_cast<SPSymbol *>(r) ) {
l = g_slist_prepend (l, r);
}
@@ -613,13 +676,14 @@ GSList* SymbolsDialog::symbols_in_doc( SPDocument* symbolDocument ) {
GSList *l = NULL;
l = symbols_in_doc_recursive (symbolDocument->getRoot(), l );
+ l = g_slist_reverse( l );
return l;
}
GSList* SymbolsDialog::use_in_doc_recursive (SPObject *r, GSList *l)
{
- if( SP_IS_USE(r) ) {
+ if ( dynamic_cast<SPUse *>(r) ) {
l = g_slist_prepend (l, r);
}
@@ -644,8 +708,9 @@ gchar const* SymbolsDialog::style_from_use( gchar const* id, SPDocument* documen
gchar const* style = 0;
GSList* l = use_in_doc( document );
for( ; l != NULL; l = l->next ) {
- SPObject* use = SP_OBJECT(l->data);
- if( SP_IS_USE( use ) ) {
+ SPObject *obj = reinterpret_cast<SPObject *>(l->data);
+ SPUse *use = dynamic_cast<SPUse *>(obj);
+ if ( use ) {
gchar const *href = use->getRepr()->attribute("xlink:href");
if( href ) {
Glib::ustring href2(href);
@@ -665,8 +730,9 @@ void SymbolsDialog::add_symbols( SPDocument* symbolDocument ) {
GSList* l = symbols_in_doc( symbolDocument );
for( ; l != NULL; l = l->next ) {
- SPObject* symbol = SP_OBJECT(l->data);
- if (SP_IS_SYMBOL(symbol)) {
+ SPObject *obj = reinterpret_cast<SPObject *>(l->data);
+ SPSymbol *symbol = dynamic_cast<SPSymbol *>(obj);
+ if (symbol) {
add_symbol( symbol );
}
}
@@ -755,8 +821,9 @@ SymbolsDialog::draw_symbol(SPObject *symbol)
previewDocument->getRoot()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
previewDocument->ensureUpToDate();
- SPItem *item = SP_ITEM(object_temp);
- unsigned psize = SYMBOL_ICON_SIZES[in_sizes];
+ SPItem *item = dynamic_cast<SPItem *>(object_temp);
+ g_assert(item != NULL);
+ unsigned psize = SYMBOL_ICON_SIZES[pack_size];
Glib::RefPtr<Gdk::Pixbuf> pixbuf(NULL);
// We could use cache here, but it doesn't really work with the structure
@@ -778,6 +845,8 @@ SymbolsDialog::draw_symbol(SPObject *symbol)
if( fitSymbol->get_active() )
scale = psize / std::max(width, height);
+ else
+ scale = pow( 2.0, scale_factor/2.0 ) * psize / 32.0;
pixbuf = Glib::wrap(render_pixbuf(renderDrawing, scale, *dbox, psize));
}
diff --git a/src/ui/dialog/symbols.h b/src/ui/dialog/symbols.h
index 8021fb0c1..5dc1e3cad 100644
--- a/src/ui/dialog/symbols.h
+++ b/src/ui/dialog/symbols.h
@@ -65,6 +65,8 @@ private:
static SymbolColumns *getColumns();
+ void packless();
+ void packmore();
void zoomin();
void zoomout();
void rebuild();
@@ -95,13 +97,18 @@ private:
std::map<Glib::ustring, SPDocument*> symbolSets;
// Index into sizes which is selected
- int in_sizes;
+ int pack_size;
+
+ // Scale factor
+ int scale_factor;
Glib::RefPtr<Gtk::ListStore> store;
Gtk::ComboBoxText* symbolSet;
Gtk::IconView* iconView;
Gtk::Button* addSymbol;
Gtk::Button* removeSymbol;
+ Gtk::Button* zoomIn;
+ Gtk::Button* zoomOut;
Gtk::ToggleButton* fitSymbol;
void setTargetDesktop(SPDesktop *desktop);
diff --git a/src/ui/dialog/tags.cpp b/src/ui/dialog/tags.cpp
new file mode 100644
index 000000000..8a104d137
--- /dev/null
+++ b/src/ui/dialog/tags.cpp
@@ -0,0 +1,1166 @@
+/*
+ * A simple panel for tags
+ *
+ * Authors:
+ * Theodore Janeczko
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if WITH_GLIBMM_2_32
+# include <glibmm/threads.h>
+#endif
+
+#include "tags.h"
+#include <gtkmm/widget.h>
+#include <gtkmm/icontheme.h>
+#include <gtkmm/imagemenuitem.h>
+#include <gtkmm/separatormenuitem.h>
+
+#include <glibmm/main.h>
+#include <glibmm/i18n.h>
+
+#include "desktop.h"
+#include "desktop-style.h"
+#include "document.h"
+#include "document-undo.h"
+#include "helper/action.h"
+#include "inkscape.h"
+#include "layer-fns.h"
+#include "layer-manager.h"
+#include "preferences.h"
+#include "sp-item.h"
+#include "sp-object.h"
+#include "sp-shape.h"
+#include "svg/css-ostringstream.h"
+#include "ui/icon-names.h"
+#include "ui/widget/layertypeicon.h"
+#include "ui/widget/addtoicon.h"
+#include "verbs.h"
+#include "widgets/icon.h"
+#include "xml/node.h"
+#include "xml/node-observer.h"
+#include "xml/repr.h"
+#include "sp-root.h"
+#include "ui/tools/tool-base.h" //"event-context.h"
+#include "selection.h"
+//#include "dialogs/dialog-events.h"
+#include "widgets/sp-color-notebook.h"
+#include "style.h"
+#include "filter-chemistry.h"
+#include "filters/blend.h"
+#include "filters/gaussian-blur.h"
+#include "sp-clippath.h"
+#include "sp-mask.h"
+#include "sp-tag.h"
+#include "sp-defs.h"
+#include "sp-tag-use.h"
+#include "sp-tag-use-reference.h"
+
+//#define DUMP_LAYERS 1
+
+namespace Inkscape {
+namespace UI {
+namespace Dialog {
+
+using Inkscape::XML::Node;
+
+TagsPanel& TagsPanel::getInstance()
+{
+ return *new TagsPanel();
+}
+
+enum {
+ COL_ADD = 1
+};
+
+enum {
+ BUTTON_NEW = 0,
+ BUTTON_TOP,
+ BUTTON_BOTTOM,
+ BUTTON_UP,
+ BUTTON_DOWN,
+ BUTTON_DELETE,
+ DRAGNDROP
+};
+
+class TagsPanel::ObjectWatcher : public Inkscape::XML::NodeObserver {
+public:
+ ObjectWatcher(TagsPanel* pnl, SPObject* obj, Inkscape::XML::Node * repr) :
+ _pnl(pnl),
+ _obj(obj),
+ _repr(repr),
+ _labelAttr(g_quark_from_string("inkscape:label"))
+ {}
+
+ ObjectWatcher(TagsPanel* pnl, SPObject* obj) :
+ _pnl(pnl),
+ _obj(obj),
+ _repr(obj->getRepr()),
+ _labelAttr(g_quark_from_string("inkscape:label"))
+ {}
+
+ virtual void notifyChildAdded( Node &/*node*/, Node &/*child*/, Node */*prev*/ )
+ {
+ if ( _pnl && _obj ) {
+ _pnl->_objectsChanged( _obj );
+ }
+ }
+ virtual void notifyChildRemoved( Node &/*node*/, Node &/*child*/, Node */*prev*/ )
+ {
+ if ( _pnl && _obj ) {
+ _pnl->_objectsChanged( _obj );
+ }
+ }
+ virtual void notifyChildOrderChanged( Node &/*node*/, Node &/*child*/, Node */*old_prev*/, Node */*new_prev*/ )
+ {
+ if ( _pnl && _obj ) {
+ _pnl->_objectsChanged( _obj );
+ }
+ }
+ virtual void notifyContentChanged( Node &/*node*/, Util::ptr_shared<char> /*old_content*/, Util::ptr_shared<char> /*new_content*/ ) {}
+ virtual void notifyAttributeChanged( Node &/*node*/, GQuark name, Util::ptr_shared<char> /*old_value*/, Util::ptr_shared<char> /*new_value*/ ) {
+ if ( _pnl && _obj ) {
+ if ( name == _labelAttr ) {
+ _pnl->_updateObject( _obj);
+ }
+ }
+ }
+
+ TagsPanel* _pnl;
+ SPObject* _obj;
+ Inkscape::XML::Node* _repr;
+ GQuark _labelAttr;
+};
+
+class TagsPanel::InternalUIBounce
+{
+public:
+ int _actionCode;
+};
+
+void TagsPanel::_styleButton( Gtk::Button& btn, SPDesktop *desktop, unsigned int code, char const* iconName, char const* tooltip )
+{
+ bool set = false;
+
+ if ( iconName ) {
+ GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, iconName );
+ gtk_widget_show( child );
+ btn.add( *manage(Glib::wrap(child)) );
+ btn.set_relief(Gtk::RELIEF_NONE);
+ set = true;
+ }
+
+ if ( desktop ) {
+ Verb *verb = Verb::get( code );
+ if ( verb ) {
+ SPAction *action = verb->get_action(desktop);
+ if ( !set && action && action->image ) {
+ GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, action->image );
+ gtk_widget_show( child );
+ btn.add( *manage(Glib::wrap(child)) );
+ set = true;
+ }
+ }
+ }
+
+ btn.set_tooltip_text (tooltip);
+}
+
+
+Gtk::MenuItem& TagsPanel::_addPopupItem( SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback, int id )
+{
+ GtkWidget* iconWidget = 0;
+ const char* label = 0;
+
+ if ( iconName ) {
+ iconWidget = sp_icon_new( Inkscape::ICON_SIZE_MENU, iconName );
+ }
+
+ if ( desktop ) {
+ Verb *verb = Verb::get( code );
+ if ( verb ) {
+ SPAction *action = verb->get_action(desktop);
+ if ( !iconWidget && action && action->image ) {
+ iconWidget = sp_icon_new( Inkscape::ICON_SIZE_MENU, action->image );
+ }
+
+ if ( action ) {
+ label = action->name;
+ }
+ }
+ }
+
+ if ( !label && fallback ) {
+ label = fallback;
+ }
+
+ Gtk::Widget* wrapped = 0;
+ if ( iconWidget ) {
+ wrapped = manage(Glib::wrap(iconWidget));
+ wrapped->show();
+ }
+
+
+ Gtk::MenuItem* item = 0;
+
+ if (wrapped) {
+ item = Gtk::manage(new Gtk::ImageMenuItem(*wrapped, label, true));
+ } else {
+ item = Gtk::manage(new Gtk::MenuItem(label, true));
+ }
+
+ item->signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &TagsPanel::_takeAction), id));
+ _popupMenu.append(*item);
+
+ return *item;
+}
+
+void TagsPanel::_fireAction( unsigned int code )
+{
+ if ( _desktop ) {
+ Verb *verb = Verb::get( code );
+ if ( verb ) {
+ SPAction *action = verb->get_action(_desktop);
+ if ( action ) {
+ sp_action_perform( action, NULL );
+ }
+ }
+ }
+}
+
+void TagsPanel::_takeAction( int val )
+{
+ if ( !_pending ) {
+ _pending = new InternalUIBounce();
+ _pending->_actionCode = val;
+ Glib::signal_timeout().connect( sigc::mem_fun(*this, &TagsPanel::_executeAction), 0 );
+ }
+}
+
+bool TagsPanel::_executeAction()
+{
+ // Make sure selected layer hasn't changed since the action was triggered
+ if ( _pending)
+ {
+ int val = _pending->_actionCode;
+// SPObject* target = _pending->_target;
+ bool empty = _desktop->selection->isEmpty();
+
+ switch ( val ) {
+ case BUTTON_NEW:
+ {
+ _fireAction( SP_VERB_TAG_NEW );
+ }
+ break;
+ case BUTTON_TOP:
+ {
+ _fireAction( empty ? SP_VERB_LAYER_TO_TOP : SP_VERB_SELECTION_TO_FRONT);
+ }
+ break;
+ case BUTTON_BOTTOM:
+ {
+ _fireAction( empty ? SP_VERB_LAYER_TO_BOTTOM : SP_VERB_SELECTION_TO_BACK );
+ }
+ break;
+ case BUTTON_UP:
+ {
+ _fireAction( empty ? SP_VERB_LAYER_RAISE : SP_VERB_SELECTION_RAISE );
+ }
+ break;
+ case BUTTON_DOWN:
+ {
+ _fireAction( empty ? SP_VERB_LAYER_LOWER : SP_VERB_SELECTION_LOWER );
+ }
+ break;
+ case BUTTON_DELETE:
+ {
+ std::vector<SPObject *> todelete;
+ _tree.get_selection()->selected_foreach_iter(sigc::bind<std::vector<SPObject *>*>(sigc::mem_fun(*this, &TagsPanel::_checkForDeleted), &todelete));
+ for (std::vector<SPObject *>::iterator iter = todelete.begin(); iter != todelete.end(); ++iter) {
+ SPObject * obj = *iter;
+ if (obj && obj->parent && obj->getRepr() && obj->parent->getRepr()) {
+ //obj->parent->getRepr()->removeChild(obj->getRepr());
+ obj->deleteObject(true, true);
+ }
+ }
+ DocumentUndo::done(_document, SP_VERB_DIALOG_TAGS, _("Remove from selection set"));
+ }
+ break;
+ case DRAGNDROP:
+ {
+ _doTreeMove( );
+ }
+ break;
+ }
+
+ delete _pending;
+ _pending = 0;
+ }
+
+ return false;
+}
+
+
+class TagsPanel::ModelColumns : public Gtk::TreeModel::ColumnRecord
+{
+public:
+
+ ModelColumns()
+ {
+ add(_colParentObject);
+ add(_colObject);
+ add(_colLabel);
+ add(_colAddRemove);
+ add(_colAllowAddRemove);
+ }
+ virtual ~ModelColumns() {}
+
+ Gtk::TreeModelColumn<SPObject*> _colParentObject;
+ Gtk::TreeModelColumn<SPObject*> _colObject;
+ Gtk::TreeModelColumn<Glib::ustring> _colLabel;
+ Gtk::TreeModelColumn<bool> _colAddRemove;
+ Gtk::TreeModelColumn<bool> _colAllowAddRemove;
+};
+
+void TagsPanel::_checkForDeleted(const Gtk::TreeIter& iter, std::vector<SPObject *>* todelete)
+{
+ Gtk::TreeRow row = *iter;
+ SPObject * obj = row[_model->_colObject];
+ if (obj && obj->parent) {
+ todelete->push_back(obj);
+ }
+}
+
+void TagsPanel::_updateObject( SPObject *obj ) {
+ _store->foreach( sigc::bind<SPObject*>(sigc::mem_fun(*this, &TagsPanel::_checkForUpdated), obj) );
+}
+
+bool TagsPanel::_checkForUpdated(const Gtk::TreePath &/*path*/, const Gtk::TreeIter& iter, SPObject* obj)
+{
+ Gtk::TreeModel::Row row = *iter;
+ if ( obj == row[_model->_colObject] )
+ {
+ /*
+ * We get notified of layer update here (from layer->setLabel()) before layer->label() is set
+ * with the correct value (sp-object bug?). So use the inkscape:label attribute instead which
+ * has the correct value (bug #168351)
+ */
+ //row[_model->_colLabel] = layer->label() ? layer->label() : layer->getId();
+ gchar const *label;
+ SPTagUse * use = SP_IS_TAG_USE(obj) ? SP_TAG_USE(obj) : 0;
+ if (use && use->ref->isAttached()) {
+ label = use->ref->getObject()->getAttribute("inkscape:label");
+ } else {
+ label = obj->getAttribute("inkscape:label");
+ }
+ row[_model->_colLabel] = label ? label : obj->getId();
+ row[_model->_colAddRemove] = SP_IS_TAG(obj);
+ }
+
+ return false;
+}
+
+void TagsPanel::_objectsSelected( Selection *sel ) {
+
+ _selectedConnection.block();
+ _tree.get_selection()->unselect_all();
+ for (const GSList * iter = sel->list(); iter != NULL; iter = iter->next)
+ {
+ SPObject *obj = reinterpret_cast<SPObject *>(iter->data);
+ _store->foreach(sigc::bind<SPObject *>( sigc::mem_fun(*this, &TagsPanel::_checkForSelected), obj));
+ }
+ _selectedConnection.unblock();
+ _checkTreeSelection();
+}
+
+bool TagsPanel::_checkForSelected(const Gtk::TreePath &/*path*/, const Gtk::TreeIter& iter, SPObject* obj)
+{
+ Gtk::TreeModel::Row row = *iter;
+ SPObject * it = row[_model->_colObject];
+ if ( it && SP_IS_TAG_USE(it) && SP_TAG_USE(it)->ref->getObject() == obj )
+ {
+ Glib::RefPtr<Gtk::TreeSelection> select = _tree.get_selection();
+
+ select->select(iter);
+ }
+ return false;
+}
+
+// TODO does not look good that we're ignoring the passed in root. Investigate.
+void TagsPanel::_objectsChanged(SPObject* root)
+{
+ while (!_objectWatchers.empty())
+ {
+ TagsPanel::ObjectWatcher *w = _objectWatchers.back();
+ w->_repr->removeObserver(*w);
+ _objectWatchers.pop_back();
+ delete w;
+ }
+
+ if (_desktop) {
+ SPDocument* document = _desktop->doc();
+ SPDefs* root = document->getDefs();
+ if ( root ) {
+ _selectedConnection.block();
+ _store->clear();
+ _addObject( document, root, 0 );
+ _selectedConnection.unblock();
+ _objectsSelected(_desktop->selection);
+ _checkTreeSelection();
+ }
+ }
+}
+
+void TagsPanel::_addObject( SPDocument* doc, SPObject* obj, Gtk::TreeModel::Row* parentRow )
+{
+ if ( _desktop && obj ) {
+ for ( SPObject *child = obj->children; child != NULL; child = child->next) {
+ if (SP_IS_TAG(child))
+ {
+ Gtk::TreeModel::iterator iter = parentRow ? _store->prepend(parentRow->children()) : _store->prepend();
+ Gtk::TreeModel::Row row = *iter;
+ row[_model->_colObject] = child;
+ row[_model->_colParentObject] = NULL;
+ row[_model->_colLabel] = child->label() ? child->label() : child->getId();
+ row[_model->_colAddRemove] = true;
+ row[_model->_colAllowAddRemove] = true;
+
+ _tree.expand_to_path( _store->get_path(iter) );
+
+ TagsPanel::ObjectWatcher *w = new TagsPanel::ObjectWatcher(this, child);
+ child->getRepr()->addObserver(*w);
+ _objectWatchers.push_back(w);
+ _addObject( doc, child, &row );
+ }
+ }
+ if (SP_IS_TAG(obj) && obj->children)
+ {
+ Gtk::TreeModel::iterator iteritems = parentRow ? _store->append(parentRow->children()) : _store->prepend();
+ Gtk::TreeModel::Row rowitems = *iteritems;
+ rowitems[_model->_colObject] = NULL;
+ rowitems[_model->_colParentObject] = obj;
+ rowitems[_model->_colLabel] = _("Items");
+ rowitems[_model->_colAddRemove] = false;
+ rowitems[_model->_colAllowAddRemove] = false;
+
+ _tree.expand_to_path( _store->get_path(iteritems) );
+
+ for ( SPObject *child = obj->children; child != NULL; child = child->next) {
+ if (SP_IS_TAG_USE(child))
+ {
+ SPItem *item = SP_TAG_USE(child)->ref->getObject();
+ Gtk::TreeModel::iterator iter = _store->prepend(rowitems->children());
+ Gtk::TreeModel::Row row = *iter;
+ row[_model->_colObject] = child;
+ row[_model->_colParentObject] = NULL;
+ row[_model->_colLabel] = item ? (item->label() ? item->label() : item->getId()) : SP_TAG_USE(child)->href;
+ row[_model->_colAddRemove] = false;
+ row[_model->_colAllowAddRemove] = true;
+
+ if (SP_TAG(obj)->expanded()) {
+ _tree.expand_to_path( _store->get_path(iter) );
+ }
+
+ if (item) {
+ TagsPanel::ObjectWatcher *w = new TagsPanel::ObjectWatcher(this, child, item->getRepr());
+ item->getRepr()->addObserver(*w);
+ _objectWatchers.push_back(w);
+ }
+ }
+ }
+ }
+ }
+}
+
+void TagsPanel::_select_tag( SPTag * tag )
+{
+ for (SPObject * child = tag->children; child != NULL; child = child->next)
+ {
+ if (SP_IS_TAG(child)) {
+ _select_tag(SP_TAG(child));
+ } else if (SP_IS_TAG_USE(child)) {
+ SPObject * obj = SP_TAG_USE(child)->ref->getObject();
+ if (obj) {
+ if (_desktop->selection->isEmpty()) _desktop->setCurrentLayer(obj->parent);
+ _desktop->selection->add(obj);
+ }
+ }
+ }
+}
+
+void TagsPanel::_selected_row_callback( const Gtk::TreeModel::iterator& iter )
+{
+ if (iter) {
+ Gtk::TreeModel::Row row = *iter;
+ SPObject *obj = row[_model->_colObject];
+ if (obj) {
+ if (SP_IS_TAG(obj)) {
+ _select_tag(SP_TAG(obj));
+ } else if (SP_IS_TAG_USE(obj)) {
+ SPObject * item = SP_TAG_USE(obj)->ref->getObject();
+ if (item) {
+ if (_desktop->selection->isEmpty()) _desktop->setCurrentLayer(item->parent);
+ _desktop->selection->add(item);
+ }
+ }
+ }
+ }
+}
+
+void TagsPanel::_pushTreeSelectionToCurrent()
+{
+ _selectionChangedConnection.block();
+ // TODO hunt down the possible API abuse in getting NULL
+ if ( _desktop && _desktop->currentRoot() ) {
+ _desktop->selection->clear();
+ _tree.get_selection()->selected_foreach_iter( sigc::mem_fun(*this, &TagsPanel::_selected_row_callback));
+ }
+ _selectionChangedConnection.unblock();
+
+ _checkTreeSelection();
+}
+
+void TagsPanel::_checkTreeSelection()
+{
+ bool sensitive = _tree.get_selection()->count_selected_rows() > 0;
+ bool sensitiveNonTop = true;
+ bool sensitiveNonBottom = true;
+// if ( _tree.get_selection()->count_selected_rows() > 0 ) {
+// sensitive = true;
+//
+// SPObject* inTree = _selectedLayer();
+// if ( inTree ) {
+//
+// sensitiveNonTop = (Inkscape::Nex(inTree->parent, inTree) != 0);
+// sensitiveNonBottom = (Inkscape::previous_layer(inTree->parent, inTree) != 0);
+//
+// }
+// }
+
+
+ for ( std::vector<Gtk::Widget*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) {
+ (*it)->set_sensitive( sensitive );
+ }
+ for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonTop.begin(); it != _watchingNonTop.end(); ++it ) {
+ (*it)->set_sensitive( sensitiveNonTop );
+ }
+ for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonBottom.begin(); it != _watchingNonBottom.end(); ++it ) {
+ (*it)->set_sensitive( sensitiveNonBottom );
+ }
+}
+
+bool TagsPanel::_handleKeyEvent(GdkEventKey *event)
+{
+
+ switch (Inkscape::UI::Tools::get_group0_keyval(event)) {
+ case GDK_KEY_Return:
+ case GDK_KEY_KP_Enter:
+ case GDK_KEY_F2: {
+ Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected();
+ if (iter && !_text_renderer->property_editable()) {
+ Gtk::TreeRow row = *iter;
+ SPObject * obj = row[_model->_colObject];
+ if (obj && SP_IS_TAG(obj)) {
+ Gtk::TreeModel::Path *path = new Gtk::TreeModel::Path(iter);
+ // Edit the layer label
+ _text_renderer->property_editable() = true;
+ _tree.set_cursor(*path, *_name_column, true);
+ grab_focus();
+ return true;
+ }
+ }
+ }
+ case GDK_KEY_Delete: {
+ std::vector<SPObject *> todelete;
+ _tree.get_selection()->selected_foreach_iter(sigc::bind<std::vector<SPObject *>*>(sigc::mem_fun(*this, &TagsPanel::_checkForDeleted), &todelete));
+ if (!todelete.empty()) {
+ for (std::vector<SPObject *>::iterator iter = todelete.begin(); iter != todelete.end(); ++iter) {
+ SPObject * obj = *iter;
+ if (obj && obj->parent && obj->getRepr() && obj->parent->getRepr()) {
+ //obj->parent->getRepr()->removeChild(obj->getRepr());
+ obj->deleteObject(true, true);
+ }
+ }
+ DocumentUndo::done(_document, SP_VERB_DIALOG_TAGS, _("Remove from selection set"));
+ }
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+bool TagsPanel::_handleButtonEvent(GdkEventButton* event)
+{
+ static unsigned doubleclick = 0;
+
+ if ( (event->type == GDK_BUTTON_PRESS) && (event->button == 3) ) {
+ // TODO - fix to a better is-popup function
+ Gtk::TreeModel::Path path;
+ int x = static_cast<int>(event->x);
+ int y = static_cast<int>(event->y);
+ if ( _tree.get_path_at_pos( x, y, path ) ) {
+ _checkTreeSelection();
+ _popupMenu.popup(event->button, event->time);
+ if (_tree.get_selection()->is_selected(path)) {
+ return true;
+ }
+ }
+ }
+
+ if ( (event->type == GDK_BUTTON_PRESS) && (event->button == 1)) {
+ // Alt left click on the visible/lock columns - eat this event to keep row selection
+ Gtk::TreeModel::Path path;
+ Gtk::TreeViewColumn* col = 0;
+ int x = static_cast<int>(event->x);
+ int y = static_cast<int>(event->y);
+ int x2 = 0;
+ int y2 = 0;
+ if ( _tree.get_path_at_pos( x, y, path, col, x2, y2 ) ) {
+ if (col == _tree.get_column(COL_ADD-1)) {
+ down_at_add = true;
+ return true;
+ } else if ( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) & _tree.get_selection()->is_selected(path) ) {
+ _tree.get_selection()->set_select_function(sigc::mem_fun(*this, &TagsPanel::_noSelection));
+ _defer_target = path;
+ } else {
+ down_at_add = false;
+ }
+ } else {
+ down_at_add = false;
+ }
+ }
+
+ if ( event->type == GDK_BUTTON_RELEASE) {
+ _tree.get_selection()->set_select_function(sigc::mem_fun(*this, &TagsPanel::_rowSelectFunction));
+ }
+
+ // TODO - ImageToggler doesn't seem to handle Shift/Alt clicks - so we deal with them here.
+ if ( (event->type == GDK_BUTTON_RELEASE) && (event->button == 1)) {
+
+ Gtk::TreeModel::Path path;
+ Gtk::TreeViewColumn* col = 0;
+ int x = static_cast<int>(event->x);
+ int y = static_cast<int>(event->y);
+ int x2 = 0;
+ int y2 = 0;
+ if ( _tree.get_path_at_pos( x, y, path, col, x2, y2 ) ) {
+ if (_defer_target) {
+ if (_defer_target == path && !(event->x == 0 && event->y == 0))
+ {
+ _tree.set_cursor(path, *col, false);
+ }
+ _defer_target = Gtk::TreeModel::Path();
+ } else {
+ Gtk::TreeModel::Children::iterator iter = _tree.get_model()->get_iter(path);
+ Gtk::TreeModel::Row row = *iter;
+
+ SPObject* obj = row[_model->_colObject];
+
+ if (obj) {
+ if (col == _tree.get_column(COL_ADD - 1) && down_at_add) {
+ if (SP_IS_TAG(obj)) {
+ bool wasadded = false;
+ for (const GSList * iter = _desktop->selection->itemList(); iter != NULL; iter = iter->next)
+ {
+ SPObject *newobj = reinterpret_cast<SPObject *>(iter->data);
+ bool addchild = true;
+ for ( SPObject *child = obj->children; child != NULL; child = child->next) {
+ if (SP_IS_TAG_USE(child) && SP_TAG_USE(child)->ref->getObject() == newobj) {
+ addchild = false;
+ }
+ }
+ if (addchild) {
+ Inkscape::XML::Node *clone = _document->getReprDoc()->createElement("inkscape:tagref");
+ clone->setAttribute("xlink:href", g_strdup_printf("#%s", newobj->getRepr()->attribute("id")), false);
+ obj->appendChild(clone);
+ wasadded = true;
+ }
+ }
+ if (wasadded) {
+ DocumentUndo::done(_document, SP_VERB_DIALOG_TAGS, _("Add selection to set"));
+ }
+ } else {
+ std::vector<SPObject *> todelete;
+ // FIXME unnecessary use of XML tree
+ _tree.get_selection()->selected_foreach_iter(sigc::bind<std::vector<SPObject *>*>(sigc::mem_fun(*this, &TagsPanel::_checkForDeleted), &todelete));
+ if (!todelete.empty()) {
+ for (std::vector<SPObject *>::iterator iter = todelete.begin(); iter != todelete.end(); ++iter) {
+ SPObject * tobj = *iter;
+ if (tobj && tobj->parent && tobj->getRepr() && tobj->parent->getRepr()) {
+ //tobj->parent->getRepr()->removeChild(tobj->getRepr());
+ tobj->deleteObject(true, true);
+ }
+ }
+ } else if (obj && obj->parent && obj->getRepr() && obj->parent->getRepr()) {
+ obj->parent->getRepr()->removeChild(obj->getRepr());
+ }
+ DocumentUndo::done(_document, SP_VERB_DIALOG_TAGS, _("Remove from selection set"));
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ if ( (event->type == GDK_2BUTTON_PRESS) && (event->button == 1) ) {
+ doubleclick = 1;
+ }
+
+ if ( event->type == GDK_BUTTON_RELEASE && doubleclick) {
+ doubleclick = 0;
+ Gtk::TreeModel::Path path;
+ Gtk::TreeViewColumn* col = 0;
+ int x = static_cast<int>(event->x);
+ int y = static_cast<int>(event->y);
+ int x2 = 0;
+ int y2 = 0;
+ if ( _tree.get_path_at_pos( x, y, path, col, x2, y2 ) && col == _name_column) {
+ Gtk::TreeModel::Children::iterator iter = _tree.get_model()->get_iter(path);
+ Gtk::TreeModel::Row row = *iter;
+
+ SPObject* obj = row[_model->_colObject];
+ if (obj && (SP_IS_TAG(obj) || (SP_IS_TAG_USE(obj) && SP_TAG_USE(obj)->ref->getObject()))) {
+ // Double click on the Layer name, enable editing
+ _text_renderer->property_editable() = true;
+ _tree.set_cursor (path, *_name_column, true);
+ grab_focus();
+ }
+ }
+ }
+
+ return false;
+}
+
+void TagsPanel::_storeDragSource(const Gtk::TreeModel::iterator& iter)
+{
+ Gtk::TreeModel::Row row = *iter;
+ SPObject* obj = row[_model->_colObject];
+ SPTag* item = ( obj && SP_IS_TAG(obj) ) ? SP_TAG(obj) : 0;
+ if (item)
+ {
+ _dnd_source.push_back(item);
+ }
+}
+
+/*
+ * Drap and drop within the tree
+ * Save the drag source and drop target SPObjects and if its a drag between layers or into (sublayer) a layer
+ */
+bool TagsPanel::_handleDragDrop(const Glib::RefPtr<Gdk::DragContext>& /*context*/, int x, int y, guint /*time*/)
+{
+ int cell_x = 0, cell_y = 0;
+ Gtk::TreeModel::Path target_path;
+ Gtk::TreeView::Column *target_column;
+
+ _dnd_into = true;
+ _dnd_target = _document->getDefs();
+ _dnd_source.clear();
+ _tree.get_selection()->selected_foreach_iter(sigc::mem_fun(*this, &TagsPanel::_storeDragSource));
+
+ if (_dnd_source.empty()) {
+ return true;
+ }
+
+ if (_tree.get_path_at_pos (x, y, target_path, target_column, cell_x, cell_y)) {
+ // Are we before, inside or after the drop layer
+ Gdk::Rectangle rect;
+ _tree.get_background_area (target_path, *target_column, rect);
+ int cell_height = rect.get_height();
+ _dnd_into = (cell_y > (int)(cell_height * 1/3) && cell_y <= (int)(cell_height * 2/3));
+ if (cell_y > (int)(cell_height * 2/3)) {
+ Gtk::TreeModel::Path next_path = target_path;
+ next_path.next();
+ if (_store->iter_is_valid(_store->get_iter(next_path))) {
+ target_path = next_path;
+ } else {
+ // Dragging to the "end"
+ Gtk::TreeModel::Path up_path = target_path;
+ up_path.up();
+ if (_store->iter_is_valid(_store->get_iter(up_path))) {
+ // Drop into parent
+ target_path = up_path;
+ _dnd_into = true;
+ } else {
+ // Drop into the top level
+ _dnd_target = _document->getDefs();
+ _dnd_into = true;
+ }
+ }
+ }
+ Gtk::TreeModel::iterator iter = _store->get_iter(target_path);
+ if (_store->iter_is_valid(iter)) {
+ Gtk::TreeModel::Row row = *iter;
+ SPObject *obj = row[_model->_colObject];
+ SPObject *pobj = row[_model->_colParentObject];
+ if (obj) {
+ if (SP_IS_TAG(obj)) {
+ _dnd_target = SP_TAG(obj);
+ } else if (SP_IS_TAG(obj->parent)) {
+ _dnd_target = SP_TAG(obj->parent);
+ _dnd_into = true;
+ }
+ } else if (pobj && SP_IS_TAG(pobj)) {
+ _dnd_target = SP_TAG(pobj);
+ _dnd_into = true;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ _takeAction(DRAGNDROP);
+
+ return false;
+}
+
+/*
+ * Move a layer in response to a drag & drop action
+ */
+void TagsPanel::_doTreeMove( )
+{
+ if (_dnd_target) {
+ for (std::vector<SPTag *>::iterator iter = _dnd_source.begin(); iter != _dnd_source.end(); ++iter)
+ {
+ SPTag *src = *iter;
+ if (src != _dnd_target) {
+ src->moveTo(_dnd_target, _dnd_into);
+ }
+ }
+ _desktop->selection->clear();
+ while (!_dnd_source.empty())
+ {
+ SPTag *src = _dnd_source.back();
+ _select_tag(src);
+ _dnd_source.pop_back();
+ }
+ DocumentUndo::done( _desktop->doc() , SP_VERB_DIALOG_TAGS,
+ _("Moved sets"));
+ }
+}
+
+
+void TagsPanel::_handleEdited(const Glib::ustring& path, const Glib::ustring& new_text)
+{
+ Gtk::TreeModel::iterator iter = _tree.get_model()->get_iter(path);
+ Gtk::TreeModel::Row row = *iter;
+
+ _renameObject(row, new_text);
+ _text_renderer->property_editable() = false;
+}
+
+void TagsPanel::_handleEditingCancelled()
+{
+ _text_renderer->property_editable() = false;
+}
+
+void TagsPanel::_renameObject(Gtk::TreeModel::Row row, const Glib::ustring& name)
+{
+ if ( row && _desktop) {
+ SPObject* obj = row[_model->_colObject];
+ if ( obj ) {
+ if (SP_IS_TAG(obj)) {
+ gchar const* oldLabel = obj->label();
+ if ( !name.empty() && (!oldLabel || name != oldLabel) ) {
+ obj->setLabel(name.c_str());
+ DocumentUndo::done( _desktop->doc() , SP_VERB_NONE,
+ _("Rename object"));
+ }
+ } else if (SP_IS_TAG_USE(obj) && (obj = SP_TAG_USE(obj)->ref->getObject())) {
+ gchar const* oldLabel = obj->label();
+ if ( !name.empty() && (!oldLabel || name != oldLabel) ) {
+ obj->setLabel(name.c_str());
+ DocumentUndo::done( _desktop->doc() , SP_VERB_NONE,
+ _("Rename object"));
+ }
+ }
+ }
+ }
+}
+
+bool TagsPanel::_noSelection( Glib::RefPtr<Gtk::TreeModel> const & /*model*/, Gtk::TreeModel::Path const & /*path*/, bool /*currentlySelected*/ )
+{
+ return false;
+}
+
+bool TagsPanel::_rowSelectFunction( Glib::RefPtr<Gtk::TreeModel> const & /*model*/, Gtk::TreeModel::Path const & /*path*/, bool currentlySelected )
+{
+ bool val = true;
+ if ( !currentlySelected && _toggleEvent )
+ {
+ GdkEvent* event = gtk_get_current_event();
+ if ( event ) {
+ // (keep these checks separate, so we know when to call gdk_event_free()
+ if ( event->type == GDK_BUTTON_PRESS ) {
+ GdkEventButton const* target = reinterpret_cast<GdkEventButton const*>(_toggleEvent);
+ GdkEventButton const* evtb = reinterpret_cast<GdkEventButton const*>(event);
+
+ if ( (evtb->window == target->window)
+ && (evtb->send_event == target->send_event)
+ && (evtb->time == target->time)
+ && (evtb->state == target->state)
+ )
+ {
+ // Ooooh! It's a magic one
+ val = false;
+ }
+ }
+ gdk_event_free(event);
+ }
+ }
+ return val;
+}
+
+void TagsPanel::_setExpanded(const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& /*path*/, bool isexpanded)
+{
+ Gtk::TreeModel::Row row = *iter;
+
+ SPObject* obj = row[_model->_colParentObject];
+ if (obj && SP_IS_TAG(obj))
+ {
+ SP_TAG(obj)->setExpanded(isexpanded);
+ obj->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT);
+ }
+}
+
+/**
+ * Constructor
+ */
+TagsPanel::TagsPanel() :
+ UI::Widget::Panel("", "/dialogs/tags", SP_VERB_DIALOG_TAGS),
+ _rootWatcher(0),
+ deskTrack(),
+ _desktop(0),
+ _document(0),
+ _model(0),
+ _pending(0),
+ _toggleEvent(0),
+ _defer_target(),
+ desktopChangeConn()
+{
+ //Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+ ModelColumns *zoop = new ModelColumns();
+ _model = zoop;
+
+ _store = Gtk::TreeStore::create( *zoop );
+
+ _tree.set_model( _store );
+ _tree.set_headers_visible(false);
+ _tree.set_reorderable(true);
+ _tree.enable_model_drag_dest (Gdk::ACTION_MOVE);
+
+ Inkscape::UI::Widget::AddToIcon * addRenderer = manage( new Inkscape::UI::Widget::AddToIcon());
+ int addColNum = _tree.append_column("type", *addRenderer) - 1;
+ Gtk::TreeViewColumn *col = _tree.get_column(addColNum);
+ if ( col ) {
+ col->add_attribute( addRenderer->property_active(), _model->_colAddRemove );
+ col->add_attribute( addRenderer->property_visible(), _model->_colAllowAddRemove );
+ }
+
+ _text_renderer = manage(new Gtk::CellRendererText());
+ int nameColNum = _tree.append_column("Name", *_text_renderer) - 1;
+ _name_column = _tree.get_column(nameColNum);
+ _name_column->add_attribute(_text_renderer->property_text(), _model->_colLabel);
+
+ _tree.set_expander_column( *_tree.get_column(nameColNum) );
+
+ _tree.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
+ _selectedConnection = _tree.get_selection()->signal_changed().connect( sigc::mem_fun(*this, &TagsPanel::_pushTreeSelectionToCurrent) );
+ _tree.get_selection()->set_select_function( sigc::mem_fun(*this, &TagsPanel::_rowSelectFunction) );
+
+ _tree.signal_drag_drop().connect( sigc::mem_fun(*this, &TagsPanel::_handleDragDrop), false);
+ _collapsedConnection = _tree.signal_row_collapsed().connect( sigc::bind<bool>(sigc::mem_fun(*this, &TagsPanel::_setExpanded), false));
+ _expandedConnection = _tree.signal_row_expanded().connect( sigc::bind<bool>(sigc::mem_fun(*this, &TagsPanel::_setExpanded), true));
+
+ _text_renderer->signal_edited().connect( sigc::mem_fun(*this, &TagsPanel::_handleEdited) );
+ _text_renderer->signal_editing_canceled().connect( sigc::mem_fun(*this, &TagsPanel::_handleEditingCancelled) );
+
+ _tree.signal_button_press_event().connect( sigc::mem_fun(*this, &TagsPanel::_handleButtonEvent), false );
+ _tree.signal_button_release_event().connect( sigc::mem_fun(*this, &TagsPanel::_handleButtonEvent), false );
+ _tree.signal_key_press_event().connect( sigc::mem_fun(*this, &TagsPanel::_handleKeyEvent), false );
+
+ _scroller.add( _tree );
+ _scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC );
+ _scroller.set_shadow_type(Gtk::SHADOW_IN);
+ Gtk::Requisition sreq;
+#if WITH_GTKMM_3_0
+ Gtk::Requisition sreq_natural;
+ _scroller.get_preferred_size(sreq_natural, sreq);
+#else
+ sreq = _scroller.size_request();
+#endif
+ int minHeight = 70;
+ if (sreq.height < minHeight) {
+ // Set a min height to see the layers when used with Ubuntu liboverlay-scrollbar
+ _scroller.set_size_request(sreq.width, minHeight);
+ }
+
+ _layersPage.pack_start( _scroller, Gtk::PACK_EXPAND_WIDGET );
+
+ _layersPage.pack_end(_buttonsRow, Gtk::PACK_SHRINK);
+
+ _getContents()->pack_start(_layersPage, Gtk::PACK_EXPAND_WIDGET);
+
+ SPDesktop* targetDesktop = getDesktop();
+
+ Gtk::Button* btn = manage( new Gtk::Button() );
+ _styleButton( *btn, targetDesktop, SP_VERB_TAG_NEW, GTK_STOCK_ADD, _("Add a new selection set") );
+ btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &TagsPanel::_takeAction), (int)BUTTON_NEW) );
+ _buttonsSecondary.pack_start(*btn, Gtk::PACK_SHRINK);
+
+// btn = manage( new Gtk::Button("Dup") );
+// btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DUPLICATE) );
+// _buttonsRow.add( *btn );
+
+ btn = manage( new Gtk::Button() );
+ _styleButton( *btn, targetDesktop, SP_VERB_LAYER_DELETE, GTK_STOCK_REMOVE, _("Remove Item/Set") );
+ btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &TagsPanel::_takeAction), (int)BUTTON_DELETE) );
+ _watching.push_back( btn );
+ _buttonsSecondary.pack_start(*btn, Gtk::PACK_SHRINK);
+
+ _buttonsRow.pack_start(_buttonsSecondary, Gtk::PACK_EXPAND_WIDGET);
+ _buttonsRow.pack_end(_buttonsPrimary, Gtk::PACK_EXPAND_WIDGET);
+
+ // -------------------------------------------------------
+ {
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_TAG_NEW, 0, "Add a new selection set", (int)BUTTON_NEW ) );
+
+ _popupMenu.show_all_children();
+ }
+ // -------------------------------------------------------
+
+
+
+ for ( std::vector<Gtk::Widget*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) {
+ (*it)->set_sensitive( false );
+ }
+ for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonTop.begin(); it != _watchingNonTop.end(); ++it ) {
+ (*it)->set_sensitive( false );
+ }
+ for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonBottom.begin(); it != _watchingNonBottom.end(); ++it ) {
+ (*it)->set_sensitive( false );
+ }
+
+ setDesktop( targetDesktop );
+
+ show_all_children();
+
+ // restorePanelPrefs();
+
+ // Connect this up last
+ desktopChangeConn = deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &TagsPanel::setDesktop) );
+ deskTrack.connect(GTK_WIDGET(gobj()));
+}
+
+TagsPanel::~TagsPanel()
+{
+
+ setDesktop(NULL);
+
+ if ( _model )
+ {
+ delete _model;
+ _model = 0;
+ }
+
+ if (_pending) {
+ delete _pending;
+ _pending = 0;
+ }
+
+ if ( _toggleEvent )
+ {
+ gdk_event_free( _toggleEvent );
+ _toggleEvent = 0;
+ }
+
+ desktopChangeConn.disconnect();
+ deskTrack.disconnect();
+}
+
+void TagsPanel::setDocument(SPDesktop* /*desktop*/, SPDocument* document)
+{
+ while (!_objectWatchers.empty())
+ {
+ TagsPanel::ObjectWatcher *w = _objectWatchers.back();
+ w->_repr->removeObserver(*w);
+ _objectWatchers.pop_back();
+ delete w;
+ }
+
+ if (_rootWatcher)
+ {
+ _rootWatcher->_repr->removeObserver(*_rootWatcher);
+ delete _rootWatcher;
+ _rootWatcher = NULL;
+ }
+
+ _document = document;
+
+ if (document && document->getDefs() && document->getDefs()->getRepr())
+ {
+ _rootWatcher = new TagsPanel::ObjectWatcher(this, document->getDefs());
+ document->getDefs()->getRepr()->addObserver(*_rootWatcher);
+ _objectsChanged(document->getDefs());
+ }
+}
+
+void TagsPanel::setDesktop( SPDesktop* desktop )
+{
+ Panel::setDesktop(desktop);
+
+ if ( desktop != _desktop ) {
+ _documentChangedConnection.disconnect();
+ _selectionChangedConnection.disconnect();
+ if ( _desktop ) {
+ _desktop = 0;
+ }
+
+ _desktop = Panel::getDesktop();
+ if ( _desktop ) {
+ //setLabel( _desktop->doc()->name );
+ _documentChangedConnection = _desktop->connectDocumentReplaced( sigc::mem_fun(*this, &TagsPanel::setDocument));
+ _selectionChangedConnection = _desktop->selection->connectChanged( sigc::mem_fun(*this, &TagsPanel::_objectsSelected));
+
+ setDocument(_desktop, _desktop->doc());
+ }
+ }
+/*
+ GSList const *layers = _desktop->doc()->getResourceList( "layer" );
+ g_message( "layers list starts at %p", layers );
+ for ( GSList const *iter=layers ; iter ; iter = iter->next ) {
+ SPObject *layer=static_cast<SPObject *>(iter->data);
+ g_message(" {%s} [%s]", layer->id, layer->label() );
+ }
+*/
+ deskTrack.setBase(desktop);
+}
+
+
+
+
+
+} //namespace Dialogs
+} //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/tags.h b/src/ui/dialog/tags.h
new file mode 100644
index 000000000..d35dfba01
--- /dev/null
+++ b/src/ui/dialog/tags.h
@@ -0,0 +1,181 @@
+/*
+ * A simple dialog for tags UI.
+ *
+ * Authors:
+ * Theodore Janeczko
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_TAGS_PANEL_H
+#define SEEN_TAGS_PANEL_H
+
+#include <gtkmm/box.h>
+#include <gtkmm/treeview.h>
+#include <gtkmm/treestore.h>
+#include <gtkmm/scrolledwindow.h>
+#include <gtkmm/dialog.h>
+#include "ui/widget/spinbutton.h"
+#include "ui/widget/panel.h"
+#include "ui/widget/object-composite-settings.h"
+#include "desktop-tracker.h"
+#include "ui/widget/style-subject.h"
+#include "selection.h"
+#include "ui/widget/filter-effect-chooser.h"
+
+class SPObject;
+class SPTag;
+struct SPColorSelector;
+
+namespace Inkscape {
+
+namespace UI {
+namespace Dialog {
+
+
+/**
+ * A panel that displays layers.
+ */
+class TagsPanel : public UI::Widget::Panel
+{
+public:
+ TagsPanel();
+ virtual ~TagsPanel();
+
+ //virtual void setOrientation( Gtk::AnchorType how );
+
+ static TagsPanel& getInstance();
+
+ void setDesktop( SPDesktop* desktop );
+ void setDocument( SPDesktop* desktop, SPDocument* document);
+
+protected:
+ //virtual void _handleAction( int setId, int itemId );
+ friend void sp_highlight_picker_color_mod(SPColorSelector *csel, GObject *cp);
+private:
+ class ModelColumns;
+ class InternalUIBounce;
+ class ObjectWatcher;
+
+ TagsPanel(TagsPanel const &); // no copy
+ TagsPanel &operator=(TagsPanel const &); // no assign
+
+ void _styleButton( Gtk::Button& btn, SPDesktop *desktop, unsigned int code, char const* iconName, char const* tooltip );
+ void _fireAction( unsigned int code );
+ Gtk::MenuItem& _addPopupItem( SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback, int id );
+
+ bool _handleButtonEvent(GdkEventButton *event);
+ bool _handleKeyEvent(GdkEventKey *event);
+
+ void _storeDragSource(const Gtk::TreeModel::iterator& iter);
+ bool _handleDragDrop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time);
+ void _handleEdited(const Glib::ustring& path, const Glib::ustring& new_text);
+ void _handleEditingCancelled();
+
+ void _doTreeMove();
+ void _renameObject(Gtk::TreeModel::Row row, const Glib::ustring& name);
+
+ void _pushTreeSelectionToCurrent();
+ void _selected_row_callback( const Gtk::TreeModel::iterator& iter );
+ void _select_tag( SPTag * tag );
+
+ void _checkTreeSelection();
+
+ void _takeAction( int val );
+ bool _executeAction();
+
+ void _setExpanded( const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path, bool isexpanded );
+
+ bool _noSelection( Glib::RefPtr<Gtk::TreeModel> const & model, Gtk::TreeModel::Path const & path, bool b );
+ bool _rowSelectFunction( Glib::RefPtr<Gtk::TreeModel> const & model, Gtk::TreeModel::Path const & path, bool b );
+
+ void _updateObject(SPObject *obj);
+ bool _checkForUpdated(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPObject* obj);
+
+ void _objectsSelected(Selection *sel);
+ bool _checkForSelected(const Gtk::TreePath& path, const Gtk::TreeIter& iter, SPObject* layer);
+
+ void _objectsChanged(SPObject *root);
+ void _addObject( SPDocument* doc, SPObject* obj, Gtk::TreeModel::Row* parentRow );
+
+ void _checkForDeleted(const Gtk::TreeIter& iter, std::vector<SPObject *>* todelete);
+
+// std::vector<sigc::connection> groupConnections;
+ TagsPanel::ObjectWatcher* _rootWatcher;
+ std::vector<TagsPanel::ObjectWatcher*> _objectWatchers;
+
+ // Hooked to the layer manager:
+ sigc::connection _documentChangedConnection;
+ sigc::connection _selectionChangedConnection;
+
+ sigc::connection _changedConnection;
+ sigc::connection _addedConnection;
+ sigc::connection _removedConnection;
+
+ // Internal
+ sigc::connection _selectedConnection;
+ sigc::connection _expandedConnection;
+ sigc::connection _collapsedConnection;
+
+ DesktopTracker deskTrack;
+ SPDesktop* _desktop;
+ SPDocument* _document;
+ ModelColumns* _model;
+ InternalUIBounce* _pending;
+ gboolean _dnd_into;
+ std::vector<SPTag*> _dnd_source;
+ SPObject* _dnd_target;
+
+ GdkEvent* _toggleEvent;
+ bool down_at_add;
+
+ Gtk::TreeModel::Path _defer_target;
+
+ Glib::RefPtr<Gtk::TreeStore> _store;
+ std::vector<Gtk::Widget*> _watching;
+ std::vector<Gtk::Widget*> _watchingNonTop;
+ std::vector<Gtk::Widget*> _watchingNonBottom;
+
+ Gtk::TreeView _tree;
+ Gtk::CellRendererText *_text_renderer;
+ Gtk::TreeView::Column *_name_column;
+#if WITH_GTKMM_3_0
+ Gtk::Box _buttonsRow;
+ Gtk::Box _buttonsPrimary;
+ Gtk::Box _buttonsSecondary;
+#else
+ Gtk::HBox _buttonsRow;
+ Gtk::HBox _buttonsPrimary;
+ Gtk::HBox _buttonsSecondary;
+#endif
+ Gtk::ScrolledWindow _scroller;
+ Gtk::Menu _popupMenu;
+ Inkscape::UI::Widget::SpinButton _spinBtn;
+ Gtk::VBox _layersPage;
+
+ sigc::connection desktopChangeConn;
+
+};
+
+
+
+} //namespace Dialogs
+} //namespace UI
+} //namespace Inkscape
+
+
+
+#endif // SEEN_OBJECTS_PANEL_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/template-load-tab.cpp b/src/ui/dialog/template-load-tab.cpp
index d75f81456..13cb01eef 100644
--- a/src/ui/dialog/template-load-tab.cpp
+++ b/src/ui/dialog/template-load-tab.cpp
@@ -24,7 +24,7 @@
#include "extension/db.h"
#include "extension/effect.h"
#include "inkscape.h"
-#include "interface.h"
+#include "ui/interface.h"
#include "file.h"
#include "path-prefix.h"
#include "preferences.h"
diff --git a/src/ui/dialog/template-widget.cpp b/src/ui/dialog/template-widget.cpp
index ef91962d4..f79d166f2 100644
--- a/src/ui/dialog/template-widget.cpp
+++ b/src/ui/dialog/template-widget.cpp
@@ -24,6 +24,7 @@
#include "document.h"
#include "document-undo.h"
#include "file.h"
+#include "sp-namedview.h"
#include "extension/implementation/implementation.h"
#include "inkscape.h"
@@ -69,7 +70,10 @@ void TemplateWidget::create()
_current_template.tpl_effect->effect(desc);
DocumentUndo::clearUndo(sp_desktop_document(desc));
sp_desktop_document(desc)->setModifiedSinceSave(false);
-
+
+ // Apply cx,cy etc. from document
+ sp_namedview_window_from_document( desc );
+
if (desktop)
desktop->clearWaitingCursor();
}
@@ -120,7 +124,7 @@ void TemplateWidget::_displayTemplateDetails()
if (_current_template.long_description != "")
message += _("Description: ") + _current_template.long_description + "\n\n";
- if (~_current_template.keywords.empty()){
+ if (!_current_template.keywords.empty()){
message += _("Keywords: ");
for (std::set<Glib::ustring>::iterator it = _current_template.keywords.begin(); it != _current_template.keywords.end(); ++it)
message += *it + " ";
diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp
index 17c29c69f..0f4a6f7f1 100644
--- a/src/ui/dialog/text-edit.cpp
+++ b/src/ui/dialog/text-edit.cpp
@@ -32,7 +32,6 @@ extern "C" {
#include <gtkmm/stock.h>
#include <libnrtype/font-instance.h>
-#include <libnrtype/font-style-to-pos.h>
#include <libnrtype/font-lister.h>
#include <xml/repr.h>
@@ -52,7 +51,7 @@ extern "C" {
#include "ui/icon-names.h"
#include "preferences.h"
#include "verbs.h"
-#include "interface.h"
+#include "ui/interface.h"
#include "svg/css-ostringstream.h"
#include "widgets/icon.h"
#include "widgets/font-selector.h"
@@ -344,9 +343,9 @@ void TextEdit::onReadSelection ( gboolean dostyle, gboolean /*docontent*/ )
Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance();
- // This is done for us by text-toolbar. No need to do it twice.
- // fontlister->update_font_list( sp_desktop_document( SP_ACTIVE_DESKTOP ));
- // fontlister->selection_update();
+ // This is normally done for us by text-toolbar but only when we are in text editing context
+ fontlister->update_font_list(sp_desktop_document(this->desktop));
+ fontlister->selection_update();
Glib::ustring fontspec = fontlister->get_fontspec();
@@ -404,12 +403,12 @@ void TextEdit::setPreviewText (Glib::ustring font_spec, Glib::ustring phrase)
double pt_size = Inkscape::Util::Quantity::convert(sp_style_css_size_units_to_px(sp_font_selector_get_size(fsel), unit), "px", "pt");
// Pango font size is in 1024ths of a point
- // C++11: Glib::ustring size = std::to_string( pt_size * PANGO_SCALE );
+ // C++11: Glib::ustring size = std::to_string( int(pt_size * PANGO_SCALE) );
std::ostringstream size_st;
- size_st << pt_size * PANGO_SCALE;
+ size_st << int(pt_size * PANGO_SCALE); // Markup code expects integers
- Glib::ustring markup = "<span font=\"" + font_spec +
- "\" size=\"" + size_st.str() + "\">" + phrase_escaped + "</span>";
+ Glib::ustring markup = "<span font=\'" + font_spec +
+ "\' size=\'" + size_st.str() + "\'>" + phrase_escaped + "</span>";
preview_label.set_markup(markup.c_str());
}
diff --git a/src/ui/dialog/transformation.cpp b/src/ui/dialog/transformation.cpp
index a7f0b068e..3e135b9b2 100644
--- a/src/ui/dialog/transformation.cpp
+++ b/src/ui/dialog/transformation.cpp
@@ -47,13 +47,13 @@ namespace Inkscape {
namespace UI {
namespace Dialog {
-static void on_selection_changed(Inkscape::Application */*inkscape*/, Inkscape::Selection *selection, Transformation *daad)
+static void on_selection_changed(InkscapeApplication */*inkscape*/, Inkscape::Selection *selection, Transformation *daad)
{
int page = daad->getCurrentPage();
daad->updateSelection((Inkscape::UI::Dialog::Transformation::PageType)page, selection);
}
-static void on_selection_modified( Inkscape::Application */*inkscape*/,
+static void on_selection_modified( InkscapeApplication */*inkscape*/,
Inkscape::Selection *selection,
guint /*flags*/,
Transformation *daad )
diff --git a/src/ui/dialog/xml-tree.cpp b/src/ui/dialog/xml-tree.cpp
index 55d0aff09..7ab6c78ba 100644
--- a/src/ui/dialog/xml-tree.cpp
+++ b/src/ui/dialog/xml-tree.cpp
@@ -24,13 +24,13 @@
#include "desktop.h"
#include "desktop-handles.h"
-#include "dialogs/dialog-events.h"
+#include "ui/dialog-events.h"
#include "document.h"
#include "document-undo.h"
#include "ui/tools/tool-base.h"
#include "helper/window.h"
#include "inkscape.h"
-#include "interface.h"
+#include "ui/interface.h"
#include "macros.h"
#include "message-context.h"
#include "message-stack.h"
@@ -1033,6 +1033,7 @@ void XmlTree::cmd_set_attr()
updated->updateRepr();
}
+ reinterpret_cast<SPObject *>(current_desktop->currentLayer())->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
DocumentUndo::done(current_document, SP_VERB_DIALOG_XML_EDITOR,
_("Change attribute"));
diff --git a/src/ui/draw-anchor.cpp b/src/ui/draw-anchor.cpp
new file mode 100644
index 000000000..84c919018
--- /dev/null
+++ b/src/ui/draw-anchor.cpp
@@ -0,0 +1,105 @@
+/** \file
+ * Anchors implementation.
+ */
+
+/*
+ * Authors:
+ * Copyright (C) 2000 Lauris Kaplinski
+ * Copyright (C) 2000-2001 Ximian, Inc.
+ * Copyright (C) 2002 Lauris Kaplinski
+ * Copyright (C) 2004 Monash University
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+
+#include "ui/draw-anchor.h"
+#include "desktop.h"
+#include "desktop-handles.h"
+#include "ui/tools/tool-base.h"
+#include "ui/tools/lpe-tool.h"
+#include "display/sodipodi-ctrl.h"
+#include "display/curve.h"
+#include "ui/control-manager.h"
+
+using Inkscape::ControlManager;
+
+#define FILL_COLOR_NORMAL 0xffffff7f
+#define FILL_COLOR_MOUSEOVER 0xff0000ff
+
+/**
+ * Creates an anchor object and initializes it.
+ */
+SPDrawAnchor *sp_draw_anchor_new(Inkscape::UI::Tools::FreehandBase *dc, SPCurve *curve, bool start, Geom::Point delta)
+{
+ if (SP_IS_LPETOOL_CONTEXT(dc)) {
+ // suppress all kinds of anchors in LPEToolContext
+ return NULL;
+ }
+
+ SPDrawAnchor *a = g_new(SPDrawAnchor, 1);
+
+ a->dc = dc;
+ a->curve = curve;
+ curve->ref();
+ a->start = start;
+ a->active = FALSE;
+ a->dp = delta;
+ a->ctrl = ControlManager::getManager().createControl(sp_desktop_controls(&dc->getDesktop()), Inkscape::CTRL_TYPE_ANCHOR);
+
+ SP_CTRL(a->ctrl)->moveto(delta);
+
+ ControlManager::getManager().track(a->ctrl);
+
+ return a;
+}
+
+/**
+ * Destroys the anchor's canvas item and frees the anchor object.
+ */
+SPDrawAnchor *sp_draw_anchor_destroy(SPDrawAnchor *anchor)
+{
+ if (anchor->curve) {
+ anchor->curve->unref();
+ }
+ if (anchor->ctrl) {
+ sp_canvas_item_destroy(anchor->ctrl);
+ }
+ g_free(anchor);
+ return NULL;
+}
+
+/**
+ * Test if point is near anchor, if so fill anchor on canvas and return
+ * pointer to it or NULL.
+ */
+SPDrawAnchor *sp_draw_anchor_test(SPDrawAnchor *anchor, Geom::Point w, bool activate)
+{
+ SPCtrl *ctrl = SP_CTRL(anchor->ctrl);
+
+ if ( activate && ( Geom::LInfty( w - anchor->dc->getDesktop().d2w(anchor->dp) ) <= (ctrl->box.width() / 2.0) ) ) {
+ if (!anchor->active) {
+ g_object_set(anchor->ctrl, "fill_color", FILL_COLOR_MOUSEOVER, NULL);
+ anchor->active = TRUE;
+ }
+ return anchor;
+ }
+
+ if (anchor->active) {
+ g_object_set(anchor->ctrl, "fill_color", FILL_COLOR_NORMAL, NULL);
+ anchor->active = FALSE;
+ }
+ return NULL;
+}
+
+
+/*
+ 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/draw-anchor.h b/src/ui/draw-anchor.h
new file mode 100644
index 000000000..1f7b55920
--- /dev/null
+++ b/src/ui/draw-anchor.h
@@ -0,0 +1,52 @@
+#ifndef SEEN_DRAW_ANCHOR_H
+#define SEEN_DRAW_ANCHOR_H
+
+/** \file
+ * Drawing anchors.
+ */
+
+#include <2geom/point.h>
+
+namespace Inkscape {
+namespace UI {
+namespace Tools {
+
+class FreehandBase;
+
+}
+}
+}
+
+class SPCurve;
+struct SPCanvasItem;
+
+/// The drawing anchor.
+/// \todo Make this a regular knot, this will allow to set statusbar tips.
+struct SPDrawAnchor {
+ Inkscape::UI::Tools::FreehandBase *dc;
+ SPCurve *curve;
+ unsigned int start : 1;
+ unsigned int active : 1;
+ Geom::Point dp;
+ SPCanvasItem *ctrl;
+};
+
+
+SPDrawAnchor *sp_draw_anchor_new(Inkscape::UI::Tools::FreehandBase *dc, SPCurve *curve, bool start,
+ Geom::Point delta);
+SPDrawAnchor *sp_draw_anchor_destroy(SPDrawAnchor *anchor);
+SPDrawAnchor *sp_draw_anchor_test(SPDrawAnchor *anchor, Geom::Point w, bool activate);
+
+
+#endif /* !SEEN_DRAW_ANCHOR_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/interface.cpp b/src/ui/interface.cpp
new file mode 100644
index 000000000..7830a8de1
--- /dev/null
+++ b/src/ui/interface.cpp
@@ -0,0 +1,2230 @@
+/**
+ * @file
+ * Main UI stuff.
+ */
+/* Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Frank Felfe <innerspace@iname.com>
+ * bulia byak <buliabyak@users.sf.net>
+ * Jon A. Cruz <jon@joncruz.org>
+ * Abhishek Sharma
+ * Kris De Gussem <Kris.DeGussem@gmail.com>
+ *
+ * Copyright (C) 2012 Kris De Gussem
+ * Copyright (C) 2010 authors
+ * Copyright (C) 1999-2005 authors
+ * Copyright (C) 2004 David Turner
+ * Copyright (C) 2001-2002 Ximian, Inc.
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "ui/dialog/dialog-manager.h"
+#include <gtkmm/icontheme.h>
+#include "file.h"
+#include <gtkmm/imagemenuitem.h>
+#include <gtkmm/separatormenuitem.h>
+
+#include "inkscape-private.h"
+#include "extension/db.h"
+#include "extension/effect.h"
+#include "extension/input.h"
+#include "widgets/icon.h"
+#include "preferences.h"
+#include "path-prefix.h"
+#include "shortcuts.h"
+#include "document.h"
+#include "desktop-handles.h"
+#include "ui/interface.h"
+#include "desktop.h"
+#include "selection.h"
+#include "selection-chemistry.h"
+#include "svg-view-widget.h"
+#include "widgets/desktop-widget.h"
+#include "sp-item-group.h"
+#include "sp-text.h"
+#include "sp-gradient.h"
+#include "sp-flowtext.h"
+#include "sp-namedview.h"
+#include "sp-root.h"
+#include "ui/view/view.h"
+#include "helper/action.h"
+#include "helper/action-context.h"
+#include "helper/gnome-utils.h"
+#include "helper/window.h"
+#include "io/sys.h"
+#include "ui/dialog-events.h"
+#include "message-context.h"
+#include "ui/uxmanager.h"
+#include "ui/clipboard.h"
+
+#include "display/sp-canvas.h"
+#include "color.h"
+#include "svg/svg-color.h"
+#include "desktop-style.h"
+#include "style.h"
+#include "ui/tools/tool-base.h"
+#include "gradient-drag.h"
+#include "widgets/ege-paint-def.h"
+#include "document-undo.h"
+#include "sp-anchor.h"
+#include "sp-clippath.h"
+#include "sp-image.h"
+#include "sp-item.h"
+#include "sp-mask.h"
+#include "message-stack.h"
+#include "ui/dialog/layer-properties.h"
+
+#include <gdk/gdkkeysyms.h>
+
+#include <glibmm/miscutils.h>
+
+using Inkscape::DocumentUndo;
+
+/* Drag and Drop */
+typedef enum {
+ URI_LIST,
+ SVG_XML_DATA,
+ SVG_DATA,
+ PNG_DATA,
+ JPEG_DATA,
+ IMAGE_DATA,
+ APP_X_INKY_COLOR,
+ APP_X_COLOR,
+ APP_OSWB_COLOR,
+ APP_X_INK_PASTE
+} ui_drop_target_info;
+
+static GtkTargetEntry ui_drop_target_entries [] = {
+ {(gchar *)"text/uri-list", 0, URI_LIST },
+ {(gchar *)"image/svg+xml", 0, SVG_XML_DATA },
+ {(gchar *)"image/svg", 0, SVG_DATA },
+ {(gchar *)"image/png", 0, PNG_DATA },
+ {(gchar *)"image/jpeg", 0, JPEG_DATA },
+#if ENABLE_MAGIC_COLORS
+ {(gchar *)"application/x-inkscape-color", 0, APP_X_INKY_COLOR},
+#endif // ENABLE_MAGIC_COLORS
+ {(gchar *)"application/x-oswb-color", 0, APP_OSWB_COLOR },
+ {(gchar *)"application/x-color", 0, APP_X_COLOR },
+ {(gchar *)"application/x-inkscape-paste", 0, APP_X_INK_PASTE }
+};
+
+static GtkTargetEntry *completeDropTargets = 0;
+static int completeDropTargetsCount = 0;
+static bool temporarily_block_actions = false;
+
+#define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0])
+static guint nui_drop_target_entries = ENTRIES_SIZE(ui_drop_target_entries);
+static void sp_ui_import_files(gchar *buffer);
+static void sp_ui_import_one_file(char const *filename);
+static void sp_ui_import_one_file_with_check(gpointer filename, gpointer unused);
+static void sp_ui_drag_data_received(GtkWidget *widget,
+ GdkDragContext *drag_context,
+ gint x, gint y,
+ GtkSelectionData *data,
+ guint info,
+ guint event_time,
+ gpointer user_data);
+static void sp_ui_drag_motion( GtkWidget *widget,
+ GdkDragContext *drag_context,
+ gint x, gint y,
+ GtkSelectionData *data,
+ guint info,
+ guint event_time,
+ gpointer user_data );
+static void sp_ui_drag_leave( GtkWidget *widget,
+ GdkDragContext *drag_context,
+ guint event_time,
+ gpointer user_data );
+static void sp_ui_menu_item_set_name(GtkWidget *data,
+ Glib::ustring const &name);
+static void sp_recent_open(GtkRecentChooser *, gpointer);
+
+static void injectRenamedIcons();
+
+static const int MIN_ONSCREEN_DISTANCE = 50;
+
+void
+sp_create_window(SPViewWidget *vw, bool editable)
+{
+ g_return_if_fail(vw != NULL);
+ g_return_if_fail(SP_IS_VIEW_WIDGET(vw));
+
+ Gtk::Window *win = Inkscape::UI::window_new("", TRUE);
+
+ gtk_container_add(GTK_CONTAINER(win->gobj()), GTK_WIDGET(vw));
+ gtk_widget_show(GTK_WIDGET(vw));
+
+ if (editable) {
+ g_object_set_data(G_OBJECT(vw), "window", win);
+
+ SPDesktopWidget *desktop_widget = reinterpret_cast<SPDesktopWidget*>(vw);
+ SPDesktop* desktop = desktop_widget->desktop;
+
+ desktop_widget->window = win;
+
+ win->set_data("desktop", desktop);
+ win->set_data("desktopwidget", desktop_widget);
+
+ win->signal_delete_event().connect(sigc::mem_fun(*(SPDesktop*)vw->view, &SPDesktop::onDeleteUI));
+ win->signal_window_state_event().connect(sigc::mem_fun(*desktop, &SPDesktop::onWindowStateEvent));
+ win->signal_focus_in_event().connect(sigc::mem_fun(*desktop_widget, &SPDesktopWidget::onFocusInEvent));
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gint prefs_geometry =
+ (2==prefs->getInt("/options/savewindowgeometry/value", 0));
+ if (prefs_geometry) {
+ gint pw = prefs->getInt("/desktop/geometry/width", -1);
+ gint ph = prefs->getInt("/desktop/geometry/height", -1);
+ gint px = prefs->getInt("/desktop/geometry/x", -1);
+ gint py = prefs->getInt("/desktop/geometry/y", -1);
+ gint full = prefs->getBool("/desktop/geometry/fullscreen");
+ gint maxed = prefs->getBool("/desktop/geometry/maximized");
+ if (pw>0 && ph>0) {
+ gint w = MIN(gdk_screen_width(), pw);
+ gint h = MIN(gdk_screen_height(), ph);
+ gint x = MIN(gdk_screen_width() - MIN_ONSCREEN_DISTANCE, px);
+ gint y = MIN(gdk_screen_height() - MIN_ONSCREEN_DISTANCE, py);
+ if (w>0 && h>0) {
+ x = MIN(gdk_screen_width() - w, x);
+ y = MIN(gdk_screen_height() - h, y);
+ desktop->setWindowSize(w, h);
+ }
+
+ // Only restore xy for the first window so subsequent windows don't overlap exactly
+ // with first. (Maybe rule should be only restore xy if it's different from xy of
+ // other desktops?)
+
+ // Empirically it seems that active_desktop==this desktop only the first time a
+ // desktop is created.
+ SPDesktop *active_desktop = SP_ACTIVE_DESKTOP;
+ if (active_desktop == desktop || active_desktop==NULL) {
+ desktop->setWindowPosition(Geom::Point(x, y));
+ }
+ }
+ if (maxed) {
+ win->maximize();
+ }
+ if (full) {
+ win->fullscreen();
+ }
+ }
+
+ }
+
+ if ( completeDropTargets == 0 || completeDropTargetsCount == 0 )
+ {
+ std::vector<gchar*> types;
+
+ GSList *list = gdk_pixbuf_get_formats();
+ while ( list ) {
+ int i = 0;
+ GdkPixbufFormat *one = (GdkPixbufFormat*)list->data;
+ gchar** typesXX = gdk_pixbuf_format_get_mime_types(one);
+ for ( i = 0; typesXX[i]; i++ ) {
+ types.push_back(g_strdup(typesXX[i]));
+ }
+ g_strfreev(typesXX);
+
+ list = g_slist_next(list);
+ }
+ completeDropTargetsCount = nui_drop_target_entries + types.size();
+ completeDropTargets = new GtkTargetEntry[completeDropTargetsCount];
+ for ( int i = 0; i < (int)nui_drop_target_entries; i++ ) {
+ completeDropTargets[i] = ui_drop_target_entries[i];
+ }
+ int pos = nui_drop_target_entries;
+
+ for (std::vector<gchar*>::iterator it = types.begin() ; it != types.end() ; it++) {
+ completeDropTargets[pos].target = *it;
+ completeDropTargets[pos].flags = 0;
+ completeDropTargets[pos].info = IMAGE_DATA;
+ pos++;
+ }
+ }
+
+ gtk_drag_dest_set((GtkWidget*)win->gobj(),
+ GTK_DEST_DEFAULT_ALL,
+ completeDropTargets,
+ completeDropTargetsCount,
+ GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE));
+
+
+ g_signal_connect(G_OBJECT(win->gobj()),
+ "drag_data_received",
+ G_CALLBACK(sp_ui_drag_data_received),
+ NULL);
+ g_signal_connect(G_OBJECT(win->gobj()),
+ "drag_motion",
+ G_CALLBACK(sp_ui_drag_motion),
+ NULL);
+ g_signal_connect(G_OBJECT(win->gobj()),
+ "drag_leave",
+ G_CALLBACK(sp_ui_drag_leave),
+ NULL);
+ win->show();
+
+ // needed because the first ACTIVATE_DESKTOP was sent when there was no window yet
+ if ( SP_IS_DESKTOP_WIDGET(vw) ) {
+ inkscape_reactivate_desktop(SP_DESKTOP_WIDGET(vw)->desktop);
+ }
+}
+
+void
+sp_ui_new_view()
+{
+ SPDocument *document;
+ SPViewWidget *dtw;
+
+ document = SP_ACTIVE_DOCUMENT;
+ if (!document) return;
+
+ dtw = sp_desktop_widget_new(sp_document_namedview(document, NULL));
+ g_return_if_fail(dtw != NULL);
+
+ sp_create_window(dtw, TRUE);
+ sp_namedview_window_from_document(static_cast<SPDesktop*>(dtw->view));
+ sp_namedview_update_layers_from_document(static_cast<SPDesktop*>(dtw->view));
+}
+
+void sp_ui_new_view_preview()
+{
+ SPDocument *document = SP_ACTIVE_DOCUMENT;
+ if ( document ) {
+ SPViewWidget *dtw = reinterpret_cast<SPViewWidget *>(sp_svg_view_widget_new(document));
+ g_return_if_fail(dtw != NULL);
+ SP_SVG_VIEW_WIDGET(dtw)->setResize(true, 400.0, 400.0);
+
+ sp_create_window(dtw, FALSE);
+ }
+}
+
+void
+sp_ui_close_view(GtkWidget */*widget*/)
+{
+ SPDesktop *dt = SP_ACTIVE_DESKTOP;
+
+ if (dt == NULL) {
+ return;
+ }
+
+ if (dt->shutdown()) {
+ return; // Shutdown operation has been canceled, so do nothing
+ }
+
+ // If closing the last document, open a new document so Inkscape doesn't quit.
+ std::list<SPDesktop *> desktops;
+ inkscape_get_all_desktops(desktops);
+ if (desktops.size() == 1) {
+ Glib::ustring templateUri = sp_file_default_template_uri();
+ SPDocument *doc = SPDocument::createNewDoc( templateUri.c_str() , TRUE, true );
+ // Set viewBox if it doesn't exist
+ if (!doc->getRoot()->viewBox_set) {
+ doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDefaultUnit()), doc->getHeight().value(doc->getDefaultUnit())));
+ }
+ dt->change_document(doc);
+ sp_namedview_window_from_document(dt);
+ sp_namedview_update_layers_from_document(dt);
+ return;
+ }
+
+ // Shutdown can proceed; use the stored reference to the desktop here instead of the current SP_ACTIVE_DESKTOP,
+ // because the user might have changed the focus in the meantime (see bug #381357 on Launchpad)
+ dt->destroyWidget();
+}
+
+
+unsigned int
+sp_ui_close_all(void)
+{
+ /* Iterate through all the windows, destroying each in the order they
+ become active */
+ while (SP_ACTIVE_DESKTOP) {
+ SPDesktop *dt = SP_ACTIVE_DESKTOP;
+ if (dt->shutdown()) {
+ /* The user canceled the operation, so end doing the close */
+ return FALSE;
+ }
+ // Shutdown can proceed; use the stored reference to the desktop here instead of the current SP_ACTIVE_DESKTOP,
+ // because the user might have changed the focus in the meantime (see bug #381357 on Launchpad)
+ dt->destroyWidget();
+ }
+
+ return TRUE;
+}
+
+/*
+ * Some day when the right-click menus are ready to start working
+ * smarter with the verbs, we'll need to change this NULL being
+ * sent to sp_action_perform to something useful, or set some kind
+ * of global "right-clicked position" variable for actions to
+ * investigate when they're called.
+ */
+static void
+sp_ui_menu_activate(void */*object*/, SPAction *action)
+{
+ if (!temporarily_block_actions) {
+ sp_action_perform(action, NULL);
+ }
+}
+
+static void
+sp_ui_menu_select_action(void */*object*/, SPAction *action)
+{
+ sp_action_get_view(action)->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, action->tip);
+}
+
+static void
+sp_ui_menu_deselect_action(void */*object*/, SPAction *action)
+{
+ sp_action_get_view(action)->tipsMessageContext()->clear();
+}
+
+static void
+sp_ui_menu_select(gpointer object, gpointer tip)
+{
+ Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*> (g_object_get_data(G_OBJECT(object), "view"));
+ view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, (gchar *)tip);
+}
+
+static void
+sp_ui_menu_deselect(gpointer object)
+{
+ Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*> (g_object_get_data(G_OBJECT(object), "view"));
+ view->tipsMessageContext()->clear();
+}
+
+/**
+ * Creates and attaches a scaled icon to the given menu item.
+ */
+static void
+sp_ui_menuitem_add_icon( GtkWidget *item, gchar *icon_name )
+{
+ static bool iconsInjected = false;
+ if ( !iconsInjected ) {
+ iconsInjected = true;
+ injectRenamedIcons();
+ }
+ GtkWidget *icon;
+
+ icon = sp_icon_new( Inkscape::ICON_SIZE_MENU, icon_name );
+ gtk_widget_show(icon);
+ gtk_image_menu_item_set_image((GtkImageMenuItem *) item, icon);
+} // end of sp_ui_menu_add_icon
+
+void
+sp_ui_dialog_title_string(Inkscape::Verb *verb, gchar *c)
+{
+ SPAction *action;
+ unsigned int shortcut;
+ gchar *s;
+ gchar *atitle;
+
+ action = verb->get_action(Inkscape::ActionContext());
+ if (!action)
+ return;
+
+ atitle = sp_action_get_title(action);
+
+ s = g_stpcpy(c, atitle);
+
+ g_free(atitle);
+
+ shortcut = sp_shortcut_get_primary(verb);
+ if (shortcut!=GDK_KEY_VoidSymbol) {
+ gchar* key = sp_shortcut_get_label(shortcut);
+ s = g_stpcpy(s, " (");
+ s = g_stpcpy(s, key);
+ s = g_stpcpy(s, ")");
+ g_free(key);
+ }
+}
+
+
+/**
+ * Appends a custom menu UI from a verb.
+ *
+ * @see ContextMenu::AppendItemFromVerb for a c++ified alternative. Consider dropping sp_ui_menu_append_item_from_verb when c++ifying interface.cpp.
+ */
+static GtkWidget *sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape::UI::View::View *view, bool radio = false, GSList *group = NULL)
+{
+ SPAction *action;
+ GtkWidget *item;
+
+ if (verb->get_code() == SP_VERB_NONE) {
+
+ item = gtk_separator_menu_item_new();
+
+ } else {
+
+ action = verb->get_action(Inkscape::ActionContext(view));
+ if (!action) return NULL;
+
+ if (radio) {
+ item = gtk_radio_menu_item_new_with_mnemonic(group, action->name);
+ } else {
+ item = gtk_image_menu_item_new_with_mnemonic(action->name);
+ }
+
+ gtk_label_set_markup_with_mnemonic( GTK_LABEL(gtk_bin_get_child(GTK_BIN (item))), action->name);
+
+ GtkAccelGroup *accel_group = sp_shortcut_get_accel_group();
+ gtk_menu_set_accel_group(menu, accel_group);
+
+ sp_shortcut_add_accelerator(item, sp_shortcut_get_primary(verb));
+
+ action->signal_set_sensitive.connect(
+ sigc::bind<0>(
+ sigc::ptr_fun(&gtk_widget_set_sensitive),
+ item));
+ action->signal_set_name.connect(
+ sigc::bind<0>(
+ sigc::ptr_fun(&sp_ui_menu_item_set_name),
+ item));
+
+ if (!action->sensitive) {
+ gtk_widget_set_sensitive(item, FALSE);
+ }
+
+ if (action->image) {
+ sp_ui_menuitem_add_icon(item, action->image);
+ }
+ gtk_widget_set_events(item, GDK_KEY_PRESS_MASK);
+ g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
+ g_signal_connect( G_OBJECT(item), "activate", G_CALLBACK(sp_ui_menu_activate), action );
+ g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select_action), action );
+ g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect_action), action );
+ }
+
+ gtk_widget_show(item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+ return item;
+
+} // end of sp_ui_menu_append_item_from_verb
+
+
+Glib::ustring getLayoutPrefPath( Inkscape::UI::View::View *view )
+{
+ Glib::ustring prefPath;
+
+ if (reinterpret_cast<SPDesktop*>(view)->is_focusMode()) {
+ prefPath = "/focus/";
+ } else if (reinterpret_cast<SPDesktop*>(view)->is_fullscreen()) {
+ prefPath = "/fullscreen/";
+ } else {
+ prefPath = "/window/";
+ }
+
+ return prefPath;
+}
+
+static void
+checkitem_toggled(GtkCheckMenuItem *menuitem, gpointer user_data)
+{
+ gchar const *pref = (gchar const *) user_data;
+ Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
+ SPAction *action = (SPAction *) g_object_get_data(G_OBJECT(menuitem), "action");
+
+ if (action) {
+
+ sp_ui_menu_activate(menuitem, action);
+
+ } else if (pref) {
+ // All check menu items should have actions now, but just in case
+ Glib::ustring pref_path = getLayoutPrefPath( view );
+ pref_path += pref;
+ pref_path += "/state";
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean checked = gtk_check_menu_item_get_active(menuitem);
+ prefs->setBool(pref_path, checked);
+
+ reinterpret_cast<SPDesktop*>(view)->layoutWidget();
+ }
+}
+
+static bool getViewStateFromPref(Inkscape::UI::View::View *view, gchar const *pref)
+{
+ Glib::ustring pref_path = getLayoutPrefPath( view );
+ pref_path += pref;
+ pref_path += "/state";
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ return prefs->getBool(pref_path, true);
+}
+
+#if GTK_CHECK_VERSION(3,0,0)
+static gboolean checkitem_update(GtkWidget *widget, cairo_t * /*cr*/, gpointer user_data)
+#else
+static gboolean checkitem_update(GtkWidget *widget, GdkEventExpose * /*event*/, gpointer user_data)
+#endif
+{
+ GtkCheckMenuItem *menuitem=GTK_CHECK_MENU_ITEM(widget);
+
+ gchar const *pref = (gchar const *) user_data;
+ Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
+ SPAction *action = (SPAction *) g_object_get_data(G_OBJECT(menuitem), "action");
+ SPDesktop *dt = static_cast<SPDesktop*>(view);
+
+ bool ison = false;
+ if (action) {
+
+ if (!strcmp(action->id, "ToggleGrid")) {
+ ison = dt->gridsEnabled();
+ }
+ else if (!strcmp(action->id, "ToggleGuides")) {
+ ison = dt->namedview->getGuides();
+ }
+ else if (!strcmp(action->id, "ViewCmsToggle")) {
+ ison = dt->colorProfAdjustEnabled();
+ }
+ else {
+ ison = getViewStateFromPref(view, pref);
+ }
+ } else if (pref) {
+ // The Show/Hide menu items without actions
+ ison = getViewStateFromPref(view, pref);
+ }
+
+ g_signal_handlers_block_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
+ gtk_check_menu_item_set_active(menuitem, ison);
+ g_signal_handlers_unblock_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
+
+ return FALSE;
+}
+
+
+static void taskToggled(GtkCheckMenuItem *menuitem, gpointer userData)
+{
+ if ( gtk_check_menu_item_get_active(menuitem) ) {
+ gint taskNum = GPOINTER_TO_INT(userData);
+ taskNum = (taskNum < 0) ? 0 : (taskNum > 2) ? 2 : taskNum;
+
+ Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
+
+ // note: this will change once more options are in the task set support:
+ Inkscape::UI::UXManager::getInstance()->setTask( dynamic_cast<SPDesktop*>(view), taskNum );
+ }
+}
+
+
+/**
+ * Callback function to update the status of the radio buttons in the View -> Display mode menu (Normal, No Filters, Outline) and Color display mode.
+ */
+#if GTK_CHECK_VERSION(3,0,0)
+static gboolean update_view_menu(GtkWidget *widget, cairo_t * /*cr*/, gpointer user_data)
+#else
+static gboolean update_view_menu(GtkWidget *widget, GdkEventExpose * /*event*/, gpointer user_data)
+#endif
+{
+ SPAction *action = (SPAction *) user_data;
+ g_assert(action->id != NULL);
+
+ Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(widget), "view");
+ SPDesktop *dt = static_cast<SPDesktop*>(view);
+ Inkscape::RenderMode mode = dt->getMode();
+ Inkscape::ColorMode colormode = dt->getColorMode();
+
+ bool new_state = false;
+ if (!strcmp(action->id, "ViewModeNormal")) {
+ new_state = mode == Inkscape::RENDERMODE_NORMAL;
+ } else if (!strcmp(action->id, "ViewModeNoFilters")) {
+ new_state = mode == Inkscape::RENDERMODE_NO_FILTERS;
+ } else if (!strcmp(action->id, "ViewModeOutline")) {
+ new_state = mode == Inkscape::RENDERMODE_OUTLINE;
+ } else if (!strcmp(action->id, "ViewColorModeNormal")) {
+ new_state = colormode == Inkscape::COLORMODE_NORMAL;
+ } else if (!strcmp(action->id, "ViewColorModeGrayscale")) {
+ new_state = colormode == Inkscape::COLORMODE_GRAYSCALE;
+ } else if (!strcmp(action->id, "ViewColorModePrintColorsPreview")) {
+ new_state = colormode == Inkscape::COLORMODE_PRINT_COLORS_PREVIEW;
+ } else {
+ g_warning("update_view_menu does not handle this verb");
+ }
+
+ if (new_state) { //only one of the radio buttons has to be activated; the others will automatically be deactivated
+ if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) {
+ // When the GtkMenuItem version of the "activate" signal has been emitted by a GtkRadioMenuItem, there is a second
+ // emission as the most recently active item is toggled to inactive. This is dealt with before the original signal is handled.
+ // This emission however should not invoke any actions, hence we block it here:
+ temporarily_block_actions = true;
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (widget), TRUE);
+ temporarily_block_actions = false;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *view, gchar const *label, gchar const *tip, gchar const *pref,
+ void (*callback_toggle)(GtkCheckMenuItem *, gpointer user_data),
+#if GTK_CHECK_VERSION(3,0,0)
+ gboolean (*callback_update)(GtkWidget *widget, cairo_t *cr, gpointer user_data),
+#else
+ gboolean (*callback_update)(GtkWidget *widget, GdkEventExpose *event, gpointer user_data),
+#endif
+ Inkscape::Verb *verb)
+{
+ unsigned int shortcut = (verb) ? sp_shortcut_get_primary(verb) : 0;
+ SPAction *action = (verb) ? verb->get_action(Inkscape::ActionContext(view)) : 0;
+ GtkWidget *item = gtk_check_menu_item_new_with_mnemonic(action ? action->name : label);
+
+#if 0
+ if (!action->sensitive) {
+ gtk_widget_set_sensitive(item, FALSE);
+ }
+#endif
+
+ sp_shortcut_add_accelerator(item, shortcut);
+
+ gtk_widget_show(item);
+
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+ g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
+ g_object_set_data(G_OBJECT(item), "action", (gpointer) action);
+
+ g_signal_connect( G_OBJECT(item), "toggled", (GCallback) callback_toggle, (void *) pref);
+
+#if GTK_CHECK_VERSION(3,0,0)
+ g_signal_connect( G_OBJECT(item), "draw", (GCallback) callback_update, (void *) pref);
+#else
+ g_signal_connect( G_OBJECT(item), "expose_event", (GCallback) callback_update, (void *) pref);
+#endif
+
+ (*callback_update)(item, NULL, (void *)pref);
+
+ g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) (action ? action->tip : tip));
+ g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
+
+}
+
+static void
+sp_recent_open(GtkRecentChooser *recent_menu, gpointer /*user_data*/)
+{
+ // dealing with the bizarre filename convention in Inkscape for now
+ gchar *uri = gtk_recent_chooser_get_current_uri(GTK_RECENT_CHOOSER(recent_menu));
+ gchar *local_fn = g_filename_from_uri(uri, NULL, NULL);
+ gchar *utf8_fn = g_filename_to_utf8(local_fn, -1, NULL, NULL, NULL);
+ sp_file_open(utf8_fn, NULL);
+ g_free(utf8_fn);
+ g_free(local_fn);
+ g_free(uri);
+}
+
+static void
+sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view)
+{
+ //sp_ui_menu_append_check_item_from_verb(m, view, _("_Menu"), _("Show or hide the menu bar"), "menu",
+ // checkitem_toggled, checkitem_update, 0);
+ sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "commands",
+ checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_COMMANDS_TOOLBAR));
+ sp_ui_menu_append_check_item_from_verb(m, view,NULL, NULL, "snaptoolbox",
+ checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_SNAP_TOOLBAR));
+ sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "toppanel",
+ checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_TOOL_TOOLBAR));
+ sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "toolbox",
+ checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_TOOLBOX));
+ sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "rulers",
+ checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_RULERS));
+ sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "scrollbars",
+ checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_SCROLLBARS));
+ sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "panels",
+ checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_PALETTE));
+ sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "statusbar",
+ checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_STATUSBAR));
+}
+
+
+static void addTaskMenuItems(GtkMenu *menu, Inkscape::UI::View::View *view)
+{
+ gchar const* data[] = {
+ C_("Interface setup", "Default"), _("Default interface setup"),
+ C_("Interface setup", "Custom"), _("Setup for custom task"),
+ C_("Interface setup", "Wide"), _("Setup for widescreen work"),
+ 0, 0
+ };
+
+ GSList *group = 0;
+ int count = 0;
+ gint active = Inkscape::UI::UXManager::getInstance()->getDefaultTask( dynamic_cast<SPDesktop*>(view) );
+ for (gchar const **strs = data; strs[0]; strs += 2, count++)
+ {
+ GtkWidget *item = gtk_radio_menu_item_new_with_label( group, strs[0] );
+ group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item) );
+ if ( count == active )
+ {
+ gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(item), TRUE );
+ }
+
+ g_object_set_data( G_OBJECT(item), "view", view );
+ g_signal_connect( G_OBJECT(item), "toggled", reinterpret_cast<GCallback>(taskToggled), GINT_TO_POINTER(count) );
+ g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), const_cast<gchar*>(strs[1]) );
+ g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), 0 );
+
+ gtk_widget_show( item );
+ gtk_menu_shell_append( GTK_MENU_SHELL(menu), item );
+ }
+}
+
+
+/**
+ * Observer that updates the recent list's max document count.
+ */
+class MaxRecentObserver : public Inkscape::Preferences::Observer {
+public:
+ MaxRecentObserver(GtkWidget *recent_menu) :
+ Observer("/options/maxrecentdocuments/value"),
+ _rm(recent_menu)
+ {}
+ virtual void notify(Inkscape::Preferences::Entry const &e) {
+ gtk_recent_chooser_set_limit(GTK_RECENT_CHOOSER(_rm), e.getInt());
+ // hack: the recent menu doesn't repopulate after changing the limit, so we force it
+ g_signal_emit_by_name((gpointer) gtk_recent_manager_get_default(), "changed");
+ }
+private:
+ GtkWidget *_rm;
+};
+
+/**
+ * This function turns XML into a menu.
+ *
+ * This function is realitively simple as it just goes through the XML
+ * and parses the individual elements. In the case of a submenu, it
+ * just calls itself recursively. Because it is only reasonable to have
+ * a couple of submenus, it is unlikely this will go more than two or
+ * three times.
+ *
+ * In the case of an unrecognized verb, a menu item is made to identify
+ * the verb that is missing, and display that. The menu item is also made
+ * insensitive.
+ *
+ * @param menus This is the XML that defines the menu
+ * @param menu Menu to be added to
+ * @param view The View that this menu is being built for
+ */
+static void sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI::View::View *view)
+{
+ if (menus == NULL) return;
+ if (menu == NULL) return;
+ GSList *group = NULL;
+
+ for (Inkscape::XML::Node *menu_pntr = menus;
+ menu_pntr != NULL;
+ menu_pntr = menu_pntr->next()) {
+ if (!strcmp(menu_pntr->name(), "submenu")) {
+ GtkWidget *mitem = gtk_menu_item_new_with_mnemonic(_(menu_pntr->attribute("name")));
+ GtkWidget *submenu = gtk_menu_new();
+ sp_ui_build_dyn_menus(menu_pntr->firstChild(), submenu, view);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), GTK_WIDGET(submenu));
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
+ continue;
+ }
+ if (!strcmp(menu_pntr->name(), "verb")) {
+ gchar const *verb_name = menu_pntr->attribute("verb-id");
+ Inkscape::Verb *verb = Inkscape::Verb::getbyid(verb_name);
+
+ if (verb != NULL) {
+ if (menu_pntr->attribute("radio") != NULL) {
+ GtkWidget *item = sp_ui_menu_append_item_from_verb (GTK_MENU(menu), verb, view, true, group);
+ group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item));
+ if (menu_pntr->attribute("default") != NULL) {
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
+ }
+ if (verb->get_code() != SP_VERB_NONE) {
+ SPAction *action = verb->get_action(Inkscape::ActionContext(view));
+#if GTK_CHECK_VERSION(3,0,0)
+ g_signal_connect( G_OBJECT(item), "draw", (GCallback) update_view_menu, (void *) action);
+#else
+ g_signal_connect( G_OBJECT(item), "expose_event", (GCallback) update_view_menu, (void *) action);
+#endif
+ }
+ } else if (menu_pntr->attribute("check") != NULL) {
+ SPAction *action = NULL;
+ if (verb->get_code() != SP_VERB_NONE) {
+ action = verb->get_action(Inkscape::ActionContext(view));
+ }
+ sp_ui_menu_append_check_item_from_verb(GTK_MENU(menu), view, action->name, action->tip, NULL,
+ checkitem_toggled, checkitem_update, verb);
+
+ } else {
+ sp_ui_menu_append_item_from_verb(GTK_MENU(menu), verb, view);
+ group = NULL;
+ }
+ } else {
+ gchar string[120];
+ g_snprintf(string, 120, _("Verb \"%s\" Unknown"), verb_name);
+ string[119] = '\0'; /* may not be terminated */
+ GtkWidget *item = gtk_menu_item_new_with_label(string);
+ gtk_widget_set_sensitive(item, false);
+ gtk_widget_show(item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+ }
+ continue;
+ }
+ if (!strcmp(menu_pntr->name(), "separator")
+ // This was spelt wrong in the original version
+ // and so this is for backward compatibility. It can
+ // probably be dropped after the 0.44 release.
+ || !strcmp(menu_pntr->name(), "seperator")) {
+ GtkWidget *item = gtk_separator_menu_item_new();
+ gtk_widget_show(item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+ continue;
+ }
+
+ if (!strcmp(menu_pntr->name(), "recent-file-list")) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+ // create recent files menu
+ int max_recent = prefs->getInt("/options/maxrecentdocuments/value");
+ GtkWidget *recent_menu = gtk_recent_chooser_menu_new_for_manager(gtk_recent_manager_get_default());
+ gtk_recent_chooser_set_limit(GTK_RECENT_CHOOSER(recent_menu), max_recent);
+ // sort most recently used documents first to preserve previous behavior
+ gtk_recent_chooser_set_sort_type(GTK_RECENT_CHOOSER(recent_menu), GTK_RECENT_SORT_MRU);
+ g_signal_connect(G_OBJECT(recent_menu), "item-activated", G_CALLBACK(sp_recent_open), (gpointer) NULL);
+
+ // add filter to only open files added by Inkscape
+ GtkRecentFilter *inkscape_only_filter = gtk_recent_filter_new();
+ gtk_recent_filter_add_application(inkscape_only_filter, g_get_prgname());
+ gtk_recent_chooser_add_filter(GTK_RECENT_CHOOSER(recent_menu), inkscape_only_filter);
+
+ gtk_recent_chooser_set_show_tips (GTK_RECENT_CHOOSER(recent_menu), TRUE);
+ gtk_recent_chooser_set_show_not_found (GTK_RECENT_CHOOSER(recent_menu), FALSE);
+
+ GtkWidget *recent_item = gtk_menu_item_new_with_mnemonic(_("Open _Recent"));
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent_item), recent_menu);
+
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), GTK_WIDGET(recent_item));
+ // this will just sit and update the list's item count
+ static MaxRecentObserver *mro = new MaxRecentObserver(recent_menu);
+ prefs->addObserver(*mro);
+ continue;
+ }
+ if (!strcmp(menu_pntr->name(), "objects-checkboxes")) {
+ sp_ui_checkboxes_menus(GTK_MENU(menu), view);
+ continue;
+ }
+ if (!strcmp(menu_pntr->name(), "task-checkboxes")) {
+ addTaskMenuItems(GTK_MENU(menu), view);
+ continue;
+ }
+ }
+}
+
+GtkWidget *sp_ui_main_menubar(Inkscape::UI::View::View *view)
+{
+ GtkWidget *mbar = gtk_menu_bar_new();
+ sp_ui_build_dyn_menus(inkscape_get_menus(INKSCAPE), mbar, view);
+ return mbar;
+}
+
+
+/* Drag and Drop */
+void
+sp_ui_drag_data_received(GtkWidget *widget,
+ GdkDragContext *drag_context,
+ gint x, gint y,
+ GtkSelectionData *data,
+ guint info,
+ guint /*event_time*/,
+ gpointer /*user_data*/)
+{
+ SPDocument *doc = SP_ACTIVE_DOCUMENT;
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+
+ switch (info) {
+#if ENABLE_MAGIC_COLORS
+ case APP_X_INKY_COLOR:
+ {
+ int destX = 0;
+ int destY = 0;
+ gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
+ Geom::Point where( sp_canvas_window_to_world( desktop->canvas, Geom::Point( destX, destY ) ) );
+
+ SPItem *item = desktop->getItemAtPoint( where, true );
+ if ( item )
+ {
+ bool fillnotstroke = (drag_context->action != GDK_ACTION_MOVE);
+
+ if ( data->length >= 8 ) {
+ cmsHPROFILE srgbProf = cmsCreate_sRGBProfile();
+
+ gchar c[64] = {0};
+ // Careful about endian issues.
+ guint16* dataVals = (guint16*)data->data;
+ sp_svg_write_color( c, sizeof(c),
+ SP_RGBA32_U_COMPOSE(
+ 0x0ff & (dataVals[0] >> 8),
+ 0x0ff & (dataVals[1] >> 8),
+ 0x0ff & (dataVals[2] >> 8),
+ 0xff // can't have transparency in the color itself
+ //0x0ff & (data->data[3] >> 8),
+ ));
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ bool updatePerformed = false;
+
+ if ( data->length > 14 ) {
+ int flags = dataVals[4];
+
+ // piggie-backed palette entry info
+ int index = dataVals[5];
+ Glib::ustring palName;
+ for ( int i = 0; i < dataVals[6]; i++ ) {
+ palName += (gunichar)dataVals[7+i];
+ }
+
+ // Now hook in a magic tag of some sort.
+ if ( !palName.empty() && (flags & 1) ) {
+ gchar* str = g_strdup_printf("%d|", index);
+ palName.insert( 0, str );
+ g_free(str);
+ str = 0;
+
+ item->setAttribute(
+ fillnotstroke ? "inkscape:x-fill-tag":"inkscape:x-stroke-tag",
+ palName.c_str(),
+ false );
+ item->updateRepr();
+
+ sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", c );
+ updatePerformed = true;
+ }
+ }
+
+ if ( !updatePerformed ) {
+ sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", c );
+ }
+
+ sp_desktop_apply_css_recursive( item, css, true );
+ item->updateRepr();
+
+ SPDocumentUndo::done( doc , SP_VERB_NONE,
+ _("Drop color"));
+
+ if ( srgbProf ) {
+ cmsCloseProfile( srgbProf );
+ }
+ }
+ }
+ }
+ break;
+#endif // ENABLE_MAGIC_COLORS
+
+ case APP_X_COLOR:
+ {
+ int destX = 0;
+ int destY = 0;
+ gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
+ Geom::Point where( sp_canvas_window_to_world( desktop->canvas, Geom::Point( destX, destY ) ) );
+ Geom::Point const button_dt(desktop->w2d(where));
+ Geom::Point const button_doc(desktop->dt2doc(button_dt));
+
+ if ( gtk_selection_data_get_length (data) == 8 ) {
+ gchar colorspec[64] = {0};
+ // Careful about endian issues.
+ guint16* dataVals = (guint16*)gtk_selection_data_get_data (data);
+ sp_svg_write_color( colorspec, sizeof(colorspec),
+ SP_RGBA32_U_COMPOSE(
+ 0x0ff & (dataVals[0] >> 8),
+ 0x0ff & (dataVals[1] >> 8),
+ 0x0ff & (dataVals[2] >> 8),
+ 0xff // can't have transparency in the color itself
+ //0x0ff & (data->data[3] >> 8),
+ ));
+
+ SPItem *item = desktop->getItemAtPoint( where, true );
+
+ bool consumed = false;
+ if (desktop->event_context && desktop->event_context->get_drag()) {
+ consumed = desktop->event_context->get_drag()->dropColor(item, colorspec, button_dt);
+ if (consumed) {
+ DocumentUndo::done( doc , SP_VERB_NONE, _("Drop color on gradient") );
+ desktop->event_context->get_drag()->updateDraggers();
+ }
+ }
+
+ //if (!consumed && tools_active(desktop, TOOLS_TEXT)) {
+ // consumed = sp_text_context_drop_color(c, button_doc);
+ // if (consumed) {
+ // SPDocumentUndo::done( doc , SP_VERB_NONE, _("Drop color on gradient stop"));
+ // }
+ //}
+
+ if (!consumed && item) {
+ bool fillnotstroke = (gdk_drag_context_get_actions (drag_context) != GDK_ACTION_MOVE);
+ if (fillnotstroke &&
+ (SP_IS_SHAPE(item) || SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item))) {
+ Path *livarot_path = Path_for_item(item, true, true);
+ livarot_path->ConvertWithBackData(0.04);
+
+ boost::optional<Path::cut_position> position = get_nearest_position_on_Path(livarot_path, button_doc);
+ if (position) {
+ Geom::Point nearest = get_point_on_Path(livarot_path, position->piece, position->t);
+ Geom::Point delta = nearest - button_doc;
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ delta = desktop->d2w(delta);
+ double stroke_tolerance =
+ ( !item->style->stroke.isNone() ?
+ desktop->current_zoom() *
+ item->style->stroke_width.computed *
+ item->i2dt_affine().descrim() * 0.5
+ : 0.0)
+ + prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
+
+ if (Geom::L2 (delta) < stroke_tolerance) {
+ fillnotstroke = false;
+ }
+ }
+ delete livarot_path;
+ }
+
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", colorspec );
+
+ sp_desktop_apply_css_recursive( item, css, true );
+ item->updateRepr();
+
+ DocumentUndo::done( doc , SP_VERB_NONE,
+ _("Drop color") );
+ }
+ }
+ }
+ break;
+
+ case APP_OSWB_COLOR:
+ {
+ bool worked = false;
+ Glib::ustring colorspec;
+ if ( gtk_selection_data_get_format (data) == 8 ) {
+ ege::PaintDef color;
+ worked = color.fromMIMEData("application/x-oswb-color",
+ reinterpret_cast<char const *>(gtk_selection_data_get_data (data)),
+ gtk_selection_data_get_length (data),
+ gtk_selection_data_get_format (data));
+ if ( worked ) {
+ if ( color.getType() == ege::PaintDef::CLEAR ) {
+ colorspec = ""; // TODO check if this is sufficient
+ } else if ( color.getType() == ege::PaintDef::NONE ) {
+ colorspec = "none";
+ } else {
+ unsigned int r = color.getR();
+ unsigned int g = color.getG();
+ unsigned int b = color.getB();
+
+ SPGradient* matches = 0;
+ const GSList *gradients = doc->getResourceList("gradient");
+ for (const GSList *item = gradients; item; item = item->next) {
+ SPGradient* grad = SP_GRADIENT(item->data);
+ if ( color.descr == grad->getId() ) {
+ if ( grad->hasStops() ) {
+ matches = grad;
+ break;
+ }
+ }
+ }
+ if (matches) {
+ colorspec = "url(#";
+ colorspec += matches->getId();
+ colorspec += ")";
+ } else {
+ gchar* tmp = g_strdup_printf("#%02x%02x%02x", r, g, b);
+ colorspec = tmp;
+ g_free(tmp);
+ }
+ }
+ }
+ }
+ if ( worked ) {
+ int destX = 0;
+ int destY = 0;
+ gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
+ Geom::Point where( sp_canvas_window_to_world( desktop->canvas, Geom::Point( destX, destY ) ) );
+ Geom::Point const button_dt(desktop->w2d(where));
+ Geom::Point const button_doc(desktop->dt2doc(button_dt));
+
+ SPItem *item = desktop->getItemAtPoint( where, true );
+
+ bool consumed = false;
+ if (desktop->event_context && desktop->event_context->get_drag()) {
+ consumed = desktop->event_context->get_drag()->dropColor(item, colorspec.c_str(), button_dt);
+ if (consumed) {
+ DocumentUndo::done( doc , SP_VERB_NONE, _("Drop color on gradient") );
+ desktop->event_context->get_drag()->updateDraggers();
+ }
+ }
+
+ if (!consumed && item) {
+ bool fillnotstroke = (gdk_drag_context_get_actions (drag_context) != GDK_ACTION_MOVE);
+ if (fillnotstroke &&
+ (SP_IS_SHAPE(item) || SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item))) {
+ Path *livarot_path = Path_for_item(item, true, true);
+ livarot_path->ConvertWithBackData(0.04);
+
+ boost::optional<Path::cut_position> position = get_nearest_position_on_Path(livarot_path, button_doc);
+ if (position) {
+ Geom::Point nearest = get_point_on_Path(livarot_path, position->piece, position->t);
+ Geom::Point delta = nearest - button_doc;
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ delta = desktop->d2w(delta);
+ double stroke_tolerance =
+ ( !item->style->stroke.isNone() ?
+ desktop->current_zoom() *
+ item->style->stroke_width.computed *
+ item->i2dt_affine().descrim() * 0.5
+ : 0.0)
+ + prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
+
+ if (Geom::L2 (delta) < stroke_tolerance) {
+ fillnotstroke = false;
+ }
+ }
+ delete livarot_path;
+ }
+
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", colorspec.c_str() );
+
+ sp_desktop_apply_css_recursive( item, css, true );
+ item->updateRepr();
+
+ DocumentUndo::done( doc , SP_VERB_NONE,
+ _("Drop color") );
+ }
+ }
+ }
+ break;
+
+ case SVG_DATA:
+ case SVG_XML_DATA: {
+ gchar *svgdata = (gchar *)gtk_selection_data_get_data (data);
+
+ Inkscape::XML::Document *rnewdoc = sp_repr_read_mem(svgdata, gtk_selection_data_get_length (data), SP_SVG_NS_URI);
+
+ if (rnewdoc == NULL) {
+ sp_ui_error_dialog(_("Could not parse SVG data"));
+ return;
+ }
+
+ Inkscape::XML::Node *repr = rnewdoc->root();
+ gchar const *style = repr->attribute("style");
+
+ Inkscape::XML::Node *newgroup = rnewdoc->createElement("svg:g");
+ newgroup->setAttribute("style", style);
+
+ Inkscape::XML::Document * xml_doc = doc->getReprDoc();
+ for (Inkscape::XML::Node *child = repr->firstChild(); child != NULL; child = child->next()) {
+ Inkscape::XML::Node *newchild = child->duplicate(xml_doc);
+ newgroup->appendChild(newchild);
+ }
+
+ Inkscape::GC::release(rnewdoc);
+
+ // Add it to the current layer
+
+ // Greg's edits to add intelligent positioning of svg drops
+ SPObject *new_obj = NULL;
+ new_obj = desktop->currentLayer()->appendChildRepr(newgroup);
+
+ Inkscape::Selection *selection = sp_desktop_selection(desktop);
+ selection->set(SP_ITEM(new_obj));
+
+ // move to mouse pointer
+ {
+ sp_desktop_document(desktop)->ensureUpToDate();
+ Geom::OptRect sel_bbox = selection->visualBounds();
+ if (sel_bbox) {
+ Geom::Point m( desktop->point() - sel_bbox->midpoint() );
+ sp_selection_move_relative(selection, m, false);
+ }
+ }
+
+ Inkscape::GC::release(newgroup);
+ DocumentUndo::done( doc, SP_VERB_NONE,
+ _("Drop SVG") );
+ break;
+ }
+
+ case URI_LIST: {
+ gchar *uri = (gchar *)gtk_selection_data_get_data (data);
+ sp_ui_import_files(uri);
+ break;
+ }
+
+ case APP_X_INK_PASTE: {
+ Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
+ cm->paste(desktop);
+ DocumentUndo::done( doc, SP_VERB_NONE, _("Drop Symbol") );
+ break;
+ }
+
+ case PNG_DATA:
+ case JPEG_DATA:
+ case IMAGE_DATA: {
+ const char *mime = (info == JPEG_DATA ? "image/jpeg" : "image/png");
+
+ Inkscape::Extension::DB::InputList o;
+ Inkscape::Extension::db.get_input_list(o);
+ Inkscape::Extension::DB::InputList::const_iterator i = o.begin();
+ while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
+ ++i;
+ }
+ Inkscape::Extension::Extension *ext = *i;
+ bool save = (strcmp(ext->get_param_optiongroup("link"), "embed") == 0);
+ ext->set_param_optiongroup("link", "embed");
+ ext->set_gui(false);
+
+ gchar *filename = g_build_filename( g_get_tmp_dir(), "inkscape-dnd-import", NULL );
+ g_file_set_contents(filename,
+ reinterpret_cast<gchar const *>(gtk_selection_data_get_data (data)),
+ gtk_selection_data_get_length (data),
+ NULL);
+ file_import(doc, filename, ext);
+ g_free(filename);
+
+ ext->set_param_optiongroup("link", save ? "embed" : "link");
+ ext->set_gui(true);
+ DocumentUndo::done( doc , SP_VERB_NONE,
+ _("Drop bitmap image") );
+ break;
+ }
+ }
+}
+
+#include "ui/tools/gradient-tool.h"
+
+void sp_ui_drag_motion( GtkWidget */*widget*/,
+ GdkDragContext */*drag_context*/,
+ gint /*x*/, gint /*y*/,
+ GtkSelectionData */*data*/,
+ guint /*info*/,
+ guint /*event_time*/,
+ gpointer /*user_data*/)
+{
+// SPDocument *doc = SP_ACTIVE_DOCUMENT;
+// SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+
+
+// g_message("drag-n-drop motion (%4d, %4d) at %d", x, y, event_time);
+}
+
+static void sp_ui_drag_leave( GtkWidget */*widget*/,
+ GdkDragContext */*drag_context*/,
+ guint /*event_time*/,
+ gpointer /*user_data*/ )
+{
+// g_message("drag-n-drop leave at %d", event_time);
+}
+
+static void
+sp_ui_import_files(gchar *buffer)
+{
+ GList *list = gnome_uri_list_extract_filenames(buffer);
+ if (!list)
+ return;
+ g_list_foreach(list, sp_ui_import_one_file_with_check, NULL);
+ g_list_foreach(list, (GFunc) g_free, NULL);
+ g_list_free(list);
+}
+
+static void
+sp_ui_import_one_file_with_check(gpointer filename, gpointer /*unused*/)
+{
+ if (filename) {
+ if (strlen((char const *)filename) > 2)
+ sp_ui_import_one_file((char const *)filename);
+ }
+}
+
+static void
+sp_ui_import_one_file(char const *filename)
+{
+ SPDocument *doc = SP_ACTIVE_DOCUMENT;
+ if (!doc) return;
+
+ if (filename == NULL) return;
+
+ // Pass off to common implementation
+ // TODO might need to get the proper type of Inkscape::Extension::Extension
+ file_import( doc, filename, NULL );
+}
+
+void
+sp_ui_error_dialog(gchar const *message)
+{
+ GtkWidget *dlg;
+ gchar *safeMsg = Inkscape::IO::sanitizeString(message);
+
+ dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE, "%s", safeMsg);
+ sp_transientize(dlg);
+ gtk_window_set_resizable(GTK_WINDOW(dlg), FALSE);
+ gtk_dialog_run(GTK_DIALOG(dlg));
+ gtk_widget_destroy(dlg);
+ g_free(safeMsg);
+}
+
+bool
+sp_ui_overwrite_file(gchar const *filename)
+{
+ bool return_value = FALSE;
+
+ if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS)) {
+ Gtk::Window *window = SP_ACTIVE_DESKTOP->getToplevel();
+ gchar* baseName = g_path_get_basename( filename );
+ gchar* dirName = g_path_get_dirname( filename );
+ GtkWidget* dialog = gtk_message_dialog_new_with_markup( window->gobj(),
+ (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ _( "<span weight=\"bold\" size=\"larger\">A file named \"%s\" already exists. Do you want to replace it?</span>\n\n"
+ "The file already exists in \"%s\". Replacing it will overwrite its contents." ),
+ baseName,
+ dirName
+ );
+ gtk_dialog_add_buttons( GTK_DIALOG(dialog),
+ _("_Cancel"), GTK_RESPONSE_NO,
+ _("Replace"), GTK_RESPONSE_YES,
+ NULL );
+ gtk_dialog_set_default_response( GTK_DIALOG(dialog), GTK_RESPONSE_YES );
+
+ if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_YES ) {
+ return_value = TRUE;
+ } else {
+ return_value = FALSE;
+ }
+ gtk_widget_destroy(dialog);
+ g_free( baseName );
+ g_free( dirName );
+ } else {
+ return_value = TRUE;
+ }
+
+ return return_value;
+}
+
+static void
+sp_ui_menu_item_set_name(GtkWidget *data, Glib::ustring const &name)
+{
+ if (data || GTK_IS_BIN (data)) {
+ void *child = gtk_bin_get_child (GTK_BIN (data));
+ //child is either
+ //- a GtkBox, whose first child is a label displaying name if the menu
+ //item has an accel key
+ //- a GtkLabel if the menu has no accel key
+ if (child != NULL){
+ if (GTK_IS_LABEL(child)) {
+ gtk_label_set_markup_with_mnemonic(GTK_LABEL (child), name.c_str());
+ } else if (GTK_IS_BOX(child)) {
+ gtk_label_set_markup_with_mnemonic(
+ GTK_LABEL (gtk_container_get_children(GTK_CONTAINER (child))->data),
+ name.c_str());
+ }//else sp_ui_menu_append_item_from_verb has been modified and can set
+ //a menu item in yet another way...
+ }
+ }
+}
+
+void injectRenamedIcons()
+{
+ Glib::RefPtr<Gtk::IconTheme> iconTheme = Gtk::IconTheme::get_default();
+
+ std::vector< std::pair<Glib::ustring, Glib::ustring> > renamed;
+ renamed.push_back(std::make_pair("gtk-file", "document-x-generic"));
+ renamed.push_back(std::make_pair("gtk-directory", "folder"));
+
+ for ( std::vector< std::pair<Glib::ustring, Glib::ustring> >::iterator it = renamed.begin(); it < renamed.end(); ++it ) {
+ bool hasIcon = iconTheme->has_icon(it->first);
+ bool hasSecondIcon = iconTheme->has_icon(it->second);
+
+ if ( !hasIcon && hasSecondIcon ) {
+ Glib::ArrayHandle<int> sizes = iconTheme->get_icon_sizes(it->second);
+ for ( Glib::ArrayHandle<int>::iterator it2 = sizes.begin(); it2 < sizes.end(); ++it2 ) {
+ Glib::RefPtr<Gdk::Pixbuf> pb = iconTheme->load_icon( it->second, *it2 );
+ if ( pb ) {
+ // install a private copy of the pixbuf to avoid pinning a theme
+ Glib::RefPtr<Gdk::Pixbuf> pbCopy = pb->copy();
+ Gtk::IconTheme::add_builtin_icon( it->first, *it2, pbCopy );
+ }
+ }
+ }
+ }
+}
+
+
+ContextMenu::ContextMenu(SPDesktop *desktop, SPItem *item) :
+ _item(item),
+ MIGroup(),
+ MIParent(_("Go to parent"))
+{
+// g_message("ContextMenu");
+ _object = static_cast<SPObject *>(item);
+ _desktop = desktop;
+
+ AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_UNDO));
+ AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_REDO));
+ AddSeparator();
+ AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_CUT));
+ AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_COPY));
+ AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_PASTE));
+ AddSeparator();
+ AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE));
+ AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_DELETE));
+
+ positionOfLastDialog = 10; // 9 in front + 1 for the separator in the next if; used to position the dialog menu entries below each other
+
+ /* Item menu */
+ if (item!=NULL) {
+ AddSeparator();
+ MakeObjectMenu();
+ }
+
+ /* layer menu */
+ SPGroup *group=NULL;
+ if (item) {
+ if (SP_IS_GROUP(item)) {
+ group = SP_GROUP(item);
+ } else if ( item != _desktop->currentRoot() && SP_IS_GROUP(item->parent) ) {
+ group = SP_GROUP(item->parent);
+ }
+ }
+
+ if (( group && group != _desktop->currentLayer() ) ||
+ ( _desktop->currentLayer() != _desktop->currentRoot() && _desktop->currentLayer()->parent != _desktop->currentRoot() ) ) {
+ AddSeparator();
+ }
+
+ if ( group && group != _desktop->currentLayer() ) {
+ /* TRANSLATORS: #%1 is the id of the group e.g. <g id="#g7">, not a number. */
+ MIGroup.set_label (Glib::ustring::compose(_("Enter group #%1"), group->getId()));
+ MIGroup.set_data("group", group);
+ MIGroup.signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &ContextMenu::EnterGroup),&MIGroup));
+ MIGroup.show();
+ append(MIGroup);
+ }
+
+ if ( _desktop->currentLayer() != _desktop->currentRoot() ) {
+ if ( _desktop->currentLayer()->parent != _desktop->currentRoot() ) {
+ MIParent.signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::LeaveGroup));
+ MIParent.show();
+ append(MIParent);
+ }
+ }
+}
+
+ContextMenu::~ContextMenu(void)
+{
+}
+
+Gtk::SeparatorMenuItem* ContextMenu::AddSeparator(void)
+{
+ Gtk::SeparatorMenuItem* sep = Gtk::manage(new Gtk::SeparatorMenuItem());
+ sep->show();
+ append(*sep);
+ return sep;
+}
+
+void ContextMenu::EnterGroup(Gtk::MenuItem* mi)
+{
+ _desktop->setCurrentLayer(reinterpret_cast<SPObject *>(mi->get_data("group")));
+ _desktop->selection->clear();
+}
+
+void ContextMenu::LeaveGroup(void)
+{
+ _desktop->setCurrentLayer(_desktop->currentLayer()->parent);
+}
+
+void ContextMenu::AppendItemFromVerb(Inkscape::Verb *verb)//, SPDesktop *view)//, bool radio, GSList *group)
+{
+ SPAction *action;
+ SPDesktop *view = _desktop;
+
+ if (verb->get_code() == SP_VERB_NONE) {
+ Gtk::MenuItem *item = AddSeparator();
+ item->show();
+ append(*item);
+ } else {
+ action = verb->get_action(Inkscape::ActionContext(view));
+ if (!action) {
+ return;
+ }
+
+ Gtk::ImageMenuItem *item = Gtk::manage(new Gtk::ImageMenuItem(action->name, true));
+
+ sp_shortcut_add_accelerator(GTK_WIDGET(item->gobj()), sp_shortcut_get_primary(verb));
+
+ action->signal_set_sensitive.connect(sigc::mem_fun(*this, &ContextMenu::set_sensitive));
+ action->signal_set_name.connect(sigc::mem_fun(*item, &ContextMenu::set_name));
+
+ if (!action->sensitive) {
+ item->set_sensitive(FALSE);
+ }
+
+ if (action->image) {
+ sp_ui_menuitem_add_icon((GtkWidget*)item->gobj(), action->image);
+ }
+ item->set_events(Gdk::KEY_PRESS_MASK);
+ item->signal_activate().connect(sigc::bind(sigc::ptr_fun(sp_ui_menu_activate),item,action));
+ item->signal_select().connect(sigc::bind(sigc::ptr_fun(sp_ui_menu_select_action),item,action));
+ item->signal_deselect().connect(sigc::bind(sigc::ptr_fun(sp_ui_menu_deselect_action),item,action));
+ item->show();
+ append(*item);
+ }
+}
+
+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();
+// }
+
+ 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)
+{
+ Gtk::MenuItem* mi;
+
+ /* Item dialog */
+ mi = Gtk::manage(new Gtk::MenuItem(_("_Object Properties..."),1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ItemProperties));
+ mi->show();
+ append(*mi);//insert(*mi,positionOfLastDialog++);
+
+ AddSeparator();
+
+ /* Select item */
+ if (Inkscape::Verb::getbyid( "org.inkscape.followlink" )) {
+ mi = Gtk::manage(new Gtk::MenuItem(_("_Select This"), 1));
+ if (_desktop->selection->includes(_item)) {
+ mi->set_sensitive(FALSE);
+ } else {
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ItemSelectThis));
+ }
+ mi->show();
+ append(*mi);
+ }
+
+
+ mi = Gtk::manage(new Gtk::MenuItem(_("Select Same")));
+ mi->show();
+ Gtk::Menu *select_same_submenu = Gtk::manage(new Gtk::Menu());
+ if (_desktop->selection->isEmpty()) {
+ mi->set_sensitive(FALSE);
+ }
+ mi->set_submenu(*select_same_submenu);
+ append(*mi);
+
+ /* Select same fill and stroke */
+ mi = Gtk::manage(new Gtk::MenuItem(_("Fill and Stroke"), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SelectSameFillStroke));
+ mi->set_sensitive(!SP_IS_ANCHOR(_item));
+ mi->show();
+ select_same_submenu->append(*mi);
+
+ /* Select same fill color */
+ mi = Gtk::manage(new Gtk::MenuItem(_("Fill Color"), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SelectSameFillColor));
+ mi->set_sensitive(!SP_IS_ANCHOR(_item));
+ mi->show();
+ select_same_submenu->append(*mi);
+
+ /* Select same stroke color */
+ mi = Gtk::manage(new Gtk::MenuItem(_("Stroke Color"), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SelectSameStrokeColor));
+ mi->set_sensitive(!SP_IS_ANCHOR(_item));
+ mi->show();
+ select_same_submenu->append(*mi);
+
+ /* Select same stroke style */
+ mi = Gtk::manage(new Gtk::MenuItem(_("Stroke Style"), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SelectSameStrokeStyle));
+ mi->set_sensitive(!SP_IS_ANCHOR(_item));
+ mi->show();
+ select_same_submenu->append(*mi);
+
+ /* Select same stroke style */
+ mi = Gtk::manage(new Gtk::MenuItem(_("Object type"), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SelectSameObjectType));
+ mi->set_sensitive(!SP_IS_ANCHOR(_item));
+ mi->show();
+ select_same_submenu->append(*mi);
+
+ /* Move to layer */
+ mi = Gtk::manage(new Gtk::MenuItem(_("_Move to layer ..."), 1));
+ if (_desktop->selection->isEmpty()) {
+ mi->set_sensitive(FALSE);
+ } else {
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ItemMoveTo));
+ }
+ mi->show();
+ append(*mi);
+
+ /* Create link */
+ mi = Gtk::manage(new Gtk::MenuItem(_("Create _Link"), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ItemCreateLink));
+ mi->set_sensitive(!SP_IS_ANCHOR(_item));
+ mi->show();
+ append(*mi);
+
+ bool ClipRefOK=false;
+ bool MaskRefOK=false;
+ if (_item){
+ if (_item->clip_ref){
+ if (_item->clip_ref->getObject()){
+ ClipRefOK=true;
+ }
+ }
+ }
+ if (_item){
+ if (_item->mask_ref){
+ if (_item->mask_ref->getObject()){
+ MaskRefOK=true;
+ }
+ }
+ }
+ /* Set mask */
+ mi = Gtk::manage(new Gtk::MenuItem(_("Set Mask"), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SetMask));
+ if (ClipRefOK || MaskRefOK) {
+ mi->set_sensitive(FALSE);
+ } else {
+ mi->set_sensitive(TRUE);
+ }
+ mi->show();
+ append(*mi);
+
+ /* Release mask */
+ mi = Gtk::manage(new Gtk::MenuItem(_("Release Mask"), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ReleaseMask));
+ if (MaskRefOK) {
+ mi->set_sensitive(TRUE);
+ } else {
+ mi->set_sensitive(FALSE);
+ }
+ mi->show();
+ append(*mi);
+
+ /*SSet Clip Group */
+ mi = Gtk::manage(new Gtk::MenuItem(_("Create Clip G_roup"),1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::CreateGroupClip));
+ mi->set_sensitive(TRUE);
+ mi->show();
+ append(*mi);
+
+ /* Set Clip */
+ mi = Gtk::manage(new Gtk::MenuItem(_("Set Cl_ip"), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SetClip));
+ if (ClipRefOK || MaskRefOK) {
+ mi->set_sensitive(FALSE);
+ } else {
+ mi->set_sensitive(TRUE);
+ }
+ mi->show();
+ append(*mi);
+
+ /* Release Clip */
+ mi = Gtk::manage(new Gtk::MenuItem(_("Release C_lip"), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ReleaseClip));
+ if (ClipRefOK) {
+ mi->set_sensitive(TRUE);
+ } else {
+ mi->set_sensitive(FALSE);
+ }
+ mi->show();
+ append(*mi);
+
+ /* Group */
+ mi = Gtk::manage(new Gtk::MenuItem(_("_Group"), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ActivateGroup));
+ if (_desktop->selection->isEmpty() || _desktop->selection->single()) {
+ mi->set_sensitive(FALSE);
+ } else {
+ mi->set_sensitive(TRUE);
+ }
+ mi->show();
+ append(*mi);
+}
+
+void ContextMenu::SelectSameFillStroke(void)
+{
+ sp_select_same_fill_stroke_style(_desktop, true, true, true);
+}
+
+void ContextMenu::SelectSameFillColor(void)
+{
+ sp_select_same_fill_stroke_style(_desktop, true, false, false);
+}
+
+void ContextMenu::SelectSameStrokeColor(void)
+{
+ sp_select_same_fill_stroke_style(_desktop, false, true, false);
+}
+
+void ContextMenu::SelectSameStrokeStyle(void)
+{
+ sp_select_same_stroke_style(_desktop);
+}
+
+void ContextMenu::SelectSameObjectType(void)
+{
+ sp_select_same_object_type(_desktop);
+}
+
+void ContextMenu::ItemProperties(void)
+{
+ _desktop->selection->set(_item);
+ _desktop->_dlg_mgr->showDialog("ObjectProperties");
+}
+
+void ContextMenu::ItemSelectThis(void)
+{
+ _desktop->selection->set(_item);
+}
+
+void ContextMenu::ItemMoveTo(void)
+{
+ Inkscape::UI::Dialogs::LayerPropertiesDialog::showMove(_desktop, _desktop->currentLayer());
+}
+
+
+
+void ContextMenu::ItemCreateLink(void)
+{
+ Inkscape::XML::Document *xml_doc = _desktop->doc()->getReprDoc();
+ Inkscape::XML::Node *repr = xml_doc->createElement("svg:a");
+ _item->parent->getRepr()->addChild(repr, _item->getRepr());
+ SPObject *object = _item->document->getObjectByRepr(repr);
+ g_return_if_fail(SP_IS_ANCHOR(object));
+
+ const char *id = _item->getRepr()->attribute("id");
+ Inkscape::XML::Node *child = _item->getRepr()->duplicate(xml_doc);
+ _item->deleteObject(false);
+ repr->addChild(child, NULL);
+ child->setAttribute("id", id);
+
+ Inkscape::GC::release(repr);
+ Inkscape::GC::release(child);
+
+ DocumentUndo::done(object->document, SP_VERB_NONE, _("Create link"));
+
+ _desktop->selection->set(SP_ITEM(object));
+ _desktop->_dlg_mgr->showDialog("ObjectAttributes");
+}
+
+void ContextMenu::SetMask(void)
+{
+ sp_selection_set_mask(_desktop, false, false);
+}
+
+void ContextMenu::ReleaseMask(void)
+{
+ sp_selection_unset_mask(_desktop, false);
+}
+
+void ContextMenu::CreateGroupClip(void)
+{
+ sp_selection_set_clipgroup(_desktop);
+}
+
+void ContextMenu::SetClip(void)
+{
+ sp_selection_set_mask(_desktop, true, false);
+}
+
+
+void ContextMenu::ReleaseClip(void)
+{
+ sp_selection_unset_mask(_desktop, true);
+}
+
+void ContextMenu::MakeGroupMenu(void)
+{
+ /* Ungroup */
+ Gtk::MenuItem* mi = Gtk::manage(new Gtk::MenuItem(_("_Ungroup"), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ActivateUngroup));
+ mi->show();
+ append(*mi);
+}
+
+void ContextMenu::ActivateGroup(void)
+{
+ sp_selection_group(_desktop->selection, _desktop);
+}
+
+void ContextMenu::ActivateUngroup(void)
+{
+ GSList *children = NULL;
+
+ sp_item_group_ungroup(static_cast<SPGroup*>(_item), &children);
+ _desktop->selection->setList(children);
+ g_slist_free(children);
+}
+
+void ContextMenu::MakeAnchorMenu(void)
+{
+ Gtk::MenuItem* mi;
+
+ /* Link dialog */
+ mi = Gtk::manage(new Gtk::MenuItem(_("Link _Properties..."), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::AnchorLinkProperties));
+ mi->show();
+ insert(*mi,positionOfLastDialog++);
+
+ /* Select item */
+ mi = Gtk::manage(new Gtk::MenuItem(_("_Follow Link"), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::AnchorLinkFollow));
+ mi->show();
+ append(*mi);
+
+ /* Reset transformations */
+ mi = Gtk::manage(new Gtk::MenuItem(_("_Remove Link"), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::AnchorLinkRemove));
+ mi->show();
+ append(*mi);
+}
+
+void ContextMenu::AnchorLinkProperties(void)
+{
+ _desktop->_dlg_mgr->showDialog("ObjectAttributes");
+}
+
+void ContextMenu::AnchorLinkFollow(void)
+{
+
+ if (_desktop->selection->isEmpty()) {
+ _desktop->selection->set(_item);
+ }
+ // Opening the selected links with a python extension
+ Inkscape::Verb *verb = Inkscape::Verb::getbyid( "org.inkscape.followlink" );
+ if (verb) {
+ SPAction *action = verb->get_action(Inkscape::ActionContext(_desktop));
+ if (action) {
+ sp_action_perform(action, NULL);
+ }
+ }
+}
+
+void ContextMenu::AnchorLinkRemove(void)
+{
+ GSList *children = NULL;
+ sp_item_group_ungroup(static_cast<SPAnchor*>(_item), &children, false);
+ DocumentUndo::done(_desktop->doc(), SP_VERB_NONE, _("Remove link"));
+ g_slist_free(children);
+}
+
+void ContextMenu::MakeImageMenu (void)
+{
+ Gtk::MenuItem* mi;
+ Inkscape::XML::Node *ir = _object->getRepr();
+ const gchar *href = ir->attribute("xlink:href");
+
+ /* Image properties */
+ mi = Gtk::manage(new Gtk::MenuItem(_("Image _Properties..."), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageProperties));
+ mi->show();
+ insert(*mi,positionOfLastDialog++);
+
+ /* Edit externally */
+ mi = Gtk::manage(new Gtk::MenuItem(_("Edit Externally..."), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageEdit));
+ mi->show();
+ insert(*mi,positionOfLastDialog++);
+ if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) {
+ mi->set_sensitive( FALSE );
+ }
+
+ /* Trace Bitmap */
+ mi = Gtk::manage(new Gtk::MenuItem(_("_Trace Bitmap..."), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageTraceBitmap));
+ mi->show();
+ insert(*mi,positionOfLastDialog++);
+ if (_desktop->selection->isEmpty()) {
+ mi->set_sensitive(FALSE);
+ }
+
+ /* Trace Pixel Art */
+ mi = Gtk::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 = Gtk::manage(new Gtk::MenuItem(C_("Context menu", "Embed Image")));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageEmbed));
+ mi->show();
+ insert(*mi,positionOfLastDialog++);
+ if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) {
+ mi->set_sensitive( FALSE );
+ }
+ }
+
+ /* Extract image */
+ if (Inkscape::Verb::getbyid( "org.ekips.filter.extractimage" )) {
+ mi = Gtk::manage(new Gtk::MenuItem(C_("Context menu", "Extract Image...")));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageExtract));
+ mi->show();
+ insert(*mi,positionOfLastDialog++);
+ if ( (!href) || ((strncmp(href, "data:", 5) != 0)) ) {
+ mi->set_sensitive( FALSE );
+ }
+ }
+}
+
+void ContextMenu::ImageProperties(void)
+{
+ _desktop->_dlg_mgr->showDialog("ObjectAttributes");
+}
+
+Glib::ustring ContextMenu::getImageEditorName() {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ Glib::ustring value;
+ Glib::ustring choices = prefs->getString("/options/bitmapeditor/value");
+ if (!choices.empty()) {
+ value = choices;
+ }
+ else {
+ value = "gimp";
+ }
+ return value;
+}
+
+void ContextMenu::ImageEdit(void)
+{
+ if (_desktop->selection->isEmpty()) {
+ _desktop->selection->set(_item);
+ }
+
+ GSList const *selected = _desktop->selection->itemList();
+
+ GError* errThing = 0;
+ Glib::ustring cmdline = getImageEditorName();
+ Glib::ustring name;
+ Glib::ustring fullname;
+
+#ifdef WIN32
+ // g_spawn_command_line_sync parsing is done according to Unix shell rules,
+ // not Windows command interpreter rules. Thus we need to enclose the
+ // executable path with single quotes.
+ int index = cmdline.find(".exe");
+ if ( index < 0 ) index = cmdline.find(".bat");
+ if ( index < 0 ) index = cmdline.find(".com");
+ if ( index >= 0 ) {
+ Glib::ustring editorBin = cmdline.substr(0, index + 4).c_str();
+ Glib::ustring args = cmdline.substr(index + 4, cmdline.length()).c_str();
+ editorBin.insert(0, "'");
+ editorBin.append("'");
+ cmdline = editorBin;
+ cmdline.append(args);
+ } else {
+ // Enclose the whole command line if no executable path can be extracted.
+ cmdline.insert(0, "'");
+ cmdline.append("'");
+ }
+#endif
+
+ for (GSList const *iter = selected; iter != NULL; iter = iter->next) {
+ Inkscape::XML::Node *ir = SP_ITEM(iter->data)->getRepr();
+ const gchar *href = ir->attribute("xlink:href");
+
+ if (strncmp (href,"file:",5) == 0) {
+ // URI to filename conversion
+ name = g_filename_from_uri(href, NULL, NULL);
+ } else {
+ name.append(href);
+ }
+
+ if (Glib::path_is_absolute(name)) {
+ fullname = name;
+ } else if (SP_ACTIVE_DOCUMENT->getBase()) {
+ fullname = Glib::build_filename(SP_ACTIVE_DOCUMENT->getBase(), name);
+ } else {
+ fullname = Glib::build_filename(Glib::get_current_dir(), name);
+ }
+
+ cmdline.append(" '");
+ cmdline.append(fullname.c_str());
+ cmdline.append("'");
+ }
+
+ //g_warning("##Command line: %s\n", cmdline.c_str());
+
+ g_spawn_command_line_async(cmdline.c_str(), &errThing);
+
+ if ( errThing ) {
+ g_warning("Problem launching editor (%d). %s", errThing->code, errThing->message);
+ (_desktop->messageStack())->flash(Inkscape::ERROR_MESSAGE, errThing->message);
+ g_error_free(errThing);
+ errThing = 0;
+ }
+}
+
+void ContextMenu::ImageTraceBitmap(void)
+{
+ inkscape_dialogs_unhide();
+ _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()) {
+ _desktop->selection->set(_item);
+ }
+
+ Inkscape::Verb *verb = Inkscape::Verb::getbyid( "org.ekips.filter.embedselectedimages" );
+ if (verb) {
+ SPAction *action = verb->get_action(Inkscape::ActionContext(_desktop));
+ if (action) {
+ sp_action_perform(action, NULL);
+ }
+ }
+}
+
+void ContextMenu::ImageExtract(void)
+{
+ if (_desktop->selection->isEmpty()) {
+ _desktop->selection->set(_item);
+ }
+
+ Inkscape::Verb *verb = Inkscape::Verb::getbyid( "org.ekips.filter.extractimage" );
+ if (verb) {
+ SPAction *action = verb->get_action(Inkscape::ActionContext(_desktop));
+ if (action) {
+ sp_action_perform(action, NULL);
+ }
+ }
+}
+
+void ContextMenu::MakeShapeMenu (void)
+{
+ Gtk::MenuItem* mi;
+
+ /* Item dialog */
+ mi = Gtk::manage(new Gtk::MenuItem(_("_Fill and Stroke..."), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::FillSettings));
+ mi->show();
+ insert(*mi,positionOfLastDialog++);
+}
+
+void ContextMenu::FillSettings(void)
+{
+ if (_desktop->selection->isEmpty()) {
+ _desktop->selection->set(_item);
+ }
+
+ _desktop->_dlg_mgr->showDialog("FillAndStroke");
+}
+
+void ContextMenu::MakeTextMenu (void)
+{
+ Gtk::MenuItem* mi;
+
+ /* Fill and Stroke dialog */
+ mi = Gtk::manage(new Gtk::MenuItem(_("_Fill and Stroke..."), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::FillSettings));
+ mi->show();
+ insert(*mi,positionOfLastDialog++);
+
+ /* Edit Text dialog */
+ mi = Gtk::manage(new Gtk::MenuItem(_("_Text and Font..."), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::TextSettings));
+ mi->show();
+ insert(*mi,positionOfLastDialog++);
+
+ /* Spellcheck dialog */
+ mi = Gtk::manage(new Gtk::MenuItem(_("Check Spellin_g..."), 1));
+ mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SpellcheckSettings));
+ mi->show();
+ insert(*mi,positionOfLastDialog++);
+}
+
+void ContextMenu::TextSettings (void)
+{
+ if (_desktop->selection->isEmpty()) {
+ _desktop->selection->set(_item);
+ }
+
+ _desktop->_dlg_mgr->showDialog("TextFont");
+}
+
+void ContextMenu::SpellcheckSettings (void)
+{
+ if (_desktop->selection->isEmpty()) {
+ _desktop->selection->set(_item);
+ }
+
+ _desktop->_dlg_mgr->showDialog("SpellCheck");
+}
+
+/*
+ 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/interface.h b/src/ui/interface.h
new file mode 100644
index 000000000..6fb74046f
--- /dev/null
+++ b/src/ui/interface.h
@@ -0,0 +1,277 @@
+#ifndef SEEN_SP_INTERFACE_H
+#define SEEN_SP_INTERFACE_H
+
+/*
+ * Main UI stuff
+ *
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Frank Felfe <innerspace@iname.com>
+ * Abhishek Sharma
+ * Kris De Gussem <Kris.DeGussem@gmail.com>
+ *
+ * Copyright (C) 2012 Kris De Gussem
+ * Copyright (C) 1999-2002 authors
+ * Copyright (C) 2001-2002 Ximian, Inc.
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+//#ifdef HAVE_CONFIG_H
+//# include <config.h>
+//#endif
+
+#include <gtkmm/menu.h>
+
+class SPItem;
+class SPObject;
+class SPDesktop;
+class SPViewWidget;
+
+namespace Gtk {
+class SeparatorMenuItem;
+}
+
+namespace Inkscape {
+
+class Verb;
+
+namespace UI {
+namespace View {
+class View;
+} // namespace View
+} // namespace UI
+} // namespace Inkscape
+
+/**
+ * Create a new document window.
+ */
+void sp_create_window (SPViewWidget *vw, bool editable);
+
+/**
+ * \param widget unused
+ */
+void sp_ui_close_view (GtkWidget *widget);
+
+void sp_ui_new_view (void);
+
+/**
+ * @todo TODO: not yet working. To be re-enabled (by adding to menu) once it works.
+ */
+void sp_ui_new_view_preview (void);
+
+/**
+ * This function is called to exit the program, and iterates through all
+ * open document view windows, attempting to close each in turn. If the
+ * view has unsaved information, the user will be prompted to save,
+ * discard, or cancel.
+ *
+ * Returns FALSE if the user cancels the close_all operation, TRUE
+ * otherwise.
+ */
+unsigned int sp_ui_close_all (void);
+
+/**
+ * Build the main tool bar.
+ *
+ * Currently the main tool bar is built as a dynamic XML menu using
+ * \c sp_ui_build_dyn_menus. This function builds the bar, and then
+ * pass it to get items attached to it.
+ *
+ * @param view View to build the bar for
+ */
+GtkWidget *sp_ui_main_menubar (Inkscape::UI::View::View *view);
+
+void sp_menu_append_recent_documents (GtkWidget *menu);
+void sp_ui_dialog_title_string (Inkscape::Verb * verb, char* c);
+
+Glib::ustring getLayoutPrefPath( Inkscape::UI::View::View *view );
+
+/**
+ *
+ */
+void sp_ui_error_dialog (char const* message);
+bool sp_ui_overwrite_file (char const* filename);
+
+
+/**
+ * Implements the Inkscape context menu.
+ *
+ * For the context menu implementation, the ContextMenu class stores the object
+ * that was selected in a private data member. This should be farely safe to do
+ * and a pointer to the SPItem as well as SPObject class are kept.
+ * All callbacks of the context menu entries are implemented as private
+ * functions.
+ *
+ * @todo add callbacks to destroy the context menu when it is closed (=key or mouse button pressed out of the scope of the context menu)
+ */
+class ContextMenu : public Gtk::Menu
+{
+ public:
+ /**
+ * The ContextMenu constructor contains all code to create and show the
+ * menu entries (aka child widgets).
+ *
+ * @param desktop pointer to the desktop the user is currently working on.
+ * @param item SPItem pointer to the object selected at the time the ContextMenu is created.
+ */
+ ContextMenu(SPDesktop *desktop, SPItem *item);
+ ~ContextMenu(void);
+
+ private:
+ SPItem *_item; // pointer to the object selected at the time the ContextMenu is created
+ SPObject *_object; // pointer to the object selected at the time the ContextMenu is created
+ SPDesktop *_desktop; //pointer to the desktop the user was currently working on at the time the ContextMenu is created
+
+ int positionOfLastDialog;
+
+ Gtk::MenuItem MIGroup; //menu entry to enter a group
+ Gtk::MenuItem MIParent; //menu entry to leave a group
+
+ /**
+ * auxiliary function that adds a separator line in the context menu
+ */
+ Gtk::SeparatorMenuItem* AddSeparator(void);
+
+ /**
+ * c++ified version of sp_ui_menu_append_item.
+ *
+ * @see sp_ui_menu_append_item_from_verb and synchronize/drop that function when c++ifying other code in interface.cpp
+ */
+ void AppendItemFromVerb(Inkscape::Verb *verb);
+
+ /**
+ * main function which is responsible for creating the context sensitive menu items,
+ * calls subfunctions below to create the menu entry widgets.
+ */
+ void MakeObjectMenu (void);
+ /**
+ * creates menu entries for an SP_TYPE_ITEM object
+ */
+ void MakeItemMenu (void);
+ /**
+ * creates menu entries for a grouped object
+ */
+ void MakeGroupMenu (void);
+ /**
+ * creates menu entries for an anchor object
+ */
+ void MakeAnchorMenu (void);
+ /**
+ * creates menu entries for a bitmap image object
+ */
+ void MakeImageMenu (void);
+ /**
+ * creates menu entries for a shape object
+ */
+ void MakeShapeMenu (void);
+ /**
+ * creates menu entries for a text object
+ */
+ void MakeTextMenu (void);
+
+ void EnterGroup(Gtk::MenuItem* mi);
+ void LeaveGroup(void);
+ //////////////////////////////////////////
+ //callbacks for the context menu entries of an SP_TYPE_ITEM object
+ void ItemProperties(void);
+ void ItemSelectThis(void);
+ void ItemMoveTo(void);
+ void SelectSameFillStroke(void);
+ void SelectSameFillColor(void);
+ void SelectSameStrokeColor(void);
+ void SelectSameStrokeStyle(void);
+ void SelectSameObjectType(void);
+ void ItemCreateLink(void);
+ void CreateGroupClip(void);
+ void SetMask(void);
+ void ReleaseMask(void);
+ void SetClip(void);
+ void ReleaseClip(void);
+ //////////////////////////////////////////
+
+
+ /**
+ * callback, is executed on clicking the anchor "Group" and "Ungroup" menu entry
+ */
+ void ActivateUngroup(void);
+ void ActivateGroup(void);
+
+ void AnchorLinkProperties(void);
+ /**
+ * placeholder for callback to be executed on clicking the anchor "Follow link" context menu entry
+ * @todo add code to follow link externally
+ */
+ void AnchorLinkFollow(void);
+
+ /**
+ * callback, is executed on clicking the anchor "Link remove" menu entry
+ */
+ void AnchorLinkRemove(void);
+
+
+ /**
+ * callback, opens the image properties dialog and is executed on clicking the context menu entry with similar name
+ */
+ void ImageProperties(void);
+
+ /**
+ * callback, is executed on clicking the image "Edit Externally" menu entry
+ */
+ void ImageEdit(void);
+
+ /**
+ * auxiliary function that loads the external image editor name from the settings.
+ */
+ Glib::ustring getImageEditorName();
+
+ /**
+ * callback, is executed on clicking the "Embed Image" menu entry
+ */
+ void ImageEmbed(void);
+
+ /**
+ * callback, is executed on clicking the "Trace Bitmap" menu entry
+ */
+ 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);
+
+
+ /**
+ * callback, is executed on clicking the "Fill and Stroke" menu entry
+ */
+ void FillSettings(void);
+
+
+ /**
+ * callback, is executed on clicking the "Text and Font" menu entry
+ */
+ void TextSettings(void);
+
+ /**
+ * callback, is executed on clicking the "Check spelling" menu entry
+ */
+ void SpellcheckSettings(void);
+};
+
+#endif // SEEN_SP_INTERFACE_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/object-edit.cpp b/src/ui/object-edit.cpp
new file mode 100644
index 000000000..ca550502d
--- /dev/null
+++ b/src/ui/object-edit.cpp
@@ -0,0 +1,1452 @@
+/*
+ * Node editing extension to objects
+ *
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Mitsuru Oka
+ * Maximilian Albert <maximilian.albert@gmail.com>
+ * Abhishek Sharma
+ * Jon A. Cruz <jon@joncruz.org>
+ *
+ * Licensed under GNU GPL
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+
+
+#include "sp-item.h"
+#include "sp-rect.h"
+#include "box3d.h"
+#include "sp-ellipse.h"
+#include "sp-star.h"
+#include "sp-spiral.h"
+#include "sp-offset.h"
+#include "sp-flowtext.h"
+#include "preferences.h"
+#include "style.h"
+#include "desktop.h"
+#include "desktop-handles.h"
+#include "sp-namedview.h"
+#include "live_effects/effect.h"
+#include "sp-pattern.h"
+#include "sp-path.h"
+#include <glibmm/i18n.h>
+#include "ui/object-edit.h"
+#include "xml/repr.h"
+#include <2geom/math-utils.h>
+#include "knot-holder-entity.h"
+
+#define sp_round(v,m) (((v) < 0.0) ? ((ceil((v) / (m) - 0.5)) * (m)) : ((floor((v) / (m) + 0.5)) * (m)))
+
+namespace {
+
+static KnotHolder *sp_lpe_knot_holder(SPLPEItem *item, SPDesktop *desktop)
+{
+ KnotHolder *knot_holder = new KnotHolder(desktop, item, NULL);
+
+ Inkscape::LivePathEffect::Effect *effect = item->getCurrentLPE();
+ effect->addHandles(knot_holder, desktop, item);
+
+ return knot_holder;
+}
+
+} // namespace
+
+namespace Inkscape {
+namespace UI {
+
+KnotHolder *createKnotHolder(SPItem *item, SPDesktop *desktop)
+{
+ KnotHolder *knotholder = NULL;
+
+ SPLPEItem *lpe = dynamic_cast<SPLPEItem *>(item);
+ if (lpe &&
+ lpe->getCurrentLPE() &&
+ lpe->getCurrentLPE()->isVisible() &&
+ lpe->getCurrentLPE()->providesKnotholder()) {
+ knotholder = sp_lpe_knot_holder(lpe, desktop);
+ } else if (dynamic_cast<SPRect *>(item)) {
+ knotholder = new RectKnotHolder(desktop, item, NULL);
+ } else if (dynamic_cast<SPBox3D *>(item)) {
+ knotholder = new Box3DKnotHolder(desktop, item, NULL);
+ } else if (dynamic_cast<SPGenericEllipse *>(item)) {
+ knotholder = new ArcKnotHolder(desktop, item, NULL);
+ } else if (dynamic_cast<SPStar *>(item)) {
+ knotholder = new StarKnotHolder(desktop, item, NULL);
+ } else if (dynamic_cast<SPSpiral *>(item)) {
+ knotholder = new SpiralKnotHolder(desktop, item, NULL);
+ } else if (dynamic_cast<SPOffset *>(item)) {
+ knotholder = new OffsetKnotHolder(desktop, item, NULL);
+ } else {
+ SPFlowtext *flowtext = dynamic_cast<SPFlowtext *>(item);
+ if (flowtext && flowtext->has_internal_frame()) {
+ knotholder = new FlowtextKnotHolder(desktop, flowtext->get_frame(NULL), NULL);
+ } else if ((item->style->fill.isPaintserver() && dynamic_cast<SPPattern *>(item->style->getFillPaintServer())) ||
+ (item->style->stroke.isPaintserver() && dynamic_cast<SPPattern *>(item->style->getStrokePaintServer()))) {
+ knotholder = new KnotHolder(desktop, item, NULL);
+ knotholder->add_pattern_knotholder();
+ }
+ }
+
+ return knotholder;
+}
+
+}
+} // namespace Inkscape
+
+/* SPRect */
+
+/* handle for horizontal rounding radius */
+class RectKnotHolderEntityRX : public KnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+ virtual void knot_click(unsigned int state);
+};
+
+/* handle for vertical rounding radius */
+class RectKnotHolderEntityRY : public KnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+ virtual void knot_click(unsigned int state);
+};
+
+/* handle for width/height adjustment */
+class RectKnotHolderEntityWH : public KnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+
+protected:
+ void set_internal(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+};
+
+/* handle for x/y adjustment */
+class RectKnotHolderEntityXY : public KnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+};
+
+Geom::Point
+RectKnotHolderEntityRX::knot_get() const
+{
+ SPRect *rect = dynamic_cast<SPRect *>(item);
+ g_assert(rect != NULL);
+
+ return Geom::Point(rect->x.computed + rect->width.computed - rect->rx.computed, rect->y.computed);
+}
+
+void
+RectKnotHolderEntityRX::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int state)
+{
+ SPRect *rect = dynamic_cast<SPRect *>(item);
+ g_assert(rect != NULL);
+
+ //In general we cannot just snap this radius to an arbitrary point, as we have only a single
+ //degree of freedom. For snapping to an arbitrary point we need two DOF. If we're going to snap
+ //the radius then we should have a constrained snap. snap_knot_position() is unconstrained
+ Geom::Point const s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed), Geom::Point(-1, 0)), state);
+
+ if (state & GDK_CONTROL_MASK) {
+ gdouble temp = MIN(rect->height.computed, rect->width.computed) / 2.0;
+ rect->rx.computed = rect->ry.computed = CLAMP(rect->x.computed + rect->width.computed - s[Geom::X], 0.0, temp);
+ rect->rx._set = rect->ry._set = true;
+
+ } else {
+ rect->rx.computed = CLAMP(rect->x.computed + rect->width.computed - s[Geom::X], 0.0, rect->width.computed / 2.0);
+ rect->rx._set = true;
+ }
+
+ update_knot();
+
+ rect->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+void
+RectKnotHolderEntityRX::knot_click(unsigned int state)
+{
+ SPRect *rect = dynamic_cast<SPRect *>(item);
+ g_assert(rect != NULL);
+
+ if (state & GDK_SHIFT_MASK) {
+ /* remove rounding from rectangle */
+ rect->getRepr()->setAttribute("rx", NULL);
+ rect->getRepr()->setAttribute("ry", NULL);
+ } else if (state & GDK_CONTROL_MASK) {
+ /* Ctrl-click sets the vertical rounding to be the same as the horizontal */
+ rect->getRepr()->setAttribute("ry", rect->getRepr()->attribute("rx"));
+ }
+
+}
+
+Geom::Point
+RectKnotHolderEntityRY::knot_get() const
+{
+ SPRect *rect = dynamic_cast<SPRect *>(item);
+ g_assert(rect != NULL);
+
+ return Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->ry.computed);
+}
+
+void
+RectKnotHolderEntityRY::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int state)
+{
+ SPRect *rect = dynamic_cast<SPRect *>(item);
+ g_assert(rect != NULL);
+
+ //In general we cannot just snap this radius to an arbitrary point, as we have only a single
+ //degree of freedom. For snapping to an arbitrary point we need two DOF. If we're going to snap
+ //the radius then we should have a constrained snap. snap_knot_position() is unconstrained
+ Geom::Point const s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed), Geom::Point(0, 1)), state);
+
+ if (state & GDK_CONTROL_MASK) { // When holding control then rx will be kept equal to ry,
+ // resulting in a perfect circle (and not an ellipse)
+ gdouble temp = MIN(rect->height.computed, rect->width.computed) / 2.0;
+ rect->rx.computed = rect->ry.computed = CLAMP(s[Geom::Y] - rect->y.computed, 0.0, temp);
+ rect->ry._set = rect->rx._set = true;
+ } else {
+ if (!rect->rx._set || rect->rx.computed == 0) {
+ rect->ry.computed = CLAMP(s[Geom::Y] - rect->y.computed,
+ 0.0,
+ MIN(rect->height.computed / 2.0, rect->width.computed / 2.0));
+ } else {
+ rect->ry.computed = CLAMP(s[Geom::Y] - rect->y.computed,
+ 0.0,
+ rect->height.computed / 2.0);
+ }
+
+ rect->ry._set = true;
+ }
+
+ update_knot();
+
+ rect->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+void
+RectKnotHolderEntityRY::knot_click(unsigned int state)
+{
+ SPRect *rect = dynamic_cast<SPRect *>(item);
+ g_assert(rect != NULL);
+
+ if (state & GDK_SHIFT_MASK) {
+ /* remove rounding */
+ rect->getRepr()->setAttribute("rx", NULL);
+ rect->getRepr()->setAttribute("ry", NULL);
+ } else if (state & GDK_CONTROL_MASK) {
+ /* Ctrl-click sets the vertical rounding to be the same as the horizontal */
+ rect->getRepr()->setAttribute("rx", rect->getRepr()->attribute("ry"));
+ }
+}
+
+#define SGN(x) ((x)>0?1:((x)<0?-1:0))
+
+static void sp_rect_clamp_radii(SPRect *rect)
+{
+ // clamp rounding radii so that they do not exceed width/height
+ if (2 * rect->rx.computed > rect->width.computed) {
+ rect->rx.computed = 0.5 * rect->width.computed;
+ rect->rx._set = true;
+ }
+ if (2 * rect->ry.computed > rect->height.computed) {
+ rect->ry.computed = 0.5 * rect->height.computed;
+ rect->ry._set = true;
+ }
+}
+
+Geom::Point
+RectKnotHolderEntityWH::knot_get() const
+{
+ SPRect *rect = dynamic_cast<SPRect *>(item);
+ g_assert(rect != NULL);
+
+ return Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed);
+}
+
+void
+RectKnotHolderEntityWH::set_internal(Geom::Point const &p, Geom::Point const &origin, unsigned int state)
+{
+ SPRect *rect = dynamic_cast<SPRect *>(item);
+ g_assert(rect != NULL);
+
+ Geom::Point s = p;
+
+ if (state & GDK_CONTROL_MASK) {
+ // original width/height when drag started
+ gdouble const w_orig = (origin[Geom::X] - rect->x.computed);
+ gdouble const h_orig = (origin[Geom::Y] - rect->y.computed);
+
+ //original ratio
+ gdouble ratio = (w_orig / h_orig);
+
+ // mouse displacement since drag started
+ gdouble minx = p[Geom::X] - origin[Geom::X];
+ gdouble miny = p[Geom::Y] - origin[Geom::Y];
+
+ Geom::Point p_handle(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed);
+
+ if (fabs(minx) > fabs(miny)) {
+ // snap to horizontal or diagonal
+ if (minx != 0 && fabs(miny/minx) > 0.5 * 1/ratio && (SGN(minx) == SGN(miny))) {
+ // closer to the diagonal and in same-sign quarters, change both using ratio
+ s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(-ratio, -1)), state);
+ minx = s[Geom::X] - origin[Geom::X];
+ miny = s[Geom::Y] - origin[Geom::Y];
+ rect->height.computed = MAX(h_orig + minx / ratio, 0);
+ } else {
+ // closer to the horizontal, change only width, height is h_orig
+ s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(-1, 0)), state);
+ minx = s[Geom::X] - origin[Geom::X];
+ miny = s[Geom::Y] - origin[Geom::Y];
+ rect->height.computed = MAX(h_orig, 0);
+ }
+ rect->width.computed = MAX(w_orig + minx, 0);
+
+ } else {
+ // snap to vertical or diagonal
+ if (miny != 0 && fabs(minx/miny) > 0.5 * ratio && (SGN(minx) == SGN(miny))) {
+ // closer to the diagonal and in same-sign quarters, change both using ratio
+ s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(-ratio, -1)), state);
+ minx = s[Geom::X] - origin[Geom::X];
+ miny = s[Geom::Y] - origin[Geom::Y];
+ rect->width.computed = MAX(w_orig + miny * ratio, 0);
+ } else {
+ // closer to the vertical, change only height, width is w_orig
+ s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(0, -1)), state);
+ minx = s[Geom::X] - origin[Geom::X];
+ miny = s[Geom::Y] - origin[Geom::Y];
+ rect->width.computed = MAX(w_orig, 0);
+ }
+ rect->height.computed = MAX(h_orig + miny, 0);
+
+ }
+
+ rect->width._set = rect->height._set = true;
+
+ } else {
+ // move freely
+ s = snap_knot_position(p, state);
+ rect->width.computed = MAX(s[Geom::X] - rect->x.computed, 0);
+ rect->height.computed = MAX(s[Geom::Y] - rect->y.computed, 0);
+ rect->width._set = rect->height._set = true;
+ }
+
+ sp_rect_clamp_radii(rect);
+
+ rect->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+void
+RectKnotHolderEntityWH::knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state)
+{
+ set_internal(p, origin, state);
+ update_knot();
+}
+
+Geom::Point
+RectKnotHolderEntityXY::knot_get() const
+{
+ SPRect *rect = dynamic_cast<SPRect *>(item);
+ g_assert(rect != NULL);
+
+ return Geom::Point(rect->x.computed, rect->y.computed);
+}
+
+void
+RectKnotHolderEntityXY::knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state)
+{
+ SPRect *rect = dynamic_cast<SPRect *>(item);
+ g_assert(rect != NULL);
+
+ // opposite corner (unmoved)
+ gdouble opposite_x = (rect->x.computed + rect->width.computed);
+ gdouble opposite_y = (rect->y.computed + rect->height.computed);
+
+ // original width/height when drag started
+ gdouble w_orig = opposite_x - origin[Geom::X];
+ gdouble h_orig = opposite_y - origin[Geom::Y];
+
+ Geom::Point s = p;
+ Geom::Point p_handle(rect->x.computed, rect->y.computed);
+
+ // mouse displacement since drag started
+ gdouble minx = p[Geom::X] - origin[Geom::X];
+ gdouble miny = p[Geom::Y] - origin[Geom::Y];
+
+ if (state & GDK_CONTROL_MASK) {
+ //original ratio
+ gdouble ratio = (w_orig / h_orig);
+
+ if (fabs(minx) > fabs(miny)) {
+ // snap to horizontal or diagonal
+ if (minx != 0 && fabs(miny/minx) > 0.5 * 1/ratio && (SGN(minx) == SGN(miny))) {
+ // closer to the diagonal and in same-sign quarters, change both using ratio
+ s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(-ratio, -1)), state);
+ minx = s[Geom::X] - origin[Geom::X];
+ miny = s[Geom::Y] - origin[Geom::Y];
+ rect->y.computed = MIN(origin[Geom::Y] + minx / ratio, opposite_y);
+ rect->height.computed = MAX(h_orig - minx / ratio, 0);
+ } else {
+ // closer to the horizontal, change only width, height is h_orig
+ s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(-1, 0)), state);
+ minx = s[Geom::X] - origin[Geom::X];
+ miny = s[Geom::Y] - origin[Geom::Y];
+ rect->y.computed = MIN(origin[Geom::Y], opposite_y);
+ rect->height.computed = MAX(h_orig, 0);
+ }
+ rect->x.computed = MIN(s[Geom::X], opposite_x);
+ rect->width.computed = MAX(w_orig - minx, 0);
+ } else {
+ // snap to vertical or diagonal
+ if (miny != 0 && fabs(minx/miny) > 0.5 *ratio && (SGN(minx) == SGN(miny))) {
+ // closer to the diagonal and in same-sign quarters, change both using ratio
+ s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(-ratio, -1)), state);
+ minx = s[Geom::X] - origin[Geom::X];
+ miny = s[Geom::Y] - origin[Geom::Y];
+ rect->x.computed = MIN(origin[Geom::X] + miny * ratio, opposite_x);
+ rect->width.computed = MAX(w_orig - miny * ratio, 0);
+ } else {
+ // closer to the vertical, change only height, width is w_orig
+ s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(0, -1)), state);
+ minx = s[Geom::X] - origin[Geom::X];
+ miny = s[Geom::Y] - origin[Geom::Y];
+ rect->x.computed = MIN(origin[Geom::X], opposite_x);
+ rect->width.computed = MAX(w_orig, 0);
+ }
+ rect->y.computed = MIN(s[Geom::Y], opposite_y);
+ rect->height.computed = MAX(h_orig - miny, 0);
+ }
+
+ rect->width._set = rect->height._set = rect->x._set = rect->y._set = true;
+
+ } else {
+ // move freely
+ s = snap_knot_position(p, state);
+ minx = s[Geom::X] - origin[Geom::X];
+ miny = s[Geom::Y] - origin[Geom::Y];
+
+ rect->x.computed = MIN(s[Geom::X], opposite_x);
+ rect->width.computed = MAX(w_orig - minx, 0);
+ rect->y.computed = MIN(s[Geom::Y], opposite_y);
+ rect->height.computed = MAX(h_orig - miny, 0);
+ rect->width._set = rect->height._set = rect->x._set = rect->y._set = true;
+ }
+
+ sp_rect_clamp_radii(rect);
+
+ update_knot();
+
+ rect->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+RectKnotHolder::RectKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler) :
+ KnotHolder(desktop, item, relhandler)
+{
+ RectKnotHolderEntityRX *entity_rx = new RectKnotHolderEntityRX();
+ RectKnotHolderEntityRY *entity_ry = new RectKnotHolderEntityRY();
+ RectKnotHolderEntityWH *entity_wh = new RectKnotHolderEntityWH();
+ RectKnotHolderEntityXY *entity_xy = new RectKnotHolderEntityXY();
+
+ entity_rx->create(desktop, item, this, Inkscape::CTRL_TYPE_ROTATE,
+ _("Adjust the <b>horizontal rounding</b> radius; with <b>Ctrl</b> "
+ "to make the vertical radius the same"),
+ SP_KNOT_SHAPE_CIRCLE, SP_KNOT_MODE_XOR);
+
+ entity_ry->create(desktop, item, this, Inkscape::CTRL_TYPE_ROTATE,
+ _("Adjust the <b>vertical rounding</b> radius; with <b>Ctrl</b> "
+ "to make the horizontal radius the same"),
+ SP_KNOT_SHAPE_CIRCLE, SP_KNOT_MODE_XOR);
+
+ entity_wh->create(desktop, item, this, Inkscape::CTRL_TYPE_SIZER,
+ _("Adjust the <b>width and height</b> of the rectangle; with <b>Ctrl</b> "
+ "to lock ratio or stretch in one dimension only"),
+ SP_KNOT_SHAPE_SQUARE, SP_KNOT_MODE_XOR);
+
+ entity_xy->create(desktop, item, this, Inkscape::CTRL_TYPE_SIZER,
+ _("Adjust the <b>width and height</b> of the rectangle; with <b>Ctrl</b> "
+ "to lock ratio or stretch in one dimension only"),
+ SP_KNOT_SHAPE_SQUARE, SP_KNOT_MODE_XOR);
+
+ entity.push_back(entity_rx);
+ entity.push_back(entity_ry);
+ entity.push_back(entity_wh);
+ entity.push_back(entity_xy);
+
+ add_pattern_knotholder();
+}
+
+/* Box3D (= the new 3D box structure) */
+
+class Box3DKnotHolderEntity : public KnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const = 0;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state) = 0;
+
+ Geom::Point knot_get_generic(SPItem *item, unsigned int knot_id) const;
+ void knot_set_generic(SPItem *item, unsigned int knot_id, Geom::Point const &p, unsigned int state);
+};
+
+Geom::Point
+Box3DKnotHolderEntity::knot_get_generic(SPItem *item, unsigned int knot_id) const
+{
+ SPBox3D *box = dynamic_cast<SPBox3D *>(item);
+ if (box) {
+ return box3d_get_corner_screen(box, knot_id);
+ } else {
+ return Geom::Point(); // TODO investigate proper fallback
+ }
+}
+
+void
+Box3DKnotHolderEntity::knot_set_generic(SPItem *item, unsigned int knot_id, Geom::Point const &new_pos, unsigned int state)
+{
+ Geom::Point const s = snap_knot_position(new_pos, state);
+
+ g_assert(item != NULL);
+ SPBox3D *box = dynamic_cast<SPBox3D *>(item);
+ g_assert(box != NULL);
+ Geom::Affine const i2dt (item->i2dt_affine ());
+
+ Box3D::Axis movement;
+ if ((knot_id < 4) != (state & GDK_SHIFT_MASK)) {
+ movement = Box3D::XY;
+ } else {
+ movement = Box3D::Z;
+ }
+
+ box3d_set_corner (box, knot_id, s * i2dt, movement, (state & GDK_CONTROL_MASK));
+ box3d_set_z_orders(box);
+ box3d_position_set(box);
+}
+
+class Box3DKnotHolderEntity0 : public Box3DKnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+};
+
+class Box3DKnotHolderEntity1 : public Box3DKnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+};
+
+class Box3DKnotHolderEntity2 : public Box3DKnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+};
+
+class Box3DKnotHolderEntity3 : public Box3DKnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+};
+
+class Box3DKnotHolderEntity4 : public Box3DKnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+};
+
+class Box3DKnotHolderEntity5 : public Box3DKnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+};
+
+class Box3DKnotHolderEntity6 : public Box3DKnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+};
+
+class Box3DKnotHolderEntity7 : public Box3DKnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+};
+
+class Box3DKnotHolderEntityCenter : public KnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+};
+
+Geom::Point
+Box3DKnotHolderEntity0::knot_get() const
+{
+ return knot_get_generic(item, 0);
+}
+
+Geom::Point
+Box3DKnotHolderEntity1::knot_get() const
+{
+ return knot_get_generic(item, 1);
+}
+
+Geom::Point
+Box3DKnotHolderEntity2::knot_get() const
+{
+ return knot_get_generic(item, 2);
+}
+
+Geom::Point
+Box3DKnotHolderEntity3::knot_get() const
+{
+ return knot_get_generic(item, 3);
+}
+
+Geom::Point
+Box3DKnotHolderEntity4::knot_get() const
+{
+ return knot_get_generic(item, 4);
+}
+
+Geom::Point
+Box3DKnotHolderEntity5::knot_get() const
+{
+ return knot_get_generic(item, 5);
+}
+
+Geom::Point
+Box3DKnotHolderEntity6::knot_get() const
+{
+ return knot_get_generic(item, 6);
+}
+
+Geom::Point
+Box3DKnotHolderEntity7::knot_get() const
+{
+ return knot_get_generic(item, 7);
+}
+
+Geom::Point
+Box3DKnotHolderEntityCenter::knot_get() const
+{
+ SPBox3D *box = dynamic_cast<SPBox3D *>(item);
+ if (box) {
+ return box3d_get_center_screen(box);
+ } else {
+ return Geom::Point(); // TODO investigate proper fallback
+ }
+}
+
+void
+Box3DKnotHolderEntity0::knot_set(Geom::Point const &new_pos, Geom::Point const &/*origin*/, unsigned int state)
+{
+ knot_set_generic(item, 0, new_pos, state);
+}
+
+void
+Box3DKnotHolderEntity1::knot_set(Geom::Point const &new_pos, Geom::Point const &/*origin*/, unsigned int state)
+{
+ knot_set_generic(item, 1, new_pos, state);
+}
+
+void
+Box3DKnotHolderEntity2::knot_set(Geom::Point const &new_pos, Geom::Point const &/*origin*/, unsigned int state)
+{
+ knot_set_generic(item, 2, new_pos, state);
+}
+
+void
+Box3DKnotHolderEntity3::knot_set(Geom::Point const &new_pos, Geom::Point const &/*origin*/, unsigned int state)
+{
+ knot_set_generic(item, 3, new_pos, state);
+}
+
+void
+Box3DKnotHolderEntity4::knot_set(Geom::Point const &new_pos, Geom::Point const &/*origin*/, unsigned int state)
+{
+ knot_set_generic(item, 4, new_pos, state);
+}
+
+void
+Box3DKnotHolderEntity5::knot_set(Geom::Point const &new_pos, Geom::Point const &/*origin*/, unsigned int state)
+{
+ knot_set_generic(item, 5, new_pos, state);
+}
+
+void
+Box3DKnotHolderEntity6::knot_set(Geom::Point const &new_pos, Geom::Point const &/*origin*/, unsigned int state)
+{
+ knot_set_generic(item, 6, new_pos, state);
+}
+
+void
+Box3DKnotHolderEntity7::knot_set(Geom::Point const &new_pos, Geom::Point const &/*origin*/, unsigned int state)
+{
+ knot_set_generic(item, 7, new_pos, state);
+}
+
+void
+Box3DKnotHolderEntityCenter::knot_set(Geom::Point const &new_pos, Geom::Point const &origin, unsigned int state)
+{
+ Geom::Point const s = snap_knot_position(new_pos, state);
+
+ SPBox3D *box = dynamic_cast<SPBox3D *>(item);
+ g_assert(box != NULL);
+ Geom::Affine const i2dt (item->i2dt_affine ());
+
+ box3d_set_center(box, s * i2dt, origin * i2dt, !(state & GDK_SHIFT_MASK) ? Box3D::XY : Box3D::Z,
+ state & GDK_CONTROL_MASK);
+
+ box3d_set_z_orders(box);
+ box3d_position_set(box);
+}
+
+Box3DKnotHolder::Box3DKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler) :
+ KnotHolder(desktop, item, relhandler)
+{
+ Box3DKnotHolderEntity0 *entity_corner0 = new Box3DKnotHolderEntity0();
+ Box3DKnotHolderEntity1 *entity_corner1 = new Box3DKnotHolderEntity1();
+ Box3DKnotHolderEntity2 *entity_corner2 = new Box3DKnotHolderEntity2();
+ Box3DKnotHolderEntity3 *entity_corner3 = new Box3DKnotHolderEntity3();
+ Box3DKnotHolderEntity4 *entity_corner4 = new Box3DKnotHolderEntity4();
+ Box3DKnotHolderEntity5 *entity_corner5 = new Box3DKnotHolderEntity5();
+ Box3DKnotHolderEntity6 *entity_corner6 = new Box3DKnotHolderEntity6();
+ Box3DKnotHolderEntity7 *entity_corner7 = new Box3DKnotHolderEntity7();
+ Box3DKnotHolderEntityCenter *entity_center = new Box3DKnotHolderEntityCenter();
+
+ entity_corner0->create(desktop, item, this, Inkscape::CTRL_TYPE_SHAPER,
+ _("Resize box in X/Y direction; with <b>Shift</b> along the Z axis; "
+ "with <b>Ctrl</b> to constrain to the directions of edges or diagonals"));
+
+ entity_corner1->create(desktop, item, this, Inkscape::CTRL_TYPE_SHAPER,
+ _("Resize box in X/Y direction; with <b>Shift</b> along the Z axis; "
+ "with <b>Ctrl</b> to constrain to the directions of edges or diagonals"));
+
+ entity_corner2->create(desktop, item, this, Inkscape::CTRL_TYPE_SHAPER,
+ _("Resize box in X/Y direction; with <b>Shift</b> along the Z axis; "
+ "with <b>Ctrl</b> to constrain to the directions of edges or diagonals"));
+
+ entity_corner3->create(desktop, item, this, Inkscape::CTRL_TYPE_SHAPER,
+ _("Resize box in X/Y direction; with <b>Shift</b> along the Z axis; "
+ "with <b>Ctrl</b> to constrain to the directions of edges or diagonals"));
+
+ entity_corner4->create(desktop, item, this, Inkscape::CTRL_TYPE_SHAPER,
+ _("Resize box along the Z axis; with <b>Shift</b> in X/Y direction; "
+ "with <b>Ctrl</b> to constrain to the directions of edges or diagonals"));
+
+ entity_corner5->create(desktop, item, this, Inkscape::CTRL_TYPE_SHAPER,
+ _("Resize box along the Z axis; with <b>Shift</b> in X/Y direction; "
+ "with <b>Ctrl</b> to constrain to the directions of edges or diagonals"));
+
+ entity_corner6->create(desktop, item, this, Inkscape::CTRL_TYPE_SHAPER,
+ _("Resize box along the Z axis; with <b>Shift</b> in X/Y direction; "
+ "with <b>Ctrl</b> to constrain to the directions of edges or diagonals"));
+
+ entity_corner7->create(desktop, item, this, Inkscape::CTRL_TYPE_SHAPER,
+ _("Resize box along the Z axis; with <b>Shift</b> in X/Y direction; "
+ "with <b>Ctrl</b> to constrain to the directions of edges or diagonals"));
+
+ entity_center->create(desktop, item, this, Inkscape::CTRL_TYPE_POINT,
+ _("Move the box in perspective"),
+ SP_KNOT_SHAPE_CROSS);
+
+ entity.push_back(entity_corner0);
+ entity.push_back(entity_corner1);
+ entity.push_back(entity_corner2);
+ entity.push_back(entity_corner3);
+ entity.push_back(entity_corner4);
+ entity.push_back(entity_corner5);
+ entity.push_back(entity_corner6);
+ entity.push_back(entity_corner7);
+ entity.push_back(entity_center);
+
+ add_pattern_knotholder();
+}
+
+/* SPArc */
+
+class ArcKnotHolderEntityStart : public KnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+ virtual void knot_click(unsigned int state);
+};
+
+class ArcKnotHolderEntityEnd : public KnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+ virtual void knot_click(unsigned int state);
+};
+
+class ArcKnotHolderEntityRX : public KnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+ virtual void knot_click(unsigned int state);
+};
+
+class ArcKnotHolderEntityRY : public KnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+ virtual void knot_click(unsigned int state);
+};
+
+/*
+ * return values:
+ * 1 : inside
+ * 0 : on the curves
+ * -1 : outside
+ */
+static gint
+sp_genericellipse_side(SPGenericEllipse *ellipse, Geom::Point const &p)
+{
+ gdouble dx = (p[Geom::X] - ellipse->cx.computed) / ellipse->rx.computed;
+ gdouble dy = (p[Geom::Y] - ellipse->cy.computed) / ellipse->ry.computed;
+
+ gdouble s = dx * dx + dy * dy;
+ if (s < 1.0) return 1;
+ if (s > 1.0) return -1;
+ return 0;
+}
+
+void
+ArcKnotHolderEntityStart::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int state)
+{
+ int snaps = Inkscape::Preferences::get()->getInt("/options/rotationsnapsperpi/value", 12);
+
+ SPGenericEllipse *arc = dynamic_cast<SPGenericEllipse *>(item);
+ g_assert(arc != NULL);
+
+ arc->setClosed(sp_genericellipse_side(arc, p) == -1);
+
+ Geom::Point delta = p - Geom::Point(arc->cx.computed, arc->cy.computed);
+ Geom::Scale sc(arc->rx.computed, arc->ry.computed);
+
+ arc->start = atan2(delta * sc.inverse());
+
+ if ((state & GDK_CONTROL_MASK) && snaps) {
+ arc->start = sp_round(arc->start, M_PI / snaps);
+ }
+
+ arc->normalize();
+ arc->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+Geom::Point
+ArcKnotHolderEntityStart::knot_get() const
+{
+ SPGenericEllipse const *ge = dynamic_cast<SPGenericEllipse const *>(item);
+ g_assert(ge != NULL);
+
+ return ge->getPointAtAngle(ge->start);
+}
+
+void
+ArcKnotHolderEntityStart::knot_click(unsigned int state)
+{
+ SPGenericEllipse *ge = dynamic_cast<SPGenericEllipse *>(item);
+ g_assert(ge != NULL);
+
+ if (state & GDK_SHIFT_MASK) {
+ ge->end = ge->start = 0;
+ ge->updateRepr();
+ }
+}
+
+void
+ArcKnotHolderEntityEnd::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int state)
+{
+ int snaps = Inkscape::Preferences::get()->getInt("/options/rotationsnapsperpi/value", 12);
+
+ SPGenericEllipse *arc = dynamic_cast<SPGenericEllipse *>(item);
+ g_assert(arc != NULL);
+
+ arc->setClosed(sp_genericellipse_side(arc, p) == -1);
+
+ Geom::Point delta = p - Geom::Point(arc->cx.computed, arc->cy.computed);
+ Geom::Scale sc(arc->rx.computed, arc->ry.computed);
+
+ arc->end = atan2(delta * sc.inverse());
+
+ if ((state & GDK_CONTROL_MASK) && snaps) {
+ arc->end = sp_round(arc->end, M_PI/snaps);
+ }
+
+ arc->normalize();
+ arc->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+Geom::Point
+ArcKnotHolderEntityEnd::knot_get() const
+{
+ SPGenericEllipse const *ge = dynamic_cast<SPGenericEllipse const *>(item);
+ g_assert(ge != NULL);
+
+ return ge->getPointAtAngle(ge->end);
+}
+
+
+void
+ArcKnotHolderEntityEnd::knot_click(unsigned int state)
+{
+ SPGenericEllipse *ge = dynamic_cast<SPGenericEllipse *>(item);
+ g_assert(ge != NULL);
+
+ if (state & GDK_SHIFT_MASK) {
+ ge->end = ge->start = 0;
+ ge->updateRepr();
+ }
+}
+
+
+void
+ArcKnotHolderEntityRX::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int state)
+{
+ SPGenericEllipse *ge = dynamic_cast<SPGenericEllipse *>(item);
+ g_assert(ge != NULL);
+
+ Geom::Point const s = snap_knot_position(p, state);
+
+ ge->rx.computed = fabs( ge->cx.computed - s[Geom::X] );
+
+ if ( state & GDK_CONTROL_MASK ) {
+ ge->ry.computed = ge->rx.computed;
+ }
+
+ item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+Geom::Point
+ArcKnotHolderEntityRX::knot_get() const
+{
+ SPGenericEllipse const *ge = dynamic_cast<SPGenericEllipse const *>(item);
+ g_assert(ge != NULL);
+
+ return (Geom::Point(ge->cx.computed, ge->cy.computed) - Geom::Point(ge->rx.computed, 0));
+}
+
+void
+ArcKnotHolderEntityRX::knot_click(unsigned int state)
+{
+ SPGenericEllipse *ge = dynamic_cast<SPGenericEllipse *>(item);
+ g_assert(ge != NULL);
+
+ if (state & GDK_CONTROL_MASK) {
+ ge->ry.computed = ge->rx.computed;
+ ge->updateRepr();
+ }
+}
+
+void
+ArcKnotHolderEntityRY::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int state)
+{
+ SPGenericEllipse *ge = dynamic_cast<SPGenericEllipse *>(item);
+ g_assert(ge != NULL);
+
+ Geom::Point const s = snap_knot_position(p, state);
+
+ ge->ry.computed = fabs( ge->cy.computed - s[Geom::Y] );
+
+ if ( state & GDK_CONTROL_MASK ) {
+ ge->rx.computed = ge->ry.computed;
+ }
+
+ item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+Geom::Point
+ArcKnotHolderEntityRY::knot_get() const
+{
+ SPGenericEllipse const *ge = dynamic_cast<SPGenericEllipse *>(item);
+ g_assert(ge != NULL);
+
+ return (Geom::Point(ge->cx.computed, ge->cy.computed) - Geom::Point(0, ge->ry.computed));
+}
+
+void
+ArcKnotHolderEntityRY::knot_click(unsigned int state)
+{
+ SPGenericEllipse *ge = dynamic_cast<SPGenericEllipse *>(item);
+ g_assert(ge != NULL);
+
+ if (state & GDK_CONTROL_MASK) {
+ ge->rx.computed = ge->ry.computed;
+ ge->updateRepr();
+ }
+}
+
+ArcKnotHolder::ArcKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler) :
+ KnotHolder(desktop, item, relhandler)
+{
+ ArcKnotHolderEntityRX *entity_rx = new ArcKnotHolderEntityRX();
+ ArcKnotHolderEntityRY *entity_ry = new ArcKnotHolderEntityRY();
+ ArcKnotHolderEntityStart *entity_start = new ArcKnotHolderEntityStart();
+ ArcKnotHolderEntityEnd *entity_end = new ArcKnotHolderEntityEnd();
+
+ entity_rx->create(desktop, item, this, Inkscape::CTRL_TYPE_SIZER,
+ _("Adjust ellipse <b>width</b>, with <b>Ctrl</b> to make circle"),
+ SP_KNOT_SHAPE_SQUARE, SP_KNOT_MODE_XOR);
+
+ entity_ry->create(desktop, item, this, Inkscape::CTRL_TYPE_SIZER,
+ _("Adjust ellipse <b>height</b>, with <b>Ctrl</b> to make circle"),
+ SP_KNOT_SHAPE_SQUARE, SP_KNOT_MODE_XOR);
+
+ entity_start->create(desktop, item, this, Inkscape::CTRL_TYPE_ROTATE,
+ _("Position the <b>start point</b> of the arc or segment; with <b>Ctrl</b> "
+ "to snap angle; drag <b>inside</b> the ellipse for arc, <b>outside</b> for segment"),
+ SP_KNOT_SHAPE_CIRCLE, SP_KNOT_MODE_XOR);
+
+ entity_end->create(desktop, item, this, Inkscape::CTRL_TYPE_ROTATE,
+ _("Position the <b>end point</b> of the arc or segment; with <b>Ctrl</b> to snap angle; "
+ "drag <b>inside</b> the ellipse for arc, <b>outside</b> for segment"),
+ SP_KNOT_SHAPE_CIRCLE, SP_KNOT_MODE_XOR);
+
+ entity.push_back(entity_rx);
+ entity.push_back(entity_ry);
+ entity.push_back(entity_start);
+ entity.push_back(entity_end);
+
+ add_pattern_knotholder();
+}
+
+/* SPStar */
+
+class StarKnotHolderEntity1 : public KnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+ virtual void knot_click(unsigned int state);
+};
+
+class StarKnotHolderEntity2 : public KnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+ virtual void knot_click(unsigned int state);
+};
+
+void
+StarKnotHolderEntity1::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int state)
+{
+ SPStar *star = dynamic_cast<SPStar *>(item);
+ g_assert(star != NULL);
+
+ Geom::Point const s = snap_knot_position(p, state);
+
+ Geom::Point d = s - star->center;
+
+ double arg1 = atan2(d);
+ double darg1 = arg1 - star->arg[0];
+
+ if (state & GDK_MOD1_MASK) {
+ star->randomized = darg1/(star->arg[0] - star->arg[1]);
+ } else if (state & GDK_SHIFT_MASK) {
+ star->rounded = darg1/(star->arg[0] - star->arg[1]);
+ } else if (state & GDK_CONTROL_MASK) {
+ star->r[0] = L2(d);
+ } else {
+ star->r[0] = L2(d);
+ star->arg[0] = arg1;
+ star->arg[1] += darg1;
+ }
+ star->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+void
+StarKnotHolderEntity2::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int state)
+{
+ SPStar *star = dynamic_cast<SPStar *>(item);
+ g_assert(star != NULL);
+
+ Geom::Point const s = snap_knot_position(p, state);
+
+ if (star->flatsided == false) {
+ Geom::Point d = s - star->center;
+
+ double arg1 = atan2(d);
+ double darg1 = arg1 - star->arg[1];
+
+ if (state & GDK_MOD1_MASK) {
+ star->randomized = darg1/(star->arg[0] - star->arg[1]);
+ } else if (state & GDK_SHIFT_MASK) {
+ star->rounded = fabs(darg1/(star->arg[0] - star->arg[1]));
+ } else if (state & GDK_CONTROL_MASK) {
+ star->r[1] = L2(d);
+ star->arg[1] = star->arg[0] + M_PI / star->sides;
+ }
+ else {
+ star->r[1] = L2(d);
+ star->arg[1] = atan2(d);
+ }
+ star->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ }
+}
+
+Geom::Point
+StarKnotHolderEntity1::knot_get() const
+{
+ g_assert(item != NULL);
+
+ SPStar const *star = dynamic_cast<SPStar const *>(item);
+ g_assert(star != NULL);
+
+ return sp_star_get_xy(star, SP_STAR_POINT_KNOT1, 0);
+
+}
+
+Geom::Point
+StarKnotHolderEntity2::knot_get() const
+{
+ g_assert(item != NULL);
+
+ SPStar const *star = dynamic_cast<SPStar const *>(item);
+ g_assert(star != NULL);
+
+ return sp_star_get_xy(star, SP_STAR_POINT_KNOT2, 0);
+}
+
+static void
+sp_star_knot_click(SPItem *item, unsigned int state)
+{
+ SPStar *star = dynamic_cast<SPStar *>(item);
+ g_assert(star != NULL);
+
+ if (state & GDK_MOD1_MASK) {
+ star->randomized = 0;
+ star->updateRepr();
+ } else if (state & GDK_SHIFT_MASK) {
+ star->rounded = 0;
+ star->updateRepr();
+ } else if (state & GDK_CONTROL_MASK) {
+ star->arg[1] = star->arg[0] + M_PI / star->sides;
+ star->updateRepr();
+ }
+}
+
+void
+StarKnotHolderEntity1::knot_click(unsigned int state)
+{
+ sp_star_knot_click(item, state);
+}
+
+void
+StarKnotHolderEntity2::knot_click(unsigned int state)
+{
+ sp_star_knot_click(item, state);
+}
+
+StarKnotHolder::StarKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler) :
+ KnotHolder(desktop, item, relhandler)
+{
+ SPStar *star = dynamic_cast<SPStar *>(item);
+ g_assert(item != NULL);
+
+ StarKnotHolderEntity1 *entity1 = new StarKnotHolderEntity1();
+ entity1->create(desktop, item, this, Inkscape::CTRL_TYPE_SHAPER,
+ _("Adjust the <b>tip radius</b> of the star or polygon; "
+ "with <b>Shift</b> to round; with <b>Alt</b> to randomize"));
+
+ entity.push_back(entity1);
+
+ if (star->flatsided == false) {
+ StarKnotHolderEntity2 *entity2 = new StarKnotHolderEntity2();
+ entity2->create(desktop, item, this, Inkscape::CTRL_TYPE_SHAPER,
+ _("Adjust the <b>base radius</b> of the star; with <b>Ctrl</b> to keep star rays "
+ "radial (no skew); with <b>Shift</b> to round; with <b>Alt</b> to randomize"));
+ entity.push_back(entity2);
+ }
+
+ add_pattern_knotholder();
+}
+
+/* SPSpiral */
+
+class SpiralKnotHolderEntityInner : public KnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+ virtual void knot_click(unsigned int state);
+};
+
+class SpiralKnotHolderEntityOuter : public KnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+};
+
+
+/*
+ * set attributes via inner (t=t0) knot point:
+ * [default] increase/decrease inner point
+ * [shift] increase/decrease inner and outer arg synchronizely
+ * [control] constrain inner arg to round per PI/4
+ */
+void
+SpiralKnotHolderEntityInner::knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ int snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12);
+
+ SPSpiral *spiral = dynamic_cast<SPSpiral *>(item);
+ g_assert(spiral != NULL);
+
+ gdouble dx = p[Geom::X] - spiral->cx;
+ gdouble dy = p[Geom::Y] - spiral->cy;
+
+ gdouble moved_y = p[Geom::Y] - origin[Geom::Y];
+
+ if (state & GDK_MOD1_MASK) {
+ // adjust divergence by vertical drag, relative to rad
+ if (spiral->rad > 0) {
+ double exp_delta = 0.1*moved_y/(spiral->rad); // arbitrary multiplier to slow it down
+ spiral->exp += exp_delta;
+ if (spiral->exp < 1e-3)
+ spiral->exp = 1e-3;
+ }
+ } else {
+ // roll/unroll from inside
+ gdouble 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;
+ spiral->t0 = (arg_t0_new - spiral->arg) / (2.0*M_PI*spiral->revo);
+
+ /* round inner arg per PI/snaps, if CTRL is pressed */
+ if ( ( state & GDK_CONTROL_MASK )
+ && ( fabs(spiral->revo) > SP_EPSILON_2 )
+ && ( snaps != 0 ) ) {
+ gdouble arg = 2.0*M_PI*spiral->revo*spiral->t0 + spiral->arg;
+ spiral->t0 = (sp_round(arg, M_PI/snaps) - spiral->arg)/(2.0*M_PI*spiral->revo);
+ }
+
+ spiral->t0 = CLAMP(spiral->t0, 0.0, 0.999);
+ }
+
+ spiral->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+/*
+ * set attributes via outer (t=1) knot point:
+ * [default] increase/decrease revolution factor
+ * [control] constrain inner arg to round per PI/4
+ */
+void
+SpiralKnotHolderEntityOuter::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int state)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ int snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12);
+
+ SPSpiral *spiral = dynamic_cast<SPSpiral *>(item);
+ g_assert(spiral != NULL);
+
+ gdouble dx = p[Geom::X] - spiral->cx;
+ gdouble dy = p[Geom::Y] - spiral->cy;
+
+ if (state & GDK_SHIFT_MASK) { // rotate without roll/unroll
+ spiral->arg = atan2(dy, dx) - 2.0*M_PI*spiral->revo;
+ if (!(state & GDK_MOD1_MASK)) {
+ // if alt not pressed, change also rad; otherwise it is locked
+ spiral->rad = MAX(hypot(dx, dy), 0.001);
+ }
+ if ( ( state & GDK_CONTROL_MASK )
+ && snaps ) {
+ spiral->arg = sp_round(spiral->arg, M_PI/snaps);
+ }
+ } else { // roll/unroll
+ // arg of the spiral outer end
+ double 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);
+
+ // arg of the mouse point relative to spiral center
+ double mouse_angle = atan2(dy, dx);
+ if (mouse_angle < 0)
+ mouse_angle += 2*M_PI;
+
+ // snap if ctrl
+ if ( ( state & GDK_CONTROL_MASK ) && snaps ) {
+ mouse_angle = sp_round(mouse_angle, M_PI/snaps);
+ }
+
+ // by how much we want to rotate the outer point
+ double diff = mouse_angle - arg_r;
+ if (diff > M_PI)
+ diff -= 2*M_PI;
+ else if (diff < -M_PI)
+ diff += 2*M_PI;
+
+ // calculate the new rad;
+ // the value of t corresponding to the angle arg_1 + diff:
+ double t_temp = ((arg_1 + diff) - spiral->arg)/(2*M_PI*spiral->revo);
+ // the rad at that t:
+ double rad_new = 0;
+ if (t_temp > spiral->t0)
+ 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);
+ if (spiral->revo < 1e-3)
+ spiral->revo = 1e-3;
+
+ // if alt not pressed and the values are sane, change the rad
+ 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;
+ spiral->getPolar(spiral->t0, &r0, NULL);
+ spiral->rad = rad_new;
+ spiral->t0 = pow(r0 / spiral->rad, 1.0/spiral->exp);
+ }
+ if (!IS_FINITE(spiral->t0)) spiral->t0 = 0.0;
+ spiral->t0 = CLAMP(spiral->t0, 0.0, 0.999);
+ }
+
+ spiral->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+Geom::Point
+SpiralKnotHolderEntityInner::knot_get() const
+{
+ SPSpiral const *spiral = dynamic_cast<SPSpiral const *>(item);
+ g_assert(spiral != NULL);
+
+ return spiral->getXY(spiral->t0);
+}
+
+Geom::Point
+SpiralKnotHolderEntityOuter::knot_get() const
+{
+ SPSpiral const *spiral = dynamic_cast<SPSpiral const *>(item);
+ g_assert(spiral != NULL);
+
+ return spiral->getXY(1.0);
+}
+
+void
+SpiralKnotHolderEntityInner::knot_click(unsigned int state)
+{
+ SPSpiral *spiral = dynamic_cast<SPSpiral *>(item);
+ g_assert(spiral != NULL);
+
+ if (state & GDK_MOD1_MASK) {
+ spiral->exp = 1;
+ spiral->updateRepr();
+ } else if (state & GDK_SHIFT_MASK) {
+ spiral->t0 = 0;
+ spiral->updateRepr();
+ }
+}
+
+SpiralKnotHolder::SpiralKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler) :
+ KnotHolder(desktop, item, relhandler)
+{
+ SpiralKnotHolderEntityInner *entity_inner = new SpiralKnotHolderEntityInner();
+ SpiralKnotHolderEntityOuter *entity_outer = new SpiralKnotHolderEntityOuter();
+
+ entity_inner->create(desktop, item, this, Inkscape::CTRL_TYPE_SHAPER,
+ _("Roll/unroll the spiral from <b>inside</b>; with <b>Ctrl</b> to snap angle; "
+ "with <b>Alt</b> to converge/diverge"));
+
+ entity_outer->create(desktop, item, this, Inkscape::CTRL_TYPE_SHAPER,
+ _("Roll/unroll the spiral from <b>outside</b>; with <b>Ctrl</b> to snap angle; "
+ "with <b>Shift</b> to scale/rotate; with <b>Alt</b> to lock radius"));
+
+ entity.push_back(entity_inner);
+ entity.push_back(entity_outer);
+
+ add_pattern_knotholder();
+}
+
+/* SPOffset */
+
+class OffsetKnotHolderEntity : public KnotHolderEntity {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+};
+
+void
+OffsetKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int /*state*/)
+{
+ SPOffset *offset = dynamic_cast<SPOffset *>(item);
+ g_assert(offset != NULL);
+
+ offset->rad = sp_offset_distance_to_original(offset, p);
+ offset->knot = p;
+ offset->knotSet = true;
+
+ offset->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+
+Geom::Point
+OffsetKnotHolderEntity::knot_get() const
+{
+ SPOffset const *offset = dynamic_cast<SPOffset const *>(item);
+ g_assert(offset != NULL);
+
+ Geom::Point np;
+ sp_offset_top_point(offset,&np);
+ return np;
+}
+
+OffsetKnotHolder::OffsetKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler) :
+ KnotHolder(desktop, item, relhandler)
+{
+ OffsetKnotHolderEntity *entity_offset = new OffsetKnotHolderEntity();
+ entity_offset->create(desktop, item, this, Inkscape::CTRL_TYPE_SHAPER,
+ _("Adjust the <b>offset distance</b>"));
+ entity.push_back(entity_offset);
+
+ add_pattern_knotholder();
+}
+
+// TODO: this is derived from RectKnotHolderEntityWH because it used the same static function
+// set_internal as the latter before KnotHolderEntity was C++ified. Check whether this also makes
+// sense logically.
+class FlowtextKnotHolderEntity : public RectKnotHolderEntityWH {
+public:
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state);
+};
+
+Geom::Point
+FlowtextKnotHolderEntity::knot_get() const
+{
+ SPRect const *rect = dynamic_cast<SPRect const *>(item);
+ g_assert(rect != NULL);
+
+ return Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed);
+}
+
+void
+FlowtextKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state)
+{
+ set_internal(p, origin, state);
+}
+
+FlowtextKnotHolder::FlowtextKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler) :
+ KnotHolder(desktop, item, relhandler)
+{
+ g_assert(item != NULL);
+
+ FlowtextKnotHolderEntity *entity_flowtext = new FlowtextKnotHolderEntity();
+ entity_flowtext->create(desktop, item, this, Inkscape::CTRL_TYPE_SHAPER,
+ _("Drag to resize the <b>flowed text frame</b>"));
+ entity.push_back(entity_flowtext);
+}
+
+/*
+ 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/object-edit.h b/src/ui/object-edit.h
new file mode 100644
index 000000000..75f3ce12b
--- /dev/null
+++ b/src/ui/object-edit.h
@@ -0,0 +1,84 @@
+#ifndef OBJECT_EDIT_H_SEEN
+#define OBJECT_EDIT_H_SEEN
+
+/*
+ * Node editing extension to objects
+ *
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Mitsuru Oka
+ * Jon A. Cruz <jon@joncruz.org>
+ *
+ * Licensed under GNU GPL
+ */
+
+#include "knotholder.h"
+
+namespace Inkscape {
+namespace UI {
+
+KnotHolder *createKnotHolder(SPItem *item, SPDesktop *desktop);
+
+}
+}
+
+class RectKnotHolder : public KnotHolder {
+public:
+ RectKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler);
+ virtual ~RectKnotHolder() {};
+};
+
+class Box3DKnotHolder : public KnotHolder {
+public:
+ Box3DKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler);
+ virtual ~Box3DKnotHolder() {};
+};
+
+class ArcKnotHolder : public KnotHolder {
+public:
+ ArcKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler);
+ virtual ~ArcKnotHolder() {};
+};
+
+class StarKnotHolder : public KnotHolder {
+public:
+ StarKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler);
+ virtual ~StarKnotHolder() {};
+};
+
+class SpiralKnotHolder : public KnotHolder {
+public:
+ SpiralKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler);
+ virtual ~SpiralKnotHolder() {};
+};
+
+class OffsetKnotHolder : public KnotHolder {
+public:
+ OffsetKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler);
+ virtual ~OffsetKnotHolder() {};
+};
+
+class FlowtextKnotHolder : public KnotHolder {
+public:
+ FlowtextKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler);
+ virtual ~FlowtextKnotHolder() {};
+};
+
+class MiscKnotHolder : public KnotHolder {
+public:
+ MiscKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler);
+ virtual ~MiscKnotHolder() {};
+};
+
+#endif // OBJECT_EDIT_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/ui/shape-editor.cpp b/src/ui/shape-editor.cpp
new file mode 100644
index 000000000..0b9fc24c5
--- /dev/null
+++ b/src/ui/shape-editor.cpp
@@ -0,0 +1,177 @@
+/*
+ * Inkscape::ShapeEditor
+ *
+ * Authors:
+ * bulia byak <buliabyak@users.sf.net>
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <glibmm/i18n.h>
+
+#include "desktop-handles.h"
+#include "document.h"
+#include "gc-anchored.h"
+#include "knotholder.h"
+#include "ui/object-edit.h"
+#include "sp-item.h"
+#include "sp-object.h"
+#include "ui/shape-editor.h"
+#include "xml/node-event-vector.h"
+
+//using Inkscape::createKnotHolder;
+
+namespace Inkscape {
+namespace UI {
+
+bool ShapeEditor::_blockSetItem = false;
+
+ShapeEditor::ShapeEditor(SPDesktop *dt) {
+ this->desktop = dt;
+ this->knotholder = NULL;
+ this->knotholder_listener_attached_for = NULL;
+}
+
+ShapeEditor::~ShapeEditor() {
+ unset_item();
+}
+
+void ShapeEditor::unset_item(bool keep_knotholder) {
+ if (this->knotholder) {
+ Inkscape::XML::Node *old_repr = this->knotholder->repr;
+ if (old_repr && old_repr == knotholder_listener_attached_for) {
+ sp_repr_remove_listener_by_data(old_repr, this);
+ Inkscape::GC::release(old_repr);
+ knotholder_listener_attached_for = NULL;
+ }
+
+ if (!keep_knotholder) {
+ delete this->knotholder;
+ this->knotholder = NULL;
+ }
+ }
+}
+
+bool ShapeEditor::has_knotholder() {
+ return this->knotholder != NULL;
+}
+
+void ShapeEditor::update_knotholder() {
+ if (this->knotholder)
+ this->knotholder->update_knots();
+}
+
+bool ShapeEditor::has_local_change() {
+ return (this->knotholder && this->knotholder->local_change != 0);
+}
+
+void ShapeEditor::decrement_local_change() {
+ if (this->knotholder) {
+ this->knotholder->local_change = FALSE;
+ }
+}
+
+const SPItem *ShapeEditor::get_item() {
+ const SPItem *item = NULL;
+ if (this->has_knotholder()) {
+ item = this->knotholder->getItem();
+ }
+ return item;
+}
+
+void ShapeEditor::event_attr_changed(Inkscape::XML::Node *, gchar const *name, gchar const *, gchar const *, bool, void *data)
+{
+ g_assert(data);
+ ShapeEditor *sh = static_cast<ShapeEditor *>(data);
+ bool changed_kh = false;
+
+ if (sh->has_knotholder())
+ {
+ changed_kh = !sh->has_local_change();
+ sh->decrement_local_change();
+ if (changed_kh) {
+ // this can happen if an LPEItem's knotholder handle was dragged, in which case we want
+ // to keep the knotholder; in all other cases (e.g., if the LPE itself changes) we delete it
+ sh->reset_item(!strcmp(name, "d"));
+ }
+ }
+}
+
+static Inkscape::XML::NodeEventVector shapeeditor_repr_events = {
+ NULL, /* child_added */
+ NULL, /* child_removed */
+ ShapeEditor::event_attr_changed,
+ NULL, /* content_changed */
+ NULL /* order_changed */
+};
+
+
+void ShapeEditor::set_item(SPItem *item, bool keep_knotholder) {
+ if (_blockSetItem) {
+ return;
+ }
+
+ // this happens (and should only happen) when for an LPEItem having both knotholder and
+ // nodepath the knotholder is adapted; in this case we don't want to delete the knotholder
+ // since this freezes the handles
+ unset_item(keep_knotholder);
+
+ if (item) {
+ Inkscape::XML::Node *repr;
+ if (!this->knotholder) {
+ // only recreate knotholder if none is present
+ this->knotholder = createKnotHolder(item, desktop);
+ }
+ if (this->knotholder) {
+ this->knotholder->update_knots();
+ // setting new listener
+ repr = this->knotholder->repr;
+ if (repr != knotholder_listener_attached_for) {
+ Inkscape::GC::anchor(repr);
+ sp_repr_add_listener(repr, &shapeeditor_repr_events, this);
+ knotholder_listener_attached_for = repr;
+ }
+ }
+ }
+}
+
+
+/** FIXME: This thing is only called when the item needs to be updated in response to repr change.
+ Why not make a reload function in KnotHolder? */
+void ShapeEditor::reset_item(bool keep_knotholder)
+{
+ if (knotholder) {
+ SPObject *obj = sp_desktop_document(desktop)->getObjectByRepr(knotholder_listener_attached_for); /// note that it is not certain that this is an SPItem; it could be a LivePathEffectObject.
+ set_item(SP_ITEM(obj), keep_knotholder);
+ }
+}
+
+/**
+ * Returns true if this ShapeEditor has a knot above which the mouse currently hovers.
+ */
+bool ShapeEditor::knot_mouseover() const {
+ if (this->knotholder) {
+ return knotholder->knot_mouseover();
+ }
+
+ return false;
+}
+
+} // 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 :
diff --git a/src/ui/shape-editor.h b/src/ui/shape-editor.h
new file mode 100644
index 000000000..142a2493b
--- /dev/null
+++ b/src/ui/shape-editor.h
@@ -0,0 +1,71 @@
+#ifndef SEEN_SHAPE_EDITOR_H
+#define SEEN_SHAPE_EDITOR_H
+
+/*
+ * Inkscape::ShapeEditor
+ *
+ * This is a container class which contains a knotholder for shapes.
+ * It is attached to a single item.
+ *
+ * Authors:
+ * bulia byak <buliabyak@users.sf.net>
+ *
+ */
+
+class KnotHolder;
+class LivePathEffectObject;
+class SPDesktop;
+class SPItem;
+
+namespace Inkscape { namespace XML { class Node; }
+namespace UI {
+
+class ShapeEditor {
+public:
+
+ ShapeEditor(SPDesktop *desktop);
+ ~ShapeEditor();
+
+ void set_item(SPItem *item, bool keep_knotholder = false);
+ void unset_item(bool keep_knotholder = false);
+
+ void update_knotholder(); //((deprecated))
+
+ bool has_local_change();
+ void decrement_local_change();
+
+ bool knot_mouseover() const;
+
+ static void blockSetItem(bool b) { _blockSetItem = b; } // kludge
+
+ static void event_attr_changed(Inkscape::XML::Node * /*repr*/, char const *name, char const * /*old_value*/,
+ char const * /*new_value*/, bool /*is_interactive*/, void *data);
+private:
+ bool has_knotholder();
+ void reset_item (bool keep_knotholder = true);
+ const SPItem *get_item();
+
+ static bool _blockSetItem;
+
+ SPDesktop *desktop;
+ KnotHolder *knotholder;
+ Inkscape::XML::Node *knotholder_listener_attached_for;
+};
+
+} // namespace UI
+} // namespace Inkscape
+
+#endif // SEEN_SHAPE_EDITOR_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 :
+
diff --git a/src/ui/tool-factory.h b/src/ui/tool-factory.h
new file mode 100644
index 000000000..726706732
--- /dev/null
+++ b/src/ui/tool-factory.h
@@ -0,0 +1,40 @@
+/** @file
+ * Factory for ToolBase 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"
+
+namespace Inkscape {
+namespace UI {
+namespace Tools {
+
+class ToolBase;
+
+}
+}
+}
+
+typedef Singleton< Factory<Inkscape::UI::Tools::ToolBase> > 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/ui/tool/control-point-selection.cpp b/src/ui/tool/control-point-selection.cpp
index d10ed0f0d..998f74ee0 100644
--- a/src/ui/tool/control-point-selection.cpp
+++ b/src/ui/tool/control-point-selection.cpp
@@ -74,7 +74,7 @@ ControlPointSelection::~ControlPointSelection()
}
/** Add a control point to the selection. */
-std::pair<ControlPointSelection::iterator, bool> ControlPointSelection::insert(const value_type &x)
+std::pair<ControlPointSelection::iterator, bool> ControlPointSelection::insert(const value_type &x, bool notify)
{
iterator found = _points.find(x);
if (found != _points.end()) {
@@ -86,6 +86,10 @@ std::pair<ControlPointSelection::iterator, bool> ControlPointSelection::insert(c
x->updateState();
_pointChanged(x, true);
+ if (notify) {
+ signal_selection_changed.emit(std::vector<key_type>(1, x), true);
+ }
+
return std::pair<iterator, bool>(found, true);
}
@@ -97,47 +101,75 @@ void ControlPointSelection::erase(iterator pos)
erased->updateState();
_pointChanged(erased, false);
}
-ControlPointSelection::size_type ControlPointSelection::erase(const key_type &k)
+ControlPointSelection::size_type ControlPointSelection::erase(const key_type &k, bool notify)
{
iterator pos = _points.find(k);
if (pos == _points.end()) return 0;
erase(pos);
+
+ if (notify) {
+ signal_selection_changed.emit(std::vector<key_type>(1, k), false);
+ }
return 1;
}
void ControlPointSelection::erase(iterator first, iterator last)
{
+ std::vector<SelectableControlPoint *> out(first, last);
while (first != last) erase(first++);
+ signal_selection_changed.emit(out, false);
}
/** Remove all points from the selection, making it empty. */
void ControlPointSelection::clear()
{
+ std::vector<SelectableControlPoint *> out(begin(), end());
for (iterator i = begin(); i != end(); )
erase(i++);
+ if (!out.empty())
+ signal_selection_changed.emit(out, false);
}
/** Select all points that this selection can contain. */
void ControlPointSelection::selectAll()
{
for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
- insert(*i);
+ insert(*i, false);
}
+ std::vector<SelectableControlPoint *> out(_all_points.begin(), _all_points.end());
+ if (!out.empty())
+ signal_selection_changed.emit(out, true);
}
/** Select all points inside the given rectangle (in desktop coordinates). */
void ControlPointSelection::selectArea(Geom::Rect const &r)
{
+ std::vector<SelectableControlPoint *> out;
for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
- if (r.contains(**i))
- insert(*i);
+ if (r.contains(**i)) {
+ insert(*i, false);
+ out.push_back(*i);
+ }
}
+ if (!out.empty())
+ signal_selection_changed.emit(out, true);
}
/** Unselect all selected points and select all unselected points. */
void ControlPointSelection::invertSelection()
{
+ std::vector<SelectableControlPoint *> in, out;
for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
- if ((*i)->selected()) erase(*i);
- else insert(*i);
+ if ((*i)->selected()) {
+ in.push_back(*i);
+ erase(*i);
+ }
+ else {
+ out.push_back(*i);
+ insert(*i, false);
+ }
}
+ if (!in.empty())
+ signal_selection_changed.emit(in, false);
+ if (!out.empty())
+ signal_selection_changed.emit(out, true);
}
void ControlPointSelection::spatialGrow(SelectableControlPoint *origin, int dir)
{
@@ -166,6 +198,7 @@ void ControlPointSelection::spatialGrow(SelectableControlPoint *origin, int dir)
if (match) {
if (grow) insert(match);
else erase(match);
+ signal_selection_changed.emit(std::vector<value_type>(1, match), grow);
}
}
@@ -389,7 +422,7 @@ void ControlPointSelection::_pointChanged(SelectableControlPoint *p, bool select
_handles->rotationCenter().move(_bounds->midpoint());
}
- signal_point_changed.emit(p, selected);
+ //signal_point_changed.emit(p, selected);
}
void ControlPointSelection::_mouseoverChanged()
diff --git a/src/ui/tool/control-point-selection.h b/src/ui/tool/control-point-selection.h
index a087e0455..2d812c0a3 100644
--- a/src/ui/tool/control-point-selection.h
+++ b/src/ui/tool/control-point-selection.h
@@ -62,18 +62,19 @@ public:
const_iterator end() const { return _points.end(); }
// insert
- std::pair<iterator, bool> insert(const value_type& x);
+ std::pair<iterator, bool> insert(const value_type& x, bool notify = true);
template <class InputIterator>
void insert(InputIterator first, InputIterator last) {
for (; first != last; ++first) {
- insert(*first);
+ insert(*first, false);
}
+ signal_selection_changed.emit(std::vector<key_type>(first, last), true);
}
// erase
void clear();
void erase(iterator pos);
- size_type erase(const key_type& k);
+ size_type erase(const key_type& k, bool notify = true);
void erase(iterator first, iterator last);
// find
@@ -108,7 +109,9 @@ public:
void toggleTransformHandlesMode();
sigc::signal<void> signal_update;
- sigc::signal<void, SelectableControlPoint *, bool> signal_point_changed;
+ // It turns out that emitting a signal after every point is selected or deselected is not too efficient,
+ // so this can be done in a massive group once the selection is finally changed.
+ sigc::signal<void, std::vector<SelectableControlPoint *>, bool> signal_selection_changed;
sigc::signal<void, CommitEvent> signal_commit;
void getOriginalPoints(std::vector<Inkscape::SnapCandidatePoint> &pts);
@@ -166,4 +169,4 @@ private:
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 :
diff --git a/src/ui/tool/curve-drag-point.cpp b/src/ui/tool/curve-drag-point.cpp
index 4ca736f80..013553410 100644
--- a/src/ui/tool/curve-drag-point.cpp
+++ b/src/ui/tool/curve-drag-point.cpp
@@ -53,9 +53,11 @@ bool CurveDragPoint::grabbed(GdkEventMotion */*event*/)
// delta is a vector equal 1/3 of distance from first to second
Geom::Point delta = (second->position() - first->position()) / 3.0;
- first->front()->move(first->front()->position() + delta);
- second->back()->move(second->back()->position() - delta);
-
+ // only update the nodes if the mode is bspline
+ if(!_pm.isBSpline(false)){
+ first->front()->move(first->front()->position() + delta);
+ second->back()->move(second->back()->position() - delta);
+ }
_pm.update();
} else {
_segment_was_degenerate = false;
@@ -88,9 +90,12 @@ void CurveDragPoint::dragged(Geom::Point &new_pos, GdkEventMotion *event)
Geom::Point offset0 = ((1-weight)/(3*t*(1-t)*(1-t))) * delta;
Geom::Point offset1 = (weight/(3*t*t*(1-t))) * delta;
- first->front()->move(first->front()->position() + offset0);
- second->back()->move(second->back()->position() + offset1);
-
+ //modified so that, if the trace is bspline, it only acts if the SHIFT key is pressed
+ if(!_pm.isBSpline(false)){
+ first->front()->move(first->front()->position() + offset0);
+ second->back()->move(second->back()->position() + offset1);
+ }else if(weight>=0.8 && held_shift(*event))second->back()->move(new_pos);
+ else if(weight<=0.2 && held_shift(*event))first->front()->move(new_pos);
_pm.update();
}
diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp
index 65987ad52..d7b35c974 100644
--- a/src/ui/tool/multi-path-manipulator.cpp
+++ b/src/ui/tool/multi-path-manipulator.cpp
@@ -122,7 +122,7 @@ MultiPathManipulator::MultiPathManipulator(PathSharedData &data, sigc::connectio
{
_selection.signal_commit.connect(
sigc::mem_fun(*this, &MultiPathManipulator::_commit));
- _selection.signal_point_changed.connect(
+ _selection.signal_selection_changed.connect(
sigc::hide( sigc::hide(
signal_coords_changed.make_slot())));
}
@@ -182,7 +182,7 @@ void MultiPathManipulator::setItems(std::set<ShapeRecord> const &s)
ShapeRecord const &r = *i;
if (!SP_IS_PATH(r.item) && !IS_LIVEPATHEFFECT(r.item)) continue;
boost::shared_ptr<PathManipulator> newpm(new PathManipulator(*this, (SPPath*) r.item,
- r.edit_transform, _getOutlineColor(r.role), r.lpe_key));
+ r.edit_transform, _getOutlineColor(r.role, r.item), r.lpe_key));
newpm->showHandles(_show_handles);
// always show outlines for clips and masks
newpm->showOutline(_show_outline || r.role != SHAPE_ROLE_NORMAL);
@@ -670,7 +670,18 @@ bool MultiPathManipulator::event(Inkscape::UI::Tools::ToolBase *event_context, G
// a) del preserves shape, and control is not pressed
// b) ctrl+del preserves shape (del_preserves_shape is false), and control is pressed
// Hence xor
- deleteNodes(del_preserves_shape ^ held_control(event->key));
+ guint mode = prefs->getInt("/tools/freehand/pen/freehand-mode", 0);
+
+ //if the trace is bspline ( mode 2)
+ if(mode==2){
+ // is this correct ?
+ if(del_preserves_shape ^ held_control(event->key))
+ deleteNodes(false);
+ else
+ deleteNodes(true);
+ }
+ else
+ deleteNodes(del_preserves_shape ^ held_control(event->key));
// Delete any selected gradient nodes as well
event_context->deleteSelectedDrag(held_control(event->key));
@@ -833,7 +844,7 @@ void MultiPathManipulator::_doneWithCleanup(gchar const *reason, bool alert_LPE)
}
/** Get an outline color based on the shape's role (normal, mask, LPE parameter, etc.). */
-guint32 MultiPathManipulator::_getOutlineColor(ShapeRole role)
+guint32 MultiPathManipulator::_getOutlineColor(ShapeRole role, SPItem *item)
{
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
switch(role) {
@@ -845,7 +856,7 @@ guint32 MultiPathManipulator::_getOutlineColor(ShapeRole role)
return prefs->getColor("/tools/nodes/lpe_param_color", 0x009000ff);
case SHAPE_ROLE_NORMAL:
default:
- return prefs->getColor("/tools/nodes/outline_color", 0xff0000ff);
+ return item->highlight_color();
}
}
diff --git a/src/ui/tool/multi-path-manipulator.h b/src/ui/tool/multi-path-manipulator.h
index 1328372c6..cdbf34e9d 100644
--- a/src/ui/tool/multi-path-manipulator.h
+++ b/src/ui/tool/multi-path-manipulator.h
@@ -53,6 +53,7 @@ public:
void insertNodesAtExtrema(ExtremumType extremum);
void insertNodes();
+ void alertLPE();
void duplicateNodes();
void joinNodes();
void breakNodes();
@@ -104,9 +105,9 @@ private:
}
void _commit(CommitEvent cps);
- void _done(gchar const *reason, bool alert_LPE = false);
+ void _done(gchar const *reason, bool alert_LPE = true);
void _doneWithCleanup(gchar const *reason, bool alert_LPE = false);
- guint32 _getOutlineColor(ShapeRole role);
+ guint32 _getOutlineColor(ShapeRole role, SPItem *item);
MapType _mmap;
public:
diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp
index fbbc4be64..8a1ca0b90 100644
--- a/src/ui/tool/node.cpp
+++ b/src/ui/tool/node.cpp
@@ -13,7 +13,6 @@
#include <glib/gi18n.h>
#include <2geom/bezier-utils.h>
#include <2geom/transforms.h>
-
#include "display/sp-ctrlline.h"
#include "display/sp-canvas.h"
#include "display/sp-canvas-util.h"
@@ -28,7 +27,10 @@
#include "ui/tool/event-utils.h"
#include "ui/tool/node.h"
#include "ui/tool/path-manipulator.h"
+#include "ui/tools/node-tool.h"
+#include "ui/tools-switch.h"
#include <gdk/gdkkeysyms.h>
+#include <cmath>
namespace {
@@ -58,6 +60,11 @@ Inkscape::ControlType nodeTypeToCtrlType(Inkscape::UI::NodeType type)
namespace Inkscape {
namespace UI {
+/*const double handleCubicGap = 0.01;*/
+const double noPower = 0.0;
+const double defaultStartPower = 0.3334;
+/*const double defaultEndPower = 0.6667;*/
+
ControlPoint::ColorSet Node::node_colors = {
{0xbfbfbf00, 0x000000ff}, // normal fill, stroke
{0xff000000, 0x000000ff}, // mouseover fill, stroke
@@ -166,6 +173,12 @@ void Handle::move(Geom::Point const &new_pos)
}
}
setPosition(new_pos);
+
+ //move the handler and its oposite the same proportion
+ if(_pm().isBSpline()){
+ setPosition(_pm().BSplineHandleReposition(this,this));
+ this->other()->setPosition(_pm().BSplineHandleReposition(this->other(),this));
+ }
return;
}
@@ -177,6 +190,13 @@ void Handle::move(Geom::Point const &new_pos)
Geom::Point new_delta = (Geom::dot(delta, direction)
/ Geom::L2sq(direction)) * direction;
setRelativePos(new_delta);
+
+ //move the handler and its oposite the same proportion
+ if(_pm().isBSpline()){
+ setPosition(_pm().BSplineHandleReposition(this,this));
+ this->other()->setPosition(_pm().BSplineHandleReposition(this->other(),this));
+ }
+
return;
}
@@ -195,8 +215,14 @@ void Handle::move(Geom::Point const &new_pos)
break;
default: break;
}
-
setPosition(new_pos);
+
+ // moves the handler and its oposite the same proportion
+ if(_pm().isBSpline()){
+ setPosition(_pm().BSplineHandleReposition(this,this));
+ this->other()->setPosition(_pm().BSplineHandleReposition(this->other(),this));
+ }
+
}
void Handle::setPosition(Geom::Point const &p)
@@ -273,12 +299,27 @@ bool Handle::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEven
break;
default: break;
}
+ break;
+ // new double click event to set the handlers of a node to the default proportion, defaultStartPower%
+ case GDK_2BUTTON_PRESS:
+ handle_2button_press();
+ break;
+
default: break;
}
return ControlPoint::_eventHandler(event_context, event);
}
+//this function moves the handler and its oposite to the default proportion of defaultStartPower
+void Handle::handle_2button_press(){
+ if(_pm().isBSpline()){
+ setPosition(_pm().BSplineHandleReposition(this,defaultStartPower));
+ this->other()->setPosition(_pm().BSplineHandleReposition(this->other(),defaultStartPower));
+ _pm().update();
+ }
+}
+
bool Handle::grabbed(GdkEventMotion *)
{
_saved_other_pos = other()->position();
@@ -289,6 +330,10 @@ bool Handle::grabbed(GdkEventMotion *)
void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event)
{
+ if (tools_isactive(_desktop, TOOLS_NODES)) {
+ Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(_desktop->event_context);
+ nt->update_helperpath();
+ }
Geom::Point parent_pos = _parent->position();
Geom::Point origin = _last_drag_origin();
SnapManager &sm = _desktop->namedview->snap_manager;
@@ -326,10 +371,18 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event)
ctrl_constraint = Inkscape::Snapper::SnapConstraint(parent_pos, parent_pos - perp_pos);
}
new_pos = result;
+ // moves the handler and its oposite in X fixed positions depending on parameter "steps with control"
+ // by default in live BSpline
+ if(_pm().isBSpline()){
+ setPosition(new_pos);
+ int steps = _pm().BSplineGetSteps();
+ new_pos=_pm().BSplineHandleReposition(this,ceilf(_pm().BSplineHandlePosition(this,this)*steps)/steps);
+ }
}
std::vector<Inkscape::SnapCandidatePoint> unselected;
- if (snap) {
+ //if the snap adjustment is activated and it is not bspline
+ if (snap && !_pm().isBSpline(false)) {
ControlPointSelection::Set &nodes = _parent->_selection.allPoints();
for (ControlPointSelection::Set::iterator i = nodes.begin(); i != nodes.end(); ++i) {
Node *n = static_cast<Node*>(*i);
@@ -369,6 +422,10 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event)
other()->setPosition(_saved_other_pos);
}
}
+ //if it is bspline but SHIFT or CONTROL are not pressed it fixes it in the original position
+ if(_pm().isBSpline() && !held_shift(*event) && !held_control(*event)){
+ new_pos=_last_drag_origin();
+ }
move(new_pos); // needed for correct update, even though it's redundant
_pm().update();
}
@@ -427,13 +484,19 @@ static double snap_increment_degrees() {
Glib::ustring Handle::_getTip(unsigned state) const
{
char const *more;
+ // a trick to mark as bspline if the node has no strength, we are going to use it later
+ // to show the appropiate messages. We cannot do it in any different way becasue the function is constant
+
+ bool isBSpline = _pm().isBSpline();
bool can_shift_rotate = _parent->type() == NODE_CUSP && !other()->isDegenerate();
- if (can_shift_rotate) {
+ if (can_shift_rotate && !isBSpline) {
more = C_("Path handle tip", "more: Shift, Ctrl, Alt");
- } else {
+ } else if(isBSpline){
+ more = C_("Path handle tip", "more: Ctrl");
+ }else {
more = C_("Path handle tip", "more: Ctrl, Alt");
}
- if (state_held_alt(state)) {
+ if (state_held_alt(state) && !isBSpline) {
if (state_held_control(state)) {
if (state_held_shift(state) && can_shift_rotate) {
return format_tip(C_("Path handle tip",
@@ -456,18 +519,24 @@ Glib::ustring Handle::_getTip(unsigned state) const
}
} else {
if (state_held_control(state)) {
- if (state_held_shift(state) && can_shift_rotate) {
+ if (state_held_shift(state) && can_shift_rotate && !isBSpline) {
return format_tip(C_("Path handle tip",
"<b>Shift+Ctrl</b>: snap rotation angle to %g° increments and rotate both handles"),
snap_increment_degrees());
- } else {
+ } else if(isBSpline){
+ return format_tip(C_("Path handle tip",
+ "<b>Ctrl</b>: Move handle by his actual steps in BSpline Live Effect"));
+ }else{
return format_tip(C_("Path handle tip",
"<b>Ctrl</b>: snap rotation angle to %g° increments, click to retract"),
snap_increment_degrees());
}
- } else if (state_held_shift(state) && can_shift_rotate) {
+ } else if (state_held_shift(state) && can_shift_rotate && !isBSpline) {
return C_("Path hande tip",
"<b>Shift</b>: rotate both handles by the same angle");
+ } else if(state_held_shift(state) && isBSpline){
+ return C_("Path hande tip",
+ "<b>Shift</b>: move handle");
}
}
@@ -476,9 +545,13 @@ Glib::ustring Handle::_getTip(unsigned state) const
return format_tip(C_("Path handle tip",
"<b>Auto node handle</b>: drag to convert to smooth node (%s)"), more);
default:
- return format_tip(C_("Path handle tip",
- "<b>%s</b>: drag to shape the segment (%s)"),
- handle_type_to_localized_string(_parent->type()), more);
+ if(!isBSpline){
+ return format_tip(C_("Path handle tip",
+ "<b>Auto node handle</b>: drag to convert to smooth node (%s)"), more);
+ }else{
+ return format_tip(C_("Path handle tip",
+ "<b>BSpline node handle</b>: Shift to drag, double click to reset (%s)"), more);
+ }
}
}
@@ -553,18 +626,80 @@ void Node::move(Geom::Point const &new_pos)
// move handles when the node moves.
Geom::Point old_pos = position();
Geom::Point delta = new_pos - position();
+
+ // save the previous nodes strength to apply it again once the node is moved
+ double nodeWeight = noPower;
+ double nextNodeWeight = noPower;
+ double prevNodeWeight = noPower;
+ Node *n = this;
+ Node * nextNode = n->nodeToward(n->front());
+ Node * prevNode = n->nodeToward(n->back());
+ nodeWeight = fmax(_pm().BSplineHandlePosition(n->front()),_pm().BSplineHandlePosition(n->back()));
+ if(prevNode){
+ if(prevNode->isEndNode()){
+ prevNodeWeight = _pm().BSplineHandlePosition(prevNode->front(),prevNode->front());
+ }
+ }
+ if(nextNode){
+ if(nextNode->isEndNode()){
+ nextNodeWeight = _pm().BSplineHandlePosition(nextNode->back(),nextNode->back());
+ }
+ }
+
setPosition(new_pos);
+
_front.setPosition(_front.position() + delta);
_back.setPosition(_back.position() + delta);
// if the node has a smooth handle after a line segment, it should be kept colinear
// with the segment
_fixNeighbors(old_pos, new_pos);
+
+ // move the affected handlers. First the node ones, later the adjoining ones.
+ if(_pm().isBSpline()){
+ _front.setPosition(_pm().BSplineHandleReposition(this->front(),nodeWeight));
+ _back.setPosition(_pm().BSplineHandleReposition(this->back(),nodeWeight));
+ if(prevNode){
+ if(prevNode->isEndNode()){
+ prevNode->front()->setPosition(_pm().BSplineHandleReposition(prevNode->front(),prevNodeWeight));
+ }else{
+ prevNode->front()->setPosition(_pm().BSplineHandleReposition(prevNode->front(),prevNode->back()));
+ }
+ }
+ if(nextNode){
+ if(nextNode->isEndNode()){
+ nextNode->back()->setPosition(_pm().BSplineHandleReposition(nextNode->back(),nextNodeWeight));
+ }else{
+ nextNode->back()->setPosition(_pm().BSplineHandleReposition(nextNode->back(),nextNode->front()));
+ }
+ }
+ }
}
void Node::transform(Geom::Affine const &m)
{
+
Geom::Point old_pos = position();
+
+ // save the previous nodes strength to apply it again once the node is moved
+ double nodeWeight = noPower;
+ double nextNodeWeight = noPower;
+ double prevNodeWeight = noPower;
+ Node *n = this;
+ Node * nextNode = n->nodeToward(n->front());
+ Node * prevNode = n->nodeToward(n->back());
+ nodeWeight = _pm().BSplineHandlePosition(n->front());
+ if(prevNode){
+ if(prevNode->isEndNode()){
+ prevNodeWeight = _pm().BSplineHandlePosition(prevNode->front(),prevNode->front());
+ }
+ }
+ if(nextNode){
+ if(nextNode->isEndNode()){
+ nextNodeWeight = _pm().BSplineHandlePosition(nextNode->back(),nextNode->back());
+ }
+ }
+
setPosition(position() * m);
_front.setPosition(_front.position() * m);
_back.setPosition(_back.position() * m);
@@ -572,6 +707,26 @@ void Node::transform(Geom::Affine const &m)
/* Affine transforms keep handle invariants for smooth and symmetric nodes,
* but smooth nodes at ends of linear segments and auto nodes need special treatment */
_fixNeighbors(old_pos, position());
+
+ // move the involved handlers, first the node ones, later the adjoining ones
+ if(_pm().isBSpline()){
+ _front.setPosition(_pm().BSplineHandleReposition(this->front(),nodeWeight));
+ _back.setPosition(_pm().BSplineHandleReposition(this->back(),nodeWeight));
+ if(prevNode){
+ if(prevNode->isEndNode()){
+ prevNode->front()->setPosition(_pm().BSplineHandleReposition(prevNode->front(),prevNodeWeight));
+ }else{
+ prevNode->front()->setPosition(_pm().BSplineHandleReposition(prevNode->front(),prevNode->back()));
+ }
+ }
+ if(nextNode){
+ if(nextNode->isEndNode()){
+ nextNode->back()->setPosition(_pm().BSplineHandleReposition(nextNode->back(),nextNodeWeight));
+ }else{
+ nextNode->back()->setPosition(_pm().BSplineHandleReposition(nextNode->back(),nextNode->front()));
+ }
+ }
+ }
}
Geom::Rect Node::bounds() const
@@ -657,6 +812,7 @@ void Node::showHandles(bool v)
if (!_back.isDegenerate()) {
_back.setVisible(v);
}
+
}
void Node::updateHandles()
@@ -758,6 +914,16 @@ void Node::setType(NodeType type, bool update_handles)
break;
default: break;
}
+ /* in node type changes, about bspline traces, we can mantain them with noPower power in border mode,
+ or we give them the default power in curve mode */
+ if(_pm().isBSpline()){
+ double weight = noPower;
+ if(_pm().BSplineHandlePosition(this->front()) != noPower ){
+ weight = defaultStartPower;
+ }
+ _front.setPosition(_pm().BSplineHandleReposition(this->front(),weight));
+ _back.setPosition(_pm().BSplineHandleReposition(this->back(),weight));
+ }
}
_type = type;
_setControlType(nodeTypeToCtrlType(_type));
@@ -870,6 +1036,7 @@ bool Node::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEvent
_selection.spatialGrow(this, dir);
}
return true;
+
default:
break;
}
@@ -1004,6 +1171,11 @@ void Node::_setState(State state)
case STATE_CLICKED:
mgr.setActive(_canvas_item, true);
mgr.setPrelight(_canvas_item, false);
+ //this shows the handlers when selecting the nodes
+ if(_pm().isBSpline()){
+ this->front()->setPosition(_pm().BSplineHandleReposition(this->front()));
+ this->back()->setPosition(_pm().BSplineHandleReposition(this->back()));
+ }
break;
}
SelectableControlPoint::_setState(state);
@@ -1055,6 +1227,10 @@ bool Node::grabbed(GdkEventMotion *event)
void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event)
{
+ if (tools_isactive(_desktop, TOOLS_NODES)) {
+ Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(_desktop->event_context);
+ nt->update_helperpath();
+ }
// For a note on how snapping is implemented in Inkscape, see snap.h.
SnapManager &sm = _desktop->namedview->snap_manager;
// even if we won't really snap, we might still call the one of the
@@ -1258,6 +1434,7 @@ Node *Node::nodeAwayFrom(Handle *h)
Glib::ustring Node::_getTip(unsigned state) const
{
+ bool isBSpline = _pm().isBSpline();
if (state_held_shift(state)) {
bool can_drag_out = (_next() && _front.isDegenerate()) || (_prev() && _back.isDegenerate());
if (can_drag_out) {
@@ -1287,15 +1464,24 @@ Glib::ustring Node::_getTip(unsigned state) const
// No modifiers: assemble tip from node type
char const *nodetype = node_type_to_localized_string(_type);
if (_selection.transformHandlesEnabled() && selected()) {
- if (_selection.size() == 1) {
+ if (_selection.size() == 1 && !isBSpline) {
return format_tip(C_("Path node tip",
"<b>%s</b>: drag to shape the path (more: Shift, Ctrl, Alt)"), nodetype);
+ }else if(_selection.size() == 1){
+ return format_tip(C_("Path node tip",
+ "<b>BSpline node</b>: %g weight, drag to shape the path (more: Shift, Ctrl, Alt)"),noPower/*this->bsplineWeight*/);
}
return format_tip(C_("Path node tip",
"<b>%s</b>: drag to shape the path, click to toggle scale/rotation handles (more: Shift, Ctrl, Alt)"), nodetype);
}
- return format_tip(C_("Path node tip",
- "<b>%s</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt)"), nodetype);
+ if (!isBSpline) {
+ return format_tip(C_("Path node tip",
+ "<b>%s</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt)"), nodetype);
+ }else{
+ return format_tip(C_("Path node tip",
+ "<b>BSpline node</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt)"));
+
+ }
}
Glib::ustring Node::_getDragTip(GdkEventMotion */*event*/) const
@@ -1452,7 +1638,37 @@ void NodeList::reverse()
void NodeList::clear()
{
- for (iterator i = begin(); i != end();) erase (i++);
+ // ugly but more efficient clearing mechanism
+ std::vector<ControlPointSelection *> to_clear;
+ std::vector<std::pair<SelectableControlPoint *, long> > nodes;
+ long in = -1;
+ for (iterator i = begin(); i != end(); ++i) {
+ SelectableControlPoint *rm = static_cast<Node*>(i._node);
+ if (std::find(to_clear.begin(), to_clear.end(), &rm->_selection) == to_clear.end()) {
+ to_clear.push_back(&rm->_selection);
+ ++in;
+ }
+ nodes.push_back(std::make_pair(rm, in));
+ }
+ for (size_t i = 0, e = nodes.size(); i != e; ++i) {
+ to_clear[nodes[i].second]->erase(nodes[i].first, false);
+ }
+ std::vector<std::vector<SelectableControlPoint *> > emission;
+ for (long i = 0, e = to_clear.size(); i != e; ++i) {
+ emission.push_back(std::vector<SelectableControlPoint *>());
+ for (size_t j = 0, f = nodes.size(); j != f; ++j) {
+ if (nodes[j].second != i)
+ break;
+ emission[i].push_back(nodes[j].first);
+ }
+ }
+
+ for (size_t i = 0, e = emission.size(); i != e; ++i) {
+ to_clear[i]->signal_selection_changed.emit(emission[i], false);
+ }
+
+ for (iterator i = begin(); i != end();)
+ erase (i++);
}
NodeList::iterator NodeList::erase(iterator i)
diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h
index 4582d998a..101af4817 100644
--- a/src/ui/tool/node.h
+++ b/src/ui/tool/node.h
@@ -41,6 +41,7 @@ template <typename> class NodeIterator;
}
}
+/*
#if HAVE_TR1_UNORDERED_SET
namespace std {
namespace tr1 {
@@ -48,6 +49,8 @@ template <typename N> struct hash< Inkscape::UI::NodeIterator<N> >;
}
}
#endif
+#endif
+*/
namespace Inkscape {
namespace UI {
@@ -117,7 +120,7 @@ public:
protected:
Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent);
-
+ virtual void handle_2button_press();
virtual bool _eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEvent *event);
virtual void dragged(Geom::Point &new_pos, GdkEventMotion *event);
virtual bool grabbed(GdkEventMotion *event);
@@ -131,6 +134,7 @@ protected:
private:
inline PathManipulator &_pm();
+ inline PathManipulator &_pm() const;
Node *_parent; // the handle's lifetime does not extend beyond that of the parent node,
// so a naked pointer is OK and allows setting it during Node's construction
SPCtrlLine *_handle_line;
@@ -217,6 +221,7 @@ public:
Node *nodeAwayFrom(Handle *h);
NodeList &nodeList() { return *(static_cast<ListNode*>(this)->ln_list); }
+ NodeList &nodeList() const { return *(static_cast<ListNode const*>(this)->ln_list); }
/**
* Move the node to the bottom of its canvas group.
@@ -263,6 +268,7 @@ private:
Inkscape::SnapSourceType _snapSourceType() const;
Inkscape::SnapTargetType _snapTargetType() const;
inline PathManipulator &_pm();
+ inline PathManipulator &_pm() const;
/** Determine whether two nodes are joined by a linear segment. */
static bool _is_line_segment(Node *first, Node *second);
@@ -490,10 +496,17 @@ inline double Handle::length() const {
inline PathManipulator &Handle::_pm() {
return _parent->_pm();
}
+inline PathManipulator &Handle::_pm() const {
+ return _parent->_pm();
+}
inline PathManipulator &Node::_pm() {
return nodeList().subpathList().pm();
}
+inline PathManipulator &Node::_pm() const {
+ return nodeList().subpathList().pm();
+}
+
// definitions for node iterator
template <typename N>
NodeIterator<N>::operator bool() const {
diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp
index 338499672..8b99c33b8 100644
--- a/src/ui/tool/path-manipulator.cpp
+++ b/src/ui/tool/path-manipulator.cpp
@@ -11,6 +11,7 @@
*/
#include "live_effects/lpe-powerstroke.h"
+#include "live_effects/lpe-fillet-chamfer.h"
#include <string>
#include <sstream>
#include <deque>
@@ -42,6 +43,7 @@
#include "ui/tool/multi-path-manipulator.h"
#include "xml/node.h"
#include "xml/node-observer.h"
+#include "live_effects/lpe-bspline.h"
namespace Inkscape {
namespace UI {
@@ -54,6 +56,10 @@ enum PathChange {
};
} // anonymous namespace
+const double handleCubicGap = 0.01;
+const double noPower = 0.0;
+const double defaultStartPower = 0.3334;
+
/**
* Notifies the path manipulator when something changes the path being edited
@@ -102,7 +108,6 @@ private:
};
void build_segment(Geom::PathBuilder &, Node *, Node *);
-
PathManipulator::PathManipulator(MultiPathManipulator &mpm, SPPath *path,
Geom::Affine const &et, guint32 outline_color, Glib::ustring lpe_key)
: PointManipulator(mpm._path_data.node_data.desktop, *mpm._path_data.node_data.selection)
@@ -139,12 +144,14 @@ PathManipulator::PathManipulator(MultiPathManipulator &mpm, SPPath *path,
_selection.signal_update.connect(
sigc::bind(sigc::mem_fun(*this, &PathManipulator::update), false));
- _selection.signal_point_changed.connect(
- sigc::mem_fun(*this, &PathManipulator::_selectionChanged));
+ _selection.signal_selection_changed.connect(
+ sigc::mem_fun(*this, &PathManipulator::_selectionChangedM));
_desktop->signal_zoom_changed.connect(
sigc::hide( sigc::mem_fun(*this, &PathManipulator::_updateOutlineOnZoomChange)));
_createControlPointsFromGeometry();
+ //Define if the path is BSpline on construction
+ isBSpline(true);
}
PathManipulator::~PathManipulator()
@@ -662,6 +669,15 @@ unsigned PathManipulator::_deleteStretch(NodeList::iterator start, NodeList::ite
nl.erase(start);
start = next;
}
+ // if we are removing, we readjust the handlers
+ if(isBSpline()){
+ if(start.prev()){
+ start.prev()->front()->setPosition(BSplineHandleReposition(start.prev()->front(),start.prev()->back()));
+ }
+ if(end){
+ end->back()->setPosition(BSplineHandleReposition(end->back(),end->front()));
+ }
+ }
return del_len;
}
@@ -816,7 +832,6 @@ void PathManipulator::scaleHandle(Node *n, int which, int dir, bool pixel)
}
h->setRelativePos(relpos);
update();
-
gchar const *key = which < 0 ? "handle:scale:left" : "handle:scale:right";
_commit(_("Scale handle"), key);
}
@@ -980,9 +995,36 @@ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, d
// set new handle positions
Node *n = new Node(_multi_path_manipulator._path_data.node_data, seg2[0]);
- n->back()->setPosition(seg1[2]);
- n->front()->setPosition(seg2[1]);
- n->setType(NODE_SMOOTH, false);
+ if(!isBSpline()){
+ n->back()->setPosition(seg1[2]);
+ n->front()->setPosition(seg2[1]);
+ n->setType(NODE_SMOOTH, false);
+ } else {
+ Geom::D2< Geom::SBasis > SBasisInsideNodes;
+ SPCurve *lineInsideNodes = new SPCurve();
+ if(second->back()->isDegenerate()){
+ lineInsideNodes->moveto(n->position());
+ lineInsideNodes->lineto(second->position());
+ SBasisInsideNodes = lineInsideNodes->first_segment()->toSBasis();
+ Geom::Point next = SBasisInsideNodes.valueAt(defaultStartPower);
+ next = Geom::Point(next[Geom::X] + handleCubicGap,next[Geom::Y] + handleCubicGap);
+ lineInsideNodes->reset();
+ n->front()->setPosition(next);
+ }else{
+ n->front()->setPosition(seg2[1]);
+ }
+ if(first->front()->isDegenerate()){
+ lineInsideNodes->moveto(n->position());
+ lineInsideNodes->lineto(first->position());
+ SBasisInsideNodes = lineInsideNodes->first_segment()->toSBasis();
+ Geom::Point previous = SBasisInsideNodes.valueAt(defaultStartPower);
+ previous = Geom::Point(previous[Geom::X] + handleCubicGap,previous[Geom::Y] + handleCubicGap);
+ n->back()->setPosition(previous);
+ }else{
+ n->back()->setPosition(seg1[2]);
+ }
+ n->setType(NODE_CUSP, false);
+ }
inserted = list.insert(insert_at, n);
first->front()->move(seg1[1]);
@@ -1104,7 +1146,6 @@ void PathManipulator::_createControlPointsFromGeometry()
Geom::Curve const &cseg = pit->back_closed();
bool fuse_ends = pit->closed()
&& Geom::are_near(cseg.initialPoint(), cseg.finalPoint());
-
for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) {
Geom::Point pos = cit->finalPoint();
Node *current_node;
@@ -1171,6 +1212,91 @@ void PathManipulator::_createControlPointsFromGeometry()
}
}
+//determines if the trace has a bspline effect and the number of steps that it takes
+int PathManipulator::BSplineGetSteps() const {
+
+ LivePathEffect::LPEBSpline const *lpe_bsp = NULL;
+
+ if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()){
+ Inkscape::LivePathEffect::Effect const *thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::BSPLINE);
+ if(thisEffect){
+ lpe_bsp = dynamic_cast<LivePathEffect::LPEBSpline const*>(thisEffect->getLPEObj()->get_lpe());
+ }
+ }
+ int steps = 0;
+ if(lpe_bsp){
+ steps = lpe_bsp->steps+1;
+ }
+ return steps;
+}
+
+// determines if the trace has bspline effect
+bool PathManipulator::isBSpline(bool recalculate){
+ if(recalculate){
+ _is_bspline = this->BSplineGetSteps() > 0;
+ }
+ return _is_bspline;
+}
+
+bool PathManipulator::isBSpline() const {
+ return BSplineGetSteps() > 0;
+}
+
+// returns the corresponding strength to the position of the handlers
+double PathManipulator::BSplineHandlePosition(Handle *h, Handle *h2){
+ using Geom::X;
+ using Geom::Y;
+ if(h2){
+ h = h2;
+ }
+ double pos = noPower;
+ Node *n = h->parent();
+ Node * nextNode = NULL;
+ nextNode = n->nodeToward(h);
+ if(nextNode){
+ SPCurve *lineInsideNodes = new SPCurve();
+ lineInsideNodes->moveto(n->position());
+ lineInsideNodes->lineto(nextNode->position());
+ if(!are_near(h->position(), n->position())){
+ pos = Geom::nearest_point(Geom::Point(h->position()[X] - handleCubicGap, h->position()[Y] - handleCubicGap), *lineInsideNodes->first_segment());
+ }
+ }
+ if (pos == noPower && !h2){
+ return BSplineHandlePosition(h, h->other());
+ }
+ return pos;
+}
+
+// give the location for the handler in the corresponding position
+Geom::Point PathManipulator::BSplineHandleReposition(Handle *h, Handle *h2){
+ double pos = this->BSplineHandlePosition(h, h2);
+ return BSplineHandleReposition(h,pos);
+}
+
+// give the location for the handler to the specified position
+Geom::Point PathManipulator::BSplineHandleReposition(Handle *h,double pos){
+ using Geom::X;
+ using Geom::Y;
+ Geom::Point ret = h->position();
+ Node *n = h->parent();
+ Geom::D2< Geom::SBasis > SBasisInsideNodes;
+ SPCurve *lineInsideNodes = new SPCurve();
+ Node * nextNode = NULL;
+ nextNode = n->nodeToward(h);
+ if(nextNode && pos != noPower){
+ lineInsideNodes->moveto(n->position());
+ lineInsideNodes->lineto(nextNode->position());
+ SBasisInsideNodes = lineInsideNodes->first_segment()->toSBasis();
+ ret = SBasisInsideNodes.valueAt(pos);
+ ret = Geom::Point(ret[X] + handleCubicGap,ret[Y] + handleCubicGap);
+ }else{
+ if(pos == noPower){
+ ret = n->position();
+ }
+ }
+ return ret;
+}
+
/** Construct the geometric representation of nodes and handles, update the outline
* and display
* \param alert_LPE if true, first the LPE is warned what the new path is going to be before updating it
@@ -1178,6 +1304,8 @@ void PathManipulator::_createControlPointsFromGeometry()
void PathManipulator::_createGeometryFromControlPoints(bool alert_LPE)
{
Geom::PathBuilder builder;
+ //Refresh if is bspline some times -think on path change selection, this value get lost
+ isBSpline(true);
for (std::list<SubpathPtr>::iterator spi = _subpaths.begin(); spi != _subpaths.end(); ) {
SubpathPtr subpath = *spi;
if (subpath->empty()) {
@@ -1186,7 +1314,6 @@ void PathManipulator::_createGeometryFromControlPoints(bool alert_LPE)
}
NodeList::iterator prev = subpath->begin();
builder.moveTo(prev->position());
-
for (NodeList::iterator i = ++subpath->begin(); i != subpath->end(); ++i) {
build_segment(builder, prev.ptr(), i.ptr());
prev = i;
@@ -1207,11 +1334,20 @@ void PathManipulator::_createGeometryFromControlPoints(bool alert_LPE)
_spcurve->set_pathvector(pathv);
if (alert_LPE) {
/// \todo note that _path can be an Inkscape::LivePathEffect::Effect* too, kind of confusing, rework member naming?
- if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()) {
- PathEffectList effect_list = _path->getEffectList();
- LivePathEffect::LPEPowerStroke *lpe_pwr = dynamic_cast<LivePathEffect::LPEPowerStroke*>( effect_list.front()->lpeobject->get_lpe() );
- if (lpe_pwr) {
- lpe_pwr->adjustForNewPath(pathv);
+ if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()){
+ Inkscape::LivePathEffect::Effect* thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::POWERSTROKE);
+ if(thisEffect){
+ LivePathEffect::LPEPowerStroke *lpe_pwr = dynamic_cast<LivePathEffect::LPEPowerStroke*>(thisEffect->getLPEObj()->get_lpe());
+ if (lpe_pwr) {
+ lpe_pwr->adjustForNewPath(pathv);
+ }
+ }
+ thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::FILLET_CHAMFER);
+ if(thisEffect){
+ LivePathEffect::LPEFilletChamfer *lpe_fll = dynamic_cast<LivePathEffect::LPEFilletChamfer*>(thisEffect->getLPEObj()->get_lpe());
+ if (lpe_fll) {
+ lpe_fll->adjustForNewPath(pathv);
+ }
}
}
}
@@ -1419,6 +1555,12 @@ bool PathManipulator::_handleClicked(Handle *h, GdkEventButton *event)
return false;
}
+void PathManipulator::_selectionChangedM(std::vector<SelectableControlPoint *> pvec, bool selected) {
+ for (size_t n = 0, e = pvec.size(); n < e; ++n) {
+ _selectionChanged(pvec[n], selected);
+ }
+}
+
void PathManipulator::_selectionChanged(SelectableControlPoint *p, bool selected)
{
if (selected) ++_num_selected;
diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h
index 7a13ce723..4d2bf4300 100644
--- a/src/ui/tool/path-manipulator.h
+++ b/src/ui/tool/path-manipulator.h
@@ -19,6 +19,7 @@
#include <boost/weak_ptr.hpp>
#include "ui/tool/node.h"
#include "ui/tool/manipulator.h"
+#include "live_effects/lpe-bspline.h"
struct SPCanvasItem;
class SPCurve;
@@ -95,6 +96,7 @@ public:
NodeList::iterator extremeNode(NodeList::iterator origin, bool search_selected,
bool search_unselected, bool closest);
+ int BSplineGetSteps() const;
// this is necessary for Tab-selection in MultiPathManipulator
SubpathList &subpathList() { return _subpaths; }
@@ -104,6 +106,12 @@ private:
typedef boost::shared_ptr<NodeList> SubpathPtr;
void _createControlPointsFromGeometry();
+
+ bool isBSpline(bool recalculate = false);
+ bool isBSpline() const;
+ double BSplineHandlePosition(Handle *h, Handle *h2 = NULL);
+ Geom::Point BSplineHandleReposition(Handle *h, Handle *h2 = NULL);
+ Geom::Point BSplineHandleReposition(Handle *h, double pos);
void _createGeometryFromControlPoints(bool alert_LPE = false);
unsigned _deleteStretch(NodeList::iterator first, NodeList::iterator last, bool keep_shape);
std::string _createTypeString();
@@ -114,7 +122,8 @@ private:
Glib::ustring _nodetypesKey();
Inkscape::XML::Node *_getXMLNode();
- void _selectionChanged(SelectableControlPoint *p, bool selected);
+ void _selectionChangedM(std::vector<SelectableControlPoint *> pvec, bool selected);
+ void _selectionChanged(SelectableControlPoint * p, bool selected);
bool _nodeClicked(Node *, GdkEventButton *);
void _handleGrabbed();
bool _handleClicked(Handle *, GdkEventButton *);
@@ -145,6 +154,7 @@ private:
bool _show_path_direction;
bool _live_outline;
bool _live_objects;
+ bool _is_bspline;
Glib::ustring _lpe_key;
friend class PathManipulatorObserver;
diff --git a/src/ui/tool/selectable-control-point.h b/src/ui/tool/selectable-control-point.h
index 8acfc1168..362d4addc 100644
--- a/src/ui/tool/selectable-control-point.h
+++ b/src/ui/tool/selectable-control-point.h
@@ -28,6 +28,7 @@ public:
virtual Geom::Rect bounds() const {
return Geom::Rect(position(), position());
}
+ friend class NodeList;
protected:
diff --git a/src/ui/tools-switch.cpp b/src/ui/tools-switch.cpp
new file mode 100644
index 000000000..47b9d2832
--- /dev/null
+++ b/src/ui/tools-switch.cpp
@@ -0,0 +1,201 @@
+/*
+ * Utility functions for switching tools (= contexts)
+ *
+ * Authors:
+ * bulia byak <buliabyak@users.sf.net>
+ * Josh Andler <scislac@users.sf.net>
+ * Jon A. Cruz <jon@joncruz.org>
+ *
+ * Copyright (C) 2003-2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <gtkmm.h> // prevents deprecation warnings
+
+#include <cstring>
+#include <string>
+
+#include "inkscape-private.h"
+#include "desktop.h"
+#include "desktop-handles.h"
+#include <glibmm/i18n.h>
+
+#include <xml/repr.h>
+
+#include "ui/tools-switch.h"
+
+#include "box3d.h"
+#include "sp-ellipse.h"
+#include "sp-flowtext.h"
+#include "sp-offset.h"
+#include "sp-path.h"
+#include "sp-rect.h"
+#include "sp-star.h"
+#include "sp-spiral.h"
+#include "sp-text.h"
+
+// TODO: How many of these are actually needed?
+#include "ui/tools/arc-tool.h"
+#include "ui/tools/box3d-tool.h"
+#include "ui/tools/calligraphic-tool.h"
+#include "ui/tools/connector-tool.h"
+#include "ui/tools/dropper-tool.h"
+#include "ui/tools/eraser-tool.h"
+#include "ui/tools/flood-tool.h"
+#include "ui/tools/gradient-tool.h"
+#include "ui/tools/lpe-tool.h"
+#include "ui/tools/measure-tool.h"
+#include "ui/tools/mesh-tool.h"
+#include "ui/tools/node-tool.h"
+#include "ui/tools/pen-tool.h"
+#include "ui/tools/pencil-tool.h"
+#include "ui/tools/rect-tool.h"
+#include "ui/tools/select-tool.h"
+#include "ui/tools/spiral-tool.h"
+#include "ui/tools/spray-tool.h"
+#include "ui/tools/text-tool.h"
+#include "ui/tools/tweak-tool.h"
+#include "ui/tools/zoom-tool.h"
+
+#include "message-context.h"
+
+using Inkscape::UI::Tools::ToolBase;
+
+static char const *const tool_names[] = {
+ NULL,
+ "/tools/select",
+ "/tools/nodes",
+ "/tools/tweak",
+ "/tools/spray",
+ "/tools/shapes/rect",
+ "/tools/shapes/3dbox",
+ "/tools/shapes/arc",
+ "/tools/shapes/star",
+ "/tools/shapes/spiral",
+ "/tools/freehand/pencil",
+ "/tools/freehand/pen",
+ "/tools/calligraphic",
+ "/tools/text",
+ "/tools/gradient",
+ "/tools/mesh",
+ "/tools/zoom",
+ "/tools/measure",
+ "/tools/dropper",
+ "/tools/connector",
+ "/tools/paintbucket",
+ "/tools/eraser",
+ "/tools/lpetool",
+ NULL
+};
+
+// TODO: HEY! these belong to the tools themselves!
+static char const *const tool_msg[] = {
+ NULL,
+ N_("<b>Click</b> to Select and Transform objects, <b>Drag</b> to select many objects."),
+ N_("Modify selected path points (nodes) directly."),
+ N_("To tweak a path by pushing, select it and drag over it."),
+ N_("<b>Drag</b>, <b>click</b> or <b>click and scroll</b> to spray the selected objects."),
+ N_("<b>Drag</b> to create a rectangle. <b>Drag controls</b> to round corners and resize. <b>Click</b> to select."),
+ N_("<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)."),
+ N_("<b>Drag</b> to create an ellipse. <b>Drag controls</b> to make an arc or segment. <b>Click</b> to select."),
+ N_("<b>Drag</b> to create a star. <b>Drag controls</b> to edit the star shape. <b>Click</b> to select."),
+ N_("<b>Drag</b> to create a spiral. <b>Drag controls</b> to edit the spiral shape. <b>Click</b> to select."),
+ N_("<b>Drag</b> to create a freehand line. <b>Shift</b> appends to selected path, <b>Alt</b> activates sketch mode."),
+ N_("<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)."),
+ N_("<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)."),
+ N_("<b>Click</b> to select or create text, <b>drag</b> to create flowed text; then type."),
+ N_("<b>Drag</b> or <b>double click</b> to create a gradient on selected objects, <b>drag handles</b> to adjust gradients."),
+ N_("<b>Drag</b> or <b>double click</b> to create a mesh on selected objects, <b>drag handles</b> to adjust meshes."),
+ N_("<b>Click</b> or <b>drag around an area</b> to zoom in, <b>Shift+click</b> to zoom out."),
+ N_("<b>Drag</b> to measure the dimensions of objects."),
+ N_("<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"),
+ N_("<b>Click and drag</b> between shapes to create a connector."),
+ N_("<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."),
+ N_("<b>Drag</b> to erase."),
+ N_("Choose a subtool from the toolbar"),
+};
+
+static int
+tools_prefpath2num(char const *id)
+{
+ int i = 1;
+ while (tool_names[i]) {
+ if (strcmp(tool_names[i], id) == 0)
+ return i;
+ else i++;
+ }
+ g_assert( 0 == TOOLS_INVALID );
+ return 0; //nothing found
+}
+
+int
+tools_isactive(SPDesktop *dt, unsigned num)
+{
+ g_assert( num < G_N_ELEMENTS(tool_names) );
+ if (dynamic_cast<ToolBase *>(dt->event_context)) {
+ return dt->event_context->pref_observer->observed_path == tool_names[num];
+ } else {
+ return FALSE;
+ }
+}
+
+int
+tools_active(SPDesktop *dt)
+{
+ return tools_prefpath2num(dt->event_context->pref_observer->observed_path.data());
+}
+
+void
+tools_switch(SPDesktop *dt, int num)
+{
+ dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, gettext( tool_msg[num] ) );
+ if (dt) {
+ // This event may change the above message
+ dt->_tool_changed.emit(num);
+ }
+
+ dt->set_event_context2(tool_names[num]);
+ /* fixme: This is really ugly hack. We should bind and unbind class methods */
+ /* First 4 tools use guides, first is undefined but we don't care */
+ dt->activate_guides(num < 5);
+ inkscape_eventcontext_set(dt->getEventContext());
+}
+
+void tools_switch_by_item(SPDesktop *dt, SPItem *item, Geom::Point const p)
+{
+ if (dynamic_cast<SPRect *>(item)) {
+ tools_switch(dt, TOOLS_SHAPES_RECT);
+ } else if (dynamic_cast<SPBox3D *>(item)) {
+ tools_switch(dt, TOOLS_SHAPES_3DBOX);
+ } else if (dynamic_cast<SPGenericEllipse *>(item)) {
+ tools_switch(dt, TOOLS_SHAPES_ARC);
+ } else if (dynamic_cast<SPStar *>(item)) {
+ tools_switch(dt, TOOLS_SHAPES_STAR);
+ } else if (dynamic_cast<SPSpiral *>(item)) {
+ tools_switch(dt, TOOLS_SHAPES_SPIRAL);
+ } else if (dynamic_cast<SPPath *>(item)) {
+ if (Inkscape::UI::Tools::cc_item_is_connector(item)) {
+ tools_switch(dt, TOOLS_CONNECTOR);
+ }
+ else {
+ tools_switch(dt, TOOLS_NODES);
+ }
+ } else if (dynamic_cast<SPText *>(item) || dynamic_cast<SPFlowtext *>(item)) {
+ tools_switch(dt, TOOLS_TEXT);
+ sp_text_context_place_cursor_at (SP_TEXT_CONTEXT(dt->event_context), item, p);
+ } else if (dynamic_cast<SPOffset *>(item)) {
+ tools_switch(dt, TOOLS_NODES);
+ }
+}
+
+/*
+ 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/tools-switch.h b/src/ui/tools-switch.h
new file mode 100644
index 000000000..280837e87
--- /dev/null
+++ b/src/ui/tools-switch.h
@@ -0,0 +1,64 @@
+/*
+ * Utility functions for switching tools (= contexts)
+ *
+ * Authors:
+ * bulia byak <bulia@dr.com>
+ *
+ * Copyright (C) 2003 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_TOOLS_SWITCH_H
+#define SEEN_TOOLS_SWITCH_H
+
+class SPDesktop;
+class SPItem;
+namespace Geom {
+class Point;
+}
+
+
+enum {
+ TOOLS_INVALID,
+ TOOLS_SELECT,
+ TOOLS_NODES,
+ TOOLS_TWEAK,
+ TOOLS_SPRAY,
+ TOOLS_SHAPES_RECT,
+ TOOLS_SHAPES_3DBOX,
+ TOOLS_SHAPES_ARC,
+ TOOLS_SHAPES_STAR,
+ TOOLS_SHAPES_SPIRAL,
+ TOOLS_FREEHAND_PENCIL,
+ TOOLS_FREEHAND_PEN,
+ TOOLS_CALLIGRAPHIC,
+ TOOLS_TEXT,
+ TOOLS_GRADIENT,
+ TOOLS_MESH,
+ TOOLS_ZOOM,
+ TOOLS_MEASURE,
+ TOOLS_DROPPER,
+ TOOLS_CONNECTOR,
+ TOOLS_PAINTBUCKET,
+ TOOLS_ERASER,
+ TOOLS_LPETOOL
+};
+
+int tools_isactive(SPDesktop *dt, unsigned num);
+int tools_active(SPDesktop *dt);
+void tools_switch(SPDesktop *dt, int num);
+void tools_switch_by_item (SPDesktop *dt, SPItem *item, Geom::Point const p);
+
+#endif // !SEEN_TOOLS_SWITCH_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/ui/tools/arc-tool.cpp b/src/ui/tools/arc-tool.cpp
index 43f8eb9e1..4f64ade25 100644
--- a/src/ui/tools/arc-tool.cpp
+++ b/src/ui/tools/arc-tool.cpp
@@ -40,7 +40,7 @@
#include "desktop-style.h"
#include "context-fns.h"
#include "verbs.h"
-#include "shape-editor.h"
+#include "ui/shape-editor.h"
#include "ui/tools/tool-base.h"
#include "ui/tools/arc-tool.h"
@@ -48,7 +48,7 @@
using Inkscape::DocumentUndo;
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
@@ -102,8 +102,8 @@ ArcTool::~ArcTool() {
* destroys old and creates new knotholder.
*/
void ArcTool::selection_changed(Inkscape::Selection* selection) {
- this->shape_editor->unset_item(SH_KNOTHOLDER);
- this->shape_editor->set_item(selection->singleItem(), SH_KNOTHOLDER);
+ this->shape_editor->unset_item();
+ this->shape_editor->set_item(selection->singleItem());
}
void ArcTool::setup() {
@@ -115,7 +115,7 @@ void ArcTool::setup() {
SPItem *item = sp_desktop_selection(this->desktop)->singleItem();
if (item) {
- this->shape_editor->set_item(item, SH_KNOTHOLDER);
+ this->shape_editor->set_item(item);
}
this->sel_changed_connection.disconnect();
diff --git a/src/ui/tools/arc-tool.h b/src/ui/tools/arc-tool.h
index c4c67660d..55cbaf78c 100644
--- a/src/ui/tools/arc-tool.h
+++ b/src/ui/tools/arc-tool.h
@@ -30,7 +30,7 @@ namespace Inkscape {
}
#define SP_ARC_CONTEXT(obj) (dynamic_cast<Inkscape::UI::Tools::ArcTool*>((Inkscape::UI::Tools::ToolBase*)obj))
-#define SP_IS_ARC_CONTEXT(obj) (dynamic_cast<const Inkscape::UI::Tools::ArcTool*>(const Inkscape::UI::Tools::ToolBase*(obj)) != NULL)
+#define SP_IS_ARC_CONTEXT(obj) (dynamic_cast<const Inkscape::UI::Tools::ArcTool*>(obj) != NULL)
namespace Inkscape {
namespace UI {
diff --git a/src/ui/tools/box3d-tool.cpp b/src/ui/tools/box3d-tool.cpp
index e00894d55..0a20a0842 100644
--- a/src/ui/tools/box3d-tool.cpp
+++ b/src/ui/tools/box3d-tool.cpp
@@ -47,12 +47,12 @@
#include "box3d-side.h"
#include "document-private.h"
#include "line-geometry.h"
-#include "shape-editor.h"
+#include "ui/shape-editor.h"
#include "verbs.h"
using Inkscape::DocumentUndo;
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
@@ -112,8 +112,8 @@ Box3dTool::~Box3dTool() {
* destroys old and creates new knotholder.
*/
void Box3dTool::selection_changed(Inkscape::Selection* selection) {
- this->shape_editor->unset_item(SH_KNOTHOLDER);
- this->shape_editor->set_item(selection->singleItem(), SH_KNOTHOLDER);
+ this->shape_editor->unset_item();
+ this->shape_editor->set_item(selection->singleItem());
if (selection->perspList().size() == 1) {
// selecting a single box changes the current perspective
@@ -147,7 +147,7 @@ void Box3dTool::setup() {
SPItem *item = sp_desktop_selection(this->desktop)->singleItem();
if (item) {
- this->shape_editor->set_item(item, SH_KNOTHOLDER);
+ this->shape_editor->set_item(item);
}
this->sel_changed_connection.disconnect();
diff --git a/src/ui/tools/calligraphic-tool.cpp b/src/ui/tools/calligraphic-tool.cpp
index 64097e834..d297fe5e1 100644
--- a/src/ui/tools/calligraphic-tool.cpp
+++ b/src/ui/tools/calligraphic-tool.cpp
@@ -82,7 +82,7 @@ using Inkscape::DocumentUndo;
#define DYNA_MIN_WIDTH 1.0e-6
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
diff --git a/src/ui/tools/connector-tool.cpp b/src/ui/tools/connector-tool.cpp
index d1355e807..7b5c84c16 100644
--- a/src/ui/tools/connector-tool.cpp
+++ b/src/ui/tools/connector-tool.cpp
@@ -109,7 +109,7 @@
using Inkscape::DocumentUndo;
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
diff --git a/src/ui/tools/dropper-tool.cpp b/src/ui/tools/dropper-tool.cpp
index 99d42a211..6c55f7484 100644
--- a/src/ui/tools/dropper-tool.cpp
+++ b/src/ui/tools/dropper-tool.cpp
@@ -52,7 +52,7 @@ using Inkscape::DocumentUndo;
static GdkCursor *cursor_dropper_fill = NULL;
static GdkCursor *cursor_dropper_stroke = NULL;
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp
index 4106785e7..bf4015b4c 100644
--- a/src/ui/tools/eraser-tool.cpp
+++ b/src/ui/tools/eraser-tool.cpp
@@ -84,7 +84,7 @@ using Inkscape::DocumentUndo;
#define DRAG_DEFAULT 1.0
#define DRAG_MAX 1.0
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
diff --git a/src/ui/tools/flood-tool.cpp b/src/ui/tools/flood-tool.cpp
index d74848dc6..5745fc9cc 100644
--- a/src/ui/tools/flood-tool.cpp
+++ b/src/ui/tools/flood-tool.cpp
@@ -50,7 +50,7 @@
#include "preferences.h"
#include "rubberband.h"
#include "selection.h"
-#include "shape-editor.h"
+#include "ui/shape-editor.h"
#include "sp-defs.h"
#include "sp-item.h"
#include "splivarot.h"
@@ -74,7 +74,7 @@ using Inkscape::Display::ExtractARGB32;
using Inkscape::Display::ExtractRGB32;
using Inkscape::Display::AssembleARGB32;
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
@@ -119,8 +119,8 @@ FloodTool::~FloodTool() {
* destroys old and creates new knotholder.
*/
void FloodTool::selection_changed(Inkscape::Selection* selection) {
- this->shape_editor->unset_item(SH_KNOTHOLDER);
- this->shape_editor->set_item(selection->singleItem(), SH_KNOTHOLDER);
+ this->shape_editor->unset_item();
+ this->shape_editor->set_item(selection->singleItem());
}
void FloodTool::setup() {
@@ -130,7 +130,7 @@ void FloodTool::setup() {
SPItem *item = sp_desktop_selection(this->desktop)->singleItem();
if (item) {
- this->shape_editor->set_item(item, SH_KNOTHOLDER);
+ this->shape_editor->set_item(item);
}
this->sel_changed_connection.disconnect();
diff --git a/src/ui/tools/flood-tool.h b/src/ui/tools/flood-tool.h
index 3ed670e8b..5104a42e9 100644
--- a/src/ui/tools/flood-tool.h
+++ b/src/ui/tools/flood-tool.h
@@ -11,9 +11,7 @@
* Released under GNU GPL
*/
-#include <stddef.h>
-#include <sigc++/sigc++.h>
-#include <gtk/gtk.h>
+#include <sigc++/connection.h>
#include "ui/tools/tool-base.h"
#define SP_FLOOD_CONTEXT(obj) (dynamic_cast<Inkscape::UI::Tools::FloodTool*>((Inkscape::UI::Tools::ToolBase*)obj))
diff --git a/src/ui/tools/freehand-base.cpp b/src/ui/tools/freehand-base.cpp
index 4f2ec6c48..68b57dc90 100644
--- a/src/ui/tools/freehand-base.cpp
+++ b/src/ui/tools/freehand-base.cpp
@@ -31,7 +31,7 @@
#include "desktop-handles.h"
#include "desktop-style.h"
#include "document.h"
-#include "draw-anchor.h"
+#include "ui/draw-anchor.h"
#include "macros.h"
#include "message-stack.h"
#include "ui/tools/pen-tool.h"
@@ -45,6 +45,7 @@
#include "live_effects/lpe-powerstroke.h"
#include "style.h"
#include "ui/control-manager.h"
+// clipboard support
#include "ui/clipboard.h"
#include "ui/tools/freehand-base.h"
@@ -80,6 +81,7 @@ FreehandBase::FreehandBase(gchar const *const *cursor_shape, gint hot_x, gint ho
, red_color(0xff00007f)
, blue_color(0x0000ff7f)
, green_color(0x00ff007f)
+ , highlight_color(0x0000007f)
, red_bpath(NULL)
, red_curve(NULL)
, blue_bpath(NULL)
@@ -91,6 +93,7 @@ FreehandBase::FreehandBase(gchar const *const *cursor_shape, gint hot_x, gint ho
, white_item(NULL)
, white_curves(NULL)
, white_anchors(NULL)
+ , overwriteCurve(NULL)
, sa(NULL)
, ea(NULL)
, waiting_LPE_type(Inkscape::LivePathEffect::INVALID_LPE)
@@ -146,6 +149,9 @@ void FreehandBase::setup() {
this->green_anchor = NULL;
this->green_closed = FALSE;
+ // Create start anchor alternative curve
+ this->overwriteCurve = new SPCurve();
+
this->attach = TRUE;
spdc_attach_selection(this, this->selection);
}
@@ -227,6 +233,32 @@ static void spdc_apply_powerstroke_shape(const std::vector<Geom::Point> & points
Effect* lpe = SP_LPE_ITEM(item)->getCurrentLPE();
static_cast<LPEPowerStroke*>(lpe)->offset_points.param_set_and_write_new_value(points);
+ // find out stroke width (TODO: is there an easier way??)
+ SPDesktop *desktop = dc->desktop;
+ Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
+ Inkscape::XML::Node *repr = xml_doc->createElement("svg:path");
+ Inkscape::GC::release(repr);
+
+ char const* tool = SP_IS_PEN_CONTEXT(dc) ? "/tools/freehand/pen" : "/tools/freehand/pencil";
+
+ // apply the tool's current style
+ sp_desktop_apply_style_tool(desktop, repr, tool, false);
+
+ double stroke_width = 1.0;
+ char const *style_str = NULL;
+ style_str = repr->attribute("style");
+ if (style_str) {
+ SPStyle *style = sp_style_new(SP_ACTIVE_DOCUMENT);
+ sp_style_merge_from_style_string(style, style_str);
+ stroke_width = style->stroke_width.computed;
+ style->stroke_width.computed = 0;
+ sp_style_unref(style);
+ }
+
+ std::ostringstream s;
+ s.imbue(std::locale::classic());
+ s << "0," << stroke_width / 2.;
+
// write powerstroke parameters:
lpe->getRepr()->setAttribute("start_linecap_type", "zerowidth");
lpe->getRepr()->setAttribute("end_linecap_type", "zerowidth");
@@ -234,6 +266,7 @@ static void spdc_apply_powerstroke_shape(const std::vector<Geom::Point> & points
lpe->getRepr()->setAttribute("sort_points", "true");
lpe->getRepr()->setAttribute("interpolator_type", "CubicBezierJohan");
lpe->getRepr()->setAttribute("interpolator_beta", "0.2");
+ lpe->getRepr()->setAttribute("offset_points", s.str().c_str());
}
@@ -241,7 +274,9 @@ static void spdc_apply_bend_shape(gchar const *svgd, FreehandBase *dc, SPItem *i
{
using namespace Inkscape::LivePathEffect;
- Effect::createAndApply(BEND_PATH, dc->desktop->doc(), item);
+ if(!SP_LPE_ITEM(item)->hasPathEffectOfType(BEND_PATH)){
+ Effect::createAndApply(BEND_PATH, dc->desktop->doc(), item);
+ }
Effect* lpe = SP_LPE_ITEM(item)->getCurrentLPE();
// write bend parameters:
@@ -261,37 +296,41 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item,
if (prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 1) {
Effect::createAndApply(SPIRO, dc->desktop->doc(), item);
}
+ //add the bspline node in the waiting effects
+ if (prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 2) {
+ Effect::createAndApply(BSPLINE, dc->desktop->doc(), item);
+ }
+
+ //Store the clipboard path to apply in the future without the use of clipboard
- //Store the clipboard path to apply in the future without the use of clipboard
static Geom::PathVector previous_shape_pathv;
- //Last shape applied type "-1" means "no previous shape"
- int shape = prefs->getInt(tool_name(dc) + "/shape", 0);
+ enum shapeType { NONE, TRIANGLE_IN, TRIANGLE_OUT, ELLIPSE, CLIPBOARD, BEND_CLIPBOARD, LAST_APPLIED };
+ static shapeType previous_shape_type = NONE;
+
+
+ shapeType shape = (shapeType)prefs->getInt(tool_name(dc) + "/shape", 0);
bool shape_applied = false;
SPCSSAttr *css_item = sp_css_attr_from_object(item, SP_STYLE_FLAG_ALWAYS);
const char *cstroke = sp_repr_css_property(css_item, "stroke", "none");
- static SPItem *itemEnd;
+ static SPItem *bendItem;
#define SHAPE_LENGTH 10
#define SHAPE_HEIGHT 10
- if(shape == 6){
+
+ if(shape == LAST_APPLIED){
+
shape = previous_shape_type;
- if(shape == 4){
- shape = 6;
- }
- if(shape == 5){
- shape = 7;
- }
- if(previous_shape_type == -1){
- shape = 0;
+ if(shape == CLIPBOARD || shape == BEND_CLIPBOARD){
+ shape = LAST_APPLIED;
}
}
switch (shape) {
- case 0:
+ case NONE:
// don't apply any shape
break;
- case 1:
+ case TRIANGLE_IN:
{
// "triangle in"
std::vector<Geom::Point> points(1);
@@ -301,7 +340,7 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item,
shape_applied = true;
break;
}
- case 2:
+ case TRIANGLE_OUT:
{
// "triangle out"
guint curve_length = curve->get_segment_count();
@@ -312,7 +351,7 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item,
shape_applied = true;
break;
}
- case 3:
+ case ELLIPSE:
{
// "ellipse"
SPCurve *c = new SPCurve();
@@ -329,7 +368,7 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item,
shape_applied = true;
break;
}
- case 4:
+ case CLIPBOARD:
{
// take shape from clipboard; TODO: catch the case where clipboard is empty
Effect::createAndApply(PATTERN_ALONG_PATH, dc->desktop->doc(), item);
@@ -342,74 +381,56 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item,
shape_applied = true;
break;
}
- case 5:
+ case BEND_CLIPBOARD:
{
- // take shape from clipboard; TODO: catch the case where clipboard is empty
Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
if(cm->paste(SP_ACTIVE_DESKTOP,false) == true){
gchar const *svgd = item->getRepr()->attribute("d");
- item->deleteObject();
- if(itemEnd != NULL && itemEnd->getRepr() != NULL)
- itemEnd->deleteObject();
- Inkscape::Selection *selection = sp_desktop_selection(dc->desktop);
- sp_selection_group(selection, dc->desktop);
- GSList *items = const_cast<GSList *>(selection->itemList());
- SPObject *obj = reinterpret_cast<SPObject *>(g_slist_nth_data(items,0));
- if(SP_IS_OBJECT(obj)){
- itemEnd = SP_ITEM(obj);
- sp_selection_duplicate(dc->desktop);
- itemEnd->setExplicitlyHidden(true);
- items = const_cast<GSList *>(selection->itemList());
- obj = reinterpret_cast<SPObject *>(g_slist_nth_data(items,0));
- if(SP_IS_OBJECT(obj)){
- spdc_apply_bend_shape(svgd, dc, SP_ITEM(obj));
- SP_ITEM(obj)->setExplicitlyHidden(false);
- selection->set(SP_ITEM(obj),true);
- }
- }
- }
- break;
- }
- case 6:
- {
- if(previous_shape_pathv.size() != 0){
- SPCurve * c = new SPCurve();
- c->set_pathvector(previous_shape_pathv);
- spdc_paste_curve_as_freehand_shape(c, dc, item);
- c->unref();
-
- shape_applied = true;
+ item->getRepr()->setAttribute("d", "");
+ bendItem = dc->selection->singleItem();
+ item->setSuccessor(bendItem);
+ item = bendItem;
+ g_assert(item != NULL);
+ spdc_apply_bend_shape(svgd, dc, item);
+ dc->selection->set(item,true);
}
-
- shape = previous_shape_type;
break;
}
- case 7:
+ case LAST_APPLIED:
{
- // take shape from clipboard; TODO: catch the case where clipboard is empty
- if(itemEnd != NULL && itemEnd->getRepr() != NULL){
- gchar const *svgd = item->getRepr()->attribute("d");
- item->deleteObject();
- Inkscape::Selection *selection = sp_desktop_selection(dc->desktop);
- selection->add(SP_OBJECT(itemEnd));
- sp_selection_duplicate(dc->desktop);
- selection->remove(SP_OBJECT(itemEnd));
- GSList *items = const_cast<GSList *>(selection->itemList());
- SPObject *obj = reinterpret_cast<SPObject *>(g_slist_nth_data(items,0));
- if(SP_IS_OBJECT(obj)){
- SP_ITEM(obj)->getRepr()->setAttribute("inkscape:path-effect", NULL);
- spdc_apply_bend_shape(svgd, dc, SP_ITEM(obj));
- SP_ITEM(obj)->setExplicitlyHidden(false);
- selection->set(SP_ITEM(obj),true);
+ if(previous_shape_type == CLIPBOARD){
+ if(previous_shape_pathv.size() != 0){
+ SPCurve * c = new SPCurve();
+ c->set_pathvector(previous_shape_pathv);
+ spdc_paste_curve_as_freehand_shape(c, dc, item);
+ c->unref();
+
+ shape_applied = true;
+ }
+ } else {
+ if(bendItem != NULL && bendItem->getRepr() != NULL){
+ gchar const *svgd = item->getRepr()->attribute("d");
+ item->getRepr()->setAttribute("d", "");
+ Inkscape::Selection *selection = sp_desktop_selection(dc->desktop);
+ selection->add(SP_OBJECT(bendItem));
+ sp_selection_duplicate(dc->desktop);
+ selection->remove(SP_OBJECT(bendItem));
+ bendItem = dc->selection->singleItem();
+ item->setSuccessor(bendItem);
+ item = bendItem;
+ g_assert(item != NULL);
+ spdc_apply_bend_shape(svgd, dc, item);
+ dc->selection->set(item,true);
}
}
- shape = previous_shape_type;
break;
}
default:
break;
}
- previous_shape_type = shape;
+ if(shape != LAST_APPLIED){
+ previous_shape_type = shape;
+ }
if (shape_applied) {
// apply original stroke color as fill and unset stroke; then return
SPCSSAttr *css = sp_repr_css_attr_new();
@@ -424,8 +445,9 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item,
sp_repr_css_attr_unref(css);
return;
}
- if(previous_shape_type == 5)return;
-
+ if(previous_shape_type == 5 || previous_shape_type == 6 || previous_shape_type == 7){
+ return;
+ }
if (dc->waiting_LPE_type != INVALID_LPE) {
Effect::createAndApply(dc->waiting_LPE_type, dc->desktop->doc(), item);
dc->waiting_LPE_type = INVALID_LPE;
@@ -564,7 +586,7 @@ void spdc_concat_colors_and_flush(FreehandBase *dc, gboolean forceclosed)
{
// Concat RBG
SPCurve *c = dc->green_curve;
-
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
// Green
dc->green_curve = new SPCurve();
while (dc->green_bpaths) {
@@ -611,9 +633,20 @@ void spdc_concat_colors_and_flush(FreehandBase *dc, gboolean forceclosed)
if (dc->sa->start && !(dc->sa->curve->is_closed()) ) {
c = reverse_then_unref(c);
}
- dc->sa->curve->append_continuous(c, 0.0625);
- c->unref();
- dc->sa->curve->closepath_current();
+ if(prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 1 ||
+ prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 2){
+ dc->overwriteCurve->append_continuous(c, 0.0625);
+ c->unref();
+ dc->overwriteCurve->closepath_current();
+ if(dc->sa){
+ dc->white_curves = g_slist_remove(dc->white_curves, dc->sa->curve);
+ dc->white_curves = g_slist_append(dc->white_curves, dc->overwriteCurve);
+ }
+ }else{
+ dc->sa->curve->append_continuous(c, 0.0625);
+ c->unref();
+ dc->sa->curve->closepath_current();
+ }
spdc_flush_white(dc, NULL);
return;
}
@@ -622,6 +655,10 @@ void spdc_concat_colors_and_flush(FreehandBase *dc, gboolean forceclosed)
if (dc->sa) {
SPCurve *s = dc->sa->curve;
dc->white_curves = g_slist_remove(dc->white_curves, s);
+ if(prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 1 ||
+ prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 2){
+ s = dc->overwriteCurve;
+ }
if (dc->sa->start) {
s = reverse_then_unref(s);
}
@@ -634,6 +671,25 @@ void spdc_concat_colors_and_flush(FreehandBase *dc, gboolean forceclosed)
if (!dc->ea->start) {
e = reverse_then_unref(e);
}
+ if(prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 1 ||
+ prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 2){
+ e = reverse_then_unref(e);
+ Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*e->last_segment());
+ SPCurve *lastSeg = new SPCurve();
+ if(cubic){
+ lastSeg->moveto((*cubic)[0]);
+ lastSeg->curveto((*cubic)[1],(*cubic)[3],(*cubic)[3]);
+ if( e->get_segment_count() == 1){
+ e = lastSeg;
+ }else{
+ //we eliminate the last segment
+ e->backspace();
+ //and we add it again with the recreation
+ e->append_continuous(lastSeg, 0.0625);
+ }
+ }
+ e = reverse_then_unref(e);
+ }
c->append_continuous(e, 0.0625);
e->unref();
}
@@ -647,7 +703,6 @@ void spdc_concat_colors_and_flush(FreehandBase *dc, gboolean forceclosed)
static void spdc_flush_white(FreehandBase *dc, SPCurve *gc)
{
SPCurve *c;
-
if (dc->white_curves) {
g_assert(dc->white_item);
c = SPCurve::concat(dc->white_curves);
@@ -677,6 +732,7 @@ static void spdc_flush_white(FreehandBase *dc, SPCurve *gc)
bool has_lpe = false;
Inkscape::XML::Node *repr;
+
if (dc->white_item) {
repr = dc->white_item->getRepr();
has_lpe = SP_LPE_ITEM(dc->white_item)->hasPathEffectRecursive();
@@ -700,12 +756,17 @@ static void spdc_flush_white(FreehandBase *dc, SPCurve *gc)
// we finished the path; now apply any waiting LPEs or freehand shapes
spdc_check_for_and_apply_waiting_LPE(dc, item, c);
-
- if(previous_shape_type != 5) dc->selection->set(repr);
+ if(previous_shape_type == -1 || previous_shape_type == 5 || previous_shape_type == 6){
+ return;
+ }
+ if(previous_shape_type != 7){
+ dc->selection->set(repr);
+ }
+
Inkscape::GC::release(repr);
- if(previous_shape_type != 5) item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
- if(previous_shape_type != 5) item->doWriteTransform(item->getRepr(), item->transform, NULL, true);
- if(previous_shape_type != 5) item->updateRepr();
+ item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
+ item->updateRepr();
+ item->doWriteTransform(item->getRepr(), item->transform, NULL, true);
}
DocumentUndo::done(doc, SP_IS_PEN_CONTEXT(dc)? SP_VERB_CONTEXT_PEN : SP_VERB_CONTEXT_PENCIL,
@@ -740,7 +801,6 @@ SPDrawAnchor *spdc_test_inside(FreehandBase *dc, Geom::Point p)
active = na;
}
}
-
return active;
}
diff --git a/src/ui/tools/freehand-base.h b/src/ui/tools/freehand-base.h
index 5a4b91800..6b4265215 100644
--- a/src/ui/tools/freehand-base.h
+++ b/src/ui/tools/freehand-base.h
@@ -55,6 +55,7 @@ public:
guint32 red_color;
guint32 blue_color;
guint32 green_color;
+ guint32 highlight_color;
// Red
SPCanvasItem *red_bpath;
@@ -75,12 +76,17 @@ public:
GSList *white_curves;
GSList *white_anchors;
+ //ALternative curve to use on continuing exisiting curve in case of bspline or spirolive
+ //because usigh anchor curves give memory and random bugs, - and obscure code- in some plataform reported by su_v in mac
+ SPCurve *overwriteCurve;
+
// Start anchor
SPDrawAnchor *sa;
// End anchor
SPDrawAnchor *ea;
+
/* type of the LPE that is to be applied automatically to a finished path (if any) */
Inkscape::LivePathEffect::EffectType waiting_LPE_type;
diff --git a/src/ui/tools/gradient-tool.cpp b/src/ui/tools/gradient-tool.cpp
index a0bbfbaf1..9c853917e 100644
--- a/src/ui/tools/gradient-tool.cpp
+++ b/src/ui/tools/gradient-tool.cpp
@@ -51,7 +51,7 @@
using Inkscape::DocumentUndo;
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
@@ -213,17 +213,20 @@ sp_gradient_context_is_over_line (GradientTool *rc, SPItem *item, Geom::Point ev
//Translate mouse point into proper coord system
rc->mousepoint_doc = desktop->w2d(event_p);
- SPCtrlLine* line = SP_CTRLLINE(item);
+ if (SP_IS_CTRLLINE(item)) {
+ SPCtrlLine* line = SP_CTRLLINE(item);
- Geom::LineSegment ls(line->s, line->e);
- Geom::Point nearest = ls.pointAt(ls.nearestPoint(rc->mousepoint_doc));
- double dist_screen = Geom::L2 (rc->mousepoint_doc - nearest) * desktop->current_zoom();
+ Geom::LineSegment ls(line->s, line->e);
+ Geom::Point nearest = ls.pointAt(ls.nearestPoint(rc->mousepoint_doc));
+ double dist_screen = Geom::L2 (rc->mousepoint_doc - nearest) * desktop->current_zoom();
- double tolerance = (double) SP_EVENT_CONTEXT(rc)->tolerance;
+ double tolerance = (double) SP_EVENT_CONTEXT(rc)->tolerance;
- bool close = (dist_screen < tolerance);
+ bool close = (dist_screen < tolerance);
- return close;
+ return close;
+ }
+ return false;
}
static std::vector<Geom::Point>
diff --git a/src/ui/tools/lpe-tool.cpp b/src/ui/tools/lpe-tool.cpp
index 9ab6d7814..1fd1ebf8c 100644
--- a/src/ui/tools/lpe-tool.cpp
+++ b/src/ui/tools/lpe-tool.cpp
@@ -28,7 +28,7 @@
#include "desktop.h"
#include "message-context.h"
#include "preferences.h"
-#include "shape-editor.h"
+#include "ui/shape-editor.h"
#include "selection.h"
#include "desktop-handles.h"
#include "document.h"
@@ -59,7 +59,7 @@ SubtoolEntry lpesubtools[] = {
};
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
@@ -129,8 +129,7 @@ void LpeTool::setup() {
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
if (item) {
- this->shape_editor->set_item(item, SH_NODEPATH);
- this->shape_editor->set_item(item, SH_KNOTHOLDER);
+ this->shape_editor->set_item(item);
}
if (prefs->getBool("/tools/lpetool/selcue")) {
@@ -146,9 +145,9 @@ void sp_lpetool_context_selection_changed(Inkscape::Selection *selection, gpoint
{
LpeTool *lc = SP_LPETOOL_CONTEXT(data);
- lc->shape_editor->unset_item(SH_KNOTHOLDER);
+ lc->shape_editor->unset_item();
SPItem *item = selection->singleItem();
- lc->shape_editor->set_item(item, SH_KNOTHOLDER);
+ lc->shape_editor->set_item(item);
}
void LpeTool::set(const Inkscape::Preferences::Entry& val) {
diff --git a/src/ui/tools/measure-tool.cpp b/src/ui/tools/measure-tool.cpp
index 2c85874bc..6b5cbeccd 100644
--- a/src/ui/tools/measure-tool.cpp
+++ b/src/ui/tools/measure-tool.cpp
@@ -49,7 +49,7 @@ using Inkscape::ControlManager;
using Inkscape::CTLINE_SECONDARY;
using Inkscape::Util::unit_table;
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
@@ -277,21 +277,13 @@ void MeasureTool::finish() {
// return ret;
//}
-static bool GeomPointSortPredicate(const Geom::Point& p1, const Geom::Point& p2)
+static void calculate_intersections(SPDesktop * /*desktop*/, SPItem* item, Geom::PathVector const &lineseg, SPCurve *curve, std::vector<double> &intersections)
{
- if (p1[Geom::Y] == p2[Geom::Y]) {
- return p1[Geom::X] < p2[Geom::X];
- } else {
- return p1[Geom::Y] < p2[Geom::Y];
- }
-}
-static void calculate_intersections(SPDesktop * /*desktop*/, SPItem* item, Geom::PathVector const &lineseg, SPCurve *curve, std::vector<Geom::Point> &intersections)
-{
curve->transform(item->i2doc_affine());
-
// Find all intersections of the control-line with this shape
Geom::CrossingSet cs = Geom::crossings(lineseg, curve->get_pathvector());
+ Geom::delete_duplicates(cs[0]);
// Reconstruct and store the points of intersection
for (Geom::Crossings::const_iterator m = cs[0].begin(); m != cs[0].end(); ++m) {
@@ -304,10 +296,11 @@ static void calculate_intersections(SPDesktop * /*desktop*/, SPItem* item, Geom:
item == doc->getItemAtPoint(desktop->dkey, lineseg[0].pointAt((*m).ta - eps), false, NULL)) ||
((*m).ta + eps < 1 &&
item == doc->getItemAtPoint(desktop->dkey, lineseg[0].pointAt((*m).ta + eps), false, NULL)) ) {
- intersections.push_back(intersection);
+ intersections.push_back((*m).ta);
}
#else
- intersections.push_back(lineseg[0].pointAt((*m).ta));
+ intersections.push_back((*m).ta);
+
#endif
}
}
@@ -441,28 +434,20 @@ bool MeasureTool::root_handler(GdkEvent* event) {
points.push_back(desktop->d2w(start_point + (i / NPOINTS) * (end_point - start_point)));
}
-// TODO: Felipe, why don't you simply iterate over all items, and test whether their bounding boxes intersect
-// with the measurement line, instead of interpolating? E.g. bbox_of_measurement_line.intersects(*bbox_of_item).
-// That's also how the object-snapper works, see _findCandidates() in object-snapper.cpp.
+ // TODO: Felipe, why don't you simply iterate over all items, and test whether their bounding boxes intersect
+ // with the measurement line, instead of interpolating over 800 points? E.g. bbox_of_measurement_line.intersects(*bbox_of_item).
+ // That's also how the object-snapper works, see _findCandidates() in object-snapper.cpp.
+
+ // TODO switch to a different variable name. The single letter 'l' is easy to misread.
//select elements crossed by line segment:
GSList *items = sp_desktop_document(desktop)->getItemsAtPoints(desktop->dkey, points);
- std::vector<Geom::Point> intersections;
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- bool ignore_1st_and_last = prefs->getBool("/tools/measure/ignore_1st_and_last", true);
-
- if (!ignore_1st_and_last) {
- intersections.push_back(desktop->dt2doc(start_point));
- }
-
- std::vector<LabelPlacement> placements;
-
- // TODO switch to a different variable name. The single letter 'l' is easy to misread.
+ std::vector<double> intersection_times;
for (GSList *l = items; l != NULL; l = l->next) {
SPItem *item = static_cast<SPItem*>(l->data);
if (SP_IS_SHAPE(item)) {
- calculate_intersections(desktop, item, lineseg, SP_SHAPE(item)->getCurve(), intersections);
+ calculate_intersections(desktop, item, lineseg, SP_SHAPE(item)->getCurve(), intersection_times);
} else {
if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) {
Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin();
@@ -486,7 +471,7 @@ bool MeasureTool::root_handler(GdkEvent* event) {
curve->transform(item->i2doc_affine());
- calculate_intersections(desktop, item, lineseg, curve, intersections);
+ calculate_intersections(desktop, item, lineseg, curve, intersection_times);
if (iter == te_get_layout(item)->end()) {
break;
@@ -496,13 +481,10 @@ bool MeasureTool::root_handler(GdkEvent* event) {
}
}
- if (!ignore_1st_and_last) {
- intersections.push_back(desktop->dt2doc(end_point));
- }
-
- //sort intersections
- if (intersections.size() > 2) {
- std::sort(intersections.begin(), intersections.end(), GeomPointSortPredicate);
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ if (!prefs->getBool("/tools/measure/ignore_1st_and_last", true)) {
+ intersection_times.push_back(0);
+ intersection_times.push_back(1);
}
Glib::ustring unit_name = prefs->getString("/tools/measure/unit");
@@ -516,6 +498,13 @@ bool MeasureTool::root_handler(GdkEvent* event) {
Geom::Point windowNormal = Geom::unit_vector(Geom::rot90(desktop->d2w(end_point - start_point)));
Geom::Point normal = desktop->w2d(windowNormal);
+ std::vector<Geom::Point> intersections;
+ std::sort(intersection_times.begin(), intersection_times.end());
+ for (std::vector<double>::iterator iter_t = intersection_times.begin(); iter_t != intersection_times.end(); iter_t++) {
+ intersections.push_back(lineseg[0].pointAt(*iter_t));
+ }
+
+ std::vector<LabelPlacement> placements;
for (size_t idx = 1; idx < intersections.size(); ++idx) {
LabelPlacement placement;
placement.lengthVal = (intersections[idx] - intersections[idx - 1]).length();
diff --git a/src/ui/tools/mesh-tool.cpp b/src/ui/tools/mesh-tool.cpp
index 7d6d3bc23..8a1fb7c72 100644
--- a/src/ui/tools/mesh-tool.cpp
+++ b/src/ui/tools/mesh-tool.cpp
@@ -53,7 +53,7 @@
using Inkscape::DocumentUndo;
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp
index b1e11bd66..838c2a884 100644
--- a/src/ui/tools/node-tool.cpp
+++ b/src/ui/tools/node-tool.cpp
@@ -19,10 +19,13 @@
#include "display/curve.h"
#include "display/sp-canvas.h"
#include "document.h"
+#include "live_effects/effect.h"
#include "live_effects/lpeobject.h"
#include "message-context.h"
#include "selection.h"
-#include "shape-editor.h" // temporary!
+#include "ui/shape-editor.h" // temporary!
+#include "live_effects/effect.h"
+#include "display/curve.h"
#include "sp-clippath.h"
#include "sp-item-group.h"
#include "sp-mask.h"
@@ -104,7 +107,7 @@
using Inkscape::ControlManager;
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
@@ -166,6 +169,13 @@ NodeTool::~NodeTool() {
if (this->flash_tempitem) {
this->desktop->remove_temporary_canvasitem(this->flash_tempitem);
}
+ if (this->helperpath_tmpitem) {
+ this->desktop->remove_temporary_canvasitem(this->helperpath_tmpitem);
+ }
+
+ if (this->helperpath_tmpitem) {
+ this->desktop->remove_temporary_canvasitem(this->helperpath_tmpitem);
+ }
this->_selection_changed_connection.disconnect();
//this->_selection_modified_connection.disconnect();
@@ -235,7 +245,7 @@ void NodeTool::setup() {
)
);
- this->_selected_nodes->signal_point_changed.connect(
+ this->_selected_nodes->signal_selection_changed.connect(
// Hide both signal parameters and bind the function parameter to 0
// sigc::signal<void, SelectableControlPoint *, bool>
// <=>
@@ -246,12 +256,14 @@ void NodeTool::setup() {
)))
);
+ this->helperpath_tmpitem = 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;
+ this->helperpath_tmpitem = NULL;
// read prefs before adding items to selection to prevent momentarily showing the outline
sp_event_context_read(this, "show_handles");
@@ -278,6 +290,50 @@ void NodeTool::setup() {
}
this->desktop->emitToolSubselectionChanged(NULL); // sets the coord entry fields to inactive
+ this->update_helperpath();
+}
+
+// show helper paths of the applied LPE, if any
+void NodeTool::update_helperpath () {
+ Inkscape::Selection *selection = sp_desktop_selection (this->desktop);
+
+ if (this->helperpath_tmpitem) {
+ this->desktop->remove_temporary_canvasitem(this->helperpath_tmpitem);
+ this->helperpath_tmpitem = NULL;
+ }
+
+ if (SP_IS_LPE_ITEM(selection->singleItem())) {
+ Inkscape::LivePathEffect::Effect *lpe = SP_LPE_ITEM(selection->singleItem())->getCurrentLPE();
+ if (lpe && lpe->isVisible()/* && lpe->showOrigPath()*/) {
+ Inkscape::UI::ControlPointSelection::Set &selectionNodes = _selected_nodes->allPoints();
+ std::vector<Geom::Point> selectedNodesPositions;
+ for (Inkscape::UI::ControlPointSelection::Set::iterator i = selectionNodes.begin(); i != selectionNodes.end(); ++i) {
+ if ((*i)->selected()) {
+ Inkscape::UI::Node *n = dynamic_cast<Inkscape::UI::Node *>(*i);
+ selectedNodesPositions.push_back(n->position());
+ }
+ }
+ lpe->setSelectedNodePoints(selectedNodesPositions);
+ lpe->setCurrentZoom(this->desktop->current_zoom());
+ SPCurve *c = new SPCurve();
+ SPCurve *cc = new SPCurve();
+ std::vector<Geom::PathVector> cs = lpe->getCanvasIndicators(SP_LPE_ITEM(selection->singleItem()));
+ for (std::vector<Geom::PathVector>::iterator p = cs.begin(); p != cs.end(); ++p) {
+ cc->set_pathvector(*p);
+ c->append(cc, false);
+ cc->reset();
+ }
+ if (!c->is_empty()) {
+ SPCanvasItem *helperpath = sp_canvas_bpath_new(sp_desktop_tempgroup(this->desktop), c);
+ sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(helperpath), 0x0000ff9A, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
+ sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(helperpath), 0, SP_WIND_RULE_NONZERO);
+ sp_canvas_item_affine_absolute(helperpath, selection->singleItem()->i2dt_affine());
+ this->helperpath_tmpitem = this->desktop->add_temporary_canvasitem(helperpath, 0);
+ }
+ c->unref();
+ cc->unref();
+ }
+ }
}
void NodeTool::set(const Inkscape::Preferences::Entry& value) {
@@ -392,11 +448,11 @@ void NodeTool::selection_changed(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)) &&
+ if ((SP_IS_SHAPE(r.item) || SP_IS_TEXT(r.item) || SP_IS_GROUP(r.item) || SP_IS_OBJECTGROUP(r.item)) &&
this->_shape_editors.find(r.item) == this->_shape_editors.end())
{
ShapeEditor *si = new ShapeEditor(this->desktop);
- si->set_item(r.item, SH_KNOTHOLDER);
+ si->set_item(r.item);
this->_shape_editors.insert(const_cast<SPItem*&>(r.item), si);
}
}
@@ -416,7 +472,7 @@ bool NodeTool::root_handler(GdkEvent* event) {
Inkscape::Selection *selection = desktop->selection;
static Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-
+
if (this->_multipath->event(this, event)) {
return true;
}
@@ -432,7 +488,9 @@ bool NodeTool::root_handler(GdkEvent* event) {
switch (event->type)
{
case GDK_MOTION_NOTIFY: {
+ this->update_helperpath();
combine_motion_events(desktop->canvas, event->motion, 0);
+ this->update_helperpath();
SPItem *over_item = sp_event_context_find_item (desktop, event_point(event->button),
FALSE, TRUE);
@@ -441,7 +499,6 @@ bool NodeTool::root_handler(GdkEvent* event) {
//ink_node_tool_update_tip(nt, event);
this->update_tip(event);
}
-
// create pathflash outline
if (prefs->getBool("/tools/nodes/pathflash_enabled")) {
if (over_item == this->flashed_item) {
@@ -473,7 +530,8 @@ bool NodeTool::root_handler(GdkEvent* event) {
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,
+ //prefs->getInt("/tools/nodes/highlight_color", 0xff0000ff), 1.0,
+ over_item->highlight_color(), 1.0,
SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(flash), 0, SP_WIND_RULE_NONZERO);
diff --git a/src/ui/tools/node-tool.h b/src/ui/tools/node-tool.h
index 4d15ab70e..ab72f3632 100644
--- a/src/ui/tools/node-tool.h
+++ b/src/ui/tools/node-tool.h
@@ -15,6 +15,9 @@
#include <glib.h>
#include "ui/tools/tool-base.h"
+// we need it to call it from Live Effect
+#include "selection.h"
+
namespace Inkscape {
namespace Display {
class TemporaryItem;
@@ -51,6 +54,7 @@ public:
static const std::string prefsPath;
virtual void setup();
+ virtual void update_helperpath();
virtual void set(const Inkscape::Preferences::Entry& val);
virtual bool root_handler(GdkEvent* event);
@@ -62,6 +66,7 @@ private:
sigc::connection _sizeUpdatedConn;
SPItem *flashed_item;
+ Inkscape::Display::TemporaryItem *helperpath_tmpitem;
Inkscape::Display::TemporaryItem *flash_tempitem;
Inkscape::UI::Selector* _selector;
Inkscape::UI::PathSharedData* _path_data;
diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp
index 09c0a2a4f..92937a135 100644
--- a/src/ui/tools/pen-tool.cpp
+++ b/src/ui/tools/pen-tool.cpp
@@ -26,7 +26,7 @@
#include "desktop-handles.h"
#include "selection.h"
#include "selection-chemistry.h"
-#include "draw-anchor.h"
+#include "ui/draw-anchor.h"
#include "message-stack.h"
#include "message-context.h"
#include "preferences.h"
@@ -40,9 +40,40 @@
#include <glibmm/i18n.h>
#include "macros.h"
#include "context-fns.h"
-#include "tools-switch.h"
+#include "ui/tools-switch.h"
#include "ui/control-manager.h"
-#include "tool-factory.h"
+// we include the necessary files for BSpline & Spiro
+#include "live_effects/effect.h"
+#include "live_effects/lpeobject.h"
+#include "live_effects/lpeobject-reference.h"
+#include "live_effects/parameter/path.h"
+#define INKSCAPE_LPE_SPIRO_C
+#include "live_effects/lpe-spiro.h"
+
+
+#include <typeinfo>
+#include <2geom/pathvector.h>
+#include <2geom/affine.h>
+#include <2geom/bezier-curve.h>
+#include <2geom/hvlinesegment.h>
+#include "helper/geom-nodetype.h"
+#include "helper/geom-curves.h"
+
+// For handling un-continuous paths:
+#include "message-stack.h"
+#include "inkscape.h"
+#include "desktop.h"
+
+#include "live_effects/spiro.h"
+
+#define INKSCAPE_LPE_BSPLINE_C
+#include "live_effects/lpe-bspline.h"
+#include <2geom/nearest-point.h>
+
+#include "ui/tool-factory.h"
+
+#include "live_effects/effect.h"
+
using Inkscape::ControlManager;
@@ -53,17 +84,17 @@ namespace Tools {
static Geom::Point pen_drag_origin_w(0, 0);
static bool pen_within_tolerance = false;
static int pen_last_paraxial_dir = 0; // last used direction in horizontal/vertical mode; 0 = horizontal, 1 = vertical
-
+const double handleCubicGap = 0.01;
namespace {
- ToolBase* createPenContext() {
- return new PenTool();
- }
+ ToolBase* createPenContext() {
+ return new PenTool();
+ }
- bool penContextRegistered = ToolFactory::instance().registerObject("/tools/freehand/pen", createPenContext);
+ bool penContextRegistered = ToolFactory::instance().registerObject("/tools/freehand/pen", createPenContext);
}
const std::string& PenTool::getPrefsPath() {
- return PenTool::prefsPath;
+ return PenTool::prefsPath;
}
const std::string PenTool::prefsPath = "/tools/freehand/pen";
@@ -135,8 +166,22 @@ PenTool::~PenTool() {
void PenTool::setPolylineMode() {
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
guint mode = prefs->getInt("/tools/freehand/pen/freehand-mode", 0);
- this->polylines_only = (mode == 2 || mode == 3);
- this->polylines_paraxial = (mode == 3);
+ // change the nodes to make space for bspline mode
+ this->polylines_only = (mode == 3 || mode == 4);
+ this->polylines_paraxial = (mode == 4);
+ //we call the function which defines the Spiro modes and the BSpline
+ //todo: merge to one function only
+ this->_pen_context_set_mode(mode);
+}
+
+/*
+*.Set the mode of draw spiro, and bsplines
+*/
+void PenTool::_pen_context_set_mode(guint mode) {
+ // define the nodes
+ this->spiro = (mode == 1);
+ this->bspline = (mode == 2);
+ this->_bspline_spiro_color();
}
/**
@@ -144,7 +189,6 @@ void PenTool::setPolylineMode() {
*/
void PenTool::setup() {
FreehandBase::setup();
-
ControlManager &mgr = ControlManager::getManager();
// Pen indicators
@@ -195,7 +239,9 @@ void PenTool::finish() {
sp_event_context_discard_delayed_snap_event(this);
if (this->npoints != 0) {
- this->_cancel();
+ // switching context - finish path
+ this->ea = NULL; // unset end anchor if set (otherwise crashes)
+ this->_finish(false);
}
FreehandBase::finish();
@@ -277,7 +323,7 @@ bool PenTool::item_handler(SPItem* item, GdkEvent* event) {
}
if (!ret) {
- ret = FreehandBase::item_handler(item, event);
+ ret = FreehandBase::item_handler(item, event);
}
return ret;
@@ -315,7 +361,7 @@ bool PenTool::root_handler(GdkEvent* event) {
}
if (!ret) {
- ret = FreehandBase::root_handler(event);
+ ret = FreehandBase::root_handler(event);
}
return ret;
@@ -332,9 +378,20 @@ bool PenTool::_handleButtonPress(GdkEventButton const &bevent) {
Geom::Point const event_w(bevent.x, bevent.y);
Geom::Point event_dt(desktop->w2d(event_w));
-
+ //Test whether we hit any anchor.
+ SPDrawAnchor * const anchor = spdc_test_inside(this, event_w);
+
+ //with this we avoid creating a new point over the existing one
+ if(bevent.button != 3 && (this->spiro || this->bspline) && this->npoints > 0 && this->p[0] == this->p[3]){
+ if( anchor && anchor == this->sa && this->green_curve->is_empty()){
+ //remove the following line to avoid having one node on top of another
+ _finishSegment(event_dt, bevent.state);
+ _finish( false);
+ return true;
+ }
+ return false;
+ }
bool ret = false;
-
if (bevent.button == 1 && !this->space_panning
// make sure this is not the last click for a waiting LPE (otherwise we want to finish the path)
&& this->expecting_clicks_for_LPE != 1) {
@@ -355,10 +412,8 @@ bool PenTool::_handleButtonPress(GdkEventButton const &bevent) {
pen_drag_origin_w = event_w;
pen_within_tolerance = true;
- // Test whether we hit any anchor.
- SPDrawAnchor * const anchor = spdc_test_inside(this, event_w);
-
switch (this->mode) {
+
case PenTool::MODE_CLICK:
// In click mode we add point on release
switch (this->state) {
@@ -380,7 +435,7 @@ bool PenTool::_handleButtonPress(GdkEventButton const &bevent) {
// This is allowed, if we just canceled curve
case PenTool::POINT:
if (this->npoints == 0) {
-
+ this->_bspline_spiro_color();
Geom::Point p;
if ((bevent.state & GDK_CONTROL_MASK) && (this->polylines_only || this->polylines_paraxial)) {
p = event_dt;
@@ -399,8 +454,12 @@ bool PenTool::_handleButtonPress(GdkEventButton const &bevent) {
// distinction so that the case of a waiting LPE is treated separately
// Set start anchor
+
this->sa = anchor;
- if (anchor && !this->hasWaitingLPE()) {
+ if(anchor){
+ this->_bspline_spiro_start_anchor(bevent.state & GDK_SHIFT_MASK);
+ }
+ if (anchor && (!this->hasWaitingLPE()|| this->bspline || this->spiro)) {
// Adjust point to anchor if needed; if we have a waiting LPE, we need
// a fresh path to be created so don't continue an existing one
p = anchor->dp;
@@ -422,7 +481,7 @@ bool PenTool::_handleButtonPress(GdkEventButton const &bevent) {
// Create green anchor
p = event_dt;
this->_endpointSnap(p, bevent.state);
- this->green_anchor = sp_draw_anchor_new(this, this->green_curve, TRUE, p);
+ this->green_anchor = sp_draw_anchor_new(this, this->green_curve, true, p);
}
this->_setInitialPoint(p);
} else {
@@ -439,7 +498,7 @@ bool PenTool::_handleButtonPress(GdkEventButton const &bevent) {
if (this->green_anchor && this->green_anchor->active) {
// we clicked on the current curve start, so close it even if
// we drag a handle away from it
- this->green_closed = TRUE;
+ this->green_closed = true;
}
ret = true;
break;
@@ -450,8 +509,8 @@ bool PenTool::_handleButtonPress(GdkEventButton const &bevent) {
this->_setSubsequentPoint(p, true);
}
}
-
- this->state = this->polylines_only ? PenTool::POINT : PenTool::CONTROL;
+ // avoid the creation of a control point so a node is created in the release event
+ this->state = (this->spiro || this->bspline || this->polylines_only) ? PenTool::POINT : PenTool::CONTROL;
ret = true;
break;
case PenTool::CONTROL:
@@ -481,6 +540,7 @@ bool PenTool::_handleButtonPress(GdkEventButton const &bevent) {
ret = true;
} else if (bevent.button == 3 && this->npoints != 0) {
// right click - finish path
+ this->ea = NULL; // unset end anchor if set (otherwise crashes)
this->_finish(false);
ret = true;
}
@@ -510,9 +570,11 @@ bool PenTool::_handleMotionNotify(GdkEventMotion const &mevent) {
Geom::Point const event_w(mevent.x, mevent.y);
+ //we take out the function the const "tolerance" because we need it later
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gint const tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
+
if (pen_within_tolerance) {
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- gint const tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
if ( Geom::LInfty( event_w - pen_drag_origin_w ) < tolerance ) {
return false; // Do not drag if we're within tolerance from origin.
}
@@ -536,7 +598,7 @@ bool PenTool::_handleMotionNotify(GdkEventMotion const &mevent) {
// Only set point, if we are already appending
this->_endpointSnap(p, mevent.state);
this->_setSubsequentPoint(p, true);
- ret = TRUE;
+ ret = true;
} else if (!this->sp_event_context_knot_mouseover()) {
SnapManager &m = desktop->namedview->snap_manager;
m.setup(desktop);
@@ -572,7 +634,11 @@ bool PenTool::_handleMotionNotify(GdkEventMotion const &mevent) {
}
if (anchor && !this->anchor_statusbar) {
- this->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>click and drag</b> to close and finish the path."));
+ if(!this->spiro && !this->bspline){
+ this->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>click and drag</b> to close and finish the path."));
+ }else{
+ this->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>click and drag</b> to close and finish the path. Shift+Click make a cusp node"));
+ }
this->anchor_statusbar = true;
} else if (!anchor && this->anchor_statusbar) {
this->message_context->clear();
@@ -582,11 +648,16 @@ bool PenTool::_handleMotionNotify(GdkEventMotion const &mevent) {
ret = true;
} else {
if (anchor && !this->anchor_statusbar) {
- this->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>click and drag</b> to continue the path from this point."));
+ if(!this->spiro && !this->bspline){
+ this->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>click and drag</b> to continue the path from this point."));
+ }else{
+ this->message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Click</b> or <b>click and drag</b> to continue the path from this point. Shift+Click make a cusp node"));
+ }
this->anchor_statusbar = true;
} else if (!anchor && this->anchor_statusbar) {
this->message_context->clear();
this->anchor_statusbar = false;
+
}
if (!this->sp_event_context_knot_mouseover()) {
SnapManager &m = desktop->namedview->snap_manager;
@@ -601,6 +672,7 @@ bool PenTool::_handleMotionNotify(GdkEventMotion const &mevent) {
// Placing controls is last operation in CLOSE state
// snap the handle
+
this->_endpointSnapHandle(p, mevent.state);
if (!this->polylines_only) {
@@ -608,6 +680,7 @@ bool PenTool::_handleMotionNotify(GdkEventMotion const &mevent) {
} else {
this->_setCtrl(this->p[1], mevent.state);
}
+
gobble_motion_events(GDK_BUTTON1_MASK);
ret = true;
break;
@@ -627,6 +700,16 @@ bool PenTool::_handleMotionNotify(GdkEventMotion const &mevent) {
default:
break;
}
+ // calls the function "bspline_spiro_motion" when the mouse starts or stops moving
+ if(this->bspline){
+ this->_bspline_spiro_motion(mevent.state & GDK_SHIFT_MASK);
+ }else{
+ if ( Geom::LInfty( event_w - pen_drag_origin_w ) > (tolerance/2) || mevent.time == 0) {
+ this->_bspline_spiro_motion(mevent.state & GDK_SHIFT_MASK);
+ pen_drag_origin_w = event_w;
+ }
+ }
+
return ret;
}
@@ -648,7 +731,12 @@ bool PenTool::_handleButtonRelease(GdkEventButton const &revent) {
Geom::Point p = this->desktop->w2d(event_w);
// Test whether we hit any anchor.
+
SPDrawAnchor *anchor = spdc_test_inside(this, event_w);
+ // if we try to create a node in the same place as another node, we skip
+ if((!anchor || anchor == this->sa) && (this->spiro || this->bspline) && this->npoints > 0 && this->p[0] == this->p[3]){
+ return true;
+ }
switch (this->mode) {
case PenTool::MODE_CLICK:
@@ -656,10 +744,17 @@ bool PenTool::_handleButtonRelease(GdkEventButton const &revent) {
case PenTool::POINT:
if ( this->npoints == 0 ) {
// Start new thread only with button release
+ this->_bspline_spiro_color();
if (anchor) {
p = anchor->dp;
}
this->sa = anchor;
+ // continue the existing curve
+ if (anchor) {
+ if(this->bspline || this->spiro){
+ this->_bspline_spiro_start_anchor(revent.state & GDK_SHIFT_MASK);;
+ }
+ }
this->_setInitialPoint(p);
} else {
// Set end anchor here
@@ -684,6 +779,10 @@ bool PenTool::_handleButtonRelease(GdkEventButton const &revent) {
this->_endpointSnap(p, revent.state);
}
this->_finishSegment(p, revent.state);
+ // hude the guide of the penultimate node when closing the curve
+ if(this->spiro){
+ sp_canvas_item_hide(this->c1);
+ }
this->_finish(true);
this->state = PenTool::POINT;
ret = true;
@@ -707,6 +806,10 @@ bool PenTool::_handleButtonRelease(GdkEventButton const &revent) {
case PenTool::CLOSE:
this->_endpointSnap(p, revent.state);
this->_finishSegment(p, revent.state);
+ // hide the penultimate node guide when closing the curve
+ if(this->spiro){
+ sp_canvas_item_hide(this->c1);
+ }
if (this->green_closed) {
// finishing at the start anchor, close curve
this->_finish(true);
@@ -727,7 +830,6 @@ bool PenTool::_handleButtonRelease(GdkEventButton const &revent) {
default:
break;
}
-
if (this->grab) {
// Release grab now
sp_canvas_item_ungrab(this->grab, revent.time);
@@ -736,7 +838,7 @@ bool PenTool::_handleButtonRelease(GdkEventButton const &revent) {
ret = true;
- this->green_closed = FALSE;
+ this->green_closed = false;
}
// TODO: can we be sure that the path was created correctly?
@@ -764,7 +866,7 @@ bool PenTool::_handle2ButtonPress(GdkEventButton const &bevent) {
bool ret = false;
// only end on LMB double click. Otherwise horizontal scrolling causes ending of the path
if (this->npoints != 0 && bevent.button == 1) {
- this->_finish(FALSE);
+ this->_finish(false);
ret = true;
}
return ret;
@@ -785,7 +887,6 @@ void PenTool::_redrawAll() {
this->green_bpaths = g_slist_prepend(this->green_bpaths, cshape);
}
-
if (this->green_anchor)
SP_CTRL(this->green_anchor->ctrl)->moveto(this->green_anchor->dp);
@@ -795,7 +896,8 @@ void PenTool::_redrawAll() {
sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(this->red_bpath), this->red_curve);
// handles
- if (this->p[0] != this->p[1]) {
+ // hide the handlers in bspline and spiro modes
+ if (this->p[0] != this->p[1] && !this->spiro && !this->bspline) {
SP_CTRL(this->c1)->moveto(this->p[1]);
this->cl1->setCoords(this->p[0], this->p[1]);
sp_canvas_item_show(this->c1);
@@ -808,8 +910,9 @@ void PenTool::_redrawAll() {
Geom::Curve const * last_seg = this->green_curve->last_segment();
if (last_seg) {
Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const *>( last_seg );
+ // hide the handlers in bspline and spiro modes
if ( cubic &&
- (*cubic)[2] != this->p[0] )
+ (*cubic)[2] != this->p[0] && !this->spiro && !this->bspline )
{
Geom::Point p2 = (*cubic)[2];
SP_CTRL(this->c0)->moveto(p2);
@@ -821,6 +924,10 @@ void PenTool::_redrawAll() {
sp_canvas_item_hide(this->cl0);
}
}
+
+ // simply redraw the spiro. because its a redrawing, we don't call the global function,
+ // but we call the redrawing at the ending.
+ this->_bspline_spiro_build();
}
void PenTool::_lastpointMove(gdouble x, gdouble y) {
@@ -838,6 +945,7 @@ void PenTool::_lastpointMove(gdouble x, gdouble y) {
}
// red
+
this->p[0] += Geom::Point(x, y);
this->p[1] += Geom::Point(x, y);
this->_redrawAll();
@@ -848,25 +956,105 @@ void PenTool::_lastpointMoveScreen(gdouble x, gdouble y) {
}
void PenTool::_lastpointToCurve() {
- if (this->npoints != 5)
+ // avoid that if the "red_curve" contains only two points ( rect ), it doesn't stop here.
+ if (this->npoints != 5 && !this->spiro && !this->bspline)
return;
- Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const *>( this->green_curve->last_segment() );
- if ( cubic ) {
- this->p[1] = this->p[0] + (Geom::Point)( (*cubic)[3] - (*cubic)[2] );
- } else {
- this->p[1] = this->p[0] + (1./3)*(this->p[3] - this->p[0]);
+ this->p[1] = this->red_curve->last_segment()->initialPoint() + (1./3.)*(this->red_curve->last_segment()->finalPoint() - this->red_curve->last_segment()->initialPoint());
+ //modificate the last segment of the green curve so it creates the type of node we need
+ if (this->spiro||this->bspline) {
+ if (!this->green_curve->is_empty()) {
+ Geom::Point A(0,0);
+ Geom::Point B(0,0);
+ Geom::Point C(0,0);
+ Geom::Point D(0,0);
+ Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>( this->green_curve->last_segment() );
+ //We obtain the last segment 4 points in the previous curve
+ if ( cubic ){
+ A = (*cubic)[0];
+ B = (*cubic)[1];
+ if (this->spiro) {
+ C = this->p[0] + (this->p[0] - this->p[1]);
+ } else {
+ C = this->green_curve->last_segment()->finalPoint() + (1./3.)*(this->green_curve->last_segment()->initialPoint() - this->green_curve->last_segment()->finalPoint());
+ }
+ D = (*cubic)[3];
+ } else {
+ A = this->green_curve->last_segment()->initialPoint();
+ B = this->green_curve->last_segment()->initialPoint();
+ if (this->spiro) {
+ C = this->p[0] + (this->p[0] - this->p[1]);
+ } else {
+ C = this->green_curve->last_segment()->finalPoint() + (1./3.)*(this->green_curve->last_segment()->initialPoint() - this->green_curve->last_segment()->finalPoint());
+ }
+ D = this->green_curve->last_segment()->finalPoint();
+ }
+ SPCurve *previous = new SPCurve();
+ previous->moveto(A);
+ previous->curveto(B, C, D);
+ if ( this->green_curve->get_segment_count() == 1) {
+ this->green_curve = previous;
+ } else {
+ //we eliminate the last segment
+ this->green_curve->backspace();
+ //and we add it again with the recreation
+ this->green_curve->append_continuous(previous, 0.0625);
+ }
+ }
+ //if the last node is an union with another curve
+ if (this->green_curve->is_empty() && this->sa && !this->sa->curve->is_empty()) {
+ this->_bspline_spiro_start_anchor(false);
+ }
}
this->_redrawAll();
}
+
void PenTool::_lastpointToLine() {
- if (this->npoints != 5)
+ // avoid that if the "red_curve" contains only two points ( rect) it doesn't stop here.
+ if (this->npoints != 5 && !this->bspline)
return;
+ // modify the last segment of the green curve so the type of node we want is created.
+ if(this->spiro || this->bspline){
+ if(!this->green_curve->is_empty()){
+ Geom::Point A(0,0);
+ Geom::Point B(0,0);
+ Geom::Point C(0,0);
+ Geom::Point D(0,0);
+ SPCurve * previous = new SPCurve();
+ Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const *>( this->green_curve->last_segment() );
+ if ( cubic ) {
+ A = this->green_curve->last_segment()->initialPoint();
+ B = (*cubic)[1];
+ C = this->green_curve->last_segment()->finalPoint();
+ D = C;
+ } else {
+ //We obtain the last segment 4 points in the previous curve
+ A = this->green_curve->last_segment()->initialPoint();
+ B = A;
+ C = this->green_curve->last_segment()->finalPoint();
+ D = C;
+ }
+ previous->moveto(A);
+ previous->curveto(B, C, D);
+ if( this->green_curve->get_segment_count() == 1){
+ this->green_curve = previous;
+ }else{
+ //we eliminate the last segment
+ this->green_curve->backspace();
+ //and we add it again with the recreation
+ this->green_curve->append_continuous(previous, 0.0625);
+ }
+ }
+ // if the last node is an union with another curve
+ if(this->green_curve->is_empty() && this->sa && !this->sa->curve->is_empty()){
+ this->_bspline_spiro_start_anchor(true);
+ }
+ }
+
this->p[1] = this->p[0];
-
this->_redrawAll();
}
@@ -971,7 +1159,7 @@ bool PenTool::_handleKeyPress(GdkEvent *event) {
case GDK_KEY_p:
if (MOD__SHIFT_ONLY(event)) {
sp_pen_context_wait_for_LPE_mouse_clicks(pc, Inkscape::LivePathEffect::PARALLEL, 2);
- ret = TRUE;
+ ret = true;
}
break;
@@ -979,7 +1167,7 @@ bool PenTool::_handleKeyPress(GdkEvent *event) {
case GDK_KEY_c:
if (MOD__SHIFT_ONLY(event)) {
sp_pen_context_wait_for_LPE_mouse_clicks(pc, Inkscape::LivePathEffect::CIRCLE_3PTS, 3);
- ret = TRUE;
+ ret = true;
}
break;
@@ -987,7 +1175,7 @@ bool PenTool::_handleKeyPress(GdkEvent *event) {
case GDK_KEY_b:
if (MOD__SHIFT_ONLY(event)) {
sp_pen_context_wait_for_LPE_mouse_clicks(pc, Inkscape::LivePathEffect::PERP_BISECTOR, 2);
- ret = TRUE;
+ ret = true;
}
break;
@@ -995,7 +1183,7 @@ bool PenTool::_handleKeyPress(GdkEvent *event) {
case GDK_KEY_a:
if (MOD__SHIFT_ONLY(event)) {
sp_pen_context_wait_for_LPE_mouse_clicks(pc, Inkscape::LivePathEffect::ANGLE_BISECTOR, 3);
- ret = TRUE;
+ ret = true;
}
break;
*/
@@ -1018,6 +1206,7 @@ bool PenTool::_handleKeyPress(GdkEvent *event) {
case GDK_KEY_Return:
case GDK_KEY_KP_Enter:
if (this->npoints != 0) {
+ this->ea = NULL; // unset end anchor if set (otherwise crashes)
this->_finish(false);
ret = true;
}
@@ -1059,8 +1248,9 @@ bool PenTool::_handleKeyPress(GdkEvent *event) {
this->red_curve->reset();
// Destroy topmost green bpath
if (this->green_bpaths) {
- if (this->green_bpaths->data)
+ if (this->green_bpaths->data) {
sp_canvas_item_destroy(SP_CANVAS_ITEM(this->green_bpaths->data));
+ }
this->green_bpaths = g_slist_remove(this->green_bpaths, this->green_bpaths->data);
}
// Get last segment
@@ -1068,19 +1258,49 @@ bool PenTool::_handleKeyPress(GdkEvent *event) {
g_warning("pen_handle_key_press, case GDK_KP_Delete: Green curve is empty");
break;
}
- // The code below assumes that pc->green_curve has only ONE path !
+ // The code below assumes that this->green_curve has only ONE path !
Geom::Curve const * crv = this->green_curve->last_segment();
this->p[0] = crv->initialPoint();
if ( Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const *>(crv)) {
this->p[1] = (*cubic)[1];
+
} else {
this->p[1] = this->p[0];
}
- Geom::Point const pt(( this->npoints < 4
- ? (Geom::Point)(crv->finalPoint())
- : this->p[3] ));
+
+ // asign the value in a third of the distance of the last segment.
+ if (this->bspline){
+ this->p[1] = this->p[0] + (1./3)*(this->p[3] - this->p[0]);
+ }
+
+ Geom::Point const pt( (this->npoints < 4) ? crv->finalPoint() : this->p[3] );
+
this->npoints = 2;
- this->green_curve->backspace();
+ // delete the last segment of the green curve
+ if (this->green_curve->get_segment_count() == 1) {
+ this->npoints = 5;
+ if (this->green_bpaths) {
+ if (this->green_bpaths->data) {
+ sp_canvas_item_destroy(SP_CANVAS_ITEM(this->green_bpaths->data));
+ }
+ this->green_bpaths = g_slist_remove(this->green_bpaths, this->green_bpaths->data);
+ }
+ this->green_curve->reset();
+ } else {
+ this->green_curve->backspace();
+ }
+
+ // assign the value of this->p[1] to the oposite of the green line last segment
+ if (this->spiro){
+ Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(this->green_curve->last_segment());
+ if ( cubic ) {
+ this->p[1] = (*cubic)[3] + (*cubic)[3] - (*cubic)[2];
+ SP_CTRL(this->c1)->moveto(this->p[0]);
+ } else {
+ this->p[1] = this->p[0];
+ }
+ }
+
sp_canvas_item_hide(this->c0);
sp_canvas_item_hide(this->c1);
sp_canvas_item_hide(this->cl0);
@@ -1088,6 +1308,9 @@ bool PenTool::_handleKeyPress(GdkEvent *event) {
this->state = PenTool::POINT;
this->_setSubsequentPoint(pt, true);
pen_last_paraxial_dir = !pen_last_paraxial_dir;
+
+ //redraw
+ this->_bspline_spiro_build();
ret = true;
}
break;
@@ -1154,11 +1377,686 @@ void PenTool::_setAngleDistanceStatusMessage(Geom::Point const p, int pc_point_t
}
this->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, message, angle, dist->str);
- g_string_free(dist, FALSE);
+ g_string_free(dist, false);
+}
+
+// this function changes the colors red, green and blue making them transparent or not, depending on if spiro is being used.
+void PenTool::_bspline_spiro_color()
+{
+ static Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ if(this->spiro){
+ this->red_color = 0xff00000;
+ this->green_color = 0x00ff000;
+ }else if(this->bspline){
+ this->highlight_color = SP_ITEM(this->desktop->currentLayer())->highlight_color();
+ if((unsigned int)prefs->getInt("/tools/nodes/highlight_color", 0xff0000ff) == this->highlight_color){
+ this->green_color = 0xff00007f;
+ this->red_color = 0xff00007f;
+ } else {
+ this->green_color = this->highlight_color;
+ this->red_color = this->highlight_color;
+ }
+ }else{
+ this->highlight_color = SP_ITEM(this->desktop->currentLayer())->highlight_color();
+ this->red_color = 0xff00007f;
+ if((unsigned int)prefs->getInt("/tools/nodes/highlight_color", 0xff0000ff) == this->highlight_color){
+ this->green_color = 0x00ff007f;
+ } else {
+ this->green_color = this->highlight_color;
+ }
+ sp_canvas_item_hide(this->blue_bpath);
+ }
+ //We erase all the "green_bpaths" to recreate them after with the colour
+ //transparency recently modified
+ if (this->green_bpaths) {
+ // remove old piecewise green canvasitems
+ while (this->green_bpaths) {
+ sp_canvas_item_destroy(SP_CANVAS_ITEM(this->green_bpaths->data));
+ this->green_bpaths = g_slist_remove(this->green_bpaths, this->green_bpaths->data);
+ }
+ // one canvas bpath for all of green_curve
+ SPCanvasItem *cshape = sp_canvas_bpath_new(sp_desktop_sketch(this->desktop), this->green_curve);
+ sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(cshape), this->green_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
+ sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(cshape), 0, SP_WIND_RULE_NONZERO);
+ this->green_bpaths = g_slist_prepend(this->green_bpaths, cshape);
+ }
+ sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->red_bpath), this->red_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
+}
+
+
+void PenTool::_bspline_spiro(bool shift)
+{
+ if(!this->spiro && !this->bspline)
+ return;
+
+ shift?this->_bspline_spiro_off():this->_bspline_spiro_on();
+ this->_bspline_spiro_build();
+}
+
+void PenTool::_bspline_spiro_on()
+{
+ if(!this->red_curve->is_empty()){
+ using Geom::X;
+ using Geom::Y;
+ this->npoints = 5;
+ this->p[0] = this->red_curve->first_segment()->initialPoint();
+ this->p[3] = this->red_curve->first_segment()->finalPoint();
+ this->p[2] = this->p[3] + (1./3)*(this->p[0] - this->p[3]);
+ this->p[2] = Geom::Point(this->p[2][X] + handleCubicGap,this->p[2][Y] + handleCubicGap);
+ }
+}
+
+void PenTool::_bspline_spiro_off()
+{
+ if(!this->red_curve->is_empty()){
+ this->npoints = 5;
+ this->p[0] = this->red_curve->first_segment()->initialPoint();
+ this->p[3] = this->red_curve->first_segment()->finalPoint();
+ this->p[2] = this->p[3];
+ }
+}
+
+void PenTool::_bspline_spiro_start_anchor(bool shift)
+{
+ if(this->sa->curve->is_empty()){
+ return;
+ }
+
+ LivePathEffect::LPEBSpline *lpe_bsp = NULL;
+
+ if (SP_IS_LPE_ITEM(this->white_item) && SP_LPE_ITEM(this->white_item)->hasPathEffect()){
+ Inkscape::LivePathEffect::Effect* thisEffect = SP_LPE_ITEM(this->white_item)->getPathEffectOfType(Inkscape::LivePathEffect::BSPLINE);
+ if(thisEffect){
+ lpe_bsp = dynamic_cast<LivePathEffect::LPEBSpline*>(thisEffect->getLPEObj()->get_lpe());
+ }
+ }
+ if(lpe_bsp){
+ this->bspline = true;
+ }else{
+ this->bspline = false;
+ }
+ LivePathEffect::LPESpiro *lpe_spi = NULL;
+
+ if (SP_IS_LPE_ITEM(this->white_item) && SP_LPE_ITEM(this->white_item)->hasPathEffect()){
+ Inkscape::LivePathEffect::Effect* thisEffect = SP_LPE_ITEM(this->white_item)->getPathEffectOfType(Inkscape::LivePathEffect::SPIRO);
+ if(thisEffect){
+ lpe_spi = dynamic_cast<LivePathEffect::LPESpiro*>(thisEffect->getLPEObj()->get_lpe());
+ }
+ }
+ if(lpe_spi){
+ this->spiro = true;
+ }else{
+ this->spiro = false;
+ }
+ if(!this->spiro && !this->bspline)
+ return;
+
+ if(shift)
+ this->_bspline_spiro_start_anchor_off();
+ else
+ this->_bspline_spiro_start_anchor_on();
+}
+
+void PenTool::_bspline_spiro_start_anchor_on()
+{
+ using Geom::X;
+ using Geom::Y;
+ SPCurve *tmpCurve = new SPCurve();
+ tmpCurve = this->sa->curve->copy();
+ if(this->sa->start)
+ tmpCurve = tmpCurve->create_reverse();
+ Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment());
+ SPCurve *lastSeg = new SPCurve();
+ Geom::Point A = tmpCurve->last_segment()->initialPoint();
+ Geom::Point D = tmpCurve->last_segment()->finalPoint();
+ Geom::Point C = D + (1./3)*(A - D);
+ C = Geom::Point(C[X] + handleCubicGap,C[Y] + handleCubicGap);
+ if(cubic){
+ lastSeg->moveto(A);
+ lastSeg->curveto((*cubic)[1],C,D);
+ }else{
+ lastSeg->moveto(A);
+ lastSeg->curveto(A,C,D);
+ }
+ if( tmpCurve->get_segment_count() == 1){
+ tmpCurve = lastSeg;
+ }else{
+ //we eliminate the last segment
+ tmpCurve->backspace();
+ //and we add it again with the recreation
+ tmpCurve->append_continuous(lastSeg, 0.0625);
+ }
+ if (this->sa->start) {
+ tmpCurve = tmpCurve->create_reverse();
+ }
+ this->overwriteCurve = tmpCurve;
+}
+
+void PenTool::_bspline_spiro_start_anchor_off()
+{
+ SPCurve *tmpCurve = new SPCurve();
+ tmpCurve = this->sa->curve->copy();
+ if(this->sa->start)
+ tmpCurve = tmpCurve->create_reverse();
+ Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment());
+ if(cubic){
+ SPCurve *lastSeg = new SPCurve();
+ lastSeg->moveto((*cubic)[0]);
+ lastSeg->curveto((*cubic)[1],(*cubic)[3],(*cubic)[3]);
+ if( tmpCurve->get_segment_count() == 1){
+ tmpCurve = lastSeg;
+ }else{
+ //we eliminate the last segment
+ tmpCurve->backspace();
+ //and we add it again with the recreation
+ tmpCurve->append_continuous(lastSeg, 0.0625);
+ }
+ }
+ if (this->sa->start) {
+ tmpCurve = tmpCurve->create_reverse();
+ }
+ this->overwriteCurve = tmpCurve;
+}
+
+void PenTool::_bspline_spiro_motion(bool shift){
+ if(!this->spiro && !this->bspline)
+ return;
+
+ using Geom::X;
+ using Geom::Y;
+ if(this->red_curve->is_empty()) return;
+ this->npoints = 5;
+ SPCurve *tmpCurve = new SPCurve();
+ this->p[2] = this->p[3] + (1./3)*(this->p[0] - this->p[3]);
+ this->p[2] = Geom::Point(this->p[2][X] + handleCubicGap,this->p[2][Y] + handleCubicGap);
+ if(this->green_curve->is_empty() && !this->sa){
+ this->p[1] = this->p[0] + (1./3)*(this->p[3] - this->p[0]);
+ this->p[1] = Geom::Point(this->p[1][X] + handleCubicGap,this->p[1][Y] + handleCubicGap);
+ if(shift){
+ this->p[2] = this->p[3];
+ }
+ }else if(!this->green_curve->is_empty()){
+ tmpCurve = this->green_curve->copy();
+ }else{
+ tmpCurve = this->overwriteCurve->copy();
+ if(this->sa->start)
+ tmpCurve = tmpCurve->create_reverse();
+ }
+
+ if(!tmpCurve->is_empty()){
+ Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment());
+ if(cubic){
+ if(this->bspline){
+ SPCurve * WPower = new SPCurve();
+ Geom::D2< Geom::SBasis > SBasisWPower;
+ WPower->moveto(tmpCurve->last_segment()->finalPoint());
+ WPower->lineto(tmpCurve->last_segment()->initialPoint());
+ float WP = Geom::nearest_point((*cubic)[2],*WPower->first_segment());
+ WPower->reset();
+ WPower->moveto(this->red_curve->last_segment()->initialPoint());
+ WPower->lineto(this->red_curve->last_segment()->finalPoint());
+ SBasisWPower = WPower->first_segment()->toSBasis();
+ WPower->reset();
+ this->p[1] = SBasisWPower.valueAt(WP);
+ if(!Geom::are_near(this->p[1],this->p[0])){
+ this->p[1] = Geom::Point(this->p[1][X] + handleCubicGap,this->p[1][Y] + handleCubicGap);
+ } else {
+ this->p[1] = this->p[0];
+ }
+ if(shift)
+ this->p[2] = this->p[3];
+ }else{
+ this->p[1] = (*cubic)[3] + ((*cubic)[3] - (*cubic)[2] );
+ }
+ }else{
+ this->p[1] = this->p[0];
+ if(shift)
+ this->p[2] = this->p[3];
+ }
+ }
+
+ if(this->anchor_statusbar && !this->red_curve->is_empty()){
+ if(shift){
+ this->_bspline_spiro_end_anchor_off();
+ }else{
+ this->_bspline_spiro_end_anchor_on();
+ }
+ }
+
+ this->_bspline_spiro_build();
+}
+
+void PenTool::_bspline_spiro_end_anchor_on()
+{
+
+ using Geom::X;
+ using Geom::Y;
+ this->p[2] = this->p[3] + (1./3)*(this->p[0] - this->p[3]);
+ this->p[2] = Geom::Point(this->p[2][X] + handleCubicGap,this->p[2][Y] + handleCubicGap);
+ SPCurve *tmpCurve = new SPCurve();
+ SPCurve *lastSeg = new SPCurve();
+ Geom::Point C(0,0);
+ bool reverse = false;
+ if( this->green_anchor && this->green_anchor->active ){
+ tmpCurve = this->green_curve->create_reverse();
+ if(this->green_curve->get_segment_count()==0){
+ return;
+ }
+ reverse = true;
+ } else if(this->sa){
+ tmpCurve = this->overwriteCurve->copy();
+ if(!this->sa->start){
+ tmpCurve = tmpCurve->create_reverse();
+ reverse = true;
+ }
+ }else{
+ return;
+ }
+ Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment());
+ if(this->bspline){
+ C = tmpCurve->last_segment()->finalPoint() + (1./3)*(tmpCurve->last_segment()->initialPoint() - tmpCurve->last_segment()->finalPoint());
+ C = Geom::Point(C[X] + handleCubicGap,C[Y] + handleCubicGap);
+ }else{
+ C = this->p[3] + this->p[3] - this->p[2];
+ }
+ if(cubic){
+ lastSeg->moveto((*cubic)[0]);
+ lastSeg->curveto((*cubic)[1],C,(*cubic)[3]);
+ }else{
+ lastSeg->moveto(tmpCurve->last_segment()->initialPoint());
+ lastSeg->lineto(tmpCurve->last_segment()->finalPoint());
+ }
+ if( tmpCurve->get_segment_count() == 1){
+ tmpCurve = lastSeg;
+ }else{
+ //we eliminate the last segment
+ tmpCurve->backspace();
+ //and we add it again with the recreation
+ tmpCurve->append_continuous(lastSeg, 0.0625);
+ }
+ if (reverse) {
+ tmpCurve = tmpCurve->create_reverse();
+ }
+ if( this->green_anchor && this->green_anchor->active )
+ {
+ this->green_curve->reset();
+ this->green_curve = tmpCurve;
+ }else{
+ this->overwriteCurve->reset();
+ this->overwriteCurve = tmpCurve;
+ }
+}
+
+void PenTool::_bspline_spiro_end_anchor_off()
+{
+
+ SPCurve *tmpCurve = new SPCurve();
+ SPCurve *lastSeg = new SPCurve();
+ bool reverse = false;
+ this->p[2] = this->p[3];
+ if( this->green_anchor && this->green_anchor->active ){
+ tmpCurve = this->green_curve->create_reverse();
+ if(this->green_curve->get_segment_count()==0){
+ return;
+ }
+ reverse = true;
+ } else if(this->sa){
+ tmpCurve = this->overwriteCurve->copy();
+ if(!this->sa->start){
+ tmpCurve = tmpCurve->create_reverse();
+ reverse = true;
+ }
+ }else{
+ return;
+ }
+ Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment());
+ if(cubic){
+ lastSeg->moveto((*cubic)[0]);
+ lastSeg->curveto((*cubic)[1],(*cubic)[3],(*cubic)[3]);
+ }else{
+ lastSeg->moveto(tmpCurve->last_segment()->initialPoint());
+ lastSeg->lineto(tmpCurve->last_segment()->finalPoint());
+ }
+ if( tmpCurve->get_segment_count() == 1){
+ tmpCurve = lastSeg;
+ }else{
+ //we eliminate the last segment
+ tmpCurve->backspace();
+ //and we add it again with the recreation
+ tmpCurve->append_continuous(lastSeg, 0.0625);
+ }
+ if (reverse) {
+ tmpCurve = tmpCurve->create_reverse();
+ }
+ if( this->green_anchor && this->green_anchor->active )
+ {
+ this->green_curve->reset();
+ this->green_curve = tmpCurve;
+ }else{
+ this->overwriteCurve->reset();
+ this->overwriteCurve = tmpCurve;
+ }
+}
+
+//prepares the curves for its transformation into BSpline curve.
+void PenTool::_bspline_spiro_build()
+{
+ if(!this->spiro && !this->bspline){
+ return;
+ }
+
+ //We create the base curve
+ SPCurve *curve = new SPCurve();
+ //If we continuate the existing curve we add it at the start
+ if(this->sa && !this->sa->curve->is_empty()){
+ curve = this->overwriteCurve->copy();
+ if (this->sa->start) {
+ curve = curve->create_reverse();
+ }
+ }
+
+ if (!this->green_curve->is_empty()){
+ curve->append_continuous(this->green_curve, 0.0625);
+ }
+
+ //and the red one
+ if (!this->red_curve->is_empty()){
+ this->red_curve->reset();
+ this->red_curve->moveto(this->p[0]);
+ if(this->anchor_statusbar && !this->sa && !(this->green_anchor && this->green_anchor->active)){
+ this->red_curve->curveto(this->p[1],this->p[3],this->p[3]);
+ }else{
+ this->red_curve->curveto(this->p[1],this->p[2],this->p[3]);
+ }
+ sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(this->red_bpath), this->red_curve);
+ curve->append_continuous(this->red_curve, 0.0625);
+ }
+
+ if(!curve->is_empty()){
+ // close the curve if the final points of the curve are close enough
+ if(Geom::are_near(curve->first_path()->initialPoint(), curve->last_path()->finalPoint())){
+ curve->closepath_current();
+ }
+ //TODO: CALL TO CLONED FUNCTION SPIRO::doEffect IN lpe-spiro.cpp
+ //For example
+ //using namespace Inkscape::LivePathEffect;
+ //LivePathEffectObject *lpeobj = static_cast<LivePathEffectObject*> (curve);
+ //Effect *spr = static_cast<Effect*> ( new LPEbspline(lpeobj) );
+ //spr->doEffect(curve);
+ if(this->bspline){
+ this->_bspline_doEffect(curve);
+ }else{
+ this->_spiro_doEffect(curve);
+ }
+
+ sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(this->blue_bpath), curve);
+ sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->blue_bpath), this->blue_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
+ sp_canvas_item_show(this->blue_bpath);
+ curve->unref();
+ this->blue_curve->reset();
+ //We hide the holders that doesn't contribute anything
+ if(this->spiro){
+ sp_canvas_item_show(this->c1);
+ SP_CTRL(this->c1)->moveto(this->p[0]);
+ }else
+ sp_canvas_item_hide(this->c1);
+ sp_canvas_item_hide(this->cl1);
+ sp_canvas_item_hide(this->c0);
+ sp_canvas_item_hide(this->cl0);
+ }else{
+ //if the curve is empty
+ sp_canvas_item_hide(this->blue_bpath);
+
+ }
+}
+
+void PenTool::_bspline_doEffect(SPCurve * curve)
+{
+ // commenting the function doEffect in src/live_effects/lpe-bspline.cpp
+ if (curve->get_segment_count() < 1){
+ return;
+ }
+ // Make copy of old path as it is changed during processing
+ Geom::PathVector const original_pathv = curve->get_pathvector();
+ curve->reset();
+
+ //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el
+ //penúltimo
+ for (Geom::PathVector::const_iterator path_it = original_pathv.begin();
+ path_it != original_pathv.end(); ++path_it) {
+ //Si está vacío...
+ if (path_it->empty())
+ continue;
+ //Itreadores
+
+ Geom::Path::const_iterator curve_it1 = path_it->begin();
+ Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
+ Geom::Path::const_iterator curve_endit = path_it->end_default();
+ SPCurve *nCurve = new SPCurve();
+ Geom::Point previousNode(0, 0);
+ Geom::Point node(0, 0);
+ Geom::Point pointAt1(0, 0);
+ Geom::Point pointAt2(0, 0);
+ Geom::Point nextPointAt1(0, 0);
+ Geom::D2<Geom::SBasis> SBasisIn;
+ Geom::D2<Geom::SBasis> SBasisOut;
+ Geom::D2<Geom::SBasis> SBasisHelper;
+ Geom::CubicBezier const *cubic = NULL;
+ if (path_it->closed()) {
+ const Geom::Curve &closingline =
+ path_it->back_closed(); // the closing line segment is always of type
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ curve_endit = path_it->end_open();
+ }
+ }
+ nCurve->moveto(curve_it1->initialPoint());
+ while (curve_it1 != curve_endit) {
+ SPCurve *in = new SPCurve();
+ in->moveto(curve_it1->initialPoint());
+ in->lineto(curve_it1->finalPoint());
+ cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
+ if (cubic) {
+ SBasisIn = in->first_segment()->toSBasis();
+ if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) {
+ pointAt1 = SBasisIn.valueAt(0.3334);
+ } else {
+ pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[1], *in->first_segment()));
+ }
+ if(are_near((*cubic)[2],(*cubic)[3]) && !are_near((*cubic)[1],(*cubic)[0])) {
+ pointAt2 = SBasisIn.valueAt(0.6667);
+ } else {
+ pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[2], *in->first_segment()));
+ }
+ } else {
+ pointAt1 = in->first_segment()->initialPoint();
+ pointAt2 = in->first_segment()->finalPoint();
+ }
+ in->reset();
+ delete in;
+ if ( curve_it2 != curve_endit ) {
+ SPCurve *out = new SPCurve();
+ out->moveto(curve_it2->initialPoint());
+ out->lineto(curve_it2->finalPoint());
+ cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it2);
+ if (cubic) {
+ SBasisOut = out->first_segment()->toSBasis();
+ if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) {
+ nextPointAt1 = SBasisIn.valueAt(0.3334);
+ } else {
+ nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment()));
+ }
+ } else {
+ nextPointAt1 = out->first_segment()->initialPoint();
+ }
+ out->reset();
+ delete out;
+ }
+ Geom::Point startNode = path_it->begin()->initialPoint();
+ if (path_it->closed() && curve_it2 == curve_endit) {
+ SPCurve *start = new SPCurve();
+ start->moveto(path_it->begin()->initialPoint());
+ start->lineto(path_it->begin()->finalPoint());
+ Geom::D2<Geom::SBasis> SBasisStart = start->first_segment()->toSBasis();
+ SPCurve *lineHelper = new SPCurve();
+ cubic = dynamic_cast<Geom::CubicBezier const *>(&*path_it->begin());
+ if (cubic) {
+ lineHelper->moveto(SBasisStart.valueAt(
+ Geom::nearest_point((*cubic)[1], *start->first_segment())));
+ } else {
+ lineHelper->moveto(start->first_segment()->initialPoint());
+ }
+ start->reset();
+ delete start;
+
+ SPCurve *end = new SPCurve();
+ end->moveto(curve_it1->initialPoint());
+ end->lineto(curve_it1->finalPoint());
+ Geom::D2<Geom::SBasis> SBasisEnd = end->first_segment()->toSBasis();
+ cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
+ if (cubic) {
+ lineHelper->lineto(SBasisEnd.valueAt(
+ Geom::nearest_point((*cubic)[2], *end->first_segment())));
+ } else {
+ lineHelper->lineto(end->first_segment()->finalPoint());
+ }
+ end->reset();
+ delete end;
+ SBasisHelper = lineHelper->first_segment()->toSBasis();
+ lineHelper->reset();
+ delete lineHelper;
+ startNode = SBasisHelper.valueAt(0.5);
+ nCurve->curveto(pointAt1, pointAt2, startNode);
+ nCurve->move_endpoints(startNode, startNode);
+ } else if ( curve_it2 == curve_endit) {
+ nCurve->curveto(pointAt1, pointAt2, curve_it1->finalPoint());
+ nCurve->move_endpoints(path_it->begin()->initialPoint(), curve_it1->finalPoint());
+ } else {
+ SPCurve *lineHelper = new SPCurve();
+ lineHelper->moveto(pointAt2);
+ lineHelper->lineto(nextPointAt1);
+ SBasisHelper = lineHelper->first_segment()->toSBasis();
+ lineHelper->reset();
+ delete lineHelper;
+ previousNode = node;
+ node = SBasisHelper.valueAt(0.5);
+ Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
+ if((cubic && are_near((*cubic)[0],(*cubic)[1])) || (cubic2 && are_near((*cubic2)[2],(*cubic2)[3]))) {
+ node = curve_it1->finalPoint();
+ }
+ nCurve->curveto(pointAt1, pointAt2, node);
+ }
+ ++curve_it1;
+ ++curve_it2;
+ }
+ if (path_it->closed()) {
+ nCurve->closepath_current();
+ }
+ curve->append(nCurve, false);
+ nCurve->reset();
+ delete nCurve;
+ }
+}
+
+//Spiro function cloned from lpe-spiro.cpp
+// commenting the function "doEffect" from src/live_effects/lpe-spiro.cpp
+void PenTool::_spiro_doEffect(SPCurve * curve)
+{
+ using Geom::X;
+ using Geom::Y;
+
+ Geom::PathVector const original_pathv = curve->get_pathvector();
+ guint len = curve->get_segment_count() + 2;
+
+ curve->reset();
+ Spiro::spiro_cp *path = g_new (Spiro::spiro_cp, len);
+ int ip = 0;
+
+ for(Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) {
+ if (path_it->empty())
+ continue;
+
+ {
+ Geom::Point p = path_it->front().pointAt(0);
+ path[ip].x = p[X];
+ path[ip].y = p[Y];
+ path[ip].ty = '{' ;
+ ip++;
+ }
+
+ Geom::Path::const_iterator curve_it1 = path_it->begin();
+ Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
+
+ Geom::Path::const_iterator curve_endit = path_it->end_default();
+ if (path_it->closed()) {
+ const Geom::Curve &closingline = path_it->back_closed();
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ curve_endit = path_it->end_open();
+ }
+ }
+
+ while ( curve_it2 != curve_endit )
+ {
+ Geom::Point p = curve_it1->finalPoint();
+ path[ip].x = p[X];
+ path[ip].y = p[Y];
+
+ bool this_is_line = is_straight_curve(*curve_it1);
+ bool next_is_line = is_straight_curve(*curve_it2);
+
+ Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2);
+
+ if ( nodetype == Geom::NODE_SMOOTH || nodetype == Geom::NODE_SYMM )
+ {
+ if (this_is_line && !next_is_line) {
+ path[ip].ty = ']';
+ } else if (next_is_line && !this_is_line) {
+ path[ip].ty = '[';
+ } else {
+ path[ip].ty = 'c';
+ }
+ } else {
+ path[ip].ty = 'v';
+ }
+
+ ++curve_it1;
+ ++curve_it2;
+ ip++;
+ }
+
+ Geom::Point p = curve_it1->finalPoint();
+ path[ip].x = p[X];
+ path[ip].y = p[Y];
+ if (path_it->closed()) {
+ Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, path_it->front());
+ switch (nodetype) {
+ case Geom::NODE_NONE:
+ path[ip].ty = '}';
+ ip++;
+ break;
+ case Geom::NODE_CUSP:
+ path[0].ty = path[ip].ty = 'v';
+ break;
+ case Geom::NODE_SMOOTH:
+ case Geom::NODE_SYMM:
+ path[0].ty = path[ip].ty = 'c';
+ break;
+ }
+ } else {
+ path[ip].ty = '}';
+ ip++;
+ }
+
+ int sp_len = ip;
+ Spiro::spiro_run(path, sp_len, *curve);
+ ip = 0;
+ }
+
+ g_free (path);
}
void PenTool::_setSubsequentPoint(Geom::Point const p, bool statusbar, guint status) {
g_assert( this->npoints != 0 );
+
// todo: Check callers to see whether 2 <= npoints is guaranteed.
this->p[2] = p;
@@ -1172,7 +2070,7 @@ void PenTool::_setSubsequentPoint(Geom::Point const p, bool statusbar, guint sta
// we are drawing horizontal/vertical lines and hit an anchor;
Geom::Point const origin = this->p[0];
// if the previous point and the anchor are not aligned either horizontally or vertically...
- if ((abs(p[Geom::X] - origin[Geom::X]) > 1e-9) && (abs(p[Geom::Y] - origin[Geom::Y]) > 1e-9)) {
+ if ((std::abs(p[Geom::X] - origin[Geom::X]) > 1e-9) && (std::abs(p[Geom::Y] - origin[Geom::Y]) > 1e-9)) {
// ...then we should draw an L-shaped path, consisting of two paraxial segments
Geom::Point intermed = p;
this->_setToNearestHorizVert(intermed, status, false);
@@ -1182,7 +2080,7 @@ void PenTool::_setSubsequentPoint(Geom::Point const p, bool statusbar, guint sta
is_curve = false;
} else {
// one of the 'regular' modes
- if (this->p[1] != this->p[0]) {
+ if (this->p[1] != this->p[0] || this->spiro) {
this->red_curve->curveto(this->p[1], p, p);
is_curve = true;
} else {
@@ -1197,10 +2095,16 @@ void PenTool::_setSubsequentPoint(Geom::Point const p, bool statusbar, guint sta
gchar *message = is_curve ?
_("<b>Curve segment</b>: angle %3.2f&#176;, distance %s; with <b>Ctrl</b> to snap angle, <b>Enter</b> to finish the path" ):
_("<b>Line segment</b>: angle %3.2f&#176;, distance %s; with <b>Ctrl</b> to snap angle, <b>Enter</b> to finish the path");
+ if(this->spiro || this->bspline){
+ message = is_curve ?
+ _("<b>Curve segment</b>: angle %3.2f&#176;, distance %s; with <b>Shift+Click</b> make a cusp node, <b>Enter</b> to finish the path" ):
+ _("<b>Line segment</b>: angle %3.2f&#176;, distance %s; with <b>Shift+Click</b> make a cusp node, <b>Enter</b> to finish the path");
+ }
this->_setAngleDistanceStatusMessage(p, 0, message);
}
}
+
void PenTool::_setCtrl(Geom::Point const p, guint const state) {
sp_canvas_item_show(this->c1);
sp_canvas_item_show(this->cl1);
@@ -1211,7 +2115,6 @@ void PenTool::_setCtrl(Geom::Point const p, guint const state) {
sp_canvas_item_hide(this->cl0);
SP_CTRL(this->c1)->moveto(this->p[1]);
this->cl1->setCoords(this->p[0], this->p[1]);
-
this->_setAngleDistanceStatusMessage(p, 0, _("<b>Curve handle</b>: angle %3.2f&#176;, length %s; with <b>Ctrl</b> to snap angle"));
} else if ( this->npoints == 5 ) {
this->p[4] = p;
@@ -1233,6 +2136,8 @@ void PenTool::_setCtrl(Geom::Point const p, guint const state) {
SP_CTRL(this->c1)->moveto(this->p[4]);
this->cl1->setCoords(this->p[3], this->p[4]);
+
+
gchar *message = is_symm ?
_("<b>Curve handle, symmetric</b>: angle %3.2f&#176;, length %s; with <b>Ctrl</b> to snap angle, with <b>Shift</b> to move this handle only") :
_("<b>Curve handle</b>: angle %3.2f&#176;, length %s; with <b>Ctrl</b> to snap angle, with <b>Shift</b> to move this handle only");
@@ -1247,11 +2152,14 @@ void PenTool::_finishSegment(Geom::Point const p, guint const state) {
pen_last_paraxial_dir = this->nextParaxialDirection(p, this->p[0], state);
}
- ++this->num_clicks;
+ ++num_clicks;
+
if (!this->red_curve->is_empty()) {
+ this->_bspline_spiro(state & GDK_SHIFT_MASK);
this->green_curve->append_continuous(this->red_curve, 0.0625);
SPCurve *curve = this->red_curve->copy();
+
/// \todo fixme:
SPCanvasItem *cshape = sp_canvas_bpath_new(sp_desktop_sketch(this->desktop), curve);
curve->unref();
@@ -1273,15 +2181,19 @@ void PenTool::_finish(gboolean const closed) {
return;
}
+
this->num_clicks = 0;
this->_disableEvents();
this->message_context->clear();
+
desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Drawing finished"));
+ // cancelate line without a created segment
this->red_curve->reset();
spdc_concat_colors_and_flush(this, closed);
+ this->overwriteCurve = NULL;
this->sa = NULL;
this->ea = NULL;
@@ -1330,7 +2242,7 @@ int PenTool::nextParaxialDirection(Geom::Point const &pt, Geom::Point const &ori
//
// num_clicks is not reliable because spdc_pen_finish_segment is sometimes called too early
// (on first mouse release), in which case num_clicks immediately becomes 1.
- // if (pc->num_clicks == 0) {
+ // if (this->num_clicks == 0) {
if (this->green_curve->is_empty()) {
// first mouse click
diff --git a/src/ui/tools/pen-tool.h b/src/ui/tools/pen-tool.h
index 4dec7b4fe..98fd0a43e 100644
--- a/src/ui/tools/pen-tool.h
+++ b/src/ui/tools/pen-tool.h
@@ -49,6 +49,9 @@ public:
bool polylines_only;
bool polylines_paraxial;
+ // propiety which saves if Spiro mode is active or not
+ bool spiro;
+ bool bspline;
int num_clicks;
unsigned int expecting_clicks_for_LPE; // if positive, finish the path after this many clicks
@@ -85,6 +88,34 @@ private:
bool _handleButtonRelease(GdkEventButton const &revent);
bool _handle2ButtonPress(GdkEventButton const &bevent);
bool _handleKeyPress(GdkEvent *event);
+ //adds spiro & bspline modes
+ void _pen_context_set_mode(guint mode);
+ //this function changes the colors red, green and blue making them transparent or not depending on if the function uses spiro
+ void _bspline_spiro_color();
+ //creates a node in bspline or spiro modes
+ void _bspline_spiro(bool shift);
+ //creates a node in bspline or spiro modes
+ void _bspline_spiro_on();
+ //creates a CUSP node
+ void _bspline_spiro_off();
+ //continues the existing curve in bspline or spiro mode
+ void _bspline_spiro_start_anchor(bool shift);
+ //continues the existing curve with the union node in bspline or spiro modes
+ void _bspline_spiro_start_anchor_on();
+ //continues an existing curve with the union node in CUSP mode
+ void _bspline_spiro_start_anchor_off();
+ //modifies the "red_curve" when it detects movement
+ void _bspline_spiro_motion(bool shift);
+ //closes the curve with the last node in bspline or spiro mode
+ void _bspline_spiro_end_anchor_on();
+ //closes the curve with the last node in CUSP mode
+ void _bspline_spiro_end_anchor_off();
+ //CHECK: join all the curves "in game" and we call doEffect function
+ void _bspline_spiro_build();
+ //function bspline cloned from lpe-bspline.cpp
+ void _bspline_doEffect(SPCurve * curve);
+ //function spiro cloned from lpe-spiro.cpp
+ void _spiro_doEffect(SPCurve * curve);
void _setInitialPoint(Geom::Point const p);
void _setSubsequentPoint(Geom::Point const p, bool statusbar, guint status = 0);
diff --git a/src/ui/tools/pencil-tool.cpp b/src/ui/tools/pencil-tool.cpp
index fb4e82c32..3ea2ae843 100644
--- a/src/ui/tools/pencil-tool.cpp
+++ b/src/ui/tools/pencil-tool.cpp
@@ -23,7 +23,7 @@
#include "desktop-handles.h"
#include "selection.h"
#include "selection-chemistry.h"
-#include "draw-anchor.h"
+#include "ui/draw-anchor.h"
#include "message-stack.h"
#include "message-context.h"
#include "sp-path.h"
@@ -43,7 +43,7 @@
#include "display/sp-canvas.h"
#include "display/curve.h"
#include "livarot/Path.h"
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
#include "ui/tool/event-utils.h"
namespace Inkscape {
@@ -200,6 +200,7 @@ bool PencilTool::_handleButtonPress(GdkEventButton const &bevent) {
}
if (anchor) {
p = anchor->dp;
+ this->overwriteCurve = anchor->curve;
desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Continuing selected path"));
} else {
m.setup(desktop);
@@ -301,7 +302,7 @@ bool PencilTool::_handleMotionNotify(GdkEventMotion const &mevent) {
if ( this->npoints != 0) { // buttonpress may have happened before we entered draw context!
if (this->ps.empty()) {
- // Only in freehand mode we have to add the first point also to pc->ps (apparently)
+ // Only in freehand mode we have to add the first point also to this->ps (apparently)
// - We cannot add this point in spdc_set_startpoint, because we only need it for freehand
// - We cannot do this in the button press handler because at that point we don't know yet
// wheter we're going into freehand mode or not
@@ -640,6 +641,9 @@ void PencilTool::_interpolate() {
return;
}
+ using Geom::X;
+ using Geom::Y;
+
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
double const tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0) * 0.4;
double const tolerance_sq = 0.02 * square(this->desktop->w2d().descrim() * tol) * exp(0.2 * tol - 2);
@@ -661,10 +665,21 @@ void PencilTool::_interpolate() {
if (n_segs > 0) {
/* Fit and draw and reset state */
- this->green_curve->moveto(b[0]);
+ this->green_curve->moveto(b[0]);
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ guint mode = prefs->getInt("/tools/freehand/pencil/freehand-mode", 0);
for (int c = 0; c < n_segs; c++) {
- this->green_curve->curveto(b[4 * c + 1], b[4 * c + 2], b[4 * c + 3]);
+ // if we are in BSpline we modify the trace to create adhoc nodes
+ if(mode == 2){
+ Geom::Point BP = b[4*c+0] + (1./3)*(b[4*c+3] - b[4*c+0]);
+ BP = Geom::Point(BP[X] + 0.0001,BP[Y] + 0.0001);
+ Geom::Point CP = b[4*c+3] + (1./3)*(b[4*c+0] - b[4*c+3]);
+ CP = Geom::Point(CP[X] + 0.0001,CP[Y] + 0.0001);
+ this->green_curve->curveto(BP,CP,b[4*c+3]);
+ }else{
+ this->green_curve->curveto(b[4 * c + 1], b[4 * c + 2], b[4 * c + 3]);
+ }
}
sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(this->red_bpath), this->green_curve);
@@ -788,6 +803,7 @@ void PencilTool::_fitAndSplit() {
g_assert(is_zero(this->req_tangent)
|| is_unit_vector(this->req_tangent));
Geom::Point const tHatEnd(0, 0);
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
int const n_segs = Geom::bezier_fit_cubic_full(b, NULL, this->p, this->npoints,
this->req_tangent, tHatEnd,
tolerance_sq, 1);
@@ -795,9 +811,22 @@ void PencilTool::_fitAndSplit() {
&& unsigned(this->npoints) < G_N_ELEMENTS(this->p) )
{
/* Fit and draw and reset state */
+
this->red_curve->reset();
this->red_curve->moveto(b[0]);
- this->red_curve->curveto(b[1], b[2], b[3]);
+ using Geom::X;
+ using Geom::Y;
+ // if we are in BSpline we modify the trace to create adhoc nodes
+ guint mode = prefs->getInt("/tools/freehand/pencil/freehand-mode", 0);
+ if(mode == 2){
+ Geom::Point B = b[0] + (1./3)*(b[3] - b[0]);
+ B = Geom::Point(B[X] + 0.0001,B[Y] + 0.0001);
+ Geom::Point C = b[3] + (1./3)*(b[0] - b[3]);
+ C = Geom::Point(C[X] + 0.0001,C[Y] + 0.0001);
+ this->red_curve->curveto(B,C,b[3]);
+ }else{
+ this->red_curve->curveto(b[1], b[2], b[3]);
+ }
sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(this->red_bpath), this->red_curve);
this->red_curve_is_valid = true;
} else {
@@ -826,6 +855,13 @@ void PencilTool::_fitAndSplit() {
/// \todo fixme:
SPCanvasItem *cshape = sp_canvas_bpath_new(sp_desktop_sketch(this->desktop), curve);
curve->unref();
+
+ this->highlight_color = SP_ITEM(this->desktop->currentLayer())->highlight_color();
+ if((unsigned int)prefs->getInt("/tools/nodes/highlight_color", 0xff0000ff) == this->highlight_color){
+ this->green_color = 0x00ff007f;
+ } else {
+ this->green_color = this->highlight_color;
+ }
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(cshape), this->green_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
this->green_bpaths = g_slist_prepend(this->green_bpaths, cshape);
diff --git a/src/ui/tools/rect-tool.cpp b/src/ui/tools/rect-tool.cpp
index 39f422c1a..de91dcff4 100644
--- a/src/ui/tools/rect-tool.cpp
+++ b/src/ui/tools/rect-tool.cpp
@@ -40,13 +40,13 @@
#include "xml/node-event-vector.h"
#include "preferences.h"
#include "context-fns.h"
-#include "shape-editor.h"
+#include "ui/shape-editor.h"
#include "verbs.h"
#include "display/sp-canvas-item.h"
using Inkscape::DocumentUndo;
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
@@ -102,8 +102,8 @@ RectTool::~RectTool() {
* destroys old and creates new knotholder.
*/
void RectTool::selection_changed(Inkscape::Selection* selection) {
- this->shape_editor->unset_item(SH_KNOTHOLDER);
- this->shape_editor->set_item(selection->singleItem(), SH_KNOTHOLDER);
+ this->shape_editor->unset_item();
+ this->shape_editor->set_item(selection->singleItem());
}
void RectTool::setup() {
@@ -113,7 +113,7 @@ void RectTool::setup() {
SPItem *item = sp_desktop_selection(this->desktop)->singleItem();
if (item) {
- this->shape_editor->set_item(item, SH_KNOTHOLDER);
+ this->shape_editor->set_item(item);
}
this->sel_changed_connection.disconnect();
diff --git a/src/ui/tools/rect-tool.h b/src/ui/tools/rect-tool.h
index a50fd7b24..a22f1caa8 100644
--- a/src/ui/tools/rect-tool.h
+++ b/src/ui/tools/rect-tool.h
@@ -6,6 +6,7 @@
*
* Author:
* Lauris Kaplinski <lauris@kaplinski.com>
+ * Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2000 Lauris Kaplinski
* Copyright (C) 2000-2001 Ximian, Inc.
@@ -21,9 +22,6 @@
#include "sp-rect.h"
-#define SP_RECT_CONTEXT(obj) (dynamic_cast<Inkscape::UI::Tools::RectTool*>((Inkscape::UI::Tools::ToolBase*)obj))
-#define SP_IS_RECT_CONTEXT(obj) (dynamic_cast<const Inkscape::UI::Tools::RectTool*>((const Inkscape::UI::Tools::ToolBase*)obj) != NULL)
-
namespace Inkscape {
namespace UI {
namespace Tools {
diff --git a/src/ui/tools/select-tool.cpp b/src/ui/tools/select-tool.cpp
index 83bef17c9..a8267ea1d 100644
--- a/src/ui/tools/select-tool.cpp
+++ b/src/ui/tools/select-tool.cpp
@@ -41,7 +41,7 @@
#include "desktop-handles.h"
#include "sp-root.h"
#include "preferences.h"
-#include "tools-switch.h"
+#include "ui/tools-switch.h"
#include "message-stack.h"
#include "selection-describer.h"
#include "seltrans.h"
@@ -49,7 +49,7 @@
#include "display/sp-canvas.h"
#include "display/sp-canvas-item.h"
#include "display/drawing-item.h"
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
using Inkscape::DocumentUndo;
@@ -264,15 +264,16 @@ sp_select_context_up_one_layer(SPDesktop *desktop)
SPObject *const current_layer = desktop->currentLayer();
if (current_layer) {
SPObject *const parent = current_layer->parent;
+ SPGroup *current_group = dynamic_cast<SPGroup *>(current_layer);
if ( parent
&& ( parent->parent
- || !( SP_IS_GROUP(current_layer)
- && ( SPGroup::LAYER
- == SP_GROUP(current_layer)->layerMode() ) ) ) )
+ || !( current_group
+ && ( SPGroup::LAYER == current_group->layerMode() ) ) ) )
{
desktop->setCurrentLayer(parent);
- if (SP_IS_GROUP(current_layer) && SPGroup::LAYER != SP_GROUP(current_layer)->layerMode())
+ if (current_group && (SPGroup::LAYER != current_group->layerMode())) {
sp_desktop_selection(desktop)->set(current_layer);
+ }
}
}
}
@@ -403,7 +404,8 @@ void SelectTool::sp_select_context_cycle_through_items(Inkscape::Selection *sele
}
Inkscape::DrawingItem *arenaitem;
- SPItem *item = SP_ITEM(this->cycling_cur_item->data);
+ SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(cycling_cur_item->data));
+ g_assert(item != NULL);
// Deactivate current item
if (!g_list_find(this->cycling_items_selected_before, item) && selection->includes(item)) {
@@ -427,7 +429,8 @@ void SelectTool::sp_select_context_cycle_through_items(Inkscape::Selection *sele
if (next) {
this->cycling_cur_item = next;
- item = SP_ITEM(this->cycling_cur_item->data);
+ item = dynamic_cast<SPItem *>(static_cast<SPObject *>(this->cycling_cur_item->data));
+ g_assert(item != NULL);
}
arenaitem = item->get_arenaitem(desktop->dkey);
@@ -442,8 +445,13 @@ void SelectTool::sp_select_context_cycle_through_items(Inkscape::Selection *sele
void SelectTool::sp_select_context_reset_opacities() {
for (GList *l = this->cycling_items; l != NULL; l = g_list_next(l)) {
- Inkscape::DrawingItem *arenaitem = SP_ITEM(l->data)->get_arenaitem(this->desktop->dkey);
- arenaitem->setOpacity(SP_SCALE24_TO_FLOAT(SP_ITEM(l->data)->style->opacity.value));
+ SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(l->data));
+ if (item) {
+ Inkscape::DrawingItem *arenaitem = item->get_arenaitem(desktop->dkey);
+ arenaitem->setOpacity(SP_SCALE24_TO_FLOAT(item->style->opacity.value));
+ } else {
+ g_assert_not_reached();
+ }
}
g_list_free(this->cycling_items);
@@ -475,8 +483,8 @@ bool SelectTool::root_handler(GdkEvent* event) {
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));
+ if (dynamic_cast<SPGroup *>(clicked_item) && !dynamic_cast<SPBox3D *>(clicked_item)) { // enter group if it's not a 3D box
+ desktop->setCurrentLayer(clicked_item);
sp_desktop_selection(desktop)->clear();
this->dragging = false;
sp_event_context_discard_delayed_snap_event(this);
@@ -591,8 +599,11 @@ bool SelectTool::root_handler(GdkEvent* event) {
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());
+ {
+ SPGroup *selGroup = dynamic_cast<SPGroup *>(selection->single());
+ if (selGroup && (selGroup->layerMode() == SPGroup::LAYER)) {
+ group_at_point = selGroup;
+ }
}
// group-at-point is meant to be topmost item if it's a group,
@@ -673,10 +684,11 @@ bool SelectTool::root_handler(GdkEvent* event) {
selection->toggle(this->item);
} else {
SPObject* single = selection->single();
+ SPGroup *singleGroup = dynamic_cast<SPGroup *>(single);
// without shift, increase state (i.e. toggle scale/rotation handles)
if (selection->includes(this->item)) {
_seltrans->increaseState();
- } else if (SP_IS_LAYER(single) && single->isAncestorOf(this->item)) {
+ } else if (singleGroup && (singleGroup->layerMode() == SPGroup::LAYER) && single->isAncestorOf(this->item)) {
_seltrans->increaseState();
} else {
_seltrans->resetState();
@@ -818,7 +830,7 @@ bool SelectTool::root_handler(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 = this->cycling_cur_item ? SP_ITEM(this->cycling_cur_item->data) : NULL;
+ SPItem *tmp_cur_item = this->cycling_cur_item ? dynamic_cast<SPItem *>(static_cast<SPObject *>(this->cycling_cur_item->data)) : NULL;
g_list_free(this->cycling_items);
this->cycling_items = NULL;
this->cycling_cur_item = NULL;
@@ -851,11 +863,14 @@ bool SelectTool::root_handler(GdkEvent* event) {
Inkscape::DrawingItem *arenaitem;
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(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));
+ SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(l->data));
+ if (item) {
+ arenaitem = item->get_arenaitem(desktop->dkey);
+ arenaitem->setOpacity(1.0);
+ //if (!shift_pressed && !g_list_find(this->cycling_items_selected_before, item) && selection->includes(item))
+ if (!g_list_find(this->cycling_items_selected_before, item) && selection->includes(item)) {
+ selection->remove(item);
+ }
}
}
@@ -869,16 +884,19 @@ bool SelectTool::root_handler(GdkEvent* event) {
// ... and rebuild them with the new items.
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
- this->cycling_items_selected_before = g_list_append(this->cycling_items_selected_before, item);
+ SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(l->data));
+ if (item) {
+ arenaitem = item->get_arenaitem(desktop->dkey);
+ arenaitem->setOpacity(0.3);
+
+ if (selection->includes(item)) {
+ // already selected items are stored separately, too
+ this->cycling_items_selected_before = g_list_append(this->cycling_items_selected_before, item);
+ }
+ } else {
+ g_assert_not_reached();
}
}
@@ -1134,9 +1152,9 @@ bool SelectTool::root_handler(GdkEvent* event) {
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
- desktop->setCurrentLayer(reinterpret_cast<SPObject *>(clicked_item));
+ SPGroup *clickedGroup = dynamic_cast<SPGroup *>(clicked_item);
+ if ( (clickedGroup && (clickedGroup->layerMode() != SPGroup::LAYER)) || dynamic_cast<SPBox3D *>(clicked_item)) { // enter group or a 3D box
+ desktop->setCurrentLayer(clicked_item);
sp_desktop_selection(desktop)->clear();
} else {
this->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Selected object is not a group. Cannot enter."));
diff --git a/src/ui/tools/select-tool.h b/src/ui/tools/select-tool.h
index edc4069a2..5af99a56a 100644
--- a/src/ui/tools/select-tool.h
+++ b/src/ui/tools/select-tool.h
@@ -13,7 +13,6 @@
*/
#include "ui/tools/tool-base.h"
-#include <gtk/gtk.h>
#define SP_SELECT_CONTEXT(obj) (dynamic_cast<Inkscape::UI::Tools::SelectTool*>((Inkscape::UI::Tools::ToolBase*)obj))
#define SP_IS_SELECT_CONTEXT(obj) (dynamic_cast<const Inkscape::UI::Tools::SelectTool*>((const Inkscape::UI::Tools::ToolBase*)obj) != NULL)
diff --git a/src/ui/tools/spiral-tool.cpp b/src/ui/tools/spiral-tool.cpp
index 5ae229df8..18c3e4e2d 100644
--- a/src/ui/tools/spiral-tool.cpp
+++ b/src/ui/tools/spiral-tool.cpp
@@ -39,13 +39,13 @@
#include "xml/node-event-vector.h"
#include "preferences.h"
#include "context-fns.h"
-#include "shape-editor.h"
+#include "ui/shape-editor.h"
#include "verbs.h"
#include "display/sp-canvas-item.h"
using Inkscape::DocumentUndo;
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
@@ -104,8 +104,8 @@ SpiralTool::~SpiralTool() {
* destroys old and creates new knotholder.
*/
void SpiralTool::selection_changed(Inkscape::Selection *selection) {
- this->shape_editor->unset_item(SH_KNOTHOLDER);
- this->shape_editor->set_item(selection->singleItem(), SH_KNOTHOLDER);
+ this->shape_editor->unset_item();
+ this->shape_editor->set_item(selection->singleItem());
}
void SpiralTool::setup() {
@@ -119,7 +119,7 @@ void SpiralTool::setup() {
SPItem *item = sp_desktop_selection(this->desktop)->singleItem();
if (item) {
- this->shape_editor->set_item(item, SH_KNOTHOLDER);
+ this->shape_editor->set_item(item);
}
Inkscape::Selection *selection = sp_desktop_selection(this->desktop);
diff --git a/src/ui/tools/spiral-tool.h b/src/ui/tools/spiral-tool.h
index 416aeb7e4..add92342d 100644
--- a/src/ui/tools/spiral-tool.h
+++ b/src/ui/tools/spiral-tool.h
@@ -15,17 +15,15 @@
* Released under GNU GPL
*/
-#include <gtk/gtk.h>
-#include <stddef.h>
-#include <sigc++/sigc++.h>
+#include <sigc++/connection.h>
#include <2geom/point.h>
#include "ui/tools/tool-base.h"
-#include "sp-spiral.h"
-
#define SP_SPIRAL_CONTEXT(obj) (dynamic_cast<Inkscape::UI::Tools::SpiralTool*>((Inkscape::UI::Tools::ToolBase*)obj))
#define SP_IS_SPIRAL_CONTEXT(obj) (dynamic_cast<const Inkscape::UI::Tools::SpiralTool*>((const Inkscape::UI::Tools::ToolBase*)obj) != NULL)
+class SPSpiral;
+
namespace Inkscape {
namespace UI {
namespace Tools {
diff --git a/src/ui/tools/spray-tool.cpp b/src/ui/tools/spray-tool.cpp
index 08d3119a1..cdc608558 100644
--- a/src/ui/tools/spray-tool.cpp
+++ b/src/ui/tools/spray-tool.cpp
@@ -84,7 +84,7 @@ using namespace std;
// Please enable again when working on 1.0
#define ENABLE_SPRAY_MODE_SINGLE_PATH
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
@@ -384,11 +384,14 @@ static bool sp_spray_recursive(SPDesktop *desktop,
gint _distrib)
{
bool did = false;
-
- if (SP_IS_BOX3D(item) ) {
- // convert 3D boxes to ordinary groups before spraying their shapes
- item = box3d_convert_to_group(SP_BOX3D(item));
- selection->add(item);
+
+ {
+ SPBox3D *box = dynamic_cast<SPBox3D *>(item);
+ if (box) {
+ // convert 3D boxes to ordinary groups before spraying their shapes
+ item = box3d_convert_to_group(box);
+ selection->add(item);
+ }
}
double _fid = g_random_double_range(0, 1);
@@ -413,7 +416,7 @@ static bool sp_spray_recursive(SPDesktop *desktop,
parent->appendChild(copy);
SPObject *new_obj = doc->getObjectByRepr(copy);
- item_copied = SP_ITEM(new_obj); // Convertion object->item
+ item_copied = dynamic_cast<SPItem *>(new_obj); // Convertion object->item
Geom::Point center=item->getCenter();
sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(_scale,_scale));
sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(scale,scale));
@@ -437,7 +440,7 @@ static bool sp_spray_recursive(SPDesktop *desktop,
items != NULL;
items = items->next) {
- SPItem *item1 = SP_ITEM(items->data);
+ SPItem *item1 = dynamic_cast<SPItem *>(static_cast<SPObject *>(items->data));
if (i == 1) {
parent_item = item1;
}
@@ -458,7 +461,7 @@ static bool sp_spray_recursive(SPDesktop *desktop,
Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc);
parent->appendChild(copy);
SPObject *new_obj = doc->getObjectByRepr(copy);
- item_copied = SP_ITEM(new_obj);
+ item_copied = dynamic_cast<SPItem *>(new_obj);
// Move around the cursor
Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());
@@ -503,7 +506,7 @@ static bool sp_spray_recursive(SPDesktop *desktop,
SPObject *clone_object = doc->getObjectByRepr(clone);
// Conversion object->item
- item_copied = SP_ITEM(clone_object);
+ item_copied = dynamic_cast<SPItem *>(clone_object);
Geom::Point center = item->getCenter();
sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(_scale, _scale));
sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(scale, scale));
@@ -554,13 +557,16 @@ static bool sp_spray_dilate(SprayTool *tc, Geom::Point /*event_p*/, Geom::Point
for (GSList *items = original_selection;
items != NULL;
items = items->next) {
- sp_object_ref(SP_ITEM(items->data));
+ SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(items->data));
+ g_assert(item != NULL);
+ sp_object_ref(item);
}
for (GSList *items = original_selection;
items != NULL;
items = items->next) {
- SPItem *item = SP_ITEM(items->data);
+ SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(items->data));
+ g_assert(item != NULL);
if (is_transform_modes(tc->mode)) {
if (sp_spray_recursive(desktop, selection, item, p, vector, tc->mode, radius, move_force, tc->population, tc->scale, tc->scale_variation, reverse, move_mean, move_standard_deviation, tc->ratio, tc->tilt, tc->rotation_variation, tc->distrib)) {
@@ -576,7 +582,9 @@ static bool sp_spray_dilate(SprayTool *tc, Geom::Point /*event_p*/, Geom::Point
for (GSList *items = original_selection;
items != NULL;
items = items->next) {
- sp_object_unref(SP_ITEM(items->data));
+ SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(items->data));
+ g_assert(item != NULL);
+ sp_object_unref(item);
}
}
@@ -677,7 +685,7 @@ bool SprayTool::root_handler(GdkEvent* event) {
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: {
diff --git a/src/ui/tools/star-tool.cpp b/src/ui/tools/star-tool.cpp
index 68f998920..7604ba04e 100644
--- a/src/ui/tools/star-tool.cpp
+++ b/src/ui/tools/star-tool.cpp
@@ -41,7 +41,7 @@
#include "xml/repr.h"
#include "xml/node-event-vector.h"
#include "context-fns.h"
-#include "shape-editor.h"
+#include "ui/shape-editor.h"
#include "verbs.h"
#include "display/sp-canvas-item.h"
@@ -49,7 +49,7 @@
using Inkscape::DocumentUndo;
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
@@ -112,8 +112,8 @@ StarTool::~StarTool() {
void StarTool::selection_changed(Inkscape::Selection* selection) {
g_assert (selection != NULL);
- this->shape_editor->unset_item(SH_KNOTHOLDER);
- this->shape_editor->set_item(selection->singleItem(), SH_KNOTHOLDER);
+ this->shape_editor->unset_item();
+ this->shape_editor->set_item(selection->singleItem());
}
void StarTool::setup() {
@@ -129,7 +129,7 @@ void StarTool::setup() {
SPItem *item = sp_desktop_selection(this->desktop)->singleItem();
if (item) {
- this->shape_editor->set_item(item, SH_KNOTHOLDER);
+ this->shape_editor->set_item(item);
}
Inkscape::Selection *selection = sp_desktop_selection(this->desktop);
diff --git a/src/ui/tools/text-tool.cpp b/src/ui/tools/text-tool.cpp
index ac830fe6b..a72748733 100644
--- a/src/ui/tools/text-tool.cpp
+++ b/src/ui/tools/text-tool.cpp
@@ -40,7 +40,7 @@
#include "rubberband.h"
#include "selection-chemistry.h"
#include "selection.h"
-#include "shape-editor.h"
+#include "ui/shape-editor.h"
#include "sp-flowtext.h"
#include "sp-namedview.h"
#include "sp-text.h"
@@ -52,7 +52,7 @@
#include "xml/node-event-vector.h"
#include "xml/repr.h"
#include <gtk/gtk.h>
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
using Inkscape::ControlManager;
using Inkscape::DocumentUndo;
@@ -177,7 +177,7 @@ void TextTool::setup() {
SPItem *item = sp_desktop_selection(this->desktop)->singleItem();
if (item && SP_IS_FLOWTEXT(item) && SP_FLOWTEXT(item)->has_internal_frame()) {
- this->shape_editor->set_item(item, SH_KNOTHOLDER);
+ this->shape_editor->set_item(item);
}
this->sel_changed_connection = sp_desktop_selection(desktop)->connectChangedFirst(
@@ -1411,10 +1411,10 @@ void TextTool::_selectionChanged(Inkscape::Selection *selection)
ToolBase *ec = SP_EVENT_CONTEXT(this);
- ec->shape_editor->unset_item(SH_KNOTHOLDER);
+ ec->shape_editor->unset_item();
SPItem *item = selection->singleItem();
if (item && SP_IS_FLOWTEXT(item) && SP_FLOWTEXT(item)->has_internal_frame()) {
- ec->shape_editor->set_item(item, SH_KNOTHOLDER);
+ ec->shape_editor->set_item(item);
}
if (this->text && (item != this->text)) {
diff --git a/src/ui/tools/text-tool.h b/src/ui/tools/text-tool.h
index ca2b3d19a..289ee180d 100644
--- a/src/ui/tools/text-tool.h
+++ b/src/ui/tools/text-tool.h
@@ -14,10 +14,7 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-/* #include <gdk/gdkic.h> */
-#include <stddef.h>
-#include <sigc++/sigc++.h>
-#include <gtk/gtk.h>
+#include <sigc++/connection.h>
#include "ui/tools/tool-base.h"
#include <2geom/point.h>
@@ -26,6 +23,8 @@
#define SP_TEXT_CONTEXT(obj) (dynamic_cast<Inkscape::UI::Tools::TextTool*>((Inkscape::UI::Tools::ToolBase*)obj))
#define SP_IS_TEXT_CONTEXT(obj) (dynamic_cast<const Inkscape::UI::Tools::TextTool*>((const Inkscape::UI::Tools::ToolBase*)obj) != NULL)
+typedef struct _GtkIMContext GtkIMContext;
+
struct SPCtrlLine;
namespace Inkscape {
diff --git a/src/ui/tools/tool-base.cpp b/src/ui/tools/tool-base.cpp
index 4195c9eb2..37ca5eeea 100644
--- a/src/ui/tools/tool-base.cpp
+++ b/src/ui/tools/tool-base.cpp
@@ -18,6 +18,8 @@
# include "config.h"
#endif
+#include "widgets/desktop-widget.h"
+
#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
#include <glibmm/threads.h>
#endif
@@ -40,12 +42,11 @@
#include "desktop-handles.h"
#include "desktop-events.h"
#include "desktop-style.h"
-#include "widgets/desktop-widget.h"
#include "sp-namedview.h"
#include "selection.h"
-#include "interface.h"
+#include "ui/interface.h"
#include "macros.h"
-#include "tools-switch.h"
+#include "ui/tools-switch.h"
#include "preferences.h"
#include "message-context.h"
#include "gradient-drag.h"
@@ -54,10 +55,11 @@
#include "selcue.h"
#include "ui/tools/lpe-tool.h"
#include "ui/tool/control-point.h"
-#include "shape-editor.h"
+#include "ui/shape-editor.h"
#include "sp-guide.h"
#include "color.h"
#include "knot.h"
+#include "knot-ptr.h"
// globals for temporary switching to selector by space
static bool selector_toggled = FALSE;
@@ -1289,8 +1291,7 @@ void sp_event_context_snap_delay_handler(ToolBase *ec,
// now, just in case there's no future motion event that drops under the speed limit (when
// stopping abruptly)
delete ec->_delayed_snap_event;
- ec->_delayed_snap_event = new DelayedSnapEvent(ec, dse_item, dse_item2,
- event, origin); // watchdog is reset, i.e. pushed forward in time
+ ec->_delayed_snap_event = new DelayedSnapEvent(ec, dse_item, dse_item2, event, origin); // watchdog is reset, i.e. pushed forward in time
// If the watchdog expires before a new motion event is received, we will snap (as explained
// above). This means however that when the timer is too short, we will always snap and that the
// speed threshold is ineffective. In the extreme case the delay is set to zero, and snapping will
@@ -1301,15 +1302,13 @@ void sp_event_context_snap_delay_handler(ToolBase *ec,
// snap, and set a new watchdog again.
if (ec->_delayed_snap_event == NULL) { // no watchdog has been set
// it might have already expired, so we'll set a new one; the snapping frequency will be limited this way
- ec->_delayed_snap_event = new DelayedSnapEvent(ec, dse_item,
- dse_item2, event, origin);
+ ec->_delayed_snap_event = new DelayedSnapEvent(ec, dse_item, dse_item2, event, origin);
} // else: watchdog has been set before and we'll wait for it to expire
}
} else {
// This is the first GDK_MOTION_NOTIFY event, so postpone snapping and set the watchdog
g_assert(ec->_delayed_snap_event == NULL);
- ec->_delayed_snap_event = new DelayedSnapEvent(ec, dse_item, dse_item2,
- event, origin);
+ ec->_delayed_snap_event = new DelayedSnapEvent(ec, dse_item, dse_item2, event, origin);
}
prev_pos = event_pos;
@@ -1362,6 +1361,7 @@ gboolean sp_event_context_snap_watchdog_callback(gpointer data) {
break;
case DelayedSnapEvent::KNOT_HANDLER: {
gpointer knot = dse->getItem2();
+ check_if_knot_deleted(knot);
if (knot && SP_IS_KNOT(knot)) {
sp_knot_handler_request_position(dse->getEvent(), SP_KNOT(knot));
}
diff --git a/src/ui/tools/tool-base.h b/src/ui/tools/tool-base.h
index b27de9030..7a6ab83e7 100644
--- a/src/ui/tools/tool-base.h
+++ b/src/ui/tools/tool-base.h
@@ -30,7 +30,6 @@ namespace Glib {
class GrDrag;
class SPDesktop;
class SPItem;
-class ShapeEditor;
namespace Inkscape {
class MessageContext;
@@ -42,6 +41,9 @@ namespace Inkscape {
namespace Inkscape {
namespace UI {
+
+class ShapeEditor;
+
namespace Tools {
class ToolBase;
diff --git a/src/ui/tools/tweak-tool.cpp b/src/ui/tools/tweak-tool.cpp
index 75650d3af..f56975de2 100644
--- a/src/ui/tools/tweak-tool.cpp
+++ b/src/ui/tools/tweak-tool.cpp
@@ -91,7 +91,7 @@ using Inkscape::DocumentUndo;
#define DYNA_MIN_WIDTH 1.0e-6
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
@@ -372,13 +372,16 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, Geom::P
{
bool did = false;
- if (SP_IS_BOX3D(item) && !is_transform_mode(mode) && !is_color_mode(mode)) {
- // convert 3D boxes to ordinary groups before tweaking their shapes
- item = box3d_convert_to_group(SP_BOX3D(item));
- selection->add(item);
+ {
+ SPBox3D *box = dynamic_cast<SPBox3D *>(item);
+ if (box && !is_transform_mode(mode) && !is_color_mode(mode)) {
+ // convert 3D boxes to ordinary groups before tweaking their shapes
+ item = box3d_convert_to_group(box);
+ selection->add(item);
+ }
}
- if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) {
+ if (dynamic_cast<SPText *>(item) || dynamic_cast<SPFlowtext *>(item)) {
GSList *items = g_slist_prepend (NULL, item);
GSList *selected = NULL;
GSList *to_select = NULL;
@@ -387,22 +390,25 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, Geom::P
g_slist_free (items);
SPObject* newObj = doc->getObjectByRepr(static_cast<Inkscape::XML::Node *>(to_select->data));
g_slist_free (to_select);
- item = SP_ITEM(newObj);
+ item = dynamic_cast<SPItem *>(newObj);
+ g_assert(item != NULL);
selection->add(item);
}
- if (SP_IS_GROUP(item) && !SP_IS_BOX3D(item)) {
+ if (dynamic_cast<SPGroup *>(item) && !dynamic_cast<SPBox3D *>(item)) {
GSList *children = NULL;
for (SPObject *child = item->firstChild() ; child; child = child->getNext() ) {
- if (SP_IS_ITEM(child)) {
+ if (dynamic_cast<SPItem *>(static_cast<SPObject *>(child))) {
children = g_slist_prepend(children, child);
}
}
for (GSList *i = children; i; i = i->next) {
- SPItem *child = SP_ITEM(i->data);
- if (sp_tweak_dilate_recursive (selection, SP_ITEM(child), p, vector, mode, radius, force, fidelity, reverse))
+ SPItem *child = dynamic_cast<SPItem *>(static_cast<SPObject *>(i->data));
+ g_assert(child != NULL);
+ if (sp_tweak_dilate_recursive (selection, child, p, vector, mode, radius, force, fidelity, reverse)) {
did = true;
+ }
}
g_slist_free(children);
@@ -509,13 +515,13 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, Geom::P
}
}
- } else if (SP_IS_PATH(item) || SP_IS_SHAPE(item)) {
+ } else if (dynamic_cast<SPPath *>(item) || dynamic_cast<SPShape *>(item)) {
Inkscape::XML::Node *newrepr = NULL;
gint pos = 0;
Inkscape::XML::Node *parent = NULL;
char const *id = NULL;
- if (!SP_IS_PATH(item)) {
+ if (!dynamic_cast<SPPath *>(item)) {
newrepr = sp_selected_item_to_curved_repr(item, 0);
if (!newrepr) {
return false;
@@ -631,7 +637,8 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, Geom::P
if (newrepr) {
newrepr->setAttribute("d", str);
} else {
- if (SP_IS_LPE_ITEM(item) && SP_LPE_ITEM(item)->hasPathEffectRecursive()) {
+ SPLPEItem *lpeitem = dynamic_cast<SPLPEItem *>(item);
+ if (lpeitem && lpeitem->hasPathEffectRecursive()) {
item->getRepr()->setAttribute("inkscape:original-d", str);
} else {
item->getRepr()->setAttribute("d", str);
@@ -769,7 +776,7 @@ static void tweak_colors_in_gradient(SPItem *item, Inkscape::PaintTarget fill_or
{
SPGradient *gradient = getGradient(item, fill_or_stroke);
- if (!gradient || !SP_IS_GRADIENT(gradient)) {
+ if (!gradient || !dynamic_cast<SPGradient *>(gradient)) {
return;
}
@@ -780,9 +787,9 @@ static void tweak_colors_in_gradient(SPItem *item, Inkscape::PaintTarget fill_or
double pos = 0;
double r = 0;
- if (SP_IS_LINEARGRADIENT(gradient)) {
- SPLinearGradient *lg = SP_LINEARGRADIENT(gradient);
+ SPLinearGradient *lg = dynamic_cast<SPLinearGradient *>(gradient);
+ if (lg) {
Geom::Point p1(lg->x1.computed, lg->y1.computed);
Geom::Point p2(lg->x2.computed, lg->y2.computed);
Geom::Point pdiff(p2 - p1);
@@ -800,11 +807,13 @@ static void tweak_colors_in_gradient(SPItem *item, Inkscape::PaintTarget fill_or
// Calculate radius in lenfth-of-gradient-line units
r = radius / vl;
- } else if (SP_IS_RADIALGRADIENT(gradient)) {
- SPRadialGradient *rg = SP_RADIALGRADIENT(gradient);
- Geom::Point c (rg->cx.computed, rg->cy.computed);
- pos = Geom::L2(p - c) / rg->r.computed;
- r = radius / rg->r.computed;
+ } else {
+ SPRadialGradient *rg = dynamic_cast<SPRadialGradient *>(gradient);
+ if (rg) {
+ Geom::Point c (rg->cx.computed, rg->cy.computed);
+ pos = Geom::L2(p - c) / rg->r.computed;
+ r = radius / rg->r.computed;
+ }
}
// Normalize pos to 0..1, taking into accound gradient spread:
@@ -836,14 +845,16 @@ static void tweak_colors_in_gradient(SPItem *item, Inkscape::PaintTarget fill_or
double offset_h = 0;
SPObject *child_prev = NULL;
for (SPObject *child = vector->firstChild(); child; child = child->getNext()) {
- if (!SP_IS_STOP(child)) {
+ SPStop *stop = dynamic_cast<SPStop *>(child);
+ if (!stop) {
continue;
}
- SPStop *stop = SP_STOP (child);
offset_h = stop->offset;
if (child_prev) {
+ SPStop *prevStop = dynamic_cast<SPStop *>(child_prev);
+ g_assert(prevStop != NULL);
if (offset_h - offset_l > r && pos_e >= offset_l && pos_e <= offset_h) {
// the summit falls in this interstop, and the radius is small,
@@ -853,9 +864,9 @@ static void tweak_colors_in_gradient(SPItem *item, Inkscape::PaintTarget fill_or
tweak_color (mode, stop->specified_color.v.c, rgb_goal,
force * (pos_e - offset_l) / (offset_h - offset_l),
do_h, do_s, do_l);
- tweak_color (mode, SP_STOP(child_prev)->specified_color.v.c, rgb_goal,
- force * (offset_h - pos_e) / (offset_h - offset_l),
- do_h, do_s, do_l);
+ tweak_color(mode, prevStop->specified_color.v.c, rgb_goal,
+ force * (offset_h - pos_e) / (offset_h - offset_l),
+ do_h, do_s, do_l);
stop->updateRepr();
child_prev->updateRepr();
break;
@@ -863,9 +874,9 @@ static void tweak_colors_in_gradient(SPItem *item, Inkscape::PaintTarget fill_or
// wide brush, may affect more than 2 stops,
// paint each stop by the force from the profile curve
if (offset_l <= pos_e && offset_l > pos_e - r) {
- tweak_color (mode, SP_STOP(child_prev)->specified_color.v.c, rgb_goal,
- force * tweak_profile (fabs (pos_e - offset_l), r),
- do_h, do_s, do_l);
+ tweak_color(mode, prevStop->specified_color.v.c, rgb_goal,
+ force * tweak_profile (fabs (pos_e - offset_l), r),
+ do_h, do_s, do_l);
child_prev->updateRepr();
}
@@ -894,10 +905,11 @@ sp_tweak_color_recursive (guint mode, SPItem *item, SPItem *item_at_point,
{
bool did = false;
- if (SP_IS_GROUP(item)) {
+ if (dynamic_cast<SPGroup *>(item)) {
for (SPObject *child = item->firstChild() ; child; child = child->getNext() ) {
- if (SP_IS_ITEM(child)) {
- if (sp_tweak_color_recursive (mode, SP_ITEM(child), item_at_point,
+ SPItem *childItem = dynamic_cast<SPItem *>(child);
+ if (childItem) {
+ if (sp_tweak_color_recursive (mode, childItem, item_at_point,
fill_goal, do_fill,
stroke_goal, do_stroke,
opacity_goal, do_opacity,
@@ -953,11 +965,11 @@ sp_tweak_color_recursive (guint mode, SPItem *item, SPItem *item_at_point,
//cycle through filter primitives
SPObject *primitive_obj = style->getFilter()->children;
while (primitive_obj) {
- if (SP_IS_FILTER_PRIMITIVE(primitive_obj)) {
- SPFilterPrimitive *primitive = SP_FILTER_PRIMITIVE(primitive_obj);
+ SPFilterPrimitive *primitive = dynamic_cast<SPFilterPrimitive *>(primitive_obj);
+ if (primitive) {
//if primitive is gaussianblur
- if(SP_IS_GAUSSIANBLUR(primitive)) {
- SPGaussianBlur * spblur = SP_GAUSSIANBLUR(primitive);
+ SPGaussianBlur * spblur = dynamic_cast<SPGaussianBlur *>(primitive);
+ if (spblur) {
float num = spblur->stdDeviation.getNumber();
blur_now += num * i2dt.descrim(); // sum all blurs in the filter
}
@@ -1080,7 +1092,7 @@ sp_tweak_dilate (TweakTool *tc, Geom::Point event_p, Geom::Point p, Geom::Point
items != NULL;
items = items->next) {
- SPItem *item = SP_ITEM(items->data);
+ SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(items->data));
if (is_color_mode (tc->mode)) {
if (do_fill || do_stroke || do_opacity) {
diff --git a/src/ui/tools/zoom-tool.cpp b/src/ui/tools/zoom-tool.cpp
index 9f99cfe2e..b3fb78c8f 100644
--- a/src/ui/tools/zoom-tool.cpp
+++ b/src/ui/tools/zoom-tool.cpp
@@ -25,7 +25,7 @@
#include "selection-chemistry.h"
#include "ui/tools/zoom-tool.h"
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
diff --git a/src/ui/view/view-widget.cpp b/src/ui/view/view-widget.cpp
index 5cb0df215..671a4afe6 100644
--- a/src/ui/view/view-widget.cpp
+++ b/src/ui/view/view-widget.cpp
@@ -15,32 +15,9 @@
//using namespace Inkscape::UI::View;
// SPViewWidget
-
-static void sp_view_widget_class_init(SPViewWidgetClass *vwc);
-static void sp_view_widget_init(SPViewWidget *widget);
static void sp_view_widget_dispose(GObject *object);
-static GtkEventBoxClass *widget_parent_class;
-
-GType sp_view_widget_get_type(void)
-{
- static GType type = 0;
- if (!type) {
- GTypeInfo info = {
- sizeof(SPViewWidgetClass),
- NULL, NULL,
- (GClassInitFunc) sp_view_widget_class_init,
- NULL, NULL,
- sizeof(SPViewWidget),
- 0,
- (GInstanceInitFunc) sp_view_widget_init,
- NULL
- };
- type = g_type_register_static (GTK_TYPE_EVENT_BOX, "SPViewWidget", &info, (GTypeFlags)0);
- }
-
- return type;
-}
+G_DEFINE_TYPE(SPViewWidget, sp_view_widget, GTK_TYPE_EVENT_BOX);
/**
* Callback to initialize the SPViewWidget vtable.
@@ -48,8 +25,6 @@ GType sp_view_widget_get_type(void)
static void sp_view_widget_class_init(SPViewWidgetClass *vwc)
{
GObjectClass *object_class = G_OBJECT_CLASS(vwc);
-
- widget_parent_class = (GtkEventBoxClass*) g_type_class_peek_parent(vwc);
object_class->dispose = sp_view_widget_dispose;
}
@@ -77,8 +52,8 @@ static void sp_view_widget_dispose(GObject *object)
vw->view = NULL;
}
- if (((GObjectClass *) (widget_parent_class))->dispose) {
- (* ((GObjectClass *) (widget_parent_class))->dispose)(object);
+ if (G_OBJECT_CLASS(sp_view_widget_parent_class)->dispose) {
+ G_OBJECT_CLASS(sp_view_widget_parent_class)->dispose(object);
}
Inkscape::GC::request_early_collection();
diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert
index 608dd5334..e18b790bd 100644
--- a/src/ui/widget/Makefile_insert
+++ b/src/ui/widget/Makefile_insert
@@ -83,5 +83,14 @@ ink_common_sources += \
ui/widget/unit-menu.cpp \
ui/widget/unit-menu.h \
ui/widget/unit-tracker.h \
- ui/widget/unit-tracker.cpp
-
+ ui/widget/unit-tracker.cpp \
+ ui/widget/clipmaskicon.cpp \
+ ui/widget/clipmaskicon.h \
+ ui/widget/highlight-picker.cpp \
+ ui/widget/highlight-picker.h \
+ ui/widget/layertypeicon.cpp \
+ ui/widget/layertypeicon.h \
+ ui/widget/insertordericon.cpp \
+ ui/widget/insertordericon.h \
+ ui/widget/addtoicon.cpp \
+ ui/widget/addtoicon.h
diff --git a/src/ui/widget/addtoicon.cpp b/src/ui/widget/addtoicon.cpp
new file mode 100644
index 000000000..0798d1c98
--- /dev/null
+++ b/src/ui/widget/addtoicon.cpp
@@ -0,0 +1,156 @@
+/*
+ * Authors:
+ * Theodore Janeczko
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+# include <glibmm/threads.h>
+#endif
+
+#include "ui/widget/addtoicon.h"
+
+#include <gtkmm/icontheme.h>
+
+#include "widgets/icon.h"
+#include "widgets/toolbox.h"
+#include "ui/icon-names.h"
+#include "layertypeicon.h"
+#include "addtoicon.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+AddToIcon::AddToIcon() :
+ Glib::ObjectBase(typeid(AddToIcon)),
+ Gtk::CellRendererPixbuf(),
+// _pixAddName(INKSCAPE_ICON("layer-new")),
+ _property_active(*this, "active", false)
+// _property_pixbuf_add(*this, "pixbuf_on", Glib::RefPtr<Gdk::Pixbuf>(0))
+{
+ property_mode() = Gtk::CELL_RENDERER_MODE_ACTIVATABLE;
+ phys = sp_icon_get_phys_size((int)Inkscape::ICON_SIZE_BUTTON);
+// Glib::RefPtr<Gtk::IconTheme> icon_theme = Gtk::IconTheme::get_default();
+//
+// if (!icon_theme->has_icon(_pixAddName)) {
+// Inkscape::queueIconPrerender( INKSCAPE_ICON(_pixAddName.data()), Inkscape::ICON_SIZE_DECORATION );
+// }
+// if (icon_theme->has_icon(_pixAddName)) {
+// _property_pixbuf_add = icon_theme->load_icon(_pixAddName, phys, (Gtk::IconLookupFlags)0);
+// }
+//
+// _property_pixbuf_add = Gtk::Widget::
+
+ property_stock_id() = GTK_STOCK_ADD;
+}
+
+
+#if WITH_GTKMM_3_0
+void AddToIcon::get_preferred_height_vfunc(Gtk::Widget& widget,
+ int& min_h,
+ int& nat_h) const
+{
+ Gtk::CellRendererPixbuf::get_preferred_height_vfunc(widget, min_h, nat_h);
+
+ if (min_h) {
+ min_h += (min_h) >> 1;
+ }
+
+ if (nat_h) {
+ nat_h += (nat_h) >> 1;
+ }
+}
+
+void AddToIcon::get_preferred_width_vfunc(Gtk::Widget& widget,
+ int& min_w,
+ int& nat_w) const
+{
+ Gtk::CellRendererPixbuf::get_preferred_width_vfunc(widget, min_w, nat_w);
+
+ if (min_w) {
+ min_w += (min_w) >> 1;
+ }
+
+ if (nat_w) {
+ nat_w += (nat_w) >> 1;
+ }
+}
+#else
+void AddToIcon::get_size_vfunc(Gtk::Widget& widget,
+ const Gdk::Rectangle* cell_area,
+ int* x_offset,
+ int* y_offset,
+ int* width,
+ int* height ) const
+{
+ Gtk::CellRendererPixbuf::get_size_vfunc( widget, cell_area, x_offset, y_offset, width, height );
+
+ if ( width ) {
+ *width = phys;//+= (*width) >> 1;
+ }
+ if ( height ) {
+ *height =phys;//+= (*height) >> 1;
+ }
+}
+#endif
+
+#if WITH_GTKMM_3_0
+void AddToIcon::render_vfunc( const Cairo::RefPtr<Cairo::Context>& cr,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ Gtk::CellRendererState flags )
+#else
+void AddToIcon::render_vfunc( const Glib::RefPtr<Gdk::Drawable>& window,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ const Gdk::Rectangle& expose_area,
+ Gtk::CellRendererState flags )
+#endif
+{
+ property_stock_id() = property_active().get_value() ? GTK_STOCK_ADD : GTK_STOCK_DELETE;
+
+#if WITH_GTKMM_3_0
+ Gtk::CellRendererPixbuf::render_vfunc( cr, widget, background_area, cell_area, flags );
+#else
+ Gtk::CellRendererPixbuf::render_vfunc( window, widget, background_area, cell_area, expose_area, flags );
+#endif
+}
+
+bool AddToIcon::activate_vfunc(GdkEvent* /*event*/,
+ Gtk::Widget& /*widget*/,
+ const Glib::ustring& /*path*/,
+ const Gdk::Rectangle& /*background_area*/,
+ const Gdk::Rectangle& /*cell_area*/,
+ Gtk::CellRendererState /*flags*/)
+{
+ return false;
+}
+
+
+} // namespace Widget
+} // 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/widget/addtoicon.h b/src/ui/widget/addtoicon.h
new file mode 100644
index 000000000..9c134d231
--- /dev/null
+++ b/src/ui/widget/addtoicon.h
@@ -0,0 +1,98 @@
+#ifndef __UI_DIALOG_ADDTOICON_H__
+#define __UI_DIALOG_ADDTOICON_H__
+/*
+ * Authors:
+ * Theodore Janeczko
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gtkmm/cellrendererpixbuf.h>
+#include <gtkmm/widget.h>
+#include <glibmm/property.h>
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+class AddToIcon : public Gtk::CellRendererPixbuf {
+public:
+ AddToIcon();
+ virtual ~AddToIcon() {};
+
+ Glib::PropertyProxy<bool> property_active() { return _property_active.get_proxy(); }
+ Glib::PropertyProxy< Glib::RefPtr<Gdk::Pixbuf> > property_pixbuf_on();
+ Glib::PropertyProxy< Glib::RefPtr<Gdk::Pixbuf> > property_pixbuf_off();
+
+protected:
+
+#if WITH_GTKMM_3_0
+ virtual void render_vfunc( const Cairo::RefPtr<Cairo::Context>& cr,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ Gtk::CellRendererState flags );
+
+ virtual void get_preferred_width_vfunc(Gtk::Widget& widget,
+ int& min_w,
+ int& nat_w) const;
+
+ virtual void get_preferred_height_vfunc(Gtk::Widget& widget,
+ int& min_h,
+ int& nat_h) const;
+#else
+ virtual void render_vfunc( const Glib::RefPtr<Gdk::Drawable>& window,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ const Gdk::Rectangle& expose_area,
+ Gtk::CellRendererState flags );
+
+ virtual void get_size_vfunc( Gtk::Widget &widget,
+ Gdk::Rectangle const *cell_area,
+ int *x_offset, int *y_offset, int *width, int *height ) const;
+#endif
+
+ virtual bool activate_vfunc(GdkEvent *event,
+ Gtk::Widget &widget,
+ const Glib::ustring &path,
+ const Gdk::Rectangle &background_area,
+ const Gdk::Rectangle &cell_area,
+ Gtk::CellRendererState flags);
+
+
+private:
+ int phys;
+
+// Glib::ustring _pixAddName;
+
+ Glib::Property<bool> _property_active;
+// Glib::Property< Glib::RefPtr<Gdk::Pixbuf> > _property_pixbuf_add;
+
+};
+
+
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+
+#endif /* __UI_DIALOG_IMAGETOGGLER_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/widget/anchor-selector.cpp b/src/ui/widget/anchor-selector.cpp
index 82e27ee89..df00b786a 100644
--- a/src/ui/widget/anchor-selector.cpp
+++ b/src/ui/widget/anchor-selector.cpp
@@ -28,7 +28,11 @@ void AnchorSelector::setupButton(const Glib::ustring& icon, Gtk::ToggleButton& b
AnchorSelector::AnchorSelector()
: Gtk::Alignment(0.5, 0, 0, 0),
+#if WITH_GTKMM_3_0
+ _container()
+#else
_container(3, 3, true)
+#endif
{
setupButton(INKSCAPE_ICON("boundingbox_top_left"), _buttons[0]);
setupButton(INKSCAPE_ICON("boundingbox_top"), _buttons[1]);
@@ -40,10 +44,20 @@ AnchorSelector::AnchorSelector()
setupButton(INKSCAPE_ICON("boundingbox_bottom"), _buttons[7]);
setupButton(INKSCAPE_ICON("boundingbox_bottom_right"), _buttons[8]);
+#if WITH_GTKMM_3_0
+ _container.set_row_homogeneous();
+ _container.set_column_homogeneous(true);
+#endif
+
for(int i = 0; i < 9; ++i) {
_buttons[i].signal_clicked().connect(
sigc::bind(sigc::mem_fun(*this, &AnchorSelector::btn_activated), i));
+
+#if WITH_GTKMM_3_0
+ _container.attach(_buttons[i], i % 3, i / 3, 1, 1);
+#else
_container.attach(_buttons[i], i % 3, i % 3+1, i / 3, i / 3+1, Gtk::FILL, Gtk::FILL);
+#endif
}
_selection = 4;
_buttons[4].set_active();
@@ -94,4 +108,4 @@ void AnchorSelector::setAlignment(int horizontal, int vertical)
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/ui/widget/anchor-selector.h b/src/ui/widget/anchor-selector.h
index 2263438e3..0a702d296 100644
--- a/src/ui/widget/anchor-selector.h
+++ b/src/ui/widget/anchor-selector.h
@@ -10,7 +10,18 @@
#ifndef ANCHOR_SELECTOR_H_
#define ANCHOR_SELECTOR_H_
-#include <gtkmm.h>
+#if HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include <gtkmm/alignment.h>
+#include <gtkmm/togglebutton.h>
+
+#if WITH_GTKMM_3_0
+ #include <gtkmm/grid.h>
+#else
+ #include <gtkmm/table.h>
+#endif
namespace Inkscape {
namespace UI {
@@ -21,7 +32,12 @@ class AnchorSelector : public Gtk::Alignment
private:
Gtk::ToggleButton _buttons[9];
int _selection;
+
+#if WITH_GTKMM_3_0
+ Gtk::Grid _container;
+#else
Gtk::Table _container;
+#endif
sigc::signal<void> _selectionChanged;
@@ -56,4 +72,4 @@ public:
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/ui/widget/button.cpp b/src/ui/widget/button.cpp
index bac866920..6c2d419cf 100644
--- a/src/ui/widget/button.cpp
+++ b/src/ui/widget/button.cpp
@@ -51,13 +51,13 @@ RadioButton::RadioButton(Glib::ustring const &label, Glib::ustring const &toolti
} // namespace UI
} // namespace Inkscape
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/button.h b/src/ui/widget/button.h
index a214dd881..471b7d8a2 100644
--- a/src/ui/widget/button.h
+++ b/src/ui/widget/button.h
@@ -67,13 +67,13 @@ public:
#endif // INKSCAPE_UI_WIDGET_BUTTON_H
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/clipmaskicon.cpp b/src/ui/widget/clipmaskicon.cpp
new file mode 100644
index 000000000..943b1bebc
--- /dev/null
+++ b/src/ui/widget/clipmaskicon.cpp
@@ -0,0 +1,183 @@
+/*
+ * Authors:
+ * Theodore Janeczko
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+# include <glibmm/threads.h>
+#endif
+
+#include "ui/widget/clipmaskicon.h"
+
+#include <gtkmm/icontheme.h>
+
+#include "widgets/icon.h"
+#include "widgets/toolbox.h"
+#include "ui/icon-names.h"
+#include "layertypeicon.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+ClipMaskIcon::ClipMaskIcon() :
+ Glib::ObjectBase(typeid(ClipMaskIcon)),
+ Gtk::CellRendererPixbuf(),
+ _pixClipName(INKSCAPE_ICON("path-intersection")),
+ _pixInverseName(INKSCAPE_ICON("path-difference")),
+ _pixMaskName(INKSCAPE_ICON("mask-intersection")),
+ _property_active(*this, "active", 0),
+ _property_pixbuf_clip(*this, "pixbuf_on", Glib::RefPtr<Gdk::Pixbuf>(0)),
+ _property_pixbuf_inverse(*this, "pixbuf_on", Glib::RefPtr<Gdk::Pixbuf>(0)),
+ _property_pixbuf_mask(*this, "pixbuf_off", Glib::RefPtr<Gdk::Pixbuf>(0))
+{
+
+ property_mode() = Gtk::CELL_RENDERER_MODE_ACTIVATABLE;
+ phys = sp_icon_get_phys_size((int)Inkscape::ICON_SIZE_DECORATION);
+ Glib::RefPtr<Gtk::IconTheme> icon_theme = Gtk::IconTheme::get_default();
+
+ if (!icon_theme->has_icon(_pixClipName)) {
+ Inkscape::queueIconPrerender( INKSCAPE_ICON(_pixClipName.data()), Inkscape::ICON_SIZE_DECORATION );
+ }
+ if (!icon_theme->has_icon(_pixInverseName)) {
+ Inkscape::queueIconPrerender( INKSCAPE_ICON(_pixInverseName.data()), Inkscape::ICON_SIZE_DECORATION );
+ }
+ if (!icon_theme->has_icon(_pixMaskName)) {
+ Inkscape::queueIconPrerender( INKSCAPE_ICON(_pixMaskName.data()), Inkscape::ICON_SIZE_DECORATION );
+ }
+
+ if (icon_theme->has_icon(_pixClipName)) {
+ _property_pixbuf_clip = icon_theme->load_icon(_pixClipName, phys, (Gtk::IconLookupFlags)0);
+ }
+ if (icon_theme->has_icon(_pixInverseName)) {
+ _property_pixbuf_inverse = icon_theme->load_icon(_pixInverseName, phys, (Gtk::IconLookupFlags)0);
+ }
+ if (icon_theme->has_icon(_pixMaskName)) {
+ _property_pixbuf_mask = icon_theme->load_icon(_pixMaskName, phys, (Gtk::IconLookupFlags)0);
+ }
+
+ property_pixbuf() = Glib::RefPtr<Gdk::Pixbuf>(0);
+}
+
+
+#if WITH_GTKMM_3_0
+void ClipMaskIcon::get_preferred_height_vfunc(Gtk::Widget& widget,
+ int& min_h,
+ int& nat_h) const
+{
+ Gtk::CellRendererPixbuf::get_preferred_height_vfunc(widget, min_h, nat_h);
+
+ if (min_h) {
+ min_h += (min_h) >> 1;
+ }
+
+ if (nat_h) {
+ nat_h += (nat_h) >> 1;
+ }
+}
+
+void ClipMaskIcon::get_preferred_width_vfunc(Gtk::Widget& widget,
+ int& min_w,
+ int& nat_w) const
+{
+ Gtk::CellRendererPixbuf::get_preferred_width_vfunc(widget, min_w, nat_w);
+
+ if (min_w) {
+ min_w += (min_w) >> 1;
+ }
+
+ if (nat_w) {
+ nat_w += (nat_w) >> 1;
+ }
+}
+#else
+void ClipMaskIcon::get_size_vfunc(Gtk::Widget& widget,
+ const Gdk::Rectangle* cell_area,
+ int* x_offset,
+ int* y_offset,
+ int* width,
+ int* height ) const
+{
+ Gtk::CellRendererPixbuf::get_size_vfunc( widget, cell_area, x_offset, y_offset, width, height );
+
+ if ( width ) {
+ *width = phys;//+= (*width) >> 1;
+ }
+ if ( height ) {
+ *height =phys;//+= (*height) >> 1;
+ }
+}
+#endif
+
+#if WITH_GTKMM_3_0
+void ClipMaskIcon::render_vfunc( const Cairo::RefPtr<Cairo::Context>& cr,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ Gtk::CellRendererState flags )
+#else
+void ClipMaskIcon::render_vfunc( const Glib::RefPtr<Gdk::Drawable>& window,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ const Gdk::Rectangle& expose_area,
+ Gtk::CellRendererState flags )
+#endif
+{
+ switch (_property_active.get_value())
+ {
+ case 1:
+ property_pixbuf() = _property_pixbuf_clip;
+ break;
+ case 2:
+ property_pixbuf() = _property_pixbuf_mask;
+ break;
+ case 3:
+ property_pixbuf() = _property_pixbuf_inverse;
+ break;
+ default:
+ property_pixbuf() = Glib::RefPtr<Gdk::Pixbuf>(0);
+ break;
+ }
+#if WITH_GTKMM_3_0
+ Gtk::CellRendererPixbuf::render_vfunc( cr, widget, background_area, cell_area, flags );
+#else
+ Gtk::CellRendererPixbuf::render_vfunc( window, widget, background_area, cell_area, expose_area, flags );
+#endif
+}
+
+bool ClipMaskIcon::activate_vfunc(GdkEvent* /*event*/,
+ Gtk::Widget& /*widget*/,
+ const Glib::ustring& /*path*/,
+ const Gdk::Rectangle& /*background_area*/,
+ const Gdk::Rectangle& /*cell_area*/,
+ Gtk::CellRendererState /*flags*/)
+{
+ return false;
+}
+
+
+} // namespace Widget
+} // 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/widget/clipmaskicon.h b/src/ui/widget/clipmaskicon.h
new file mode 100644
index 000000000..eca852a83
--- /dev/null
+++ b/src/ui/widget/clipmaskicon.h
@@ -0,0 +1,102 @@
+#ifndef __UI_DIALOG_CLIPMASKICON_H__
+#define __UI_DIALOG_CLIPMASKICON_H__
+/*
+ * Authors:
+ * Theodore Janeczko
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gtkmm/cellrendererpixbuf.h>
+#include <gtkmm/widget.h>
+#include <glibmm/property.h>
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+class ClipMaskIcon : public Gtk::CellRendererPixbuf {
+public:
+ ClipMaskIcon();
+ virtual ~ClipMaskIcon() {};
+
+ Glib::PropertyProxy<int> property_active() { return _property_active.get_proxy(); }
+ Glib::PropertyProxy< Glib::RefPtr<Gdk::Pixbuf> > property_pixbuf_on();
+ Glib::PropertyProxy< Glib::RefPtr<Gdk::Pixbuf> > property_pixbuf_off();
+
+protected:
+
+#if WITH_GTKMM_3_0
+ virtual void render_vfunc( const Cairo::RefPtr<Cairo::Context>& cr,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ Gtk::CellRendererState flags );
+
+ virtual void get_preferred_width_vfunc(Gtk::Widget& widget,
+ int& min_w,
+ int& nat_w) const;
+
+ virtual void get_preferred_height_vfunc(Gtk::Widget& widget,
+ int& min_h,
+ int& nat_h) const;
+#else
+ virtual void render_vfunc( const Glib::RefPtr<Gdk::Drawable>& window,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ const Gdk::Rectangle& expose_area,
+ Gtk::CellRendererState flags );
+
+ virtual void get_size_vfunc( Gtk::Widget &widget,
+ Gdk::Rectangle const *cell_area,
+ int *x_offset, int *y_offset, int *width, int *height ) const;
+#endif
+
+ virtual bool activate_vfunc(GdkEvent *event,
+ Gtk::Widget &widget,
+ const Glib::ustring &path,
+ const Gdk::Rectangle &background_area,
+ const Gdk::Rectangle &cell_area,
+ Gtk::CellRendererState flags);
+
+
+private:
+ int phys;
+
+ Glib::ustring _pixClipName;
+ Glib::ustring _pixInverseName;
+ Glib::ustring _pixMaskName;
+
+ Glib::Property<int> _property_active;
+ Glib::Property< Glib::RefPtr<Gdk::Pixbuf> > _property_pixbuf_clip;
+ Glib::Property< Glib::RefPtr<Gdk::Pixbuf> > _property_pixbuf_inverse;
+ Glib::Property< Glib::RefPtr<Gdk::Pixbuf> > _property_pixbuf_mask;
+
+};
+
+
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+
+#endif /* __UI_DIALOG_IMAGETOGGLER_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/widget/color-picker.cpp b/src/ui/widget/color-picker.cpp
index 5585f2db4..6b5a351f6 100644
--- a/src/ui/widget/color-picker.cpp
+++ b/src/ui/widget/color-picker.cpp
@@ -15,7 +15,7 @@
#include "desktop-handles.h"
#include "document.h"
#include "document-undo.h"
-#include "dialogs/dialog-events.h"
+#include "ui/dialog-events.h"
#include "widgets/sp-color-notebook.h"
#include "verbs.h"
diff --git a/src/ui/widget/entity-entry.cpp b/src/ui/widget/entity-entry.cpp
index 0f526f77a..c7d5efe29 100644
--- a/src/ui/widget/entity-entry.cpp
+++ b/src/ui/widget/entity-entry.cpp
@@ -206,9 +206,9 @@ EntityMultiLineEntry::on_changed()
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/entity-entry.h b/src/ui/widget/entity-entry.h
index 09289496d..35f6ecfb4 100644
--- a/src/ui/widget/entity-entry.h
+++ b/src/ui/widget/entity-entry.h
@@ -76,9 +76,9 @@ protected:
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/filter-effect-chooser.cpp b/src/ui/widget/filter-effect-chooser.cpp
index 65706a9dc..4754b9c23 100644
--- a/src/ui/widget/filter-effect-chooser.cpp
+++ b/src/ui/widget/filter-effect-chooser.cpp
@@ -23,6 +23,8 @@ namespace Widget {
SimpleFilterModifier::SimpleFilterModifier(int flags)
: _lb_blend(_("Blend mode:")),
+ _lb_blur(_("_Blur:")),
+ _lb_blur_unit(_("%")),
_blend(BlendModeConverter, SP_ATTR_INVALID, false),
_blur(_("Blur (%)"), 0, 0, 100, 1, 0.01, 1)
{
@@ -56,15 +58,12 @@ const Glib::ustring SimpleFilterModifier::get_blend_mode()
if (!(_flags & BLEND)) {
return "normal";
}
- if (_blend.get_active_row_number() == 5) {
+
+ const Util::EnumData<Inkscape::Filters::FilterBlendMode> *d = _blend.get_active_data();
+ if (d) {
+ return _blend.get_active_data()->key;
+ } else
return "normal";
- } else {
- const Util::EnumData<Inkscape::Filters::FilterBlendMode> *d = _blend.get_active_data();
- if (d) {
- return _blend.get_active_data()->key;
- } else
- return "normal";
- }
}
void SimpleFilterModifier::set_blend_mode(const int val)
diff --git a/src/ui/widget/filter-effect-chooser.h b/src/ui/widget/filter-effect-chooser.h
index 8d2389b15..6092c61a5 100644
--- a/src/ui/widget/filter-effect-chooser.h
+++ b/src/ui/widget/filter-effect-chooser.h
@@ -53,11 +53,13 @@ public:
double get_blur_value() const;
void set_blur_value(const double);
void set_blur_sensitive(const bool);
+ Gtk::Label *get_blur_label() { return &_lb_blur; };
private:
int _flags;
Gtk::HBox _hb_blend;
- Gtk::Label _lb_blend;
+ Gtk::HBox _hb_blur;
+ Gtk::Label _lb_blend, _lb_blur, _lb_blur_unit;
ComboBoxEnum<Inkscape::Filters::FilterBlendMode> _blend;
SpinScale _blur;
diff --git a/src/ui/widget/highlight-picker.cpp b/src/ui/widget/highlight-picker.cpp
new file mode 100644
index 000000000..09999b52d
--- /dev/null
+++ b/src/ui/widget/highlight-picker.cpp
@@ -0,0 +1,206 @@
+/*
+ * Authors:
+ * Theodore Janeczko
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glibmm.h>
+#include <gtkmm/icontheme.h>
+
+#include "display/cairo-utils.h"
+
+#include "highlight-picker.h"
+#include "widgets/icon.h"
+#include "widgets/toolbox.h"
+#include "ui/icon-names.h"
+#include <glibmm/i18n.h>
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+HighlightPicker::HighlightPicker() :
+ Glib::ObjectBase(typeid(HighlightPicker)),
+ Gtk::CellRendererPixbuf(),
+ _property_active(*this, "active", 0)
+{
+
+ property_mode() = Gtk::CELL_RENDERER_MODE_ACTIVATABLE;
+}
+
+HighlightPicker::~HighlightPicker()
+{
+}
+
+
+#if WITH_GTKMM_3_0
+void HighlightPicker::get_preferred_height_vfunc(Gtk::Widget& widget,
+ int& min_h,
+ int& nat_h) const
+{
+ Gtk::CellRendererPixbuf::get_preferred_height_vfunc(widget, min_h, nat_h);
+
+ if (min_h) {
+ min_h += (min_h) >> 1;
+ }
+
+ if (nat_h) {
+ nat_h += (nat_h) >> 1;
+ }
+}
+
+void HighlightPicker::get_preferred_width_vfunc(Gtk::Widget& widget,
+ int& min_w,
+ int& nat_w) const
+{
+ Gtk::CellRendererPixbuf::get_preferred_width_vfunc(widget, min_w, nat_w);
+
+ if (min_w) {
+ min_w += (min_w) >> 1;
+ }
+
+ if (nat_w) {
+ nat_w += (nat_w) >> 1;
+ }
+}
+#else
+void HighlightPicker::get_size_vfunc(Gtk::Widget& widget,
+ const Gdk::Rectangle* cell_area,
+ int* x_offset,
+ int* y_offset,
+ int* width,
+ int* height ) const
+{
+ Gtk::CellRendererPixbuf::get_size_vfunc( widget, cell_area, x_offset, y_offset, width, height );
+
+ if ( width ) {
+ *width = 10;//+= (*width) >> 1;
+ }
+ if ( height ) {
+ *height = 20; //cell_area ? cell_area->get_height() / 2 : 50; //+= (*height) >> 1;
+ }
+}
+#endif
+
+#if WITH_GTKMM_3_0
+void HighlightPicker::render_vfunc( const Cairo::RefPtr<Cairo::Context>& cr,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ Gtk::CellRendererState flags )
+#else
+void HighlightPicker::render_vfunc( const Glib::RefPtr<Gdk::Drawable>& window,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ const Gdk::Rectangle& expose_area,
+ Gtk::CellRendererState flags )
+#endif
+{
+ GdkRectangle carea;
+
+ cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 20);
+ cairo_t *ct = cairo_create(s);
+
+ /* Transparent area */
+ carea.x = 0;
+ carea.y = 0;
+ carea.width = 10;
+ carea.height = 20;
+
+ cairo_pattern_t *checkers = ink_cairo_pattern_create_checkerboard();
+
+ cairo_rectangle(ct, carea.x, carea.y, carea.width, carea.height / 2);
+ cairo_set_source(ct, checkers);
+ cairo_fill_preserve(ct);
+ ink_cairo_set_source_rgba32(ct, _property_active.get_value());
+ cairo_fill(ct);
+
+ cairo_pattern_destroy(checkers);
+
+ cairo_rectangle(ct, carea.x, carea.y + carea.height / 2, carea.width, carea.height / 2);
+ ink_cairo_set_source_rgba32(ct, _property_active.get_value() | 0x000000ff);
+ cairo_fill(ct);
+
+ cairo_rectangle(ct, carea.x, carea.y, carea.width, carea.height);
+ ink_cairo_set_source_rgba32(ct, 0x333333ff);
+ cairo_set_line_width(ct, 2);
+ cairo_stroke(ct);
+
+ cairo_destroy(ct);
+ cairo_surface_flush(s);
+
+ GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( cairo_image_surface_get_data(s),
+ GDK_COLORSPACE_RGB, TRUE, 8,
+ 10, 20, cairo_image_surface_get_stride(s),
+ ink_cairo_pixbuf_cleanup, s);
+ convert_pixbuf_argb32_to_normal(pixbuf);
+
+ property_pixbuf() = Glib::wrap(pixbuf);
+#if WITH_GTKMM_3_0
+ Gtk::CellRendererPixbuf::render_vfunc( cr, widget, background_area, cell_area, flags );
+#else
+ Gtk::CellRendererPixbuf::render_vfunc( window, widget, background_area, cell_area, expose_area, flags );
+#endif
+}
+
+bool HighlightPicker::activate_vfunc(GdkEvent* /*event*/,
+ Gtk::Widget& /*widget*/,
+ const Glib::ustring& /*path*/,
+ const Gdk::Rectangle& /*background_area*/,
+ const Gdk::Rectangle& /*cell_area*/,
+ Gtk::CellRendererState /*flags*/)
+{
+ return false;
+}
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+//should be okay to put this here
+/**
+ * Converts GdkPixbuf's data to premultiplied ARGB.
+ * This function will convert a GdkPixbuf in place into Cairo's native pixel format.
+ * Note that this is a hack intended to save memory. When the pixbuf is in Cairo's format,
+ * using it with GTK will result in corrupted drawings.
+ */
+void
+convert_pixbuf_normal_to_argb32(GdkPixbuf *pb)
+{
+ convert_pixels_pixbuf_to_argb32(
+ gdk_pixbuf_get_pixels(pb),
+ gdk_pixbuf_get_width(pb),
+ gdk_pixbuf_get_height(pb),
+ gdk_pixbuf_get_rowstride(pb));
+}
+
+/**
+ * Converts GdkPixbuf's data back to its native format.
+ * Once this is done, the pixbuf can be used with GTK again.
+ */
+void
+convert_pixbuf_argb32_to_normal(GdkPixbuf *pb)
+{
+ convert_pixels_argb32_to_pixbuf(
+ gdk_pixbuf_get_pixels(pb),
+ gdk_pixbuf_get_width(pb),
+ gdk_pixbuf_get_height(pb),
+ gdk_pixbuf_get_rowstride(pb));
+}
+
+/*
+ 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/widget/highlight-picker.h b/src/ui/widget/highlight-picker.h
new file mode 100644
index 000000000..c5fe4c02c
--- /dev/null
+++ b/src/ui/widget/highlight-picker.h
@@ -0,0 +1,90 @@
+#ifndef __UI_DIALOG_HIGHLIGHT_PICKER_H__
+#define __UI_DIALOG_HIGHLIGHT_PICKER_H__
+/*
+ * Authors:
+ * Theodore Janeczko
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gtkmm/cellrendererpixbuf.h>
+#include <gtkmm/widget.h>
+#include <glibmm/property.h>
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+class HighlightPicker : public Gtk::CellRendererPixbuf {
+public:
+ HighlightPicker();
+ virtual ~HighlightPicker();
+
+ Glib::PropertyProxy<guint32> property_active() { return _property_active.get_proxy(); }
+
+protected:
+
+#if WITH_GTKMM_3_0
+ virtual void render_vfunc( const Cairo::RefPtr<Cairo::Context>& cr,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ Gtk::CellRendererState flags );
+
+ virtual void get_preferred_width_vfunc(Gtk::Widget& widget,
+ int& min_w,
+ int& nat_w) const;
+
+ virtual void get_preferred_height_vfunc(Gtk::Widget& widget,
+ int& min_h,
+ int& nat_h) const;
+#else
+ virtual void render_vfunc( const Glib::RefPtr<Gdk::Drawable>& window,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ const Gdk::Rectangle& expose_area,
+ Gtk::CellRendererState flags );
+
+ virtual void get_size_vfunc( Gtk::Widget &widget,
+ Gdk::Rectangle const *cell_area,
+ int *x_offset, int *y_offset, int *width, int *height ) const;
+#endif
+
+ virtual bool activate_vfunc(GdkEvent *event,
+ Gtk::Widget &widget,
+ const Glib::ustring &path,
+ const Gdk::Rectangle &background_area,
+ const Gdk::Rectangle &cell_area,
+ Gtk::CellRendererState flags);
+
+private:
+
+ Glib::Property<guint32> _property_active;
+};
+
+
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+
+#endif /* __UI_DIALOG_IMAGETOGGLER_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/widget/insertordericon.cpp b/src/ui/widget/insertordericon.cpp
new file mode 100644
index 000000000..9aec7d135
--- /dev/null
+++ b/src/ui/widget/insertordericon.cpp
@@ -0,0 +1,164 @@
+/*
+ * Authors:
+ * Theodore Janeczko
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "ui/widget/insertordericon.h"
+
+#include <gtkmm/icontheme.h>
+
+#include "widgets/icon.h"
+#include "widgets/toolbox.h"
+#include "ui/icon-names.h"
+#include "layertypeicon.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+InsertOrderIcon::InsertOrderIcon() :
+ Glib::ObjectBase(typeid(InsertOrderIcon)),
+ Gtk::CellRendererPixbuf(),
+ _pixTopName(INKSCAPE_ICON("insert-top")),
+ _pixBottomName(INKSCAPE_ICON("insert-bottom")),
+ _property_active(*this, "active", 0),
+ _property_pixbuf_top(*this, "pixbuf_on", Glib::RefPtr<Gdk::Pixbuf>(0)),
+ _property_pixbuf_bottom(*this, "pixbuf_on", Glib::RefPtr<Gdk::Pixbuf>(0))
+{
+
+ property_mode() = Gtk::CELL_RENDERER_MODE_ACTIVATABLE;
+ phys = sp_icon_get_phys_size((int)Inkscape::ICON_SIZE_DECORATION);
+ Glib::RefPtr<Gtk::IconTheme> icon_theme = Gtk::IconTheme::get_default();
+
+ if (!icon_theme->has_icon(_pixTopName)) {
+ Inkscape::queueIconPrerender( INKSCAPE_ICON(_pixTopName.data()), Inkscape::ICON_SIZE_DECORATION );
+ }
+ if (!icon_theme->has_icon(_pixBottomName)) {
+ Inkscape::queueIconPrerender( INKSCAPE_ICON(_pixBottomName.data()), Inkscape::ICON_SIZE_DECORATION );
+ }
+
+ if (icon_theme->has_icon(_pixTopName)) {
+ _property_pixbuf_top = icon_theme->load_icon(_pixTopName, phys, (Gtk::IconLookupFlags)0);
+ }
+ if (icon_theme->has_icon(_pixBottomName)) {
+ _property_pixbuf_bottom = icon_theme->load_icon(_pixBottomName, phys, (Gtk::IconLookupFlags)0);
+ }
+
+ property_pixbuf() = Glib::RefPtr<Gdk::Pixbuf>(0);
+}
+
+
+#if WITH_GTKMM_3_0
+void InsertOrderIcon::get_preferred_height_vfunc(Gtk::Widget& widget,
+ int& min_h,
+ int& nat_h) const
+{
+ Gtk::CellRendererPixbuf::get_preferred_height_vfunc(widget, min_h, nat_h);
+
+ if (min_h) {
+ min_h += (min_h) >> 1;
+ }
+
+ if (nat_h) {
+ nat_h += (nat_h) >> 1;
+ }
+}
+
+void InsertOrderIcon::get_preferred_width_vfunc(Gtk::Widget& widget,
+ int& min_w,
+ int& nat_w) const
+{
+ Gtk::CellRendererPixbuf::get_preferred_width_vfunc(widget, min_w, nat_w);
+
+ if (min_w) {
+ min_w += (min_w) >> 1;
+ }
+
+ if (nat_w) {
+ nat_w += (nat_w) >> 1;
+ }
+}
+#else
+void InsertOrderIcon::get_size_vfunc(Gtk::Widget& widget,
+ const Gdk::Rectangle* cell_area,
+ int* x_offset,
+ int* y_offset,
+ int* width,
+ int* height ) const
+{
+ Gtk::CellRendererPixbuf::get_size_vfunc( widget, cell_area, x_offset, y_offset, width, height );
+
+ if ( width ) {
+ *width = phys;//+= (*width) >> 1;
+ }
+ if ( height ) {
+ *height =phys;//+= (*height) >> 1;
+ }
+}
+#endif
+
+#if WITH_GTKMM_3_0
+void InsertOrderIcon::render_vfunc( const Cairo::RefPtr<Cairo::Context>& cr,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ Gtk::CellRendererState flags )
+#else
+void InsertOrderIcon::render_vfunc( const Glib::RefPtr<Gdk::Drawable>& window,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ const Gdk::Rectangle& expose_area,
+ Gtk::CellRendererState flags )
+#endif
+{
+ switch (_property_active.get_value())
+ {
+ case 1:
+ property_pixbuf() = _property_pixbuf_top;
+ break;
+ case 2:
+ property_pixbuf() = _property_pixbuf_bottom;
+ break;
+ default:
+ property_pixbuf() = Glib::RefPtr<Gdk::Pixbuf>(0);
+ break;
+ }
+#if WITH_GTKMM_3_0
+ Gtk::CellRendererPixbuf::render_vfunc( cr, widget, background_area, cell_area, flags );
+#else
+ Gtk::CellRendererPixbuf::render_vfunc( window, widget, background_area, cell_area, expose_area, flags );
+#endif
+}
+
+bool InsertOrderIcon::activate_vfunc(GdkEvent* /*event*/,
+ Gtk::Widget& /*widget*/,
+ const Glib::ustring& /*path*/,
+ const Gdk::Rectangle& /*background_area*/,
+ const Gdk::Rectangle& /*cell_area*/,
+ Gtk::CellRendererState /*flags*/)
+{
+ return false;
+}
+
+
+} // namespace Widget
+} // 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/widget/insertordericon.h b/src/ui/widget/insertordericon.h
new file mode 100644
index 000000000..fb3412d3f
--- /dev/null
+++ b/src/ui/widget/insertordericon.h
@@ -0,0 +1,100 @@
+#ifndef __UI_DIALOG_INSERTORDERICON_H__
+#define __UI_DIALOG_INSERTORDERICON_H__
+/*
+ * Authors:
+ * Theodore Janeczko
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glibmm.h>
+#include <gtkmm/cellrendererpixbuf.h>
+#include <gtkmm/widget.h>
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+class InsertOrderIcon : public Gtk::CellRendererPixbuf {
+public:
+ InsertOrderIcon();
+ virtual ~InsertOrderIcon() {};
+
+ Glib::PropertyProxy<int> property_active() { return _property_active.get_proxy(); }
+ Glib::PropertyProxy< Glib::RefPtr<Gdk::Pixbuf> > property_pixbuf_on();
+ Glib::PropertyProxy< Glib::RefPtr<Gdk::Pixbuf> > property_pixbuf_off();
+
+protected:
+
+#if WITH_GTKMM_3_0
+ virtual void render_vfunc( const Cairo::RefPtr<Cairo::Context>& cr,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ Gtk::CellRendererState flags );
+
+ virtual void get_preferred_width_vfunc(Gtk::Widget& widget,
+ int& min_w,
+ int& nat_w) const;
+
+ virtual void get_preferred_height_vfunc(Gtk::Widget& widget,
+ int& min_h,
+ int& nat_h) const;
+#else
+ virtual void render_vfunc( const Glib::RefPtr<Gdk::Drawable>& window,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ const Gdk::Rectangle& expose_area,
+ Gtk::CellRendererState flags );
+
+ virtual void get_size_vfunc( Gtk::Widget &widget,
+ Gdk::Rectangle const *cell_area,
+ int *x_offset, int *y_offset, int *width, int *height ) const;
+#endif
+
+ virtual bool activate_vfunc(GdkEvent *event,
+ Gtk::Widget &widget,
+ const Glib::ustring &path,
+ const Gdk::Rectangle &background_area,
+ const Gdk::Rectangle &cell_area,
+ Gtk::CellRendererState flags);
+
+
+private:
+ int phys;
+
+ Glib::ustring _pixTopName;
+ Glib::ustring _pixBottomName;
+
+ Glib::Property<int> _property_active;
+ Glib::Property< Glib::RefPtr<Gdk::Pixbuf> > _property_pixbuf_top;
+ Glib::Property< Glib::RefPtr<Gdk::Pixbuf> > _property_pixbuf_bottom;
+
+};
+
+
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+
+#endif /* __UI_DIALOG_IMAGETOGGLER_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/widget/layertypeicon.cpp b/src/ui/widget/layertypeicon.cpp
new file mode 100644
index 000000000..3d6182bf8
--- /dev/null
+++ b/src/ui/widget/layertypeicon.cpp
@@ -0,0 +1,174 @@
+/*
+ * Authors:
+ * Theodore Janeczko
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
+# include <glibmm/threads.h>
+#endif
+
+#include "ui/widget/layertypeicon.h"
+
+#include <gtkmm/icontheme.h>
+
+#include "widgets/icon.h"
+#include "widgets/toolbox.h"
+#include "ui/icon-names.h"
+#include "layertypeicon.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+LayerTypeIcon::LayerTypeIcon() :
+ Glib::ObjectBase(typeid(LayerTypeIcon)),
+ Gtk::CellRendererPixbuf(),
+ _pixLayerName(INKSCAPE_ICON("dialog-layers")),
+ _pixGroupName(INKSCAPE_ICON("layer-duplicate")),
+ _pixPathName(INKSCAPE_ICON("layer-rename")),
+ _property_active(*this, "active", false),
+ _property_activatable(*this, "activatable", true),
+ _property_pixbuf_layer(*this, "pixbuf_on", Glib::RefPtr<Gdk::Pixbuf>(0)),
+ _property_pixbuf_group(*this, "pixbuf_off", Glib::RefPtr<Gdk::Pixbuf>(0)),
+ _property_pixbuf_path(*this, "pixbuf_off", Glib::RefPtr<Gdk::Pixbuf>(0))
+{
+
+ property_mode() = Gtk::CELL_RENDERER_MODE_ACTIVATABLE;
+ int phys = sp_icon_get_phys_size((int)Inkscape::ICON_SIZE_DECORATION);
+ Glib::RefPtr<Gtk::IconTheme> icon_theme = Gtk::IconTheme::get_default();
+
+ if (!icon_theme->has_icon(_pixLayerName)) {
+ Inkscape::queueIconPrerender( INKSCAPE_ICON(_pixLayerName.data()), Inkscape::ICON_SIZE_DECORATION );
+ }
+ if (!icon_theme->has_icon(_pixGroupName)) {
+ Inkscape::queueIconPrerender( INKSCAPE_ICON(_pixGroupName.data()), Inkscape::ICON_SIZE_DECORATION );
+ }
+ if (!icon_theme->has_icon(_pixPathName)) {
+ Inkscape::queueIconPrerender( INKSCAPE_ICON(_pixPathName.data()), Inkscape::ICON_SIZE_DECORATION );
+ }
+
+ if (icon_theme->has_icon(_pixLayerName)) {
+ _property_pixbuf_layer = icon_theme->load_icon(_pixLayerName, phys, (Gtk::IconLookupFlags)0);
+ }
+ if (icon_theme->has_icon(_pixGroupName)) {
+ _property_pixbuf_group = icon_theme->load_icon(_pixGroupName, phys, (Gtk::IconLookupFlags)0);
+ }
+ if (icon_theme->has_icon(_pixPathName)) {
+ _property_pixbuf_path = icon_theme->load_icon(_pixPathName, phys, (Gtk::IconLookupFlags)0);
+ }
+
+ property_pixbuf() = _property_pixbuf_path.get_value();
+}
+
+
+#if WITH_GTKMM_3_0
+void LayerTypeIcon::get_preferred_height_vfunc(Gtk::Widget& widget,
+ int& min_h,
+ int& nat_h) const
+{
+ Gtk::CellRendererPixbuf::get_preferred_height_vfunc(widget, min_h, nat_h);
+
+ if (min_h) {
+ min_h += (min_h) >> 1;
+ }
+
+ if (nat_h) {
+ nat_h += (nat_h) >> 1;
+ }
+}
+
+void LayerTypeIcon::get_preferred_width_vfunc(Gtk::Widget& widget,
+ int& min_w,
+ int& nat_w) const
+{
+ Gtk::CellRendererPixbuf::get_preferred_width_vfunc(widget, min_w, nat_w);
+
+ if (min_w) {
+ min_w += (min_w) >> 1;
+ }
+
+ if (nat_w) {
+ nat_w += (nat_w) >> 1;
+ }
+}
+#else
+void LayerTypeIcon::get_size_vfunc(Gtk::Widget& widget,
+ const Gdk::Rectangle* cell_area,
+ int* x_offset,
+ int* y_offset,
+ int* width,
+ int* height ) const
+{
+ Gtk::CellRendererPixbuf::get_size_vfunc( widget, cell_area, x_offset, y_offset, width, height );
+
+ if ( width ) {
+ *width += (*width) >> 1;
+ }
+ if ( height ) {
+ *height += (*height) >> 1;
+ }
+}
+#endif
+
+#if WITH_GTKMM_3_0
+void LayerTypeIcon::render_vfunc( const Cairo::RefPtr<Cairo::Context>& cr,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ Gtk::CellRendererState flags )
+#else
+void LayerTypeIcon::render_vfunc( const Glib::RefPtr<Gdk::Drawable>& window,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ const Gdk::Rectangle& expose_area,
+ Gtk::CellRendererState flags )
+#endif
+{
+ property_pixbuf() = _property_active.get_value() == 1 ? _property_pixbuf_group : (_property_active.get_value() == 2 ? _property_pixbuf_layer : _property_pixbuf_path);
+#if WITH_GTKMM_3_0
+ Gtk::CellRendererPixbuf::render_vfunc( cr, widget, background_area, cell_area, flags );
+#else
+ Gtk::CellRendererPixbuf::render_vfunc( window, widget, background_area, cell_area, expose_area, flags );
+#endif
+}
+
+bool
+LayerTypeIcon::activate_vfunc(GdkEvent* event,
+ Gtk::Widget& /*widget*/,
+ const Glib::ustring& path,
+ const Gdk::Rectangle& /*background_area*/,
+ const Gdk::Rectangle& /*cell_area*/,
+ Gtk::CellRendererState /*flags*/)
+{
+ _signal_pre_toggle.emit(event);
+ _signal_toggled.emit(path);
+
+ return false;
+}
+
+
+} // namespace Widget
+} // 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/widget/layertypeicon.h b/src/ui/widget/layertypeicon.h
new file mode 100644
index 000000000..6c71ce361
--- /dev/null
+++ b/src/ui/widget/layertypeicon.h
@@ -0,0 +1,108 @@
+#ifndef __UI_DIALOG_LAYERTYPEICON_H__
+#define __UI_DIALOG_LAYERTYPEICON_H__
+/*
+ * Authors:
+ * Theodore Janeczko
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gtkmm/cellrendererpixbuf.h>
+#include <gtkmm/widget.h>
+#include <glibmm/property.h>
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+class LayerTypeIcon : public Gtk::CellRendererPixbuf {
+public:
+ LayerTypeIcon();
+ virtual ~LayerTypeIcon() {};
+
+ sigc::signal<void, const Glib::ustring&> signal_toggled() { return _signal_toggled;}
+ sigc::signal<void, GdkEvent const *> signal_pre_toggle() { return _signal_pre_toggle; }
+
+ Glib::PropertyProxy<int> property_active() { return _property_active.get_proxy(); }
+ Glib::PropertyProxy<int> property_activatable() { return _property_activatable.get_proxy(); }
+ Glib::PropertyProxy< Glib::RefPtr<Gdk::Pixbuf> > property_pixbuf_on();
+ Glib::PropertyProxy< Glib::RefPtr<Gdk::Pixbuf> > property_pixbuf_off();
+
+protected:
+
+#if WITH_GTKMM_3_0
+ virtual void render_vfunc( const Cairo::RefPtr<Cairo::Context>& cr,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ Gtk::CellRendererState flags );
+
+ virtual void get_preferred_width_vfunc(Gtk::Widget& widget,
+ int& min_w,
+ int& nat_w) const;
+
+ virtual void get_preferred_height_vfunc(Gtk::Widget& widget,
+ int& min_h,
+ int& nat_h) const;
+#else
+ virtual void render_vfunc( const Glib::RefPtr<Gdk::Drawable>& window,
+ Gtk::Widget& widget,
+ const Gdk::Rectangle& background_area,
+ const Gdk::Rectangle& cell_area,
+ const Gdk::Rectangle& expose_area,
+ Gtk::CellRendererState flags );
+
+ virtual void get_size_vfunc( Gtk::Widget &widget,
+ Gdk::Rectangle const *cell_area,
+ int *x_offset, int *y_offset, int *width, int *height ) const;
+#endif
+
+ virtual bool activate_vfunc(GdkEvent *event,
+ Gtk::Widget &widget,
+ const Glib::ustring &path,
+ const Gdk::Rectangle &background_area,
+ const Gdk::Rectangle &cell_area,
+ Gtk::CellRendererState flags);
+
+
+private:
+ Glib::ustring _pixLayerName;
+ Glib::ustring _pixGroupName;
+ Glib::ustring _pixPathName;
+
+ Glib::Property<int> _property_active;
+ Glib::Property<int> _property_activatable;
+ Glib::Property< Glib::RefPtr<Gdk::Pixbuf> > _property_pixbuf_layer;
+ Glib::Property< Glib::RefPtr<Gdk::Pixbuf> > _property_pixbuf_group;
+ Glib::Property< Glib::RefPtr<Gdk::Pixbuf> > _property_pixbuf_path;
+
+ sigc::signal<void, const Glib::ustring&> _signal_toggled;
+ sigc::signal<void, GdkEvent const *> _signal_pre_toggle;
+
+};
+
+
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+
+#endif /* __UI_DIALOG_IMAGETOGGLER_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/widget/licensor.cpp b/src/ui/widget/licensor.cpp
index 42f352e3c..7429bb07e 100644
--- a/src/ui/widget/licensor.cpp
+++ b/src/ui/widget/licensor.cpp
@@ -160,9 +160,9 @@ void Licensor::update (SPDocument *doc)
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/licensor.h b/src/ui/widget/licensor.h
index 0ac3e5ab8..c75c5fe9e 100644
--- a/src/ui/widget/licensor.h
+++ b/src/ui/widget/licensor.h
@@ -56,9 +56,9 @@ protected:
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/notebook-page.cpp b/src/ui/widget/notebook-page.cpp
index 6653499b8..2f03ed23b 100644
--- a/src/ui/widget/notebook-page.cpp
+++ b/src/ui/widget/notebook-page.cpp
@@ -44,13 +44,13 @@ NotebookPage::NotebookPage(int n_rows, int n_columns, bool expand, bool fill, gu
} // namespace UI
} // namespace Inkscape
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/notebook-page.h b/src/ui/widget/notebook-page.h
index 38ae9e054..4f7915423 100644
--- a/src/ui/widget/notebook-page.h
+++ b/src/ui/widget/notebook-page.h
@@ -67,13 +67,13 @@ protected:
#endif // INKSCAPE_UI_WIDGET_NOTEBOOK_PAGE_H
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/object-composite-settings.cpp b/src/ui/widget/object-composite-settings.cpp
index 537db0fdd..e4cd76345 100644
--- a/src/ui/widget/object-composite-settings.cpp
+++ b/src/ui/widget/object-composite-settings.cpp
@@ -40,7 +40,7 @@ namespace UI {
namespace Widget {
/*void ObjectCompositeSettings::_on_desktop_activate(
- Inkscape::Application *application,
+ InkscapeApplication *application,
SPDesktop *desktop,
ObjectCompositeSettings *w
) {
@@ -50,7 +50,7 @@ namespace Widget {
}
void ObjectCompositeSettings::_on_desktop_deactivate(
- Inkscape::Application *application,
+ InkscapeApplication *application,
SPDesktop *desktop,
ObjectCompositeSettings *w
) {
diff --git a/src/ui/widget/object-composite-settings.h b/src/ui/widget/object-composite-settings.h
index 19a6cb2a5..e375bf24a 100644
--- a/src/ui/widget/object-composite-settings.h
+++ b/src/ui/widget/object-composite-settings.h
@@ -30,9 +30,9 @@
#include "ui/widget/spinbutton.h"
class SPDesktop;
+struct InkscapeApplication;
namespace Inkscape {
-struct Application;
namespace UI {
namespace Widget {
@@ -66,8 +66,8 @@ private:
gulong _desktop_activated;
sigc::connection _subject_changed;
- static void _on_desktop_activate(Inkscape::Application *application, SPDesktop *desktop, ObjectCompositeSettings *w);
- static void _on_desktop_deactivate(Inkscape::Application *application, SPDesktop *desktop, ObjectCompositeSettings *w);
+ static void _on_desktop_activate(InkscapeApplication *application, SPDesktop *desktop, ObjectCompositeSettings *w);
+ static void _on_desktop_deactivate(InkscapeApplication *application, SPDesktop *desktop, ObjectCompositeSettings *w);
void _subjectChanged();
void _blendBlurValueChanged();
void _opacityValueChanged();
diff --git a/src/ui/widget/page-sizer.cpp b/src/ui/widget/page-sizer.cpp
index eae0d4a95..32e357c57 100644
--- a/src/ui/widget/page-sizer.cpp
+++ b/src/ui/widget/page-sizer.cpp
@@ -311,8 +311,8 @@ PageSizer::PageSizer(Registry & _wr)
SPDesktop *dt = SP_ACTIVE_DESKTOP;
SPNamedView *nv = sp_desktop_namedview(dt);
_wr.setUpdating (true);
- if (nv->units) {
- _dimensionUnits.setUnit(nv->units->abbr);
+ if (nv->page_size_units) {
+ _dimensionUnits.setUnit(nv->page_size_units->abbr);
} else if (nv->doc_units) {
_dimensionUnits.setUnit(nv->doc_units->abbr);
}
@@ -728,9 +728,9 @@ PageSizer::on_units_changed()
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/page-sizer.h b/src/ui/widget/page-sizer.h
index dc8e34d82..f4bcae4b6 100644
--- a/src/ui/widget/page-sizer.h
+++ b/src/ui/widget/page-sizer.h
@@ -277,9 +277,9 @@ protected:
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/panel.cpp b/src/ui/widget/panel.cpp
index b37137228..0abd81b16 100644
--- a/src/ui/widget/panel.cpp
+++ b/src/ui/widget/panel.cpp
@@ -643,13 +643,13 @@ Panel::signalDocumentReplaced()
return _signal_document_replaced;
}
-sigc::signal<void, Inkscape::Application *, SPDesktop *> &
+sigc::signal<void, InkscapeApplication *, SPDesktop *> &
Panel::signalActivateDesktop()
{
return _signal_activate_desktop;
}
-sigc::signal<void, Inkscape::Application *, SPDesktop *> &
+sigc::signal<void, InkscapeApplication *, SPDesktop *> &
Panel::signalDeactiveDesktop()
{
return _signal_deactive_desktop;
diff --git a/src/ui/widget/panel.h b/src/ui/widget/panel.h
index 0c3d822b8..177314797 100644
--- a/src/ui/widget/panel.h
+++ b/src/ui/widget/panel.h
@@ -45,9 +45,9 @@ namespace Gtk {
class MenuItem;
}
-namespace Inkscape {
+struct InkscapeApplication;
-struct Application;
+namespace Inkscape {
class Selection;
namespace UI {
@@ -116,8 +116,8 @@ public:
void setResponseSensitive(int response_id, bool setting);
virtual sigc::signal<void, SPDesktop *, SPDocument *> &signalDocumentReplaced();
- virtual sigc::signal<void, Inkscape::Application *, SPDesktop *> &signalActivateDesktop();
- virtual sigc::signal<void, Inkscape::Application *, SPDesktop *> &signalDeactiveDesktop();
+ virtual sigc::signal<void, InkscapeApplication *, SPDesktop *> &signalActivateDesktop();
+ virtual sigc::signal<void, InkscapeApplication *, SPDesktop *> &signalDeactiveDesktop();
protected:
/**
@@ -147,8 +147,8 @@ protected:
sigc::signal<void, int> _signal_response;
sigc::signal<void> _signal_present;
sigc::signal<void, SPDesktop *, SPDocument *> _signal_document_replaced;
- sigc::signal<void, Inkscape::Application *, SPDesktop *> _signal_activate_desktop;
- sigc::signal<void, Inkscape::Application *, SPDesktop *> _signal_deactive_desktop;
+ sigc::signal<void, InkscapeApplication *, SPDesktop *> _signal_activate_desktop;
+ sigc::signal<void, InkscapeApplication *, SPDesktop *> _signal_deactive_desktop;
private:
void _init();
diff --git a/src/ui/widget/preferences-widget.cpp b/src/ui/widget/preferences-widget.cpp
index 3ba00c083..7f3e6cd47 100644
--- a/src/ui/widget/preferences-widget.cpp
+++ b/src/ui/widget/preferences-widget.cpp
@@ -14,10 +14,6 @@
# include <config.h>
#endif
-#ifdef WIN32
-#include <windows.h>
-#endif
-
#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
#include <glibmm/threads.h>
#endif
@@ -49,6 +45,10 @@
#include <glibmm/convert.h>
#include <glibmm/i18n.h>
+#ifdef WIN32
+#include <windows.h>
+#endif
+
using namespace Inkscape::UI::Widget;
namespace Inkscape {
diff --git a/src/ui/widget/preferences-widget.h b/src/ui/widget/preferences-widget.h
index cb4ce17d1..5d9816e74 100644
--- a/src/ui/widget/preferences-widget.h
+++ b/src/ui/widget/preferences-widget.h
@@ -306,9 +306,9 @@ public:
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/registered-widget.cpp b/src/ui/widget/registered-widget.cpp
index 92cb3f03d..e97285de4 100644
--- a/src/ui/widget/registered-widget.cpp
+++ b/src/ui/widget/registered-widget.cpp
@@ -99,6 +99,59 @@ RegisteredCheckButton::on_toggled()
_wr->setUpdating (false);
}
+/*#########################################
+ * Registered TOGGLEBUTTON
+ */
+
+RegisteredToggleButton::~RegisteredToggleButton()
+{
+ _toggled_connection.disconnect();
+}
+
+RegisteredToggleButton::RegisteredToggleButton (const Glib::ustring& /*label*/, const Glib::ustring& tip, const Glib::ustring& key, Registry& wr, bool right, Inkscape::XML::Node* repr_in, SPDocument *doc_in, char const *active_str, char const *inactive_str)
+ : RegisteredWidget<Gtk::ToggleButton>()
+ , _active_str(active_str)
+ , _inactive_str(inactive_str)
+{
+ init_parent(key, wr, repr_in, doc_in);
+ setProgrammatically = false;
+ set_tooltip_text (tip);
+ set_alignment (right? 1.0 : 0.0, 0.5);
+ _toggled_connection = signal_toggled().connect (sigc::mem_fun (*this, &RegisteredToggleButton::on_toggled));
+}
+
+void
+RegisteredToggleButton::setActive (bool b)
+{
+ setProgrammatically = true;
+ set_active (b);
+ //The slave button is greyed out if the master button is untoggled
+ for (std::list<Gtk::Widget*>::const_iterator i = _slavewidgets.begin(); i != _slavewidgets.end(); ++i) {
+ (*i)->set_sensitive(b);
+ }
+ setProgrammatically = false;
+}
+
+void
+RegisteredToggleButton::on_toggled()
+{
+ if (setProgrammatically) {
+ setProgrammatically = false;
+ return;
+ }
+
+ if (_wr->isUpdating())
+ return;
+ _wr->setUpdating (true);
+
+ write_to_xml(get_active() ? _active_str : _inactive_str);
+ //The slave button is greyed out if the master button is untoggled
+ for (std::list<Gtk::Widget*>::const_iterator i = _slavewidgets.begin(); i != _slavewidgets.end(); ++i) {
+ (*i)->set_sensitive(get_active());
+ }
+
+ _wr->setUpdating (false);
+}
/*#########################################
* Registered UNITMENU
@@ -735,9 +788,9 @@ RegisteredRandom::on_value_changed()
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/registered-widget.h b/src/ui/widget/registered-widget.h
index d64c09c16..1f505a3cd 100644
--- a/src/ui/widget/registered-widget.h
+++ b/src/ui/widget/registered-widget.h
@@ -163,6 +163,31 @@ protected:
void on_toggled();
};
+class RegisteredToggleButton : public RegisteredWidget<Gtk::ToggleButton> {
+public:
+ virtual ~RegisteredToggleButton();
+ RegisteredToggleButton (const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Registry& wr, bool right=true, Inkscape::XML::Node* repr_in=NULL, SPDocument *doc_in=NULL, char const *active_str = "true", char const *inactive_str = "false");
+
+ void setActive (bool);
+
+ std::list<Gtk::Widget*> _slavewidgets;
+
+ // a slave button is only sensitive when the master button is active
+ // i.e. a slave button is greyed-out when the master button is not checked
+
+ void setSlaveWidgets(std::list<Gtk::Widget*> btns) {
+ _slavewidgets = btns;
+ }
+
+ bool setProgrammatically; // true if the value was set by setActive, not changed by the user;
+ // if a callback checks it, it must reset it back to false
+
+protected:
+ char const *_active_str, *_inactive_str;
+ sigc::connection _toggled_connection;
+ void on_toggled();
+};
+
class RegisteredUnitMenu : public RegisteredWidget<Labelled> {
public:
~RegisteredUnitMenu();
@@ -394,9 +419,9 @@ protected:
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/registry.cpp b/src/ui/widget/registry.cpp
index 725e52791..ea8198422 100644
--- a/src/ui/widget/registry.cpp
+++ b/src/ui/widget/registry.cpp
@@ -48,9 +48,9 @@ Registry::setUpdating (bool upd)
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/registry.h b/src/ui/widget/registry.h
index 2da29735c..a236b96ad 100644
--- a/src/ui/widget/registry.h
+++ b/src/ui/widget/registry.h
@@ -39,9 +39,9 @@ protected:
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/rendering-options.cpp b/src/ui/widget/rendering-options.cpp
index d6248df69..837387f7b 100644
--- a/src/ui/widget/rendering-options.cpp
+++ b/src/ui/widget/rendering-options.cpp
@@ -12,6 +12,9 @@
# include <config.h>
#endif
+#include <gtkmm.h>
+
+#include "preferences.h"
#include "rendering-options.h"
#include "util/units.h"
#include <glibmm/i18n.h>
@@ -38,6 +41,7 @@ RenderingOptions::RenderingOptions () :
Glib::ustring(""), Glib::ustring(""),
false)
{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
// set up tooltips
_radio_vector.set_tooltip_text(
_("Render using Cairo vector operations. "
@@ -52,15 +56,21 @@ RenderingOptions::RenderingOptions () :
set_border_width(2);
- // default to vector operations
- _radio_vector.set_active (true);
Gtk::RadioButtonGroup group = _radio_vector.get_group ();
_radio_bitmap.set_group (group);
_radio_bitmap.signal_toggled().connect(sigc::mem_fun(*this, &RenderingOptions::_toggled));
-
+
+ // default to vector operations
+ if (prefs->getBool("/dialogs/printing/asbitmap", false)) {
+ _radio_bitmap.set_active();
+ } else {
+ _radio_vector.set_active();
+ }
+
// configure default DPI
_dpi.setRange(Inkscape::Util::Quantity::convert(1, "in", "pt"),2400.0);
- _dpi.setValue(Inkscape::Util::Quantity::convert(1, "in", "pt"));
+ _dpi.setValue(prefs->getDouble("/dialogs/printing/dpi",
+ Inkscape::Util::Quantity::convert(1, "in", "pt")));
_dpi.setIncrements(1.0,10.0);
_dpi.setDigits(0);
_dpi.update();
diff --git a/src/ui/widget/rotateable.cpp b/src/ui/widget/rotateable.cpp
index 72ec69362..2d7597d7c 100644
--- a/src/ui/widget/rotateable.cpp
+++ b/src/ui/widget/rotateable.cpp
@@ -173,13 +173,13 @@ Rotateable::~Rotateable() {
} // namespace UI
} // namespace Inkscape
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/rotateable.h b/src/ui/widget/rotateable.h
index 52fb5306c..6404c3550 100644
--- a/src/ui/widget/rotateable.h
+++ b/src/ui/widget/rotateable.h
@@ -62,9 +62,9 @@ private:
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/selected-style.cpp b/src/ui/widget/selected-style.cpp
index 042a6614e..d22c59aa4 100644
--- a/src/ui/widget/selected-style.cpp
+++ b/src/ui/widget/selected-style.cpp
@@ -25,6 +25,7 @@
#include "desktop-style.h"
#include "sp-namedview.h"
#include "sp-linear-gradient.h"
+#include "sp-mesh-gradient.h"
#include "sp-radial-gradient.h"
#include "sp-pattern.h"
#include "ui/dialog/dialog-manager.h"
@@ -179,7 +180,11 @@ SelectedStyle::SelectedStyle(bool /*layout*/)
_na[i].show_all();
__na[i] = (_("Nothing selected"));
- _none[i].set_markup (C_("Fill and stroke", "<i>None</i>"));
+ if (i == SS_FILL) {
+ _none[i].set_markup (C_("Fill", "<i>None</i>"));
+ } else {
+ _none[i].set_markup (C_("Stroke", "<i>None</i>"));
+ }
sp_set_font_size_smaller (GTK_WIDGET(_none[i].gobj()));
_none[i].show_all();
__none[i] = (i == SS_FILL)? (C_("Fill and stroke", "No fill")) : (C_("Fill and stroke", "No stroke"));
@@ -209,6 +214,18 @@ SelectedStyle::SelectedStyle(bool /*layout*/)
_gradient_box_r[i].pack_start(*(Glib::wrap(_gradient_preview_r[i])));
_gradient_box_r[i].show_all();
+#ifdef WITH_MESH
+ _mgradient[i].set_markup (_("<b>M</b>"));
+ sp_set_font_size_smaller (GTK_WIDGET(_mgradient[i].gobj()));
+ _mgradient[i].show_all();
+ __mgradient[i] = (i == SS_FILL)? (_("Mesh gradient fill")) : (_("Mesh gradient stroke"));
+
+ _gradient_preview_m[i] = GTK_WIDGET(sp_gradient_image_new (NULL));
+ _gradient_box_m[i].pack_start(_mgradient[i]);
+ _gradient_box_m[i].pack_start(*(Glib::wrap(_gradient_preview_m[i])));
+ _gradient_box_m[i].show_all();
+#endif
+
_many[i].set_markup (_("Different"));
sp_set_font_size_smaller (GTK_WIDGET(_many[i].gobj()));
_many[i].show_all();
@@ -1028,6 +1045,14 @@ SelectedStyle::update()
place->add(_gradient_box_r[i]);
place->set_tooltip_text(__rgradient[i]);
_mode[i] = SS_RGRADIENT;
+#ifdef WITH_MESH
+ } else if (SP_IS_MESHGRADIENT(server)) {
+ SPGradient *vector = SP_GRADIENT(server)->getVector();
+ sp_gradient_image_set_gradient(SP_GRADIENT_IMAGE(_gradient_preview_m[i]), vector);
+ place->add(_gradient_box_m[i]);
+ place->set_tooltip_text(__mgradient[i]);
+ _mode[i] = SS_MGRADIENT;
+#endif
} else if (SP_IS_PATTERN (server)) {
place->add(_pattern[i]);
place->set_tooltip_text(__pattern[i]);
@@ -1195,7 +1220,9 @@ void SelectedStyle::on_opacity_menu (Gtk::Menu *menu) {
menu->show_all();
}
-void SelectedStyle::on_opacity_changed () {
+void SelectedStyle::on_opacity_changed ()
+{
+ g_return_if_fail(_desktop); // TODO this shouldn't happen!
if (_opacity_blocked)
return;
_opacity_blocked = true;
@@ -1550,9 +1577,9 @@ Dialog::FillAndStroke *get_fill_and_stroke_panel(SPDesktop *desktop)
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/selected-style.h b/src/ui/widget/selected-style.h
index 9557a8d74..0b6a14762 100644
--- a/src/ui/widget/selected-style.h
+++ b/src/ui/widget/selected-style.h
@@ -60,6 +60,9 @@ enum {
SS_PATTERN,
SS_LGRADIENT,
SS_RGRADIENT,
+#ifdef WITH_MESH
+ SS_MGRADIENT,
+#endif
SS_MANY,
SS_COLOR
};
@@ -186,6 +189,14 @@ protected:
GtkWidget *_gradient_preview_r[2];
Gtk::HBox _gradient_box_r[2];
+#ifdef WITH_MESH
+ Gtk::Label _mgradient[2];
+ Glib::ustring __mgradient[2];
+
+ GtkWidget *_gradient_preview_m[2];
+ Gtk::HBox _gradient_box_m[2];
+#endif
+
Gtk::Label _many[2];
Glib::ustring __many[2];
@@ -290,13 +301,13 @@ protected:
#endif // INKSCAPE_UI_WIDGET_BUTTON_H
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/spin-scale.cpp b/src/ui/widget/spin-scale.cpp
index ade3d1e60..bb08d67df 100644
--- a/src/ui/widget/spin-scale.cpp
+++ b/src/ui/widget/spin-scale.cpp
@@ -235,13 +235,13 @@ void DualSpinScale::update_linked()
} // namespace UI
} // namespace Inkscape
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/spin-scale.h b/src/ui/widget/spin-scale.h
index 5fec8b1d8..d0447e4a6 100644
--- a/src/ui/widget/spin-scale.h
+++ b/src/ui/widget/spin-scale.h
@@ -113,13 +113,13 @@ private:
#endif // INKSCAPE_UI_WIDGET_SPIN_SCALE_H
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/spin-slider.cpp b/src/ui/widget/spin-slider.cpp
index 1cb59a7b3..9b361ae78 100644
--- a/src/ui/widget/spin-slider.cpp
+++ b/src/ui/widget/spin-slider.cpp
@@ -262,13 +262,13 @@ void DualSpinSlider::update_linked()
} // namespace UI
} // namespace Inkscape
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/spin-slider.h b/src/ui/widget/spin-slider.h
index 5f86fd15a..74982ea58 100644
--- a/src/ui/widget/spin-slider.h
+++ b/src/ui/widget/spin-slider.h
@@ -111,13 +111,13 @@ private:
#endif // INKSCAPE_UI_WIDGET_SPIN_SLIDER_H
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/spinbutton.cpp b/src/ui/widget/spinbutton.cpp
index 7709a837b..d7669d4e5 100644
--- a/src/ui/widget/spinbutton.cpp
+++ b/src/ui/widget/spinbutton.cpp
@@ -100,13 +100,13 @@ void SpinButton::undo()
} // namespace UI
} // namespace Inkscape
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/spinbutton.h b/src/ui/widget/spinbutton.h
index 812b5f515..cbe33e8ea 100644
--- a/src/ui/widget/spinbutton.h
+++ b/src/ui/widget/spinbutton.h
@@ -111,13 +111,13 @@ private:
#endif // INKSCAPE_UI_WIDGET_SPINBUTTON_H
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/style-subject.h b/src/ui/widget/style-subject.h
index c2941d995..47da91732 100644
--- a/src/ui/widget/style-subject.h
+++ b/src/ui/widget/style-subject.h
@@ -20,7 +20,7 @@
class SPDesktop;
class SPObject;
class SPCSSAttr;
-struct SPStyle;
+class SPStyle;
namespace Inkscape {
class Selection;
diff --git a/src/ui/widget/style-swatch.cpp b/src/ui/widget/style-swatch.cpp
index a33c1d09f..157fd2ad9 100644
--- a/src/ui/widget/style-swatch.cpp
+++ b/src/ui/widget/style-swatch.cpp
@@ -261,7 +261,7 @@ void StyleSwatch::setStyle(SPCSSAttr *css)
Glib::ustring css_string;
sp_repr_css_write_string (_css, css_string);
SPStyle *temp_spstyle = sp_style_new(SP_ACTIVE_DOCUMENT);
- if (~css_string.empty()) {
+ if (!css_string.empty()) {
sp_style_merge_from_style_string (temp_spstyle, css_string.c_str());
}
@@ -386,9 +386,9 @@ void StyleSwatch::setStyle(SPStyle *query)
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/style-swatch.h b/src/ui/widget/style-swatch.h
index 23ecbdfda..582d2ebb3 100644
--- a/src/ui/widget/style-swatch.h
+++ b/src/ui/widget/style-swatch.h
@@ -29,7 +29,7 @@
#include "desktop.h"
#include "preferences.h"
-struct SPStyle;
+class SPStyle;
class SPCSSAttr;
namespace Gtk {
@@ -108,13 +108,13 @@ friend class ToolObserver;
#endif // INKSCAPE_UI_WIDGET_BUTTON_H
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/tolerance-slider.cpp b/src/ui/widget/tolerance-slider.cpp
index 5fc588fdc..aac7451f4 100644
--- a/src/ui/widget/tolerance-slider.cpp
+++ b/src/ui/widget/tolerance-slider.cpp
@@ -216,9 +216,9 @@ void ToleranceSlider::update (double val)
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/tolerance-slider.h b/src/ui/widget/tolerance-slider.h
index 2184cd52b..7ae8e4712 100644
--- a/src/ui/widget/tolerance-slider.h
+++ b/src/ui/widget/tolerance-slider.h
@@ -88,9 +88,9 @@ protected:
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/unit-menu.cpp b/src/ui/widget/unit-menu.cpp
index 7416a2f02..423313a1f 100644
--- a/src/ui/widget/unit-menu.cpp
+++ b/src/ui/widget/unit-menu.cpp
@@ -140,13 +140,13 @@ bool UnitMenu::isRadial() const
} // namespace UI
} // namespace Inkscape
-/*
+/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/unit-menu.h b/src/ui/widget/unit-menu.h
index 114c536c9..2fd25a6a9 100644
--- a/src/ui/widget/unit-menu.h
+++ b/src/ui/widget/unit-menu.h
@@ -141,9 +141,9 @@ protected:
Local Variables:
mode:c++
c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0))
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
-// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/unit-tracker.cpp b/src/ui/widget/unit-tracker.cpp
index 67eb1f48d..c6318db25 100644
--- a/src/ui/widget/unit-tracker.cpp
+++ b/src/ui/widget/unit-tracker.cpp
@@ -13,7 +13,7 @@
*/
#include "unit-tracker.h"
-#include "ege-select-one-action.h"
+#include "widgets/ege-select-one-action.h"
#define COLUMN_STRING 0
diff --git a/src/ui/widget/unit-tracker.h b/src/ui/widget/unit-tracker.h
index 61bb556ef..06245930e 100644
--- a/src/ui/widget/unit-tracker.h
+++ b/src/ui/widget/unit-tracker.h
@@ -16,13 +16,16 @@
#define INKSCAPE_UI_WIDGET_UNIT_TRACKER_H
#include <map>
-#include <gtk/gtk.h>
-
#include "util/units.h"
using Inkscape::Util::Unit;
using Inkscape::Util::UnitType;
+typedef struct _GObject GObject;
+typedef struct _GtkAction GtkAction;
+typedef struct _GtkAdjustment GtkAdjustment;
+typedef struct _GtkListStore GtkListStore;
+
namespace Inkscape {
namespace UI {
namespace Widget {