This is an idea that I think would be very nice to have in GIMP.  It
would probably take a bit of programming, and I can't do that unfortunately.

I'm not sure of the proper terms, so I will define what I mean:

Controller - A source of data that is used to modify an attribute of the
Attribute - Part of the data for a brush, such as size, color, opacity,
angle, etc, etc.  Can be modified by a controller.

The current control-to-attribute has few features and does not offer a
great deal of control to the user.  It only supports one control and a
few attributes.  Additionally, for the attributes, there is no
specification for how much the attribute is affected.  What I mean is,
in the toolbox you can check to have the pressure affect the opacity,
but not by any given range.

Each attribute connected to a control should have some parameters.
Three important ones are start-adjustment, end-adjustment, and

adjustment-type can be 'absolute', 'relative', or 'percent', and
start-adjustment/end-adjustment would the the absolute, relative, or
percentage of adjustment caused to the selected attribute based on the
value of the controller.

If adjustment-type is 'relative', adjustment-start is '-10',
adjustment-end is '10', the selected attribute is brush-size, and the
brush size is currently 76, then the controller would cause the brush to
go from 66 to 86. if the controller value at the time the data is
sampled is 0, then it would be 66, if the controller value is 1, it
would be 86.

If adjustment-type is 'absolute', adjustment-start is '50',
adjustment-end is '75', the selected attribute is brush-size, and the
brush size is currently 76 (that does not matter since it is absolute),
then the controller would cause the brush to go from 50 to 75. if the
controller value at the time the data is sampled is 0, then it would be
50, if the controller value is 1, it would be 75

If the adjustment-type is 'percent', then it is relative but by
percentage. If adjustment-start is '50% (0.5)', adjustment-end is '150%
(1.5)', the selected attribute is brush-size, and the brush size is
currently 76, then the controller would cause the brush to go from 38 to
114. if the controller value at the time the data is sampled is 0, then
it would be 38, if the controller value is 1, it would be 114

adjustment-start can also be larger than adjustment-end, to cause the
opposite affect.  For example, to have the opacity be higher with a
'soft' pressure than with a 'hard' pressure

Controller-attribute chain:
The design could be such that for each controller, the user can select
which attribute(s) is modified, and set the parameters, the problem is
that one controller can only be connected the attributes and shares the

    [Checkbox] - Controller1 Enabled
       [Checkbox] - Attribute1 affected
       [Checkbox] - Attribute2 affected
       [Checkbox] -AttributeN affected
       [RadioBox]-Adjustment Type
       [NumberBox]-Adjustment Start
       [NumberBox]-Adjustment End

This would allow the user to enable the controller, tell it that the
controller affects this attribute and that one, and the parameters.  But
the parameters are the same for  Controller1->Attribute2 and
Controller1->Attribute2.  It would be desired to have separate
parameters for different controller->attribute links.  For example,
pressure may vary opacity by a certain amount, but size by an even
greater amount, for this to be, they can't share parameters.

A controller-attribute chain is really just a list of what controller
affects what attribute, and parameters for that specific item:

struct ControllerAttributeSomethingOrAnother
    int controllerSource;
    int targetAttribute;
    AdjustmentType type;
    double start;
    double end;

When a given brush is applied, each item in the chain would be applied
to the 'original' brush attributes, modifying it by some manor:

BrushAttributes b = GetCurrentBrushAttributes();

foreach item in chain
    // interpolate the controller value with the start/end range
    // so that controller value 0 represents the start value and
controller value 1 represents the end value
    double control_value = GetControllerValue(item.controllerSource) *
(item.end - item.start) + item.start;
    double value;

        case 'absolute'
           value = control_value;
       case 'relative'
           value = control_value +
        case 'percent'
            value = control_value *

    b.SetAttributeValue(item.targetAttribute, value);

It would also be possible for the same attribute to be affected by two
different controllers.  Order does matter for such things, such as
Pressure->Opacity percent 0%-100%
Direction->Opacity relative -0.2-0.2
Inital opacity: 75% (0.75)
Pressure controller: 0.75
Direction controller: 0.75

1. opacity becomes 56% (0.5625) from Pressure->Opacity
2. opacity becomes 66% (0.6625) from Direction->Opacity

