00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00028
00029 #include <stdio.h>
00030 #include <string.h>
00031 #include <assert.h>
00032
00033 #include <common/xmalloc.h>
00034 #include "charrenderer.h"
00035
00036
00037
00038
00039 typedef enum
00040 {
00041 ROW = 1, COL, FIELD
00042 }
00043 tag_t;
00044
00045 static tag_t cl_tagindex_[] =
00046 {
00047 ROW, COL, FIELD
00048 };
00049
00050 static dict_pair cl_tags_d[] =
00051 {
00052 { "col", &(cl_tagindex_[1]) },
00053 { "field", &(cl_tagindex_[2]) },
00054 { "row", &(cl_tagindex_[0]) }
00055 };
00056
00057 static dictionary cd_tags =
00058 { cl_tags_d, sizeof (cl_tags_d) / sizeof (dict_pair) };
00059
00060
00061 typedef enum
00062 {
00063 TYPE, ID, NAME, VALIGN, HALIGN, EXPAND
00064 }
00065 attr_t;
00066
00067 static attr_t cl_attrindex_[] =
00068 {
00069 TYPE, ID, NAME, VALIGN, HALIGN, EXPAND
00070 };
00071
00072 static dict_pair cl_attr_d[] =
00073 {
00074 { "expand", &(cl_attrindex_[5]) },
00075 { "halign", &(cl_attrindex_[4]) },
00076 { "id", &(cl_attrindex_[1]) },
00077 { "name", &(cl_attrindex_[2]) },
00078 { "type", &(cl_attrindex_[0]) },
00079 { "valign", &(cl_attrindex_[3]) }
00080 };
00081
00082 static dictionary cd_attrs =
00083 { cl_attr_d, sizeof (cl_attr_d) / sizeof (dict_pair) };
00084
00085
00086
00087
00088
00089
00090
00092 typedef enum
00093 {
00094 ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTERED
00095 }
00096 align_hor_t;
00097
00099 typedef enum
00100 {
00101 ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE
00102 }
00103 align_ver_t;
00104
00105
00106
00107
00108
00109
00111 typedef enum
00112 {
00113 CROW,
00114 CCOL,
00115 CFIELD
00116 }
00117 widget_class_t;
00118
00126 typedef struct _widget_size_hint
00127 {
00128 int width;
00129 int height;
00130 int penalty;
00135 struct _widget_size_hint **children_layout;
00136 }
00137 widget_size_hint;
00138
00139 typedef struct
00140 {
00141 widget_class_t type;
00142 slist children;
00143 slist layout_hints;
00150 int expand_x;
00151 int expand_y;
00157 align_hor_t align_hor;
00158 align_ver_t align_ver;
00161 void *data;
00162 }
00163 cl_widget;
00164
00165
00167 typedef struct
00168 {
00169 slist *list;
00170 slist_iter iter;
00171 }
00172 list_iter_pair;
00173
00174 void _widget_calc_hints (void *widget_, void *dummy);
00175
00176
00180 static void
00181 _widget_init (cl_widget *widget, widget_class_t type)
00182 {
00183 widget->type = type;
00184 slist_init (&widget->children);
00185 slist_init (&widget->layout_hints);
00186 widget->expand_x = 0;
00187 widget->expand_y = 0;
00188 widget->data = 0;
00189 }
00190
00195 static int
00196 _compare_hints (const void* _data, const void* _compare)
00197 {
00198 widget_size_hint *data = (widget_size_hint*)_data;
00199 widget_size_hint *compare = (widget_size_hint*)_compare;
00200
00201 return (data->width == compare->width && data->height == compare->height);
00202 }
00203
00206 static void
00207 _hint_init (widget_size_hint *hint)
00208 {
00209 hint->width = 0;
00210 hint->height = 0;
00211 hint->penalty = 0;
00212 hint->children_layout = 0;
00213 }
00214
00218 static widget_size_hint *
00219 _hint_dup (widget_size_hint *hint)
00220 {
00221 widget_size_hint *new_hint = xmalloc (sizeof (widget_size_hint));
00222
00223 new_hint->width = hint->width;
00224 new_hint->height = hint->height;
00225 new_hint->penalty = hint->penalty;
00226 new_hint->children_layout = 0;
00227
00228 return new_hint;
00229 }
00230
00231 void
00232 _layout_strategy_row (widget_size_hint *hint, widget_size_hint *new_hint)
00233 {
00234 if (hint->height > new_hint->height)
00235 new_hint->height = hint->height;
00236
00237 new_hint->width += hint->width;
00238 }
00239
00240 void
00241 _layout_strategy_col (widget_size_hint *hint, widget_size_hint *new_hint)
00242 {
00243 if (hint->width > new_hint->width)
00244 new_hint->width = hint->width;
00245
00246 new_hint->height += hint->height;
00247 }
00248
00249 void
00250 _widget_calc_penalties (cl_widget *widget,
00251 void(*strategy)(widget_size_hint*,
00252 widget_size_hint*))
00253 {
00254 slist_iter iter;
00255 list_iter_pair *pairs;
00256 int index_;
00257 int array_size;
00258
00259
00260 slist_for_each (&widget->children, _widget_calc_hints, 0);
00261
00262
00263
00264 array_size = slist_length (&widget->children);
00265 pairs = xmalloc (sizeof (list_iter_pair) * array_size);
00266
00267 iter = slist_begin_iter (&widget->children);
00268 index_ = 0;
00269 while (!slist_iter_at_end (iter))
00270 {
00271 cl_widget *child = (cl_widget*)slist_iter_and_next (&iter);
00272 pairs[index_].list = &child->layout_hints;
00273 pairs[index_].iter = slist_begin_iter (&child->layout_hints);
00274 ++index_;
00275 }
00276
00277
00278 for (;;)
00279 {
00280 widget_size_hint new_hint;
00281 slist_iter found;
00282
00283 _hint_init (&new_hint);
00284
00285
00286 for (index_ = 0; index_ < array_size; ++index_)
00287 {
00288 widget_size_hint *hint;
00289 hint = (widget_size_hint*)slist_at_iter (pairs[index_].iter);
00290 strategy (hint, &new_hint);
00291 new_hint.penalty += hint->penalty;
00292 }
00293
00294
00295 found = slist_find_if (&widget->layout_hints,
00296 &new_hint, _compare_hints);
00297
00298 if (slist_iter_at_end (found))
00299 {
00300 widget_size_hint *copy = _hint_dup (&new_hint);
00301 widget_size_hint **array;
00302
00303 array = xmalloc (sizeof (widget_size_hint*) * array_size);
00304 for (index_ = 0; index_ < array_size; ++index_)
00305 array[index_] = slist_at_iter (pairs[index_].iter);
00306
00307 copy->children_layout = array;
00308 slist_append (&widget->layout_hints, copy);
00309 }
00310 else
00311 {
00312 widget_size_hint *found_hint = slist_at_iter (found);
00313
00314 if (found_hint->penalty > new_hint.penalty)
00315 {
00316 widget_size_hint **array = found_hint->children_layout;
00317
00318 found_hint->penalty = new_hint.penalty;
00319 for (index_ = 0; index_ < array_size; ++index_)
00320 array[index_] = slist_at_iter (pairs[index_].iter);
00321 }
00322 }
00323
00324
00325 for (index_ = 0; index_ < array_size; ++index_)
00326 {
00327 slist_iter_and_next (&pairs[index_].iter);
00328
00329 if (slist_iter_at_end (pairs[index_].iter))
00330 pairs[index_].iter = slist_begin_iter (pairs[index_].list);
00331 else
00332 break;
00333 }
00334
00335
00336 if (index_ == array_size)
00337 break;
00338 }
00339 }
00340
00341
00342 void
00343 _widget_calc_hints (void *widget_, void *dummy)
00344 {
00345 cl_widget *widget = (cl_widget*)widget_;
00346 (void)dummy;
00347
00348 switch (widget->type)
00349 {
00350 case CROW:
00351 _widget_calc_penalties (widget, _layout_strategy_row);
00352 break;
00353
00354 case CCOL:
00355 _widget_calc_penalties (widget, _layout_strategy_col);
00356 break;
00357
00358 case CFIELD:
00359 {
00360 widget_size_hint *new_hint = xmalloc (sizeof (widget_size_hint));
00361 new_hint->width = strlen ((char*)(widget->data));
00362 new_hint->height = 1;
00363 new_hint->penalty = 0;
00364 slist_append (&widget->layout_hints, new_hint);
00365
00366 new_hint = xmalloc (sizeof (widget_size_hint));
00367 new_hint->width = strlen ((char*)(widget->data)) / 2;
00368 new_hint->height = 1;
00369 new_hint->penalty = 1;
00370 slist_append (&widget->layout_hints, new_hint);
00371
00372 new_hint = xmalloc (sizeof (widget_size_hint));
00373 new_hint->width = 0;
00374 new_hint->height = 0;
00375 new_hint->penalty = 3;
00376 slist_append (&widget->layout_hints, new_hint);
00377 }
00378 break;
00379
00380 default:
00381 assert (0);
00382 }
00383 }
00384
00385 int
00386 _widget_allocate_space (cl_widget *widget, int w, int h, int x, int y,
00387 cl_layout* layout)
00388 {
00389 widget_size_hint *best_hint = 0;
00390 unsigned int index_;
00391
00392 slist_iter iter = slist_begin_iter (&widget->layout_hints);
00393 while (!slist_iter_at_end (iter))
00394 {
00395 widget_size_hint *hint = slist_iter_and_next (&iter);
00396 if (hint->width > w || hint->height > h)
00397 continue;
00398
00399 if (best_hint == 0 || best_hint->penalty > hint->penalty)
00400 best_hint = hint;
00401 }
00402
00403 if (best_hint == 0)
00404 return 0;
00405
00406 index_ = 0;
00407 iter = slist_begin_iter (&widget->children);
00408 while (!slist_iter_at_end (iter))
00409 {
00410 cl_widget* child = slist_iter_and_next (&iter);
00411 widget_size_hint *best_layout = best_hint->children_layout[index_];
00412 _widget_allocate_space (child, best_layout->width, best_layout->height,
00413 x, y, layout);
00414
00415 switch (widget->type)
00416 {
00417 case CROW:
00418 x += best_layout->width; break;
00419 case CCOL:
00420 y += best_layout->height; break;
00421 case CFIELD:
00422 break;
00423 }
00424
00425 ++index_;
00426 }
00427
00428 if (widget->type == CFIELD)
00429 {
00430 cl_layout_elem *elem = layout->layout_data + layout->layout_data_size++;
00431 elem->x = x;
00432 elem->y = y;
00433 elem->width = w;
00434 elem->height = h;
00435 elem->utf8_data = strdup (widget->data);
00436 }
00437
00438 return 1;
00439 }
00440
00441
00442 static int
00443 _is_layout_or_field (xml_node *node)
00444 {
00445 int tag = node->tag;
00446 return tag == ROW || tag == COL || tag == FIELD;
00447 }
00448
00449
00450 static cl_widget *
00451 _parse_widget (xml_node *node)
00452 {
00453 cl_widget *result = xmalloc (sizeof (cl_widget));
00454 xml_node *iter = 0;
00455
00456 switch (node->tag)
00457 {
00458 case ROW:
00459 _widget_init (result, CROW); break;
00460 case COL:
00461 _widget_init (result, CCOL); break;
00462 case FIELD:
00463 _widget_init (result, CFIELD);
00464 result->data = strdup("Test");
00465 break;
00466 default:
00467 return 0;
00468 }
00469
00470 if (node->tag != FIELD)
00471 {
00472 while ((iter = xmlt_find_if (node, iter, _is_layout_or_field)) != 0)
00473 slist_append (&result->children, (void *)_parse_widget (iter));
00474 }
00475 return result;
00476 }
00477
00478
00479 cl_layout *
00480 cl_make_layout (xml_node *layout)
00481 {
00482 cl_widget *widgets = 0;
00483 cl_layout *result = xmalloc (sizeof (cl_layout));
00484 xml_node *node = 0;
00485
00486 assert (layout);
00487
00488 result->layout_data_size = 0;
00489 result->layout_data = xmalloc (sizeof (cl_layout_elem) * 20 * 4);
00490
00491
00492 xmlt_rescan_document (layout, &cd_tags, &cd_attrs);
00493
00494
00495 node = xmlt_find_if (layout, node, _is_layout_or_field);
00496 if (!node)
00497 return 0;
00498
00499 widgets = _parse_widget (node);
00500 _widget_calc_hints (widgets, 0);
00501 if (!_widget_allocate_space (widgets, 20, 4, 0, 0, result))
00502 printf ("Cannot fit elements.\n");
00503
00504 return result;
00505 }
00506