Page MenuHome

Support units in modal numinput
ClosedPublic

Authored by Bastien Montagne (mont29) on Nov 30 2013, 9:23 PM.

Details

Summary

This completly changes the way modal numinput is handled. Now, edited one is basically a simplified (ASCII-only) string, which then gets unit- and py-evaluated to get a float value.

We gain many power and flexibility, but lose a few "shortcuts" like '-' to negate, or '/' to inverse (if they are really needed, we still can add them with modifiers, like e.g. ctrl-/ or so).

Features:

  • units (cm, ", deg, etc.).
  • basic operations from python/BKE_unit (+, *, **, etc.).
  • you can use '$' as placeholder to be replaced by current value (so if you have e.g. '2' as current value, '$*3' will give you 6, '$**-1' will give you 0.5, etc.).
  • you can navigate in edited value (left/right key) and insert/delete chars, e.g. to fix a typo without having to rewrite everything.

Notes:

  • Did not touch to how values are shown in header when modal numinput is not enabled (would do that in another commit), so this is still quite inconsistent.
  • Added back radian support in BKE_unit.
  • Added arcminute/arcsecond to BKE_unit.

Related to T37600.

Diff Detail

Branch
units_in_modal_inputs

Event Timeline

First pass code review.

General Comment:

This seems a lot of effort to add a fairly hidden feature (using $), not sure about using special characters, think its worth trying to check on how this could be done without them.

source/blender/editors/transform/transform.c
3110

Prefer to replace comments like this with t->num.unit_type[0] = B_UNIT_NONE; even if its a little redundant.

3601

*style*, prefer bool expressions use parens a = (b == c);, goes for other instances too.

source/blender/editors/util/CMakeLists.txt
30

should be under if(WITH_PYTHON), same for scons.

source/blender/editors/util/numinput.c
27

just remove them instead of commenting?

43

should be within #ifdef WITH_PYTHON

93

*picky* - would prefer precission be more explicit. const int prec = 4; later on 9 is used - which seems a bit arbitrary.

146–149

(float)(int)val is a bit strange, why not floorf(val) ?

337

there should be a #ifdef WITH_PYTHON check here.

347

prefer not add /* XXX Why? */ type comments - did you do git blame?

After adding this comment git-blame will trace back to this commit rather then the one which added it.

395

*picky*, prefer const int prev = 9; /* explain why this is used */

Bastien Montagne (mont29) updated this revision to Unknown Object (????).Dec 1 2013, 12:22 PM

Various fixes from Campbell's review.

Thanks for that first review, Campbell! Addressed your remarks and suggestions in updated patch.

About the '$' placeholder, I think this is a nice feature to have , and it does not add much complexity to the code, imho… I first thought of supporting a few "heading ops" (e.g. '+0.1' would have added 0.1 to existing value), but this was less powerful and not simpler on code side.
Anyway, not a key feature, easy to remove if you guys really do not like it. ;)

Brecht Van Lommel (brecht) requested changes to this revision.Dec 1 2013, 2:44 PM

I didn't read the code yet, but testing the functionality found that it's not dealing well with shortcut keys like X to constrain along the X axis. If you press that it will do both, record it into the string and constraint, it should only do one.

I'm not quite sure how you want to deal with this conflict. I guess the simple way would be to only recording using such characters once a number, "-" or "+" has been typed. It also means you can't press such shortcuts after you start typing a number, but maybe that's not so common.

Bastien Montagne (mont29) updated this revision to Unknown Object (????).Dec 1 2013, 3:03 PM

Tweak handling of events in transform.c, so that handleNumInput() does not get called when event has already been handled in transformEvent()

Thanks for finding that issue, Brecht!

@Bastien Montagne (mont29) this is such a huge improvement. Really, nice work. From a user perspective, this suddenly makes units truly useful.

My one concern, though, is the loss of "-" during transforms. It becomes quite cumbersome to move something along any negative axis. Basically you have to multiply everything times negative one. Is there anyway we can work around this to allow negative integers?

Bastien Montagne (mont29) updated this revision to Unknown Object (????).Dec 4 2013, 8:12 PM

