Similarly to how I improved "Select Top|Bottom Channel", we should set
the actions sensitive not only when the selected layers are not the
top/bottom ones, but also when there are no selected layers at all.
I had a weird case where g_return_val_if_fail() ran but I could not
reproduce and am not sure how this happened. Adding the item name may
help diagnose the next time it happens.
Now that we have implementations for select_items everywhere and that
all the code is only wired to call or handle select_items, the single
item variant select_item is of no use anymore. Let's make a big cleanup.
… for the container tree view contextual menu.
A very annoying point of contextual menus is that they happen on button
press whereas menu item selection happens on button release. When the
menu corner is positionned on the click position, nothing bad happens;
yet when place is missing on screen, the menu might get positionned over
the pointer position. And worse, the mouse position might be just over
an activatable menu item. So we end up in this weird situation where a
click implies: press, menu opens, release, random item (whatever is
below the pointer) is selected and menu closes.
To get rid of this weird case, let's have our contextual menu happen on
button release. In reality, I don't think anyone cares that it happens
on press or release, you just "click". But what you certainly don't want
is to click random menu items!
… the container.
There was this weird case which we somehow could only reproduce on
Aryeom's computer/build, not mine, with the same code and reproduction
steps (reproducible at will on her build only). Basically when drag'n
dropping a duplicated layer inside a collapsed layer group, the
row-expanded handler would try to select the moved layer before it is
actually inserted. This would end up into crash-happy code.
I'm still unsure of why the order of operation is different here, but
anyway what is for sure is that the `inserting_item` boolean flag was
not protecting much. It's not like it's an actual mutex and anyway this
is not multi-threaded code either so this flag was mostly useless (which
is why we were crashing). Instead let's actually look if the item is in
the container or not.
… and use gimp_container_view_select_items() when the context changes.
Even though some types of containers still expect only a single
selected content, we should slowly move to multiple item code. The
reason is to avoid 2 code paths which makes the code more complicated
and bug-prone. When all child classes of GimpContainerView will have a
valid select_items() implementation, we can work on getting rid of the
select_item() in favor of the multi-item one.
The bin window coordinates must be converted to the widget coordinates.
This was not a problem before, but now with the column header, if I
don't do this, the position is wrong.
Similarly fix the lock popover position.
The header shows a lock icon, making the column more discoverable, as
well as where to click.
Also the title for the item column will now be used for the
multi-selection label (counting items) instead of using
GimpItemTreeView's options box.
Finally use the new gimp-multi-lock icon to show multiple locks.
This makes for much nicer and usable item tree.
… the selected items only.
This is the exact same algorithm as Shift-click, except that Shift-click
switch exclusivity within the whole level of items. Alt-click does the
same but only within selected items in the list.
Similar to exclusive visibility switch on layers, now for locks too, if
one wants to lock all layers within a same level for instance by
Shift-clicking the lock icon.
Also once again I factorized the exclusive switching code to ensure it
will always works the same for all similar features (visibility and all
locks).
First of all, let's use gtk_widget_show|hide() instead of
gtk_popover_popup|down() because these GtkPopover API sometimes "block"
when clicking very fast on the item list, sometimes up to 2 or 3 seconds
(at least it feels like seconds, I haven't actually timed it!). I'm sure
the ones who developed it thought it was nice to have slow popping
dialogs, but when working fast, this can only be frustrating).
The second responsiveness change is that when clicking out of useful
lock popover area, it should not only close, but the event should be
passed onto the item tree view when relevant. This allows for instance
to directly click on an eye cell to change a layer visibility without
having to click twice.
Use this for the alpha lock brought by GimpLayerTreeView.
Also use the new gimp_widget_blink_rect() to only blink the appropriate
cell when a lock is preventing you from doing something.
… and drop the link cell (the lock cell takes the space).
This is an experiment with the following logics:
* I am getting rid on the linked item logics, so the icon cell
disappears anyway.
* The lock buttons are not so visible above the Layers dockable and so
many have I seen people frustrated of not being able to do some action
until they realize they locked something in the layer (even sometimes
advanced users).
The icon next to the eye is much more visible. Also I will now display
different icons depending on the type of locks. If a single lock is in
effect, I show the corresponding icon. If 2 or more locks are in
effect, I show a generic lock icon.
* With multi-selection of items in particular, this top lock row was a
lot more weird and could show inconsistent state (some of the
selection is locked, other is not). Now the per-row lock icon allows a
much nicer granularity.
Sometimes one may want to lock visibility of a given layer. This is very
useful in particular when shift-clicking a layer visibility. In this
case, it won't be included in the list of layer to update. This can be
used for instance if you want some layers always visible (or always
hidden) while setting exclusive visibility of some other layers only.
Instead of just storing list of layers, I created a new simple type
GimpItemList (actually GimpItemSet would be better named, but
unfortunately we use this name for an enum type). So far, this new class
can handle 2 types of item sets: named fixed sets and pattern-generated
sets.
I am unsure if regular expression is the right choice as it may
obviously be a bit too technical. I hesitated with glob-type match for a
while. We'll see!
The eventual goal is to replace the "linked layers" concept, which is
why I am using similar vocabulary. The point is that linked layers are
mostly useless/redundant now with multiplie layer selection, except for
one thing: they kind of serve like a way to "save" a selection of layers
(to be moved/transformed together mostly). Apart from this, multiple
selection is more powerful on any way. You can do much more than
transforming the layers together (you can reorganize them together,
delete them, crop them and so on).
Therefore this new feature is the way to fill the only weakness of layer
selection: its ephemerality. Now we can save a given set of layers, not
even only one, but as many as we want, and under a meaningful name, for
later reuse.
Moreover it will make layer-handling core code much simpler as we
currently have 2 concepts of layer set: multiple selection and links.
The new stored links are only a way to recreate multiple selections.
More is to come, for instance right now, these are not stored in the XCF
format. Also it would be awesome to add logical operators (Shift for
union of layer sets, Ctrl for subtraction and Shift-Ctrl for
intersection). And finally I was thinking about a way to select by
pattern (regular expression? Shell-style glob patterns?) and even store
these patterns. So if you save a "Marmot .*" selection pattern, then
when you select it later, new layers matching this pattern will be
included too (instead of fixed-in-time list of layers).
This change allows gimp to run from the build
directory rather than having to wait for the
full packaging process to complete.
However, 'gi' modules are not loading properly
so that might be something to fix.
Rather than trying to fix up our own heuristics using a
`GtkMenuPositionFunc`, use whatever GTK provides to position given a
specific rectangle, which also has the benefit of nicely integrating
with GDK backends such as Wayland. Another advantage is that we can use
GdkGravity to center the popup.
Since GTK 3, GtkWidget also gained a "popup-menu" signal, which we
can/should use instead of rolling our own context signals.
Rather than trying to fix up our own heuristics using a
`GtkMenuPositionFunc`, use the API that GTK provides to have popup
nicely placed near the pointer, which also has the benefit of nicely
integrating with GDK backends such as Wayland.