Per-tool opacity setting
Open, Needs TriagePublic

Description

Related bug: https://bugs.kde.org/show_bug.cgi?id=421752

The Problem

Different tools use opacity settings, and they use it in a bit different ways. E.g. Brush Tool paints with the opacity, stored in the brush preset. But Gradient and FloodFill Tools use opacity just to render the gradient/filling.

But in Krita, we store the opacity in the brush preset all the time. We don't have a separate storage for opacity intended for the tools that don't use brushes. It means that when you use Gradient Tool with 50% opacity, this opacity will be written to the brush preset and the preset will be marked as "dirty".

What is more, right now, we have a temporary workaround for that in Krita, which makes things even worse. Every time a tool is deactivated/activated, it saves/restores the opacity saved specifically for this tool. And during this save-restore operation the paintop preset is modified and marked as dirty.

One can reproduce this bug with the following steps:

  1. Activate Gradient Tool
  2. Set opacity to 50%
  3. Switch back to Brush Tool
  4. Select a clean preset
  5. Switch to Gradient Tool and back to Brush Tool

BUG: the brush preset is marked as dirty

Proposed solution

  1. There should be two kinds of opacities: brush opacity and external opacity
  2. Brush opacity is stored in in the brush preset itself
  3. External opacity is stored in Krita's resource server (in a global or per-tool manner, see "Question 1")
  4. Every tool can declare what opacity it would like to use, external or brush one. It can be done by declaring a special flag, like we do that in KisTool::flags(). E.g. Brush Tool would request brush opacity, Gradient Tool would request external opacity (see "Question 3")
  5. On activation of the tool, the resource server (or tool manager?) would reroute all the requests to opacity to the corresponding storage (preset or something local). It would also handle all the "opacity-changed" signals delivery.
  6. The same strategy would also apply to other resources that are stored in a brush: Blending Mode, Eraser Mode, Flow, Size, Alpha Lock. All of them should have their own flags.

Questions

  1. Should every tool have its own external opacity setting or there should be only two opacities: one in the preset and another one for "all the other tools", like Gradient and Fill? In other words, should Gradient and Fill tools share the opacity setting?
  1. Should the extrenal opacity be saved in Krita config file? In other words, should Gradient Tool restore last-used opacity when restarting Krita or it should always start from 100% opacity?
  1. Should Rectangle and Ellipse tools use opacity from the brush preset or use the external one?
dkazakov created this task.Jun 29 2020, 8:15 AM
dkazakov updated the task description. (Show Details)Jun 29 2020, 8:47 AM
dkazakov updated the task description. (Show Details)Jun 29 2020, 8:50 AM
tymond added a subscriber: tymond.Jun 29 2020, 10:03 AM
  1. No strong feelings, but I think they should share it.
  2. No strong feelings again, but I think it should start always from 100%.
  3. In my opinion they should use brush opacity for the line and external opacity for the fill.

General note plus reasoning about 3.:
There are some brushes that by default have less than 100% opacity (for example Pencil-3 Large 4B). Now if I want to change it from the Freehand Brush Tool to Line Tool, it will use 100% and the resulting line will be different from what I expect because the opacity is changed. I expect the Line Tool to be consistent with the Freehand Brush Tool (with the note that the pressure is a bit hard to control... but in the worst case it should look like using a mouse).

And considering that the rectangle tool and ellipse tool also use brushes to paint the outline, I guess I'd expect them to use the brushes in the same way, without overwriting the opacity.

However the fill inside makes it a bit more difficult, of course, since users cannot really set two opacities, can they... Maybe there could be external opacity slider in the Tool Options for the Rectangle and Ellipse Tool (so the top bar would control brush opacity and the Tool Options slider the external opacity)? That sounds a bit hacky though.

emmetoneill added a subscriber: emmetoneill.EditedJun 29 2020, 8:07 PM

Yeah, this is annoying...

  1. Should every tool have its own external opacity setting or there should be only two opacities: one in the preset and another one for "all the other tools", like Gradient and Fill? In other words, should Gradient and Fill tools share the opacity setting?

In my opinion, having two opacity settings should work like this:

(1) Preset Opacity (Per Preset); used by brush creators to define the base characteristics of a given brush preset, including the base opacity, whether opacity is modulated by pressure or other parameters, etc. (This is part of the resource itself, doesn't store temporary changes, and is meant to be edited via brush editor interface only.)

(2) Global Opacity (One only); used by the artist to make adjustments to the opacity of their current tool (brush, gradient, etc.) while working. Each brush preset could temporarily store information about its last global opacity setting, in order to preserve temporarily changes while switching between brushes, but this value would should never mark a preset as dirty and never be written to a brush resource.

This sounds like what you're describing, but instead of tools deciding which of these two opacity values to use, the final opacity should probably be a function of these two things. For example:

Final Dab Opacity on Canvas = Brush Preset Opacity * Global Opacity.

Final Gradient Opacity on Canvas = Gradient Preset Opacity * Global Opacity.

In other words, the global opacity setting (controlled by the artist) simply modulates the various preset opacity setting (controlled by the preset creator), and if a given tool doesn't use presets with opacity, then the global opacity alone can be used if desired. (If no preset, preset opacity = 1.0)

  1. Should the extrenal opacity be saved in Krita config file? In other words, should Gradient Tool restore last-used opacity when restarting Krita or it should always start from 100% opacity?

Yes, the state of the external/global opacity should be saved between sessions. Just like we store which brush was last used, we should try to remember the global opacity that was last used, so that artists will be able to quickly jump back into whatever they were working on last and continue without resetting things.

As for what global opacity does when switching between presets, this should be configurable much in the same way "Temporarily save tweaks" works now. If users want Krita to remember what each brush's last used global opacity setting was they should have that option, while others might prefer global opacity to return to 100% (effectively the default preset opacity value) each time they change brushes.

  1. Should Rectangle and Ellipse tools use opacity from the brush preset or use the external one.

If the final opacity is a function of preset opacity * global opacity, then it will use both!

The brush creator's preset opacity will determine the base opacity of the outline based on the currently selected brush (and maybe a pattern preset opacity could determine the base opacity of the inner fill). Finally, the artist's global opacity setting would modulate the entire opacity of the rectangle as a whole as it is drawn to the canvas.


As I see it, doing it this way creates two big benefits:

  1. The behavior of all tools is consistent and easy to understand. Final opacity = Preset Opacity (if any, else 1.0) * Global Opacity. Always and forever!
  1. We solve the dirty preset issue and eliminate the need for temporary opacity tweaks entirely. This same concept could be applied to flow, rotation, size or any other highly tweakable parameter that artists want to control while painting, ideally without touching any resources at all.
I expect the Line Tool to be consistent with the Freehand Brush Tool

There is one complication: line tool (and other figure tools) can draw vector shapes. In such a case, they should use "external" opacity.

So, if we declare that figure painting tools should used "brush" opacity, then they should be able to switch their flags depending on the currently selected layer.

New Requirement

  • The tool flags should be switchable at the runtime. That is, there should be a signal that will be handled by KisPaintOpBox on such change.

Hi, @emmetoneill!

Each brush preset could temporarily store information about its last global opacity setting, in order to preserve temporarily changes while switching between brushes, but this value would should never mark a preset as dirty and never be written to a brush resource.

And what about blending mode? Should it also override the brush settings only without marking it as dirty?

(2) Global Opacity (One only); used by the artist to make adjustments to the opacity of their current tool (brush, gradient, etc.) while working

I think it breaks the requirement of having different opacity for the brush and gradient tool. Or you think that separation of the brush opacity from the global one would be enough?

Related bug/wish reports: