Small qtable fix
[gmpc.git] / src / Widgets / gmpc-widgets-qtable.vala
blob5cd5b7106e87337f10aa646e72264530e898ec61
1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3 * Project homepage: http://gmpclient.org/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 using Config;
21 using Gtk;
22 using Gmpc;
24 private const bool use_transition_gav = Gmpc.use_transition;
25 private const string some_unique_name_gav = Config.VERSION;
26 [compact]
27 private class QtableEntry
29 public enum Type
31 HEADER,
32 ITEM
34 public Type type;
35 public weak Gtk.Widget widget;
39 public class Gmpc.Widgets.Qtable : Gtk.Container, Gtk.Buildable
41 private int item_width_real = 0;
42 private int item_height_real = 0;
43 private int header_height_real = 0;
44 private int max_columns_real = 0;
45 private int num_items = 0;
46 private int columns = 3;
47 public int spacing {get; set; default=8;}
48 public int padding_left {get; set; default=0;}
49 public int padding_right {get; set; default=0;}
51 public int max_columns
53 get {
54 return max_columns_real;
56 set {
57 max_columns_real = value;
58 this.queue_resize();
62 public int item_width
64 get {
65 return item_width_real;
67 set {
68 item_width_real = value;
69 this.queue_resize();
73 public int item_height
75 get {
76 return item_height_real;
78 set {
79 item_height_real = value;
80 this.queue_resize();
83 public int header_height
85 get {
86 return header_height_real;
88 set {
89 header_height_real = value;
90 this.queue_resize();
95 private List<QtableEntry> children = null;
96 /* GtkBuildable override */
97 public void add_child(Gtk.Builder build, GLib.Object child, string? type)
99 if(!(child is Gtk.Widget))
101 GLib.warning("Trying to add non widget");
102 return;
104 if(type != null && type == "header")
106 add_header(child as Gtk.Widget);
108 else
110 add(child as Gtk.Widget);
115 construct
117 this.set_has_window(false);
118 this.set_redraw_on_allocate(false);
121 public Qtable()
123 // Set resize mode.
124 this.resize_mode = Gtk.ResizeMode.QUEUE;
128 * Calculates the size of the widget.
130 public override void get_preferred_height_for_width(int actual_width, out int min_height, out int nat_height)
132 int cover_width = item_width_real;
133 int cover_height= item_height_real;
134 int header_height = header_height_real;
135 int items = 0, width=0;
138 /* determine max width/height */
139 foreach ( var child in children)
141 if(child.widget.get_visible())
143 int w,h;
144 if(child.type == QtableEntry.Type.ITEM)
146 Gtk.Requisition cr = {0,0};
147 child.widget.get_preferred_size(null, out cr);
148 cover_width = int.max(cr.width,cover_width);
149 cover_height = int.max(cr.height,cover_height);
151 else
153 Gtk.Requisition cr = {0,0};
154 child.widget.get_preferred_size(null, out cr);
155 width = int.max(cr.width,width);
156 header_height = int.max(cr.height,header_height);
160 if(spacing>0)
162 cover_width += spacing;
163 cover_height += spacing;
164 header_height += spacing;
166 columns = int.max(actual_width/cover_width,1);
167 if(max_columns_real > 0)
169 columns = int.min(columns,max_columns_real);
171 int rows = 0;
172 foreach ( var child in children)
174 if(child.widget.get_visible())
176 if(child.type == QtableEntry.Type.ITEM)
178 items++;
180 else
182 if(items != 0)
184 int nrows = items/columns;
185 int remain = (items%columns >0)?1:0;
186 rows += (nrows+remain)*cover_height;
188 items = 0;
189 rows+=header_height;
193 if(items != 0)
195 int nrows = items/columns;
196 int remain = (items%columns >0)?1:0;
197 rows = rows + (nrows+remain)*cover_height;
199 /* Width of one column */
200 min_height = rows;
201 nat_height = rows;
204 public override void add(Gtk.Widget widget)
206 if(widget != null)
208 QtableEntry a = new QtableEntry();
209 a.type = QtableEntry.Type.ITEM;
210 a.widget = widget;
211 children.append(a);
212 widget.set_parent(this);
213 num_items++;
214 this.queue_resize();
217 public void add_header(Gtk.Widget widget)
219 if(widget != null)
221 QtableEntry a = new QtableEntry();
222 a.type = QtableEntry.Type.HEADER;
223 a.widget = widget;
224 children.append(a);
225 widget.set_parent(this);
226 num_items++;
227 this.queue_resize();
231 public override GLib.Type child_type()
233 return typeof(Gtk.Widget);
235 public override void remove(Gtk.Widget widget)
237 if(widget != null )
239 QtableEntry a = null;
241 if((a = children.find_custom(widget,compare)) == null) {
242 GLib.error("Failed to find widget in container");
245 foreach(QtableEntry f in this.children)
247 if(f.widget == widget)
249 a = f;
250 break;
253 if(a == null)
254 GLib.error("Failed to find widget in container");
255 bool visible = widget.get_visible();
256 widget.unparent();
258 /* owned is needed to avoid leak */
259 children.remove((owned)a);
260 num_items--;
261 if(visible)
262 this.queue_resize();
265 public override void size_allocate(Gtk.Allocation alloc)
267 int cover_width = item_width_real;
268 int cover_height= item_height_real;
269 int header_height = header_height_real;
270 /* Hack to avvoid pointless resizes,
271 * I get this "1" size when a child widget changes */
272 if(alloc.width == 1) return;
273 int width = alloc.width;
274 int new_columns = 0;
275 int rows = 0;
276 int item = 0;
277 // This fixes it so the correct taborder is calculated.
278 this.set_allocation(alloc);
279 foreach ( var child in children)
281 if(child.widget.get_visible())
284 if(child.type == QtableEntry.Type.ITEM)
286 Gtk.Requisition cr = {0,0};
287 child.widget.get_preferred_size(null, out cr);
288 cover_width = int.max(cr.width,cover_width);
289 cover_height = int.max(cr.height,cover_height);
290 item++;
292 else
294 Gtk.Requisition cr = {0,0};
295 child.widget.get_preferred_size(null, out cr);
296 item = 0;
298 width = int.max(cr.width,width);
299 header_height = int.max(cr.height,header_height);
303 if(spacing>0)
305 cover_width += spacing;
306 cover_height += spacing;
307 header_height += spacing;
309 new_columns = int.max((width-padding_left - padding_right+spacing)/cover_width, 1);
310 if(max_columns_real > 0)
312 new_columns = int.min(new_columns,max_columns_real);
315 item = 0;
316 foreach ( var child in children)
318 if(child.widget.get_visible())
320 if(child.type == QtableEntry.Type.ITEM)
322 Gtk.Allocation ca = {0,0,0,0};
323 ca.x = alloc.x + (item%new_columns)*cover_width+padding_left;
324 ca.y = rows+alloc.y + (item/new_columns)*cover_height;
325 ca.width = cover_width - spacing;
326 ca.height = cover_height - spacing;
328 child.widget.size_allocate(ca);
329 item++;
331 else
333 if(item != 0)
335 int nrows = item/new_columns;
336 int remain = (item%new_columns >0)?1:0;
337 rows = rows + (nrows+remain)*cover_height;
339 item = 0;
341 Gtk.Allocation ca = {0,0,0,0};
342 ca.x = alloc.x-padding_left;
343 ca.y = alloc.y+rows;
344 ca.width = cover_width*new_columns;
345 ca.height = header_height - spacing;
347 child.widget.size_allocate(ca);
348 rows+=header_height;
352 if(new_columns != columns)
354 columns = new_columns;
355 this.queue_resize();
358 public override void forall_internal(bool include_internals,
359 Gtk.Callback callback)
361 weak List<QtableEntry> iter = children.first();
362 /* Somehow it fails when doing a foreach() construction,
363 weird vala bug I guess */
364 /* would be nice if I could filter out say only the visible ones */
365 while(iter != null)
367 weak QtableEntry child = iter.data;
368 iter = iter.next;
369 callback(child.widget);
372 public void clear()
374 foreach(var a in children)
376 a.widget.unparent();
377 num_items--;
379 children = null;
380 this.queue_resize();
384 public override Gtk.SizeRequestMode get_request_mode ()
386 return Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH;