7 #include "../graphics.h"
15 #include "scrollbar.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
)
49 call_widget_event_func(xuni
, widget
, event
, function
,
50 sizeof(function
) / sizeof(*function
));
53 double real_scale_width(struct widget_t
*widget
) {
56 if(!widget
) return 100.0;
58 w
*= widget
->pos
->scale
.w
/ 100.0;
59 if(widget
->base
) w
*= real_scale_width(widget
->base
);
64 double real_scale_height(struct widget_t
*widget
) {
67 if(!widget
) return 100.0;
69 h
*= widget
->pos
->scale
.h
/ 100.0;
70 if(widget
->base
) h
*= real_scale_height(widget
->base
);
75 double calculate_scrollbar_width(struct widget_t
*widget
,
76 struct xuni_t
*xuni
) {
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
);
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 */
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
);
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
],
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
);
253 if(last
&& last
->pos
->real
.y
+ last
->pos
->real
.h
> area
->pos
->real
.h
) {
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
);
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
) {
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
);
289 if(prev
&& prev
->pos
) {
290 x
= prev
->pos
->scale
.x
;
291 y
= prev
->pos
->scale
.y
; /* !!! */
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
];
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);*/
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
);
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
)
351 - (area
->pos
->real
.h
- last
->pos
->real
.h
) - height
* 2;
355 set_scrollbar_max(xuni
, widget
->compose
->widget
[WID_LISTBOX_VSCROLL
],
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
);
368 widget
->p
.listbox
->maxwidth
= 0;
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;*/
409 widget_event(xuni
, widget
->compose
->widget
[WID_LISTBOX_BOX
],
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;*/
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);
430 widget_event(xuni
, widget
->compose
->widget
[WID_LISTBOX_DATA
],
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);
439 widget_event(xuni
, widget
->compose
->widget
[WID_LISTBOX_VSCROLL
],
441 widget_event(xuni
, widget
->compose
->widget
[WID_LISTBOX_HSCROLL
],
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
) {
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
);