Commit graph

5546 commits

Author SHA1 Message Date
Gabriele Barbero
8af15d525a tools: fix font size jump when using shortcuts
Previously, when using shortcuts to increase or decrease the font size of
the selected text, the size would jump to 0. This behavior occurred because,
if the text did not yet have a font tag, the initial font size was evaluated as 0.

This commit ensures that the text tool's default font size is used when
no font tag is present. This prevents the font size from jumping to 0 the
first time the shortcuts are used.
2026-04-02 00:24:26 +02:00
Alx Sa
a749329ab6 tools: Turn off floating selection outline when moving
When moving a floating layer or selection, we draw a solid
border around the object. However, we also let the "marching
ants" selection continue (if the user has it enabled). This slows
down performance when moving, especially on large selections.

This patch incorporates logic from the Selection tools into the
Edit Selection tool (which the Move Tool uses for translation).
It stores the user's "Show Selection" setting, sets it to FALSE
while moving the layer or selection, then restores it to its
prior value when the cursor is released.

This logic also extends to using Ctrl + Alt to drag a floating
selection out of a layer that already has a selection.
2026-03-31 23:46:05 +00:00
Gabriele Barbero
2d83568bb9 tools: prioritize proxy bindings over IM context in text tool
Try proxy bindings before the IM context. On macOS and Windows,
the IM context consumes Alt+key events (Option produces special
characters on macOS; Alt triggers alt-codes on Windows), so
bindings such as Alt+Plus/Minus (size) and Alt+arrows
(baseline/kerning) would never be reached otherwise.
2026-03-31 15:31:25 +02:00
Jehan
045c818d0e Issue #15962: initialize Levels dialog in Perceptual.
Unlike for Curves (commit 7b4f0993e8), we cannot just change the "trc"
default of "gimp:levels", because then it could break any existing
script, made during the 3.0 series, which was applying this filter on
layers.
Instead, the "trc" stays linear by default for the op, but the tool's
dialog will override it to perceptual.

When we'll have implemented proper op versioning, we will be able to
change the default.
2026-03-09 14:26:58 +01:00
Alx Sa
c2f87513d6 app/tools: Fix ordering of selection mode options
In 046c8f27, we added a new function
gimp_selection_options_get_mode_box () so that the
Paint Select tool would use the same enum as other
selection tools. Code was added to move the
GIMP_CHANNEL_OP_REPLACE enum to the front only if
it was greater than the min value and less than the max value
that was passed in. This was to allow the Paint Select tool to
keep GIMP_CHANNEL_OP_ADD at the front while leaving the
other selection tools as they are.

However, the original call used 0, 0 for those values, so the
rearrangement code never ran at all. This patch changes the
parameter max value to GIMP_CHANNEL_OP_INTERSECT so
that Replace is moved for non-Paint Select tools.
2026-03-09 10:26:46 +00:00
Alx Sa
2af5aa651a tools: Don't disconnect rasterized layer signals
In the path tool, when setting a new vector layer as
the editable path, we try to disconnect the old signal for
gimp_path_tool_vector_layer_path_changed () from the
vector layer options. However, if this code is triggered
because we rasterized the vector layer while the path
tool was active, it will throw a warning because the
layer options are NULL. This patch adds a check to make
sure the options exist before trying to disconnect their
"notify::path" signal.
2026-02-20 02:48:05 +00:00
Alx Sa
6ab235dc20 tools: Grab display from correct path's image
When copying and pasting a vector layer into
another image, the display would jump back to
the original image. This also happened if you
re-selected the pasted vector layer in the new
image after choosing another layer.

This patch makes sure that when updating the
selected path in the Path tool, it grabs the display
from the pasted vector layer rather than the old
image's path.

Note that this may be a "symptom" rather than a
root cause, due to a number of remaining issues
with copying and pasting vector layers.
2026-02-19 18:57:40 +00:00
Alx Sa
57795c0c25 tools: Add arrow keys to Shear tool
Per user request, this allows you to use
arrow keys to adjust the shear tool.
Left/right move the shear on the X axis,
up/down move the shear on the Y axis.
By default, it moves one pixel at a time.
If you hold shift (similar to the move
tool), it moves based on the slider's
page increment setting (factoring in the
current zoom).
2026-02-14 22:36:08 +00:00
Alx Sa
b507aae3fc tools: Add alpha if crop can grow the layer
This patch conditionally adds an alpha
channel to a layer when using the Crop
Tool, under the following conditions:
1) "Selected layers only" is checked
2) "Allow growing" is checked
3) "Fill with" is set to transparency
4) The crop rectangle is larger than the
width or height of the layer
5) The layer does not already have an
alpha channel.
2026-02-14 14:23:39 +00:00
Alx Sa
c9c932a87f tools: Add arrow keys to Flip tool
Per user request, this allows you to flip
on-canvas items with the arrow keys when
the Flip tool is active. Left/right arrow keys flip
horizontally, up/down arrow keys flip vertically.
Note that having an active guide highlighted overrides
this distinction - pressing any arrow key will always flip
over the guide, same as with the mouse.
2026-02-06 04:05:48 +00:00
Jehan
9417565ea2 Issue #15575: add arg to color button prop widget to choose context awareness.
In particular, for indexed images, color choice will happen within the
colormap.

