Numerical input boxes
Open, WishlistPublic

Description

"Not all of us are good at maths... Especially not mental arithmetic! The computer can do that for us. So, wherever you can enter a number, you should be able to enter a sum, and get the result!"

Implies:

  • Being able to type 4*5 and the input box interpretting that as 20

Notes:

  • Blender has this
  • So does Gimp, but apparantly here it was hell to debug and make safe.
jospin added a subscriber: jospin.May 12 2016, 1:00 PM

Hello, as said on IRC I'm interested in this task (since I worked on something quite similar for a school project).

I have a draft of a qstring parser that support basic arithmetic (+ - */), powers, trigonometry, exponentials an logarithms.

I think pasting this code within krita one is a good option because:

  • It won't add extra dependencies
  • Since it's not a complete script language it will be safer

Then it's possible to override a few functions in the QDoubleSpinBox and QSpinBox to get some smart spin boxes ables to perform numeric operations on the flight that we can use everywhere within the program just like normal spin boxes.

Do you have any questions and or recommendations ? Are you ok I do that ?

rempt added a subscriber: rempt.May 12 2016, 1:20 PM

Yes, sure!

jospin claimed this task.May 13 2016, 1:04 PM

Ok, I've started working on a small proof of concept written in Qt. I will begin implementation in Krita code in 1 or 2 week I think.

I will first focus on arithmetic, unit conversions may be implemented later.

I did a small proof of concept:

some thoughts:

  • so far trigonometric functions are in radians (the ones implemented in Qt are in Radians). For Krita it would be better to have them in degree (nothing hard to change).
  • integer parser fail if one integer is written as a float. Maybe we should floor it instead ?
  • In case of error the parser become 0. It's also possible to have a special value for error code to display in the spinbox but then how do we manage it ? At least with 0 it's a numerical value...
rempt added a comment.May 25 2016, 9:16 AM

Cool! I've tested it just now :-). Degrees are probably better indeed. I think that flooring is better than a parser fail, and as for the fallback number: I think we should restore the string the user typed and add a warning icon or something like that.

I'll look if it's possible to display and icon in the spinbox. But I know it's possible to make the spinbox appear red, which is visually explicit.

It should also be possible to store the last string to retreive it in case of error. Then, if the last string was wrong, textFromValue will replace 0.0 (the result of an error) by the last string parsed.

I will try this week-end.

jospin added a comment.Jun 7 2016, 2:26 PM

I've done a small git repo for convenience when working with the mockup: https://github.com/french-paragon/numerical-box-krita-research

It's quite good right know, I've solve one bug related to multi-threading and implemented a signal/slot mechanism so that the widget can tell if there's an error or not (in the mockup it tell itself and become red but it's one between many possibilities).

There's still a quite annoying bug I need to solve: basically the program segfault at deletion when the widget is in a external lib (apparently both static or dynamic). When it's solve I think it will be ready for me to bring it to krita (if no other horrible bug appear).

rempt added a comment.Jun 7 2016, 2:30 PM

okay! good work!

Tadaa, today I used a numerical input box to resize my canva in krita today and it worked !

There's still some little problems whit the error management.
Basically when the value is set from outside the error is cleared (which is normal behaviour), but in some cases it's cleared too early and the box is set to 0 (1 for the spin boxes of the resize dialog).

I will try to do some improvements:

  • keep the old value to reset it if needed
  • try to improve the validator to avoid parsing an expression that is in an intermediate state (and thus, sending signals like valueChanged).

I will push my changes later...

rempt added a comment.Jun 13 2016, 8:41 AM

Good news!

Here's the promised diff :

!

For the moment only canvas resize have numerical spinboxes (this is usually where I use them in gimp so I thought it was the best place for a test, especially because more than one spinboxes are synchronized).

The only change to the previous code is that I promoted the widgets to the numeric parser spin boxes classes, all the rest work as is (if we have to go in the c++ code of every widget/docker/windows to make change we will become crazy).

Since the setValue slot is not virtual there is a little problem with polymorphism.

I tried to fix it using a signal/slot based hack, but it won't work if the widget is accessed via a normal spin box pointer and signals are blocked (but I think this case won't happen... or at least doesn't need to).

woltherav added a comment.EditedJun 14 2016, 5:06 PM

Awesome! How about you put it up for review in the differential tab of phabricator? Just set @rempt or Krita:_next as the reviewers :)

Ha, yes... done !

Hello.

