diff options
| author | Jon A. Cruz <jon@joncruz.org> | 2010-12-18 06:03:56 +0000 |
|---|---|---|
| committer | Jon A. Cruz <jon@joncruz.org> | 2010-12-18 06:03:56 +0000 |
| commit | 9568768f68b4d97b37fc3da92d5c2f92628e0512 (patch) | |
| tree | 565f7044566ab5cc8466a2302414a65a9ae61ddd /src | |
| parent | Simple first pass for rough timing (diff) | |
| parent | Simple tracking of time to display dialogs and main window. (diff) | |
| download | inkscape-9568768f68b4d97b37fc3da92d5c2f92628e0512.tar.gz inkscape-9568768f68b4d97b37fc3da92d5c2f92628e0512.zip | |
Merge from trunk.
(bzr r9955.1.2)
Diffstat (limited to 'src')
| -rw-r--r-- | src/dialogs/text-edit.cpp | 12 | ||||
| -rw-r--r-- | src/dialogs/xml-tree.cpp | 13 | ||||
| -rw-r--r-- | src/ui/dialog/dialog-manager.cpp | 18 | ||||
| -rw-r--r-- | src/ui/dialog/fill-and-stroke.cpp | 2 | ||||
| -rw-r--r-- | src/ui/tool/control-point-selection.cpp | 2 | ||||
| -rw-r--r-- | src/ui/tool/multi-path-manipulator.cpp | 81 | ||||
| -rw-r--r-- | src/ui/tool/node.cpp | 87 | ||||
| -rw-r--r-- | src/ui/tool/node.h | 1 | ||||
| -rw-r--r-- | src/ui/tool/path-manipulator.cpp | 88 | ||||
| -rw-r--r-- | src/ui/tool/path-manipulator.h | 4 | ||||
| -rw-r--r-- | src/ui/tool/transform-handle-set.cpp | 20 | ||||
| -rw-r--r-- | src/ui/widget/filter-effect-chooser.cpp | 2 | ||||
| -rw-r--r-- | src/ui/widget/object-composite-settings.cpp | 3 | ||||
| -rw-r--r-- | src/util/Makefile_insert | 2 | ||||
| -rw-r--r-- | src/util/ege-appear-time-tracker.cpp | 162 | ||||
| -rw-r--r-- | src/util/ege-appear-time-tracker.h | 89 | ||||
| -rw-r--r-- | src/verbs.cpp | 2 | ||||
| -rw-r--r-- | src/widgets/desktop-widget.cpp | 36 |
18 files changed, 511 insertions, 113 deletions
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 <xml/repr.h> +#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/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/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); diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index ef1c764bb..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() @@ -695,6 +766,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; diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index 12d04dd2b..fea02d399 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) @@ -212,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(); @@ -226,6 +270,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<Inkscape::Snapper::SnapConstraint> ctrl_constraint; // with Alt, preserve length if (held_alt(*event)) { @@ -241,16 +286,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<Inkscape::SnapCandidatePoint> unselected; @@ -264,13 +316,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); } 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/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index 5ae9c4137..ea7f3412d 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<SubpathPtr>::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<bool> 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() { @@ -332,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 + } } } } 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; 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<Inkscape::Snapper::SnapConstraint> 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", "<b>Rotation center</b>: drag to change the origin of transforms"); 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/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 <glib-object.h> +#include <gtk/gtk.h> + + +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<AppearTimeTracker*>(userData); + tracker->report("MAP"); + if ( tracker->_autodelete ) { + delete tracker; + } + return FALSE; +} + +void AppearTimeTracker::realizeCB(GtkWidget * /*widget*/, gpointer userData) +{ + AppearTimeTracker *tracker = reinterpret_cast<AppearTimeTracker*>(userData); + tracker->report("REALIZE"); +} + +void AppearTimeTracker::hierarchyCB(GtkWidget * /*widget*/, GtkWidget *prevTop, gpointer userData) +{ + AppearTimeTracker *tracker = reinterpret_cast<AppearTimeTracker*>(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 <glib/gtimer.h> +#include <glibmm/ustring.h> + +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/verbs.cpp b/src/verbs.cpp index c1726ecd4..00a82624b 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), diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index 57e58cd5e..4620b1532 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 @@ -267,6 +269,8 @@ SPDesktopWidget::window_get_pointer() return Geom::Point(x,y); } +static GTimer *overallTimer = 0; + /** * Registers SPDesktopWidget class and returns its type number. */ @@ -288,6 +292,8 @@ GType SPDesktopWidget::getType(void) 0 // value_table }; type = g_type_register_static(SP_TYPE_VIEW_WIDGET, "SPDesktopWidget", &info, static_cast<GTypeFlags>(0)); + // Begin a timer to watch for the first desktop to appear on-screen + overallTimer = g_timer_new(); } return type; } @@ -592,29 +598,19 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) gtk_widget_grab_focus (GTK_WIDGET(dtw->canvas)); - { - g_message("FIRE UP"); - - gtk_widget_add_events( eventbox, GDK_STRUCTURE_MASK ); - - gboolean fooMap(GtkWidget *widget, GdkEvent *event, gpointer userData); - g_signal_connect( G_OBJECT(eventbox), "map-event", G_CALLBACK(fooMap), dtw ); - - void fooReal(GtkWidget *widget, gpointer userData); - g_signal_connect( G_OBJECT(eventbox), "map-event", G_CALLBACK(fooReal), dtw ); + // 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; } } -gboolean fooMap(GtkWidget *widget, GdkEvent *event, gpointer userData) { - checkTime( "MAP"); - return FALSE; -} - -void fooReal(GtkWidget *widget, gpointer userData) -{ - checkTime("REALIZE"); -} - /** * Called before SPDesktopWidget destruction. */ |