The following uses are made context-aware:

* Test tool options color;
* Fill colors.

These other uses will not be context-aware:

* Padding, quick-mask and padding colors;
* Out-of-gamut colors;
* Generically generated color buttons (e.g. in filter dialogs);
* Foreground selection's mask color;
* Grid colors.
2026-02-03 13:10:41 +01:00
Gabriele Barbero
651ec04744 display, tools: use gimp_display_shell_untransform_xy_f...
... to get limits in image coordinates instead of gimp_ruler_get_range.
Rulers return values in the active unit (e.g. mm, inches), while the
overlay logic works in pixels. This unit mismatch caused incorrect
clamping of the text overlay position, making it jump
when dragging if the unit wasn't set to pixels.
2025-12-18 14:49:11 +01:00
Alx Sa
540fe925f1 tools: Crop Tool is conditionally destructive
Resolves #15418
Destructive tools can not be used on non-raster layers
(vector, text, link). However, the Crop Tool is only destructive
when "Delete Pixels" option is enabled - otherwise it just crops
the canvas size. This patch toggles the GimpTool classes'
"is_destructive" setting based on the value of "Delete Pixels".
2025-12-07 17:38:08 +00:00
Bruno Lopes
8748b8bb41
app, libgimpbase, plug-ins, tools: Include missing IO headers if on Windows
Otherwise, gimp fails to build on MSVC
2025-11-29 18:16:54 -03:00
Jehan
046c8f2745 app: use the same mode box in Paint Select as in other Selection tools.
To avoid duplicating code, I make a friend function to be reusable in
Paint Select options code: gimp_selection_options_get_mode_box().

I also get rid of GimpPaintSelectMode enum, which was clearly a
duplicate type to GimpChannelOps. Right now only ADD and SUBTRACT are
supported in Paint Select tool, yet we are perfectly able to generate
widgets showing only partial data. Which is what I do here by adding
appropriate min/max value args to the new function.

Note though that I don't see why we should not be able to replace or
intersect using Paint Select. But since these 2 modes are not
implemented right now, I haven't tried to add support in this commit.
For now, only making our GUI consistent so that Paint Select looks like
any other selection tools (simply only with 2 modes).
2025-11-27 22:24:54 +01:00
Jehan
2a12e53d95 app: fix hitting a modifier before painting. 2025-11-27 16:10:47 +01:00
Jehan
f3098dd935 app: cosmetic space, indentation, etc. fixes.
These have been itching me ever since I started fixing this code. Better
just do a full pass of cleanup now.
2025-11-27 00:19:04 +01:00
Jehan
e8b160a5e1 app: reset the scribbles at every new strokes.
Every time we press for a selection update, we will start with a blank
tri-map, instead of reusing previous "scribbles". In my various tests,
it felt like I would get better results this way. Also if you do some
mistakes (maybe getting off-border of your object in a previous stroke),
it would be much harder to fix, unless you are alway showing the
scribbles.

