Numerical input of node coordinates
Hello Inkscape developers.
I recently started looking at how to add support for numerical input of node coordinates when editing a path, and it seems it will be a bit trickier than I initially though.
My first question is how would you want this feature to work? There are two approaches that I can see:
* Inputs in node editing tool bar - Values are updated while dragging a node? - Values are updated when a node is released after dragging? * Inputs in a dialog - Dialog is shown when double clicking a node? - Dialog is shown by pressing a button in the tool bar?
After mentioning this on IRC, it seems the first approach is the favored one. So a couple of questions regarding this approach:
1) What's the best way to make the node editing tool bar aware of what goes on in nodepath.cpp (node selected, moved, N of selected nodes et.c.). Can I fire off signals and the tool bar will see them? The approach that the select tool bar uses to get notified of object modifications does not really seem to work for this (though I'm not sure).
2) Is it really important that the input values are updated _while_ dragging a node (like with object dragging), and not when dragging stops? (Latter seems easier to implement).
Any advice and pointers from people more familiar with this part of the Inkscape code is appreciated, since this is my first stab at hacking Inkscape and I might be poking at the wrong places.
Best regards, Aron Stansvik
PS. ACSpike on IRC suggested that bbyak is probably the man I'm after. You there bbyak? :) DS.
On 1/24/07, Aron Stansvik <elvstone@...400...> wrote:
My first question is how would you want this feature to work? There are two approaches that I can see:
- Inputs in node editing tool bar
- Values are updated while dragging a node?
- Values are updated when a node is released after dragging?
- Inputs in a dialog
- Dialog is shown when double clicking a node?
- Dialog is shown by pressing a button in the tool bar?
After mentioning this on IRC, it seems the first approach is the favored one. So a couple of questions regarding this approach:
Certainly the controls bar (= toolbar) is the way to go. We try to avoid adding new dialogs if possible.
Here's the corresponding RFE:
https://sourceforge.net/tracker/?func=detail&atid=604309&aid=865050&...
where you can find some discussion on what to display when more than one node is selected.
- What's the best way to make the node editing tool bar aware of what
goes on in nodepath.cpp (node selected, moved, N of selected nodes et.c.). Can I fire off signals and the tool bar will see them? The approach that the select tool bar uses to get notified of object modifications does not really seem to work for this (though I'm not sure).
The selector just listens to the object selection's changed and modified signals. This indeed won't work with node tool, because node selection is completely independent of object selection. Object selection is global and is always there, regardless of which tool you are in; node selection is only active in node tool and shuts down when you switch to another tool. If you listen to object selection changes, you will get notified when a node is moved (because that changes the path object, which is selected, and therefore fires the selection-changed signal) but you won't get any notification when a node is selected or deselected.
Sure, you will need to create new signals fired by the nodepath and listened to by the node toolbar. However, it's made more difficult by the fact that the toolbar stays always on (it's just hidden and shown when you switch tools) but nodepath is launched and shut down every time you switch to Node tool and back. So you'll need to emit the signal from something that's always on, most appropriately the SPDesktop, not from nodepath (i.e. nodepath would just call a SPDesktop method for emitting the signal). But even then, you can't send all the information that the toolbar needs with a signal. You will still need to create query methods on nodepath that the toolbar would use to get the actual coordinates etc. That is probably the most correct way to implement this.
A simpler approach would be to do away with any signals and just access the toolbar directly from nodepath or node-context. It's been done for example in Calligraphic tool: when you press left/right arrow keys, the calligraphic context processes the keystrokes, digs out the corresponding spinbutton on the toolbar (by its associated data string), and updates it directly. But this might get a little too messy for a more complex case such as the coordinate controls.
- Is it really important that the input values are updated _while_
dragging a node (like with object dragging), and not when dragging stops? (Latter seems easier to implement).
It is much better to see the spinbutton updated while you drag, because it allows you to drag a node to a precise position in one go, without several drag-and-drop attempts. It will also be more consistent with the Selector toolbar.
2007/1/24, bulia byak <buliabyak@...400...>:
On 1/24/07, Aron Stansvik <elvstone@...400...> wrote:
My first question is how would you want this feature to work? There are two approaches that I can see:
- Inputs in node editing tool bar
- Values are updated while dragging a node?
- Values are updated when a node is released after dragging?
- Inputs in a dialog
- Dialog is shown when double clicking a node?
- Dialog is shown by pressing a button in the tool bar?
After mentioning this on IRC, it seems the first approach is the favored one. So a couple of questions regarding this approach:
Certainly the controls bar (= toolbar) is the way to go. We try to avoid adding new dialogs if possible.
Here's the corresponding RFE:
https://sourceforge.net/tracker/?func=detail&atid=604309&aid=865050&...
where you can find some discussion on what to display when more than one node is selected.
- What's the best way to make the node editing tool bar aware of what
goes on in nodepath.cpp (node selected, moved, N of selected nodes et.c.). Can I fire off signals and the tool bar will see them? The approach that the select tool bar uses to get notified of object modifications does not really seem to work for this (though I'm not sure).
The selector just listens to the object selection's changed and modified signals. This indeed won't work with node tool, because node selection is completely independent of object selection. Object selection is global and is always there, regardless of which tool you are in; node selection is only active in node tool and shuts down when you switch to another tool. If you listen to object selection changes, you will get notified when a node is moved (because that changes the path object, which is selected, and therefore fires the selection-changed signal) but you won't get any notification when a node is selected or deselected.
Right.
Sure, you will need to create new signals fired by the nodepath and listened to by the node toolbar. However, it's made more difficult by the fact that the toolbar stays always on (it's just hidden and shown when you switch tools) but nodepath is launched and shut down every time you switch to Node tool and back. So you'll need to emit the signal from something that's always on, most appropriately the SPDesktop, not from nodepath (i.e. nodepath would just call a SPDesktop method for emitting the signal). But even then, you can't send all the information that the toolbar needs with a signal. You will still need to create query methods on nodepath that the toolbar would use to get the actual coordinates etc. That is probably the most correct way to implement this.
Okay. Correct is what I'm after. Thanks for clearing some things up.
A simpler approach would be to do away with any signals and just access the toolbar directly from nodepath or node-context. It's been done for example in Calligraphic tool: when you press left/right arrow keys, the calligraphic context processes the keystrokes, digs out the corresponding spinbutton on the toolbar (by its associated data string), and updates it directly. But this might get a little too messy for a more complex case such as the coordinate controls.
Yea, sounds like a backwards way of going about it.
- Is it really important that the input values are updated _while_
dragging a node (like with object dragging), and not when dragging stops? (Latter seems easier to implement).
It is much better to see the spinbutton updated while you drag, because it allows you to drag a node to a precise position in one go, without several drag-and-drop attempts. It will also be more consistent with the Selector toolbar.
Ah, very true.
Thanks a lot for the information. It has given me some new angles to work with. I didn't find that RFE when I first searched, probably because I used the keyword "numerical" instead of "coordinate", I'll check it out.
Regards, Aron
On 1/25/07, Aron Stansvik <elvstone@...400...> wrote:
2007/1/24, bulia byak <buliabyak@...400...>:
Sure, you will need to create new signals fired by the nodepath and listened to by the node toolbar. However, it's made more difficult by the fact that the toolbar stays always on (it's just hidden and shown when you switch tools) but nodepath is launched and shut down every time you switch to Node tool and back. So you'll need to emit the signal from something that's always on, most appropriately the SPDesktop, not from nodepath (i.e. nodepath would just call a SPDesktop method for emitting the signal). But even then, you can't send all the information that the toolbar needs with a signal. You will still need to create query methods on nodepath that the toolbar would use to get the actual coordinates etc. That is probably the most correct way to implement this.
Okay. Correct is what I'm after. Thanks for clearing some things up.
One thing I didn't think of yesterday: There's already a similar signal issued by SPDesktop (and retransmitted by the global Inkscape object for dialogs which do not belong to any single desktop): it's called subselection_change. It is intended to reflect a change in some "subselection", i.e. tool-specific secondary selection while the regular object selection remains the same. Currently subselection is used when you change text selection (i.e. shift+arrows or mouse drag over text) in Text tool and when you select one or more gradient handles in Gradient tool. So, in principle, you can reuse this signal for the node selection changes too, at least it would be consistent.
However, so far the primary function of the subselection_change signal has been to track style changes in parts of the selection, i.e. color/opacity of gradient stops and the style of fragments of text in a text object. When a widget (such as selected style indicator at the left side of the statusbar) or dialog (such as Fill&Stroke) gets this signal, it runs a query on the desktop, which causes the desktop to emit a query_style signal. Subselections are supposed to listen to this signal and, when they get it, and when the queried style properties apply to them, return the style of the subselection which would be then displayed by the querying widget/dialog.
However, since a path node cannot conceivably have a style of its own, nodepath need not listen to the query signal at all. If no subselection answered the query, SPDesktop just retuens the style of the selected objects. So, if you reuse the subselection_change signal, each selecting or deselecting of a node in Node tool will cause all style-displaying widgets to requery the style and the SPDesktop to return the style of the selected object to every of them. That's the price to pay for consistency :) Even if useless, I don't think it will be too bad. Just make sure that when you do bulk changes in node selection (such as Ctrl+A to select all nodes), you emit the subselection_change signal only once at the end, and not for every node.
On still another hand, when we have Path Effects implemented, one of the effects would be a variable-width stroke built from a given path as "skeleton" and an array of widths. It is logical to allow the node tool to edit the skeleton path when such a shaped stroke is selected. But then, the notion of a "style of path node" will suddenly make sense for at least one property: stroke width. That is, you will be able to select a node, see its associated stroke width in all style-displaying widgets, and set it back _on that node only_ exactly in the same way as you do now for the entire stroke. That will be the triumph of consistency :)
So, to summarize, I think it makes sense to just fire the existing subselection_change signal for node selection changes and make the node toolbar listen to it. Hope this makes sense, feel free to ask anything that's unclear.
2007/1/25, bulia byak <buliabyak@...400...>:
On 1/25/07, Aron Stansvik <elvstone@...400...> wrote:
2007/1/24, bulia byak <buliabyak@...400...>:
Sure, you will need to create new signals fired by the nodepath and listened to by the node toolbar. However, it's made more difficult by the fact that the toolbar stays always on (it's just hidden and shown when you switch tools) but nodepath is launched and shut down every time you switch to Node tool and back. So you'll need to emit the signal from something that's always on, most appropriately the SPDesktop, not from nodepath (i.e. nodepath would just call a SPDesktop method for emitting the signal). But even then, you can't send all the information that the toolbar needs with a signal. You will still need to create query methods on nodepath that the toolbar would use to get the actual coordinates etc. That is probably the most correct way to implement this.
Okay. Correct is what I'm after. Thanks for clearing some things up.
One thing I didn't think of yesterday: There's already a similar signal issued by SPDesktop (and retransmitted by the global Inkscape object for dialogs which do not belong to any single desktop): it's called subselection_change. It is intended to reflect a change in some "subselection", i.e. tool-specific secondary selection while the regular object selection remains the same. Currently subselection is used when you change text selection (i.e. shift+arrows or mouse drag over text) in Text tool and when you select one or more gradient handles in Gradient tool. So, in principle, you can reuse this signal for the node selection changes too, at least it would be consistent.
I already found this and started writing code that uses it :)
However, so far the primary function of the subselection_change signal has been to track style changes in parts of the selection, i.e. color/opacity of gradient stops and the style of fragments of text in a text object. When a widget (such as selected style indicator at the left side of the statusbar) or dialog (such as Fill&Stroke) gets this signal, it runs a query on the desktop, which causes the desktop to emit a query_style signal. Subselections are supposed to listen to this signal and, when they get it, and when the queried style properties apply to them, return the style of the subselection which would be then displayed by the querying widget/dialog.
Ah, I see. It's exactly these kind of things that a newcomer like me could overlook, thanks for enlightening me.
However, since a path node cannot conceivably have a style of its own, nodepath need not listen to the query signal at all. If no subselection answered the query, SPDesktop just retuens the style of the selected objects. So, if you reuse the subselection_change signal, each selecting or deselecting of a node in Node tool will cause all style-displaying widgets to requery the style and the SPDesktop to return the style of the selected object to every of them. That's the price to pay for consistency :) Even if useless, I don't think it will be too bad. Just make sure that when you do bulk changes in node selection (such as Ctrl+A to select all nodes), you emit the subselection_change signal only once at the end, and not for every node.
Right, makes sense and was what I was aiming for anyway.
On still another hand, when we have Path Effects implemented, one of the effects would be a variable-width stroke built from a given path as "skeleton" and an array of widths. It is logical to allow the node tool to edit the skeleton path when such a shaped stroke is selected. But then, the notion of a "style of path node" will suddenly make sense for at least one property: stroke width. That is, you will be able to select a node, see its associated stroke width in all style-displaying widgets, and set it back _on that node only_ exactly in the same way as you do now for the entire stroke. That will be the triumph of consistency :)
Tadaa!
So, to summarize, I think it makes sense to just fire the existing subselection_change signal for node selection changes and make the node toolbar listen to it. Hope this makes sense, feel free to ask anything that's unclear.
Alright. Question; do you think it would make sense to make a sister signal to subselection_changed called subselection_moved, or should I reuse the subselection_changed signal for this purpose also? Having all style-displaying widgets to requery the style during dragging of nodes sounds not so good.
Also, your idea about what should happen when multiple nodes are selected is really good, and I'll try I implement it.
Regards, Aron
PS. Your mails rock! :) DS.
On 1/25/07, Aron Stansvik <elvstone@...400...> wrote:
Alright. Question; do you think it would make sense to make a sister signal to subselection_changed called subselection_moved, or should I reuse the subselection_changed signal for this purpose also? Having all style-displaying widgets to requery the style during dragging of nodes sounds not so good.
Yes, absolutely. For regular selection, we have two signals: _changed means that the scope of selection has changed; and _modified means that one of the selected objects was modified in some way (the names aren't too obvious, but this is what we inherited from Sodipodi). For subselection, so far there was only one signal because I was only interested in style changes and scope changes and treated them the same. But obviously the right way to do it is to use three signals:
_changed: the scope of selection has changed
_transformed: subselection or part of it was affine-transformed without changing style
_modified: subselection or part of it was modified in some other way (most likely by assigning style)
Then, the style displaying widgets would only listen to _changed and _modified, and the node toolbar would only listen to _changed and _transformed.
There are not too many emitters and listeners to subselection signals so far, so it should be easy to make this change consistently everywhere.
Note that you'll also need to create corresponding retransmission signals in inkscape.cpp. The only technical difficulty is that SPDesktop signals are sigc++ signals while inkscape.cpp uses the old-style GObject signals; hope you can sort them out :)
2007/1/25, bulia byak <buliabyak@...400...>:
On 1/25/07, Aron Stansvik <elvstone@...400...> wrote:
Alright. Question; do you think it would make sense to make a sister signal to subselection_changed called subselection_moved, or should I reuse the subselection_changed signal for this purpose also? Having all style-displaying widgets to requery the style during dragging of nodes sounds not so good.
Yes, absolutely. For regular selection, we have two signals: _changed means that the scope of selection has changed; and _modified means that one of the selected objects was modified in some way (the names aren't too obvious, but this is what we inherited from Sodipodi). For subselection, so far there was only one signal because I was only interested in style changes and scope changes and treated them the same. But obviously the right way to do it is to use three signals:
_changed: the scope of selection has changed
_transformed: subselection or part of it was affine-transformed without changing style
_modified: subselection or part of it was modified in some other way (most likely by assigning style)
Then, the style displaying widgets would only listen to _changed and _modified, and the node toolbar would only listen to _changed and _transformed.
Okay. I'll start out with re-using the existing subselection_changed signal, and add a new subselection_transformed.
There are not too many emitters and listeners to subselection signals so far, so it should be easy to make this change consistently everywhere.
Is it okay if I leave the splitting of subselection_changed into _changed/_modified for later, and focus on getting the _tranformed necessary for toolbar spinboxes up and running first?
Note that you'll also need to create corresponding retransmission signals in inkscape.cpp. The only technical difficulty is that SPDesktop signals are sigc++ signals while inkscape.cpp uses the old-style GObject signals; hope you can sort them out :)
I'm sure I'll figure it out by looking at the existing retransmissions. If not, I'll yell here :)
Regards, Aron
On 1/25/07, Aron Stansvik <elvstone@...400...> wrote:
Is it okay if I leave the splitting of subselection_changed into _changed/_modified for later, and focus on getting the _tranformed necessary for toolbar spinboxes up and running first?
Sure, start with whichever is easier :)
2007/1/25, bulia byak <buliabyak@...400...>:
On 1/25/07, Aron Stansvik <elvstone@...400...> wrote:
Is it okay if I leave the splitting of subselection_changed into _changed/_modified for later, and focus on getting the _tranformed necessary for toolbar spinboxes up and running first?
Sure, start with whichever is easier :)
Right there was one last thing I wanted to ask you. The methods in nodepath that I need to use from the toolbar to get node count, position et.c. are declared static (naturally). Should I just make declarations for them in nodepath.h and remove their static-ness, or should I make new methods that wrap a call to the static ones?
Regards, Aron
On 1/25/07, Aron Stansvik <elvstone@...400...> wrote:
Right there was one last thing I wanted to ask you. The methods in nodepath that I need to use from the toolbar to get node count, position et.c. are declared static (naturally). Should I just make declarations for them in nodepath.h and remove their static-ness, or should I make new methods that wrap a call to the static ones?
Wrappers for wrapping sake are not a good idea. If you see that the function needs exactly what you need, feel free to unstatic it and declare it in .h. Make a wrapper only when you need to add some functionality which is missing in the native function. There may also be cases when a function does _more_ than you need, in which case you'll need to break it into two and export one of them.
A still better approach would be to convert more of the C-style functions of nodepath into methods of the Path class. As you may know, we're in a slow transition from C to C++, and in this case, the struct itself has been made a class long ago, but most of the functions remain separate. If you convert them into class methods, we'll be able to properly sort them into private/public.
participants (2)
-
Aron Stansvik
-
bulia byak