|
6 | 6 | */ |
7 | 7 |
|
8 | 8 | public class Dock.ItemGroup : Gtk.Fixed { |
| 9 | + private const string OBJECT_DATA_KEY = "item-group-obj"; |
| 10 | + |
| 11 | + [CCode (has_target = false)] |
| 12 | + public delegate BaseItem CreateBaseItemFunc (Object obj); |
| 13 | + |
9 | 14 | private static Settings settings; |
10 | 15 |
|
11 | 16 | public ListModel items { get; construct; } |
| 17 | + public CreateBaseItemFunc create_item_func { get; construct; } |
12 | 18 |
|
13 | 19 | private Sequence<BaseItem> item_store; |
14 | 20 | private ListStore current_children; |
|
17 | 23 |
|
18 | 24 | private bool relayout_queued = false; |
19 | 25 |
|
20 | | - public ItemGroup (ListModel items) { |
21 | | - Object (items: items); |
| 26 | + private HashTable<Object, BaseItem> cached_items; |
| 27 | + private uint clear_cache_id = 0; |
| 28 | + |
| 29 | + public ItemGroup (ListModel items, CreateBaseItemFunc create_item_func) { |
| 30 | + Object (items: items, create_item_func: create_item_func); |
22 | 31 | } |
23 | 32 |
|
24 | 33 | static construct { |
|
42 | 51 | on_items_changed (0, 0, items.get_n_items ()); |
43 | 52 |
|
44 | 53 | overflow = VISIBLE; |
| 54 | + |
| 55 | + cached_items = new HashTable<Object, BaseItem> (null, null); |
45 | 56 | } |
46 | 57 |
|
47 | 58 | private void queue_relayout () { |
|
87 | 98 | private void on_items_changed (uint position, uint removed, uint added) { |
88 | 99 | var start_iter = item_store.get_iter_at_pos ((int) position); |
89 | 100 | var end_iter = start_iter.move ((int) removed); |
| 101 | + start_iter.foreach_range (end_iter, cache_item); |
90 | 102 | start_iter.foreach_range (end_iter, remove_item); |
91 | 103 | start_iter.remove_range (end_iter); |
92 | 104 |
|
93 | 105 | var insert_iter = item_store.get_iter_at_pos ((int) position); |
94 | 106 | for (int i = (int) position; i < position + added; i++) { |
95 | | - var item = (BaseItem) items.get_item (i); |
| 107 | + var item = get_or_create_item (items.get_item (i)); |
96 | 108 | insert_iter.insert_before (item); |
97 | 109 |
|
98 | 110 | add_item (i, item); |
99 | 111 | } |
100 | 112 | } |
101 | 113 |
|
| 114 | + // Make sure that if an item is removed and added again in the same |
| 115 | + // mainloop iteration it gets mapped to the same BaseItem |
| 116 | + private void cache_item (BaseItem item) { |
| 117 | + cached_items[item.get_data<Object> (OBJECT_DATA_KEY)] = item; |
| 118 | + |
| 119 | + if (clear_cache_id == 0) { |
| 120 | + clear_cache_id = Idle.add_once (clear_cache); |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + private void clear_cache () { |
| 125 | + cached_items.remove_all (); |
| 126 | + clear_cache_id = 0; |
| 127 | + } |
| 128 | + |
| 129 | + private BaseItem get_or_create_item (Object obj) { |
| 130 | + if (obj in cached_items) { |
| 131 | + return cached_items[obj]; |
| 132 | + } |
| 133 | + |
| 134 | + var base_item = create_item_func (obj); |
| 135 | + base_item.set_data<Object> (OBJECT_DATA_KEY, obj); |
| 136 | + return base_item; |
| 137 | + } |
| 138 | + |
102 | 139 | private void add_item (int pos, BaseItem item) { |
103 | 140 | if (item.parent == this) { |
104 | 141 | // The item was already in this group and is currently being removed |
|
119 | 156 | private void remove_item (BaseItem item) { |
120 | 157 | item.revealed_done.connect (finish_remove); |
121 | 158 | item.set_revealed (false); |
| 159 | + |
| 160 | + cached_items[item.get_data<Object> ("dock-obj")] = item; |
122 | 161 | } |
123 | 162 |
|
124 | 163 | private void finish_remove (BaseItem item) { |
|
0 commit comments