... on top-level layers.
There was even a comment for this, but I missed this when I moved some
code to the top of the function in commit b9577a783d. Now moving this
call up as well. This appeared to be more of a problem when merging
layers without a GUI (script-fu). I'm guessing the GUI calls this anyway
before.
Replace all g_assert_not_reached() in app/core/ by g_return_if_reached()
or g_return_val_if_reached(). GIMP may handle a lot of creative work,
sometimes unsaved for hours. We should not just crash on purpose.
g_assert*() could theoretically be turned off on a glib build, but this
is nearly never done, and is not a solution either (actually it is
probably even worse because the broken code would just continue on a
forbidden path). It is much better to return with a warning on such
forbidden code paths, allowing someone to report a bug without
experiencing a crash and data loss.
For now, I only took care of g_assert_not_reached() inside app/core.
More g_assert*() code should be replaced.
Note: assert are acceptable in plug-ins though, but not in the main
executable, unless absolutely necessary (something happening so bad that
crash is better than continuing).
Don't use g_assert(). Instead use g_return_val_if_fail().
This commit therefore does not fix the actual bug, but at least it does
not crash. GIMP simply outputs a warning upon trying to merge down a
hidden layer. The actual fix will follow later.
The CPU group monitors GIMP's CPU usage, and can measure the amount
of time the CPU has been active, which can be used to get a rough
estimate of the execution time of certain operations.
Be warned: while the CPU group is available on *nix and Windows, it
has only been tested on Linux.
Allow controlling the gauge/history visibility, and the history
interpolation method, of individual values.
Improve redraw elision when some values are hidden.
...if "Show rulers" is disabled
Add HACK to gimp_display_shell_canvas_realize() that makes sure the
rulers are always mapped once for each new GimpDisplayShell. This
seems to magically fix all the crashes.
Before you get too exceited -- no, this commit doesn't integrate
transform previews into the image graph :) We still use a
separate canvas-item overlay, just like before, but instead of
using an impromptu implementation to render the preview, we use
gegl:transform. We properly adjust the matrix passed to the op
according to the display scale, so that we still render only as
much as needed.
This is both notably faster than the current code, and, for
perspective transforms, more accurate.
Whereas we would only scale *down* big pixel images, we should both
scale up or down vector images since such format is made for display at
any size. This way, a vector splash screen is always displayed at ideal
size, whatever your display size.
Current code was using the dimension of the screen as a max size. That
is really too big. 2/3 of the screen size is an acceptable size being
both well visible and not overwhelming.
Also the current code was cropping, not rescaling, the splash image,
which is obviously not an acceptable solution because on a very small
displays, we would end up with ununderstandable piece of a bigger image.
This new code will allow to ship big size default splash image(s), and
display it in an acceptable size on both low and high density displays.
We indeed got a feedback from someone with a 4K display who was saying
the current dev splash screen was tiny on one's display.
Of course, custom splash can still be at any size; but from now on, we
will need for the *default upstream splash image(s)* to be of huge
dimension in order to show up well everywhere (at least Full HD splash,
which is half of a 4K UHD screen).
Animated splash images are still not resized though and will show up at
their default dimension. This means we cannot ship animated splash
screens as a default for the time being (they can still be installed as
custom splash).
The four remaining "classic" color tools (Brightness-Contrast, Curves,
Levels and Threshold) are in fact just special UIs for otherwise
completely normal filter ops.
Add normal filter actions for them and invoke them like all
other filters, which makes them show up in the filter history
automatically.
The only small hack needed is to special case them in
gimp_gegl_procedure_execute_async() so the right tools are created
instead of the default GimpOperationTool. Also, blacklist the
automatically generated tools actions from action search and the
shortcut editor.
gimp_action_history_init(): when deserializing the action history,
check each action against gimp_action_history_excluded_action() so
when we decide to exclude an action, it doesn't come back as history
zombie from disk.
... be used effectively.
We have had display pixel density detection for quite some time, but I
guess the step I set to switch to the "Huge" icon size (48px for the
toolbox icons) was too high at 300 PPI. Someone with a screen of about
280PPI reported the icons to be far too small on GIMP 2.9.8.
It seems that 240PPI is already even considered as XDPI already. Let's
just set our new "Huge" step at the 250PPI intermediate.
In any case, it seems GIMP 2.10 will have problems with even denser
displays, but the way GTK+2 handles icon sizes with a GTK_ICON_SIZE_*
enum is quite limited. That is quite a problem considering screens
getting denser in pixels nowadays. Hopefully GTK+ 3 will improve the
situation.
...on the list dialogs on the Input text area
gimp_container_editor_constructed(): connect the container
view's "select-item" with G_CONNECT_AFTER because the signal
is G_SIGNAL_RUN_LAST. Some quick greps didn't find anything that
would be affected, except fixing this bug. Found by Massimo.
...instead of center
The scale tool implicitly uses GimpToolTransformGrid's "pivot-x" and
"pivot-y" properties, so they need to be properly initialized and
updated to be at the grid's center.
Also add a tool options toggle "Around center".
The attached patch avoids CRITICALs when executing Debug actions
with no images open.
1) do not run projection benchmark unless there is an image
2) memsize of pluginmanager member was incorrectly computed using
gimp_object functions for 2 GObjects
This reverts commit 36258a671a.
This commit was making the rotated canvas rendering quite horrible to
the point that I think it would make the canvas rotation feature barely
usable. See bug 759287, comments 13 to 18.
I think we will need to find other ways to accelerate rendering.
Compromise on quality is possible, but I think that in this case, this
was more than just a compromise. It was more like completely abandonning
quality. We could even see the lines "spiking" while you were rotating!
Like your drawing was alive!
When the active modifier mode is GIMP_TOOL_ACTIVE_MODIFIERS_SAME (the
tool does not want to distinguish between modifier states depending
on whether or not the first mouse button down), we need to make sure
these states are in sync in GimpTool's bookkeeping, and we must not
generate synthetic modifier releases when the mouse button is
released.
Looks like we should use L*, C*, and h° to stay consistent (in
particular Lab L* and LCH L* are the same value), and also to allow for
future implementation of variants of LCH.
Value "h°" was the hardest to choose since we sometimes see just "h",
sometimes with a star, and other times with a degree. Even reference
documents display the 3 versions in the same documents! I just went with
a 2-letter version with degree, as seen on Wikipedia, and to align
better with other 2-letter LCh values. That's pretty arbitrary and can
be changed if another shortened name is considered better.
Elle Stone says (cf. bug 791484, comment 9):
> there are several variants of "Lab" out there, with the most commonly
> used (and the version GIMP currently uses) being the 1976 version,
> which uses asterisks to differentiate it from the earlier "Hunter"
> version. So yes, asterisks are technically correct.
Better use the most conventional naming. And as a side effect, it makes
differentiating Lab a* and Alpha shortened names more obvious, while not
making them that much bigger (2 characters instead of one for "a*").
To mark them as different strings with a context, otherwise "B" for Blue
and "B" for Lab b* cannot be translated separately (for instance).
See commit 7ac7b9519f and previous commit.
These labels were shortened but it's difficult for translators to know
what they are, especially when same shortened labels are common to
different concepts.
See commit 7ac7b9519f.
... removed by commit 0f9da165e0, and
improved by this commit.
Our foo-light modes aren't really prepared to handle out-of-range
input. Make sure that in-range input doesn't result in out-of-
range output.
Add a safe_div() function to gimpoperationlayermode-blend.c, and
use it in the relevant blend funcs, instead of plain division.
This function clamps the quotient to some reasonable range, to
avoid infinities, and maps epsilon/... to 0, to avoid NaN. The
latter part results in similar qualitative results to the
corresponding legacy modes, when calculating 0/0.
Oh blasphemy! The Wilber logo in the toolbox can now be disabled
directly via the Preferences dialog (on the Toolbox page).
The logo is staying enabled by default though. Long live Wilber!
...and present linear RGB Histograms
This is step one: implement the feature at all (without new defaults
or proper GUI, cough).
Add boolean "linear" properties to GimpOperationPointFilter,
GimpCurvesConfig and GimpLevelsConfig.
In the filter, simply set the input/output formats to linear in
prepare().
In the curves and levels tools, add "Linear" toggles from hell,
like in the histogram dockable, and make sure things work right
wrt changing and resetting the property, switching from levels
to curves, and picking colors.
The result currently changes when switching a non-nop curves/levels
between perceptual and linear, because adjusting the parameters
between the spaces is not implemented yet.
It appears that GTK+/GNOME don't have an icon with
"help-browser" ID anymore, but we have exactly the icon
that is needed for two menu entries.
Also, the menu entry for "Search and Run..." was using
a system icon for finding stuff, which looked wrong when
used with a symbolic theme.
We could come up with something overly clever like
a dedicated CLI/terminal icon, but people would expect
a magnifier instead (judging by what Blender does)
and that's what we already use for the Zoom tool.
Hence the lazy fix.
In legacy layer modes that may produce out-of-range output given
in-range input, clamp the result after blending and before
compositing, instead of after compositing, to avoid producing
different results than 2.8 in certain cases.
Improve the disabling/enabling of extended input events for the
canvas during enter/leave-notify events, in particular, so that
enter-notify events that are a result of pointer ungrabbing don't
erroneously reeanble extended input events.
Something about the unqueueing and requeueing of the entire event
queue during motion compression fries GTK's brain w.r.t. extended
input events. Instead, have gimp_display_shell_compress_motion()
return the first non-compressed event to the caller, making it
responsible for dispatching it after handling the motion event.
Add "color-profile-path" to GimpDialogConfig to remember the last-used
path in any profile chooser dialog.
Whenever a GimpColorProfileChooserDialog is created, call a new
gimpwidgets-utils helper function that connects to the dialog's "show"
and "response" signals and makes sure "color-profile-path" is set on
the dialog if it doesn't have a current folder already, and sets the
property back to the config object when a profile was actually chosen
from disk.
Fix the crashes from the third zip:
- forgot to guard the other writing place in the RLE decoder
- one byte after the buffer is still one byte too much
- protect against seeking to bogus offsets
Add "clamp-input" (which clamps the input values to [0..1])
and "clamp-output" (which clips the final result to [0..1]),
properties, parameters and GUI to:
- GimpLevelsConfig
- GimpOperationLevels
- The levels tool dialog
- The gimp_drawable_levels() PDB API
The old deprecated gimp_levels() PDB API now sets both clamping
options to TRUE which restores the 2.8 behavior.
Also reorder some stuff in GimpLevelsConfig and elsewhere so the
levels parameters are always in the same order.
Add brush dimension/depth/compression sanity checks for v6 brushes,
and make sure we don't overrun the RLE decoder's destination buffer.
This properly rejects all brushes from the second zip in the bug.
...outside area of Crop Tool -> Highlight option
Add "highlight-opacity" property and turn the controlling GUI into an
expanding toggle that reveals an opacity slider.
...to allow more space for the channel values
to allow the Pointer, Sample Points, and Color Picker Information
dialogs to be narrower and still show the channel value, without the
channel value running over the top of the channel identifier.
Mitch: did even more and also split the coordinates display to two
lines, because on large images the widget's width was flickering
or the labels were overwriting each other.
...in brushes user directory
Consider 8bim section size unsigned, to avoid seeking backward when a
malicious brush includes an 8bim section unknown to GIMP.
This avoids the possibility to start an infinite loop on GIMP start.
Found just a water drop in the ocean, GIMP is still not secure.
Mitch: Added more sanity checks on the Abr's width/height/bytes so now
all brushes in the zip attached to the bug are properly rejected
instead of crashing GIMP.
This ensures that MyPaint default brushes are installed, otherwise this
makes the MyPaint brush tool quite useless and confusing unless MyPaint
is installed (which was making MyPaint a de-facto dependency of GIMP
until this commit!). Also we won't have to guess anymore the right path
for these brushs. The path will be known at compile time.
If the user enters a value in the shear tool dialog, that value must
be honored. Always set the shear direction to the edited axis and
reset the other axis to 0.
Use a GimpSpinScale widget instead of scale entry cruft, it handles
the model vs. view factor of 100.0 correctly. Also modernize the GUI
without using a table.
The C language only promotes data values up to (un)signed int,
which is 32 bit, if no larger data type is used within the
calculation. Having a multiplication of two gint variables,
even if the expected target variable is of type gsize (64 bit),
leads to a possible integer overflow.
This bug can be triggered in gimp_temp_buf_new, which is used
to allocate memory for given supplied dimensions and bytes per
pixel. If triggered, less memory than needed is allocated and
therefore allows out of boundary accesses, either resulting in
possible code execution or information leakage.
While at it, make sure that the supplied format can actually be
resolved to a bytes per pixel value. If not, return NULL.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Replace gimp_parameter_*() utility functions with equivalent
gimp_properties_*() functions which deal with separate arrays of names
and values, and use g_object_new_with_properties() instead of
g_object_newv().
After commit 8029508fbe, we always
render the image in chunks that are at most
GIMP_DISPLAY_RENDER_BUF_WIDTH x GIMP_DISPLAY_RENDER_BUF_HEIGHT,
even when the window's scale factor is > 1.
This reverts commit 40bc5307dc.
It's not *exactly* the same. The floating selection can belong to a
channel or layer mask. Also, this belongs into the GUI layer, not the
core.
Anchoring a floating layer is basically equivalent to merge down. This
is already what we do in other merging actions (flatten image and merge
visible layers).
Refactor GimpDashboard to autogenerate the UI based on a
description of the different variables, fields, and groups.
Allow individual groups to be expanded/collapsed, and individual
fields to be enabled/disabled. Save the relevant state in the
dashboard's aux-info.
Add fields for the new GeglStats properties, as per GEGL commit
25c39ce6c9bb618f06ac96d118e624be66464d74. The new fields are not
enabled by default.
Add "reset" action, to clear the history, and reset cumulative
data.
Current migration code would still return TRUE for success if the copy
of a regular file failed for any reason.
Also getting rid of some weird block and making sure we free dirname
only when it has been assigned a value.
When recursively browsing folders, there is always the risk of infinite
recursivity, in particular with symbolic links which can create loops.
Let's just assume that we don't have any data over 5 levels of
directories to avoid a security risk.
paintbrush.pgm and paintbrush01.pgm are binary identical. If they were
brushes we ship as data, that would be more annoying because they could
be used in scripts or in various other places. But here it looks they
are used for gimpressionist plug-in only, which means they are probably
not used in some random script. All it takes is probably only to
properly migrate gimpressionist presets.
Presets using "paintbrush.pgm" will be migrated to use
"paintbrush01.pgm" instead.
In particular, I noticed that some data can be on 2 levels (or more?).
For instance gimpressionist presets were not migrated from 2.8 to 2.9
because of this.
Override get_invalidated_by_change() with the same logic as
get_required_for_output(), to avoid unnecessary invalidation.
Avoid format conversion when input and aux have the same format.
Add pass-through fast path when the ROI is completely inside/
outside the cropped rectangle.
Use bulk memcpy(), instead of per-pixel test-and-copy, in
process().
This avoids unnecessarily processing regions of the input and/or
aux nodes that will get cropped out. In particular, this avoids
processing cropped-out regions when using the filter tool in split-
view mode.
Since commit a427213fb8, the special glib value "help" does not work
anymore as a helper (listing the list of available flags).
This means that to use GIMP_DEBUG environment variable, one has to
either know them all by heart or check the app/gimp-log.c file.
This commit still leaves "help" as a normal flag for GIMP_LOG_HELP
domain in GIMP, but creates instead "list-all" as the new helper value.
Moreover as a fallback, setting a random value to GIMP_DEBUG with no
valid flags in it will also output the list of available flags. This
way, one doesn't even have to remember a specific string to obtain the
list.
Replace the "lock brush size to zoom" paint option with a "lock
brush to view" option, which links the entire brush transform to
the view transform, so that the brush remains invariant in display
space under scaling, rotation, and reflection.
Add support for reflecting brushes as part of their transformation.
The reflection is performed as the last step of the transformation,
across the vertical axis.
The option to reflect the brush is not exposed in the UI, or
through the PDB, but is intended to be used for linking the brush
transformation to the view transformation, in the next commit.
When you move an endpoint in the Blend Tool, angle and distance
information are especially important, in case you want to draw a
gradient with specific values.
Currently Blend tool only shows the vector coordinates whose usefulness
is a bit of a question. Now it will also show distance (in current shell
unit) and angle!
Add an offset_angle parameter to gimp_constrain_line(), which
offsets the radial lines by a given angle.
Add gimpdisplayshell-utils.[ch], with two new functions:
- gimp_display_shell_get_constrained_line_offset_angle():
Returns the offset angle to be passed to
gimp_constrain_line(), in order to constrain line angles in
display space, according to the shell's rotation angle and
flip mode.
- gimp_display_shell_constrain_line(): A convenience function
which calls gimp_constrain_line() with the said offset angle.
Use the new functions in all instances where we constrain line
angles, so that angles are constrained in display space, rather
than image space.
The only exception is GimpEditSelectionTool, which keeps
constraining angles in image space, since it's not entirely obvious
that we want to constrain angles of dragged layers/selections in
display space.
The file formats GBR and PAT contain names which are supposed to be
NUL-terminated within the files. If no such terminating NUL byte
exists, the parsers of GBR and PAT trigger an out of boundary read
during utf-8 conversion.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Add gimp_display_shell_[un]transform_with_scale(), which are
similar to gimp_display_shell_[un]transform(), however, they
transform the bounding box to/from uniformly-scaled image space,
given the scale factor as a parameter. These functions are more
accurate than using gimp_display_shell_[un]transform() and applying
the scaling separately, in particular, when the scale matches the
(horizontal or vertical) display scale.
Use these functions in gimp_display_shell_draw_image(), to avoid an
off-by-one error when transforming screen-space chunks to image-
space chunks, which leads to the symptoms described in the bug.
Fix another potential off-by-one error affecting non-uniformly
scaled images, and window scale factors other than 1.
The dashboard dockable shows the current GEGL cache and swap sizes,
and their recent history. It has options to control the update
rate and history duration of the data, and an option to warn (by
raising/blinking the dialog) when the swap size approaches its
limit.
GimpMeter visualizes a set of values that change over time. It
consists of a gauge, showing the most-recent sampled values, a
history graph, showing a plot of the values over time, and an LED,
which can be used as a boolean indicator for some condition.
GimpMeter is used in the dashboard dockable, added in the next
commit.
Replace the GIMP_BOUNDARY_HALF_WAY macro by two others : one for perceptual and
one for linear gamma.
Use the GIMP_BOUNDARY_HALF_WAY_LINEAR to compute channels and floating selection
boundaries.
It never belonged inside "tools". Also rename its "pdb" subdirectory
to "groups". This had to happen before 2.10 so cherry-picking between
branches doesn't become a nightmare in the future.
It turns out we already have the support since it uses the same axis as
the "wheel", used by other devices (for instance the Airbrush pen of
Wacom has a wheel reporting on this same axis).
We can't do any fancy support for this right now, but at least we can
clarify a bit the dynamics naming so that people understands it can be
used for both wheel and rotation input.
Fix the various "Wheel" dynamics strings into "Wheel/Rotation".
Use CAIRO_FILTER_FAST when painting the xfer surface to the
screen. This notably improves performance when the canvas is
rotated, at the cost of lower filtering quality.
Based on a patch by Massimo.
Move the entire image-space/screen-space transformation logic from
gimp_display_shell_render() to gimp_display_shell_draw_image(), so
that the former works entirely in image space, and do the chunking
and clipping in screen-space, making sure that image-space chunks
are never larger than
GIMP_DISPLAY_RENDER_BUF_WIDTH x GIMP_DISPLAY_RENDER_BUF_HEIGHT,
even when the window's scale factor is greater than 1.
Add a GIMP_BRICK_WALL environment variable, which, when set, shows
the screen-space chunk bounds.
In gimp_layer_new(), set opacity and mode using the setter
functions, instead of modifying the members directly, so that all
the necessary side effects take place.
Add gimp_item_get_merged_color_tag(), which returns the color tag
of the nearest ancestor (including the current item) that has a
color tag other than NONE. Use this function in GimpItemTreeView,
instead of gimp_item_get_color_tag(), to set the cell color of
items, so that item's with a NONE color tag inherit the color of
their parent. Add a boolean "inherited" parameter to
gimp_get_color_tag_color(), which indicates if the color tag is the
item's actual color tag, or an inherited color tag, and modify the
returned color accordingly, so that inherited colors are less
saturated/lighter than non-inherited ones.
The free select tool now commits on double click inside a closed
polygon, which caused the foreground select tool to switch modes in
the middle of a click, breaking both its own and its parent class'
state.
Fixed by detecting whether the commit was done by double click and
delaying the mode switch until after the parent class button release
code is done.
Unrelated: Don't call both COMMIT and HALT, the generic tool mechanism
does that automatically now, forgot to port this file.
Keep multi-threading disable on the cage transform operation. It is now
fixed but is a lot much slower than when single-threaded, making it
painful to use on bigger images.
So let's reenable later if we can improve this. See bug 787663.
Override GimpLayer::get_effective_mode() in GimpGroupLayer, to
perform strength-reduction of pass-through groups to normal groups
under certain conditions (see gimp_group_layer_get_effective_mode()
for the logic.)
The main motivation for this is the fact that Photoshop uses pass-
through mode as the default mode for groups, resulting in many PSDs
using pass-through groups generously and unnecessarily. Since
pass-through groups are more expensive that normal groups, reducing
them to normal groups when possible can make a big difference.
Note that, while the results of the strength-reduced composition
are theoretically equivalent, there may be small differences in
practice due to numerical errors, especially when using low
precision. This is unlikely to be an issue, but, just in case,
allow disabling this optimization using the
GIMP_NO_PASS_THROUGH_STRENGTH_REDUCTION environment variable.
gimp_layer_get_effective_mode() returns the actual layer mode,
blend space, comosite space, and composite mode used for the
layer's mode node, allowing them to be different from the values of
the corresponding layer properties. The aim is to allow us to
replace expensive layer configurations with cheaper but equivalent
ones transparently. This is used in the next commit to replace
pass-through groups with normal groups under certain conditions.
The effective values are computed by the new
GimpLayer::get_effective_mode() virtual function. The default
implementation provided by GimpLayer returns the corresponding
layer properties as-is (replaceing AUTO with concrete values).
Subclasses can override this function, providing more
sophisticated logic.
When attaching a layer as a floating selection to a drawable,
unbind its visiblility from its activeness, as per the previous
commit, and use its visibility to control the activeness of the
drawable's floating selection filter.
Properly update the drawable when the floating selection's
visibility and excludes-backdrop properties change.
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
Currently, when a GimpFilter's visibility changes, we rely on its
various visibility-changed signal handlers to rewire the filter
node's graph to reflect the change. This has two main
disadvantages:
- There's no easy, generic way to toggle a filter's effect,
especially one that is not subclassed, since GimpFilter only
takes care of the case where visibility becomes FALSE, and does
nothing by itself when it becomes TRUE again.
- While GimpDrawable does handle the visibility => TRUE case, it
doesn't disconnect the filter's input from its mode and
(potentially) source nodes when it becomes invisible. As a
result, while none of the drawable's graph is processed as part
of the composition when not visible, the mode and source nodes
do get invalidated when the filter's input is invalidated, such
as while painting on a layer below the drawable. This is
particularly bad for pass-through groups, since their source
node can be an arbitrarily complex graph, whose invlidation
incurs a nontrivial overhead.
Instead, don't touch the filter's node at all when visibility
changes, and rather have GimpFilterStack remove it from the graph
entirely when the filter becomes invisible, and re-add it once it
becomes visible again. This solves both of the above problems, as
well as simplifies the code.
When merging a drawable filter, we call
gimp_gegl_apply_cached_operation() on a node that's part of the
drawable's filter stack graph. The function rewires the node's
input, and doesn't restore its original input connection before
returning, leaving the graph in an inconsistent state. Currently,
this doesn't matter, since we remove the filter right after that,
but the next commit expects the filter stack graph to remain
consistent.
Remember the original source node of "operation" in
gimp_gegl_apply_cached_operation(), and restore it upon exit, to
fix that.
Since commit ff59aebbe8, blur-gauss plug-in and the associated
"plug-in-gauss" action don't exist anymore. Migrate any custom shortcut
to "filters-gaussian-blur", which is the expected replacement.
See also bug 775931.
Current logics of dealing with duplicate accelerators was just to delete
one randomly. This works ok in most case since we can't be in the head
of people and can't know which one they want to keep (yet we can't keep
both because that makes it very complicated to reset the shortcut
appropriately by hand/GUI, without a tedious work of researching which
other action uses the same shortcut. See commit 2a232398c4).
There is still some cases where we can be a bit more clever than random
deletion: when one of the accelerator is mapped to a non-existing
action. In this case, let's delete this accelerator in priority. Not
only the chances of this being the expected result are higher; but even
worse, there is anyway no GUI way to delete the accelerator for the
non-existing action! Thus you could try and reset your existing action's
shortcut as many times as you want in the GUI, it would always end up
deleted at next startup!
Note that if the non-existing action's shortcut has no duplicate, it
won't be deleted. This ensure that you could uninstall a plugin, then
reinstall it later and still have your custom shortcuts saved in the
meantime. A shortcut of a non-existing action will *only* be cleaned out
if it is redundant with the shortcut of an existing action.
Use gimp:buffer-source-validate, introduced in the previous commit,
for the source node of GimpDrawables. This avoids threading issues
with layer groups, or any other drawables that may use a validating
buffer, by making sure the buffer is validated before any
succeeding operations, and hence the associated graph is processed
on the same thread as the parent composition.
Restore multithreaded processing in GimpOperationLayerMode.
gimp:buffer-source-validate is a drop-in replacement for
gegl:buffer-source, however, if the attached buffer has a
validating tile-handler, it makes sure the required region is
validated during process(). This avoids a situation in which
validation happens in different worker threads at the same time
during the processing of a succeeding operation; since validation
is protected by the buffer's tile-storage mutex, this can result in
either a deadlock (currently), or an effective fallback to single-
threaded processing.
When switching a group layer from pass-through mode to a non-pass-
through mode, flush the projection synchrnously, to make sure that
the projection's buffer gets properly invalidated at that point,
and can be subsequently used as a source for the rest of the
composition.
Add a boolean 'pass_through' member to GimpGroupLayerPrivate, which
indicates if the group is a pass-through group, and use it instead
of checking the group's mode, so that we can detect that the group
used to be a pass-through group when the mode changes, and to
simplify the rest of the code.
Set the priority of group-layer projections according to the group
layer's depth, so that top-level groups have a priority of 1
(compared to a priority of 0 for the image projection), and nested
groups have a priority one greater than their parent (in other
words, shallower groups have higher priority than deeper groups,
all of which have lower priority than the image.)
This makes pass-through groups much faster, in particular.
... which control the priority of the projection's idle source.
The projection's priority is specified relatively to
GIMP_PRIORITY_PROJECTION_IDLE (i.e., a priority of 1 results in an
idle source with priority GIMP_PRIORITY_PROJECTION_IDLE + 1, etc.)
Add GimpViewable::ancestry-changed signal, which is emitted when
the viewable's ancestry changes, i.e., when its parent, or the
parent of one of its ancestors, changes.
Add gimp_viewable_get_depth() function, which returns the
viewable's depth in the hierarchy, i.e., its ancestor count.
...is a regression in common cases
Commit the free select tool on double click inside the polygon.
Done by implementing GimpCanvasItem::hit() in GimpCanvasPolygon, using
ugly code.
Massimo is worried that it could unload the module (maybe in some
specific cases?), which could indeed happen when the g_type_class_ref()
just before was the first call to the class (hence it's the only ref).
So let's just unref() in the exit() function instead.
Not sure if g_type_class_ref() can actually return NULL here, but let's
add a check, just in case.
Also unref() after since we ref-ed it ourselves.
Finally reorganize a bit to keep the private functions together and
named appropriately, clean some tabs and add a comment to remind of
further check/cleanup once we port to GTK+3.
Comment by Jehan after review:
"Quick and dirty hack" but a working one. Since the bug will likely
disappear with the GTK+3 port (to be verified) which uses another theme
system, let's just do it this way.
The value descriptions of GimpGradientColor,
GimpGradientSegmentColor, and GimpGradientSegmentType enums appear
in the on-canvas gradient editor UI, as combo-box items in the tool
GUI overlay. Since we want to keep the overlay as small as
possible, we previously used abbreviations for these descriptions
(e.g., "FG (t)", instead of "Foreground (transparent)").
Replace the abbreviated descriptions with unabbreviated ones, and
move the abbreviations to the "abbrev" parameter. This way we get
the abbreviated version in the combo-box, and the full version in
the combo-box's menu.
Update the dprod production of generated enum files to include
abbreviated value descriptions, as per the previous commits.
Add a comment for translators above the abbreviated descriptions,
specifying the full description they abbreviate.
Temporarily disable multithreading for GimpOperationLayerMode, to
avoid the deadlock. The environment variable
GIMP_MULTITHREADED_COMPOSITING can be set to reenable it, for the
sake of debugging.
This reverts commit 4bd118ec8a.
The mutex introduced by the above commit should no longer be
necessary, after GEGL commit
8b034c437b0162b26f85eb80867914977ac3cf57.
When the group's offset changes, update the item's offset *after*
updating the group's offset node, so that the item's offset nodes
and the group's offset node are in sync when the corresponding
"notify" signals are emitted.
Same as for the color tags issue, short labels look much better in
menus. On the other hand, the longer description needs to be as a
tooltip, otherwise there is not enough information in the action search
to distinguish one action purpose from another.
It is possible to trigger a heap overflow while opening a malicious
pattern due to integer overflows.
The validation is adopted from plugin-parser. It also takes a proper
cast to gsize to avoid integer overflow in size calculation.
This reverts commit 189a474502.
As Mitch notes, this does not look that good in the menus. As for the
action search, since the tooltip is still shown below, the shortness and
duplication of the action labels make it less a problem.
...after exporting the image
Call gimp_image_name_changed() in both gimp_image_clean_all() and
gimp_image_export_clean_all() so we clear the cached displayed URI in
all cases, even if this means we're emitting "name-changed"
redundantly some times.
When a single blend-tool action adds and removes the same gradient
stop, restore the original gradient, rather than actually adding
and removing the stop, so that the affected midpoint returns to its
original state at the beginning of the action, rather than being
reset (and, consequently, so that the redo stack isn't lost.)
... from the undo stack
When a blend-tool edit action modifies the gradient, do a deep
comparison of the original gradient against the current gradient,
to test if anything changed, instead of just assuming that
something did change.
Current labels were very uninformative while tooltips contained what
should have been the labels. Just switch these.
Also replace GIMP_ICON_CLOSE by GIMP_ICON_EDIT_CLEAR for the various
*-color-tag-none actions. As a comment was reminding next to these
icons, the close icon was abused. The edit-clear icon on the other hand
is quite relevant.
Looking at most action labels, it seems the "Title Case" mixed-case
style has to be applied. Fix the few labels I found which were not
following this case style.
Also no need to have a tooltip when it is basically the same as the
label.
There were 4 actions displaying as "Visible" only: channels-visible,
drawable-visible, layers-visible and vectors-visible. This was not very
useful to differentiate them (for instance in action search). Just make
clearer labels.
Now add also flip information in the status bar so that one knows that
the canvas is flipped horizontally and/or vertically. Especially if you
often flip and rotate the canvas (or if you did it by mistake), at some
point, it may become confusing to remember whether this is the case. Now
it will be possible to check in a single glimpse at the status bar.
Similarly to what I previously did for the rotation information, hitting
the flip icons in status will allow to unflip easily without having to
go in menus or remember all shortcuts.
These information will be visible only when the canvas is flipped or
rotated.
Both view-rotate-other and view-zoom-other had for label "Othe_r...".
This is quite vague in particular when in out-of-menu contexts (i.e. the
action search).
In GimpCanvasTransformPreview, use the transform matrix to
determine if we're doing a perspective transform, rather than
relying on a separate property, so that we don't use the slow
perspective path unnecessarily.
Consequently, remove the does_perspective member of
GimpTransformTool, since it's no longer used.
Add "In Place" variants for all sorts of pasting:
- extend the GimpPasteType enum with IN_PLACE values
- add the needed actions and menu items
- merge the action callbacks into one, taking an enum value as parameter
- refactor the pasting code in gimp-edit.c into smaller functions
We probably have too menu items in the "Edit" menu now, needs to be
sorted out.
In gimp_group_layer_update_size(), when the layer's bounds have
changed, update the group layer's offset before the call to
gimp_pickable_flush() when reallocating the projection. Otherwise,
if the group layer's graph isn't constructed yet, it will get
constructed during the call to gimp_pickable_flush(), however,
gimp_group_layer_get_graph() will pick up the old coordinates for
the offset node.
... upon NaN values
Make the histogram bin calculation NaN-safe, by mapping NaNs to 0.
Ideally, NaNs should probably not be counted at all, but since we
already count negative values as 0, and > 1 values as 1, we might
as well not pessimize performance over it, at least until we add
support for unbounded histograms.
At the same time, improve rounding in the bin calculation, so that
the result is more accurate.
Return FALSE from gimp_display_shell_has_filter() when there are
filters, but they're all disabled, to avoid unnecessary extra
color conversions during rendering.
... leading to a crash
Add gimp_data_is_copyable() and gimp_data_is_dulicatable().
Use gimp_data_is_duplicatable() when setting the sensitivity of the
various "foo-duplicate" actions, instead of inspecting the object's
GimpDataClass::duplicate pointer directly, since this is no longer
an indication of whether a GimpData object is duplicatable or not
(since commit 33de4d5530).
When copying a generated brush, copy its "spacing" property, in
addition to the other properties, which hasn't been previously
copied by ::duplicate().
Finish up commit 17583ff04a, which
ported GimpGradient from ::duplicate() to ::copy(), by doing the
same for the rest of the GimpData subclasses that implement
::duplicate().
We still keep GimpData's ::duplicate() virtual function around,
even though it now points to the default implementation (which uses
::copy()) for all subclasses, since ::copy() is stronger than
::duplicate(), and we might want to have certain GimpData types
that are duplicatable, but not copyable.
When we have display filters, break the color profile transform in
two: first, convert from the image profile to sRGB, then apply the
filters, then convert from sRGB to the monitor profile.
When a display filter's configure() function returns NULL, use a
propgui for the filter, instead of not showing a widget at all, to
spare filters the need to manually construct a configuration gui.
When processing display filters, shift the filter buffer to the
top-left corner of the render area, and pass the actual render
area, instead of an area whose top-left coords are (0, 0), to the
display filter. This allows for position-dependent display
filters.
When applying a relative adjustment to a spin scale, don't wrap the
pointer around the corresponding screen edge if the spin scale's
value is already minimal/maximal.
While applying a relative spin scale adjusment (i.e., when dragging
from the lower half of the spin scale), wrap the pointer around the
screen edges (of the current monitor), so that the maximal possible
adjustment amount isn't artifically limited by the screen geometry.
This is especially useful for spin scales in dockables, since
dockables are normally placed near the edge of the screen.
When the mouse is released, move the pointer back to its initial
position (at the beginning of the drag), to allow for subsequent
adjustments.
Unfortunately, moving the pointer programatically isn't supported
on all envrionments (Wayland, Xephyr, ...), and worse yet,
detecting that the pointer failed to move is tricky, so we have to
resort to an ungly hack to maintain the current behavior in this
case. Gah :P
Small fix to last commit: make the name entry editable when the
data is renamable, even if it's not otherwise writable (completely
hypothetical for now.)
Make internal data objects non-renamable, even if they're writable,
through gimp_data_is_name_editable(). Currently, the only such
object is the custom gradient.
Prevent changing the name of non-renamable data by making the name
entry of GimpDataEditor non-editable whenever
gimp_viewable_is_name_editable() is FALSE, even if the data is
otherwise editable.
Prevent the vairous PDB -rename() functions from renaming non-
renamable data, by adding a GimpPDBDataAccess flags type,
specifying the desired access mode for the data -- any combination
of READ, WRITE, and RENAME -- and replacing the 'writable'
parameter of the gimp_pdb_get_foo() functions with an 'access'
parameter. Change the various .pdb files to use READ where they'd
used FALSE, and WRITE where they'd used TRUE; use RENAME, isntead
of WRITE, in the -rename() functions.
Keep track of the selected viewable of a GimpContainerEntry, and
update the entry text when the viewable's name changes, if the text
hasn't changed since the viewable was selected.
Change gimp_tool_set_active_modifier_state() to honor the new
GimpToolControlSetting. Explicitly set the mode to SEPARATE in
all tools that require modifier keys during a stroke.
And here comes the actual fix: change GimpTransformTool and
GimpToolTransformGrid to use SAME mode, and remove their
active_modifer_key() and hover_modifier() impls, so it makes no
difference whether a modifier is pressed before of after mouse button
press/release.
Add new enum GimpToolActiveModifiers { OFF, SAME, SEPARATE } and
new API gimp_tool_control_set,get_active_modifiers(), the default
value is OFF.
OFF: the tool gets no modifier keys at all during a stroke
SAME: all modifiers are always delivered via GimpTool::modifier_key(),
and no magic is applied whatsoever when a mouse button is pressed or
released.
SEPARATE: this is the "classic" way: modifiers while hovering and
while stroking are delivered separately, and hover modifiers don't
affect stroke modifiers.
Add a framework for saving and restoring internal data objects, in
gimp-internal-data.c. Internal data objects are saved in separate
files under a new "internal-data" subdirectory of the user's gimp
directory. The internal data is saved, restored, and cleared
together with the tool options.
Use this to save and restore the custom gradient. In the future,
we might add similar writable internal data objects that we'd want
to save.
Currently, the error console is highlighted (shown/blinked) only
upon errors; however, warnings, which are not shown on the
statusbar while the error console is open, often also contain
important information.
Allow the user to configure which message types (errors, warnings,
and regular messages) highlight the error console, using a new
"highlight" submenu in the error-console menu. Add corresponding
config options, saved in sessionrc. By default, highlight the
error console unpon both errors and warnings.
gimp_dockable_blink() is used to attract the user's attention to a
specific dockable. Generalize this to arbitrary widgets, by
replacing gimp_dockable_blink[_cancel]() with
gimp_widget_blink[_cancel](), in gimpwidgets-utils.c.
The GTK+ implementation of gtk_drag_higlight(), used by
gimp_highlight_widget(), paints a black box around the widget,
which is not very noticable when using a dark theme. Copy the GTK+
code (which is simple enough) over to gimpwidgets-utils.c, and use
the widget's text color for the box instead.
When changing the layer-mode group in a GimpLayerModeComboBox, check
the new mode against the combo's context, and fall back to normal if
it's not applicable. This is necessary for the color-erase mode,
which has both a legacy and non-legacy variants. The former is
applicable for painting contexts, so we want to map the non-legacy
mode to it when changing groups, however, it's not applicable for
layer contexts, so, in this case, we want to map the non-legacy mode
to normal.
It was accidentally made applicable to layers by commit
7d345071c7. Only the non-legacy
color-erase mode shoule be applicable to layers (since 2.8 didn't
allow it as a layer mode), while the legacy mode is only available
for painting, and in the fade dialog.
When set, the opacity and transparenct threshold range is compressed
to the minimal extent that would produce different results.
When the property is toggled, update the opacity and transparency
thresholds, such that the result remains the same.
Add an "expanded-changed" signal to GimpViewable, which should be
emitted by subclasses when the viewable's expanded state changes.
Emit this signal when the expanded state of group layers changes.
Respond to this signal in GimpContainerView, by calling a new
expand_item() virtual function. Implement expand_item() in
GimpContainerTreeView, expanding or collapsing the item as
necessary.
When creating a flatten node, which is used when removing alpha
channels and when flattening an image, use a gimp:normal node to
combine the layer with the background color, instead of a gegl:over
node. gegl:over can apparently result in completely black output
with OpenCL enabled, under certain (not fully pinned-down)
conditions.
As long as the OpenCL version of gegl:over is borked, there is not
much reason to use it over gimp:normal, which is more consistent
(in intension, if not in extension) with the rest of the
compositing pipeline.
Add a composite_space parameter to gimp_gegl_create_flatten_node()
and gimp_gegl_apply_flatten(), which controld the color space --
linear or perceptual RGB -- used for the operation (instead of
hardcoding it to linear).
When removing a layer's alpha channel, use the layer's composite
space for the flattening. When flattening an image, use the bottom
layer's composite space. Keep using linear space when creating a
channel or a mask from a drawable with alpha.
... which return the layer's blend/composite space/mode. However,
unlike the non-"_real" versions, these functions never return AUTO
-- instead, they return the actual space/mode that AUTO maps to for
the current layer mode.
When changing a layer's blend/composite space/mode, avoid
updating the drawable if the real space/mode didn't change (i.e.,
if changing from AUTO to the concrete value, or vice versa.)
When the mouse hovers over the upper or lower half of a spinscale,
highlight the corresponding area, to hint that the two halves
behave differently. This seems to cause a lot of confusion, so the
different cursors are apparently not enough :P
We use a low-opacity version of the current theme's text color for
the highlight, since it should have a good contrast to both the bar
color and the background color.
Increase the step and page increments of the brush radius spinscale
in the brush editor to 1.0 and 10.0, respectively, to match those of
the corresponding spinscale in the paint tool options.
Add a specialized propgui constructor for gegl:color-to-alpha-plus.
This op is currently in the workshop, but is set to be merged with
the existing gegl:color-to-alpha, so we omit the '-plus' from file-
and function-names.
The new op adds a pair of properties to control the radii, relative
to the selected color, below which colors become fully transparent,
and above which colors remain fully opaque. Allow these properties
to be set by picking a color from the image, and calculating the
radius accordingly.
Allow propgui constructors to specify an (optional) callback function
when creating pickers, to be called when a color/coordinate is picked,
similarly to controller callbacks.
Implement picker callback support in GimpFilterTool. When the active
picker has an associated callback function, call it instead of the
class's color_picked() function.
Add lots of "#include <gegl.h>" to .c files that miss it, which is
now necessary, since this commit adds a Babl* parameter in
propgui-types.h.
When switching between the save/export dialogs, preserve the
dirname part of the path (or rather, use it to set the dialog's
current folder,) not just the basename.
When rendering a gradient with a repeat mode of NONE, don't sample
the gradient at 0.0 and 1.0, for pixels that lie to the left and to
the right of the gradient, respectively. Instead, use the left
color of the leftmost segment directly, and, likewise, the right
color of the rightmost segment. This always gives us the right
color for such pixels, even when there are gradient stops, that may
use different colors, at 0.0 and 1.0,
Remember the gradient segment at which the most-recent sample lies,
and pass it to gimp_gradient_get_color_at() as a seed for segement
lookup on the next sample. This improves the performance
marginally.
When one of the line widget's properties changes, only update the
blend tool filter if the property has an effect on the result. In
particular, don't update the filter when only the selection
changes.
Separate the handling of changes to the FG/BG color from the gradient
dirty signal handling, so that the gradient editor doesn't purge the
history in response. Additionally, correctly respond to such changes
whenever the gradient has segments that depend on the FG/BG colors,
even if the dependency is introduced after the gradient is selected.
Move the tool undo functionality of the blend tool to the editor,
and add support for undoing gradient edit operations. Each undo
step that affects the gradient holds, in addition to the line
endpoint poisitions, a copy of the gradient at the beginning of the
operation, as well as necessary information to allow the selection
to "follow" undo. When undoing the operation, the saved gradient
is copied back to the active gradient.
To avoid all kinds of complex scenarios, when the active gradient
changes, or when the gradient is modified externally (e.g., by the
(old) gradient editor), all undo steps that affect the gradient are
deleted from the history, while those that affect only the endpoint
positions are kept.
Allows setting the midpoint's position, blending function, and
coloring type.
The midpoint can be converted to a stop, and centered, through
editor buttons.
Allows setting the stop's position, and its left and right colors
and color types. A chain button can be used to modify the two
colors (and color types) together.
The stop can be deleted through an editor button.
To be used by the blend tool gradient editor to edit the gradient
endpoint/stop/midpoint properties corresponding to the selected
handle.
The GUI is currently empty; the following commits add its contents.
When a midpoint is double-clicked, convert it into a gradient stop
(i.e., split the corresponding segment at the midpoint,) by
responding to the line's handle-clicked signal.
Add a tentative_gradient member to GimpBlendTool, which, when set,
is displayed instead of the current gradient.
Use this to show a version of the gradient with the currently
selected stop deleted, upon receiving a prepare-to-remove-slider
signal, i.e., when the slider is about to be removed.
Add a boolean "modify active gradient" option to the blend tool.
when checked, the active gradient is modified in-place while edited.
When unchecked, the active gradient is copied to the internal
"custom" gradient upon editing, and the custom gradient becomes
subsequently active.
Show a hint when the option is checked, but the active gradient is
non-writable, and can't be edited directly.
This commit adds the new gimpblendtool-editor.[hc] files, which are
where the gradient-editing related functionality of the blend tool
is going to go.
Add a boolean "instant mode" option to the blend tool, togglable
using shift. When checked, commit the gradient immediately when
the mouse is released.
When not in instant mode, don't commit the gradient when clicking
outside the line, since this will become easy to do accidentally
once we add on-canvas gradient editing.
Add gimp_color_panel_dialong_response() to GimpColorPanel, which
emits a response for the color panel's color dialog, if shown.
Add a "response" signal to GimpColorPanel, which is emitted upon
color dialog response.
In both cases, the response is a GimpColorDialogState, which should
be either GIMP_COLOR_DIALOG_OK or GIMP_COLOR_DIALOG_CANCEL, and not
an actual dialog response id.
Use gimp_gradient_get_{left,right}_flat_color(), instead of
gimp_gradient_get_color_at(), to get the selection endpoints'
colors in the gradient editor, so that the correct colors are used
under any condition (in particular, if there are 0-length
segments.)
When using gimp_gradient_segment_range_compress() to expand a 0-
length segment, redistribute the range's endpoints and midpoints
uniformly, rather than using the regular code path, which would
result in NaN values.
Make sure that the left and right endpoints of the range are
*exactly* equal to the new left and right values. Previously,
they could be slightly off due to numerical errors.
Treat gradient segment exents as [left, right) ranges, instead of
[left, right], so that they don't overlap, and each point
corresponds to a unique color.
Perform less comparisons in gimp_gradient_get_segment_at_internal().
... which merges a segment range into a single segment, that spans
the entire range, and has the same endpoint colors. The merged
segment's midpoint is at its center, and its blend function and
coloring type are those of the range's segments if they're uniform,
or the default ones otherwise.
... which returns the flat (context-independent) left and right
colors of a egment. Replace code that calculates the flat color
explicitly with calls to these functions.
An internal gradient object, that will be used by the blend tool
when editing a gradient. By default, the active gradient will not
be edited directly, but rather, upon editing, the active gradient's
contents will be copied to the custom gradient, which will then
become the active gradient and be edited. This allows editing both
writable and nonwritable gradients without modifying them, and
without having to duplicate them.
... which copies the contents of a GimpData into an existing GimpData,
without creating a new instance.
Add a copy() virtual function to GimpData, which subclasses can
override to implement copying; gimp_data_copy() may only be called
for types that implement copy(). Keep the duplicate() virtual
function around, but provide a default implementation that creates
a new object of the source type, and uses copy() to copy the source
object into it.
Add parameters, controlling the behavior and appearance of sliders,
to GimpControllerSlider. The macro GIMP_CONTROLLER_SLIDER_DEFAULT
expands to a nonmodifiable lvalue of type GimpControllerSlider,
whose members are initialized with the most common default values.
Handle the new parameters in GimpToolLine. A slider using the new
"autohide" mode is only visible when selected, or when the cursor
is close enough to the line, between the slider's min and max
values, and no other handle is grabbed or hovered-over.
... which is emitted when a handle is single/double/tripple clicked.
The signal handler returns a boolean value. A return value of TRUE
stops further event processing, while a return value of FALSE allows
it.
The signal is emitted when a slider is dragged away from the line,
and will be removed when the button is released, and when the
slider is dragged back to the vicinity of the line, and won't be
removed. The last parameter of the signal is a boolean flag
differentiating between the two cases.
Note that a remove-slider signal may be emitted without a preceeding
prepare-to-remove-slider signal, however, is a prepare-to-remove-
slider signal is emitted with a TRUE last parameter, it must be
eventually followed by a remove-slider signal, or by another
prepare-to-remove-slider signal with a FALSE last parameter.
Add support for adding and removing sliders to/from a GimpToolLine,
using three new signals:
- can-add-slider: Takes a double argument in the range [0,1],
indicating a location along the line, and returns a boolean
value, indicating whether a slider can be added at that
location.
- add-slider: Takes a double argument in the range [0,1],
indicating a location along the line, for which can-add-slider
returned TRUE. In response, should add a new slider at that
location, and return its index, or a negative value if no
slider was added.
- remove-slider: Takes a slider index. In response, may remove
the slider.
On the UI side, when the cursor is close enough to the line, but
not within the hit area of an existing handle, GimpToolLine checks
if a slider can be added at the cursor position, using can-add-
slider. If a slider can be added, a dashed circle appears at the
cursor position along the line, indicating where a slider will be
added. The cursor is added by clicking, which emits an add-slider
signal; if the signal returns a slider index, the new slider is
selected, and can be subsequently dragged.
Removing a slider is done by either selecting the slider and
pressing backspace (or delete, although we don't actually forward
it to the tool atm,) or by "tearing" the slider: when dragging
the slider, if the cursor is far enough from the liner, a dashed
circle appears around the slider, and releasing the mouse removes
the slider.
En route to on-canvas gradient editing, add support for persistent
handle selection to GimpToolLine (a handle being either an endpoint
or a slider). Handles are selected through clicking, however,
unlike before, the selection persists after the mouse is released.
A new "selection" property specifies the currently-selected handle
(who knows, maybe in the future we'll add multi-selection), and a
new "selection-changed" signal is emitted when the selection changes.
The visual feedback has been changed to better suit the new behavior,
and the behaviors yet to be added: The selected handle is marked
using highlighting; the highlighting doesn't change while hovering
over other handles. Only the hit-test circle is used as hover
indication, however, we use a fixed-size circle, and only show the
circle for the currently hovered-over handle -- no more trippy
expanding circles :)
A few minor changes along the way:
- The selected handle is now the (first) one that's closest to the
cursor, instead of the first one to pass hit-testing.
- We don't move the selectd handle upon button-press, only upon
motion, so that handles can be selected without moving them.
- Show a MOVE cursor modifier when hovering over a handle.
... and ignore language setting (e.g. en_US).
The problem came from the fact that these settings names are class
properties of GimpPaintOptions/GimpContext which is first instanciated
when the Gimp object is created. This unfortunately happened before
language_init() since we needed these objects when loading gimprc
(making inversion of calls rather complicated).
Therefore they were localized with the system language, not the
configured language.
The solution was to create a very simple object GimpLangRC which
implements the GimpConfig interface, for sole purpose to read the
language from `gimprc` in a first pass. gimp_load_config() will still
happen later as a second pass to properly load the rest of the
configuration.
While I am at it, let's spread the improvement to options_box which was
also a weak pointer with g_object_add_weak_pointer(). Let's make it
rather a GWeakRef for the same reason as I did options_gui.
Other than multi-threading (which here is not the problem), using
GWeakRef has the other advantage that it makes the type of pointer
obvious, hence avoiding the kind of errors as fixed in commit 12df796.
One can't just change the pointer value directly, and has to use
g_weak_ref_set(), so such problem won't happen again.
Repalce the two separate size entries, used for the position and
size properties of GimpRectangleOptions, with a single size entry
with two fields, so that they accept ratio expressions. Note that
this doesn't change the UI.
When loading tile data, avoid copying the data into the GEGL
buffer when the tile is empty (i.e., all its bytes are 0), so that
GEGL doesn't allocate memory for it unnecessarily.
Better factorize by reusing code rather than recreating a combo box
which does basically the same thing. I only added a boolean parameter to
retrieve only the sublist of manual language.
It also takes advantage of the self-translated language names from
initialization.
In gimp_canvas_sample_point_get_extents(), use the drawn number's
actual size instead of some random constant that was good enough for
my own font size.
When the manual in your current language is not installed, yet other
manuals are available, the help dialog will now propose either to read
the manual online (as was already the case) or to select a manual in
another language instead. This is even more important since we don't
have as many manuals as localizations of GIMP. Therefore if one took the
explicit step to install a manual in another language, it makes sense
that means one may know the alternative language. As an example, we have
3 Chinese localizations (zh_CN|TW|HK) but only a zh_CN manual. I could
definitely imagine someone with a zh_HK GUI to go for the zh_CN manual
as a fallback. Or other languages even, whatever!
This is a first step. Right now once one chose the alternative help
language, it is not possible to reset it yet (except by editing
"help-locales" in gimprc). The next step will be to add the settings in
Help System preferences.
... the matrix is not actually used
Don't abort transform-tool commits when the transformation matrix
is the identity, for transform tools that don't calculate a
transformation matrix to begin with (i.e., the flip tool),
otherwise they do nothing.
An empty gorup layer has no extent, so we fake its extents to be at
least 1x1 whenever its projection is being recreated, because we can't
have a 0x0 buffer in a drawable. This safeguard was forgotten in
gimp_group_layer_convert_type() which gets called on image duplicate.
It was always supposed to be like that, but simply forgotten.
Fortunately, big-endian machines are almost extinct...
The new code is triggered with XCF version >= 12, but we will start
using that only after code review.
Updating the cursor information involves sampling the active image/
drawable, which can be expensive, especially if there are filters
active that also respond to cursor motion, e.g., while using the
warp tool.
Move the actual updating to an idle function. This dramatically
improves responsiveness in these situations.
Remove the invert-linear and invert-non-linear variants and simply add
"gboolean linear" to gimp-drawable-invert. This should actually be an
enum but I didn't find a good name right now...
Pass through mode uses the same compositing logic as REPLACE mode,
however, it's a special case of REPLACE, where the layer is already
composited against the backdrop. This allows us to take a few
shortcuts that aren't generally applicable to REPLACE mode.
Add a dedicated op class for pass through mode, derived from the
REPLACE mode op, implementing these shortcuts.
and add gimp_drawable_invert_linear(). Also, finally deprecate
gimp_invert() and port all its uses in plug-ins and scripts to
gimp_drawable_invert_non_linear() so the result is the same.
Fix the default brush name -- "Round Fuzzy" was gone for a while :P
The fact that "Hardness 050" was the default brush regardless is a
conincidence; see the bug report for more details.
glib-genmarshal was rewritten in glib 2.53.4, and as of now (2.53.6)
it has a bug where it unconditionally generates marshaler bodies,
even for standard marshalers, even with --stdinc. This causes
libgimpwidgets to define and export g_cclosure_marshal_VOID__INT()
and g_cclosure_marshal_VOID__OBJECT(), which upsets defcheck, and
breaks the build.
Work around this for now by using --header --body when generating
the marshal.c files, which includes the prototypes in the source,
instead of including the header ourselves. This is the only code
path where the new glib-genmarshal doesn't generate bodies for
standard marshalers. Note, however, that this usage is deprecated,
so we'll probably want to change it back once it's fixed.
...in both the core and libgimp.
Images now know what the default mode for new layers is:
- NORMAL for empty images
- NORMAL for images with any non-legacy layer
- NORMAL_LEGAVY for images with only legacy layers
This changes behavior when layers are created from the UI, but *also*
when created by plug-ins (yes there is a compat issue here):
- Most (all?) single-layer file importers now create NORMAL layers
- Screenshot, Webpage etc also create NORMAL layers
Scripts that create images from scratch (logos etc) should not be
affected because they usually have NORMAL_LEGACY hardcoded.
3rd party plug-ins and scripts will also behave old-style unless they
get ported to gimp_image_get_default_new_layer_mode().
gimp_layer_update_mode_node(): when showing the mask, set mode to
NORMAL, and make sure that the composite space is PERCEPTUAL for
LEGACY layers, and LINEAR (or whatever is chosen in layer attibutes)
otherwise.
this commit changes just those which make no difference to
functionality: property and object member defaults that get overridden
anyway, return values of g_return_val_if_fail(), some other stuff.
Looked a bit deeper into heal: while I didn't try to understand what
it's actually doing, this is strange: there is a comment that says
that healing should done in perceptual space, and the code uses
R'G'B'A float (at least it completely did before the last commit).
On the other hand, the code adds and subtracts temporary buffers,
which screams "gamma artifacts" unless done in linear space.
This commit changes everything to use linear float buffers,
and removes the comment. It "looks" right to me now, please test.
Split libappgegl into libappgegl-generic and libappgegl-sse2, and
move the SSE2 code (part of the newly added smudge code) to the
latter, so that the rest of the code can be compiled without SSE2
compiler flags. This allows building GIMP with SSE acceleration
enabled, while running the resulting binary on a target with no
SSE accelration.
Commit 3635cf04ab moved the special
handling of bottom-layer compositing to GimpOperationLayerMode.
This required giving the op more control over the process()
function of its subclasses. As a temporary workaround, the commit
bypassed the subclasses entirely, using "gimp:layer-mode" for all
modes. This is the reckoning :)
Add a process() virtual function to GimpOperationLayerMode, which
its subclasses should override instead of
GeglOperationPointComposer3's process() functions. Reinstate the
subclasses (by returning the correct op in
gimp_layer_mode_get_oepration()), and have them override this
function.
Improve the way gimp_operation_layer_mode_process() dispatches to
the actual process function, to slightly lower its overhead and
fix some thread-safety issues.
Remove the "function" field of the layer-mode info array, and have
gimp_layer_mode_get_function() return the
GimpOperationLayerMode::process() function of the corresponding
op's class (caching the result, to keep it cheap.) This reduces
redundancy, allows us to make the ops' process() functions private,
and simplifies SSE dispatching (only used by NORMAL mode,
currently.)
Move the blend and composite functions of the non-specialized
layer modes to gimpoperationlayermode-{blend,composite}.[hc],
respectively, to improve code organization.
Move the SSE2 composite functions to a separate file, so that they
can be built as part of libapplayermodes_sse2, allowing
libapplayermodes to be built without SSE2 compiler flags. This
allows building GIMP with SSE acceleration enabled, while running
the resulting binary on a target with no SSE accelration.
Add a "blend_function" field to the layer-mode info array, and use
it to specify the blend function for the non-specialized modes.
This replaces the separate switch() statement that we used
previously.
Remove the "affected_region" field of the layer-mode info array.
We don't need it anymore, since we can go back to using
GimpOperationLayerMode's virtual get_affected_region() function.
Last but not least, a bunch of code cleanups and consistency
adjustments.
Paint tools in straight line mode (shift click) will now display the
angle in status bar. Angle 0 is considered as the horizontal line from
left to right, and angle is measured counterclockwise from there, which
is the most common convention.
Use GIMP_LAYER_MODE_NORMAL (not NORMAL_LEGACY) when falling back from
gimp_paint_core_replace() to gimp_paint_core_paste() for layers
without alpha. Adapt the format of the used paint buffers accordingly.
... and fix flatten-image along the way. *And* do some cleanup.
Currently, gimp_image_merge_layers() combines the layers on its own,
one by one. This is incompatible with pass-through groups, because
the group's buffer is rendered independently of its backdrop, while
we need to take the backdrop into account when mergeing the group.
Instead, render the subgraph of the parent graph, corresponding to
the set of merged layers, directly into the new layer. Since the
layers we merge are always visible and continuous, all we need is a
minor massage to the parent graph to make it work. This takes care
of pass-through groups intrinsicly.
This commit also changes the behavior of flatten-image: Currently,
the flattened layers are rendered directly on top of the opaque
background, which can make previously-hidden areas (due to layers
using composite modes other than src-over, or legacy layer modes)
visible. This is almost certainly not desirable.
Instead, construct the graph such that the flattened layers are
combined with the background only after being merged with one
another.
GimpFilter's is_last_node field only reflects the item's position
within the parent stack. When a layer is contained in a pass-
through group, it can be the last layer of the group, while not
being the last layer in the graph as a whole (paticularly, if
there are visible layers below the group). In fact, when we have
nested pass-through groups, whether or not a layer is the last
node depends on which group we're considering as the root (since
we exclude the backdrop from the group's projection, resulting in
different graphs for different groups).
Instead of rolling our own graph traversal, just move the relevant
logic to GimpOperationLayerMode, and let GEGL do the work for us.
At processing time, we can tell if we're the last node by checking
if we have any input.
For this to work, GimpOperationLayerMode's process() function needs
to have control over what's going on. Replace the derived op
classes, which override process(), with a call to the layer mode's
function (as per gimp_layer_mode_get_function()) in
GimpOperationLayerMode's process() function. (Well, actually, this
commit keeps the ops around, and just hacks around them in
gimp_layer_mode_get_operation(), because laziness :P)
Keep using the layer's is_last_node property to do the invalidation.
GimpTileHandlerProjectable is similar to GimpTileHandlerValidate,
except that it calls {begin,end}_render() on its associated
projectable before validating.
In pass-through mode, the group layer-stack's input is connected to
the backdrop. However, when rendering the group's projection, we
want to render the stack independently of the backdrop.
Unfortunately, we can't use the stack's graph as a subgraph of two
different graphs.
To work around that, the next few commits add a mechanism for a
projectable to be notified before and after its graph is being
rendered. We use this mechanism to disconnect the stack's graph
from the backdrop before rendering the projection, and reconnect
it afterwards. Yep, it's ugly, but it's better than having to
maintain n copies of (each node of) the graph (each nesting level
requires an extra copy.)
This commit adds {begin,end}_render() functions to GimpProjectable.
These functions should be called right before/after rendering the
projectable's graph.
When any of the children of a pass-through group excludes its
backdrop, the group itself should exclude the backdrop too. Override
get_excludes_backdrop() to follow this logic, and call
update_excludes_backdrop() when this condition might change.
Note that we always composite pass-through groups using src-over mode,
so to actually hide the backdrop, we need to disconnect it from the
group's mode node's input pad (and reconnect it, when the backdrop is
no longer hidden).
Override GimpDrawable::get_source_node() for GimpGroupLayer. Use
a node that contains both the drawable's buffer-source node, and the
layer stack's graph node. Choose which one of these to connect to
the source node's output based on the group's layer mode: the stack
graph for pass-through mode, and the buffer-source node for all the
rest.
When in pass-through mode, connect the source node's input (which
receives the backdrop) to the stack graph's input. Keep maintaining
the projection in pass-through mode. ATM, the projection uses the
same graph as the source node, so it's rendered against the group's
backdrop -- we don't want that. The next few commits fix it.
Update the group's drawable directly upon filter stack update in
pass-though mode, because the group's graph doesn't go through the
projection.
TODO: if any of the group's children (or a child of a nested pass-
through group, etc.) uses dst-atop/src-in, this needs special
attention.
Make sure the input of the layer's filter node is connected to its
source node (when it has an input pad), so that, once we implement
pass-though mode, the group's source node can see the backdrop.
For pass-through groups, we want to use the group's layer-stack
graph directly in its filter node, in place of the drawable's
buffer-source node. Add a get_source_node() vfunc to GimpDrawable,
which defaults to returning the buffer-source node, and use it in
gimp_drawable_get_source_node() instead of using the buffer-source
node directly. We'll later override this function for
GimpGroupLayer.
... causing compilation to fail on 32 bit targets
Use SSE2 compiler flags when building libappgegl, since it's used by
the new smudge tool code.
Avoid using SSE for the smudge tool if SSE acceleration is disabled
at runtime, or if the buffers are not properly aligned.
Add "gboolean with_filters" to gimp_drawable_calculate_histogram(),
which is passed as FALSE in almost all places, except the histogram
dockable where we want to see both the drawable's unmodified histogram
*and* the histogram after filters are applied.
During constrained motion, round the slider value before clamping
it, so that the slider limits are always enforced. Additionally,
snap the slider to 1/12-ths of the line length, rather than
1/24-ths.
Make sure that sliders can never have negative-zero values, which
can result in a -inf base for spiral.
Shift-click should actually toggle only within a given group. The new
capability of toggling only a sub-item, brought by commit 970e9ac is
still feasible in 2 steps: first toggling the parent (item group), then
the desired child.
It brings now a third possibility with exclusive toggle among many
children items, without touching other groups and top-level items.
... so that when the base and balance sliders overlap, the base
slider is the one that's picked, since the balance slider is
constrained by the base, but not the other way around.
When loading tiles from an XCF, reject tiles whose on-disk size is
greater than 1.5 times the size of an uncompressed tile -- a limit
that is already present for the last tile in the buffer. This
should allow for the possibility of negative compression, while
restricting placing a realistic limit.
Currently, no limit is placed on the on-disk tile data size. When
loading RLE- and zlib-compressed tiles, a buffer large enough to
hold the entire on-disk tile data, up to 2GB, is allocated on the
stack, and the data is read into it. If the file is smaller than
the reported tile data size, the area of the buffer past the end
of the file is not touched. This allows a malicious XCF to write
up to 2GB of arbitrary data, at an arbitrary offset, up to 2GB,
below the stack.
Note that a similar issue had existed for earlier versions of GIMP
(see commit d7a9e6079d3e65baa516f302eb285fb2bbd97c2f), however,
since prior to 2.9 the tile data buffer was allocated on the heap,
the potential risk is far smaller.
...with known plugins
Add new plug-in file-raw-placeholder.c that registers itself for
loading all RAW formats from file-raw/file-formats.h, but does nothing
except returning an error message pointing to darktable and
RawTherapee.
When no real RAW loader is installed, this plug-in is selected
automatically as RAW loader, otherwise the first installed RAW loader
is used. Selecting another in prefs still works as before.
... "threads" property.
Actually there is no need of having a public GEGL_MAX_THREADS as written
in the previous commit. We can just retrieve the max for a GObject
property.
Raise GIMP_MAX_NUM_THREADS to 64, following the changes in GEGL (see
GEGL commits 6d128ac and f26acbb). This is still considered unstable and
to be used at one's own risk (cf. GIMP commit 1f5739d) but at least, it
could allow discovering and fixing bugs.
It would be nice if GEGL_MAX_THREADS could be public so that to not have
to edit this by hand at each change.
- trailing whitespaces cleaned out;
- vectors are called "path" in all visible strings;
- do not check for floating selection and active channel: oppositely to
layers, a vector can be selected in the same time as a channel, and
while there is a floating selection.
and update the grid as soon as a constraint is changed, not only on
the next motion. Change GimpTransformTool to forward the events to the
widget if it exists, but still handle them if it doesn't (yes this
code duplication is ugly, but the widget can hardly handle events if
it doesn't exist...).
More than 2000 lines of code less in app/, instead of
if (instance->member)
{
g_object_unref/g_free/g_whatever (instance->member);
instance->member = NULL;
}
we now simply use
g_clear_object/pointer (&instance->member);
Change the text selection to draw an outline around each selected
glyph. It looks just as ugly as before but at least keeps the text
readable regardless of its color.
if did revert to the previous selection and thus break stuff like
enbaling quick mask or inverting the selection, because I merged the
undo magic it does into gimp_rectangle_select_tool_halt(), whereas
before it was done by the former gimp_rectangle_tool_cancel(), so only
on explicit cancel not HALT from whatever source.
Do the same in the new code and move the undo magic from halt() to
rectangle_response(CANCEL), which is exactly the same distinction as
with the old GimpRectangleTool code.
When the user provides a filename without an extension in the save
dialog, we add one for them, update the filename in the dialog, and
retry. However, the updated filename is made up of only the
basename, leaving out the dirname part, if specified. This means
that if the user enters "/somedir/somefile", the new filename
becomes "somefile.xcf", which refers to the current directory,
instead of "somedir".
Fix this by maintaining the dirname when adding a file extension.
Don't unconditionally call COMMIT in rectangle_response(), because
that now implicitly HALTs the tool. Instead, check if we got here
because of a click, and call our commit() directly.
which is the same as g_object_class_list_properties() but filters
out the properties for which we don't want to create a GUI.
Use it in gimp_prop_gui_new().
GimpOperationTool's aux inputs were not properly ported to the new way
filter tools work (complete destruction and re-creation of the tool
dialog).
Split creating the operation GUI and adding it to the dialog into
separate functions, and call them at the right places.
Call HALT generically in gimp_tool_control() after calling COMMIT, and
remove all hacks in tools that call both COMMIT and HALT or call
halt() from commit().
Some tools interact with their subclasses (e.g. filter tool and
operation tool), and it's essential that COMMIT runs through the
entire class hierarchy before HALT.
Probably breaks something, please test.
Need to keep around the operation's name and its description, so
everything can be re-created when an image is clicked.
Instead, completely shut down GimpOperationTool when GimpGeglTool is
halted, so the next click will bring up a dialog with only the
operation selection combo.
which allow to override stuff from GimpToolInfo for dynamic tools like
GimpFilterTool and friends. When NULL, the getters are falling back to
GimpToolInfo strings.
...and "export_dialog_title"
It's ridiculous to keep this code around for strings that are only
marginally different (and not better) than the strings we can generate
from other strings we have anyway.
to ::can_undo() and ::can_redo(). They still return description
strings and the new naming is slightly off :) but get_undo_desc() will
be needed for something else soon, and half of the time the functions
are indeed used to check whether there are undo/redo staps at all.
Switch the gegl:spiral prop gui from using a line controller to
a slider-line controller, and use sliders to control the "balance"
and "base" properties.
Add supprt for placing sliders on a GimpToolLine -- handles that can
be dragged over the line. The sliders are accesible through a new
"sliders" property, and via the gimp_tool_line_{get,set}_sliders()
functions.
Add a slider-line controller, which works like a line controller,
but whose callback also supplies/takes an array of sliders.
Note that the data type for individual sliders is called
GimpControllerSlider (in particular, it's not line specific), so
that we may use it with other controller/tool-widget types in the
future.
Use the new gimp_filter_tool_get_drawable_area() instead of always
using gimp_item_mask_intersect() which is only right when the
operation is applied to the "selection" region. Also call
gimp_operation_tool_sync_op() when the region is changed in the UI.
Don't offset the ui range of op properties that use pixel-distance
units to the top-left corner of the region, since they're relative;
only do that for pixel-coordinate units. Let their ui range be
[0, width/height].
Pass a "GimpCreateControllerFunc" to all gimppropgui-*.[ch]
constructors which takes a callback (to update the config object when
the on-canvas GUI) and a controller type that determines the
callback's signature, and returns another callback (to update the
on-canvas GUI when the config object changes).
In GimpOperationTool, pass such a GimpCreateControllerFunc that
handles creating and adding on-canvas controller via the new
gimpfiltertool-widgets.[ch]. So far, a simple line like in the
blend tool is supported.
Add a custom GUI for gegl:spiral, and have its origin, radius and
angle controlled by such a line.
which return's the used drawable's offsets and a GeglRectangle
where the filter is applied according to GimpFilterOptions::region
(either the selection or the whole drawable).
and call it from GimpFilterTool's "notify" callback. Remove signal
connections from all subblasses and instead implement ::config_notify().
The config object belongs to GimpFilterTool, and only GimpFilterTool
should know when it's created and can be connected to.
so things from the tool's previous use get destroyed, including their
(maybe dangling) signal connections. Also shut down more stuff in
halt(), including destroying not just hiding the GUI.
because widgets are bound to one GimpDisplayShell. Also, chain up
unconditionally in gimp_color_tool_draw(), we always want to draw the
widget even while picking colors.
The widget is fed events by GimpFilterTool, the actual interaction
with the filters operation and config will be done by subclasses.
The order of precedence when there are multiple possible canvas
interactions is: moving the split preview guide, color picking,
widget.
- introduce new state "boolean is_first" which tracks if the currently
drawn rectangle is the first with this instance
- cancel the widget if there was no movement when creating the first
rectangle
- undo to the previous rectangle if the user created a zero-extent
rectangle
- also undo to the previous rectangle if a newly drawn rectangle is
canceled with button-3 release
We can't rely on g_object_unref() in halt() for breaking all property
GBindings between the tool options and GimpToolRectangle, because we
might be in the middle of a signal emission which also refs and keeps
the rectangle alive until the last callback returns. So we had
dangling rectangles interacting with tool options.
Remember all bindings in a list, and break them explicitly when we
shut down the rectangle in halt().
Also, forgot to unset the display's highlight in the rectangle
selection tool.
because of bailing out early after emitting "response". Instead, don't
ref the object around this function, and move the "response" emission
to the end of the function.
The tool manager still keeps an active tool which it unrefs on
destruction, triggering a final HALT on the tool, which may want to
lookup tool options to reset something. Happened with the new
widget-ported rectangle select tool.
- enable the setting code in gimp-gegl.c again
- but set the default to one thread in GimpGeglConfig, with a CPP warning
- rename "processors" to "threads" in the GUI
- add a warning box about unexpected results when increasing #threads
We were leaking all tool widgets set with gimp_draw_tool_set_widget(),
and those having signal connections to e.g. the display shell were
doing things when they were supposed to be gone. Fixes make check.
- factor out widget creation to new start() function
- and tool shutdown to new halt() function
- connect to "response" and remove key_press()
- remove oper_update(), it was doing the same as the draw tool impl
- unset "rect_adjusting" before bailing out on button_release()
- update the integer rectangle when the double properties change
- don't try to show handles with a size of < 3
- remove unused members
- shorten some variable names
which is a replacement for GimpRectangleTool. It's a massive piece of
code and I'm not sure everyting works as it should, but it seems to do
crop stuff without any glitches.
and a default key_press() handler that emits CONFIRM, CANCEL and RESET
responses. Remove code with the same purpose from all subclasses.
Change tools feed key_press() to the widget and connect to its
"response" instead of implementing key_press() themselves. This will
only be better and less code after the tool side of this is done
generically.
Rename gimp_tool_widget_snap_offsets() to set_snap_offsets(),
and add gimp_tool_widget_get_snap_offsets().
Also rename gimp_tool_widget_status() to set_status(), and
add new function and signal set_status_coords().
When toggling visibility of a child in an item group, we should also
toggle the visibility of other items in the same group, as well as
top-level items. Otherwise toggling exclusive visibility of any item in
a group is identical to toggling the parent's exclusive visibility,
which is simply absurd.
We still don't touch visibility of items in other groups.
which is the code that calculates handle size based on pointer
proximity. Use the new function in GimpToolHandleGrid and
GimpToolLine, and clean up some stuff in GimpToolLine.
Simply use g_object_bind_property() to connect the grid properties of
GimpTransformOoptions and GimpToolTransformGrid and remove all other
grid property setting code.
The GimpLayer implementation of the GimpItem transform functions,
and the GimpDrawable convert_type() function, apply their operation
to both the layer and its mask. The subclasses of GimpLayer --
GimpGroupLayer and GimpTextLayer -- override some of these
functions, providing their own logic for the layer part, and
duplicating the mask part.
Avoid this duplication by adding a set of virtual transform and
type-conversion functions to GimpLayer. Have the GimpLayer
implementaion of the corresponding GimpItem and GimpDrawable
functions use these functions to apply the operation to the layer,
while taking care of the mask themselves. Have GimpLayer's
subclasses override the new virtual functions, instead of the
GimpItem and GimpDrawable ones.
Note that the existing implementation of convert_type() in
GimpTextLayer neglected to convert the mask, hence text layer masks
retained their old format after conversion. This issue is fixed as
a side effect of this commit.
Humanize action names to make them readable while
preserving their original grouping. Mark for translation
the missing ones. Use absolute values to make
"increase/decrease more" less cryptic since we hardcode
those values anyway.
so widgets can return which handle was clicked. The values boolean
semantics stay the same so if(retval) gives the same result. This is
useful for the upcoming transform tool widgets.
The GEGL ops sanity check causes all ops to be initialized. The
strings used by their properties will pick the translation selected
at the time of the check. It must therefore run after language
intiailization, otherwise the selected translation would correspond
to the system locale, even if the user selected a different language
in the preferences.
Split the sanity check into early and late stages. The early stage
is run before the call to app_run(), as it did before, while the
late stage is run during app_run(), after the configuration has been
loaded. Currently, the GEGL ops check is the only late-stage check;
all other checks are performed during the early stage.
The identity parameter checks added to the raster brush
transformation functions in the previous commit are unnecessary,
since we're already testing for the identity matrix. Remove them.
Check if the brush parameters match the identity parameters, and
return the original brush mask/pixmap if they do, in the actual
mask/pixmap transformation virtual functions, instead of in their
wrappers. While the identity parameters for raster brushes are
always scale=1, aspect-ratio=0, angle=0, and hardness=1, for
generated brushes they depend on the specific brush
parameterization.
Thanks to Lionel N. who bugged me with his Windows installation where
the XML file was not found by GIMP. We should output a warning when this
happens so that packagers can detect the issue and the expected
installation path for this dependency.
The reporter wants me to call him "Padawan Lionel" but I won't fall for
it! Or did I? :-D
This option behaves similarly to the other transform tool, however
it's limited to "adjust" and "clip" only. Now that the flip tool
can reflect across guides, this option is meaningful.
... when clipping, if they have an alpha channel
Right now, this case is only reachable through PDB, but it will become
relevant for the flip tool soon.
When compressing tool motion events, only compress motion events
at the front of the event queue, targeted at the same widget as,
and having similar characteristics to, the initial motion event;
stop compressing upon the first mismatched event.
Previously, all pending motion events targeted at the canvas were
compressed, stopping only at a button-release event targeted at the
canvas. As a result, when adding a guide by dragging from a ruler,
there could be a situation where a pending button-release event
targeted at the ruler would be followed by motion events targeted at
the canvas, with a cleared state mask. These motion events would
get compressed to the initial motion event targeted at the ruler,
resulting in a motion event with a cleared state mask being processed
before the said button-release event. This, in turn, would cause the
guide tool's cursor_update function to be called, while the tool is
still active, emitting a CRITICAL. Sheesh.
The moral of the story is: let's play it safe.
which encapsulates a bunch of GimpCanvasItems plus their interaction,
using GimpTool-like virtual functions like button_press(),
button_release() motion() etc. Also has GimpDrawTool-like API to
manage the canvas items of its subclasses.
Call gimp_canvas_group_remove_item() and don't just unref them, so
their state gets restored and signals get disconnected. They may not
be owned by the group, or have other external references.
Simply increase its change_count in dispose(). There is really no
reason to build expensive update regions and emitting signals when we
are about to go away.
Add a log handler so that GIMP can display errors outputted by GEGL.
Since third party code may run in threads and we have no control on
these, we have to be sure GTK+ code is run in a thread-safe way, hence
the usage of gdk_threads_add_idle_full(). This was the case here for
GEGL, and handling GEGL logs the same way as other GIMP logs would
result in crashes.
This way, you can increment repeated messages even when not the last
one and you don't overflow the error dialog needelessly when 2 errors
repeat one after another.
by encoding them directly in the string attached to all filter
actions. The code now supports both "gegl:some-operation" and
"gegl:some-operation\n<serialized config>".
Add "default_settings" to GimpGeglProcedure to store the settings of
the invoking action, much like the "default_run_mode" member.
Change filters-commands.c to parse the new operation string, create
GimpGeglProcedures with the deserialized settings, and use those
settings when the procedures are ran.
Change the filter history to be smarter about what is already in the
history, there can now be several different procedures with the same
name.
Remove the dilate and erode actions from the drawable group, and add
them to filters, they are just special cases of value-propagate with
fixed settings.
Allow NONE(0) for "wrapmode" (which translates to GEGL_ABYSS_NONE) in
the plug-in-edge PDB compat wrapper. The old plug-in accepted this
(undocumented) value and used a GimpPixelFetches in NONE mode.
which determines if a filter is applied directly (RUN_NONINTERACTIVE)
or asynchronously using GimpOperationTool (RUN_INTERACTIVE).
Split filter actions in two groups, one for direct apply and one for
interactive apply, which have separate callbacks that create
GimpGeglProcedures with the right default_run_mode set.
(After doing this distinction automatically based on the existance of
editable properties, I figured will might want direct apply also for
filters that do have properties, such as e.g. dilate and erode, which
are just value-propagate with some constant property values)
which gets added automatically by procedure_commands_get_display_args().
Move the non-interactive and run-with-last-vals code to
gimp_gegl_procedure_execute() (not execute_async()) because it makes
more sence to call it synchronously anyway (not implemented yet).
This commit should change no behavior.
Since commit bc4589968c, GimpFilterTool
assumes that color picking is only ever enabled through color picker
toggles, created using gimp_filter_tool_add_color_picker(). However,
the curves tool enables color picking using the color tool functions
directly. CRITICALS ensued.
Use the new gimp_filter_tool_enable_color_picking() function, added
in the previous commit, and handle picking through the filter tool
interface, instead of the color tool interface. This fixes the
issue.
Subclasses of GimpFilterTool should use these functions to control
picking, instead of using gimp_color_tool_{enable,disable}()
directly. This makes sure that the tool's picking state is
consistent, and allows the caller to control the pick identifier,
and use abyss picking (not currently needed by any subclass, but
maybe in the future, who knows.)
Return only the config object's GType and do the g_object_new() in the
caller (one caller only needs the type, there is no need to create a
dummy object just to get to its type).
around calling the actual execute vfuncs, Seen a crash when quitting
GIMP while a script-fu window was open, the progress was already
finalized. Now it simply prints the error message about the failing
script on the concole.
so they show up in recent filters, and don't need their own callbacks.
This has the problem that they now show a GUI with no options, but
that simply puts on more pressure to fix this general uglyness of ops
without editable properties.
We don't search recursively but only at the first level. If a plugin is
in its own subdirectory, the entry point has to be named the same (minus
extension) as the directory. For instance my-plugin/my-plugin for a
binary, or my-plugin/my-plugin.(py|exe|…).
This way, a plugin can load shared objects (libraries, other script
files, etc.) without polluting the main plug-ins directories, and in
particular without interfering with other plug-ins.
This is a first step to fix bug 757057 (DLL files which were used in
various plugins).
Commit 1e6acbd4e1 modified the
generated enum recipes to run gimp-mkenums from the source
directory, instead of the build directory, so that only the
basenames of the corresponding header files would appear in
the comment at the top of the generated files. This was a
mistake -- $(GIMP_MKENUMS) is expecting to be invoked from the
build directory.
Switch back to running gimp-mkenums from the build directory. To
avoid including the relative path from the build directory to the
source directory in the generated file, add a @basename@ production
variable to gimp-mkenums, which exapnds to the basename of the
input file, and use it instead of @filename@ in the recipes for the
generated enum files.
When regenerating an enum file, don't copy it back to the source
directory if it hasn't actually changed. This allows using a read-
only source directory where the enum header is newer than the
generated file, as long as they're not really out of sync.
OTOH, *do* touch the generated source-dir file even when unchanged,
in order to avoid re-running its recipe on the next build, however,
allow this to silently fail (which is harmless).
The layer blend space, composite space, and composite mode
properties have a special AUTO value, which may map to different
concrete values based on the layer mode. Make sure we can change
this mapping in the future, without affecting existing XCFs (saved
after this commit), by encoding these properties as follows:
When saving an XCF, if the property has a concrete (non-AUTO)
value, which is always positive, encode it as is. If the property
is AUTO, which is always 0, encode it as the negative of the value
it actually maps to at the time of saving (note that in some cases
AUTO may map to AUTO, in which case it's encoded as 0).
When loading an XCF, if the encoded property (stored in the file)
is nonnegative, use it as is. Otherwise, compare the negative of
the encoded property to the value AUTO maps to at the time of
loading. If the values are equal, set the property to AUTO;
otherwise, use the concrete value (i.e., the negative of the value
stored in the XCF).
Note that XCFs saved prior to this commit still load fine, it's
simply that if we change the AUTO mapping in the future, all their
AUTO properties will keep being loaded as AUTO, even if the
resulting concrete values will have changed.
... to the warp tool
The interpolation and abyss policy options control the sampler type
and abyss policy of the map-relative node. The high quality preview
option determines whether to use the same sampler for map-relative
during preview as the one used during commit, or whether to use a
fast nearest-neighbor sampler.
A bit too much? Maybe :)
... and to disable/control the rate of the periodic stroke.
The warp tool is now fast enough to enable stroking directly in
the motion handler, which gives better-quality response to motion
than stroking periodically. It's not quite fast enough to enable
exact motion, though :/
Allow individually enabling/disabling stroking during motion and
periodically, and allow controlling the rate of the periodical
stroke.
because the scale is useless otherwise with its range of 2..10000,
and because I needed a test case for the next commit (the
gimp_scale_entry_set_logarithmic() API was unused).
When using the MOVE behavior, don't append the current cursor
position to the stroke path in the timeout proc if the cursor
hasn't moved since last time. It has no effect, except for
requiring an unnecessary update.
When undoing a warp stroke, don't disconnect the current warp node
from its predecessor; rather, keep the graph as-is, and only
reconnect the render_node to the previous node. This avoids
invalidating the undone node, so that redoing it (which, likewise,
only involves reconnecting the render_node) doesn't require
reprocessing, making it much faster.
The spacing parameter controls the stroke spacing of the warp op.
It's similar, but not identical, to the brush spacing parameter of
the paint tools. It provides a tradeoff between speed and quality.
Change the UI range of the hardness parameter from [0, 1] to [0, 100],
to match the other parameters.
"layers-text-tool" action shows as "Text Tool" while "vectors-path-tool"
shows as "Path Tool". That's very confusing with tools-text and
tools-vectors respectively.
These actions are mostly about entering in edit mode with the active
layer or path. For text layers, it will enter text edition on canvas,
whereas just open the attributes edition dialog on other layers. For
consistency, layers-text-edit is renamed as well too layers-edit-text.
This also fix the side effect of commits 10099bd and 526918b where I
didn't realize that layers-text-tool was also working on non text layers
on purpose (being very badly named). Now there is a separate layers-edit
and layers-edit-text.
Thanks to Pat David for English corrections. :-)
Limit the number of lines drawn in the transform tool canvas grid to
one line every 5 image pixels. This should probably be done in display
pixels, didn't change that yet.
When transform tools are applied on a path, set their bounding box as follow:
- if a selection exists, use the selection bounds
- else if the path has a valid bounding box, use it
- else use the image canvas bounds
Also disable transform tools on an empty path (path without strokes) since
there is no data to transform.
Add support for The following GEGL op property keys, which shall
contain GUM expressions of the specified type, controlling the
corresponding UI attributes of the property's widget:
- sensitive [boolean]: controls widget sensitivity.
- visible [boolean]: controls widget visibility.
- label [string]: controls widget label (or the label of the
associated label widget).
- description [string]: controls widget tooltip text.
When any of above keys are present, the values they evaluate to take
precedence over the static values the corresponding attributes would
otherwise have.
GUM is a small DSL, used in some property keys of GEGL operations
to dynamically control UI attributes based on context. This commit
only adds an interpreter for the language; see the next commit for
the actual handling of the relevant keys.
See the comment at the top of gimppropgui-eval.c for a description
of the language.
Note that the interpreter is licensed under the LGPL.
If focus is on the layer list for instance, running this action from
right-click menu raises the on-canvas toolbar, ready for edition, with a
visible text cursor. But if the canvas has no focus (since you clicked
on the layer list, it has the focus), you still have to move your mouse
over and click the text on canvas. That doesn't make sense and there
would be barely any reason to use this over selecting the text tool then
clicking the canvas.
... non-text layers.
Since commit 10099bd, the action will be non-sensitive with non-text
layers, so if it happens, there is a bug somewhere. Therefore
g_return_if_fail() on this condition.
Moreover opening the edit attributes dialog was absolutely confusing on
what this action is supposed to do. We should not have these kind of
random behaviors.
When a layer is removed from a layer stack, and its backdrop needs
invalidating, emit the UPDATE signals for the backdrop only after
the layer has been removed from the container.
A subclass of GimpDrawableStack, for layer stacks. Invalidates the
layers' backdrop as/when necessary, according to the value of their
excludes_backdrop property.
Make gimp_drawable_stack_update() protected, instead of private, so
that we can use it in GimpLayerStack.
A boolean flag, specifying whether the backdrop is clipped to the
layer. That's the case when the layer's composite mode is dst-atop
or src-in.
This is a read-only property, derived from the other attributes of
the layer. We compute its value through a virtual function, so that
GimpGroupLayer will eventually be able to specialize it for pass-
through groups.
The next commit uses this property to actually do something useful.
Takes a layer mode and a composite mode, and returns the region
included in the composition.
Use this function in GimpOperationLayerMode, instead of testing
for specific composite modes directly. Will also be used by
the next commit.
Indentation cleanup in gimp_layer_modes.h
... so that we can use it for other functions that involve
compositing regions (which we do in the next commit).
Rename gimp_operation_layer_mode_get_affect_mask() and
friends to _get_affected_region().
With bigger and denser default images, the older 18px font default is
very small (~ 4pt font at 300PPI).
I decided to settle for a 15pt font, i.e. 62 px at 300 PPI, which seems
like quite an acceptable relative size for our FullHD defaults.
It is bigger than a default font size for —say— a text processor, but
GIMP is not really designed to process large walls of small text anyway.
Rather shorter texts at bigger sizes (i.e. designs, etc.). So this seems
like quite an ok default.
Note that as any defaults, this only goes as far and won't be what most
people need most of the time anyway. But at least we should get rid of
this ridiculous 18px default.
... tool when font unit is not pixel.
The default size is 18px. If for instance one is on a 300 PPI image, and
set the unit to mm, hitting "Reset to default values" sets to 213 px
(which corresponds to 18mm at 300PPI). I'm not 100% sure of the source
of the problem, but resetting the font size before the unit fixes it and
properly sets back to 18px. Let's go the lazy way and just do this.
Add the additional enum values to enum GimpSelectCriterion, and
the few needed lines to gimppickable-contiguous-region.c.
It's horribly slow, but works.
We check them into git, so this makes it easier to keep them in
sync when using a separate build directory.
Case in point -- this commit also syncs a few enum files that went
out-of-sync with their headers.
gimp_unit_get_digits() won't return relevant information when using
higher resolution. gimp_unit_get_scaled_digits() will provide the right
amount of details relatively to the actual print resolution of the
active image.
Add "import-raw-plug-in" to gimprc, and a new procedure
gimp_register_file_handler_raw(). On startup, remove all load
procedures that are marked as "handles raw" but are not implemented by
the configured plug-in. Add the list of available plug-ins to prefs ->
import/export. Register all file-darktable procedures as handling raw.
... brush features.
My previous commit only fixed aspect ratio reset, but I realize that
much more brush options are affected by defaults of generated brushes
(size, hardness, aspect ratio, angle and spacing). Let's reset all these
after the basic property reset.
Generated brushes can have specific aspect ratio, hence resetting to
fixed property defaults may be wrong. Therefore GimpPaintOptions needs
to redefine the reset() method from GimpConfigInterface.
Note: the specific "Reset aspect ratio to brush's native aspect ratio"
button was alright. But the broader "Reset to default values" was not.
Determines if the tool can pick at a given coordinate, without
actually picking. The default implementation uses
gimp_image_coords_in_active_pickable(); GimpFilterTool overrides
this function, to return TRUE whenever the active picker has
pick_abyss == TRUE.
Use this function when updating the cursor, and when determining
whether to draw the sample-average region indicator.
Add a boolean 'pick_abyss' parameter to GimpCreatePickerFunc. When
this parameter is TRUE, the picker should pick outside the bounds
of the drawable. Use FALSE for color pickers, and TRUE for position
pickers.
and use them for the new image in "Paste as new image". We were using
the resolution and unit of the image the paste command was invoked
from, which is entirely random and useless.
Change wording in Advanced Color Options drop-down menu to not imply
that GIMP isn't color-managed.
Slightly changed wording from Elle's original patch (mitch).
Also set the combo box' "ellipsize" property to END because it's too
wide. As mentioned before, this doesn't work for whatever reason,
hints are appreciated :)
when a click is detected by gimp_tool_check_click_distance(), only do
a motion() back to the button_press() coordinates if there has been a
motion at all since button_press(). This should not change any tool's
behavior, it's only an optimization to keep tools from doing useless
work.
The halftones transfer mode of dodge/burn uses pow(), which produces
NaN for negative input values. This tool doesn't really have OOG
values in mind, but using an odd power function fixes this issue,
and is in line with the behavior of the other modes w.r.t. OOG
values.
Spotted by José Americo Gobbo: when using a pattern source
for the clone tool, the top left corner was picked
as starting control point, which made the "fixed" aligment
rather useless. Using the pattern center allows the
better control of a pattern source.
Add a "mask-only" property to GimpBrushClipboard. When TRUE, only
create a brush mask (not a pixmap brush with mask and image).
Keep two clipboard brushes around: one classic "Clipboard Image" one
to be used as "stamp", and one new "Clipboard Mask" one that turns the
clipboard into a brush mask.
Fix the edit-paste and edit-paste-as-new-image PDB wrappers to use
gimp_get_clipboard_object(), not just clipboard_buffer(), and deal
correctly with entire images in the clipboard.
Fix brush shrinking used to compensate for the blur: avoid over-
shrinking the brush and changing its aspect ratio.
Change the way hardness maps to blur radius: hardness == 0 maps to
the largest radius such that, when the kernel is applied to the
middle pixel of the brush, the kernel is completely within the brush
bounds, taking brush shrinking into account, *assuming the brush is
a circle*.
Use the dimensions of the unrotated brush when calculating the blur
radius, so that rotation doesn't affect the blur amount (the blur
itself is not isotropic, though, and is applied after rotation, so
while the blur amount remains uniform, its effect does depend on the
brush angle.)
Get rid of the blur-radius upper limit -- it's fast enough to handle
large radii now.
A few additional minor speedups.
Also, make sure we don't overflow for large blur radii. Not a
problem yet, since the blur radius is capped, but soon...
Add a specialized convolution algorithm for the hardness blur. It
uses the same kernel as before, but performs the convolution in
(amortized) O(1)-per-pixel time, instead of O(n^2), where n is the
size of the kernel (or the blur radius).
Note that the new code performs the convolution in the input color
space, instead of always using a linear space. Since our brush
pixmaps (but the not masks) are currently perceptual, the result is
a bit different.
Add a debug procedure group, living in 'debug.pdb', which would host
useful debug helper functions. Functions in this group are not part
of the stable API, and may be changed at any point.
All procedures added to 'debug.pdb' should have a 'debug_' prefix,
and use the new std_pdb_debug() macro, which adds the proper "here be
dragons" warning to their description.
Add two debug procedures: gimp-debug-timer-start() and
gimp-debug-timer-end(), which measure elapsed time, a la
GIMP_TIMER_{START,END}, and can be used to profile script-fu
commands.
If the transformed item is a layer, and we are transforming the entire
layer (if there is now selection), hide the original layer during the
interactive transform. Based on a 2.8 patch from saulgoode.
Commit 9d4084c82f skips conversion and
blending of (some) transparent source and destination pixels. When
`blend_out == blend_layer`, it banks on the fact that the alpha values
of `blend_out` would be the same as those of `blend_layer`, and hence
the same as those of `layer`; thing is, we only copy those values from
`layer` to `blend_layer` for the pixels that we *don't* skip, so this
assumption is just wrong :P This leaves us with bogus alpha values in
`blend_out` for the skipped pixels, when the above equality holds.
For composite modes that use the alpha values of `blend_op` (aka `comp`)
even for transparent input pixels (i.e., src-atop and src-in), this may
result in artifacts.
Fix this by simply initializing the alpha values of `blend_out` for
skipped pixels unconditionally.
The expression `src_offset_x - coords->x + origin->x` is parsed as
`(src_offset_x - coords->x) + origin->x`; since floating point
arithmetic is not generally associative, even when
`coords->x == origin->x` (in particular, when there is no active
symmetry), it may still yield a different result than plain
`src_offset_x` if there's not enough precision for the intermediary
result (which is usually the case when `{origin,coords}->x` is
noninteger.) Since `src_offset_x` is an integer, and since the result
of this expression is rounded to an integer, if the error happens to
be in the direction of the rounding, it's magnified to a whole pixel,
which causes visible "jitter". (Ditto for `src_offset_y` and co.)
Regardless of this issue, we want to individually round `origin->[xy]`
and `coord->[xy]` down before taking their difference, since the
original offset is calculated according to rounded-down coordinates.
This solves the original issue along the way.
We don't support subpixel source sampling, so there's no use in
pretending that we do. Demoting everything to int as soon as
possible helps guarantee that these values are at least rounded
properly and in fewer places.
Make sure we always round coordinates down, and not toward zero.
Keep using floats only in the signatures of the relevant PDB
functions.
Copy TransInfo arrays around using memcpy(), use memcmp() to
compare them, add a function to allocate one. Clean up some
logic in gimp_transform_tool_check_active_item().
and a GimpSettingsBox. This brings savable settings to all ops, also
the automatic ones in the GEGL tool. It also makes the code cleaner
and more general.
... have been saved.
No need to keep a list of 0 images when the creator requested a quit or
close-all actions and manually went through the list to save all
remaining images. Yet one can still cancel the quit/close-all action by
hitting Esc (or Cancel button) during the last save, since it is an
idle source action.
GimpFilterTool::get_settings_ui() is no longer needed, replace
it by a simple utility function in gimpfiltertool-settings.c.
Also, use the GimpFilterOptions functions added earlier, and some
random cleanup.
and add them as return values to GimpFilterToool::get_operation(), so
the tools is configured entirely per-instance now.
This makes get_operations()'s signature more evil, but helps making
GimpOperationTool less conplicated and convoluted.
We were still saving channel colors in 8 bit, this additionally
saves/loads the color as float values. Still save the old PROP_COLOR
for compatibility.
from gimpdir/tool-options/ to gimpdir/filters/, and only if moving
fails try reading from the old location as fallback. We don't normally
move files around, but this one-liner nicely avoids cluttering
gimpdir.
Filters settings used to be serialized and deserialized only
when a filter tool's GUI was shown, too late for the code that
re-runs/re-shows filters with previous values.
Move the entire loading/saving code to gimp-operation-config.c, even
adding/removing the dummy separator item between timestamped automatic
history and manually saved settings. Load the settings automatically
when a settings container is requested, but still trigger saving from
the few places the container is changed in the GUI; could also
automate that later.
This commit also moves all settings of filters that have their own
tools from gimpdir/tool-options/ to gimpdir/filters/. Add compat code
to try the old filename if the new doesn't exist, so files are
migrated automatically.
WIP, but this step already fixes the bug.
Both in the GimpImage API and in the GUI. The toggle in the save
dialog now controls ZLIB compression directly. Changed the various
info labels accordingly. Ditch the XCF parasite that saved the XCF
compat mode.
Commit 4beff2f was basing it on the screen y PPI but that is not really
consistent or logical actually. Since the actual stroke dialog uses the
y resolution of the current image, it makes sense that the generic
stroke defaults in the preferences should use the y resolution of the
default image.
Enable 64 bit file offsets in XCF files, starting with newly added XCF
version 11.
We use at least version 11 if:
- we would use the previous version 10 (essentially skipping 10)
- the in-memory size of the image is larger than 4 Gig
Change the xcf_read_foo() functions to take the XcfInfo* instead of
a GInputStream*, and make them advance the info->cp offset by
themselves. Makes xcf-load.c a lot more readable.
Step one, without changing anything in the saved XCFs yet:
Abstract reading and writing of file offsets away into their own
xcf_read_offset() and xcf_write_offset() functions, which take
"goffset" instead of "guint32". Also change xcf_seek_pos() to take a
goffset argument.
Change all file offset variables in xcf-load.c, xcf-write.c and struct
XcfInfo to goffset, and add new member "bytes_per_offset" to XcfInfo,
which is currently always 4.
This value could be based on either the x or y resolution, or maybe some
kind of mean values. It could also be based off the print resolution of
any image (if the user sets a physical dimension, the actual pixel width
will vary depending on the print resolution). There is no actual "good"
answer here. But any of these values will be better than a default 96.0.
The abbreviated commit hash we show in the shell and the about
dialog is currently just the last 7 characters of 'git describe',
based on the assumption that abbreviated hashes are always 7-digits
long. When the hash is longer than that, we're just showing a
nonsense commit.
This was never a good idea, since users can override this, and
since disambiguation can result in longer hashes, but since git
2.11, the default abbreviated hash length is determined based on
the size of the repository, which currently results in 10 digits
for us.
Let's just do it right.
It is a little fuzzy whether expected or not, architecturally-wise. On
one hand, I can see some core/ header includes under config/. Though on
the other hand, app/Makefile.am explicitly sorts config/ below core/.
Anyway let's just use g_cclosure_marshal_VOID__VOID which is the same as
gimp_marshal_VOID__VOID and get rid of the include.
This fixes builds from scratch.
It was agreed that we should write "plug-in" consistently. Only possibly
user-visible strings were updated.
Thanks to scootergrisen for a first patch which could not make it
after changing decision on the canonical writing.
Current code only guess resolution for a single monitor. Ideally
the widget sizes could be different depending on the window where a
given widget is on. But that's a start.
In particular all rotate/flip actions can apply to an image or drawable.
Let's make it clear, especially when it is run out of the menu context,
for instance in the action search.
which unlike HSL Lightness is actually physically meaningful and
also generally speaking much more useful than HSL Lightness.
Change "Lightness" to "Lightness (HSL)" to make it clear that
the "Lightness" in the Colors/Desaturate/Desaturate menu is not the
same as "Lightness" in LAB/LCH.
For completeness add the option to desaturate to "Value (HSV)".
Add links in app/operations/gimpoperationdesaturate.c
to the Wikipedia article with definitions of L/I/V in HSL/HSI/HSV.
Use gimp_item_translate() instead of gimp_item_set_offset() to set
a pasted item's position, so that the offsets of pasted layer group
children are updated correctly. Otherwise, only the group itself
moves, while its children remain positioned relative to the top-left
corner of the image.
... since that's the color space it actually works in.
Keep the legacy "Color (HSV)" mode's name as is, wrong as it is,
since, well, that's what it used to be called...
No need to do full back and forth RGB/HSV conversions.
Change the behavior such that fully desaturated values remain
desaturated, instead of saturating towards red.
Pixels whose source or destination alpha is zero are not blended, and
therefore do not need to be converted between the composite and blend
spaces (assuming a conversion is necessary to begin with.) When there
is a large enough segment of consecutive pixels that don't need
blending, split the conversion/blending process around it, so that
we don't convert too many unblended pixels unnecessarily.
For layers with lots of transparency, this can dramatically reduce
compositing time; for layers with no transparency, the added
overhead is rather negligible.
When adding an item to a filter stack that doesn't have a graph yet,
calling gimp_filter_stack_update_last_node() may ultimately lead to
the invocation of gimp_filter_stack_get_graph(), which would create
a new graph, and add the item's node to it; gimp_filter_stack_add()
would then erroneously attempt to re-add the node to the graph.
Fix this by calling gimp_filter_stack_update_last_node() after
(potentially) adding the node to the graph in
gimp_filter_stack_add().
The function has been unused since commit b5cc2a9.
Its work is now divided into gimp_tool_palette_set_toolbox() and
gimp_tool_palette_hierarchy_changed().
Argh! Always triple-check commits before pushing!
Commit e30c92c had completely wrong big values, which I was using
to make tab border update really visible while testing.
Allow overriding icon sizes set in themes from the preferences.
This initial commit updates only toolbox icons. More to come.
4 options are available: small, medium, large and huge (the later would
likely be useful for HiDPI screens).
Uses a new widget GimpIconSizeScale.
Merge mode lays the source layer on top of the destination, same as
normal mode, however, it assumes the source and destination are two
parts of an original whole, and are therefore mutually exclusive.
This is useful for blending cut & pasted content without artifacts,
or for replacing erased content in general.
Calculates the dot product of the two input colors, and uses that
as the value for all the output color's components. Basically,
a per-pixel mono mixer.
Useful for custom desaturation, component extraction, and crazier
stuff (bump mapping!)
Include erase mode in the menu for layers and general paint tools.
This makes the eraser tool somewhat unnecessary, but allows for
interesting use cases (e.g., airbrush eraser, etc.)
... possibly due to small win32 stack
Limit the number of samples processed in one go by gimp_composite_blend()
so that we don't overflow the stack when we alloca() buffers on it.
... and get rid of the dedicated op. This gives us support for all
the blend/composite options for this mode.
Rename COLOR_ERASE to COLOR_ERASE_LEGACY, with perceptual blending/
compositing and immutable everything, and add a new COLOR_ERASE
mode, defaulting to linear blending/compositing, with mutable
everything. Modify affected code.
These are more general, and more expensive, versions of the non-
subtractive compositing functions. They are used with modes that
specify the SUBTRACTIVE flag. This doesn't affect anything yet, but
the next commit ports color-erase mode to a blendfun.
Most modes only modify the *color* of overlapping dest/src regions,
however, erase and color-erase may also reduce their *alpha*, i.e.,
eliminate some of the overlapping content. Flag these modes with
the new SUBTRACTIVE flag, as they require more general compositing
code. The next commit adds the said code.
The mode group switching combo box is hard to discover, until we use the
default group instead of legacy group as default - it is better to make legacy
resemble the full old set to.
Try to sort all GIMP_ICON_* defines into FDO categories like in
https://specifications.freedesktop.org/icon-naming-spec/latest/ar01s04.html
Add defines for all icons we override, rename some icons to their FDO
standard names, and mark the ones we duplicate with a comment so we
don't forget to rename those to standard names in 3.0.
In DEs which use a global menu, such as Unity, updating the menu
can be expensive. This particularly affects canvas scaling and
rotation, for which updating the menu synchronously causes notable
lag.
Remove all stock items added since 2.8, restore accidentially removed
ones, and rename the newly added GIMP_STOCK_* defines to GIMP_ICON_*.
(will move to having GIMP_ICON_* defines instead of magic hardcoded
strings for all icons).
being exported to libgimp, and having a non-exported value, this is a
horrible mess like with GimpLayerMode, but at least the cruft value
names are deprecated now.
Need to provide the pixels in a format that matches the profile,
simply using "RGBA float" here was a brain bug of mine. Two profiles
and two formats are parameters the used GimpProfileTransform needs to
work correctly.
.. due to gdk_pixbuf_scale() with themes using the pixbuf engine
Make GimpDisplayShell a subclass of GtkEventBox, so that it gets its
own window, isolating its events from those of its ancestors.
In particular, the "expose" event handler of GtkNotebook, which the
shell is a child of in SWM, is particularly slow with themes that
use the pixbuf engine. If the notebook and the shell use the same
window, this can cause notable, and somtimes severe, lag when the
rulers or scrollbars are updated frequently, such as when rapidly
moving the cursor.
which got renamed from create_map() in this commit too. "Completely"
means including insane options like color_managed and gamma_hack, they
are confusing enough so they should at least work correctly.
Need to convert both from the drawable's profile to the filter's input
format and from the filter's output format back to the drawable's
profile. This change fixes things for the case where the filter's
input and output formats are different.
which returns an array of modes in the order they would appear in a
GimpLayerModeContext's UI (like tool options or the layers dialog),
without the separators.
Use it in context-commands.c and layers-commands.c instead of static
(and outdated) arrays for the actions that cycle through modes.
In particular, this enables grids whose points of intersection
are at the middle of the image's pixels, which is useful for
undistorted painting with odd-sized brushes using tools other than
the pencil.
This commit also changes the grid visibility behavior, so that the
the visibiltiy of horizontal and vertical grid lines (depending on
the zoom level) is independent.
Instead, add a gimp_layer_mode_get_format() function, which takes
the layer mode, composite space, and blend space, and returns the
I/O format.
Currently, we always use the composite space format as the I/O
format. This simplifies gimp_composite_blend(), and gives us
composite-space support for the "special" layer mode ops for free.
Replace the 'with-behind' and 'with-replace' properties with a
single 'context' property, and use it to select the included
layer modes, according to their context mask.
Add a dummy GIMP_LAYER_MODE_SEPARATOR value to the GimpLayerMode
enum, and use it to explicitly mark the menu separators in the
layer-mode group arrays; add separators to the layer-mode menu
accordingly.
Update the rest of the code to use 'context' instead of 'with-behind'
and 'with-replace'. In particular, in the layers and layer options
dialogs, select the right context based on whether or not the
selected layer is a group.
A bitmask, specifying in which contexts a layer mode is applicable.
Can be a combination of:
- LAYER: usable as a layer mode for actual layers.
- GROUP: usable as a layer mode for layer groups. Currently, all
modes that specify LAYER also specify GROUP, and vice versa,
but the planned pass-through mode will be GROUP only.
- PAINT: can be used as a paint mode.
- FADE: can be used for fading.
Add a 'context' field to _GimpLayerModeInfo, and provide context
masks to all the modes.
Use the context mask for validation when setting a layer's mode.
The next commit will use the mask when populating the layer mode
menus.
Add a "paint_composite_mode" field to GimpLayerModeInfo and set the
mode of the eraser to SRC_ATOP. Defaulting to SRC_OVER for all
painting didn't quite do it for all modes.
set all legacy modes to completely immutable and the LAB modes'
blend mode to immutable. Change GimpLayer setters and the UI
accordingly. Remove the LAB color spaces from the GUI, they can
only be used with the LAB blend modes anyway and not changed.
Nobody has them anymore, and they are deprecated in GTK+ 3.x. This
also fixes all conflicting mnemonics except those I missed, but we can
fix them now.
Fix cage transform to refuse to work on locked, invisible and group
layers. Add GimpTool::initialize() implementation so the generic
"drawable has changed" mechanism triggers the right response.
They can be affected by the same problem described in
commit 4c3a772cd8, although in the
case of SRC_ATOP, the affected pixels are always fully transparent.
When the source alpha is zero, we don't calculate the blended color,
so `comp[b]` can be infinite or NaN, in which case the expression
`in[ALPHA] * (comp[b] - layer[b])` is NaN, rather than the expected
value of zero.
and to operations/layer-modes/, respectively.
Add gimp_layer_modes_init() which asserts on the correct order of the
GimpLayerModeInfo array, and switch to accessing the array directly in
gimp_layer_mode_info().
Similar to the Photoshop mode of the same name. Assigns
either 0 or 1 to each of the channels, depending on whether the
sum of source and destination channel values is less than, or
greater than (or equals to), one, respectively.
This is equivalent to inverting the source, and using it to perform
per-pixel, per-channel threshold against the destination, which is
useful for various effects.
Stuff like passing "input" directly if "aux"'s opacity is 0, etc.
Used to be partly handled by normal mode, even though it applies
to other modes too.
Adjust the logic for the new compositing modes.
Add a GimpLayerModeAffectMask enum, and a corresponding
get_affect_mask() function to GimpOperationLayerMode, which
specifies which of the op's inputs, if any, are affected by the
mode, apart from the overlapping regions. Most modes affect only
the overlapping regions, but dissolve and replace also affect the
rest of the input. This information is used for determining if
the optimizations are applicable.
Some of the generic files still contain SSE2 code, in particular
gimpoperationlayermode.c. The reason why it often works without is that
native gcc will usually pre-define SSE macros by default.
To check this: gcc -dM -E - < /dev/null | grep SSE
Yet I had a case on a small netbook where the SSE macros were not
pre-defined even though supported. Consequently the build failed.
Largely based on a patch by Ell, with the enum type renamed and
various small changes. Adds another axis of configurability to the
existing layer mode madness, and is WIP too.
The colon-separated list used in the plugin originally comes from
gimp_help_get_locales() anyway. My previous code was using different
lists of locales in different places, which was inconsistent.
I know this looks absolutely horrible, please spare me comments about
that. This commit has the purpose to let everybody experiment with the
new modes, and suggest improvements of the GimpLayerModeBox widget; we
need *some* way of controlling the new layer mode madness.
These variations on darken only and lighten only have the advantage over the
componentvise versions that they always use the full triplet of either original
or new layer - meaning no new colors/hues will be introduced. This is similar
to how these modes operated/operates in picture publisher and photo-paint.
- set the filter_tool->drawable before showing the tool gui.
- set the sensitivity functions for channel combobox of threshold,
levels and curves tools dialogs only once during dialog creations.
- use the filter_tool->drawable inside the sensitivity functions
C++ won't allow us to use GimpLayerMode in the API where we used to
have GimpLayerModeEffects.
Move GimpLayerModeEffects to libgimpbase/gimpcompatenums.h so it's
not in the API any longer, and instead typedef and define stuff in
libgimp/gimptypes.h, and adapt the compat enum registering code
accordingly.
The porting from 8bit per component scaled some 8bit fractions up to huge
floating point numbers, this works for most values but causes trouble for near
transparent pixel values. This commit copies the inner blend loop from the new
divide layer mode, but keeps the old compositing logic.
... is fully transparent, instead of just src.
The blend func results only affect the intersection of dest and src.
Run time is currently dominated by the compositing step for most modes,
so the difference in performance is pretty negligible, but it does make
a difference for the more expensive modes, like the HSV ones.
The print size displayed in image property and title format should use
gimp_unit_get_scaled_digits() instead of gimp_unit_get_digits() and
adding 1, which is quite random or magic number-y.
For operations needing to override default behavior sub-classes should still be
used.
This commit also enables pinligh, vividlight and linearlight blend mode modes
We can't just switch to a GimpOperationTool by using the normal
gimp_context_set_tool() or gimp_context_tool_changed() because it
needs additional initialization like setting an operation at all.
In gimp_gegl_procedure_execute_async(), g_object_set_data() the used
procedure on the newly created tool.
In gimp_display_shell_initialize_tool(), when we re-create the active
tool because of a drawable change, check for the procedure and invoke
it again, instead of simply creating an empty operation tool by
calling gimp_context_tool_changed().
Optionally convert all imported (not XCFs) images to 32 bit linear
floating point, and optionally add a little noise in order to
distribute the colors minimally. The new options are on a new "Image
Import & Export" prefs page that needs a new icon. Original dithering
patch by pippin.
Since CIE Lab is one of the supported color spaces for doing the blending -
this enum is not only about transfer functions/curves or gamma. This finishes
already started cleanups.
... in status bar.
Follow-up of commits f836892 and d1c3c3d. With high resolutions, the
distance displayed in the status bar when shift-clicking in a paint tool
may lack digit precision and show the same value (in non-pixel unit) for
several consecutive pixels. Compute a more accurate precision than what
gimp_unit_get_digits() can provide in such cases.
When working with high resolution, you may have cases where measured
length won't be displayed with enough digits; i.e. several pixels length
would show up as 0. For instance at 4000 PPI, up to 7 pixels show up as
0 mm, then at 0.1 mm from the 8th pixel (actually reaching over 0.05 mm,
approximating as 0.1), then 0.2 at 24 pixels (actually: 0.152), and so
on. At such a resolution, 3 digits are needed for 'mm' instead of the
1 digit returned by gimp_unit_get_digits() so that we display reliable
lengths.
Therefore we need to compute ideal digit precision. Configured digits
for a given unit will now be used as a minimum value, but actually used
digits may be higher.
Compute the ideal decimal precision for cursor position and length
status so that you get the best precision on physical units depending
on the current resolution, yet avoiding over-precision (which can be
misleading). The unit's "digits" value is now used as a minimum
precision only.
It is used both for blending and compositing, the repeated use of the word
BLEND in code made the logic involving both blending and compositing hard to
read.
Note that in some cases the alloca may be unnecessary, but this keeps
the code clean, and we have to be able to *potentially* do the alloca
anyway, so what the hell.
Implement a common utility function gimp_blend_composite that uses utility
functions for implementing layer modes, with separate (possibly SIMD) optimized
loops for blending and compositing, with configured linear TRC, perceptual
gamma TRC or even using CIE Lab as the space.
from gimp_applicator_new() and gimp_gegl_mode_node_set_mode().
Compositing doesn't depend on the layer format any longer, only on the
layer mode. Painting with "use applicator" unchecked is still broken
in some cases and needs more fixing.
like all other function typedefs and add GimpBlendFunc typedef which
will be needed soon. Also rename get_layer_mode_function() to
gimp_get_layer_mode_function().
...layer group cause a bug in the existing layer size
Change gimp_group_layer_get_size() to return FALSE if there are no
children (there is no content).
In gimp_group_layer_update_size(), skip children where get_size()
returns FALSE. Fixes bogus size calculation.
Temporarily slower - but permits paint modes like overlay/softlight to work at
all for linear TRC pixel encodings. Should be reverted when the non-graph
approach works properly again.
with proper value names. Mark most values as _BROKEN because they use
weird alpha compositing that has to die. Move GimpLayerModeEffects to
libgimpbase, deprecate it, and set it as compat enum for GimpLayerMode.
Add the GimpLayerModeEffects values as compat constants to script-fu
and pygimp.
Make overlay, Lch color, Lch hue, Lch saturation and Lch lightness mode handle
alpha more like how normal does it. This is a change that we ideally might want
applied to other layer modes as well to get rid of MIN() calls.
when parsing of an object property fails, we need to set *expected to
G_TOKEN_NONE to tell the config parser that something has gone wrong,
or it will continue parsing and run into trouble with the inconsistent
state (it will try to set an error over the already set error, causing
a warning).
The "accumulated" (color value) adjective does not look like the best
word in both descriptions. Respectively, the first is an averaged
value whereas the second would be a "merged" or "composited" value.
If native speakers have comments or better propositions, they are
welcome to speak up.
...regardless of image color precision
Split enum value GIMP_COLOR_FRAME_MODE_RGB into RGB_PERCENT and RGB_U8,
which display the current % values, and values in a range of 0..255.
Move the entire drawing control logic to gimp_color_tool_oper_update()
which gets invoked on hovering, and don't mess with it in
button_press() and button_release(). Tested to work with the color
picker, paint and filter tools.
Disable the new "automatic window tabbing" feature introduced on macOS
Sierra. It breaks GTK+ applications and we would need proper support for
this in GTK+ if we want to use it.
Change GimpHistogram to take a "gboolean linear" parameter and always
honor that parameter, so both kinds of histograms can now be created
for all drawables.
Add a horrible "Linear" toggle to the histogram dockable which always
defaults to the active layer's actual pixel format, but can be
switched at any time. This UI is ugly and needs to change.
On the PDB, default to gamma-corrected if the plug-in is unaware of
higher precision, and to the drawable's native pixel format otherwise.
Other places using histograms (e.g. levels, curves) are unchanged.
Set gimp_tool_control_set_preserve() to TRUE and set an appropriate
dirty_mask, just like all tools which have a permanent on-canvas state
outside of a simple press-drag-release.
The white, gray and dark sliders of GimpHandleBar have a black contour.
This makes the white and gray slider visible even with similar colored
background. On the other hand, the black slider is barely visible on a
dark background (and could even be made totally invisible using the same
color). So let's use a light-gray contour on the dark slider, making now
all sliders working with any background color.
gimp_dialog_config_fill,stroke_options_notify(): ignore notifications
on the fill and stroke option's parent class properties, they are not
serialized and completely irrelevent here.
This reverts commit eab4929a78.
Oups it would seem gtk_accel_map_change_entry() could return FALSE even
when the expected shortcut is correctly set (my guess is that it was
already the same shortcut, so indeed no "change" happened, though it is
not a failure either; yet I haven't checked if that is the actual
reason).
Let's just revert this. It's not always a good thing to be too thorough!
Sorry for this!
These are used for display switching, and even though you could
remap these shortcuts, it would work only until you close an image,
open a new one, or reorder tabs in SWM, in which case your shortcut
would end up forcefully overrided, which is a bad user experience.
If we want to give more flexibility and allow one to map these
shortcuts, we must also make sure the display showing actions won't
override customized shortcuts. In the meantime, it is better to
simply forbid these in our preferences.
... for "windows-display-*" actions.
I should not happen, but let's be thorough and properly handle failure
with a message since this is a runtime issue.
gtk_action_group_remove_action() removes the action from the group while
not actually cleaning any accelerator. This is a problem for transient
actions which have only a meaning within the current session, such as
the display switching actions named with the display ID (unique within
the session only).
Current commit, combined with the previous one (commit c0ee959), fix
"windows-display-*" actions being saved inside menurc.
Some actions are not meant to be saved, in particular the
"windows-display-*" which have only a meaning during a same session
since display IDs are session-dependent. So let display deletion
happen first so that proper cleaning of action is done when writing
menurc.
Revert "app: action search should search accross all available actions."
This reverts commit 53b3673bd8.
Had to revert these two commits, quoting comment 6 of the bug:
Thinking again, that entire change is unfortunately wrong, the only
right UI manager is in fact
gimp_ui_managers_from_name ("<Image>")->data
because it's the global popup <Image> UI manager which is independent
of a display and it always in the right state for the currently
active image, all other UI managers are wrong.
Current defaults are from another time. Acceptable defaults could be
common screen resolutions. 1366x768 is apparently the most common
(according to various stats on the web), but since we target advanced
graphics artists, let's go for 1920x1080, which is the second most
common resolution, also known as Full HD.
For unstable builds, let's have at least one odd number, uncommon ratio
and higher values, encouraging tests with less common numbers and bigger
images. I chose 2001x1984. Feel free to update to any other funky values
following these "unstable" rules.
... with something more suitable.
72 PPI is from a time where people thought this was a common screen
resolution. This is not the case nowadays, and anyway images targetted
for screen display should not bother with PPI resolution at all, only
with actual pixel dimensions.
PPI resolution is more useful for printing. And for this case, 300 is
quite an accepted OK value for most cases. So this is likely a better
default for GIMP.
Add GimpMenuFactory can always be found in a GimpDialogManager, use
gimp_dialog_factory_get_menu_factory() where we have a dialog factory
instead of accessing "global_menu_factory" or redundantly passing a
menu factory around where we already pass around a dialog factory.
<Dockable> has this whole list of actions named similarly to dialogs-*
actions, and we don't want these to take precedence, especially since
they would always create a new dock instead of just showing the existing
one if already present.
Also fix the redundancy check on already added actions.
There is no reasons not to translate the "occurs" text which will be
in the color names in palettes extracted from images. It indicates on
how many pixels a given extracted color was occuring. We should also
translate the full string (not just "occurs") since some language will
have to reorder words, and may even use different bracket characters.
So I also add a translator comment to make sure the translators get
what the %s and %d stand for in this string.
Duplicate accelerators are not supposed to happen. It is not possible
to set them through the GUI in particular. Nevertheless
gtk_accel_map_load() would apparently let duplicates pass, which could
happen after editing the menurc directly, or using the development
version (no action name migration happens there), or simply after a
potential bug. This is then very annoying because you may see several
actions displaying the same shortcut but only one actually work. And
trying to re-set through GUI the shortcut to the one action you wish to
run does not fix the duplicate issue (you have to laboriously find which
other action use the same accelerator and delete it first).
Better be safe than sorry and make a quick check at startup, then delete
the accelerator on one of the duplicates (you can't guess which one was
actually wanted, but at least you will facilitate manual reset through
the GUI).
Redundant accelerators were:
- <Primary><Shift>y on dialogs-mypaint-brushes and edit-strong-redo.
Since the <Primary>z vs <Primary>y has quite a strong history for
undo/redo actions, and dialogs-mypaint-brushes is quite new, let's
unmap the latest.
- <shift>l on tools-seamless-clone and tools-unified-transform.
Since the Seamless clone tool is still in the playground and we
don't even know if it will make it out quite soon, let's give
priority to the Unified Transform tool.
Limit selection shrinking to MIN (sel_width, sel_height) / 2, larger
values make no sense.
Limit selection bordering to the same value and growing to
MAX (image_width, image_height).
Introduce virtual function GimpViewable::is_name_editable() and class
member "gboolean name_editable" for the default value. Default to
FALSE and only return TRUE if the name can actually be edited by the
user.
When attemting an edit, check the new API and beep instead of starting
the edit.
Don't rely on the exact modifier being pressed or released. Instead,
check if only the right modifier is pressed after *each* modifier
change, and switch to color picking if it is; disable color picking
otherwise. This greatly reduces the risk of missing the user's wish to
pick colors because of other modifiers being pressed and released in
whatever order.
Probably fixes bug #734743.
We handle multi-selection by letting GtkTreeView handle button press
when the widget is in GTK_SELECTION_MULTIPLE mode. Change that code to
only do that when one of the participating modifiers (shift and
control on Linux and Windows, shift and cmd on macOS) is pressed.
This makes sure that the same thing is not randomly handled by two
different pieces of code, and probably fixes bug #738440, tho I can't
be sure.
When calculating an overlap between two ranges, interpolate the hue
adjustment from config->hue[primary_range] and
config->hue[secondary_range] BEFORE mapping it to the input value.
This fixes odd edge cases where only one of the ranges crosses the
red/magenta wraparound, or if adjustments to different channels yield
more than 180 degree difference from each other.
In the "New Image" and "Convert Precision" dialogs. The "Gamma/Linear"
switches get adjusted automatically to the new defaults, but can be
changed manually.
Don't offer dithering options when converting to 16 bit, it doesn't
make much sense to dither for anything but 8 bit. Thanks to Elle for
testing that this assumption is indeed true.
Use a properly commented #define instead of just a hardcoded "8 bits"
to make clear that this is a pure GUI "restriction".
Disable the convert precision dialog's dithering controls when
converting to higher bit depths o to anything > 16 bit.
Make sure the disabled dithering widgets always says "None", which
implies duplicating the bit depth checking logic in both the dialog
and its callback, in order to protect the values in GimpDialogConfig
from being overwritten by NONE.
The new properties are "virtual", they share their storage with the
"precision" property and are not serialized, they are meant for GUI
property widgets.
...instead of transforming it
Add gimp_matrix3_will_explode() which determines if a transform
matrix will blow up something in a rectangle to infinity, and use
the function so set both the GIMP and GEGL code paths to clip the
transform to the input size.
This got lost when dropping the file-uri plug-in and switching to
interal download using GIO. The file-uri plug-in would just download
whatever remote thing and open it locally, using local magic matching.
We now do the same internally and try the magic matching again on the
downloaded file.
Don't migrate any paths from an older gimprc. This unfortunately kills
all manually added paths, but makes sure all paths default to the
files of the new GIMP version, could be improved by parsing the path
and replacing only the right elements.
Add color management to GimpDrawableFilter and GimpFilterTool, GEGL
ops applied to drawables can be applied in color managed space
now. Sadly, this is very slow, so disabled by default.
I'm sure the profile guessing based on the operation's format doesn't
always work, but this general bug counts as fixed now.
Fix cursor rotation jump when tablet pen is tilted horizontally.
This changes to the correct values for the special case of tilt_x == 0.0.
Reviewer (Jehan)'s note: computing the convergence of the tilt function
in the `else` block, when tilt_x approaches 0, tilt value indeed
converges to 0.25 with tilt_y > 0 and 0.75 (or -0.25 which is the same)
with tilt_y < 0.
Initialization was failing when a paint buffer could not be returned for
a stroke (which was bound to happen in tiling). Instead it must just
ignore the coordinates which won't result in painting, and continue to
the next ones.
gimp_drawable_equalize(): is mask_only is FALSE, suspend the selection
around gimp_drawable_apply_operation() so the operation affects the
entire drawable.
The code was still checking for "plug-in-recent-*". Also, rename the
actions to "filters-recent-*" instead of "filter-recent-*" for
consistency with the other filters actions.
so the threshold can now be based on the GimpHistogramChannel enum.
Add a channel menu to the threshold dialog and a channel argument to
the PDB procedure (which is new in 2.10).
If I hadn't forgotten what the "RGB" channel is supposed to do I would
have implemented the RGB mode in GimpOperationThreshold correctly.
Right now I'm just guessing. Anyone?
They used to be 0..255, inherited from the old gimp_histogram() and
gimp_threshold() procedures. This commit deprecates these old
procedures and changes the ranges in the new gimp_drawable_histogram()
and gimp_drawable_threshold() to double with a 0.0..1.0 range.
Add property "color-tag" of type enum GimpColorTag to GimpItem so all
layers, channels and paths can be tagged with a color.
For interoperability, use the color list from Krita which is a
superset of Photoshop's colors.
Features a "Color Tag" submenu in the layers, channels and paths
menus, a row of color radio buttons in the properties dialogs,
undo and PDB API.
As a side effect, some common code is now factores out into
items-actions.[ch] and items-commands.[ch] which adds visible, linked
and lock actions for layers and channels.
Introduce item-options-dialog.[ch] which abstracts this away and use
it from the layer, channel, vectors options dialogs. This is all
pretty ugly but better than duplicating that code three times. The
vector-options-dialog is now completely pointless but I kept it anyway
for now, let's see what unique path options we come up with.
Convert GimpRGB to CMYK using a color transform to the configured CMYK
profile instead of the naive gimp_rgb_to_cmyk().
Add gimp_color_frame_set_color_config() and call it on all color
frames in the GUI (color picker tool, cursor info, sample point view).
Keep a GimpColorTransform around that does the conversion.
Also color manages the frame's color area now (visible in the sample
point view), which was forgotten earlier. Addresses bug #467930.
Fix the check that keeps events on overlay widgets from entering the
tool event mechanism, they have no business there.
gimp_overlay_child_realize(): set the embedding widget's event mask on
all overlay children, so their windows will be used as event window,
so their events become distinguishable from events on the parent (the
canvas).
gimp_display_shell_canvas_tool_events(): fix the check for events on
overlays, and skip them for real this time.
Call gimp_context_tool_preset_changed() on the global user context,
not on the tool preset list's or tool preset editor's local
context. Fixes restoring of presets in MWM. Tracked down by Jose
Americo Gobbo.
Have "Save" and "Restore" buttons in both the tool preset list/grid
and the tool preset editor. The save button stores the active tool's
options in the preset, if possible.
This fixes restoring of brush properties (size, spacing angle etc.)
from presets, which was utterly broken before. The fix consists of
two parts:
- In tool_manager_preset_changed(), always copy the brush properties
again after setting the preview on the tool options, in order to
override brush properites that get copied from a linked brush when
that brush gets set on the tool options.
But no amount of copying stuff again and again would help without:
- In gimp_context_set_by_type(), don't use g_object_set() to set the
object (brush, pattern etc.). Instead, build a GValue and call
gimp_context_set_property(). This may seem odd, but avoids a
g_object_freeze_notify()/thaw_notify() around the g_object_set(),
which was causing "notify" to be emitted at the very end, after
everything this context change has triggered. GimpContext is an
essential core object and there is an expectation of a reasonable
order of signal emissions and callbacks being called. The "notify"
at the end was keeping any callbacks of the context's "foo-changed"
signals to override anything an earlier callback had done, if a
"notify" callback was overriding that overriding again.
This was probably the reason for a lot of odd behavior observed over
the years. In fact, I have been searching for this for at least 5
years.
...are not submitted to respective Tool Options sliders
Treat brush angle and aspect ratio like all other paint options values
that can be linked to brush defaults and take their default values
from the brush. They were special casing their defaults to constants,
and GimpBrushGenerated was adding the passed dynamic radius and aspect
values to its own. This was totally incomprehensible.
Now GimpBrushGenerated's transform_size() and transform_mask()
implementations just translate between these APIs value ranges and the
brush's own value range and only use the passed values (not the
brush's native values), which makes the editor <-> tool options
interaction and the painted brush shape predictable.
Also connect the active brush's property notifications to the paint
options properties, so the paint options follow a brush edit live if
the respective "linked" toggles are checked.
And some cleanup.
Add a GimpFillType argument to GimpItem::resize() and fill type
widgets to the canvas and layer resize dialogs. Fill the new parts of
the drawable according to fill type in gimp_drawable_resize(). Make
sure places that need the old behavior get GIMP_FILL_TRANSPARENT
passed by hardcoding it in the GimpItem::resize() implemetations of
channel, mask, selection etc.
We didn't convert patterns to the target drawable's profile when using
gimp_drawable_fill().
Introduce gimp_drawable_fill_buffer() as single filling utility
function that does things right and use it from gimp_drawable_fill()
and gimp_fill_options_create_buffer().
Use a GimpSpinScale in channel-options-dialog.c and clean up the
dialog layout. Affects the "Quick Mask Attributes", "New Channel" and
"Channel Attributes" dialogs.
Add new setting GimpGuiConfig:devices-share-tool. When TRUE, we never
copy any properties between the user context and the GimpDeviceInfo's
context, so no tool or anything changes.
We do however still keep track of the active device so the setting can
be enabled/disabled at any time. Also hide GimpDeviceStatus' tool,
brush etc. indicators in "shared" mode.
Otherwise the quit dialog is still in front yet it has no focus and
one doesn't see this immediately.
Hitting ctrl-d to exit and ignore any subsequent files for instance
duplicates the current active image instead.
making its external API "complete". Remove the redundant
"new_base_type" and "new_precision" from the internal (vfunc) API (the
Babl format has the same information).
Rename "dialog" variables to "private" like in the other recently
cleaned up dialogs. Use less complicated code when connecting to the
container of dirty images.
Otherwise keyboard interaction (like hitting Escape or ctrl-d) ends up
broken and you may not realize immediately the dialog lost focus since
it is still the top window.
"There is one image" should not necessarily be translated to '1' in
other languages. It depends if their singular applies only to 1, like
in English. For instance in French, it can also apply to 0, so I fixed
the French translation.
...when moving guides
Show relative coordinates when moving guides and sample points, the
cursor display in the statusbar already shows absolute coordinates.
Add GimpCellRendererButton and use it to add a "Save" icon to each row
of dirty images. Click invokes the "edit-save" action, shift-click
invokes "edit-save-as". Also add a tooltip for the icon button.
Involves minor changes to GimpContainerTreeView to allow
GimpCellRendererButton to be added, and to allow external
"query-tooltip" handlers to run.
and use gimp_file_new_for_config_path() and _get_config_path() when
dealing with them. We used a weird mix of config paths and plain
(filesystem encoded) paths, waiting to to break on umlauts or
whatever. The code in gimpcolorconfig.c was particularly bad.
Add a SELECT_SOFTPROOF_PROFILE mode to the color profile dialog and
use it to select a profile from a newly added "Soft-Proofing Profile..."
menu item in view -> color management.
In a blocking operation we don't give the main loop time to lay out
the statusbar correctly after showing the progress bar. Force a size
on the progress bar using gtk_widget_size_allocate(). This sucks.
and call gimp_image_convert_indexed() in image-commands.c where it
belongs. Also remember the default values there, they will to to
GimpDialogConfig next.
and move the actual stroking code to select-commands.c,
vectors-commands.c and gimpvectorstool.c. Remember the active drawable
so the stroke always happens on the drawable the dialog was invoked
with.
and move the actual filling code to select-commands.c and
vectors-commands.c. Remember the active drawable so the fill always
happens on the drawable the dialog was invoked with.
Don't change the paste_type to NEW_LAYER just because there is a
complex thing in the clipboard. Instead, honor the request to paste
FLOATING or FLOATING_INTO and reduce the pasted thing to a simple flat
layer. Also remove the message and paste_type change from edit_paste()
in edit-commands.c, it had the same purpose, just with a user
notification.
In order to paste the full layer one needs to explicitly invoke
"Paste as new layer" now.
It still changes the paste_type to NEW_LAYER if it's impossible to
attach a floating selection to the target, the menu item was simply
insensitive before.
Instead, provide a custom GimpAddMaskCallback, connect to "response"
internally and call the callback. Takes clutter out of layers-commands.c.
Also attach the dialog to the layer so we don't show multiple add
mask dialogs. Should do the same to all dialogs with public structs,
the custom callback approach keep things more encapsulated.