X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fui%2Ftool%2Fnode-tool.cpp;h=8661e79465dbf13ef75c43501da10230c1d3eb5c;hb=030609cb99174ea85e69635c494ccaaaa20b2ac5;hp=443e7f2585abb027c867f97763a286ffc05d3bd7;hpb=169137abdc47194cc713151697e7c269835459e7;p=inkscape.git diff --git a/src/ui/tool/node-tool.cpp b/src/ui/tool/node-tool.cpp index 443e7f258..8661e7946 100644 --- a/src/ui/tool/node-tool.cpp +++ b/src/ui/tool/node-tool.cpp @@ -3,6 +3,7 @@ */ /* Authors: * Krzysztof Kosiński + * Abhishek Sharma * * Copyright (C) 2009 Authors * Released under GNU GPL, read the file 'COPYING' for more information @@ -25,6 +26,7 @@ #include "sp-mask.h" #include "sp-object-group.h" #include "sp-path.h" +#include "sp-text.h" #include "ui/tool/node-tool.h" #include "ui/tool/control-point-selection.h" #include "ui/tool/curve-drag-point.h" @@ -71,7 +73,17 @@ * is to eventually use a common class for object and control point transforms. * - SelectableControlPoint: base for any type of selectable point. It can belong to only one * selection. - * + * + * @par Functionality that resides in weird places + * @par + * + * This list is probably incomplete. + * - Curve dragging: CurveDragPoint, controlled by PathManipulator + * - Single handle shortcuts: MultiPathManipulator::event(), ModifierTracker + * - Linear and spatial grow: Node, spatial grow routed to ControlPointSelection + * - Committing handle actions performed with the mouse: PathManipulator + * - Sculpting: ControlPointSelection + * * @par Plans for the future * @par * - MultiPathManipulator should become a generic shape editor that manages all active manipulator, @@ -164,6 +176,7 @@ void ink_node_tool_init(InkNodeTool *nt) new (&nt->_multipath) MultiPathPtr(); new (&nt->_selector) SelectorPtr(); new (&nt->_path_data) PathSharedDataPtr(); + new (&nt->_shape_editors) ShapeEditors(); } void ink_node_tool_dispose(GObject *object) @@ -178,6 +191,7 @@ void ink_node_tool_dispose(GObject *object) nt->_multipath.~MultiPathPtr(); nt->_selected_nodes.~CSelPtr(); nt->_selector.~SelectorPtr(); + nt->_shape_editors.~ShapeEditors(); Inkscape::UI::PathSharedData &data = *nt->_path_data; destroy_group(data.node_data.node_group); @@ -195,10 +209,6 @@ void ink_node_tool_dispose(GObject *object) if (nt->_node_message_context) { delete nt->_node_message_context; } - if (nt->shape_editor) { - nt->shape_editor->unset_item(SH_KNOTHOLDER); - delete nt->shape_editor; - } G_OBJECT_CLASS(g_type_class_peek(g_type_parent(INK_TYPE_NODE_TOOL)))->dispose(object); } @@ -281,9 +291,6 @@ void ink_node_tool_setup(SPEventContext *ec) nt->flash_tempitem = NULL; nt->flashed_item = NULL; nt->_last_over = NULL; - // TODO long term, fold ShapeEditor into MultiPathManipulator and rename MPM - // to something better - nt->shape_editor = new ShapeEditor(nt->desktop); // read prefs before adding items to selection to prevent momentarily showing the outline sp_event_context_read(nt, "show_handles"); @@ -316,7 +323,8 @@ void ink_node_tool_set(SPEventContext *ec, Inkscape::Preferences::Entry *value) Glib::ustring entry_name = value->getEntryName(); if (entry_name == "show_handles") { - nt->_multipath->showHandles(value->getBool(true)); + nt->show_handles = value->getBool(true); + nt->_multipath->showHandles(nt->show_handles); } else if (entry_name == "show_outline") { nt->show_outline = value->getBool(); nt->_multipath->showOutline(nt->show_outline); @@ -358,7 +366,8 @@ void gather_items(InkNodeTool *nt, SPItem *base, SPObject *obj, Inkscape::UI::Sh using namespace Inkscape::UI; if (!obj) return; - if (SP_IS_PATH(obj) && obj->repr->attribute("inkscape:original-d") != NULL) { + //XML Tree being used directly here while it shouldn't be. + if (SP_IS_PATH(obj) && obj->getRepr()->attribute("inkscape:original-d") != NULL) { ShapeRecord r; r.item = static_cast(obj); r.edit_transform = Geom::identity(); // TODO wrong? @@ -373,7 +382,7 @@ void gather_items(InkNodeTool *nt, SPItem *base, SPObject *obj, Inkscape::UI::Sh ShapeRecord r; r.item = item; // TODO add support for objectBoundingBox - r.edit_transform = base ? sp_item_i2doc_affine(base) : Geom::identity(); + r.edit_transform = base ? base->i2doc_affine() : Geom::identity(); r.role = role; if (s.insert(r).second) { // this item was encountered the first time @@ -402,22 +411,30 @@ void ink_node_tool_selection_changed(InkNodeTool *nt, Inkscape::Selection *sel) } } - // ugly hack: set the first editable non-path item for knotholder - // maybe use multiple ShapeEditors for now, to allow editing many shapes at once? - bool something_set = false; + // use multiple ShapeEditors for now, to allow editing many shapes at once + // needs to be rethought + for (ShapeEditors::iterator i = nt->_shape_editors.begin(); + i != nt->_shape_editors.end(); ) + { + ShapeRecord s; + s.item = i->first; + if (shapes.find(s) == shapes.end()) { + nt->_shape_editors.erase(i++); + } else { + ++i; + } + } + for (std::set::iterator i = shapes.begin(); i != shapes.end(); ++i) { ShapeRecord const &r = *i; - if (SP_IS_SHAPE(r.item) || - (SP_IS_PATH(r.item) && r.item->repr->attribute("inkscape:original-d") != NULL)) + if ((SP_IS_SHAPE(r.item) || SP_IS_TEXT(r.item)) && + nt->_shape_editors.find(r.item) == nt->_shape_editors.end()) { - nt->shape_editor->set_item(r.item, SH_KNOTHOLDER); - something_set = true; - break; + ShapeEditor *si = new ShapeEditor(nt->desktop); + si->set_item(r.item, SH_KNOTHOLDER); + nt->_shape_editors.insert(const_cast(r.item), si); } } - if (!something_set) { - nt->shape_editor->unset_item(SH_KNOTHOLDER); - } nt->_multipath->setItems(shapes); ink_node_tool_update_tip(nt, NULL); @@ -466,7 +483,7 @@ gint ink_node_tool_root_handler(SPEventContext *event_context, GdkEvent *event) nt->flashed_item = over_item; SPCurve *c = sp_path_get_curve_for_edit(SP_PATH(over_item)); - c->transform(sp_item_i2d_affine(over_item)); + c->transform(over_item->i2d_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, @@ -491,6 +508,7 @@ gint ink_node_tool_root_handler(SPEventContext *event_context, GdkEvent *event) ink_node_tool_update_tip(nt, event); return TRUE; case GDK_a: + case GDK_A: if (held_control(event->key) && held_alt(event->key)) { nt->_selected_nodes->selectAll(); // Ctrl+A is handled in selection-chemistry.cpp via verb @@ -498,6 +516,14 @@ gint ink_node_tool_root_handler(SPEventContext *event_context, GdkEvent *event) return TRUE; } break; + case GDK_h: + case GDK_H: + if (held_only_control(event->key)) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/nodes/show_handles", !nt->show_handles); + return TRUE; + } + break; default: break; } @@ -524,11 +550,11 @@ void ink_node_tool_update_tip(InkNodeTool *nt, GdkEvent *event) if (state_held_shift(new_state)) { if (nt->_last_over) { nt->_node_message_context->set(Inkscape::NORMAL_MESSAGE, - C_("Node tool tip", "Shift: drag to add nodes to the selection, " + C_("Node tool tip", "Shift: drag to add nodes to the selection, " "click to toggle object selection")); } else { nt->_node_message_context->set(Inkscape::NORMAL_MESSAGE, - C_("Node tool tip", "Shift: drag to add nodes to the selection")); + C_("Node tool tip", "Shift: drag to add nodes to the selection")); } return; } @@ -536,19 +562,24 @@ void ink_node_tool_update_tip(InkNodeTool *nt, GdkEvent *event) unsigned sz = nt->_selected_nodes->size(); unsigned total = nt->_selected_nodes->allPoints().size(); if (sz != 0) { + char *nodestring = g_strdup_printf( + ngettext("%u of %u node selected.", "%u of %u nodes selected.", total), + sz, total); if (nt->_last_over) { + // TRANSLATORS: The %s below is where the "%u of %u nodes selected" sentence gets put char *dyntip = g_strdup_printf(C_("Node tool tip", - "%u of %u nodes selected. " - "Drag to select nodes, click to edit only this object (more: Shift)"), sz, total); + "%s Drag to select nodes, click to edit only this object (more: Shift)"), + nodestring); nt->_node_message_context->set(Inkscape::NORMAL_MESSAGE, dyntip); g_free(dyntip); } else { char *dyntip = g_strdup_printf(C_("Node tool tip", - "%u of %u nodes selected. " - "Drag to select nodes, click clear the selection"), sz, total); + "%s Drag to select nodes, click clear the selection"), + nodestring); nt->_node_message_context->set(Inkscape::NORMAL_MESSAGE, dyntip); g_free(dyntip); } + g_free(nodestring); } else if (!nt->_multipath->empty()) { if (nt->_last_over) { nt->_node_message_context->set(Inkscape::NORMAL_MESSAGE, C_("Node tool tip", @@ -583,8 +614,7 @@ void ink_node_tool_select_area(InkNodeTool *nt, Geom::Rect const &sel, GdkEventB if (nt->_multipath->empty()) { // if multipath is empty, select rubberbanded items rather than nodes Inkscape::Selection *selection = nt->desktop->selection; - GSList *items = sp_document_items_in_box( - sp_desktop_document(nt->desktop), nt->desktop->dkey, sel); + GSList *items = sp_desktop_document(nt->desktop)->getItemsInBox(nt->desktop->dkey, sel); selection->setList(items); g_slist_free(items); } else { @@ -605,8 +635,14 @@ void ink_node_tool_select_point(InkNodeTool *nt, Geom::Point const &/*sel*/, Gdk if (item_clicked == NULL) { // nothing under cursor // if no Shift, deselect - if (!(event->state & GDK_SHIFT_MASK)) { - selection->clear(); + // if there are nodes selected, the first click should deselect the nodes + // and the second should deselect the items + if (!state_held_shift(event->state)) { + if (nt->_selected_nodes->empty()) { + selection->clear(); + } else { + nt->_selected_nodes->clear(); + } } } else { if (held_shift(*event)) { @@ -648,4 +684,4 @@ void ink_node_tool_mouseover_changed(InkNodeTool *nt, Inkscape::UI::ControlPoint fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :