Commit graph

5521 commits

Author SHA1 Message Date
Alx Sa
5fde1b9e89 libgimpwidgets, theme: Group radio buttons together
This patch swaps out the GtkBox in
gimp_enum_icon_box_new_with_toggle ()
with a GtkButtonBox and sets it to EXPAND
so that the buttons are pressed together.
It also adds some CSS style to complete
the effect.
2025-11-15 02:50:17 +00:00
Jehan
b2e70c5b89 Issue #15206: do not initialize transform tools when swapping tools…
… automatically.

We still initialize on manual swapping through the action.
2025-11-08 11:26:04 +01:00
Gabriele Barbero
c12ea92376 tools: destry text style editor each time a textbox is selected
This patch ensures that the text style editor is destroyed whenever a text layer
is selected, even switching between them clicking on different textboxes.
This is necessary to ensure that the on-canvas editor is positioned
correctly according to the coordinates of the selected text layer.
2025-10-31 15:39:10 +01:00
Gabriele Barbero
f089ed69d7 tools: prevent on-canvas text editor from being dragged outside the image bounds
This commit prevents the on-canvas text editor from being dragged outside
the image bounds by checking the overlay's position and adjusting the
coordinates to keep it within the canvas. Additionally, it checks whether
the overlay is entirely outside the canvas and, if so, pushes it back inside.
2025-10-31 15:39:10 +01:00
Gabriele Barbero
791f9616fe move style_overlay_offset_[xy] to text_layer 2025-10-31 15:39:10 +01:00
Gabriele Barbero
dc1bd701ac tools: add icon to restore on-canvas text editor position
This commit adds a button inside the on-canvas text editor
that restores the editor to its original position after it has
been moved. The button is only visible when the editor has been
moved, and disappears when it returns to its default position.
2025-10-31 15:39:10 +01:00
Gabriele Barbero
a193d45ab8 tools: implement restore option for on-canvas text editor ...
... to reset its position via right-click menu

This commit adds the ability to restore the original position of the
on-canvas text editor after it has been moved, by accessing the option
from the context menu opened with a right-click on the text box.
2025-10-31 15:39:10 +01:00
Gabriele Barbero
83497695fd tools: store the on-canvas text editor position per text layer
Once the on-canvas text editor has been moved, its position should be
preserved across editing sessions. This commit stores the editor's
position per text layer and restores it when the layer is activated again.
2025-10-31 15:39:10 +01:00
Gabriele Barbero
bd6fc8594a tools: fix on-canvas text editor position on screen after being moved
After the on-canvas text editor has been moved, it should remain fixed
on the screen when zooming or panning the canvas. This commit preserves
the current behavior when the editor is in its original position, and
fixes its position on-screen after it has been moved.
2025-10-31 15:39:10 +01:00
Gabriele Barbero
dae8472d58 tools: allow on-canvas text editor to move
This commit implements the ability to freely move the on-canvas
text editor across the screen by introducing a drag-and-drop mechanism.
2025-10-31 15:39:10 +01:00
Jehan
bfd414ead9 Issue #9463: select back the previous tool when halting a layer effect.
This implies both when canceling or committing a filter.

Part of the fix is that we don't store filter tools as part of the tool
history, which means that when we swap back to the previous tool, the
filter tool info is dropped as though we never went through it. This
way, filter tools don't actually look as other tools (even though they
technically still are, since this is how we can implement canvas
interaction for some of the filters).
2025-10-31 13:54:59 +01:00
Jehan
dddca29423 app: move the tool swapping code to tool manager and action to tools-action.
Per review, let's avoid having all the tools history in every
GimpContext.

Also a further commit will work on special-casing filter tools, which is
why we are storing up to 3 tool infos, instead of only 2.
2025-10-31 13:54:59 +01:00
Jehan
1235bf00bd app: factorize auto-rename code into GimpRasterizable.
Rasterizable objects are all created from some side data and can be
renamed automatically based on this data (from the link file for link
layers; from the path for vector layers; from the text for text layers).