More tweaks to transform.c's transformEvent().

Thanks for noting this, carter! transformEvent() was actually "eating" far too much events!

From my testing so far this feels very good and is ready from a user perspective. I haven't found any problems yet.

Brecht Van Lommel (brecht) requested changes to this revision.Dec 6 2013, 4:00 PM

Overall this looks quite good to me now, just two comments about the code.

Regarding $, I don't understand how to use it, what is the "current value"? If it's the objects original location when translating, then it doesn't seem to do anything here and just gives 0. If I move an object with the mouse and press $ it doesn't seem to take that value specified with the mouse, and if I'm typing an expressions already then it seems pointless? I guess I'm using it wrong, or it's broken in the latest patch.

source/blender/editors/transform/transform.c
2857–2858

Debug print?

source/blender/editors/util/numinput.c
330

BPY_button_exec => bpy_context_set => BPY_context_update => CTX_data_main seems like it would dereference a NULL pointer.

Bastien Montagne (mont29) updated this revision to Unknown Object (????).Dec 6 2013, 7:14 PM

Use valid context for handleNumInput(), other minor tweaks/fixes.

About contexts for py: indeed, was assuming we would already be in a py context, so py_call_level
would be > 1, so context would not have been used... Completely stupid, especially as it's
easy to get a valid context here!

About '$':

In this patch, as init value of numinput are always 0.0, it is only useful when you come back over a value already edited (with tab, so that you can do: 'rotate Y 127°'; 'tab'; ah, seeing result, want 90° less for Y; 'tab' to Y; '$-90';).

I agree it would be much more useful if we could get 'current' value as init one for numinput, but to avoid having too much in this patch, I created a new one for this (which applies on top of this one): D83.

Thanks for the explanation and fixes. These are fairly big changes for the $ feature, which to me seems a bit of an obscure technical feature. Is this something users have asked for? At the moment I'm not sure if this is important enough to support.

@Brecht Van Lommel (brecht), @Bastien Montagne (mont29) the $ feature is very cool and I can see it being very useful. But there's only no good way that I can think of to make it visible to users, thus it's likely to stay a very obscure feature. I think it might be a better effort to simplify the transform code and remove it, for the sake of simplicity and better support. But that's also me not remotely understanding the code base.

Hmmm… Well the $ code itself is pretty simple and compact. the current issue is the default (start) numinput value, which is always 0.0 instead of the "real" current value. That’s the topic of D83, and indeed that’s quite some big changes.

I did not get any request for $, just thought it would be handy sometimes to be able to edit the value in a diff way, instead of always replacing existing one. But it's not a key feature either, and may be overkill… Would let the decision to keep it or drop it to UI team! ;)

Ok, I would say drop the $ feature then.

But other than that, looks good to me.

Bastien Montagne (mont29) updated this revision to Unknown Object (????).Dec 10 2013, 5:22 PM

Remove '$' feature, tweak event handling for EditMesh ops, add string from numinput to bevel.

@cambellbarton a nice clean patch to review… ;)

It looks good to me, but I'll let Campbell give final approval.

Checked the patch, mostly good, Listing some issues I found and suggestions (it may be impractical to implement all, but think its worth at least seeing if they can be supported.)

Observations

One thing that this patch removes is the ability to press:
G X 10 Y 2

To move x-10, y-2

Since Y now is entered as text rather then switching to the Y axis.
Though CtrlX/Y/Z work... not sure, the replacement functionality is handy but a shame to remove quickly being able to switch different axis.

That aside some other things...

Currently if you enter in an invalid expression there is no feedback, ideally there could be some feedback... (2 ideas, and a 3rd below...

  • report an error that shows in info header
  • have a REDALERT flag for the header so its color changes when input is invalid - would be a flag, similar to what we have for buttons in the UI, but apply to the region).

Issues

  • Pressing Delete key adds odd square character
  • Holding down any key does a strange wrapping of the cursor when it fills in the allotted space - not crashing but looks buggy (if you did by accident it could mess up your expression).

Improvements

