summaryrefslogtreecommitdiffstats
path: root/objects_dialog.patch
diff options
context:
space:
mode:
authorLiam P. White <inkscapebronyat-signgmaildotcom>2014-03-05 20:24:04 +0000
committerLiam P. White <inkscapebronyat-signgmaildotcom>2014-03-05 20:24:04 +0000
commitfcffbecabedd7c6bca1312918c918d57fee3cf8c (patch)
tree38546ab2abbbf7cf95b8fbb4d8931e5369a15bae /objects_dialog.patch
parentAdded a few swatch related functions (does not compile) (diff)
downloadinkscape-fcffbecabedd7c6bca1312918c918d57fee3cf8c.tar.gz
inkscape-fcffbecabedd7c6bca1312918c918d57fee3cf8c.zip
Added new swatches dialog
(bzr r13090.1.16)
Diffstat (limited to 'objects_dialog.patch')
-rw-r--r--objects_dialog.patch3637
1 files changed, 3637 insertions, 0 deletions
diff --git a/objects_dialog.patch b/objects_dialog.patch
new file mode 100644
index 000000000..1cdd09c34
--- /dev/null
+++ b/objects_dialog.patch
@@ -0,0 +1,3637 @@
+=== modified file 'src/attributes.cpp'
+--- src/attributes.cpp 2012-12-22 16:34:31 +0000
++++ src/attributes.cpp 2013-03-17 14:36:44 +0000
+@@ -41,6 +41,7 @@
+ {SP_ATTR_TRANSFORM_CENTER_X, "inkscape:transform-center-x"},
+ {SP_ATTR_TRANSFORM_CENTER_Y, "inkscape:transform-center-y"},
+ {SP_ATTR_INKSCAPE_PATH_EFFECT, "inkscape:path-effect"},
++ {SP_ATTR_INKSCAPE_HIGHLIGHT_COLOR, "inkscape:highlight-color"},
+ /* SPAnchor */
+ {SP_ATTR_XLINK_HREF, "xlink:href"},
+ {SP_ATTR_XLINK_TYPE, "xlink:type"},
+@@ -50,7 +51,9 @@
+ {SP_ATTR_XLINK_SHOW, "xlink:show"},
+ {SP_ATTR_XLINK_ACTUATE, "xlink:actuate"},
+ {SP_ATTR_TARGET, "target"},
++ /* SPGroup */
+ {SP_ATTR_INKSCAPE_GROUPMODE, "inkscape:groupmode"},
++ {SP_ATTR_INKSCAPE_EXPANDED, "inkscape:expanded"},
+ /* SPRoot */
+ {SP_ATTR_VERSION, "version"},
+ {SP_ATTR_WIDTH, "width"},
+
+=== modified file 'src/attributes.h'
+--- src/attributes.h 2012-12-22 16:34:31 +0000
++++ src/attributes.h 2013-03-17 14:36:17 +0000
+@@ -40,6 +40,7 @@
+ SP_ATTR_TRANSFORM_CENTER_X,
+ SP_ATTR_TRANSFORM_CENTER_Y,
+ SP_ATTR_INKSCAPE_PATH_EFFECT,
++ SP_ATTR_INKSCAPE_HIGHLIGHT_COLOR,
+ /* SPAnchor */
+ SP_ATTR_XLINK_HREF,
+ SP_ATTR_XLINK_TYPE,
+@@ -51,6 +52,7 @@
+ SP_ATTR_TARGET,
+ /* SPGroup */
+ SP_ATTR_INKSCAPE_GROUPMODE,
++ SP_ATTR_INKSCAPE_EXPANDED,
+ /* SPRoot */
+ SP_ATTR_VERSION,
+ SP_ATTR_WIDTH,
+
+=== modified file 'src/desktop.cpp'
+--- src/desktop.cpp 2013-01-27 14:19:11 +0000
++++ src/desktop.cpp 2013-03-17 14:43:46 +0000
+@@ -1885,6 +1885,7 @@
+ std::map<int, Glib::ustring> mapVerbPreference;
+ std::map<int, Glib::ustring>::const_iterator iter;
+ mapVerbPreference.insert(std::make_pair ((int)SP_VERB_DIALOG_LAYERS, "/dialogs/layers") );
++ mapVerbPreference.insert(std::make_pair ((int)SP_VERB_DIALOG_OBJECTS, "/dialogs/objects") );
+ mapVerbPreference.insert(std::make_pair ((int)SP_VERB_DIALOG_FILL_STROKE, "/dialogs/fillstroke") );
+ mapVerbPreference.insert(std::make_pair ((int)SP_VERB_DIALOG_EXTENSIONEDITOR, "/dialogs/extensioneditor") );
+ mapVerbPreference.insert(std::make_pair ((int)SP_VERB_DIALOG_ALIGN_DISTRIBUTE, "/dialogs/align") );
+
+=== modified file 'src/menus-skeleton.h'
+--- src/menus-skeleton.h 2013-03-16 16:26:03 +0000
++++ src/menus-skeleton.h 2013-03-17 14:30:19 +0000
+@@ -180,6 +180,8 @@
+ " <verb verb-id=\"DialogLayers\" />\n"
+ " </submenu>\n"
+ " <submenu name=\"" N_("_Object") "\">\n"
++" <verb verb-id=\"DialogObjects\" />\n"
++" <separator/>\n"
+ " <verb verb-id=\"DialogFillStroke\" />\n"
+ " <verb verb-id=\"DialogObjectProperties\" />\n"
+ " <verb verb-id=\"DialogSymbols\" />\n"
+
+=== modified file 'src/sp-item-group.cpp'
+--- src/sp-item-group.cpp 2013-01-24 11:43:26 +0000
++++ src/sp-item-group.cpp 2013-03-17 14:50:17 +0000
+@@ -123,6 +123,7 @@
+ static void sp_group_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
+ {
+ object->readAttr( "inkscape:groupmode" );
++ object->readAttr( "inkscape:expanded" );
+
+ if (((SPObjectClass *)sp_group_parent_class)->build) {
+ ((SPObjectClass *)sp_group_parent_class)->build(object, document, repr);
+@@ -221,7 +222,7 @@
+ Inkscape::GC::release((Inkscape::XML::Node *) l->data);
+ l = g_slist_remove (l, l->data);
+ }
+- } else {
++ } else if (!(flags & SP_OBJECT_WRITE_NO_CHILDREN)) {
+ for (SPObject *child = object->firstChild() ; child ; child = child->getNext() ) {
+ if ( !SP_IS_TITLE(child) && !SP_IS_DESC(child) ) {
+ child->updateRepr(flags);
+@@ -241,6 +242,12 @@
+ value = NULL;
+ }
+ repr->setAttribute("inkscape:groupmode", value);
++
++ if (group->_expanded) {
++ repr->setAttribute("inkscape:expanded", "true");
++ } else {
++ repr->setAttribute("inkscape:expanded", NULL);
++ }
+ }
+
+ if (((SPObjectClass *) (sp_group_parent_class))->write) {
+@@ -280,6 +287,11 @@
+ group->setLayerMode(SPGroup::GROUP);
+ }
+ break;
++ case SP_ATTR_INKSCAPE_EXPANDED:
++ if ( value && !strcmp(value, "true") ) {
++ group->setExpanded(true);
++ }
++ break;
+ default: {
+ if (((SPObjectClass *) (sp_group_parent_class))->set) {
+ (* ((SPObjectClass *) (sp_group_parent_class))->set)(object, key, value);
+@@ -517,6 +529,12 @@
+ }
+ }
+
++void SPGroup::setExpanded(bool isexpanded) {
++ if ( _expanded != isexpanded ){
++ _expanded = isexpanded;
++ }
++}
++
+ SPGroup::LayerMode SPGroup::layerDisplayMode(unsigned int dkey) const {
+ std::map<unsigned int, LayerMode>::const_iterator iter;
+ iter = _display_modes.find(dkey);
+
+=== modified file 'src/sp-item-group.h'
+--- src/sp-item-group.h 2011-10-04 19:04:58 +0000
++++ src/sp-item-group.h 2013-03-17 14:50:53 +0000
+@@ -36,11 +36,15 @@
+ struct SPGroup : public SPLPEItem {
+ enum LayerMode { GROUP, LAYER, MASK_HELPER };
+
++ bool _expanded;
+ LayerMode _layer_mode;
+ std::map<unsigned int, LayerMode> _display_modes;
+
+ LayerMode layerMode() const { return _layer_mode; }
+ void setLayerMode(LayerMode mode);
++
++ bool expanded() const { return _expanded; }
++ void setExpanded(bool isexpanded);
+
+ LayerMode effectiveLayerMode(unsigned int display_key) const {
+ if ( _layer_mode == LAYER ) {
+
+=== modified file 'src/sp-item.cpp'
+--- src/sp-item.cpp 2013-01-23 12:22:14 +0000
++++ src/sp-item.cpp 2013-03-17 14:54:59 +0000
+@@ -72,6 +72,9 @@
+ #include "live_effects/lpeobject.h"
+ #include "live_effects/effect.h"
+ #include "live_effects/lpeobject-reference.h"
++#include "ui/tool/node-tool.h"
++#include "ui/tool/multi-path-manipulator.h"
++#include "tools-switch.h"
+
+ #define noSP_ITEM_DEBUG_IDLE
+
+@@ -135,6 +138,8 @@
+ _is_evaluated = true;
+ _evaluated_status = StatusUnknown;
+
++ _highlightColor = NULL;
++
+ transform = Geom::identity();
+ doc_bbox = Geom::OptRect();
+ freeze_stroke_width = false;
+@@ -210,6 +215,62 @@
+ return true;
+ }
+
++bool SPItem::isHighlightSet() const {
++ return _highlightColor != NULL;
++}
++
++guint32 SPItem::highlight_color() const {
++ if (_highlightColor)
++ {
++ return atoi(_highlightColor) | 0x000000ff;
++ }
++ else if (parent && parent != this && SP_IS_ITEM(parent))
++ {
++ return SP_ITEM(parent)->highlight_color();
++ }
++ else
++ {
++ static Inkscape::Preferences *prefs = Inkscape::Preferences::get();
++ return prefs->getInt("/tools/nodes/highlight_color", 0xff0000ff) | 0x000000ff;
++ }
++}
++
++void SPItem::setHighlightColor(guint32 const color)
++{
++ g_free(_highlightColor);
++ if (color & 0x000000ff)
++ {
++ _highlightColor = g_strdup_printf("%u", color);
++ }
++ else
++ {
++ _highlightColor = NULL;
++ }
++
++ InkNodeTool *tool = 0;
++ if (SP_ACTIVE_DESKTOP ) {
++ SPEventContext *ec = SP_ACTIVE_DESKTOP->event_context;
++ if (INK_IS_NODE_TOOL(ec)) {
++ tool = static_cast<InkNodeTool*>(ec);
++ tools_switch(tool->desktop, TOOLS_NODES);
++ }
++ }
++}
++
++void SPItem::unsetHighlightColor()
++{
++ g_free(_highlightColor);
++ _highlightColor = NULL;
++ InkNodeTool *tool = 0;
++ if (SP_ACTIVE_DESKTOP ) {
++ SPEventContext *ec = SP_ACTIVE_DESKTOP->event_context;
++ if (INK_IS_NODE_TOOL(ec)) {
++ tool = static_cast<InkNodeTool*>(ec);
++ tools_switch(tool->desktop, TOOLS_NODES);
++ }
++ }
++}
++
+ void SPItem::setEvaluated(bool evaluated) {
+ _is_evaluated = evaluated;
+ _evaluated_status = StatusSet;
+@@ -387,14 +448,30 @@
+ while (target_ref->parent() != target_ref->root()) {
+ target_ref = target_ref->parent();
+ }
++ if (target_ref) {
++ SPObject *obj = document->getObjectByRepr(target_ref);
++ if (SP_IS_ITEM(obj)) {
++ target = SP_ITEM(obj);
++ }
++ }
+ first = TRUE;
+ }
++
++ g_assert(target_ref != NULL);
+
+ if (intoafter) {
++ Geom::Affine t = getRelativeTransform(target);
++ doWriteTransform(our_ref, t);
++ our_ref = getRepr();
++
+ // Move this inside of the target at the end
+ our_ref->parent()->removeChild(our_ref);
+ target_ref->addChild(our_ref, NULL);
+ } else if (target_ref->parent() != our_ref->parent()) {
++ Geom::Affine t = getRelativeTransform(target->parent);
++ doWriteTransform(our_ref, t);
++ our_ref = getRepr();
++
+ // Change in parent, need to remove and add
+ our_ref->parent()->removeChild(our_ref);
+ target_ref->parent()->addChild(our_ref, target_ref);
+@@ -424,6 +501,7 @@
+ object->readAttr( "inkscape:transform-center-y" );
+ object->readAttr( "inkscape:connector-avoid" );
+ object->readAttr( "inkscape:connection-points" );
++ object->readAttr( "inkscape:highlight-color" );
+
+ if ((SP_OBJECT_CLASS(sp_item_parent_class))->build) {
+ (* (SP_OBJECT_CLASS(sp_item_parent_class))->build)(object, document, repr);
+@@ -510,6 +588,14 @@
+ v->arenaitem->setSensitive(item->sensitive);
+ }
+ break;
++ case SP_ATTR_INKSCAPE_HIGHLIGHT_COLOR:
++ g_free(item->_highlightColor);
++ if (value) {
++ item->_highlightColor = g_strdup(value);
++ } else {
++ item->_highlightColor = NULL;
++ }
++ break;
+ case SP_ATTR_CONNECTOR_AVOID:
+ item->avoidRef->setAvoid(value);
+ break;
+@@ -720,6 +806,11 @@
+ g_free ((void *) value);
+ }
+ }
++ if (item->_highlightColor){
++ repr->setAttribute("inkscape:highlight-color", item->_highlightColor);
++ } else {
++ repr->setAttribute("inkscape:highlight-color", NULL);
++ }
+
+ if ((SP_OBJECT_CLASS(sp_item_parent_class))->write) {
+ (SP_OBJECT_CLASS(sp_item_parent_class))->write(object, xml_doc, repr, flags);
+
+=== modified file 'src/sp-item.h'
+--- src/sp-item.h 2013-03-14 23:24:17 +0000
++++ src/sp-item.h 2013-03-17 14:51:37 +0000
+@@ -144,11 +144,21 @@
+
+ void init();
+ bool isLocked() const;
++ bool isSensitive() const {
++ return sensitive;
++ };
+ void setLocked(bool lock);
+
+ bool isHidden() const;
+ void setHidden(bool hidden);
+
++ bool isHighlightSet() const;
++ guint32 highlight_color() const;
++
++ void setHighlightColor(guint32 color);
++
++ void unsetHighlightColor();
++
+ bool isEvaluated() const;
+ void setEvaluated(bool visible);
+ void resetEvaluated();
+@@ -218,6 +228,7 @@
+ Geom::Affine dt2i_affine() const;
+ void convert_to_guides();
+
++ gchar *_highlightColor;
+ private:
+ enum EvaluatedStatus
+ {
+
+=== modified file 'src/sp-object.h'
+--- src/sp-object.h 2013-03-14 01:33:10 +0000
++++ src/sp-object.h 2013-03-17 14:53:10 +0000
+@@ -48,6 +48,7 @@
+ #define SP_OBJECT_WRITE_BUILD (1 << 0)
+ #define SP_OBJECT_WRITE_EXT (1 << 1)
+ #define SP_OBJECT_WRITE_ALL (1 << 2)
++#define SP_OBJECT_WRITE_NO_CHILDREN (1 << 3)
+
+ #include <glib-object.h>
+ #include <stddef.h>
+
+=== modified file 'src/ui/dialog/Makefile_insert'
+--- src/ui/dialog/Makefile_insert 2012-10-11 17:54:14 +0000
++++ src/ui/dialog/Makefile_insert 2013-03-17 13:55:34 +0000
+@@ -70,6 +70,8 @@
+ ui/dialog/memory.h \
+ ui/dialog/messages.cpp \
+ ui/dialog/messages.h \
++ ui/dialog/objects.cpp \
++ ui/dialog/objects.h \
+ ui/dialog/ocaldialogs.cpp \
+ ui/dialog/ocaldialogs.h \
+ ui/dialog/object-attributes.cpp \
+
+=== modified file 'src/ui/dialog/dialog-manager.cpp'
+--- src/ui/dialog/dialog-manager.cpp 2013-03-16 16:26:03 +0000
++++ src/ui/dialog/dialog-manager.cpp 2013-03-17 14:03:02 +0000
+@@ -40,6 +40,7 @@
+ #include "ui/dialog/undo-history.h"
+ #include "ui/dialog/panel-dialog.h"
+ #include "ui/dialog/layers.h"
++#include "ui/dialog/objects.h"
+ #include "ui/dialog/icon-preview.h"
+ #include "ui/dialog/floating-behavior.h"
+ #include "ui/dialog/dock-behavior.h"
+@@ -108,6 +109,7 @@
+ registerFactory("IconPreviewPanel", &create<IconPreviewPanel, FloatingBehavior>);
+ registerFactory("InkscapePreferences", &create<InkscapePreferences, FloatingBehavior>);
+ registerFactory("LayersPanel", &create<LayersPanel, FloatingBehavior>);
++ registerFactory("ObjectsPanel", &create<ObjectsPanel, FloatingBehavior>);
+ registerFactory("LivePathEffect", &create<LivePathEffectEditor, FloatingBehavior>);
+ registerFactory("Memory", &create<Memory, FloatingBehavior>);
+ registerFactory("Messages", &create<Messages, FloatingBehavior>);
+@@ -142,6 +144,7 @@
+ registerFactory("IconPreviewPanel", &create<IconPreviewPanel, DockBehavior>);
+ registerFactory("InkscapePreferences", &create<InkscapePreferences, DockBehavior>);
+ registerFactory("LayersPanel", &create<LayersPanel, DockBehavior>);
++ registerFactory("ObjectsPanel", &create<ObjectsPanel, DockBehavior>);
+ registerFactory("LivePathEffect", &create<LivePathEffectEditor, DockBehavior>);
+ registerFactory("Memory", &create<Memory, DockBehavior>);
+ registerFactory("Messages", &create<Messages, DockBehavior>);
+
+=== added file 'src/ui/dialog/objects.cpp'
+--- src/ui/dialog/objects.cpp 1970-01-01 00:00:00 +0000
++++ src/ui/dialog/objects.cpp 2013-03-17 15:01:22 +0000
+@@ -0,0 +1,2014 @@
++/*
++ * A simple panel for objects
++ *
++ * 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
++
++#include "objects.h"
++#include <gtkmm/widget.h>
++#include <gtkmm/icontheme.h>
++#include <gtkmm/imagemenuitem.h>
++#include <gtkmm/separatormenuitem.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 "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/imagetoggler.h"
++#include "ui/widget/layertypeicon.h"
++#include "ui/widget/clipmaskicon.h"
++#include "ui/widget/highlight-picker.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 "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 "layer-manager.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_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_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);
++ }
++ 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;
++};
++
++/**
++ * 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;
++ row[_model->_colLabel] = item->label() ? item->label() : item->getId();
++ 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);
++
++ //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
++ _store->foreach_iter( sigc::bind<SPObject*>(sigc::mem_fun(*this, &ObjectsPanel::_checkForUpdated), obj) );
++ 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;
++
++ 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
++ _opacity_adjustment.set_value((item->style->opacity.set ? SP_SCALE24_TO_FLOAT(item->style->opacity.value) : 1) * _opacity_adjustment.get_upper());
++ 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)
++{
++
++ switch (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_Home:
++ {
++ //Move item(s) to top of containing group/layer
++ if (_desktop->selection->isEmpty())
++ {
++ _fireAction( SP_VERB_LAYER_TO_TOP );
++ }
++ else
++ {
++ _fireAction( SP_VERB_SELECTION_TO_FRONT );
++ }
++ return true;
++ }
++ case GDK_End:
++ {
++ //Move item(s) to bottom of containing group/layer
++ if (_desktop->selection->isEmpty())
++ {
++ _fireAction( SP_VERB_LAYER_TO_BOTTOM );
++ }
++ else
++ {
++ _fireAction( SP_VERB_SELECTION_TO_BACK );
++ }
++ return true;
++ }
++ case GDK_KEY_Page_Up:
++ {
++ //Move item(s) up in containing group/layer
++ if (_desktop->selection->isEmpty())
++ {
++ _fireAction( SP_VERB_LAYER_RAISE );
++ }
++ else
++ {
++ if (event->state & GDK_SHIFT_MASK) {
++ _fireAction( SP_VERB_LAYER_MOVE_TO_NEXT );
++ } else {
++ _fireAction( SP_VERB_SELECTION_RAISE );
++ }
++ }
++ return true;
++ }
++ case GDK_KEY_Page_Down:
++ {
++ //Move item(s) down in containing group/layer
++ if (_desktop->selection->isEmpty())
++ {
++ _fireAction( SP_VERB_LAYER_LOWER );
++ }
++ else
++ {
++ if (event->state & GDK_SHIFT_MASK) {
++ _fireAction( SP_VERB_LAYER_MOVE_TO_PREV );
++ } else {
++ _fireAction( SP_VERB_SELECTION_LOWER );
++ }
++ }
++ return true;
++ }
++ //TODO: Handle Ctrl-A, etc.
++ }
++ return false;
++}
++
++/**
++ * 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_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_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_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::done(SP_ACTIVE_DOCUMENT, 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;
++ item->style->opacity.value = SP_SCALE24_FROM_FLOAT(_opacity_adjustment.get_value() / _opacity_adjustment.get_upper());
++ 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 );
++ }
++
++ //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, &ObjectCompositeSettings::_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
++ Gtk::Button* btn = Gtk::manage( new Gtk::Button() );
++ _styleButton( *btn, GTK_STOCK_ADD, _("New Layer") );
++ btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_takeAction), (int)BUTTON_NEW) );
++ _buttonsSecondary.pack_start(*btn, Gtk::PACK_SHRINK);
++
++ btn = Gtk::manage( new Gtk::Button() );
++ _styleButton( *btn, GTK_STOCK_REMOVE, _("Remove") );
++ 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);
++
++ btn = Gtk::manage( new Gtk::Button() );
++ _styleButton( *btn, GTK_STOCK_GOTO_BOTTOM, _("Move To Bottom") );
++ 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);
++
++ btn = Gtk::manage( new Gtk::Button() );
++ _styleButton( *btn, GTK_STOCK_GO_DOWN, _("Move Down") );
++ 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);
++
++ btn = Gtk::manage( new Gtk::Button() );
++ _styleButton( *btn, GTK_STOCK_GO_UP, _("Move Up") );
++ 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);
++
++ btn = Gtk::manage( new Gtk::Button() );
++ _styleButton( *btn, GTK_STOCK_GOTO_TOP, _("Move To Top") );
++ 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);
++
++ btn = Gtk::manage( new Gtk::Button() );
++ _styleButton( *btn, GTK_STOCK_UNINDENT, _("Collapse All") );
++ 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_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
++
++
++/*
++ 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 :
+
+=== added file 'src/ui/dialog/objects.h'
+--- src/ui/dialog/objects.h 1970-01-01 00:00:00 +0000
++++ src/ui/dialog/objects.h 2013-03-17 13:42:01 +0000
+@@ -0,0 +1,255 @@
++/*
++ * 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
++
++#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 :
+
+=== modified file 'src/ui/tool/multi-path-manipulator.cpp'
+--- src/ui/tool/multi-path-manipulator.cpp 2012-09-06 02:25:16 +0000
++++ src/ui/tool/multi-path-manipulator.cpp 2013-03-19 00:31:09 +0000
+@@ -195,7 +195,7 @@
+ 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);
+@@ -834,7 +834,7 @@
+ }
+
+ /** 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) {
+@@ -846,7 +846,7 @@
+ 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();
+ }
+ }
+
+
+=== modified file 'src/ui/tool/multi-path-manipulator.h'
+--- src/ui/tool/multi-path-manipulator.h 2012-05-17 09:10:15 +0000
++++ src/ui/tool/multi-path-manipulator.h 2013-03-19 00:31:16 +0000
+@@ -106,7 +106,7 @@
+ void _commit(CommitEvent cps);
+ void _done(gchar const *reason, bool alert_LPE = false);
+ void _doneWithCleanup(gchar const *reason, bool alert_LPE = false);
+- guint32 _getOutlineColor(ShapeRole role);
++ guint32 _getOutlineColor(ShapeRole role, SPItem *item);
+
+ MapType _mmap;
+ public:
+
+=== modified file 'src/ui/tool/node-tool.cpp'
+--- src/ui/tool/node-tool.cpp 2013-01-26 19:33:04 +0000
++++ src/ui/tool/node-tool.cpp 2013-03-19 00:31:25 +0000
+@@ -488,7 +488,7 @@
+ c->transform(over_item->i2dt_affine());
+ SPCanvasItem *flash = sp_canvas_bpath_new(sp_desktop_tempgroup(desktop), c);
+ sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(flash),
+- prefs->getInt("/tools/nodes/highlight_color", 0xff0000ff), 1.0,
++ 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);
+ nt->flash_tempitem = desktop->add_temporary_canvasitem(flash,
+
+=== modified file 'src/ui/widget/Makefile_insert'
+--- src/ui/widget/Makefile_insert 2013-01-08 12:06:44 +0000
++++ src/ui/widget/Makefile_insert 2013-03-17 14:17:34 +0000
+@@ -4,6 +4,8 @@
+ ui/widget/attr-widget.h \
+ ui/widget/button.h \
+ ui/widget/button.cpp \
++ ui/widget/clipmaskicon.cpp \
++ ui/widget/clipmaskicon.h \
+ ui/widget/color-picker.cpp \
+ ui/widget/color-picker.h \
+ ui/widget/color-preview.cpp \
+@@ -23,6 +25,8 @@
+ ui/widget/gimpspinscale.h \
+ ui/widget/gimpcolorwheel.c \
+ ui/widget/gimpcolorwheel.h \
++ ui/widget/highlight-picker.cpp \
++ ui/widget/highlight-picker.h \
+ ui/widget/frame.cpp \
+ ui/widget/frame.h \
+ ui/widget/imageicon.cpp \
+@@ -33,6 +37,8 @@
+ ui/widget/labelled.h \
+ ui/widget/layer-selector.cpp \
+ ui/widget/layer-selector.h \
++ ui/widget/layertypeicon.cpp \
++ ui/widget/layertypeicon.h \
+ ui/widget/licensor.cpp \
+ ui/widget/licensor.h \
+ ui/widget/notebook-page.cpp \
+
+=== added file 'src/ui/widget/clipmaskicon.cpp'
+--- src/ui/widget/clipmaskicon.cpp 1970-01-01 00:00:00 +0000
++++ src/ui/widget/clipmaskicon.cpp 2013-03-14 23:36:37 +0000
+@@ -0,0 +1,177 @@
++/*
++ * 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/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 :
++
++
+
+=== added file 'src/ui/widget/clipmaskicon.h'
+--- src/ui/widget/clipmaskicon.h 1970-01-01 00:00:00 +0000
++++ src/ui/widget/clipmaskicon.h 2013-03-08 04:27:35 +0000
+@@ -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 <glibmm/property.h>
++#include <gtkmm/cellrendererpixbuf.h>
++#include <gtkmm/widget.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 :
+
+=== added file 'src/ui/widget/highlight-picker.cpp'
+--- src/ui/widget/highlight-picker.cpp 1970-01-01 00:00:00 +0000
++++ src/ui/widget/highlight-picker.cpp 2013-03-08 04:27:35 +0000
+@@ -0,0 +1,176 @@
++/*
++ * Authors:
++ * Theodore Janeczko
++ *
++ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
++ *
++ * Released under GNU GPL, read the file 'COPYING' for more information
++ */
++
++#include <glibmm/i18n.h>
++#include "display/cairo-utils.h"
++
++#include <gtkmm/icontheme.h>
++
++#include "highlight-picker.h"
++#include "widgets/icon.h"
++#include "widgets/toolbox.h"
++#include "ui/icon-names.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
++
++/*
++ 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 :
++
++
+
+=== added file 'src/ui/widget/highlight-picker.h'
+--- src/ui/widget/highlight-picker.h 1970-01-01 00:00:00 +0000
++++ src/ui/widget/highlight-picker.h 2013-03-08 04:27:35 +0000
+@@ -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 <glibmm/property.h>
++#include <gtkmm/cellrendererpixbuf.h>
++#include <gtkmm/widget.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 :
+
+=== added file 'src/ui/widget/layertypeicon.cpp'
+--- src/ui/widget/layertypeicon.cpp 1970-01-01 00:00:00 +0000
++++ src/ui/widget/layertypeicon.cpp 2013-03-08 04:27:35 +0000
+@@ -0,0 +1,167 @@
++/*
++ * 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/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 :
++
++
+
+=== added file 'src/ui/widget/layertypeicon.h'
+--- src/ui/widget/layertypeicon.h 1970-01-01 00:00:00 +0000
++++ src/ui/widget/layertypeicon.h 2013-03-08 04:27:35 +0000
+@@ -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 <glibmm/property.h>
++#include <gtkmm/cellrendererpixbuf.h>
++#include <gtkmm/widget.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 :
+
+=== modified file 'src/verbs.cpp'
+--- src/verbs.cpp 2013-03-04 17:21:11 +0000
++++ src/verbs.cpp 2013-03-17 14:29:16 +0000
+@@ -1980,6 +1980,9 @@
+ case SP_VERB_DIALOG_LAYERS:
+ dt->_dlg_mgr->showDialog("LayersPanel");
+ break;
++ case SP_VERB_DIALOG_OBJECTS:
++ dt->_dlg_mgr->showDialog("ObjectsPanel");
++ break;
+ case SP_VERB_DIALOG_LIVE_PATH_EFFECT:
+ dt->_dlg_mgr->showDialog("LivePathEffect");
+ break;
+@@ -2791,6 +2794,8 @@
+ N_("Query information about extensions"), NULL),
+ new DialogVerb(SP_VERB_DIALOG_LAYERS, "DialogLayers", N_("Layer_s..."),
+ N_("View Layers"), INKSCAPE_ICON("dialog-layers")),
++ new DialogVerb(SP_VERB_DIALOG_OBJECTS, "DialogObjects", N_("Object_s..."),
++ N_("View Objects"), INKSCAPE_ICON("dialog-layers")),
+ new DialogVerb(SP_VERB_DIALOG_LIVE_PATH_EFFECT, "DialogLivePathEffect", N_("Path E_ffects ..."),
+ N_("Manage, edit, and apply path effects"), NULL),
+ new DialogVerb(SP_VERB_DIALOG_FILTER_EFFECTS, "DialogFilterEffects", N_("Filter _Editor..."),
+
+=== modified file 'src/verbs.h'
+--- src/verbs.h 2013-03-04 17:21:11 +0000
++++ src/verbs.h 2013-03-17 14:28:15 +0000
+@@ -285,6 +285,7 @@
+ SP_VERB_DIALOG_INPUT,
+ SP_VERB_DIALOG_EXTENSIONEDITOR,
+ SP_VERB_DIALOG_LAYERS,
++ SP_VERB_DIALOG_OBJECTS,
+ SP_VERB_DIALOG_LIVE_PATH_EFFECT,
+ SP_VERB_DIALOG_FILTER_EFFECTS,
+ SP_VERB_DIALOG_SVG_FONTS,
+