One can consider that once you edited the image selection, what is done
is done. You don't constantly edit the past, and your resulting
selection could have been done with any other selection tool (how it was
done doesn't matter anymore). This makes the tool actually stateless
in-between strokes.

Note that I reset the tri-map at the start of a stroke, rather than at
the end. This way, it still allows one to see the previous stroke (it
can be useful for verifying how it was done before undoing and
retrying).
2025-11-26 23:24:50 +01:00
Jehan
77d1b66edd app: display progression feedback on canvas.
This change won't do much right now, using upstream libmaxflow (though
it won't hurt either). It will really show its usefulness together once
this patch will have been merged in libmaxflow:

https://github.com/gerddie/maxflow/pull/8

… then once done, I will push also a small update in "gegl:paint-select"
code on GEGL repo, which will in turn report the progression as reported
by libmaxflow.

This is particularly needed for big images on limited hardware, which is
when the current algorithm or its implementation will start showing some
weakness. I had cases (on 4000×3000 images in Balanced power mode) where
the processing inside graph->maxflow() could take more than 10 seconds,
the GUI would look frozen and the desktop would warn you through a popup
that the software "is not responding" (with the option to kill the
process). Furthermore without any kind of feedback, you have no idea if
processing will be soon finished or if it will take 10 minutes, or 1
hour, or even if you may be stuck in some infinite loop. In such
conditions, even 10 seconds actually feel long and the software appear
broken.

But when you have the progression feedback, you see that processing is
soon finished, and when working on huge images, you may expect that some
things may take longer than others. In such a case, even longer time may
actually feel very acceptable.

Note: an alternative to show progression would have been to use a
GeglProcessor, but apparently it gets its progression status a different
way, by cutting the image into smaller pieces. This doesn't work with
"gegl:paint-select", or at least its current implementation. Using the
"progress" signal works fine though.
2025-11-26 23:06:24 +01:00
Jehan
0720c5dfe1 app: better local region computation.
Increasing the viewport region with the region of same size, yet
centered around the cursor position (whether the button_release() one or
even any motion() position) doesn't make much sense.

If the idea is to limit the work on the viewport, which is indeed quite
interesting performance-wise, but also worflow-wise to allow targetting
parts of an image while ignoring the rest, then let's stick to the
actual viewport indeed!

I am only adding half the "brush size" to every edge of the viewport,
because technically we can move the cursor so that half of the brush
preview is off-view. Though even this, I am hesitating. Indeed
workflow-wise, it may be much more interesting to be able to really
limit where want the selection to stop. Selecting a bit further than
"what you see" may be unwanted, even if the brush itself could
technically go further.
2025-11-26 23:06:24 +01:00
Jehan
d797894c3e app: making sure we redraw the "brush" shape while moving the cursor. 2025-11-26 23:06:24 +01:00
Jehan
fe39d68caa app: do not process when fully painting inside/outside selection in…
… respectively Add or Subtract modes.

When all the "scribbles" are already inside the fully selected area, it
is likely unneeded to recompute the paint selection (it's not entirely
true, algorithmically-wise, but workflow-wise, it makes sense: if you
are not happy with your selection and want to add some parts of the
image, you would obviously "paint" in the area which you want to add in.

And reciprocally for removing some of the selection, you'd paint within
the existing selection.

This also cleans out some of the logic in the button_press() code, where
we were adding the initial "scribble" to the mask. In original code,
when clicking without any motion, what was happening was that you were
only adding this one round selection and nothing else was happening,
which I always found weird (when you want to add some tiny piece of the
image into the selection, you may not have a lot of space to move and
would still want to do a quick click while hoping it will compute a bit
more into the selection). Now the new code anyway computes during
button_release() so adding this initial small-round mask is even more
unneeded.

Last, I am moving more of the motion() code into button_release().
2025-11-26 23:06:24 +01:00
Jehan
f167385d7c app: don't ignore events anymore.
I can see why this was added when we used to re-process the graph during
motion (it was already slow and would have just been so much slower),
but if we only process at the end, it is simply counter-productive not
to store all motion events. It doesn't actually make the finale
processing (on release) slower, at least not obviously, and we get more
data for more accurate (hopefully) selection.
2025-11-26 16:43:20 +01:00
Jehan
f757865e7d app: only process the paint-select graph on button release.
I can read in the source paper that the original goal was to have
instant feedback "as they drag the mouse", but truth is that right now,
this doesn't work out. On bigger images (yet reasonably sized, like
3000×4000, which is even smaller than what the paper claims should be
instant), we end up reprocessing for 10 seconds (on my laptop, in
"Balanced" power mode) multiple times in a single stroke!
Only processing on releasing the stroke (and only storing the
"scribbles" into the trimap during the stroke), we get back to a more
reasonable wait time, such as **once** 10 seconds on my test image and
laptop. And for smaller test images, like near-FullHD, we get very quick
processing on releasing the pointer click.

This may not be ideal, and the problem may be that our implementation is
not ideal and could be improved (I think it should be multi-threadable,
at least that's what it looks like when I read libmaxflow code — this is
where most of the processing time is actually spent! —, and also the
source paper mentions "multi-core graph-cut as an optimization). But
then we can revert to during-motion processing later. For now, all it
does is make this tool unusable.
2025-11-26 15:09:59 +01:00
Alx Sa
ed7f53b7a6 tools: Don't update position if no prior moves
Resolves #12755
gimp_edit_selection_tool_active_modifier_key () assumed
that if you press a modifier key while a selection/move tool
is active, we should move the selected item to the last place
recorded. However, it's possible to run this function before
we've moved anything, thus defaulting the "original position"
to 0, 0.
This is most noticeable in the Move Tool, where pressing Ctrl
or Shift after clicking a layer but before moving it will cause
the layer to "jump" based on where the cursor is placed on the
item.
This patch adds an additional condition to the motion function
in gimp_edit_selection_tool_active_modifier_key (), so that
we only do it if we've already moved the cursor at least once.
2025-11-22 05:17:00 +00:00
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