Minor syntactical changes for readability.
[xuni.git] / src / widget / listbox.c
blob392c8214c287ad142d6edbb59992d8d916a295d8
1 /*! \file listbox.c
3 */
5 #include <string.h>
7 #include "../graphics.h"
8 #include "../error.h"
9 #include "../memory.h"
10 #include "widgets.h"
11 #include "dump.h"
12 #include "listbox.h"
13 #include "box.h"
14 #include "label.h"
15 #include "scrollbar.h"
16 #include "panel.h"
18 static void resize_listbox_view(struct xuni_t *xuni, struct widget_t *widget,
19 enum scrollbar_use_t scroll);
20 static void enable_scrollbar(struct xuni_t *xuni, struct widget_t *widget,
21 enum scrollbar_use_t scroll);
22 static void check_scrollbars(struct xuni_t *xuni, struct widget_t *widget);
23 static int check_vertical_scrollbar(struct widget_t *widget);
24 static int check_horizontal_scrollbar(struct widget_t *widget);
26 static void calculate_vertical_scrollbar_max(struct xuni_t *xuni,
27 struct widget_t *widget);
28 static void calculate_horizontal_scrollbar_max(struct xuni_t *xuni,
29 struct widget_t *widget);
31 static void free_listbox(struct xuni_t *xuni, struct widget_t *widget);
32 static void reposition_listbox(struct xuni_t *xuni, struct widget_t *widget);
33 static void rescale_listbox(struct xuni_t *xuni, struct widget_t *widget);
34 static void paint_listbox(struct xuni_t *xuni, struct widget_t *widget);
36 void listbox_widget_event(struct xuni_t *xuni, struct widget_t *widget,
37 enum widget_event_t event) {
39 static void (*function[])(struct xuni_t *xuni, struct widget_t *widget)
40 = {
42 free_listbox,
44 paint_listbox,
45 reposition_listbox,
46 rescale_listbox
49 call_widget_event_func(xuni, widget, event, function,
50 sizeof(function) / sizeof(*function));
53 double real_scale_width(struct widget_t *widget) {
54 double w = 1.0;
56 if(!widget) return 100.0;
58 w *= widget->pos->scale.w / 100.0;
59 if(widget->base) w *= real_scale_width(widget->base);
61 return w;
64 double real_scale_height(struct widget_t *widget) {
65 double h = 1.0;
67 if(!widget) return 100.0;
69 h *= widget->pos->scale.h / 100.0;
70 if(widget->base) h *= real_scale_height(widget->base);
72 return h;
75 double calculate_scrollbar_width(struct widget_t *widget,
76 struct xuni_t *xuni) {
78 double ratio;
80 ratio = (widget->pos->scale.w / 100.0 * xuni->smode->screen->w)
81 / (widget->pos->scale.h / 100.0 * xuni->smode->screen->h);
83 return (100.0 / 15.0) / (real_scale_width(widget));
86 double calculate_scrollbar_height(struct widget_t *widget,
87 struct xuni_t *xuni) {
89 return (100.0 / 15.0) / (real_scale_height(widget));
92 void init_listbox(struct widget_t *widget, struct xuni_t *xuni,
93 enum scrollbar_use_t allow, enum scrollbar_use_t force) {
95 double width = calculate_scrollbar_width(widget, xuni);
96 double height = calculate_scrollbar_height(widget, xuni);
97 double boxsize = get_box_width(xuni, xuni->theme->current);
98 double boxsizeh = get_box_height(xuni, xuni->theme->current);
99 int w = 0, h = 0;
101 boxsize /= real_scale_width(widget);
102 boxsizeh /= real_scale_height(widget);
104 /*printf("%f %f\n", boxsize, boxsizeh);*/
106 if(force & SCROLLBAR_USE_VERTICAL) w = width;
107 if(force & SCROLLBAR_USE_HORIZONTAL) h = height;
109 widget->type = WIDGET_LISTBOX;
110 widget->p.listbox = xuni_memory_allocate(sizeof(*widget->p.listbox));
112 /* make sure anything that is forced is allowed */
113 allow |= force;
115 widget->p.listbox->scroll.allow = allow;
116 widget->p.listbox->scroll.force = force;
117 widget->p.listbox->scroll.current = force;
119 widget->p.listbox->maxwidth = 0;
120 /*widget->p.listbox->yclip = 0;*/
122 add_allocate_widget_compose(widget, "listbox area");
124 init_widget_pos(last_compose_widget(widget),
125 0, 0, 100.0 - w, 100.0 - h, POS_PACK_NONE);
126 init_box(last_compose_widget(widget), BOX_STYLE_ALWAYSIN, 0);
127 last_compose_widget(widget)->visibility &= ~WIDGET_VISIBILITY_INDEPENDENT;
129 add_allocate_widget_compose(widget, "listbox vertical scrollbar");
131 init_widget_pos(last_compose_widget(widget),
132 100.0 - width, 0, width, 100.0 - h, POS_PACK_NONE);
133 init_scrollbar(last_compose_widget(widget), xuni, widget->pos->scale.h,
134 SCROLLBAR_ORIENTATION_VERTICAL);
135 if((force & SCROLLBAR_USE_VERTICAL) == 0) {
136 last_compose_widget(widget)->visibility
137 &= ~WIDGET_VISIBILITY_VISIBLE;
140 add_allocate_widget_compose(widget, "listbox horizontal scrollbar");
142 init_widget_pos(last_compose_widget(widget),
143 0, 100.0 - height, 100.0 - w, height, POS_PACK_NONE);
144 init_scrollbar(last_compose_widget(widget), xuni, widget->pos->scale.h,
145 SCROLLBAR_ORIENTATION_HORIZONTAL);
146 if((force & SCROLLBAR_USE_HORIZONTAL) == 0) {
147 last_compose_widget(widget)->visibility
148 &= ~WIDGET_VISIBILITY_VISIBLE;
151 add_allocate_widget_compose(widget, "listbox data");
153 init_widget_pos(last_compose_widget(widget), boxsize, boxsizeh,
154 100.0 - boxsize * 2 - w, 100.0 - boxsizeh * 2 - h, POS_PACK_NONE);
155 init_panel(last_compose_widget(widget));
156 last_compose_widget(widget)->visibility &= ~WIDGET_VISIBILITY_INDEPENDENT;
158 last_compose_widget(widget)->visibility &= ~WIDGET_VISIBILITY_NOT_COMPOSE;
160 widget->visibility &= ~WIDGET_VISIBILITY_NOT_COMPOSE;
163 /*static void enable_one_scrollbar(struct widget_t *widget,
164 enum scrollbar_use_t scroll, enum scrollbar_use_t which) {
166 if((scroll & which) != (widget->p.listbox->scroll.current & which)) {
167 set_bit_p(&widget->compose->widget[WID_LI scroll & which
170 set_bit_p(&widget->p.listbox->scroll.current, which, scroll & which);
173 static void resize_listbox_view(struct xuni_t *xuni, struct widget_t *widget,
174 enum scrollbar_use_t scroll) {
176 double width = calculate_scrollbar_width(widget, xuni);
177 double height = calculate_scrollbar_height(widget, xuni);
178 double boxsize = get_box_width(xuni, xuni->theme->current);
179 double boxsizeh = get_box_height(xuni, xuni->theme->current);
180 int w = 0, h = 0;
182 boxsize /= real_scale_width(widget);
183 boxsizeh /= real_scale_height(widget);
185 if(scroll & SCROLLBAR_USE_VERTICAL) w = width;
186 if(scroll & SCROLLBAR_USE_HORIZONTAL) h = height;
188 /* make sure anything that is forced is allowed */
189 scroll |= widget->p.listbox->scroll.force;
191 init_widget_pos(widget->compose->widget[WID_LISTBOX_BOX],
192 0, 0, 100.0 - w, 100.0 - h, POS_PACK_NONE);
194 init_widget_pos(widget->compose->widget[WID_LISTBOX_VSCROLL],
195 100.0 - width, 0, width, 100.0 - h, POS_PACK_NONE);
197 init_widget_pos(widget->compose->widget[WID_LISTBOX_HSCROLL],
198 0, 100.0 - height, 100.0 - w, height, POS_PACK_NONE);
200 init_widget_pos(widget->compose->widget[WID_LISTBOX_DATA],
201 boxsize, boxsizeh,
202 100.0 - boxsize * 2 - w, 100.0 - boxsizeh * 2 - h, POS_PACK_NONE);
204 widget_compose_event(xuni, widget->compose->widget[WID_LISTBOX_DATA],
205 WIDGET_EVENT_RESCALE);
208 static void enable_scrollbar(struct xuni_t *xuni, struct widget_t *widget,
209 enum scrollbar_use_t scroll) {
211 scroll |= widget->p.listbox->scroll.force;
213 /*printf("Set scroll = v:%i h:%i\n", scroll & SCROLLBAR_USE_VERTICAL,
214 scroll & SCROLLBAR_USE_HORIZONTAL);*/
216 if((scroll & SCROLLBAR_USE_VERTICAL)
217 != (widget->p.listbox->scroll.current & SCROLLBAR_USE_VERTICAL)) {
219 set_bit_p(&widget->compose->widget[WID_LISTBOX_VSCROLL]->visibility,
220 WIDGET_VISIBILITY_VISIBLE, scroll & SCROLLBAR_USE_VERTICAL);
223 if((scroll & SCROLLBAR_USE_HORIZONTAL)
224 != (widget->p.listbox->scroll.current & SCROLLBAR_USE_HORIZONTAL)) {
226 set_bit_p(&widget->compose->widget[WID_LISTBOX_HSCROLL]->visibility,
227 WIDGET_VISIBILITY_VISIBLE, scroll & SCROLLBAR_USE_HORIZONTAL);
230 if(widget->p.listbox->scroll.current != scroll) {
231 resize_listbox_view(xuni, widget, scroll);
234 /* redundant -- set by resize_listbox_view() */
235 widget->p.listbox->scroll.current = scroll;
238 static void check_scrollbars(struct xuni_t *xuni, struct widget_t *widget) {
239 enum scrollbar_use_t use = SCROLLBAR_USE_NONE;
241 if(check_vertical_scrollbar(widget)) use |= SCROLLBAR_USE_VERTICAL;
242 if(check_horizontal_scrollbar(widget)) use |= SCROLLBAR_USE_HORIZONTAL;
244 enable_scrollbar(xuni, widget, use);
247 static int check_vertical_scrollbar(struct widget_t *widget) {
248 struct widget_t *area = widget->compose->widget[WID_LISTBOX_DATA];
249 struct widget_t *last = last_compose_widget(area);
251 if(!last) return 0;
253 if(last && last->pos->real.y + last->pos->real.h > area->pos->real.h) {
254 return 1;
257 return 0;
260 /* !!! very inefficient, especially since the same sort of thing is done when
261 scrollbars are scrolled
263 static int check_horizontal_scrollbar(struct widget_t *widget) {
264 struct widget_t *area = widget->compose->widget[WID_LISTBOX_DATA];
265 struct widget_t *widest = last_compose_widget(area);
266 size_t x;
267 int width, w;
269 if(area->compose) {
270 for(x = 0; x < area->compose->widgets; x ++) {
271 width = area->compose->widget[x]->pos->real.w;
273 if(area->compose->widget[x]->pos->real.w > area->pos->real.w) {
274 return 1;
279 return 0;
282 void add_listbox_item(struct xuni_t *xuni, struct widget_t *widget,
283 size_t font, const char *data) {
285 struct widget_t *prev = last_compose_widget(widget);
286 const char *p;
287 int x, y;
289 if(prev && prev->pos) {
290 x = prev->pos->scale.x;
291 y = prev->pos->scale.y; /* !!! */
292 x = 0;
293 y = 0;
295 else {
296 x = 0 /*widget->pos->scale.x*/;
297 y = 0 /*widget->pos->scale.y*/;
300 add_allocate_widget_compose(widget, "listbox item");
302 init_widget_pos(last_compose_widget(widget),
303 x, y, 0, 0, POS_PACK_TOP);
305 p = xuni_memory_duplicate_string(data);
306 init_label(last_compose_widget(widget),
307 font, p, LABEL_ALIGN_LEFT, 255, 255, 255);
308 xuni_memory_decrement((void *)p);
310 last_compose_widget(widget)->visibility &= ~WIDGET_VISIBILITY_INDEPENDENT;
312 widget_event(xuni, last_compose_widget(widget), WIDGET_EVENT_RESCALE);
315 struct widget_t *listbox_sel_item(struct widget_t *widget) {
316 struct widget_t *data = widget->compose->widget[WID_LISTBOX_DATA];
317 size_t x;
319 if(!data->compose) return 0;
321 for(x = 0; x < data->compose->widgets; x ++) {
322 if(data->compose->widget[x]->sel) {
323 return data->compose->widget[x];
327 /*log_message(ERROR_TYPE_WARNING, 0, __FILE__, __LINE__,
328 "No listbox item selected");
329 print_widget_backtrace(widget);*/
331 return 0;
334 static void calculate_vertical_scrollbar_max(struct xuni_t *xuni,
335 struct widget_t *widget) {
337 struct widget_t *area = widget->compose->widget[WID_LISTBOX_DATA];
338 struct widget_t *first;
339 struct widget_t *last = last_compose_widget(area);
340 int max, height;
342 if(last) {
343 first = area->compose->widget[0];
345 height = get_box_height(xuni, xuni->theme->current) / 100.0
346 * xuni->smode->height;
348 max = ((last->pos->real.y - area->pos->real.y)
349 - (first->pos->real.y - area->pos->real.y)
350 + last->pos->real.h)
351 - (area->pos->real.h - last->pos->real.h) - height * 2;
353 else max = 0;
355 set_scrollbar_max(xuni, widget->compose->widget[WID_LISTBOX_VSCROLL],
356 max);
359 /* !!! recording the widest label might be a good idea */
360 static void calculate_horizontal_scrollbar_max(struct xuni_t *xuni,
361 struct widget_t *widget) {
363 struct widget_t *area = widget->compose->widget[WID_LISTBOX_DATA];
364 struct widget_t *widest = last_compose_widget(area);
365 size_t x;
366 int width, w;
368 widget->p.listbox->maxwidth = 0;
370 if(area->compose) {
371 for(x = 1; x < area->compose->widgets; x ++) {
372 width = area->compose->widget[x]->pos->real.w;
374 if(width > widest->pos->real.w) {
375 widest = area->compose->widget[x];
379 widget->p.listbox->maxwidth = widest->pos->real.w;
381 w = get_box_width(xuni, xuni->theme->current) / 100.0
382 * xuni->smode->width;
384 widget->p.listbox->maxwidth -= area->pos->real.w;
387 if(widget->p.listbox->maxwidth < 0) widget->p.listbox->maxwidth = 0;
389 set_scrollbar_max(xuni, widget->compose->widget[WID_LISTBOX_HSCROLL],
390 widget->p.listbox->maxwidth);
393 void listbox_calculate_scrollbar_max(struct xuni_t *xuni,
394 struct widget_t *widget) {
396 calculate_vertical_scrollbar_max(xuni, widget);
397 calculate_horizontal_scrollbar_max(xuni, widget);
400 static void free_listbox(struct xuni_t *xuni, struct widget_t *widget) {
401 xuni_memory_free(widget->p.listbox);
404 static void paint_listbox(struct xuni_t *xuni, struct widget_t *widget) {
405 /*size_t x, start = 3;*/
406 /*int height, width;*/
407 int yclip;
409 widget_event(xuni, widget->compose->widget[WID_LISTBOX_BOX],
410 WIDGET_EVENT_PAINT);
412 /*height = get_box_height(xuni, xuni->theme->current) / 100.0
413 * xuni->smode->height;
414 width = get_box_width(xuni, xuni->theme->current) / 100.0
415 * xuni->smode->width;*/
417 yclip = get_scrollbar_pos_int(
418 widget->compose->widget[WID_LISTBOX_VSCROLL]);
419 /*wclip = widget->compose->widget[WID_LISTBOX_BOX]->pos->real.w - width * 2;
420 hclip = widget->compose->widget[WID_LISTBOX_BOX]->pos->real.h;*/
422 #if !1
423 /*clear_widget_clip(xuni, widget->compose->widget[WID_LISTBOX_DATA]);*/
425 /* !!! why does +width work but +height not? */
426 add_widget_clip(xuni, widget->compose->widget[WID_LISTBOX_DATA],
427 0, -yclip + width, 0, yclip /*+ width*/, /*-width * 2*/0, 0);
428 #endif
430 widget_event(xuni, widget->compose->widget[WID_LISTBOX_DATA],
431 WIDGET_EVENT_PAINT);
433 #if 0
434 /* !!! why does +width work but +height not? */
435 add_widget_clip(xuni, widget->compose->widget[WID_LISTBOX_DATA],
436 0, -(-yclip + width), 0, -yclip /*+ width*/, /*-width * 2*/0, 0);
437 #endif
439 widget_event(xuni, widget->compose->widget[WID_LISTBOX_VSCROLL],
440 WIDGET_EVENT_PAINT);
441 widget_event(xuni, widget->compose->widget[WID_LISTBOX_HSCROLL],
442 WIDGET_EVENT_PAINT);
445 static void reposition_listbox(struct xuni_t *xuni, struct widget_t *widget) {
446 int yclip = get_scrollbar_pos_int(
447 widget->compose->widget[WID_LISTBOX_VSCROLL]);
448 int xclip = get_scrollbar_pos_int(
449 widget->compose->widget[WID_LISTBOX_HSCROLL]);
451 check_scrollbars(xuni, widget);
453 listbox_calculate_scrollbar_max(xuni, widget);
455 clear_widget_clip(xuni, widget->compose->widget[WID_LISTBOX_DATA]);
457 add_panel_clip(xuni, widget->compose->widget[WID_LISTBOX_DATA],
458 -xclip, -yclip, xclip, yclip, 0, 0);
459 /*add_widget_clip(xuni, widget->compose->widget[WID_LISTBOX_DATA],
460 width, 0, 0, 0, -width * 2, 0);*/
463 static void rescale_listbox(struct xuni_t *xuni, struct widget_t *widget) {
464 #if 0
465 double width = calculate_scrollbar_width(widget, xuni);
466 double boxsize = (get_box_width(xuni->theme->current) / 100.0) * 2.0
467 * widget->pos->real.w;
468 double boxsizeh = (get_box_height(xuni->theme->current) / 100.0) * 2.0
469 * widget->pos->real.h;
470 /*double boxsizeh = get_box_height(xuni->theme->current)
471 * (get_box_height(xuni->theme->current) / 100.0);*/
472 struct widget_t *data = widget->compose->widget[WID_LISTBOX_DATA];
474 data->pos->scale.x = boxsize;
475 data->pos->scale.y = boxsizeh;
476 data->pos->scale.w = 100.0 - width - boxsize * 2;
477 data->pos->scale.h = 100.0 - boxsizeh * 2;
479 widget_compose_event(xuni, widget, WIDGET_EVENT_RESCALE);
480 #endif