1#include <cgv/gui/layout_table.h>
3#include <cgv/type/variant.h>
59 layout_table::layout_table()
65 do_not_layout =
false;
76 do_not_layout =
false;
80 layout_table::~layout_table()
82 delete_space_tables();
86 void layout_table::delete_space_tables()
100 void layout_table::initialize_space_tables()
102 int opt_width, opt_height, min_width, min_height, hints;
106 columns =
new layout_table_cell[nr_cols];
107 rows =
new layout_table_cell[nr_rows];
111 for (
int c=0; c<nr_cols; c++)
113 for (
int r=0; r<nr_rows; r++)
116 for (
int r=0; r<nr_rows; r++)
117 for (
int c=0; c<nr_cols; c++) {
121 get_child_default_size(cur_child, opt_width, opt_height);
122 get_child_minimum_size(cur_child, min_width, min_height);
123 hints = get_child_layout_hints(cur_child);
125 update_spaces_table(columns[c], opt_width, min_width, hints, LH_HHINTS);
126 update_spaces_table(rows[r], opt_height, min_height, hints, LH_VHINTS);
133 void layout_table::update()
135 int opt_cwidth, opt_cheight, min_cwidth, min_cheight, chints;
136 int opt_width, opt_height;
137 int min_width, min_height;
138 int border_width, border_height;
139 int new_cwidth, new_cheight;
140 int realized_cwidth, realized_cheight;
141 bool is_wrong_size, need_relayout;
142 int pos_x, pos_y, pos_x_offset, pos_y_offset;
145 if (do_not_layout || !container || !container->get_nr_children() || !nr_cols || !nr_rows)
151 is_wrong_size =
false;
154 border_width = spacings.horizontal.element*(nr_cols-1) + spacings.horizontal.border*2;
155 border_height = spacings.vertical.element*(nr_rows-1) + spacings.vertical.border*2;
159 initialize_space_tables();
161 int num_relayouts = 100;
166 need_relayout =
false;
169 get_sizes(columns, nr_cols, &opt_width, &min_width);
170 get_sizes(rows, nr_rows, &opt_height, &min_height);
173 opt_width+=border_width;
174 min_width+=border_width;
175 opt_height+=border_height;
176 min_height+=border_height;
179 if (min_width > true_w) {
180 is_wrong_size =
true;
183 if (min_height > true_h) {
184 is_wrong_size =
true;
190 distribute_space(columns, nr_cols, true_w - border_width);
191 distribute_space(rows, nr_rows, true_h - border_height);
193 for (
int r=0; r<nr_rows; r++) {
194 for (
int c=0; c<nr_cols; c++) {
197 get_child_default_size(cur_child, opt_cwidth, opt_cheight);
198 get_child_minimum_size(cur_child, min_cwidth, min_cheight);
199 chints = get_child_layout_hints(cur_child);
203 calculate_child_size(columns[c], opt_cwidth, min_cwidth, chints, LH_HHINTS, new_cwidth);
204 calculate_child_size(rows[r], opt_cheight, min_cheight, chints, LH_VHINTS, new_cheight);
207 set_child_size(cur_child, new_cwidth, new_cheight);
210 get_child_size(cur_child, realized_cwidth, realized_cheight);
215 if (realized_cwidth > columns[c].real_size) {
216 if (columns[c].min_size < realized_cwidth)
217 columns[c].min_size = realized_cwidth;
218 if (columns[c].opt_size < columns[c].min_size)
219 columns[c].opt_size = columns[c].min_size;
221 cur_child->set<
int>(
"mw", realized_cwidth);
223 is_wrong_size =
true;
224 need_relayout =
true;
228 if (realized_cheight > rows[r].real_size) {
229 if (rows[r].min_size < realized_cheight)
230 rows[r].min_size = realized_cheight;
231 if (rows[r].opt_size < rows[r].min_size)
232 rows[r].opt_size = rows[r].min_size;
234 cur_child->set<
int>(
"mh", realized_cheight);
235 is_wrong_size =
true;
236 need_relayout =
true;
241 }
while(need_relayout && num_relayouts>0);
243 if (num_relayouts == 0) {
244 std::cerr<<
"layout_table stopped layouting the GUI because the maximum number of layouting iterations"<<std::endl;
245 std::cerr<<
"was reached. This is probably a bug in the layouter."<<std::endl;
249 pos_y = spacings.vertical.border;
251 for (
int r=0; r<nr_rows; r++) {
252 pos_x = spacings.horizontal.border;
253 for (
int c=0; c<nr_cols; c++) {
256 get_child_size(cur_child, opt_cwidth, opt_cheight);
257 chints = get_child_layout_hints(cur_child);
259 calculate_child_pos(columns[c], opt_cwidth, chints, LH_HHINTS, pos_x_offset);
260 calculate_child_pos(rows[r], opt_cheight, chints, LH_VHINTS, pos_y_offset);
262 set_child_position(cur_child, pos_x + pos_x_offset, pos_y + pos_y_offset);
264 pos_x+=columns[c].real_size + spacings.horizontal.element;
266 pos_y+=rows[r].real_size + spacings.vertical.element;
270 do_not_layout =
true;
275 repair_default_values(min_width, min_height,
276 opt_width, opt_height);
279 container->set<
int>(
"w", true_w);
280 container->set<
int>(
"h", true_h);
282 do_not_layout =
false;
288 void layout_table::repair_default_values(
int min_width,
int min_height,
int opt_width,
int opt_height)
290 int cur_dwidth, cur_dheight;
293 container->set<
int>(
"mw", min_width);
294 container->set<
int>(
"mh", min_height);
297 get_child_default_size(container, cur_dwidth, cur_dheight);
298 int hints = get_child_layout_hints(container);
303 if ((hints & LH_HEXPAND) || (hints & LH_HFILL))
304 container->set<
int>(
"dw", opt_width);
305 else if (min_width > cur_dwidth)
306 container->set<
int>(
"dw", min_width);
308 if ((hints & LH_VEXPAND) || (hints & LH_HEXPAND))
309 container->set<
int>(
"dh", opt_height);
310 else if (min_height > cur_dheight)
311 container->set<
int>(
"dh", min_height);
317 void layout_table::calculate_child_size(layout_table_cell &element,
int opt_size,
int min_size,
int hints,
int hints_shift,
int &new_size)
321 if (element.real_size > opt_size && ((hints & (LH_HFILL<<hints_shift)) || (hints & (LH_HEXPAND<<hints_shift))))
322 new_size = element.real_size;
325 if ((hints & (LH_HSHRINK<<hints_shift)) && (element.real_size<opt_size))
327 if (element.real_size >= min_size)
328 new_size = element.real_size;
336 void layout_table::calculate_child_pos(layout_table_cell &element,
int child_size,
int hints,
int hints_shift,
int &new_pos)
341 if (element.real_size <= child_size)
346 if ((hints & (LH_RIGHT<<hints_shift)))
347 new_pos = element.real_size - child_size;
350 if ((hints & (LH_CENTER<<hints_shift))) {
351 new_pos = (element.real_size - child_size)/2;
359 void layout_table::update_spaces_table(layout_table_cell &element,
int opt_size,
int min_size,
int hints,
int hints_shift)
362 if (opt_size > element.opt_size)
363 element.opt_size = opt_size;
367 if (!(hints & (LH_HSHRINK << hints_shift)))
369 if (min_size > element.min_size)
370 element.min_size = min_size;
371 if (element.opt_size < element.min_size)
372 element.opt_size = element.min_size;
376 if (hints & (LH_HFILL << hints_shift))
377 element.can_fill =
true;
379 if (hints & (LH_HSHRINK << hints_shift))
380 element.can_shrink =
true;
382 if (hints & (LH_HEXPAND << hints_shift))
383 element.can_expand =
true;
388 void layout_table::get_sizes(layout_table_cell *elements,
int nr_elements,
int *opt_size,
int *min_size)
392 for (
int i=0; i<nr_elements; i++)
393 (*opt_size)+=elements[i].opt_size;
398 for (
int i=0; i<nr_elements; i++)
399 (*min_size)+=elements[i].min_size;
406 bool layout_table::distribute_space(layout_table_cell *elements,
int nr_elements,
int new_size)
414 get_sizes(elements, nr_elements, &opt_size, NULL);
415 for (
int i=0; i<nr_elements; i++)
416 elements[i].real_size = elements[i].opt_size;
421 if (new_size >= opt_size) {
422 int remain_space = new_size - opt_size;
426 int expand_space = 0;
427 for (
int i=0; i<nr_elements; i++) {
428 if (elements[i].can_fill)
429 fill_space+=elements[i].opt_size;
430 if (elements[i].can_expand)
431 expand_space+=elements[i].opt_size;
437 for (
int i=0; i<nr_elements; i++)
438 if (elements[i].can_fill)
439 elements[i].real_size+=elements[i].opt_size*remain_space/fill_space;
446 if (expand_space > 0) {
447 for (
int i=0; i<nr_elements; i++)
448 if (elements[i].can_expand)
449 elements[i].real_size+=elements[i].opt_size*remain_space/expand_space;
455 for (
int i=0; i<nr_elements; i++)
456 elements[i].real_size+=elements[i].opt_size*remain_space/opt_size;
462 if (new_size < opt_size) {
465 get_sizes(elements, nr_elements, NULL, &min_size);
469 if (min_size>new_size) {
474 int shrink_size = opt_size - min_size;
476 int overfl_size = opt_size - new_size;
480 for (
int i=0; i<nr_elements; i++)
481 if (elements[i].can_shrink) {
482 elements[i].real_size-= (elements[i].opt_size - elements[i].min_size)*overfl_size/shrink_size;
483 shrunk+=(elements[i].opt_size - elements[i].min_size)*overfl_size/shrink_size;
489 if (shrunk != overfl_size)
490 for (
int i=0; i<nr_elements; i++)
491 if (elements[i].can_shrink && elements[i].real_size > elements[i].min_size) {
492 elements[i].real_size--;
502 std::string layout_table::get_property_declarations()
504 return layout::get_property_declarations()+
";cols:int32;rows:int32";
508 bool layout_table::set_void(
const std::string& property,
const std::string& value_type,
const void* value_ptr)
510 if (layout::set_void(property, value_type, value_ptr))
513 if (property ==
"cols")
515 else if (property ==
"rows")
524 bool layout_table::get_void(
const std::string& property,
const std::string& value_type,
void* value_ptr)
526 if (layout::get_void(property, value_type, value_ptr))
529 if (property ==
"cols")
530 cgv::type::set_variant(nr_cols, value_type, value_ptr);
531 else if (property ==
"rows")
532 cgv::type::set_variant(nr_rows, value_type, value_ptr);
540 int layout_table::get_column_width(
int col)
542 if (col<nr_cols && columns)
543 return columns[col].min_size;
549 int layout_table::get_row_height(
int row)
551 if (row<nr_rows && rows)
552 return rows[row].min_size;
558 void layout_table::get_cell_size(
int row,
int col,
int &width,
int &height)
560 width = get_column_width(col);
561 height = get_row_height(row);
static T get(const std::string &value_type, const void *value_ptr)
convert the value pointed to by value_ptr of type value_type to type T and return it