objects.cpp revision c10edd3236e4ac02e1918837596756ed1ef8b441
/*
* A simple panel for objects
*
* Authors:
* Theodore Janeczko
* Tweaked by Liam P White for use in Inkscape
*
* Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "objects.h"
#include <gtkmm/icontheme.h>
#include <gtkmm/imagemenuitem.h>
#include <gtkmm/separatormenuitem.h>
#include "desktop.h"
#include "desktop-style.h"
#include "ui/dialog-events.h"
#include "document.h"
#include "document-undo.h"
#include "filter-chemistry.h"
#include "filters/gaussian-blur.h"
#include "inkscape.h"
#include "layer-manager.h"
#include "preferences.h"
#include "selection.h"
#include "sp-clippath.h"
#include "sp-mask.h"
#include "sp-item.h"
#include "sp-object.h"
#include "sp-root.h"
#include "sp-shape.h"
#include "style.h"
#include "ui/tools-switch.h"
#include "ui/icon-names.h"
#include "ui/selected-color.h"
#include "ui/widget/imagetoggler.h"
#include "ui/widget/layertypeicon.h"
#include "ui/widget/insertordericon.h"
#include "ui/widget/clipmaskicon.h"
#include "ui/widget/highlight-picker.h"
#include "ui/tools/node-tool.h"
#include "ui/tools/tool-base.h"
#include "verbs.h"
#include "ui/widget/color-notebook.h"
#include "xml/node-observer.h"
//#define DUMP_LAYERS 1
namespace Inkscape {
namespace UI {
namespace Dialog {
/**
* Gets an instance of the Objects panel
*/
{
return *new ObjectsPanel();
}
/**
* Column enumeration
*/
enum {
COL_VISIBLE = 1,
// COL_INSERTORDER,
};
/**
* Button enumeration
*/
enum {
BUTTON_NEW = 0,
// BUTTON_SETINVCLIP,
};
/**
* Xml node observer for observing objects in the document
*/
public:
/**
* Creates a new object watcher
* @param pnl The panel to which the object watcher belongs
* @param obj The object to watch
*/
{}
{
}
}
{
}
}
virtual void notifyChildOrderChanged( Node &/*node*/, Node &/*child*/, Node */*old_prev*/, Node */*new_prev*/ )
{
}
}
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 ( name == _lockedAttr || name == _labelAttr || name == _highlightAttr || name == _groupAttr || name == _styleAttr || name == _clipAttr || name == _maskAttr ) {
if ( name == _styleAttr ) {
_pnl->_updateComposite();
}
}
}
}
/**
* Objects panel to which this watcher belongs
*/
/**
* The object that is being observed
*/
/**
* The xml representation of the object that is being observed
*/
/* These are quarks which define the attributes that we are observing */
};
class ObjectsPanel::InternalUIBounce
{
public:
int _actionCode;
};
{
public:
{
//add(_colInsertOrder);
}
virtual ~ModelColumns() {}
//Gtk::TreeModelColumn<int> _colInsertOrder;
};
/**
* Stylizes a button using the given icon name and tooltip
*/
{
gtk_widget_show( child );
}
/**
* 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 ) {
}
if ( desktop ) {
if ( verb ) {
}
if ( action ) {
// label = action->name;
}
}
}
}
if ( iconWidget ) {
}
if (wrapped) {
} else {
}
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)
*/
{
//First, unattach the watchers
while (!_objectWatchers.empty())
{
w->_repr->removeObserver(*w);
delete w;
}
if (_desktop) {
//Get the current document's root and use that to enumerate the tree
if ( root ) {
//Clear the tree store
//Add all items recursively
_addObject( root, 0 );
//Set the tree selection
//Handle button sensitivity
}
}
}
/**
* 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)
*/
{
if (SP_IS_ITEM(child))
{
//Add the item to the tree and set the column information
Gtk::TreeModel::iterator iter = parentRow ? _store->prepend(parentRow->children()) : _store->prepend();
//this seems to crash on convert stroke to path then undo (probably no ID?)
try {
} catch (...) {
g_critical("item->getId() failed, using \"getId_failure\"");
}
row[_model->_colHighlight] = item->isHighlightSet() ? item->highlight_color() : item->highlight_color() & 0xffffff00;
row[_model->_colClipMask] = item->clip_ref && item->clip_ref->getObject() ? 1 : (item->mask_ref && item->mask_ref->getObject() ? 2 : 0);
//row[_model->_colInsertOrder] = group ? (group->insertBottom() ? 2 : 1) : 0;
//If our parent object is a group and it's expanded, expand the tree
{
}
//Add an object watcher to the item
//If the item is a group, recursively add its children
if (group)
{
}
}
}
}
}
/**
* 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
*/
//Find the object in the tree store and update it
//mark
_store->foreach_iter( sigc::bind<SPObject*>(sigc::mem_fun(*this, &ObjectsPanel::_checkForUpdated), obj) );
//end mark
if (recurse)
{
{
}
}
}
/**
* 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
*/
{
{
//We found our item in the tree!! Update it!
row[_model->_colHighlight] = item ? (item->isHighlightSet() ? item->highlight_color() : item->highlight_color() & 0xffffff00) : 0;
row[_model->_colClipMask] = item ? (item->clip_ref && item->clip_ref->getObject() ? 1 : (item->mask_ref && item->mask_ref->getObject() ? 2 : 0)) : 0;
//row[_model->_colInsertOrder] = group ? (group->insertBottom() ? 2 : 1) : 0;
return true;
}
return false;
}
/**
* Updates the composite controls for the selected item
*/
void ObjectsPanel::_updateComposite() {
if (!_blockCompositeUpdate)
{
//Set the default values
bool setValues = true;
_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
*/
{
if (iter) {
if (*setValues)
{
*setValues = false;
}
}
}
/**
* Occurs when the current desktop selection changes
* @param sel The current selection
*/
bool setOpacity = true;
item = *i;
if (setOpacity)
{
setOpacity = false;
}
_store->foreach(sigc::bind<SPItem *, bool>( sigc::mem_fun(*this, &ObjectsPanel::_checkForSelected), item, (*i)==items.back()));
}
if (!item) {
_store->foreach(sigc::bind<SPItem *, bool>( sigc::mem_fun(*this, &ObjectsPanel::_checkForSelected), item, true));
}
}
}
/**
* Helper function for setting the compositing values
* @param item Item to use for setting the compositing values
*/
{
//Block the connections to avoid interference
//Set the opacity
#if WITH_GTKMM_3_0
_opacity_adjustment->set_value((item->style->opacity.set ? SP_SCALE24_TO_FLOAT(item->style->opacity.value) : 1) * _opacity_adjustment->get_upper());
#else
_opacity_adjustment.set_value((item->style->opacity.set ? SP_SCALE24_TO_FLOAT(item->style->opacity.value) : 1) * _opacity_adjustment.get_upper());
#endif
{
for(SPObject *primitive_obj = item->style->getFilter()->children; primitive_obj && SP_IS_FILTER_PRIMITIVE(primitive_obj); primitive_obj = primitive_obj->next) {
//Get the blend mode
}
//Get the blur value
}
}
}
//Set the blend mode
//Set the blur value
double perimeter = bbox->dimensions()[Geom::X] + bbox->dimensions()[Geom::Y]; // fixme: this is only half the perimeter, is that correct?
} else {
}
//Unblock connections
}
/**
* 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;
{
//We found the item! Expand to the path and select it in the tree.
if (scrollto) {
//Scroll to the item in the tree
}
stopGoing = true;
}
return stopGoing;
}
/**
* Pushes the current tree selection to the canvas
*/
{
//block connections for selection and compositing values to prevent interference
//Clear the selection and then iterate over the tree selection, pushing each item to the desktop
bool setOpacity = true;
_tree.get_selection()->selected_foreach_iter( sigc::bind<bool *>(sigc::mem_fun(*this, &ObjectsPanel::_selected_row_callback), &setOpacity));
//unblock connections
}
}
/**
* 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) {
{
//If the item is not a layer, then select it and set the current layer to its parent (if it's the first item)
}
else
{
//If the item is a layer, set the current layer
}
if (*setCompositingValues)
{
//Only set the compositing values for the first item
*setCompositingValues = false;
}
}
}
/**
* Handles button sensitivity
*/
void ObjectsPanel::_checkTreeSelection()
{
bool sensitiveNonTop = true;
bool sensitiveNonBottom = true;
}
for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonTop.begin(); it != _watchingNonTop.end(); ++it ) {
}
for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonBottom.begin(); it != _watchingNonBottom.end(); ++it ) {
}
}
/**
* Sets visibility of items in the tree
* @param iter Current item in the tree
* @param visible Whether the item should be visible or not
*/
{
if (item)
{
}
}
/**
* Sets sensitivity of items in the tree
* @param iter Current item in the tree
* @param locked Whether the item should be locked
*/
{
if (item)
{
}
}
/**
* Handles keyboard events
* @param event Keyboard event passed in from GDK
* @return Whether the event should be eaten (om nom nom)
*/
{
case GDK_KEY_Return:
case GDK_KEY_KP_Enter:
case GDK_KEY_F2:
{
//Rename item
_text_renderer->property_editable() = true;
grab_focus();
return true;
}
}
break;
case GDK_KEY_Home:
break;
case GDK_KEY_End:
break;
case GDK_KEY_Page_Up:
{
break;
}
case GDK_KEY_Page_Down:
{
break;
}
//TODO: Handle Ctrl-A, etc.
default:
return false;
}
return true;
}
/**
* Handles mouse events
* @param event Mouse event from GDK
* @return whether to eat the event (om nom nom)
*/
{
static unsigned doubleclick = 0;
static bool overVisible = false;
//Right mouse button was clicked, launch the pop-up menu
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...
overVisible = false;
int x2 = 0;
int y2 = 0;
//Click on visible column, eat this event to keep row selection
overVisible = true;
return true;
//col == _tree.get_column(COL_INSERTORDER - 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
}
}
}
//Restore the selection function to allow tree selection on mouse 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
int x2 = 0;
int y2 = 0;
if (_defer_target) {
//We had deferred a selection target, select it here (assuming no drag & drop)
{
}
}
else {
}
DocumentUndo::maybeDone(_desktop->doc(), "layer:lockothers", SP_VERB_LAYER_LOCK_OTHERS, _("Lock other layers"));
}
}
} else {
if (overVisible) {
//Toggle visibility
{
//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
}
overVisible = false;
}
//Toggle locking
{
//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
}
if (SP_IS_GROUP(item))
{
//Toggle the current item between a group and a layer
}
} /*else if (col == _tree.get_column(COL_INSERTORDER - 1)) {
if (SP_IS_GROUP(item))
{
//Toggle the current item's insert order
SPGroup * g = SP_GROUP(item);
bool newValue = !g->insertBottom();
row[_model->_colInsertOrder] = newValue ? 2: 1;
g->setInsertBottom(newValue);
g->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT);
DocumentUndo::done( _desktop->doc() , SP_VERB_DIALOG_OBJECTS,
newValue? _("Set insert mode bottom") : _("Set insert mode top"));
}
//Clear the highlight targets
{
//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
}
if (_selectedColor)
{
//Set up the color selector
}
//Show the color selector dialog
}
}
}
}
}
//Second mouse button press, set double click status for when the mouse is released
doubleclick = 1;
}
//Double click on mouse button release, if we're over the label column, edit
//the item name
doubleclick = 0;
int x2 = 0;
int y2 = 0;
// Double click on the Layer name, enable editing
_text_renderer->property_editable() = 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
*/
{
if (item)
{
}
}
/*
* Drap and drop within the tree
*/
bool ObjectsPanel::_handleDragDrop(const Glib::RefPtr<Gdk::DragContext>& /*context*/, int x, int y, guint /*time*/)
{
//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));
// Are we before, inside or after the drop layer
} else {
// Dragging to the "end"
// Drop into parent
_dnd_into = true;
} else {
// Drop into the top level
_dnd_target = NULL;
}
}
}
//Set the drop target. If we're not dropping into a group, we cannot
//drop into it, so set _dnd_into false.
}
}
return false;
}
/**
* Stores all selected items as the drag source
* @param iter Current tree item
*/
{
if (item)
{
}
}
/*
* Move a layer in response to a drag & drop action
*/
void ObjectsPanel::_doTreeMove( )
{
//Clear the desktop selection
while (!_dnd_source.empty())
{
if (obj != _dnd_target) {
//Store the object id (for selection later) and move the object
}
}
//Select items
//Grab the id from the vector, get the item in the document and select it
{
}
else
{
}
}
}
_("Moved objects"));
}
/**
* Fires the action verb
*/
{
if ( _desktop ) {
if ( verb ) {
if ( action ) {
}
}
}
}
/**
* Executes the given button action during the idle time
*/
{
if ( !_pending ) {
_pending = new InternalUIBounce();
}
}
/**
* Executes the pending button action
*/
bool ObjectsPanel::_executeAction()
{
// Make sure selected layer hasn't changed since the action was triggered
{
// SPObject* target = _pending->_target;
switch ( val ) {
case BUTTON_NEW:
{
}
break;
case BUTTON_RENAME:
{
}
break;
case BUTTON_TOP:
{
{
}
else
{
}
}
break;
case BUTTON_BOTTOM:
{
{
}
else
{
}
}
break;
case BUTTON_UP:
{
{
}
else
{
}
}
break;
case BUTTON_DOWN:
{
{
}
else
{
}
}
break;
case BUTTON_DUPLICATE:
{
{
}
else
{
}
}
break;
case BUTTON_DELETE:
{
{
}
else
{
}
}
break;
case BUTTON_SOLO:
{
}
break;
case BUTTON_SHOW_ALL:
{
}
break;
case BUTTON_HIDE_ALL:
{
}
break;
case BUTTON_LOCK_OTHERS:
{
}
break;
case BUTTON_LOCK_ALL:
{
}
break;
case BUTTON_UNLOCK_ALL:
{
}
break;
case BUTTON_CLIPGROUP:
{
}
case BUTTON_SETCLIP:
{
}
break;
case BUTTON_UNSETCLIP:
{
}
break;
case BUTTON_SETMASK:
{
}
break;
case BUTTON_UNSETMASK:
{
}
break;
case BUTTON_GROUP:
{
}
break;
case BUTTON_UNGROUP:
{
}
break;
case BUTTON_COLLAPSE_ALL:
{
if (SP_IS_GROUP(obj)) {
}
}
}
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
*/
{
_text_renderer->property_editable() = false;
}
/**
* Renames an item in the tree
* @param row Tree row
* @param name New label to give to the item
*/
{
if ( item ) {
_("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 )
{
if ( event ) {
// (keep these checks separate, so we know when to call gdk_event_free()
)
{
// Ooooh! It's a magic one
val = false;
}
}
}
}
return val;
}
/**
* Sets a group to be collapsed and recursively collapses its children
* @param group The group to collapse
*/
{
group->setExpanded(false);
{
}
}
/**
* 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)
{
{
if (isexpanded)
{
//If we're expanding, simply perform the expansion
}
else
{
//If we're collapsing, we need to recursively collapse, so call our helper function
}
}
}
/**
* Callback for when the highlight color is changed
* @param csel Color selector
* @param cp Objects panel
*/
void ObjectsPanel::_highlightPickerColorMod()
{
float alpha = 0;
//Set the highlight color for all items in the _highlight_target (all selected items)
for (std::vector<SPItem *>::iterator iter = _highlight_target.begin(); iter != _highlight_target.end(); ++iter)
{
}
DocumentUndo::maybeDone(SP_ACTIVE_DOCUMENT, "highlight", SP_VERB_DIALOG_OBJECTS, _("Set object highlight color"));
}
/**
* Callback for when the opacity value is changed
*/
void ObjectsPanel::_opacityValueChanged()
{
_blockCompositeUpdate = true;
_tree.get_selection()->selected_foreach_iter(sigc::mem_fun(*this, &ObjectsPanel::_opacityChangedIter));
_blockCompositeUpdate = false;
}
/**
* Change the opacity of the selected items in the tree
* @param iter Current tree item
*/
{
if (item)
{
#if WITH_GTKMM_3_0
item->style->opacity.value = SP_SCALE24_FROM_FLOAT(_opacity_adjustment->get_value() / _opacity_adjustment->get_upper());
#else
item->style->opacity.value = SP_SCALE24_FROM_FLOAT(_opacity_adjustment.get_value() / _opacity_adjustment.get_upper());
#endif
}
}
/**
* Callback for when the blend mode is changed
*/
void ObjectsPanel::_blendValueChanged()
{
_blockCompositeUpdate = true;
_tree.get_selection()->selected_foreach_iter(sigc::bind<Glib::ustring>(sigc::mem_fun(*this, &ObjectsPanel::_blendChangedIter), blendmode));
_blockCompositeUpdate = false;
}
/**
* Sets the blend mode of the selected tree items
* @param iter Current tree item
* @param blendmode Blend mode to set
*/
{
if (item)
{
//Since blur and blend are both filters, we need to set both at the same time
if (blendmode != "normal") {
for (SPObject *primitive = item->style->getFilter()->children; primitive && SP_IS_FILTER_PRIMITIVE(primitive); primitive = primitive->next) {
if (SP_IS_GAUSSIANBLUR(primitive)) {
if (bbox) {
}
}
}
}
} else {
for (SPObject *primitive = item->style->getFilter()->children; primitive && SP_IS_FILTER_PRIMITIVE(primitive); primitive = primitive->next) {
if (SP_IS_FEBLEND(primitive)) {
break;
}
}
remove_filter(item, false);
}
}
}
}
/**
* 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()));
_blockCompositeUpdate = false;
}
/**
* Sets the blur value for the selected items in the tree
* @param iter Current tree item
* @param blur Blur value to set
*/
{
if (item)
{
//Since blur and blend are both filters, we need to set both at the same time
if (style) {
double radius;
if (bbox) {
double perimeter = bbox->dimensions()[Geom::X] + bbox->dimensions()[Geom::Y]; // fixme: this is only half the perimeter, is that correct?
} else {
radius = 0;
}
if (radius != 0) {
// The modify function expects radius to be in display pixels.
for (SPObject *primitive = item->style->getFilter()->children; primitive && SP_IS_FILTER_PRIMITIVE(primitive); primitive = primitive->next) {
if (SP_IS_GAUSSIANBLUR(primitive)) {
break;
}
}
remove_filter(item, false);
}
}
}
}
}
/**
* Constructor
*/
ObjectsPanel::ObjectsPanel() :
_rootWatcher(0),
_deskTrack(),
_desktop(0),
_document(0),
_model(0),
_pending(0),
_toggleEvent(0),
_nameHeader(_("Label")),
_composite_vbox(false, 0),
_opacity_vbox(false, 0),
_opacity_label(_("Opacity:")),
_opacity_label_unit(_("%")),
#if WITH_GTKMM_3_0
#else
#endif
_fe_vbox(false, 0),
_blur_vbox(false, 0),
_colorSelectorDialog("dialogs.colorpickerwindow")
{
//Create the tree model and store
//Set up the tree
_tree.set_headers_visible(true);
_tree.set_reorderable(true);
//Create the column CellRenderers
//Visible
Inkscape::UI::Widget::ImageToggler *eyeRenderer = Gtk::manage( new Inkscape::UI::Widget::ImageToggler(
eyeRenderer->property_activatable() = true;
if ( col ) {
// In order to get tooltips on header, we must create our own label.
}
//Locked
Inkscape::UI::Widget::ImageToggler * renderer = Gtk::manage( new Inkscape::UI::Widget::ImageToggler(
renderer->property_activatable() = true;
if ( col ) {
_lockHeader.show();
}
//Type
Inkscape::UI::Widget::LayerTypeIcon * typeRenderer = Gtk::manage( new Inkscape::UI::Widget::LayerTypeIcon());
typeRenderer->property_activatable() = true;
if ( col ) {
_typeHeader.set_tooltip_text(_("Type: Layer, Group, or Object. Clicking on Layer or Group icon, toggles between the two types."));
_typeHeader.show();
}
//Insert order (LiamW: unused)
/*Inkscape::UI::Widget::InsertOrderIcon * insertRenderer = Gtk::manage( new Inkscape::UI::Widget::InsertOrderIcon());
int insertColNum = _tree.append_column("type", *insertRenderer) - 1;
col = _tree.get_column(insertColNum);
if ( col ) {
col->add_attribute( insertRenderer->property_active(), _model->_colInsertOrder );
}*/
Inkscape::UI::Widget::ClipMaskIcon * clipRenderer = Gtk::manage( new Inkscape::UI::Widget::ClipMaskIcon());
if ( col ) {
}
//Highlight
Inkscape::UI::Widget::HighlightPicker * highlightRenderer = Gtk::manage( new Inkscape::UI::Widget::HighlightPicker());
if ( col ) {
_highlightHeader.set_tooltip_text(_("Highlight color of outline in Node tool. Click to set. If alpha is zero, use inherited color."));
}
//Label
if( _name_column ) {
_nameHeader.set_tooltip_text(_("Layer/Group/Object label (inkscape:label). Double-click to set. Default value is object 'id'."));
_nameHeader.show();
}
//Set the expander and search columns
//Set up the tree selection
_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_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_editing_canceled().connect( sigc::mem_fun(*this, &ObjectsPanel::_handleEditingCancelled) );
//Set up the scroller window and pack the page
#if WITH_GTKMM_3_0
#else
#endif
int minHeight = 70;
// Set a min height to see the layers when used with Ubuntu liboverlay-scrollbar
}
//Set up the compositing items
//Blend mode filter effect
_blendConnection = _fe_cb.signal_blend_blur_changed().connect(sigc::mem_fun(*this, &ObjectsPanel::_blendValueChanged));
//Blur filter effect
_blurConnection = _fe_blur.signal_blend_blur_changed().connect(sigc::mem_fun(*this, &ObjectsPanel::_blurValueChanged));
//Opacity
_opacity_hscale.set_draw_value(false);
#if WITH_GTKMM_3_0
_opacityConnection = _opacity_adjustment->signal_value_changed().connect(sigc::mem_fun(*this, &ObjectsPanel::_opacityValueChanged));
#else
_opacityConnection = _opacity_adjustment.signal_value_changed().connect(sigc::mem_fun(*this, &ObjectsPanel::_opacityValueChanged));
#endif
//Keep the labels aligned
//Pack the compositing functions and the button row
//Pack into the panel contents
//Set up the button row
btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_takeAction), (int)BUTTON_NEW) );
//Remove object
btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_takeAction), (int)BUTTON_DELETE) );
//Move to bottom
btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_takeAction), (int)BUTTON_BOTTOM) );
//Move down
btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_takeAction), (int)BUTTON_DOWN) );
//Move up
btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_takeAction), (int)BUTTON_UP) );
//Move to top
btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_takeAction), (int)BUTTON_TOP) );
//Collapse all
btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_takeAction), (int)BUTTON_COLLAPSE_ALL) );
//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 ) );
_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 ) );
_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 ) );
_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 ) );
_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 ) );
_watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_SET_CLIPPATH, 0, _("Set Clip"), (int)BUTTON_SETCLIP ) );
_watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_CREATE_CLIP_GROUP, 0, _("Create Clip Group"), (int)BUTTON_CLIPGROUP ) );
//will never be implemented
//_watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_SET_INVERSE_CLIPPATH, 0, "Set Inverse Clip", (int)BUTTON_SETINVCLIP ) );
_watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_UNSET_CLIPPATH, 0, _("Unset Clip"), (int)BUTTON_UNSETCLIP ) );
_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 ) );
}
// -------------------------------------------------------
//Set initial sensitivity of buttons
(*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
_colorSelectorDialog.property_modal() = true;
Gtk::Widget *color_selector = Gtk::manage(new Inkscape::UI::Widget::ColorNotebook(*_selectedColor));
*color_selector, true, true, 0);
_selectedColor->signal_dragged.connect(sigc::mem_fun(*this, &ObjectsPanel::_highlightPickerColorMod));
_selectedColor->signal_released.connect(sigc::mem_fun(*this, &ObjectsPanel::_highlightPickerColorMod));
_selectedColor->signal_changed.connect(sigc::mem_fun(*this, &ObjectsPanel::_highlightPickerColorMod));
color_selector->show();
//Connect the desktop changed connection
desktopChangeConn = _deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &ObjectsPanel::setDesktop) );
}
/**
* Destructor
*/
{
//Close the highlight selection dialog
//Set the desktop to null, which will disconnect all object watchers
if ( _model )
{
delete _model;
_model = 0;
}
if (_pending) {
delete _pending;
_pending = 0;
}
if ( _toggleEvent )
{
_toggleEvent = 0;
}
}
/**
* Sets the current document
*/
{
//Clear all object watchers
while (!_objectWatchers.empty())
{
w->_repr->removeObserver(*w);
delete w;
}
//Delete the root watcher
if (_rootWatcher)
{
delete _rootWatcher;
_rootWatcher = NULL;
}
{
//Create a new root watcher for the document and then call _objectsChanged to fill the tree
}
}
/**
* Set the current panel desktop
*/
{
if ( _desktop ) {
_desktop = 0;
}
if ( _desktop ) {
//Connect desktop signals
_documentChangedConnection = _desktop->connectDocumentReplaced( sigc::mem_fun(*this, &ObjectsPanel::setDocument));
_selectionChangedConnection = _desktop->selection->connectChanged( sigc::mem_fun(*this, &ObjectsPanel::_objectsSelected));
} else {
}
}
}
} //namespace Dialogs
} //namespace UI
} //namespace Inkscape
//should be okay to put these here because they are never referenced anywhere else
{
if (color & 0x000000ff)
{
}
else
{
}
if (SP_ACTIVE_DESKTOP ) {
if (INK_IS_NODE_TOOL(ec)) {
}
}
}
void SPItem::unsetHighlightColor()
{
if (SP_ACTIVE_DESKTOP ) {
if (INK_IS_NODE_TOOL(ec)) {
}
}
}
/*
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 :