summaryrefslogtreecommitdiffstats
path: root/src/ui
diff options
context:
space:
mode:
authorLiam P. White <inkscapebrony@gmail.com>2014-10-29 22:40:05 +0000
committerLiam P. White <inkscapebrony@gmail.com>2014-10-29 22:40:05 +0000
commite9943b70c7bf507b9639ecb0a421bcee7ce93e33 (patch)
tree2d2fe7ee7a566e1ef1a5dcde18296d9f21188f35 /src/ui
parenti18n. Fixing untranslated strings. (diff)
parentMerge with trunk r13640 (diff)
downloadinkscape-e9943b70c7bf507b9639ecb0a421bcee7ce93e33.tar.gz
inkscape-e9943b70c7bf507b9639ecb0a421bcee7ce93e33.zip
Merge experimental
(bzr r13641)
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/CMakeLists.txt15
-rw-r--r--src/ui/Makefile_insert13
-rw-r--r--src/ui/clipboard.cpp4
-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.cpp6
-rw-r--r--src/ui/dialog/aboutbox.h6
-rw-r--r--src/ui/dialog/align-and-distribute.cpp6
-rw-r--r--src/ui/dialog/calligraphic-profile-rename.h2
-rw-r--r--src/ui/dialog/clonetiler.cpp6
-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.cpp10
-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.cpp8
-rw-r--r--src/ui/dialog/document-properties.h4
-rw-r--r--src/ui/dialog/export.cpp4
-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.cpp3
-rw-r--r--src/ui/dialog/filedialogimpl-win32.h3
-rw-r--r--src/ui/dialog/fill-and-stroke.h2
-rw-r--r--src/ui/dialog/find.cpp4
-rw-r--r--src/ui/dialog/floating-behavior.cpp4
-rw-r--r--src/ui/dialog/font-substitution.cpp2
-rw-r--r--src/ui/dialog/grid-arrange-tab.cpp2
-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.h4
-rw-r--r--src/ui/dialog/lpe-fillet-chamfer-properties.cpp278
-rw-r--r--src/ui/dialog/lpe-fillet-chamfer-properties.h110
-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/polar-arrange-tab.cpp32
-rw-r--r--src/ui/dialog/polar-arrange-tab.h19
-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/tags.cpp1165
-rw-r--r--src/ui/dialog/tags.h181
-rw-r--r--src/ui/dialog/template-load-tab.cpp2
-rw-r--r--src/ui/dialog/text-edit.cpp2
-rw-r--r--src/ui/dialog/transformation.cpp4
-rw-r--r--src/ui/dialog/xml-tree.cpp4
-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.h23
-rw-r--r--src/ui/tool/path-manipulator.cpp173
-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.cpp100
-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.cpp2
-rw-r--r--src/ui/tools/mesh-tool.cpp2
-rw-r--r--src/ui/tools/node-tool.cpp22
-rw-r--r--src/ui/tools/node-tool.h3
-rw-r--r--src/ui/tools/pen-tool.cpp995
-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/select-tool.cpp4
-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.cpp2
-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.cpp8
-rw-r--r--src/ui/tools/tool-base.h4
-rw-r--r--src/ui/tools/tweak-tool.cpp2
-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.cpp157
-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.cpp184
-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.cpp2
-rw-r--r--src/ui/widget/filter-effect-chooser.h4
-rw-r--r--src/ui/widget/highlight-picker.cpp207
-rw-r--r--src/ui/widget/highlight-picker.h90
-rw-r--r--src/ui/widget/insertordericon.cpp165
-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.cpp4
-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/rotateable.cpp6
-rw-r--r--src/ui/widget/rotateable.h4
-rw-r--r--src/ui/widget/selected-style.cpp25
-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-swatch.cpp4
-rw-r--r--src/ui/widget/style-swatch.h6
-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
169 files changed, 13205 insertions, 569 deletions
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 2b9dd6e45..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
@@ -151,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
@@ -194,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 4b4b14c22..931a295d8 100644
--- a/src/ui/clipboard.cpp
+++ b/src/ui/clipboard.cpp
@@ -54,7 +54,7 @@
#include <2geom/transforms.h>
#include "box3d.h"
#include "gradient-drag.h"
-#include "marker.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"
@@ -77,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"
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..26a59ce2c 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/dialpg/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 fad10ae11..50b35ca2f 100644
--- a/src/ui/dialog/aboutbox.cpp
+++ b/src/ui/dialog/aboutbox.cpp
@@ -955,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 e02ccd3f1..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();
}
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 9b67132c0..5ef885ab2 100644
--- a/src/ui/dialog/clonetiler.cpp
+++ b/src/ui/dialog/clonetiler.cpp
@@ -38,7 +38,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 +1349,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 +1378,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);
}
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 7e69e439a..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.
@@ -110,6 +112,8 @@ DialogManager::DialogManager() {
registerFactory("Glyphs", &create<GlyphsPanel, FloatingBehavior>);
registerFactory("IconPreviewPanel", &create<IconPreviewPanel, 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>);
@@ -143,6 +147,8 @@ DialogManager::DialogManager() {
registerFactory("Glyphs", &create<GlyphsPanel, DockBehavior>);
registerFactory("IconPreviewPanel", &create<IconPreviewPanel, 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>);
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 1f220b246..dc8a0fee2 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"
@@ -1594,7 +1594,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);
@@ -1603,7 +1603,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);
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..a4d8801f7 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"
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 1eeee0592..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"
@@ -1853,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 c523f041d..f77249abd 100644
--- a/src/ui/dialog/filedialogimpl-win32.h
+++ b/src/ui/dialog/filedialogimpl-win32.h
@@ -22,13 +22,14 @@
#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/find.cpp b/src/ui/dialog/find.cpp
index 37f2761df..1a4823e4a 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"
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 6e9ecc3c8..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"
diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp
index 72217c729..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();
}
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.h b/src/ui/dialog/inkscape-preferences.h
index 9f37626ed..dcea91741 100644
--- a/src/ui/dialog/inkscape-preferences.h
+++ b/src/ui/dialog/inkscape-preferences.h
@@ -545,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/lpe-fillet-chamfer-properties.cpp b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp
new file mode 100644
index 000000000..ad8b66b8c
--- /dev/null
+++ b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp
@@ -0,0 +1,278 @@
+/**
+ * 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(2, 2);
+
+ // 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_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_double_chamfer.set_label(_("Double chamfer"));
+ _fillet_chamfer_type_double_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_double_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()
+{
+
+ _setDesktop(NULL);
+}
+
+void FilletChamferPropertiesDialog::showDialog(
+ SPDesktop *desktop, Geom::Point knotpoint,
+ const Inkscape::LivePathEffect::
+ FilletChamferPointArrayParamKnotHolderEntity *pt,
+ const gchar *unit,
+ bool use_distance,
+ bool aprox_radius)
+{
+ FilletChamferPropertiesDialog *dialog = new FilletChamferPropertiesDialog();
+
+ dialog->_setDesktop(desktop);
+ dialog->_setUnit(unit);
+ dialog->_set_use_distance(use_distance);
+ dialog->_set_aprox(aprox_radius);
+ dialog->_setKnotPoint(knotpoint);
+ dialog->_setPt(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_chamfer.get_active() == true) {
+ d_width = 3;
+ } else {
+ d_width = 4;
+ }
+ 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, "px");
+ d_pos = d_pos * -1;
+ }
+ _knotpoint->knot_set_offset(Geom::Point(d_pos, d_width));
+ }
+ _close();
+}
+
+void FilletChamferPropertiesDialog::_close()
+{
+ _setDesktop(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::_setKnotPoint(Geom::Point knotpoint)
+{
+ double position;
+ std::string distance_or_radius = std::string(_("Radius "));
+ if(aprox){
+ distance_or_radius = std::string(_("Radius aproximated "));
+ }
+ 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, "px", 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() == 3) {
+ _fillet_chamfer_type_chamfer.set_active(true);
+ } else if (knotpoint.y() == 1) {
+ _fillet_chamfer_type_double_chamfer.set_active(true);
+ }
+}
+
+void FilletChamferPropertiesDialog::_setPt(
+ const Inkscape::LivePathEffect::
+ FilletChamferPointArrayParamKnotHolderEntity *pt)
+{
+ _knotpoint = const_cast<
+ Inkscape::LivePathEffect::FilletChamferPointArrayParamKnotHolderEntity *>(
+ pt);
+}
+
+void FilletChamferPropertiesDialog::_setUnit(const gchar *abbr)
+{
+ 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::_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-fillet-chamfer-properties.h b/src/ui/dialog/lpe-fillet-chamfer-properties.h
new file mode 100644
index 000000000..47ff97b00
--- /dev/null
+++ b/src/ui/dialog/lpe-fillet-chamfer-properties.h
@@ -0,0 +1,110 @@
+/**
+ *
+ * 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);
+
+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_double_chamfer;
+
+ 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 _setDesktop(SPDesktop *desktop);
+ void _setPt(const Inkscape::LivePathEffect::
+ FilletChamferPointArrayParamKnotHolderEntity *pt);
+ void _setUnit(const gchar *abbr);
+ void _set_use_distance(bool use_knot_distance);
+ void _set_aprox(bool aprox_radius);
+ void _apply();
+ void _close();
+ bool _flexible;
+ const gchar *unit;
+ bool use_distance;
+ bool aprox;
+ 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::
+ 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..c34351511
--- /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..93d5dfbd5
--- /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/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/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/tags.cpp b/src/ui/dialog/tags.cpp
new file mode 100644
index 000000000..127e4d95e
--- /dev/null
+++ b/src/ui/dialog/tags.cpp
@@ -0,0 +1,1165 @@
+/*
+ * 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;
+}
+
+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/text-edit.cpp b/src/ui/dialog/text-edit.cpp
index 9996fc0f9..0f4a6f7f1 100644
--- a/src/ui/dialog/text-edit.cpp
+++ b/src/ui/dialog/text-edit.cpp
@@ -51,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"
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 c87e42633..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"
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..4abc901d2 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 b2f338e2c..101af4817 100644
--- a/src/ui/tool/node.h
+++ b/src/ui/tool/node.h
@@ -41,6 +41,17 @@ template <typename> class NodeIterator;
}
}
+/*
+#if HAVE_TR1_UNORDERED_SET
+namespace std {
+namespace tr1 {
+template <typename N> struct hash< Inkscape::UI::NodeIterator<N> >;
+}
+}
+#endif
+#endif
+*/
+
namespace Inkscape {
namespace UI {
@@ -109,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);
@@ -123,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;
@@ -209,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.
@@ -255,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);
@@ -482,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..52ff5d42c 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;
+const double defaultEndPower = 0.6667;
/**
* 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,37 @@ 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 {
+ const double handleCubicGap = 0.01;
+ 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 +1147,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 +1213,93 @@ 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;
+ const double handleCubicGap = 0.01;
+ 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;
+ const double handleCubicGap = 0.01;
+ 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 +1307,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 +1317,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 +1337,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 +1558,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 37a170bc9..6434c30d2 100644
--- a/src/ui/tools/freehand-base.cpp
+++ b/src/ui/tools/freehand-base.cpp
@@ -30,7 +30,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"
@@ -44,6 +44,8 @@
#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"
#include <gdk/gdkkeysyms.h>
@@ -78,6 +80,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)
@@ -89,6 +92,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)
@@ -144,6 +148,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);
}
@@ -270,8 +277,18 @@ 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
+ static Geom::PathVector previous_shape_pathv;
+ enum shapeType { NONE, TRIANGLE_IN, TRIANGLE_OUT, ELLIPSE, CLIPBOARD, LAST_APPLIED };
+ static shapeType previous_shape_type = NONE;
- int shape = prefs->getInt(tool_name(dc) + "/shape", 0);
+
+ 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");
@@ -279,11 +296,18 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item,
#define SHAPE_LENGTH 10
#define SHAPE_HEIGHT 10
+ if(shape == LAST_APPLIED){
+ shape = previous_shape_type;
+ if(shape == 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);
@@ -293,7 +317,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();
@@ -304,7 +328,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();
@@ -317,22 +341,40 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item,
c->closepath();
spdc_paste_curve_as_freehand_shape(c, dc, item);
c->unref();
+
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);
Effect* lpe = SP_LPE_ITEM(item)->getCurrentLPE();
static_cast<LPEPatternAlongPath*>(lpe)->pattern.on_paste_button_click();
+ Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
+ Glib::ustring svgd = cm->getPathParameter(SP_ACTIVE_DESKTOP);
+ previous_shape_pathv = sp_svg_read_pathv(svgd.data());
shape_applied = true;
break;
}
+ case LAST_APPLIED:
+ {
+ 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;
+ }
+ break;
+ }
default:
break;
}
+ 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();
@@ -486,7 +528,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) {
@@ -533,9 +575,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;
}
@@ -544,6 +597,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);
}
@@ -556,6 +613,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();
}
@@ -599,6 +675,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();
@@ -662,7 +739,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 feeb68288..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 {
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 4be547506..e2bb85d11 100644
--- a/src/ui/tools/node-tool.cpp
+++ b/src/ui/tools/node-tool.cpp
@@ -23,7 +23,9 @@
#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"
@@ -105,7 +107,7 @@
using Inkscape::ControlManager;
-#include "tool-factory.h"
+#include "ui/tool-factory.h"
namespace Inkscape {
namespace UI {
@@ -171,6 +173,10 @@ NodeTool::~NodeTool() {
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();
this->_mouseover_changed_connection.disconnect();
@@ -239,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>
// <=>
@@ -257,6 +263,7 @@ void NodeTool::setup() {
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");
@@ -435,7 +442,7 @@ void NodeTool::selection_changed(Inkscape::Selection *sel) {
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);
}
}
@@ -455,7 +462,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;
}
@@ -473,6 +480,7 @@ bool NodeTool::root_handler(GdkEvent* event) {
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);
@@ -481,7 +489,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) {
@@ -513,7 +520,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 459ecd0a7..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;
diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp
index 649c64034..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,7 +84,7 @@ 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();
@@ -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();
@@ -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:
@@ -511,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.
}
@@ -537,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);
@@ -573,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();
@@ -583,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;
@@ -602,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) {
@@ -609,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;
@@ -628,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;
}
@@ -649,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:
@@ -657,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
@@ -685,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;
@@ -708,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);
@@ -728,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);
@@ -737,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?
@@ -765,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;
@@ -786,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);
@@ -796,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);
@@ -809,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);
@@ -822,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) {
@@ -839,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();
@@ -849,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();
}
@@ -972,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;
@@ -980,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;
@@ -988,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;
@@ -996,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;
*/
@@ -1071,15 +1258,23 @@ 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];
}
+
+ // 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;
// delete the last segment of the green curve
if (this->green_curve->get_segment_count() == 1) {
@@ -1094,6 +1289,18 @@ bool PenTool::_handleKeyPress(GdkEvent *event) {
} 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);
@@ -1101,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;
@@ -1167,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;
@@ -1195,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 {
@@ -1210,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);
@@ -1224,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;
@@ -1246,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");
@@ -1260,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();
@@ -1286,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;
@@ -1343,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/select-tool.cpp b/src/ui/tools/select-tool.cpp
index 21f37e83d..21459e5d0 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;
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 e15dbb59f..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 {
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 1c1e8a17a..37ca5eeea 100644
--- a/src/ui/tools/tool-base.cpp
+++ b/src/ui/tools/tool-base.cpp
@@ -44,9 +44,9 @@
#include "desktop-style.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"
@@ -55,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;
@@ -1360,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 571a17b70..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 {
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..ce665295b
--- /dev/null
+++ b/src/ui/widget/addtoicon.cpp
@@ -0,0 +1,157 @@
+/*
+ * 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..6331d70d8
--- /dev/null
+++ b/src/ui/widget/clipmaskicon.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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 78988a041..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)
{
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..8593f0bdf
--- /dev/null
+++ b/src/ui/widget/highlight-picker.cpp
@@ -0,0 +1,207 @@
+/*
+ * 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..a28b0f834
--- /dev/null
+++ b/src/ui/widget/insertordericon.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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..89b0b8f7e 100644
--- a/src/ui/widget/page-sizer.cpp
+++ b/src/ui/widget/page-sizer.cpp
@@ -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..44d8dcbf3 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/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 a575dd592..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"
@@ -213,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();
@@ -1032,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]);
@@ -1556,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-swatch.cpp b/src/ui/widget/style-swatch.cpp
index 98f4e47cd..157fd2ad9 100644
--- a/src/ui/widget/style-swatch.cpp
+++ b/src/ui/widget/style-swatch.cpp
@@ -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 557ca82e2..582d2ebb3 100644
--- a/src/ui/widget/style-swatch.h
+++ b/src/ui/widget/style-swatch.h
@@ -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 {