Skip to content

Commit 7d2ad1c

Browse files
committed
Introduce an ItemGroup
1 parent 372ceb8 commit 7d2ad1c

4 files changed

Lines changed: 178 additions & 117 deletions

File tree

src/BaseItem.vala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ public class Dock.BaseItem : Gtk.Box {
133133
reveal.done.connect (set_revealed_finish);
134134

135135
var animation_target = new Adw.CallbackAnimationTarget ((val) => {
136-
ItemManager.get_default ().move (this, val, 0);
136+
((Gtk.Fixed) parent).move (this, val, 0);
137137
current_pos = val;
138138
});
139139

@@ -219,6 +219,10 @@ public class Dock.BaseItem : Gtk.Box {
219219
* when moving a launcher so that its current_pos is always up to date.
220220
*/
221221
public void animate_move (double new_position) {
222+
if (timed_animation.value_to == new_position) {
223+
return;
224+
}
225+
222226
timed_animation.value_from = current_pos;
223227
timed_animation.value_to = new_position;
224228

src/ItemGroup.vala

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
* SPDX-License-Identifier: GPL-3.0
3+
* SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4+
*
5+
* Authored by: Leonhard Kargl <leo.kargl@proton.me>
6+
*/
7+
8+
public class Dock.ItemGroup : Gtk.Fixed {
9+
private static Settings settings;
10+
11+
public ListModel items { get; construct; }
12+
13+
private GenericArray<BaseItem> item_array;
14+
private ListStore current_children;
15+
16+
private Adw.TimedAnimation resize_animation;
17+
18+
private bool relayout_queued = false;
19+
20+
public ItemGroup (ListModel items) {
21+
Object (items: items);
22+
}
23+
24+
static construct {
25+
settings = new Settings ("io.elementary.dock");
26+
}
27+
28+
construct {
29+
item_array = new GenericArray<BaseItem> ();
30+
31+
current_children = new ListStore (typeof (BaseItem));
32+
current_children.items_changed.connect (queue_relayout);
33+
34+
settings.changed["icon-size"].connect (queue_relayout);
35+
36+
var animation_target = new Adw.PropertyAnimationTarget (this, "width-request");
37+
38+
resize_animation = new Adw.TimedAnimation (this, 0, 0, Granite.TRANSITION_DURATION_OPEN, animation_target);
39+
resize_animation.done.connect (on_resized);
40+
41+
items.items_changed.connect (on_items_changed);
42+
on_items_changed (0, 0, items.get_n_items ());
43+
44+
overflow = VISIBLE;
45+
}
46+
47+
private void queue_relayout () {
48+
if (relayout_queued) {
49+
return;
50+
}
51+
52+
relayout_queued = true;
53+
Idle.add_once (relayout);
54+
}
55+
56+
private void relayout () {
57+
resize_animation.value_from = width_request;
58+
resize_animation.value_to = get_launcher_size () * current_children.get_n_items ();
59+
resize_animation.duration = resize_animation.value_from < resize_animation.value_to ?
60+
Granite.TRANSITION_DURATION_OPEN : Granite.TRANSITION_DURATION_CLOSE;
61+
resize_animation.play ();
62+
63+
for (uint i = 0; i < current_children.get_n_items (); i++) {
64+
var item = (BaseItem) current_children.get_item (i);
65+
item.animate_move (get_launcher_size () * i);
66+
}
67+
68+
relayout_queued = false;
69+
}
70+
71+
private static int get_launcher_size () {
72+
return settings.get_int ("icon-size") + Launcher.PADDING * 2;
73+
}
74+
75+
private void on_resized () {
76+
// When we finished resizing we know we now have enough space for all new items
77+
// so reveal them
78+
for (uint i = 0; i < current_children.get_n_items (); i++) {
79+
var item = (BaseItem) current_children.get_item (i);
80+
if (!item.visible) {
81+
item.visible = true;
82+
item.set_revealed (true);
83+
}
84+
}
85+
}
86+
87+
private void on_items_changed (uint position, uint removed, uint added) {
88+
for (uint i = position; i < position + removed; i++) {
89+
var item = item_array[i];
90+
item_array.remove (item);
91+
92+
remove_item (item);
93+
}
94+
95+
for (int i = (int) position; i < position + added; i++) {
96+
var item = (BaseItem) items.get_item (i);
97+
item_array.insert (i, item);
98+
99+
add_item (i, item);
100+
}
101+
}
102+
103+
private void add_item (int pos, BaseItem item) {
104+
if (item.parent == this) {
105+
// The item was already in this group and is currently being removed
106+
// so immediately finish the removal and add it as if it was new
107+
// This happens when the items are repositioned via dnd
108+
finish_remove (item);
109+
}
110+
111+
item.visible = false;
112+
113+
var item_pos = get_launcher_size () * pos;
114+
put (item, item_pos, 0);
115+
item.current_pos = item_pos;
116+
117+
current_children.insert (pos, item);
118+
}
119+
120+
private void remove_item (BaseItem item) {
121+
item.revealed_done.connect (finish_remove);
122+
item.set_revealed (false);
123+
}
124+
125+
private void finish_remove (BaseItem item) {
126+
item.revealed_done.disconnect (finish_remove);
127+
128+
remove (item);
129+
130+
uint index;
131+
if (current_children.find (item, out index)) {
132+
current_children.remove (index);
133+
}
134+
}
135+
}

0 commit comments

Comments
 (0)