diff options
| author | Liam P. White <inkscapebronyat-signgmaildotcom> | 2014-03-05 20:24:04 +0000 |
|---|---|---|
| committer | Liam P. White <inkscapebronyat-signgmaildotcom> | 2014-03-05 20:24:04 +0000 |
| commit | fcffbecabedd7c6bca1312918c918d57fee3cf8c (patch) | |
| tree | 38546ab2abbbf7cf95b8fbb4d8931e5369a15bae /objects_dialog.patch | |
| parent | Added a few swatch related functions (does not compile) (diff) | |
| download | inkscape-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.patch | 3637 |
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, + |
