summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJohn Smith <john.smith7545@yahoo.com>2012-07-05 00:35:33 +0000
committerJohn Smith <john.smith7545@yahoo.com>2012-07-05 00:35:33 +0000
commit23b6b126c73efed2f651727f5f0c5763de3fd57c (patch)
tree891a930cb4379c9d76e668815ce9a872c8422f50 /src
parentFix for 168658 : Font substitution warning dialog - GTK3 compile (diff)
downloadinkscape-23b6b126c73efed2f651727f5f0c5763de3fd57c.tar.gz
inkscape-23b6b126c73efed2f651727f5f0c5763de3fd57c.zip
Fix for 181473 : Layers drag and drop
(bzr r11526)
Diffstat (limited to 'src')
-rw-r--r--src/sp-item.cpp46
-rw-r--r--src/sp-item.h1
-rw-r--r--src/ui/dialog/layers.cpp144
-rw-r--r--src/ui/dialog/layers.h12
4 files changed, 196 insertions, 7 deletions
diff --git a/src/sp-item.cpp b/src/sp-item.cpp
index d182c7d07..9f50e5e0c 100644
--- a/src/sp-item.cpp
+++ b/src/sp-item.cpp
@@ -368,6 +368,52 @@ void SPItem::lowerToBottom() {
}
}
+/*
+ * Move this SPItem into or after another SPItem in the doc
+ * \param target - the SPItem to move into or after
+ * \param intoafter - move to after the target (false), move inside (sublayer) of the target (true)
+ */
+void SPItem::moveTo(SPItem *target, gboolean intoafter) {
+
+ Inkscape::XML::Node *target_ref = ( target ? target->getRepr() : NULL );
+ Inkscape::XML::Node *our_ref = getRepr();
+ gboolean first = FALSE;
+
+ if (target_ref == our_ref) {
+ // Move to ourself ignore
+ return;
+ }
+
+ if (!target_ref) {
+ // Assume move to the "first" in the top node, find the top node
+ target_ref = our_ref;
+ while (target_ref->parent() != target_ref->root()) {
+ target_ref = target_ref->parent();
+ }
+ first = TRUE;
+ }
+
+ if (intoafter) {
+ // 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()) {
+ // Change in parent, need to remove and add
+ our_ref->parent()->removeChild(our_ref);
+ target_ref->parent()->addChild(our_ref, target_ref);
+ } else if (!first) {
+ // Same parent, just move
+ our_ref->parent()->changeOrder(our_ref, target_ref);
+ }
+
+ if (first) {
+ // If "first" ensure it appears after the defs etc
+ lowerToBottom();
+ return;
+ }
+}
+
+
void SPItem::sp_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
{
object->readAttr( "style" );
diff --git a/src/sp-item.h b/src/sp-item.h
index 62bde616a..2c7bd5a5d 100644
--- a/src/sp-item.h
+++ b/src/sp-item.h
@@ -174,6 +174,7 @@ public:
void lowerOne();
void raiseToTop();
void lowerToBottom();
+ void moveTo(SPItem *target, gboolean intoafter);
sigc::connection connectTransformed(sigc::slot<void, Geom::Affine const *, SPItem *> slot) {
return _transformed_signal.connect(slot);
diff --git a/src/ui/dialog/layers.cpp b/src/ui/dialog/layers.cpp
index 0a6900066..77873e5ec 100644
--- a/src/ui/dialog/layers.cpp
+++ b/src/ui/dialog/layers.cpp
@@ -66,7 +66,8 @@ enum {
BUTTON_DOWN,
BUTTON_DUPLICATE,
BUTTON_DELETE,
- BUTTON_SOLO
+ BUTTON_SOLO,
+ DRAGNDROP
};
class LayersPanel::InternalUIBounce
@@ -195,7 +196,7 @@ bool LayersPanel::_executeAction()
// Make sure selected layer hasn't changed since the action was triggered
if ( _pending
&& (
- (_pending->_actionCode == BUTTON_NEW)
+ (_pending->_actionCode == BUTTON_NEW || _pending->_actionCode == DRAGNDROP)
|| !( (_desktop && _desktop->currentLayer())
&& (_desktop->currentLayer() != _pending->_target)
)
@@ -250,6 +251,11 @@ bool LayersPanel::_executeAction()
_fireAction( SP_VERB_LAYER_SOLO );
}
break;
+ case DRAGNDROP:
+ {
+ _doTreeMove( );
+ }
+ break;
}
delete _pending;
@@ -503,10 +509,11 @@ void LayersPanel::_toggled( Glib::ustring const& str, int targetCol )
void LayersPanel::_handleButtonEvent(GdkEventButton* evt)
{
+ static unsigned doubleclick = 0;
+
// TODO - fix to a better is-popup function
if ( (evt->type == GDK_BUTTON_PRESS) && (evt->button == 3) ) {
-
{
Gtk::TreeModel::Path path;
Gtk::TreeViewColumn* col = 0;
@@ -523,21 +530,131 @@ void LayersPanel::_handleButtonEvent(GdkEventButton* evt)
}
}
+
+ if ( (evt->type == GDK_2BUTTON_PRESS) && (evt->button == 1) ) {
+ doubleclick = 1;
+ }
+
+ if ( evt->type == GDK_BUTTON_RELEASE && doubleclick) {
+ doubleclick = 0;
+ Gtk::TreeModel::Path path;
+ Gtk::TreeViewColumn* col = 0;
+ int x = static_cast<int>(evt->x);
+ int y = static_cast<int>(evt->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();
+ }
+ }
+
+}
+
+/*
+ * Drap and drop within the tree
+ * Save the drag source and drop target SPObjects and if its a drag between layers or into (sublayer) a layer
+ */
+bool LayersPanel::_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;
+ SPObject *selected = _selectedLayer();
+
+ _dnd_into = false;
+ _dnd_target = NULL;
+ _dnd_source = ( selected && SP_IS_ITEM(selected) ) ? SP_ITEM(selected) : 0;
+
+ if (_tree.get_path_at_pos (x, y, target_path, target_column, cell_x, cell_y)) {
+ // Are we before, inside or after the drop layer
+ Gdk::Rectangle rect;
+ _tree.get_background_area (target_path, *target_column, rect);
+ int cell_height = rect.get_height();
+ _dnd_into = (cell_y > (int)(cell_height * 1/3) && cell_y <= (int)(cell_height * 2/3));
+ if (cell_y > (int)(cell_height * 2/3)) {
+ Gtk::TreeModel::Path next_path = target_path;
+ next_path.next();
+ if (_store->iter_is_valid(_store->get_iter(next_path))) {
+ target_path = next_path;
+ } else {
+ // Dragging to the "end"
+ Gtk::TreeModel::Path up_path = target_path;
+ up_path.up();
+ if (_store->iter_is_valid(_store->get_iter(up_path))) {
+ // Drop into parent
+ target_path = up_path;
+ _dnd_into = true;
+ } else {
+ // Drop into the top level
+ _dnd_target = NULL;
+ }
+ }
+ }
+ Gtk::TreeModel::iterator iter = _store->get_iter(target_path);
+ if (_store->iter_is_valid(iter)) {
+ Gtk::TreeModel::Row row = *iter;
+ SPObject *obj = row[_model->_colObject];
+ _dnd_target = ( obj && SP_IS_ITEM(obj) ) ? SP_ITEM(obj) : 0;
+ }
+ }
+
+ _takeAction(DRAGNDROP);
+
+ return false;
+}
+
+/*
+ * Move a layer in response to a drag & drop action
+ */
+void LayersPanel::_doTreeMove( )
+{
+ if (_dnd_source ) {
+ _dnd_source->moveTo(_dnd_target, _dnd_into);
+ _selectLayer(_dnd_source);
+ _dnd_source = NULL;
+ DocumentUndo::done( _desktop->doc() , SP_VERB_NONE,
+ _("Moved layer"));
+
+ }
+}
+
+
+void LayersPanel::_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;
+
+ _renameLayer(row, new_text);
+ _text_renderer->property_editable() = false;
+}
+
+void LayersPanel::_handleEditingCancelled()
+{
+ _text_renderer->property_editable() = false;
}
void LayersPanel::_handleRowChange( Gtk::TreeModel::Path const& /*path*/, Gtk::TreeModel::iterator const& iter )
{
Gtk::TreeModel::Row row = *iter;
+ Glib::ustring label = row[_model->_colLabel];
+ _renameLayer(row, label);
+}
+
+void LayersPanel::_renameLayer(Gtk::TreeModel::Row row, const Glib::ustring& name)
+{
if ( row && _desktop && _desktop->layer_manager) {
SPObject* obj = row[_model->_colObject];
if ( obj ) {
gchar const* oldLabel = obj->label();
- Glib::ustring tmp = row[_model->_colLabel];
- if ( oldLabel && oldLabel[0] && !tmp.empty() && (tmp != oldLabel) ) {
- _desktop->layer_manager->renameLayer( obj, tmp.c_str(), FALSE );
+ if ( oldLabel && oldLabel[0] && !name.empty() && (name != oldLabel) ) {
+ _desktop->layer_manager->renameLayer( obj, name.c_str(), FALSE );
DocumentUndo::done( _desktop->doc() , SP_VERB_NONE,
_("Renamed layer"));
}
+
}
}
}
@@ -594,6 +711,8 @@ LayersPanel::LayersPanel() :
_tree.set_model( _store );
_tree.set_headers_visible(false);
+ _tree.set_reorderable(true);
+ _tree.enable_model_drag_dest (Gdk::ACTION_MOVE);
Inkscape::UI::Widget::ImageToggler *eyeRenderer = manage( new Inkscape::UI::Widget::ImageToggler(
INKSCAPE_ICON("object-visible"), INKSCAPE_ICON("object-hidden")) );
@@ -606,6 +725,7 @@ LayersPanel::LayersPanel() :
col->add_attribute( eyeRenderer->property_active(), _model->_colVisible );
}
+
Inkscape::UI::Widget::ImageToggler * renderer = manage( new Inkscape::UI::Widget::ImageToggler(
INKSCAPE_ICON("object-locked"), INKSCAPE_ICON("object-unlocked")) );
int lockedColNum = _tree.append_column("lock", *renderer) - 1;
@@ -617,7 +737,10 @@ LayersPanel::LayersPanel() :
col->add_attribute( renderer->property_active(), _model->_colLocked );
}
- int nameColNum = _tree.append_column_editable("Name", _model->_colLabel) - 1;
+ _text_renderer = manage(new Gtk::CellRendererText());
+ int nameColNum = _tree.append_column("Name", *_text_renderer) - 1;
+ _name_column = _tree.get_column(nameColNum);
+ _name_column->add_attribute(_text_renderer->property_text(), _model->_colLabel);
_tree.set_expander_column( *_tree.get_column(nameColNum) );
@@ -626,8 +749,15 @@ LayersPanel::LayersPanel() :
_selectedConnection = _tree.get_selection()->signal_changed().connect( sigc::mem_fun(*this, &LayersPanel::_pushTreeSelectionToCurrent) );
_tree.get_selection()->set_select_function( sigc::mem_fun(*this, &LayersPanel::_rowSelectFunction) );
+ _tree.signal_drag_drop().connect( sigc::mem_fun(*this, &LayersPanel::_handleDragDrop), false);
_tree.get_model()->signal_row_changed().connect( sigc::mem_fun(*this, &LayersPanel::_handleRowChange) );
+
+
+ _text_renderer->signal_edited().connect( sigc::mem_fun(*this, &LayersPanel::_handleEdited) );
+ _text_renderer->signal_editing_canceled().connect( sigc::mem_fun(*this, &LayersPanel::_handleEditingCancelled) );
+
_tree.signal_button_press_event().connect_notify( sigc::mem_fun(*this, &LayersPanel::_handleButtonEvent) );
+ _tree.signal_button_release_event().connect_notify( sigc::mem_fun(*this, &LayersPanel::_handleButtonEvent) );
_scroller.add( _tree );
_scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC );
diff --git a/src/ui/dialog/layers.h b/src/ui/dialog/layers.h
index 7959d0e6e..6d3ea2224 100644
--- a/src/ui/dialog/layers.h
+++ b/src/ui/dialog/layers.h
@@ -67,6 +67,12 @@ private:
void _handleButtonEvent(GdkEventButton* evt);
void _handleRowChange( Gtk::TreeModel::Path const& path, Gtk::TreeModel::iterator const& 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 _renameLayer(Gtk::TreeModel::Row row, const Glib::ustring& name);
void _pushTreeSelectionToCurrent();
void _checkTreeSelection();
@@ -102,13 +108,19 @@ private:
SPDesktop* _desktop;
ModelColumns* _model;
InternalUIBounce* _pending;
+ gboolean _dnd_into;
+ SPItem* _dnd_source;
+ SPItem* _dnd_target;
GdkEvent* _toggleEvent;
+
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::ButtonBox _buttonsRow;
#else