So let's share code.
2025-10-22 22:29:19 +02:00
Jehan
1a73a4ddc6 app: edit vector layer with path tool as default edit action.
- Getting rid of the dedicated vector layer options dialog (with fill
  and stroke settings) which appeared when double-clicking on a vector
  layer. This is a duplicated with the Path tool options.
- Double-clicking a vector layer instead will simply start the Path tool
  (same as double-clicking a text layer starts the Text tool).
- The path choice settings only is missing from the Path tool options.
  Instead of moving it there, I move it to the generic layer options
  dialog. I don't think it's the kind of setting you really change often
  (most of the time, you likely just make a new vector layer).
- Offsets are ignored too and hidden for vector layers.
- Also making sure that the path changes shows live when editing the
  setting in dialog, but it is properly reverted if canceling the
  attributes edition.
- Also make sure the undo step changes the path back.
2025-10-22 19:33:58 +02:00
Gabriele Barbero
6719f28319 tools: use primary_mask for unformatted paste in text tool
The analogue of Control key on macOS is the Command key, this means that
`GDK_CONTROL_MASK` has not the expected behavior on macOS. This commit
changes the modifier for unformatted paste in text tool from Control to
Primary, which maps to Command on macOS and Control on other platforms.
2025-10-19 14:28:30 +02:00
megakite
ac13449142 app, menus: Support pasting unformatted text in Text Tool
This patch adds a Paste Unformatted Text item inside the
right-click menu of Text Tool, which allows user to paste
previously copied, possibly formatted (marked) text as plain
text with no markup.
2025-10-19 03:22:49 +00:00
Jehan
5622708c0a app: improve layer and path selection logic.
- The "Create New Vector Layer" button is now always active, as long as
  there is an image.
- When a path is selected with no matching vector layer, the button's
  label will be "Create Vector Layer from Path", indicating that it will
  create a new vector layer from the current path.
- When selecting a path while the Path tool is active, let's update the
  selected layers to all the layers (it may be several layers!) tied to
  this path. Otherwise, this can be quite confusing, showing a path
  while another layer is selected, or worse, showing a path while the
  selected layer is a vector layer (but not tied to this path).
2025-10-15 21:07:55 +02:00
Jehan
0f65d3923e app: show a menu path to advertize how to "Rasterize" and blink the selected layer.
This is the result of a UX session with Aryeom. Just showing a message
forbidding editing of non-rasterized text/link/vector layers is
problematic, because it doesn't help people understand how to unblock
their situation (if they really want to just edit directly the layer).
Additionally we are now blinking the layer.

A possible alternative could have been to pop a dialog up, with the
same message but also with a quick-action button to allow rasterize in a
click (similar to how we are popping a dialog up to revert the
rasterization when clicking on a text layer with the text tool or a
vector layer with the path tool). The problem is that even though the
need to edit directly a non-raster layer arises from time to time, most
of the time, when you use such layers, you don't intend to edit these
(unlike editing text/path with matching tools, you more often wanted to
edit the relevant data).
Therefore it is more often than not just a mistake when you try to paint
directly on such a layer. I.e. that very often, you were intending to
paint on another layer, or add a new layer above your non-raster layer.
Therefore a dialog popping up every time you made such a mistake would
be annoying and workflow-breaking. A simple error message and some
blinking leave for a fluid process.
2025-10-15 14:57:36 +02:00
Jehan
50fd97b28b app: better logic to generically prevent drawing on rasterizable drawables.
The previous code was preventing initializing, but some succession of
actions could go round this check: Rasterize then Revert Rasterize. In
this state, the next click would not try to initialize again, which
first is not very good if the initialization was necessary, and second
would allow drawing on a non-rasterized text/link/vector layer.

So let's just have all the code blocking drawing on rasterizable
drawables in the generic gimp_tool_button_press() code only.
2025-10-15 13:00:44 +02:00
Jehan
d593cb3230 app, pdb, po: new GimpRasterizable interface.
Share the whole rasterize logic of the text, link and vector layer into
an interface. I didn't write it as an abstract parent class, because we
might have more rasterizable items in the future, which may not be
layers (e.g. there were discussions of vector masks).
2025-10-13 15:37:11 +02:00
Jehan
9d45f41868 app: properly react to the currently selected vector layer being rasterized.
Also properly factorize the set_layer() code, avoiding duplicating the
(dis)connecting signal handler code in various places.
2025-10-12 19:58:28 +02:00
Jehan
1e88cfd70f app: make the "Create New Layer" option work properly.
It will duplicate the current path, create a new vector layer based on
it and will let one start editing it.
2025-10-10 23:40:54 +02:00
Jehan
0725b023cd app: add "Confirm Path Editing" dialog on Path tool similar to the…
… "Confirm Text Editing" one on Text tool.