Results if order is switched:
1. opacity becomes 85% (0.85) from Direction->Opacity
2. opacity becomes 63% (0.6375) from Pressure->Opacity

Additional types of controllers and attributes:
I also think it would be nice if there were some additional controllers
and additional attributes:

    pressure - Same as usual, represents the pressure, only specialized
devices can use it (tablets)
    tilt - Again only special devices can support it
    rotation - Not the same as 'direction' below, but some devices can
detect the rotation of the pen on the tablet, or so I've heard
    direction - Based on sampling the position of two points, determine
the direction of the line from the first point to the second point
    speed - Determine timing between the sampling of two points
    noise - A random source from 0 to 1. This can allow the 'jitter'
option to be applied to other things, such as jitter the color or size
as well.
              Note that a 'noise' controller is different than a
'jitter' attribute  It allows an attribute to be 'randomly' changed.  It
can even be connected to the 'jitter' attribute to allow the jitter
radius to be random.

    gradient - When using a gradient for a stroke, normally it is based
on the movement of distance.  This would allow a controller to select
what part of the gradient to use.  The valid range would be from 0
(start of gradient) to 1 (end of gradient).  The initial value of this
attribute would be computed as normal (distance into the stroke and the
length), and adjustment types would still work, absolute specifying an
exact position, and relative/percent specifying a position offset from
where it is 'supposed' to be in the gradient
    angle - One useful combination would be to connect a 'direction'
controller to the 'angle' attribute, so it seems that the brush is
rotating with the stroke.  This means that 'direction' and 'angle' would
need to be in the same orientation, either both clockwise or both
counter clockwise.
    jitter - The position of the applied stroke.  Default value is 0
(draw where the cursor is), but it can be adjusted by by a controller if
desired.  For example, a light pressure can draw directly at the given
position and a hard pressure can increase the jitter radius.

GUI interface:
A new dialog would exist which would allow the creation of the
controller-attribute chain.  Some features would thus be removed from
the toolbox.  It may still be desired to have a separate 'chain' per
tool, similar to how the settings of one tool can be difference from the
other tool, and when selecting the first tool, it will restore it
settings like blend mode/etc.  It may be desirable to implement separate
chains per tool, so when the user selects one tool, it's chain is used,
and when selecting another tool, it's chain is reloaded and used.

This new dialog would consist of a list-like control that is by default
empty, with a +/- button to add a new item to the chain.  Pressing '+'
would insert a new item with default values, '-' would remove the
selected item, also maybe a '*' to clone the current item.

Attached is a small mock-up of an idea for the interface. It shows 3
items in the list chain.

*Pressure will adjust the opacity by the current value from 0 to 100
percent.  If the brush opacity is 75%, then it will vary from 0 to 75%
based on the pressure.
*Pressure will adjust the size by the current value from -20 to 50.  If
the brush size is currently 45, it will vary from 20 to 95 based on the
*Direction will adjust the angle by an absolute value from 0 to 1.  (0
to 360 degrees of direction will adjust the angle of the brush from 0 to
360 degrees).  Since it is absolute, the current brush angle is
disregarded.  If it was relative, it would be added to the current brush
angle.  More often, relative would probably be the desired setting and
not absolute, as the initial 'angle' for the brush may be properly set.
Also, how this would work for bitmap brushes would be unclear, (the
bitmap would be rotated, and may loose quality), but if it was a vector
brush, it would probably work fine as rotation would not cause bad

Again this is just an idea that I think would be useful and would love
to see in a future version.  The code shown is just the idea for
operation, I don't know much about the actual GIMP code.


Another idea proposed by David Gowers is to use a tree-based approach instead of a list based approach. Each top-level item in the tree would represent the 'target' attribute, and items in the tree represent the 'source' controller and parameters:

   Pressure [absolute: 0 to 100%]
   Direction [relative: -0.2 to 0.2]

Absolute items for any given destination attribute would be moved to the top automatically. During processing of each attribute based on input controllers, encountering an absolute attribute would stop processing, after since it should set the value absolutely instead of relative to the current value.

Brian Vanderburg II

<<inline: gui.png>>

Gimp-developer mailing list

Reply via email to