3 require 'booh/booh-lib'
8 "width:#{width} heigth:#{height}"
12 class Gtk::AutoTable < Gtk::VBox
14 def initialize(row_spacings)
19 @row_spacings = row_spacings
23 signal_connect('size-allocate') { |w, allocation|
24 msg 3, "got self allocation: #{allocation}"
25 if @width != allocation.width
26 if !@old_widths.include?(allocation.width)
27 @width = allocation.width
28 @old_widths.unshift(@width)
29 @old_widths = @old_widths[0..2]
32 msg 3, "\tDISABLING: #{allocation.width} - #{@old_widths.join(',')}"
36 @timeout = Gtk.timeout_add(100) {
47 Gtk.timeout_remove(@timeout)
51 #- add (append) a widget to the list of automatically handled widgets
52 def append(widget, name)
53 #- create my child hash
54 child = { :widget => widget, :name => name }
55 #- put it in the table if last container's widget has been allocated
56 last_container = @containers[-1]
57 if !last_container || last_container[:contained_element] && last_container[:contained_element][:allocation]
58 put(child, (last_container ? last_container[:x] : -1) + 1, last_container ? last_container[:y] : 0)
60 #- add it to the internal children array
63 #- connect 'size-allocate' signal to be sure to update allocation when received
64 widget.signal_connect('size-allocate') { |w, allocation|
65 msg 3, "got allocation for #{w.hash}: #{allocation} (#{allocation.hash})"
66 chld = @children.find { |e| e[:widget] == w }
68 old = chld[:allocation]
69 #- need to copy values because the object will be magically exploded when widget is removed
70 chld[:allocation] = { :width => allocation.width, :height => allocation.height }
71 if !old #|| old[:width] != allocation.width # || old[:height] != allocation.height
72 msg 3, "redistribute!"
73 chld == @children[0] && old and msg 3, "************ old was #{old[:width]} #{old[:height]}"
77 warn "Critical: child not found!"
82 #- remove a widget from the list of automatically handled widgets
84 @children.each_with_index { |chld, index|
85 if chld[:widget] == widget
86 @children.delete_at(index)
94 #- re-insert a widget at a given pos
95 def reinsert(pos, widget, name)
96 child = { :widget => widget, :name => name }
97 @children[pos, 0] = child
101 #- remove all widgets
107 #- get current order of widget
109 return @children.collect { |chld| chld[:name] }
112 #- get current [x, y] position of widget within automatically handled table
113 def get_current_pos(widget)
114 chld = @children.find { |e| e[:widget] == widget }
116 return [ chld[:x], chld[:y] ]
122 #- get current number (rank in current ordering) of widget within automatically handled table
123 def get_current_number(widget)
124 @children.each_with_index { |chld, index|
125 if chld[:widget] == widget
132 #- move widgets by numbers
135 chld = @children.delete_at(src)
136 @children[dst > src ? dst - 1 : dst, 0] = chld
141 #- get widget at [x, y] position of automatically handled table
142 def get_widget_at_pos(x, y)
143 @children.each { |chld|
144 if chld[:x] == x && chld[:y] == y
151 #- get maximum `y' position within the automatically handled table
153 return @children[-1][:y]
156 #- get the current `previous' widget (table-wise); important since widgets can be reordered with mouse drags
157 def get_previous_widget(widget)
158 @children.each_with_index { |chld, index|
159 if chld[:widget] == widget
163 return @children[index - 1][:widget]
170 #- get the current `next' widget (table-wise); important since widgets can be reordered with mouse drags
171 def get_next_widget(widget)
172 @children.each_with_index { |chld, index|
173 if chld[:widget] == widget
174 if index == @children.size - 1
177 return @children[index + 1][:widget]
184 #- move specified widget `up' in the table
186 @children.each_with_index { |chld, index|
187 if chld[:widget] == widget && chld[:y] > 0
188 @children.each_with_index { |chld2, index2|
189 if chld2[:x] == chld[:x] && chld[:y] == chld2[:y] + 1
190 @children[index], @children[index2] = chld2, chld
200 #- move specified widget `down' in the table
201 def move_down(widget)
202 @children.each_with_index { |chld, index|
203 if chld[:widget] == widget && chld[:y] < get_max_y
204 @children.each_with_index { |chld2, index2|
205 if chld2[:x] == chld[:x] && chld[:y] == chld2[:y] - 1
206 @children[index], @children[index2] = chld2, chld
216 #- move specified widget `left' in the table
217 def move_left(widget)
218 @children.each_with_index { |chld, index|
219 if chld[:widget] == widget && chld[:x] > 0
220 @children[index], @children[index - 1] = @children[index - 1], @children[index]
228 #- move specified widget `right' in the table
229 def move_right(widget)
230 @children.each_with_index { |chld, index|
231 if chld[:widget] == widget && @children[index + 1] && chld[:x] < @children[index + 1][:x]
232 @children[index], @children[index + 1] = @children[index + 1], @children[index]
243 def put(element, x, y)
244 msg 3, "putting #{element[:widget].hash} at #{x},#{y}"
247 container = @containers.find { |e| e[:x] == x && e[:y] == y }
249 container = { :x => x, :y => y, :widget => Gtk::VBox.new, :fake => Gtk::Label.new('fake') }
250 msg 3, "attaching at #{x},#{y}"
251 @table.attach(container[:widget], x, x + 1, y, y + 1, Gtk::FILL, Gtk::FILL, 5, 0)
252 @containers << container
254 if container[:contained_element]
255 container[:widget].remove(container[:contained_element][:widget])
257 container[:contained_element] = element
258 container[:widget].add(element[:widget])
263 @containers.each { |e|
264 if e[:contained_element]
265 e[:widget].remove(e[:contained_element][:widget])
273 add(@table = Gtk::Table.new(0, 0, true))
274 @table.set_row_spacings(@row_spacings)
277 def redistribute(force)
278 msg 3, "redistribute: "
279 @children.each { |e| msg_ 3, e[:allocation] ? 'O' : '.' }; msg 3, ''
280 if unallocated = @children.find { |e| !e[:allocation] }
281 #- waiting for allocations. replace last displayed widget with first unallocated.
282 last_container = @containers[-1]
283 put(unallocated, last_container[:x], last_container[:y])
286 if @children.size == 0
291 totalwidth = allocation.width
292 maxwidth = @children.collect { |chld| chld[:allocation][:width] }.max
293 xpix = 5 + maxwidth + 5
296 @children[1..-1].each { |e|
297 if xpix + 5 + maxwidth + 5 > totalwidth - 1
305 xpix += 5 + maxwidth + 5
307 if @children[1..-1].find { |e| e[:xnew] != e[:x] || e[:ynew] != e[:y] } || force
308 msg 3, "I can proceed with #{allocation}"
310 put(@children[0], 0, 0)
311 @children[1..-1].each { |e|
312 put(e, e[:xnew], e[:ynew])