When selecting a rasterized vector layer, this will suggest to edit it
anyway (hence losing any modification since rasterization), create a new
layer based off the same path, or cancel.
2025-10-10 23:34:37 +02:00
Jehan
8e9c6d7e3c Issue gimp-ux#252: simpler, more to the point, dialog text. 2025-10-10 21:22:48 +02:00
Jehan
0fea05af78 app: indentation fixes. 2025-10-10 20:23:46 +02:00
Jehan
42783ace78 app: also apply the no-edit on non-raster layers to text layers! 2025-10-08 23:26:24 +02:00
Jehan
5ddb853964 app: globally block editing vector and link layers.
Instead of blocking various drawable-editing tools to work on vector or
link layers, per tool (as in commits 38c379cd92 or 36330a271a), let's
have a more generic logic in GimpTool. We will now block the tool
initialization early when it's destructive and tries to work on link or
vector layers.

By default, all tools are set as being destructive, but we can override
this per-class by setting the class' is_destructive flag. For instance,
text and path tools, or the Zoom or Color picker tools, etc. are
non-destructive.
Filter tools also are non-destructive (they may be destructive, but have
their internal code to disable this path on these types of layers).

Source tools are special-cased because we may allow them to be
initialized on a link/vector layer as sources. For this special-case, I
make a second check on gimp_tool_button_press().
2025-10-08 23:21:59 +02:00
Jehan
6095b247be app: special-case pass-through groups' drawable area.
On empty pass-through groups, it was returning a 1×1 area, which
triggered effects with X/Y distance arguments to have no set min/max
values. For instance, a gaussian blue's X/Y scale widgets end up showing
a [0, 1.5] range, making it very impractical to set higher values.
2025-10-07 23:34:55 +02:00
Alx Sa
a5182a010f tools: Fix missing cursor for MyPaint Brush tool
Resolves #15001
In the MyPaint Brushes v2 port (ea8b9dc1),
I implemented a cursor_update () function from the
parent class. However, I did not call the parent's
version of the function afterwards, so the MyPaint
Brush cursor was not being redrawn. This patch
adds the call to fix the cursor display issue.
2025-10-03 22:14:52 +00:00
Bruno Lopes
f09007507f
Declare gexiv2 dependency on many targets (due to gimpmetadata.h)
Our build files were relying 'sysroot' to find gexiv2.h but this is
not possible with Apple Clang om which sysroot points to macOS SDK.
So, exotic environments like Homebrew were failing. Let's fix this.
2025-10-03 18:31:53 -03:00
Alx Sa
81c67e5614 tools: Don't commit Filter Tool without a filter
The Filter Tool is a "hidden" tool that we switch to
when applying a filter. Like other tools, it commits when
we save our image. However, we may no longer have an
active filter in the tool when we do so (like, after applying
an NDE filter). Because we check the drawable from the
filter to confirm whether we should force NDE or not,
this can cause a CRITICAL when we try to access a now
non-existent filter.

This patch extends the "if (filter_tool->filter)" check to
cover the full commit check process, to prevent the bug.
2025-10-02 12:07:25 +00:00
Alx Sa
36330a271a tools: Prevent bucket fill on link/vector layers
Resolves #14993
We currently prevent paint tools from painting on
link or vector layers. However, we had not added this
protection to the bucket fill tool. This patch copies over
the relevant if statements to prevent this.
2025-10-01 13:23:09 +00:00
Jehan
38c379cd92 app: properly forbid paint tools to draw on link layers and forbid…
… filter tools to merge filters, both on link and vector layers.
2025-08-30 10:12:17 +02:00
Jehan
2c44689fe2 app, po: localize various strings which were blocked by string freeze. 2025-08-30 09:15:28 +02:00
Jehan
35b972c854 app, desktop: update demo tour for vector layers. 2025-08-29 13:15:24 +02:00
Gabriele Barbero
eeeaca928b tools: implement shortcuts in text tool...
...for toggle bold/italic/underline.

