From 89363253b6fc2e0f1d01136fb91f039599236be2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 16 Dec 2010 20:27:26 +0100 Subject: Node tool: correctly save node skewing to undo history Fixed bugs: - https://launchpad.net/bugs/590259 (bzr r9956) --- src/ui/tool/multi-path-manipulator.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index ef1c764bb..5f60f117a 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -695,6 +695,14 @@ void MultiPathManipulator::_commit(CommitEvent cps) reason = _("Scale nodes vertically"); key = "node:scale:y"; break; + case COMMIT_MOUSE_SKEW_X: + reason = _("Skew nodes horizontally"); + key = "node:skew:x"; + break; + case COMMIT_MOUSE_SKEW_Y: + reason = _("Skew nodes vertically"); + key = "node:skew:y"; + break; case COMMIT_FLIP_X: reason = _("Flip nodes horizontally"); break; -- cgit v1.2.3 From cb1e5c9cd7b8d9c44f728433d9300e04209d8585 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 16 Dec 2010 20:28:30 +0100 Subject: Node tool: fix moving multiple nodes along handles (Ctrl+Alt) Fixed bugs: - https://launchpad.net/bugs/642536 (bzr r9957) --- src/ui/tool/control-point-selection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/tool/control-point-selection.cpp b/src/ui/tool/control-point-selection.cpp index 91e0bc2c2..baa53f76e 100644 --- a/src/ui/tool/control-point-selection.cpp +++ b/src/ui/tool/control-point-selection.cpp @@ -290,7 +290,7 @@ void ControlPointSelection::_pointDragged(Geom::Point &new_pos, GdkEventMotion * { Geom::Point abs_delta = new_pos - _original_positions[_grabbed_point]; double fdist = Geom::distance(_original_positions[_grabbed_point], _original_positions[_farthest_point]); - if (held_alt(*event) && fdist > 0) { + if (held_only_alt(*event) && fdist > 0) { // Sculpting for (iterator i = _points.begin(); i != _points.end(); ++i) { SelectableControlPoint *cur = (*i); -- cgit v1.2.3 From 981c5891a7cf64021d724f4b33d133f66427e18c Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 16 Dec 2010 21:11:16 +0100 Subject: Node tool: fix handle retraction with non-cusp nodes Fixed bugs: - https://launchpad.net/bugs/610817 (bzr r9958) --- src/ui/tool/node.cpp | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index 12d04dd2b..1ea994bb9 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -113,12 +113,29 @@ void Handle::move(Geom::Point const &new_pos) Handle *towards_second = node_towards ? node_towards->handleToward(_parent) : NULL; if (Geom::are_near(new_pos, _parent->position())) { - // The handle becomes degenerate. If the segment between it and the node + // The handle becomes degenerate. + // Adjust node type as necessary. + if (other->isDegenerate()) { + // If both handles become degenerate, convert to parent cusp node + _parent->setType(NODE_CUSP, false); + } else { + // Only 1 handle becomes degenerate + switch (_parent->type()) { + case NODE_AUTO: + case NODE_SYMMETRIC: + _parent->setType(NODE_SMOOTH, false); + break; + default: + // do nothing for other node types + break; + } + } + // If the segment between the handle and the node // in its direction becomes linear and there are smooth nodes // at its ends, make their handles colinear with the segment - if (towards && towards->isDegenerate()) { + if (towards && towards_second->isDegenerate()) { if (node_towards->type() == NODE_SMOOTH) { - towards_second->setDirection(*_parent, *node_towards); + towards->setDirection(*_parent, *node_towards); } if (_parent->type() == NODE_SMOOTH) { other->setDirection(*node_towards, *_parent); @@ -160,6 +177,7 @@ void Handle::move(Geom::Point const &new_pos) void Handle::setPosition(Geom::Point const &p) { + Geom::Point old_pos = position(); ControlPoint::setPosition(p); sp_ctrlline_set_coords(SP_CTRLLINE(_handle_line), _parent->position(), position()); @@ -167,15 +185,12 @@ void Handle::setPosition(Geom::Point const &p) if (Geom::are_near(position(), _parent->position())) _degenerate = true; else _degenerate = false; + if (_parent->_handles_shown && _parent->visible() && !_degenerate) { setVisible(true); } else { setVisible(false); } - // If both handles become degenerate, convert to parent cusp node - if (_parent->isDegenerate()) { - _parent->setType(NODE_CUSP, false); - } } void Handle::setLength(double len) @@ -187,7 +202,7 @@ void Handle::setLength(double len) void Handle::retract() { - setPosition(_parent->position()); + move(_parent->position()); } void Handle::setDirection(Geom::Point const &from, Geom::Point const &to) -- cgit v1.2.3 From d7f88cb16397d88cd5839bd71c1091f3332bec8a Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 16 Dec 2010 21:56:43 +0100 Subject: Node tool: fix snapping during constrained rotation of handles (bzr r9959) --- src/ui/tool/node.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index 1ea994bb9..a79a5c409 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -241,6 +241,7 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) Geom::Point origin = _last_drag_origin(); SnapManager &sm = _desktop->namedview->snap_manager; bool snap = sm.someSnapperMightSnap(); + boost::optional ctrl_constraint; // with Alt, preserve length if (held_alt(*event)) { @@ -256,16 +257,23 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) // note: if snapping to the original position is only desired in the original // direction of the handle, change to Ray instead of Line Geom::Line original_line(parent_pos, origin); + Geom::Line perp_line(parent_pos, parent_pos + Geom::rot90(origin - parent_pos)); Geom::Point snap_pos = parent_pos + Geom::constrain_angle( Geom::Point(0,0), new_pos - parent_pos, snaps, Geom::Point(1,0)); Geom::Point orig_pos = original_line.pointAt(original_line.nearestPoint(new_pos)); + Geom::Point perp_pos = perp_line.pointAt(perp_line.nearestPoint(new_pos)); - if (Geom::distance(snap_pos, new_pos) < Geom::distance(orig_pos, new_pos)) { - new_pos = snap_pos; - } else { - new_pos = orig_pos; + Geom::Point result = snap_pos; + ctrl_constraint = Inkscape::Snapper::SnapConstraint(parent_pos, parent_pos - snap_pos); + if (Geom::distance(orig_pos, new_pos) < Geom::distance(result, new_pos)) { + result = orig_pos; + ctrl_constraint = Inkscape::Snapper::SnapConstraint(parent_pos, parent_pos - orig_pos); } - snap = false; + if (Geom::distance(perp_pos, new_pos) < Geom::distance(result, new_pos)) { + result = perp_pos; + ctrl_constraint = Inkscape::Snapper::SnapConstraint(parent_pos, parent_pos - perp_pos); + } + new_pos = result; } std::vector unselected; @@ -279,13 +287,20 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) } sm.setupIgnoreSelection(_desktop, true, &unselected); - Node *node_away = (this == &_parent->_front ? _parent->_prev() : _parent->_next()); + Node *node_away = _parent->nodeAwayFrom(this); if (_parent->type() == NODE_SMOOTH && Node::_is_line_segment(_parent, node_away)) { Inkscape::Snapper::SnapConstraint cl(_parent->position(), _parent->position() - node_away->position()); Inkscape::SnappedPoint p; p = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, SNAPSOURCE_NODE_HANDLE), cl); new_pos = p.getPoint(); + } else if (ctrl_constraint) { + // NOTE: this is subtly wrong. + // We should get all possible constraints and snap along them using + // multipleConstrainedSnaps, instead of first snapping to angle and the to objects + Inkscape::SnappedPoint p; + p = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, SNAPSOURCE_NODE_HANDLE), *ctrl_constraint); + new_pos = p.getPoint(); } else { sm.freeSnapReturnByRef(new_pos, SNAPSOURCE_NODE_HANDLE); } -- cgit v1.2.3 From d18ee1bd701f1e78a42fc4253f7a5c4e7ece714a Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 16 Dec 2010 23:07:52 +0100 Subject: Node tool: fix snapping of node rotation center Fixed bugs: - https://launchpad.net/bugs/667072 (bzr r9960) --- src/ui/tool/node.cpp | 29 +++++++++++++++++++++++++++++ src/ui/tool/node.h | 1 + src/ui/tool/transform-handle-set.cpp | 20 +++++++++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index a79a5c409..fea02d399 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -227,6 +227,35 @@ char const *Handle::handle_type_to_localized_string(NodeType type) } } +bool Handle::_eventHandler(GdkEvent *event) +{ + switch (event->type) + { + case GDK_KEY_PRESS: + switch (shortcut_key(event->key)) + { + case GDK_s: + case GDK_S: + if (held_only_shift(event->key) && _parent->_type == NODE_CUSP) { + // when Shift+S is pressed when hovering over a handle belonging to a cusp node, + // hold this handle in place; otherwise process normally + // this handle is guaranteed not to be degenerate + other()->move(_parent->position() - (position() - _parent->position())); + _parent->setType(NODE_SMOOTH, false); + _parent->_pm().update(); // magic triple combo to add undo event + _parent->_pm().writeXML(); + _parent->_pm()._commit(_("Change node type")); + return true; + } + break; + default: break; + } + default: break; + } + + return ControlPoint::_eventHandler(event); +} + bool Handle::grabbed(GdkEventMotion *) { _saved_other_pos = other()->position(); diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h index 0194f5053..b5d4d88f2 100644 --- a/src/ui/tool/node.h +++ b/src/ui/tool/node.h @@ -102,6 +102,7 @@ public: protected: Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent); + virtual bool _eventHandler(GdkEvent *event); virtual void dragged(Geom::Point &, GdkEventMotion *); virtual bool grabbed(GdkEventMotion *); virtual void ungrabbed(GdkEventButton *); diff --git a/src/ui/tool/transform-handle-set.cpp b/src/ui/tool/transform-handle-set.cpp index ef93a3767..cafd592a3 100644 --- a/src/ui/tool/transform-handle-set.cpp +++ b/src/ui/tool/transform-handle-set.cpp @@ -18,6 +18,8 @@ #include "desktop-handles.h" #include "display/sodipodi-ctrlrect.h" #include "preferences.h" +#include "snap.h" +#include "sp-namedview.h" #include "ui/tool/commit-events.h" #include "ui/tool/control-point.h" #include "ui/tool/event-utils.h" @@ -473,7 +475,23 @@ public: } protected: - + virtual void dragged(Geom::Point &new_pos, GdkEventMotion *event) { + SnapManager &sm = _desktop->namedview->snap_manager; + sm.setup(_desktop); + bool snap = !held_shift(*event) && sm.someSnapperMightSnap(); + if (held_control(*event)) { + // constrain to axes + Geom::Point origin = _last_drag_origin(); + std::vector constraints; + constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, Geom::Point(1, 0))); + constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, Geom::Point(0, 1))); + new_pos = sm.multipleConstrainedSnaps(Inkscape::SnapCandidatePoint(new_pos, + SNAPSOURCE_ROTATION_CENTER), constraints, held_shift(*event)).getPoint(); + } else if (snap) { + sm.freeSnapReturnByRef(new_pos, SNAPSOURCE_ROTATION_CENTER); + } + sm.unSetup(); + } virtual Glib::ustring _getTip(unsigned /*state*/) { return C_("Transform handle tip", "Rotation center: drag to change the origin of transforms"); -- cgit v1.2.3 From 3a38979f6034517961c09e0af5a3028f0d6d7a52 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 17 Dec 2010 00:01:36 +0100 Subject: Node tool: fix Tab and Shift+Tab (bzr r9961) --- src/ui/tool/multi-path-manipulator.cpp | 73 +++++++++++++++++++++++++++++++++- src/ui/tool/path-manipulator.cpp | 59 +-------------------------- src/ui/tool/path-manipulator.h | 4 +- 3 files changed, 76 insertions(+), 60 deletions(-) diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index 5f60f117a..082ac194b 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -210,7 +210,78 @@ void MultiPathManipulator::selectSubpaths() void MultiPathManipulator::shiftSelection(int dir) { - invokeForAll(&PathManipulator::shiftSelection, dir); + if (empty()) return; + + // 1. find last selected node + // 2. select the next node; if the last node or nothing is selected, + // select first node + MapType::iterator last_i; + SubpathList::iterator last_j; + NodeList::iterator last_k; + bool anything_found = false; + + for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { + SubpathList &sp = i->second->subpathList(); + for (SubpathList::iterator j = sp.begin(); j != sp.end(); ++j) { + for (NodeList::iterator k = (*j)->begin(); k != (*j)->end(); ++k) { + if (k->selected()) { + last_i = i; + last_j = j; + last_k = k; + anything_found = true; + // when tabbing backwards, we want the first node + if (dir == -1) goto exit_loop; + } + } + } + } + exit_loop: + + // NOTE: we should not assume the _selection contains only nodes + // in future it might also contain handles and other types of control points + // this is why we use a flag instead in the loop above, instead of calling + // selection.empty() + if (!anything_found) { + // select first / last node + // this should never fail because there must be at least 1 non-empty manipulator + if (dir == 1) { + _selection.insert((*_mmap.begin()->second->subpathList().begin())->begin().ptr()); + } else { + _selection.insert((--(*--(--_mmap.end())->second->subpathList().end())->end()).ptr()); + } + return; + } + + // three levels deep - w00t! + if (dir == 1) { + if (++last_k == (*last_j)->end()) { + // here, last_k points to the node to be selected + ++last_j; + if (last_j == last_i->second->subpathList().end()) { + ++last_i; + if (last_i == _mmap.end()) { + last_i = _mmap.begin(); + } + last_j = last_i->second->subpathList().begin(); + } + last_k = (*last_j)->begin(); + } + } else { + if (!last_k || last_k == (*last_j)->begin()) { + if (last_j == last_i->second->subpathList().begin()) { + if (last_i == _mmap.begin()) { + last_i = _mmap.end(); + } + --last_i; + last_j = last_i->second->subpathList().end(); + } + --last_j; + last_k = (*last_j)->end(); + } + --last_k; + } + _selection.clear(); + _selection.insert(last_k.ptr()); } void MultiPathManipulator::invertSelectionInSubpaths() diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index 5ae9c4137..7c60efbab 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -215,7 +215,7 @@ void PathManipulator::clear() /** Select all nodes in subpaths that have something selected. */ void PathManipulator::selectSubpaths() { - for (std::list::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) { + for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) { NodeList::iterator sp_start = (*i)->begin(), sp_end = (*i)->end(); for (NodeList::iterator j = sp_start; j != sp_end; ++j) { if (j->selected()) { @@ -229,63 +229,6 @@ void PathManipulator::selectSubpaths() } } -/** Move the selection forward or backward by one node in each subpath, based on the sign - * of the parameter. */ -void PathManipulator::shiftSelection(int dir) -{ - if (dir == 0) return; - if (_num_selected == 0) { - // select the first node of the path. - SubpathList::iterator s = _subpaths.begin(); - if (s == _subpaths.end()) return; - NodeList::iterator n = (*s)->begin(); - if (n != (*s)->end()) - _selection.insert(n.ptr()); - return; - } - // We cannot do any tricks here, like iterating in different directions based on - // the sign and only setting the selection of nodes behind us, because it would break - // for closed paths. - for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) { - std::deque sels; // I hope this is specialized for bools! - unsigned num = 0; - - for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) { - sels.push_back(j->selected()); - _selection.erase(j.ptr()); - ++num; - } - if (num == 0) continue; // should never happen! zero-node subpaths are not allowed - - num = 0; - // In closed subpath, shift the selection cyclically. In an open one, - // let the selection 'slide into nothing' at ends. - if (dir > 0) { - if ((*i)->closed()) { - bool last = sels.back(); - sels.pop_back(); - sels.push_front(last); - } else { - sels.push_front(false); - } - } else { - if ((*i)->closed()) { - bool first = sels.front(); - sels.pop_front(); - sels.push_back(first); - } else { - sels.push_back(false); - num = 1; - } - } - - for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) { - if (sels[num]) _selection.insert(j.ptr()); - ++num; - } - } -} - /** Invert selection in the selected subpaths. */ void PathManipulator::invertSelectionInSubpaths() { diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h index 87b88fc77..8a0167e59 100644 --- a/src/ui/tool/path-manipulator.h +++ b/src/ui/tool/path-manipulator.h @@ -65,7 +65,6 @@ public: SPPath *item() { return _path; } void selectSubpaths(); - void shiftSelection(int dir); void invertSelectionInSubpaths(); void insertNodes(); @@ -94,6 +93,9 @@ public: NodeList::iterator extremeNode(NodeList::iterator origin, bool search_selected, bool search_unselected, bool closest); + // this is necessary for Tab-selection in MultiPathManipulator + SubpathList &subpathList() { return _subpaths; } + static bool is_item_type(void *item); private: typedef NodeList Subpath; -- cgit v1.2.3 From 69059080428adb8b6258a6d5de15f0028c4444f8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 17 Dec 2010 00:16:33 +0100 Subject: Node tool: special case node duplication for endnodes - select new endnode (bzr r9962) --- src/ui/tool/path-manipulator.cpp | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index 7c60efbab..ea7f3412d 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -275,22 +275,31 @@ void PathManipulator::duplicateNodes() NodeList::iterator k = j.next(); Node *n = new Node(_multi_path_manipulator._path_data.node_data, *j); - // Move the new node to the bottom of the Z-order. This way you can drag all - // nodes that were selected before this operation without deselecting - // everything because there is a new node above. - n->sink(); + if (k) { + // Move the new node to the bottom of the Z-order. This way you can drag all + // nodes that were selected before this operation without deselecting + // everything because there is a new node above. + n->sink(); + } n->front()->setPosition(*j->front()); j->front()->retract(); j->setType(NODE_CUSP, false); (*i)->insert(k, n); - // We need to manually call the selection change callback to refresh - // the handle display correctly. - // This call changes num_selected, but we call this once for a selected node - // and once for an unselected node, so in the end the number stays correct. - _selectionChanged(j.ptr(), true); - _selectionChanged(n, false); + if (k) { + // We need to manually call the selection change callback to refresh + // the handle display correctly. + // This call changes num_selected, but we call this once for a selected node + // and once for an unselected node, so in the end the number stays correct. + _selectionChanged(j.ptr(), true); + _selectionChanged(n, false); + } else { + // select the new end node instead of the node just before it + _selection.erase(j.ptr()); + _selection.insert(n); + break; // this was the end node, nothing more to do + } } } } -- cgit v1.2.3 From c799a45ef4123181d91eb4f2d91c4d2ceec45685 Mon Sep 17 00:00:00 2001 From: Kris De Gussem Date: Fri, 17 Dec 2010 16:30:57 +0100 Subject: User message context in extensions (bzr r9963) --- share/extensions/gcodetools_all_in_one.inx | 2 +- share/extensions/gcodetools_area.inx | 2 +- share/extensions/measure.inx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/share/extensions/gcodetools_all_in_one.inx b/share/extensions/gcodetools_all_in_one.inx index 0f566fc7b..85d7cfbee 100644 --- a/share/extensions/gcodetools_all_in_one.inx +++ b/share/extensions/gcodetools_all_in_one.inx @@ -15,7 +15,7 @@ The segment will be split into two segments if the distance between path's segme - + 100 -10 diff --git a/share/extensions/gcodetools_area.inx b/share/extensions/gcodetools_area.inx index 718ae0d9f..53ceeafaa 100644 --- a/share/extensions/gcodetools_area.inx +++ b/share/extensions/gcodetools_area.inx @@ -6,7 +6,7 @@ inkex.py - + 100 -10 diff --git a/share/extensions/measure.inx b/share/extensions/measure.inx index 264e33ab6..63a919806 100644 --- a/share/extensions/measure.inx +++ b/share/extensions/measure.inx @@ -8,7 +8,7 @@ <_item value="length">Length - <_item value="area">Area + <_item msgctxt="measure extension" value="area">Area 12 -6 -- cgit v1.2.3 From c3051ca878d6120911d9ca6534dfd63ad80cb19d Mon Sep 17 00:00:00 2001 From: Kris De Gussem Date: Fri, 17 Dec 2010 17:06:36 +0100 Subject: Mnemonics in fill and stroke dialog and menu (bzr r9964) --- src/ui/dialog/fill-and-stroke.cpp | 2 +- src/ui/widget/filter-effect-chooser.cpp | 2 +- src/ui/widget/object-composite-settings.cpp | 3 ++- src/verbs.cpp | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ui/dialog/fill-and-stroke.cpp b/src/ui/dialog/fill-and-stroke.cpp index 0c234003e..19bcadc00 100644 --- a/src/ui/dialog/fill-and-stroke.cpp +++ b/src/ui/dialog/fill-and-stroke.cpp @@ -54,7 +54,7 @@ FillAndStroke::FillAndStroke() contents->pack_start(_notebook, true, true); - _notebook.append_page(_page_fill, _createPageTabLabel(_("Fill"), INKSCAPE_ICON_OBJECT_FILL)); + _notebook.append_page(_page_fill, _createPageTabLabel(_("_Fill"), INKSCAPE_ICON_OBJECT_FILL)); _notebook.append_page(_page_stroke_paint, _createPageTabLabel(_("Stroke _paint"), INKSCAPE_ICON_OBJECT_STROKE)); _notebook.append_page(_page_stroke_style, _createPageTabLabel(_("Stroke st_yle"), INKSCAPE_ICON_OBJECT_STROKE_STYLE)); diff --git a/src/ui/widget/filter-effect-chooser.cpp b/src/ui/widget/filter-effect-chooser.cpp index 309730600..aba3a18e8 100644 --- a/src/ui/widget/filter-effect-chooser.cpp +++ b/src/ui/widget/filter-effect-chooser.cpp @@ -23,7 +23,7 @@ namespace Widget { SimpleFilterModifier::SimpleFilterModifier(int flags) : _lb_blend(_("_Blend mode:")), - _lb_blur(_("Blur:"), Gtk::ALIGN_LEFT), + _lb_blur(_("_Blur:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, true), _blend(BlendModeConverter, SP_ATTR_INVALID, false), _blur(0, 0, 100, 1, 0.01, 1) { diff --git a/src/ui/widget/object-composite-settings.cpp b/src/ui/widget/object-composite-settings.cpp index 1de425da3..997c2f0dc 100644 --- a/src/ui/widget/object-composite-settings.cpp +++ b/src/ui/widget/object-composite-settings.cpp @@ -60,7 +60,7 @@ ObjectCompositeSettings::ObjectCompositeSettings(unsigned int verb_code, char co _opacity_tag(Glib::ustring(history_prefix) + ":opacity"), _opacity_vbox(false, 0), _opacity_label_box(false, 0), - _opacity_label(_("Opacity (%):"), 0.0, 1.0, true), + _opacity_label(_("_Opacity (%):"), 0.0, 1.0, true), _opacity_adjustment(100.0, 0.0, 100.0, 1.0, 1.0, 0.0), _opacity_hscale(_opacity_adjustment), _opacity_spin_button(_opacity_adjustment, 0.01, 1), @@ -86,6 +86,7 @@ ObjectCompositeSettings::ObjectCompositeSettings(unsigned int verb_code, char co _opacity_hscale.set_draw_value(false); _opacity_hscale.set_update_policy(Gtk::UPDATE_DELAYED); _opacity_adjustment.signal_value_changed().connect(sigc::mem_fun(*this, &ObjectCompositeSettings::_opacityValueChanged)); + _opacity_label.set_mnemonic_widget(_opacity_hscale); show_all_children(); diff --git a/src/verbs.cpp b/src/verbs.cpp index a218e85db..4cdad7d36 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -2437,7 +2437,7 @@ Verb *Verb::_base_verbs[] = { N_("Raise the current layer"), INKSCAPE_ICON_LAYER_RAISE), new LayerVerb(SP_VERB_LAYER_LOWER, "LayerLower", N_("_Lower Layer"), N_("Lower the current layer"), INKSCAPE_ICON_LAYER_LOWER), - new LayerVerb(SP_VERB_LAYER_DUPLICATE, "LayerDuplicate", N_("Duplicate Current Layer"), + new LayerVerb(SP_VERB_LAYER_DUPLICATE, "LayerDuplicate", N_("D_uplicate Current Layer"), N_("Duplicate an existing layer"), NULL), new LayerVerb(SP_VERB_LAYER_DELETE, "LayerDelete", N_("_Delete Current Layer"), N_("Delete the current layer"), INKSCAPE_ICON_LAYER_DELETE), -- cgit v1.2.3 From 44b3e81057c797849129db959d09e3baa1520bce Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Fri, 17 Dec 2010 20:19:39 -0500 Subject: support for 5 point spline (Bug 685707) Fixed bugs: - https://launchpad.net/bugs/685707 (bzr r9965) --- share/extensions/dxf_input.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/share/extensions/dxf_input.py b/share/extensions/dxf_input.py index b46477de1..ee52b8c30 100644 --- a/share/extensions/dxf_input.py +++ b/share/extensions/dxf_input.py @@ -88,6 +88,10 @@ def export_SPLINE(): path = 'M %f,%f Q %f,%f %f,%f' % (vals[groups['10']][0], vals[groups['20']][0], vals[groups['10']][1], vals[groups['20']][1], vals[groups['10']][2], vals[groups['20']][2]) attribs = {'d': path, 'style': style} inkex.etree.SubElement(layer, 'path', attribs) + if not (vals[groups['70']][0] & 3) and len(vals[groups['10']]) == 5 and len(vals[groups['20']]) == 5: + path = 'M %f,%f Q %f,%f %f,%f Q %f,%f %f,%f' % (vals[groups['10']][0], vals[groups['20']][0], vals[groups['10']][1], vals[groups['20']][1], vals[groups['10']][2], vals[groups['20']][2], vals[groups['10']][3], vals[groups['20']][3], vals[groups['10']][4], vals[groups['20']][4]) + attribs = {'d': path, 'style': style} + inkex.etree.SubElement(layer, 'path', attribs) def export_CIRCLE(): # mandatory group codes : (10, 20, 40) (x, y, radius) @@ -322,7 +326,7 @@ parser.add_option("--font", action="store", type="string", dest="font", default= parser.add_option("--tab", action="store", type="string", dest="tab", default="Options") parser.add_option("--inputhelp", action="store", type="string", dest="inputhelp", default="") (options, args) = parser.parse_args(inkex.sys.argv[1:]) -doc = inkex.etree.parse(StringIO('')) +doc = inkex.etree.parse(StringIO('' % (210*90/25.4, 297*90/25.4))) desc = inkex.etree.SubElement(doc.getroot(), 'desc', {}) defs = inkex.etree.SubElement(doc.getroot(), 'defs', {}) marker = inkex.etree.SubElement(defs, 'marker', {'id': 'DistanceX', 'orient': 'auto', 'refX': '0.0', 'refY': '0.0', 'style': 'overflow:visible'}) -- cgit v1.2.3 From f827bacbbab8d98adb460dc85279d584fee6435c Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Fri, 17 Dec 2010 20:54:08 -0800 Subject: Simple tracking of time to display dialogs and main window. (bzr r9966) --- src/dialogs/text-edit.cpp | 12 +++ src/dialogs/xml-tree.cpp | 13 ++- src/ui/dialog/dialog-manager.cpp | 18 +++- src/util/Makefile_insert | 2 + src/util/ege-appear-time-tracker.cpp | 162 +++++++++++++++++++++++++++++++++++ src/util/ege-appear-time-tracker.h | 89 +++++++++++++++++++ src/widgets/desktop-widget.cpp | 18 ++++ 7 files changed, 311 insertions(+), 3 deletions(-) create mode 100644 src/util/ege-appear-time-tracker.cpp create mode 100644 src/util/ege-appear-time-tracker.h diff --git a/src/dialogs/text-edit.cpp b/src/dialogs/text-edit.cpp index 61f56e3f7..d741e2de0 100644 --- a/src/dialogs/text-edit.cpp +++ b/src/dialogs/text-edit.cpp @@ -49,8 +49,10 @@ extern "C" { #include "svg/css-ostringstream.h" #include "widgets/icon.h" #include +#include "util/ege-appear-time-tracker.h" using Inkscape::DocumentUndo; +using ege::AppearTimeTracker; #define VB_MARGIN 4 #define MIN_ONSCREEN_DISTANCE 50 @@ -139,6 +141,9 @@ text_view_focus_out (GtkWidget */*w*/, GdkEventKey */*event*/, gpointer data) void sp_text_edit_dialog (void) { + bool wantTiming = Inkscape::Preferences::get()->getBool("/dialogs/debug/trackAppear", false); + GTimer *timer = wantTiming ? g_timer_new() : 0; + if (!dlg) { gchar title[500]; @@ -457,6 +462,13 @@ sp_text_edit_dialog (void) sp_text_edit_dialog_read_selection (dlg, TRUE, TRUE); } + if ( wantTiming ) { + // Time tracker takes ownership of the timer. + AppearTimeTracker *tracker = new AppearTimeTracker(timer, GTK_WIDGET(dlg), "DialogText"); + tracker->setAutodelete(true); + timer = 0; + } + gtk_window_present ((GtkWindow *) dlg); } // end of sp_text_edit_dialog() diff --git a/src/dialogs/xml-tree.cpp b/src/dialogs/xml-tree.cpp index c90cde490..d25bdad72 100644 --- a/src/dialogs/xml-tree.cpp +++ b/src/dialogs/xml-tree.cpp @@ -41,8 +41,10 @@ #include "../widgets/sp-xmlview-attr-list.h" #include "../widgets/sp-xmlview-content.h" #include "../widgets/sp-xmlview-tree.h" +#include "util/ege-appear-time-tracker.h" using Inkscape::DocumentUndo; +using ege::AppearTimeTracker; #define MIN_ONSCREEN_DISTANCE 50 @@ -178,11 +180,13 @@ void attr_reset_context(gint attr) void sp_xml_tree_dialog() { SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if (!desktop) { return; } + bool wantTiming = Inkscape::Preferences::get()->getBool("/dialogs/debug/trackAppear", false); + GTimer *timer = wantTiming ? g_timer_new() : 0; + if (dlg == NULL) { // very long block @@ -604,6 +608,13 @@ void sp_xml_tree_dialog() tree_reset_context(); } // end of if (dlg == NULL) + if ( wantTiming ) { + // Time tracker takes ownership of the timer. + AppearTimeTracker *tracker = new AppearTimeTracker(timer, GTK_WIDGET(dlg), "DialogXMLEditor"); + tracker->setAutodelete(true); + timer = 0; + } + gtk_window_present((GtkWindow *) dlg); g_assert(desktop != NULL); diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp index ff31c91c4..0c49690cc 100644 --- a/src/ui/dialog/dialog-manager.cpp +++ b/src/ui/dialog/dialog-manager.cpp @@ -42,6 +42,7 @@ #include "ui/dialog/floating-behavior.h" #include "ui/dialog/dock-behavior.h" //#include "ui/dialog/print-colors-preview-dialog.h" +#include "util/ege-appear-time-tracker.h" #include "preferences.h" #ifdef ENABLE_SVG_FONTS @@ -232,10 +233,23 @@ void DialogManager::showDialog(gchar const *name) { * Shows the named dialog, creating it if necessary. */ void DialogManager::showDialog(GQuark name) { - Dialog *dialog=getDialog(name); - if (dialog) { + bool wantTiming = Inkscape::Preferences::get()->getBool("/dialogs/debug/trackAppear", false); + GTimer *timer = (wantTiming) ? g_timer_new() : 0; // if needed, must be created/started before getDialog() + Dialog *dialog = getDialog(name); + if ( dialog ) { + if ( wantTiming ) { + gchar const * nameStr = g_quark_to_string(name); + ege::AppearTimeTracker *tracker = new ege::AppearTimeTracker(timer, dialog->gobj(), nameStr); + tracker->setAutodelete(true); + timer = 0; + } dialog->present(); } + + if ( timer ) { + g_timer_destroy(timer); + timer = 0; + } } } // namespace Dialog diff --git a/src/util/Makefile_insert b/src/util/Makefile_insert index d2f005531..deff951d4 100644 --- a/src/util/Makefile_insert +++ b/src/util/Makefile_insert @@ -5,6 +5,8 @@ ink_common_sources += \ util/compose.hpp \ util/copy.h \ util/enums.h \ + util/ege-appear-time-tracker.cpp \ + util/ege-appear-time-tracker.h \ util/ege-tags.h \ util/ege-tags.cpp \ util/filter-list.h \ diff --git a/src/util/ege-appear-time-tracker.cpp b/src/util/ege-appear-time-tracker.cpp new file mode 100644 index 000000000..d53e86742 --- /dev/null +++ b/src/util/ege-appear-time-tracker.cpp @@ -0,0 +1,162 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Appear Time Tracker. + * + * The Initial Developer of the Original Code is + * Jon A. Cruz. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#include "ege-appear-time-tracker.h" +#include +#include + + +namespace ege +{ + +namespace { + +void unhookHandler( gulong &id, GtkWidget *obj ) +{ + if ( id ) { + if ( obj ) { + g_signal_handler_disconnect( G_OBJECT(obj), id ); + } + id = 0; + } +} + +} // namespace + + +AppearTimeTracker::AppearTimeTracker(GTimer *timer, GtkWidget *widget, gchar const* name) : + _name(name ? name : ""), + _timer(timer), + _widget(widget), + _topMost(widget), + _autodelete(false), + _mapId(0), + _realizeId(0), + _hierarchyId(0) + +{ + while (_topMost->parent) { + _topMost = _topMost->parent; + } + _mapId = g_signal_connect( G_OBJECT(_topMost), "map-event", G_CALLBACK(mapCB), this ); + _realizeId = g_signal_connect( G_OBJECT(_topMost), "realize", G_CALLBACK(realizeCB), this ); + _hierarchyId = g_signal_connect( G_OBJECT(_widget), "hierarchy-changed", G_CALLBACK(hierarchyCB), this ); +} + +AppearTimeTracker::~AppearTimeTracker() +{ + if ( _timer ) { + g_timer_destroy(_timer); + _timer = 0; + } + + unhookHandler( _mapId, _topMost ); + unhookHandler( _realizeId, _topMost ); + unhookHandler( _hierarchyId, _widget ); +} + +void AppearTimeTracker::stop() { + if (_timer) { + g_timer_stop(_timer); + } +} + +void AppearTimeTracker::setAutodelete(bool autodelete) +{ + if ( autodelete != _autodelete ) { + _autodelete = autodelete; + } +} + +void AppearTimeTracker::report(gchar const* msg) +{ + gulong msCount = 0; + gdouble secs = g_timer_elapsed( _timer, &msCount ); + g_message("Time ended at %2.3f with [%s] on [%s]", secs, msg, _name.c_str()); +} + +void AppearTimeTracker::handleHierarchyChange( GtkWidget * /*prevTop*/ ) +{ + GtkWidget *newTop = _widget; + while (newTop->parent) { + newTop = newTop->parent; + } + + if ( newTop != _topMost ) { + unhookHandler( _mapId, _topMost ); + unhookHandler( _realizeId, _topMost ); + + _topMost = newTop; + _mapId = g_signal_connect( G_OBJECT(_topMost), "map-event", G_CALLBACK(mapCB), this ); + _realizeId = g_signal_connect( G_OBJECT(_topMost), "realize", G_CALLBACK(realizeCB), this ); + } +} + +gboolean AppearTimeTracker::mapCB(GtkWidget * /*widget*/, GdkEvent * /*event*/, gpointer userData) +{ + AppearTimeTracker *tracker = reinterpret_cast(userData); + tracker->report("MAP"); + if ( tracker->_autodelete ) { + delete tracker; + } + return FALSE; +} + +void AppearTimeTracker::realizeCB(GtkWidget * /*widget*/, gpointer userData) +{ + AppearTimeTracker *tracker = reinterpret_cast(userData); + tracker->report("REALIZE"); +} + +void AppearTimeTracker::hierarchyCB(GtkWidget * /*widget*/, GtkWidget *prevTop, gpointer userData) +{ + AppearTimeTracker *tracker = reinterpret_cast(userData); + tracker->handleHierarchyChange( prevTop ); +} + +} // namespace ege + +/* + 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 : diff --git a/src/util/ege-appear-time-tracker.h b/src/util/ege-appear-time-tracker.h new file mode 100644 index 000000000..b5ea8b5d2 --- /dev/null +++ b/src/util/ege-appear-time-tracker.h @@ -0,0 +1,89 @@ +#ifndef SEEN_APPEAR_TIME_TRACKER_H +#define SEEN_APPEAR_TIME_TRACKER_H + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Appear Time Tracker. + * + * The Initial Developer of the Original Code is + * Jon A. Cruz. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include + +typedef union _GdkEvent GdkEvent; +typedef struct _GtkWidget GtkWidget; + +namespace ege +{ + +class AppearTimeTracker { +public: + AppearTimeTracker(GTimer *timer, GtkWidget *widget, gchar const* name); + ~AppearTimeTracker(); + + void stop(); + + bool isAutodelete() const { return _autodelete; } + void setAutodelete(bool autodelete); + +private: + Glib::ustring _name; + GTimer *_timer; + GtkWidget *_widget; + GtkWidget *_topMost; + bool _autodelete; + gulong _mapId; + gulong _realizeId; + gulong _hierarchyId; + + static gboolean mapCB(GtkWidget *widget, GdkEvent *event, gpointer userData); + static void realizeCB(GtkWidget *widget, gpointer userData); + static void hierarchyCB(GtkWidget *widget, GtkWidget *prevTop, gpointer userData); + + void report(gchar const* msg); + void handleHierarchyChange( GtkWidget *prevTop ); +}; + +} // namespace ege + +#endif // SEEN_APPEAR_TIME_TRACKER_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 : diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index 7a3e337de..3509a1040 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -56,6 +56,7 @@ #include "ui/widget/layer-selector.h" #include "ui/widget/selected-style.h" #include "ui/uxmanager.h" +#include "util/ege-appear-time-tracker.h" // We're in the "widgets" directory, so no need to explicitly prefix these: #include "button.h" @@ -73,6 +74,7 @@ using Inkscape::round; using Inkscape::UnitTracker; using Inkscape::UI::UXManager; using Inkscape::UI::ToolboxFactory; +using ege::AppearTimeTracker; #ifdef WITH_INKBOARD #endif @@ -243,6 +245,8 @@ SPDesktopWidget::window_get_pointer() return Geom::Point(x,y); } +static GTimer *overallTimer = 0; + /** * Registers SPDesktopWidget class and returns its type number. */ @@ -263,6 +267,8 @@ GType SPDesktopWidget::getType(void) 0 // value_table }; type = g_type_register_static(SP_TYPE_VIEW_WIDGET, "SPDesktopWidget", &info, static_cast(0)); + // Begin a timer to watch for the first desktop to appear on-screen + overallTimer = g_timer_new(); } return type; } @@ -564,6 +570,18 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) gtk_widget_show_all (dtw->vbox); gtk_widget_grab_focus (GTK_WIDGET(dtw->canvas)); + + // If this is the first desktop created, report the time it takes to show up + if ( overallTimer ) { + if ( prefs->getBool("/dialogs/debug/trackAppear", false) ) { + // Time tracker takes ownership of the timer. + AppearTimeTracker *tracker = new AppearTimeTracker(overallTimer, GTK_WIDGET(dtw), "first SPDesktopWidget"); + tracker->setAutodelete(true); + } else { + g_timer_destroy(overallTimer); + } + overallTimer = 0; + } } /** -- cgit v1.2.3