For the next merge windows I will try to have the second part of the project ready, meaning unit management. Here are some idea about it:

  • The user can change the active unit by rewriting the suffix ( it will not be Qt suffix system or Qt will alway rewrite the old unit at the end).
  • The spinbox should be aware of which category of unit it belongs to: length, text size or angle (do you have another idea ?)
  • The user can perform conversion using unit functions with the syntax "unit(value)". Alternatively the user can put a new unit at the end of a subexpression within parenthesis: "(value unit)". Or we can enforce unit consistency using the following rules:
      • a block with unit has the shape "number unit" or "(subexpr) unit".
      • blocks with unit can be added, subtracted multiplied by the left or the right by a scalar and divided by a scalar.
    • expressions are scalar as long as they contain no block with unit. If they do they become expression with unit of the given type (defined by the scope)
      • functions subexpressions authorize units only in some cases (trigonometric functions accept expression in angle unit and return scalar, inverse trigonometric functions accept only scalar expression en return in angle unit, exp and log accept scalar expression and return scalar and abs and simple parenthesis accept expression as scalar of with the same unit type as the main expression and return with the same unit as the input).

... Ok, it is complicated, but it would be aesthetic.

  • The unit spinbox can be configured with a reference for relative units (% for length, % and em for text), if no reference in absolute unit is provided relative units are disabled.
  • Absolute direct lenght unit are the ones defined in KoUnit. We can maybe define indirect length units like vw, vh, vmin and vmax.
  • Absolute text units are the same as length unit.
  • Absolute angle units would be °, deg, d, grad, gon, rad and % (can we consider 100% is alway the full circle, or should we say % are relative also for angle length ?)
  • The unit spin box can be connected to a combobox to select the current unit. In this case the unit doesn't appear as the suffix anymore. Writing the suffix can still change the current unit.

What do you think ? Do you think I should write some kind of "KomplexUnitHandler", complementing KoUnit, to manage thoses conversions. Or I embed it in the unit spin box class ?

I can't answer all of these but some thoughts:

  • For animation, it might be worth it to think about time as a unit, with a special mention of frames>seconds and seconds>frames. This might need to be discussed with @jounip
  • 100% == full circle makes sense to me personally. I think the grammar to state "of angle" and "of full" might be too complicated otherwise.

Ok, for time I think we should say frames are the reference (since time is managed in frame in KisImageAnimationInterface). seconds should be a relative unit, configured from the framerate.

The spinbox should be a doublespinbox, since seconds may be floating point numbers. But we need a way to define constrains to ensure some units like frame are integer.

moving this to releases board.

I ran into some nasty problem today. Basically I want to add support for image relative units directly into the KisSpinBoxUnitManager.

The idea is that instead of storing the conversion factor between thoses units (that may change, for example if active document change), the KisSpinBoxUnitManager will get it every time it's needed. It may avoid complex signal/slot tricks to maintain the conversion factors of a lot of KisUnitSpinBoxes.

The problem is that KisPart, KisDocument, and/or KisView are in the UI lib, that can't be accessed from WidgetUtils lib. So one can't access directly those values.

There are a few solution I can think about, which do you think is best ? (or do you see another option ?)

  • Create an abstract interface (KisDocumentSiezReference) in WidgetUtils, find a way to connect the appropriate signals/slots in UI so that this interface can monitor the changes of active document change or resize. The downside are that it will be hard to implement such an interface... without using KisPart.
  • Move the UnitSpinBoxes from Widgets to UI... but it imply moving a few other classes from widgets to UI (KoMarkerItemDelegate, KoMarkerModel, KoMarkerSelector, KoPageLayoutDialog, KoPageLayoutWidgets, KoShadowconfigwidget and KoStrokeconfigWidget if I believe git, maybe there's more now)... and that's precisely why we've put the ParseSpinBoxes in Widgets.
  • Subclass the UnitParseSpinBox and it's unit manager in UI. It just mean all the old widgets won't be able to use document relative units. I would go for this.

We discussed two things with Boud:

First, the "vw" (1 % of image width) and vh (1% of image height) units may be cumbersome for some peoples (even if they are css units). Would we want to change that, and which name would we take instead ?

Second, in the "Scale image to new size" dialog, it would be nice to set the appropriate resolution unit when the paper / image units changes. But some people may not like it (I'm used to compute my resolution in dpi and my paper size in cm for example). What I suppose would be nice is to have an option. What do you think ? Do I add an option in the dialog or somewhere in the config dialog ?

rempt added a comment.Jun 29 2017, 9:31 AM

I don't really know about the first question -- "1 percent of image w/h" sounds more intelligible, but is really long.

As for the second question, the most important thing would be to remember and restore the user's choice for resolution unit.

Maybe, instead of changing the unit name, it would be better to add tooltips. Since the unit lists are implemented using Qt models/views it should be easy.

And we should also pay attention to have % that are synonyms for vh or vw depending on the context, since it will be clearer for the users.