Some improvements come to mind.

  • While typing in expressions you dont see the final result- could be good to have, This could double as a way to show an error, eg: [1+some/expression]=123 or [2/0]=Error
  • Use BLI_str_cursor_step_utf8 for Ctrl+Arrow/Backspace/Delete keys (used by number buttons, text editor and console already).
  • Ctrl+C/V for paste (maybe overkill? - but if you have number in clipboard it could be nice to add the ability and not so hard).
source/blender/editors/util/numinput.c
238

unused var, can be removed.

Bastien Montagne (mont29) updated this revision to Unknown Object (????).Dec 17 2013, 9:51 PM

Thanks for those review & suggestions, Campbell!

  • Refactor: use increment and move most flags on a per value basis
  • Switch from simple ascii to full utf8 support. Needed among other thing if we want to support copy/paste.
  • Add 'Invalid' as value when current expression is invalid (suggested by Campbell).
  • Add DELKEY in event handler (same as BACKSPACEKEY), else it generates a char...
  • Add copy/paste from/to current expression, as suggested by Campbell.

Re: Issues:

  • Del is now handled like backspace, so it won't generate a char anymore (not sure why it did?).
  • wrapping when holding down keys seems to be fixed (at least cannot reproduce with current code).

Re: remarks:

  • About XYZ, user can use tab to switch between values, think this is rather efficient as well? 'G tab 10 tab 2'... We could make a special check to not handle those keys as char, but I'd rather avoid such hack, backfires too much easily.
  • Report invalid state: don't think REDALERT is a good option here (would make the header flash, as while typing an expression it becomes invalid often), but priting "Invalid" instead of value is nice imho, implemented this.

Re: suggestions:

  • Report current value/invalid state in header: nice, done.
  • Use utf8: actually, was ascii-only, but made it full-unicode, as we need it for copy/paste anyway.
  • Copy/paste: great idea too, done!

Asside from that, did some more improvements:

  • Now most behavior flags are per-value (so that you can have v1 integer strictly positive, and v2 default float, eg., useful for some EditMesh tools).
  • When you come back to an already edited value (with tab e.g.), edit string is initiated with this value, instead of being void again (that's a bit the after-death vangeance of the '$' feature, as it was its main usecase ;) ).

Note, one of my main concerns was in fact based on misunderstanding,

G x 10, y 2

Is not moving X 10, Y 2 (ugh), its moving Y 102

So Ill do final check over the patch but think functionality wise its probably fine to go into master.

Mostly very good now. some final issues.

  • Delete is currently doing the same thing as backspace (it should be removing text in front of the cursor)
  • Home/End keys would be nice to support (simple one).
  • Ctrl+Left/Right can be easily supported (step over words) with BLI_str_cursor_step_utf8.

Finally the brackets and = characters get a bit cramped, eg: [1|]=1, space around = would be better imho -> [1|] = 1.

source/blender/blenkernel/intern/unit.c
264

Why add these? who uses them and why are they important?

417–418

good to note in comment that the function returns the string length.

437–438

rather just keep this as i, can add comment that its used to track string length if thats unclear.

Bastien Montagne (mont29) updated this revision to Unknown Object (????).Dec 20 2013, 10:58 PM

Thanks for those ideas & remarks, @Campbell Barton (campbellbarton)!

  • DELKEY now deletes char after cursor, as it should!
  • ctrl-(left/right/backspace/del) can be used to navigate or delete blocks instead of single chars.
  • home/end keys can be used to go to start/end of expression.

About arcminute/second units: they are quite common in areas like astronomy or navigation (longitude/latitude coordinates)…
Just added them “on the move” as I was re-enabling radians, will comment (or even remove) them if you think it’s overdoing.

Think this can go into master now.

Why are you using size_t bUnit_AsString instead of void?
I don't see you using the returned value anywhere.

I ran into that because I was updating my smpte patch and I have to decided whether to make bUnit_AsString_smpte a size_t or keep it as a void.

Hmmm… think I used it for something that didn’t make it into trunk (probably the '$' feature). Anyway, returning generated string size is a good practice in general, so I guess you should do it for smpte as well, yes, if it does not complicate the code. Helps making complex string operations, like insertions or so…