This commit adds support for common formatting shortcuts in the Text Tool:
- Ctrl+B: Toggle bold
- Ctrl+I: Toggle italic
- Ctrl+U: Toggle underline
2025-08-27 11:21:51 +00:00
Jehan
2821dbab58 app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.

For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!

Note nevertheless the following limitations in current implementation:

* The link layer with transformations will still show as a standard link
  layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
  the link info, then monitor the link again. A specific action in the
  contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
  perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
  will it work for the Transform actions. I will need to implement
  GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
  made any tests with layer masks yet, but this should be done next
  too).
* I think that the "scaled-only" property is now meaningless. It is now
  being replaced by the presence of the GimpMatrix3. Nevertheless I have
  still not removed this property.
* The load/save code has not been redone yet to include all these
  changes.

The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):

* Any intermediate interpolation methods are dropped when cumulating
  transform steps. Only the last interpolation is stored. This is
  because anyway the interpolation is only there as the best algorithm
  where we visually see the less quality loss. Applying several
  transformations as a single matrix will always be visually better than
  applying several matrices (whatever the intermediate interpolation
  methods chosen).
* This only works with the "Adjust" clipping method (basically no
  clipping) because 2 transform steps with clipping won't produce the
  same result as the multiplied matrix with clipping. It means that
  applying a transform with clipping will downgrade your link layer to
  being a normal layer.
  The only issue I have with this is how to best convey that clipping is
  a major setting setting here, which disables our less-destructive
  abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
  non/less-destructivity transforms. In particular any scaling (both
  through "Scale Image", "Scale Layers" and transform tools — since I
  added code to detect a matrix doing only scaling and optionally
  translation) done **first** will be completely non-destructive since
  we will simply reload the original vector source at the right
  dimensions. Any other kind of transforms will be appended through the
  cumulative matrix, as raster link layers. This also includes scaling
  done **after** other transforms, since we cannot easily move the
  scaling first (matrix multiplication is not commutative). This second
  level of scaling will therefore be *less* destructive, but still
  destructive.
  It is possible eventually to improve the whole thing if we add some
  day the ability to request loading a vector image with a transform
  matrix (it will then be up to each vector format plug-in to support
  this feature or not).

Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-27 11:34:04 +02:00
Alx Sa
4b67eb9cd0 paths, tools: Prevent CRITICAL when discarding empty vector layer
Resolves #14705
The path tool prevents creating a vector layer from an empty path.
However, the menu option "Path to Vector Layers" does not have this check.
This patch updates the check to constrain it to just one path.
Additionally, it adds a check for the path being NULL before trying to use
it in g_set_object ().
2025-08-19 00:10:22 -04:00
Alx Sa
a1cd2a2588 path, tools, pdb: UX updates to vector layers
This patch improves vector layer UX based on feedback.
In summary:
* Makes vector layer editable from the Path tool
* Adds initial PDB for creating vector layers in scripts
* Size vector layers to the path size, rather than image
* Transform tools utilize the path for resizing
* Path tool automatically selects vector layer path
2025-08-17 02:20:19 +00:00
Henk Boom
60ed90e10a vectors: Implement vector layers from GSoC 2006
Ports the work done by Hendrik Boom, Martin Nordholts, Gilles Rochefort,
and Jacob Boerema to Gimp 2.99/3.0.
2025-08-17 02:20:19 +00:00
Alx Sa
ede124ff85 tools: Fix crash in passthrough composited preview
Resolves #13087
We use gimp_layer_get_effective_mode () to retrieve
a simplified layer mode for optimization purposes
(e.g. if it's effectively NORMAL, we can do less processing).
GimpTransformGridTool used this function when the user
requests Composited Preview to only apply transforms to
individual layers in a group if absolutely necessary.
This means that sometimes, it returns NORMAL instead of
PASS_THROUGH depending on the number and types of
layers in the group.

Since 71aff497, when we remove a filter we also update the
effective mode of the group layer. However, this leads to an
infinite loop scenario where the effective mode change causes
the TransformGridTool to repeatedly remove and add a filter
until GIMP crashes.

This patch changes the gimp_transform_grid_tool_add_filter ()
check to always get the actual mode rather than the effective mode.
This prevents the effective mode change from causing an infinite loop,
but does mean that we now always apply transforms to all layers of the
group even if the composite preview would work fine.
2025-08-15 06:03:13 +00:00
Ondřej Míchal
00c08e81d4 app: Make block-listing of GIMP operations optional
In an upcoming commit a new user of gimp_gegl_get_op_classes will expect
a list of all operations supported/allowed in GIMP and not just the ones
that are not exposed in the GUI.
2025-08-03 21:38:28 +00:00
Ondřej Míchal
caa61e5925 app: Separate GEGL op blacklist based on filter actions
In an upcoming commit a new user of gimp_gegl_get_op_classes will expect
a list of all operations supported/allowed in GIMP and not just the ones
that are not exposed in the GUI.

With the same change, this switches from maintaining a list of
operations exposed as an action, this now uses the actions themselves
for the filtering. During this I found some operations that were in the
"exposed in GUI sub-list" were in-fact not exposed but were straight up
blocked. I moved them to the appropriate sub-list along with the
justifications I found in the commit history.
2025-08-03 21:38:28 +00:00
Michael Natterer
b416994ed0 app: make GimpContainerView behave like a normal widget
The old API to select stuff and its signals was doing unexpected
stuff and was very confusing. Change things to be "normal":

The selection API is now set_selected() and get_selected(), with no
internal data exposed, and set_selected() emitting the expected
signal.

The signals are now "selection-changed" and "item-activated".
"selection-changed" is always emitted in response to changing the
selection, be it via the API, or by changes in the model (the internal
callbacks in from e.g. GimpContext or GimpImage simply call set_selected()
and don't do any unxpected magic).
2025-08-01 10:02:37 +02:00
Alx Sa
f7ef01f44a tools: Update Seamless Clone paste check
The experimental Seamless Clone tool assumes
that all pasted objects are GimpBuffers. With multi-select,
it's now likely that the pasted object is an image containing
layers instead. Thus, the tool would report there was no pasted
data to work with, even though there was.
This patch updates the check so that it retrieves the first selected
layer from the pasted image if it's not a GimpBuffer, allowing the
tool to function again.

Note that this patch does not improve the speed of the Seamless Clone
GEGL operation, just enables the tool to work again in GIMP.
2025-07-31 14:49:35 +00:00
Alx Sa
df8063c861 tools: Make transform boundary multi-select aware
Resolves #13589
When selecting multiple layers to transform, the boundaries
would only consider the first layer selected - leaving the other
items invisible.
This patch reuses code from gimp_edit_paste_get_viewport_offset ()
to loop through all selected layers and update the transform
boundaries to consider the total offset and dimensions of the selected
layers.
2025-07-27 04:01:27 +00:00
Michael Natterer
d4e8ab0234 app: rename GimpContainer's "children-type" property to "child-type" 2025-07-18 08:19:13 +02:00
Michael Natterer
14fb14effc app: #pragma once in app/tools 2025-07-13 09:26:04 +02:00
Michael Natterer
246f9d284f app, pdb, libgimp: use "#pragma once" instead of:
#ifndef __FOO_H__
 #define __FOO_H__

 /* declarations  */

 #endif /* __FOO_H__ */

And some cleanups while I saw the headers.
This is far from finished...
2025-07-13 03:21:37 +02:00
Alx Sa
2449d2f3ad paint, tools: Minor fixes to MyPaint Brushes code
* Anders Jonsson noticed a typo where the
'r' in "pressure" was left off in the Gain
parameter description
* Since 0.0 is an invalid value for the viewzoom
parameter in MyPaint, the cut off is adjusted
to be greater than 0, not greater than or
equal to 0.
* The default viewzoom value is set to 1.0f,
100%, rather than 0.0001, very zoomed out.
2025-07-10 01:39:36 +00:00