1 /*
2 * (SLIK) SimpLIstic sKin functions
3 * (C) 2005 John Ellis
4 *
5 * Author: John Ellis
6 *
7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
10 */
11
12 #include "ui2_includes.h"
13 #include "ui2_typedefs.h"
14
15 #include "ui2_list.h"
16 #include "ui2_list_edit.h"
17
18 #include "ui2_display.h"
19 #include "ui2_main.h"
20 #include "ui2_parse.h"
21 #include "ui2_skin.h"
22 #include "ui2_util.h"
23 #include "ui2_widget.h"
24 #include "ui_pixbuf_ops.h"
25
26 #include "ui2_button.h"
27 #include "ui2_slider.h"
28
29
30 #include <gdk/gdkkeysyms.h> /* for key values */
31
32
33 #define UI2_LIST_SCROLL_DELAY 200
34 #define UI2_LIST_SCROLL_DELAY_FAST 67
35 #define UI2_LIST_SCROLL_SPEEDUP 4
36 #define UI2_LIST_SELECT_TIME 333
37
38 typedef struct _ListCallbackData ListCallbackData;
39 struct _ListCallbackData
40 {
41 gint (*length_request_func)(ListData *list, const gchar *key, gpointer data);
42 gint (*row_info_func)(ListData *list, const gchar *key, gint row, ListRowData *rd, gpointer data);
43 void (*row_click_func)(ListData *list, const gchar *key, gint row, ListRowData *rd, gint button, gpointer data);
44 void (*row_select_func)(ListData *list, const gchar *key, gint row, ListRowData *rd, gpointer data);
45 gint (*row_move_func)(ListData *list, const gchar *key, gint source_row, gint dest_row, gpointer data);
46
47 gpointer length_request_data;
48 gpointer row_info_data;
49 gpointer row_click_data;
50 gpointer row_select_data;
51 gpointer row_move_data;
52
53 /* only use for menu mode */
54 gint (*menu_move_func)(ListData *list, const gchar *key, gint row, gint activated, gint up, gpointer data);
55 gpointer menu_move_data;
56 };
57
58
59 static WidgetType type_id = -1;
60
61
62 static void list_rows_free(ListData *ld);
63 static gint list_length_sync(ListData *ld, gint length, gint force);
64 static void list_scroll_update_widgets(ListData *ld);
65
66
67 /*
68 *-----------------------------
69 * new / free
70 *-----------------------------
71 */
72
list_new(GdkPixbuf * pb,gint x,gint y,gint w,gint h,gint sizeable,gint columns,gint border_top,gint border_right,gint border_bottom,gint border_left,gint stretch)73 ListData *list_new(GdkPixbuf *pb, gint x, gint y, gint w, gint h, gint sizeable, gint columns,
74 gint border_top, gint border_right, gint border_bottom, gint border_left, gint stretch)
75 {
76 ListData *ld;
77
78 list_type_init();
79
80 if (!pb) return NULL;
81
82 ld = g_new0(ListData, 1);
83
84 util_size(&x);
85 util_size(&y);
86 util_size(&w);
87 util_size(&h);
88
89 util_size(&border_top);
90 util_size(&border_right);
91 util_size(&border_bottom);
92 util_size(&border_left);
93
94 ld->x = x;
95 ld->y = y;
96 ld->width = w;
97 ld->height = h;
98 ld->sizeable = sizeable;
99
100 ld->border_top = border_top;
101 ld->border_right = border_right;
102 ld->border_bottom = border_bottom;
103 ld->border_left = border_left;
104 ld->stretch = stretch;
105
106 ld->column_count = columns;
107 ld->column_widths = g_new0(gint, columns);
108 ld->column_flags = g_new0(ListColumnFlags, columns);
109 ld->column_real_widths = g_new0(gint, columns);
110 ld->column_keys = g_new0(gchar *, columns);
111
112 ld->columns_right_justify = FALSE;
113
114 ld->font = NULL;
115 ld->text_r = 0;
116 ld->text_g = 0;
117 ld->text_b = 0;
118 ld->text_a = 255;
119
120 ld->overlay = util_size_pixbuf(pb, TRUE);
121
122 ld->timeout_id = -1;
123 ld->row_prelight = -1;
124 ld->row_press = -1;
125 ld->focus_row = -1;
126
127 ld->scroll_idle_id = -1;
128
129 return ld;
130 }
131
list_set_column_attributes(ListData * ld,gint column,gint length,ListColumnFlags flags,const gchar * key)132 void list_set_column_attributes(ListData *ld, gint column, gint length, ListColumnFlags flags, const gchar *key)
133 {
134 if (!ld) return;
135 if (column >= ld->column_count) return;
136
137 if (flags & UI_LIST_COLUMN_SIZE_FIXED) util_size(&length);
138
139 ld->column_widths[column] = length;
140 ld->column_flags[column] = flags;
141 g_free(ld->column_keys[column]);
142 ld->column_keys[column] = g_strdup(key);
143
144 if (key && strcmp(key, "flags") == 0) ld->flag_column = column;
145 }
146
list_set_column_justify(ListData * ld,gint justify_right)147 void list_set_column_justify(ListData *ld, gint justify_right)
148 {
149 if (!ld) return;
150 ld->columns_right_justify = justify_right;
151 }
152
list_image_row(ListData * ld,GdkPixbuf * pb,gint has_press,gint has_prelight,gint border_left,gint border_right,gint stretch,GdkPixbuf * divider)153 void list_image_row(ListData *ld, GdkPixbuf *pb, gint has_press, gint has_prelight,
154 gint border_left, gint border_right, gint stretch, GdkPixbuf *divider)
155 {
156 if (!ld || !pb) return;
157
158 util_size(&border_left);
159 util_size(&border_right);
160
161 ld->row_overlay = util_size_pixbuf(pb, TRUE);
162 ld->row_height = gdk_pixbuf_get_height(ld->row_overlay) / (1 + (has_press) + (has_prelight));
163 ld->row_width = gdk_pixbuf_get_width(ld->row_overlay);
164 ld->row_border_left = border_left;
165 ld->row_border_right = border_right;
166 ld->row_stretch = stretch;
167 ld->row_has_press = has_press;
168 ld->row_has_prelight = has_prelight;
169
170 if (divider)
171 {
172 ld->divider_overlay = util_size_pixbuf(divider, TRUE);
173 ld->divider_width = gdk_pixbuf_get_width(ld->divider_overlay);
174 ld->divider_height = MIN(gdk_pixbuf_get_height(ld->divider_overlay), ld->row_height);
175 }
176 else
177 {
178 ld->divider_width = 3;
179 ld->divider_height = 0;
180 }
181 }
182
list_image_row_flag(ListData * ld,GdkPixbuf * pb,gint sections,gint column)183 void list_image_row_flag(ListData *ld, GdkPixbuf *pb, gint sections, gint column)
184 {
185 if (!ld || !pb) return;
186
187 ld->flag_overlay = util_size_pixbuf(pb, TRUE);
188 ld->flag_sections = sections;
189 ld->flag_column = column;
190
191 ld->flag_width = gdk_pixbuf_get_width(ld->flag_overlay);
192 ld->flag_height = gdk_pixbuf_get_height(ld->flag_overlay) / sections;
193 }
194
list_set_font(ListData * ld,const gchar * description,GdkPixbuf * pb,gint extended,guint8 r,guint8 g,guint8 b,guint8 a)195 void list_set_font(ListData *ld, const gchar *description, GdkPixbuf *pb, gint extended,
196 guint8 r, guint8 g, guint8 b, guint8 a)
197 {
198 if (!ld || (!description && !pb)) return;
199
200 util_color(&r, &g, &b, &a);
201
202 ld->text_r = r;
203 ld->text_g = g;
204 ld->text_b = b;
205 ld->text_a = a;
206
207 if (ld->font) return;
208
209 if (pb)
210 {
211 ld->font = font_new(pb, extended);
212
213 /* no need to pad text end with spaces for lists */
214 if (ld->font) ld->font->fill = FALSE;
215 }
216 else
217 {
218 ld->font = font_new_from_x(description);
219 }
220
221 if (!ld->font)
222 {
223 printf("ui2_list.c: warning failed to create font for list\n");
224 }
225 }
226
list_free(ListData * ld)227 void list_free(ListData *ld)
228 {
229 gint i;
230
231 if (!ld) return;
232
233 if (ld->timeout_id != -1) g_source_remove(ld->timeout_id);
234 if (ld->scroll_idle_id != -1) g_source_remove(ld->scroll_idle_id);
235
236 if (ld->overlay) gdk_pixbuf_unref(ld->overlay);
237 if (ld->pixbuf) gdk_pixbuf_unref(ld->pixbuf);
238 if (ld->clip_mask) gdk_pixbuf_unref(ld->clip_mask);
239 if (ld->row_overlay) gdk_pixbuf_unref(ld->row_overlay);
240 if (ld->row_overlay_center) gdk_pixbuf_unref(ld->row_overlay_center);
241 if (ld->divider_overlay) gdk_pixbuf_unref(ld->divider_overlay);
242 if (ld->flag_overlay) gdk_pixbuf_unref(ld->flag_overlay);
243
244 font_unref(ld->font);
245
246 g_free(ld->column_widths);
247 g_free(ld->column_flags);
248 g_free(ld->column_real_widths);
249
250 for (i = 0; i < ld->column_count; i++) g_free(ld->column_keys[i]);
251 g_free(ld->column_keys);
252
253 list_rows_free(ld);
254
255 g_free(ld);
256 }
257
list_free_cb(gpointer data)258 static void list_free_cb(gpointer data)
259 {
260 list_free((ListData *)data);
261 }
262
263 /*
264 *-----------------------------
265 * row data handlers
266 *-----------------------------
267 */
268
list_row_new(guint columns)269 static ListRowData *list_row_new(guint columns)
270 {
271 ListRowData *rd;
272
273 rd = g_new0(ListRowData, 1);
274 rd->cells = columns;
275 rd->text = g_new0(gchar*, columns + 1);
276 rd->sensitive = TRUE;
277 rd->flag_mask = -1;
278
279 return rd;
280 }
281
list_row_free(ListRowData * rd)282 static void list_row_free(ListRowData *rd)
283 {
284 if (!rd) return;
285
286 if (rd->text)
287 {
288 gint i;
289
290 for(i = 0; i < rd->cells; i++) g_free(rd->text[i]);
291 g_free(rd->text);
292 }
293 g_free(rd);
294 }
295
list_row_clear_text(ListRowData * rd)296 static void list_row_clear_text(ListRowData *rd)
297 {
298 gint i;
299
300 if (!rd) return;
301
302 for (i = 0; i < rd->cells; i++)
303 {
304 g_free(rd->text[i]);
305 rd->text[i] = NULL;
306 }
307
308 /* also clear the flag here */
309 rd->flag_mask = -1;
310 }
311
list_rows_free(ListData * ld)312 static void list_rows_free(ListData *ld)
313 {
314 GList *work;
315
316 work = ld->row_list;
317 while (work)
318 {
319 ListRowData *rd = work->data;
320 work = work->next;
321 list_row_free(rd);
322 }
323
324 g_list_free(ld->row_list);
325 ld->row_list = NULL;
326 }
327
list_row_text_set(ListRowData * rd,gint column,const gchar * text)328 void list_row_text_set(ListRowData *rd, gint column, const gchar *text)
329 {
330 if (!rd || column >= rd->cells) return;
331
332 g_free(rd->text[column]);
333 rd->text[column] = g_strdup(text);
334 }
335
list_row_text_get(ListRowData * rd,gint column)336 static const gchar *list_row_text_get(ListRowData *rd, gint column)
337 {
338 if (!rd || column >= rd->cells) return NULL;
339
340 return rd->text[column];
341 }
342
list_row_column_set_text(ListData * ld,ListRowData * rd,const gchar * column_key,const gchar * text)343 void list_row_column_set_text(ListData *ld, ListRowData *rd, const gchar *column_key, const gchar *text)
344 {
345 gint column;
346
347 if (!ld || !rd || !column_key) return;
348
349 for (column = 0; column < ld->column_count; column++)
350 {
351 if (ld->column_keys[column] && strcmp(ld->column_keys[column], column_key) == 0)
352 {
353 list_row_text_set(rd, column, text);
354 }
355 }
356 }
357
list_row_set_flag(ListRowData * rd,gint flag)358 void list_row_set_flag(ListRowData *rd, gint flag)
359 {
360 if (rd) rd->flag_mask = flag;
361 }
362
list_row_set_sensitive(ListRowData * rd,gint sensitive)363 void list_row_set_sensitive(ListRowData *rd, gint sensitive)
364 {
365 if (rd) rd->sensitive = sensitive;
366 }
367
368 /*
369 *-----------------------------
370 * syncing utils
371 *-----------------------------
372 */
373
list_sync(ListData * ld)374 static void list_sync(ListData *ld)
375 {
376 gint i;
377 gint w;
378 gint area;
379 gint row_oh;
380
381 if (!ld->force_sync &&
382 ld->pixbuf &&
383 gdk_pixbuf_get_width(ld->pixbuf) == ld->width &&
384 gdk_pixbuf_get_height(ld->pixbuf) == ld->height &&
385 ld->region_width == ld->width - ld->border_left - ld->border_right &&
386 ld->region_height == ld->height - ld->border_top - ld->border_bottom &&
387 ld->row_overlay_center) return;
388
389 ld->force_sync = FALSE;
390
391 if (ld->pixbuf) gdk_pixbuf_unref(ld->pixbuf);
392 ld->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, ld->width, ld->height);
393
394 ld->region_width = ld->width - ld->border_left - ld->border_right;
395 ld->region_height = ld->height - ld->border_top - ld->border_bottom;
396
397 row_oh = gdk_pixbuf_get_height(ld->row_overlay);
398 area = ld->region_width - ld->row_border_left - ld->row_border_right;
399
400 if (ld->row_overlay_center) gdk_pixbuf_unref(ld->row_overlay_center);
401 ld->row_overlay_center = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
402 gdk_pixbuf_get_has_alpha(ld->row_overlay),
403 8, area, row_oh);
404 pixbuf_copy_fill(ld->row_overlay, ld->row_border_left, 0,
405 ld->row_width - ld->row_border_left - ld->row_border_right, row_oh,
406 ld->row_overlay_center, 0, 0,
407 area, row_oh,
408 ld->row_stretch, TRUE);
409
410 w = 0;
411 for (i = 0; i < ld->column_count; i++)
412 {
413 gint c;
414 gint s;
415 gint p;
416
417 s = w;
418
419 if (ld->columns_right_justify)
420 {
421 p = (ld->column_count - 1) - i;
422 }
423 else
424 {
425 p = i;
426 }
427
428 if (w >= area)
429 {
430 ld->column_real_widths[p] = 0;
431 continue;
432 }
433
434 if (i == ld->column_count - 1)
435 {
436 c = area - w;
437 w += c;
438 }
439 else
440 {
441 if (ld->column_flags[p] & UI_LIST_COLUMN_SIZE_PROPORTIONAL)
442 {
443 c = ((float)ld->column_widths[p] / 100.0 * ld->region_width) - ld->divider_width;
444 if (c < 1) c = 1;
445 }
446 else
447 {
448 c = ld->column_widths[p];
449 }
450 w += c + ld->divider_width;
451 }
452 if (w >= area) c = area - s;
453 ld->column_real_widths[p] = c;
454 if (debug_mode) printf("column %d with width of %d (%d)\n", p, c, ld->column_widths[p]);
455 }
456
457 /* vertical centering offsets */
458 ld->text_voff = MAX((ld->row_height - ld->font->char_height) / 2, 0);
459 ld->divider_voff = MAX((ld->row_height - ld->divider_height) / 2, 0);
460 ld->flag_voff = MAX((ld->row_height - ld->flag_height) / 2, 0);
461
462 list_length_sync(ld, 0, TRUE);
463 }
464
list_rows_visible(ListData * ld)465 static gint list_rows_visible(ListData *ld)
466 {
467 return (ld->region_height / ld->row_height);
468 }
469
list_scroll_clamp(ListData * ld)470 static gint list_scroll_clamp(ListData *ld)
471 {
472 gint vis;
473 gint old_s, old_e;
474
475 vis = list_rows_visible(ld);
476
477 old_s = ld->row_start;
478 old_e = ld->row_end;
479
480 ld->row_start = CLAMP(ld->row_start, 0, MAX(0, ld->row_count - vis));
481 ld->row_end = CLAMP(ld->row_start + vis - 1, ld->row_start, ld->row_count - 1);
482
483 list_scroll_update_widgets(ld);
484
485 return (ld->row_start != old_s || ld->row_end != old_e);
486 }
487
list_length_sync(ListData * ld,gint length,gint force)488 static gint list_length_sync(ListData *ld, gint length, gint force)
489 {
490
491 if (ld->row_count == length && !force) return FALSE;
492 if (!force) ld->row_count = length;
493
494 if (ld->focus_row >= ld->row_count)
495 {
496 ld->focus_row = ld->row_count - 1;
497 }
498 else if (ld->focus_row < 0 && ld->row_count > 0)
499 {
500 ld->focus_row = 0;
501 }
502
503 if (list_scroll_clamp(ld))
504 {
505 gint i;
506 list_rows_free(ld);
507
508 if (ld->row_count > 0)
509 for (i = 0; i <= ld->row_end - ld->row_start; i++)
510 {
511 ld->row_list = g_list_prepend(ld->row_list, list_row_new(ld->column_count));
512 }
513
514 return TRUE;
515 }
516
517 return FALSE;
518 }
519
list_row_sync(ListData * ld,UIData * ui,const gchar * key,gint row)520 static gint list_row_sync(ListData *ld, UIData *ui, const gchar *key, gint row)
521 {
522 ListCallbackData *cd;
523 ListRowData *rd;
524
525 rd = g_list_nth_data(ld->row_list, row - ld->row_start);
526 if (!rd) return FALSE;
527
528 cd = ui_get_registered_callbacks(ui, key, type_id);
529 if (!cd || !cd->row_info_func) return FALSE;
530
531 list_row_clear_text(rd);
532 return cd->row_info_func(ld, key, row, rd, cd->row_info_data);
533 }
534
list_row_sync_n(ListData * ld,UIData * ui,const gchar * key,gint start,gint end,ListCallbackData * cd)535 static gint list_row_sync_n(ListData *ld, UIData *ui, const gchar *key,
536 gint start, gint end, ListCallbackData *cd)
537 {
538 GList *work;
539 gint row;
540 gint ret = FALSE;
541
542 if (!cd) cd = ui_get_registered_callbacks(ui, key, type_id);
543 if (!cd || !cd->row_info_func) return FALSE;
544
545 row = ld->row_start + start;
546
547 work = g_list_nth(ld->row_list, start);
548 while (work && start <= end)
549 {
550 ListRowData *rd = work->data;
551
552 list_row_clear_text(rd);
553 ret |= cd->row_info_func(ld, key, row, rd, cd->row_info_data);
554 work = work->next;
555 start++;
556 row++;
557 }
558
559 return ret;
560 }
561
list_row_sync_all(ListData * ld,UIData * ui,const gchar * key,ListCallbackData * cd)562 static gint list_row_sync_all(ListData *ld, UIData *ui, const gchar *key, ListCallbackData *cd)
563 {
564 gint row;
565 GList *work;
566 gint ret = FALSE;
567
568 if (!cd) cd = ui_get_registered_callbacks(ui, key, type_id);
569 if (!cd || !cd->row_info_func) return FALSE;
570
571 row = ld->row_start;
572 work = ld->row_list;
573 while (work)
574 {
575 ListRowData *rd = work->data;
576 work = work->next;
577
578 ret |= cd->row_info_func(ld, key, row, rd, cd->row_info_data);
579
580 row++;
581 }
582
583 return ret;
584 }
585
586 /*
587 *-----------------------------
588 * draw, etc.
589 *-----------------------------
590 */
591
list_draw_text(ListData * ld,GdkPixbuf * pb,const gchar * text,gint x,gint y,gint w,gint right_justify,gint alpha)592 static void list_draw_text(ListData *ld, GdkPixbuf *pb, const gchar *text, gint x, gint y,
593 gint w, gint right_justify, gint alpha)
594 {
595 gint p;
596
597 if (!text) return;
598
599 if (right_justify)
600 {
601 p = w - font_string_length(ld->font, text);
602 if (p < 0) p = 0;
603 }
604 else
605 {
606 p = 0;
607 }
608
609 font_draw(ld->font, text, 0, x + p, y,
610 w - p, MIN(ld->row_height - ld->text_voff, ld->font->char_height), 0,
611 ld->text_r, ld->text_g, ld->text_b, ld->text_a,
612 pb, ld->ui, alpha);
613 }
614
list_draw_cell(ListData * ld,GdkPixbuf * pb,gint x,gint y,gint row,gint column,gint divider)615 static void list_draw_cell(ListData *ld, GdkPixbuf *pb, gint x, gint y, gint row, gint column, gint divider)
616 {
617 ListRowData *rd;
618 const gchar *text;
619 gint w;
620 gint alpha;
621
622 rd = g_list_nth_data(ld->row_list, row);
623 if (!rd) return;
624
625 alpha = (rd->sensitive) ? 255 : 86;
626
627 w = ld->column_real_widths[column];
628 text = list_row_text_get(rd, column);
629 if (text) list_draw_text(ld, pb, text, ld->x + x, ld->y + y + ld->text_voff, w,
630 (ld->column_flags[column] & UI_LIST_COLUMN_JUSTIFY_RIGHT),
631 alpha);
632 if (divider && ld->divider_overlay)
633 {
634 pixbuf_copy_area_alpha(ld->divider_overlay, 0, 0,
635 pb, ld->x + x + w, ld->y + y + ld->divider_voff,
636 ld->divider_width, ld->divider_height, alpha);
637 }
638 if (column == ld->flag_column && ld->flag_overlay && rd->flag_mask >= 0 && rd->flag_mask < ld->flag_sections)
639 {
640 pixbuf_copy_area_alpha(ld->flag_overlay, 0, rd->flag_mask * ld->flag_height,
641 pb, ld->x + x, ld->y + y + ld->flag_voff,
642 MIN(ld->flag_width, w), MIN(ld->flag_height, ld->row_height), alpha);
643 }
644 }
645
list_draw_row_image(ListData * ld,GdkPixbuf * pb,gint y_off,gint x,gint y)646 static void list_draw_row_image(ListData *ld, GdkPixbuf *pb, gint y_off, gint x, gint y)
647 {
648 pixbuf_copy_area_alpha(ld->row_overlay, 0, y_off,
649 pb, ld->x + x, ld->y + y, ld->row_border_left, ld->row_height, 255);
650 pixbuf_copy_area_alpha(ld->row_overlay_center, 0, y_off,
651 pb, ld->x + x + ld->row_border_left, ld->y + y,
652 ld->region_width - ld->row_border_left - ld->row_border_right, ld->row_height, 255);
653 pixbuf_copy_area_alpha(ld->row_overlay, ld->row_width - ld->row_border_right, y_off,
654 pb, ld->x + x + ld->region_width - ld->row_border_right, ld->y + y,
655 ld->row_border_right, ld->row_height, 255);
656 }
657
list_draw_row(ListData * ld,GdkPixbuf * pb,UIData * ui,gint row,gint render)658 static void list_draw_row(ListData *ld, GdkPixbuf *pb, UIData *ui, gint row, gint render)
659 {
660 gint x, y;
661 gint i;
662 gint row_has_alpha;
663 gint pressed;
664 gint prelit;
665
666 x = ld->border_left;
667 y = row * ld->row_height + ld->border_top;
668
669 row_has_alpha = gdk_pixbuf_get_has_alpha(ld->row_overlay);
670
671 if (row_has_alpha)
672 {
673 pixbuf_copy_area(ld->pixbuf, x, y,
674 pb, ld->x + x, ld->y + y, ld->region_width, ld->row_height,
675 FALSE);
676 }
677
678 pressed = (ld->row_has_press && row == ld->row_press - ld->row_start);
679 prelit = (ld->row_has_prelight && row == ld->row_prelight - ld->row_start);
680
681 if (row_has_alpha || (!pressed && !prelit))
682 {
683 list_draw_row_image(ld, pb, 0, x, y);
684 }
685 if (pressed)
686 {
687 list_draw_row_image(ld, pb, ld->row_height, x, y);
688 }
689 if (prelit && (!row_has_alpha || slik_transparency_force))
690 {
691 list_draw_row_image(ld, pb, ld->row_height * (ld->row_has_press + 1), x, y);
692 }
693
694 x += ld->row_border_left;
695 i = 0;
696 while (i < ld->column_count && ld->column_real_widths[i] > 0)
697 {
698 gint divider;
699
700 divider = !(i == ld->column_count - 1 || ld->column_real_widths[i+1] < 1);
701 list_draw_cell(ld, pb, x, y, row, i, divider);
702 x += ld->column_real_widths[i] + ld->divider_width;
703 i++;
704 }
705
706 x = ld->border_left;
707
708 if (prelit && (row_has_alpha && !slik_transparency_force))
709 {
710 list_draw_row_image(ld, pb, ld->row_height * (ld->row_has_press + 1), x, y);
711 }
712
713 if (render && ui)
714 {
715 ui_display_render_area(ui, ld->x + ld->border_left, ld->y + y,
716 ld->region_width, ld->row_height, ld->wd);
717 }
718 }
719
list_draw_empty_rows(ListData * ld,GdkPixbuf * pb,UIData * ui,gint render)720 static void list_draw_empty_rows(ListData *ld, GdkPixbuf *pb, UIData *ui, gint render)
721 {
722 gint vis;
723 gint y;
724
725 vis = list_rows_visible(ld);
726
727 y = 0;
728 if (ld->row_count > 0) y += vis < 1 ? 0 : ld->row_height * (ld->row_end - ld->row_start + 1);
729 if (y >= ld->region_height) return;
730
731 pixbuf_copy_area(ld->pixbuf, ld->border_left, ld->border_top + y,
732 pb, ld->x + ld->border_left, ld->y + ld->border_top + y,
733 ld->region_width, ld->region_height - y, FALSE);
734
735 if (render && ui)
736 {
737 ui_display_render_area(ui, ld->x + ld->border_left, ld->y + ld->border_top + y,
738 ld->region_width, ld->region_height - y, ld->wd);
739 }
740 }
741
list_draw_border(ListData * ld,GdkPixbuf * pb)742 static void list_draw_border(ListData *ld, GdkPixbuf *pb)
743 {
744 pixbuf_copy_area(ld->pixbuf, 0, 0,
745 pb, ld->x, ld->y,
746 ld->width, ld->border_top, FALSE);
747 pixbuf_copy_area(ld->pixbuf, 0, ld->border_top,
748 pb, ld->x, ld->y + ld->border_top,
749 ld->border_left, ld->region_height, FALSE);
750 pixbuf_copy_area(ld->pixbuf, ld->width - ld->border_right, ld->border_top,
751 pb, ld->x + ld->width - ld->border_right, ld->y + ld->border_top,
752 ld->border_right, ld->region_height, FALSE);
753 pixbuf_copy_area(ld->pixbuf, 0, ld->height - ld->border_bottom,
754 pb, ld->x, ld->y + ld->height - ld->border_bottom,
755 ld->width, ld->border_bottom, FALSE);
756 }
757
list_redraw_row(ListData * ld,GdkPixbuf * pb,UIData * ui,gint row)758 static void list_redraw_row(ListData *ld, GdkPixbuf *pb, UIData *ui, gint row)
759 {
760 if (ld->row_count < 1 || row < 0 || row > ld->row_end - ld->row_start + 1) return;
761 list_draw_row(ld, pb, ui, row, TRUE);
762 }
763
list_draw_rows(ListData * ld,GdkPixbuf * pb,UIData * ui,gint start,gint end,gint render)764 static void list_draw_rows(ListData *ld, GdkPixbuf *pb, UIData *ui, gint start, gint end, gint render)
765 {
766 gint row;
767
768 row = start;
769 while (row <= end)
770 {
771 list_draw_row(ld, pb, NULL, row, FALSE);
772 row++;
773 }
774
775 if (render && ui)
776 {
777 ui_display_render_area(ui, ld->x + ld->border_left, ld->y + ld->border_top + start * ld->row_height,
778 ld->region_width, (end - start + 1) * ld->row_height, ld->wd);
779 }
780 }
781
list_draw_all_rows(ListData * ld,GdkPixbuf * pb,UIData * ui,gint render)782 static void list_draw_all_rows(ListData *ld, GdkPixbuf *pb, UIData *ui, gint render)
783 {
784 if (ld->row_count > 0 && list_rows_visible(ld) > 0)
785 {
786 list_draw_rows(ld, pb, ui, 0, ld->row_end - ld->row_start, render);
787 }
788 list_draw_empty_rows(ld, pb, ui, render);
789 }
790
list_draw_all(ListData * ld,GdkPixbuf * pb,UIData * ui)791 static void list_draw_all(ListData *ld, GdkPixbuf *pb, UIData *ui)
792 {
793 list_draw_border(ld, pb);
794 list_draw_all_rows(ld, pb, ui, FALSE);
795
796 ui_display_render_area(ui, ld->x, ld->y, ld->width, ld->height, ld->wd);
797 }
798
799 /*
800 *-----------------------------
801 * scrolling
802 *-----------------------------
803 */
804
list_row_scroll_by_row(ListData * ld,GdkPixbuf * pb,UIData * ui,const gchar * key,gint rows)805 static void list_row_scroll_by_row(ListData *ld, GdkPixbuf *pb, UIData *ui, const gchar *key, gint rows)
806 {
807 gint vis;
808 gint old_s;
809
810 old_s = ld->row_start;
811
812 ld->row_start += rows;
813 list_scroll_clamp(ld);
814
815 if (old_s == ld->row_start) return;
816
817 vis = list_rows_visible(ld);
818
819 if (abs(old_s - ld->row_start) < vis)
820 {
821 GList *link;
822 GList *tail;
823
824 if (ld->row_start > old_s)
825 {
826 link = g_list_nth(ld->row_list, abs(ld->row_start - old_s));
827 }
828 else
829 {
830 link = g_list_nth(ld->row_list, vis - abs(ld->row_start - old_s));
831 }
832
833 tail = link->prev;
834 tail->next = NULL;
835 link->prev = NULL;
836
837 tail = g_list_last(link);
838 tail->next = ld->row_list;
839 ld->row_list->prev = tail;
840
841 ld->row_list = link;
842
843 if (ld->row_start > old_s)
844 {
845 list_row_sync_n(ld, ui, key, vis - (ld->row_start - old_s), vis - 1, NULL);
846 }
847 else
848 {
849 list_row_sync_n(ld, ui, key, 0, old_s - ld->row_start - 1, NULL);
850 }
851 }
852 else
853 {
854 list_row_sync_all(ld, ui, key, NULL);
855 }
856
857 if (ld->focus_row < ld->row_start) ld->focus_row = ld->row_start;
858 if (ld->focus_row > ld->row_end) ld->focus_row = ld->row_end;
859
860 if (ld->row_prelight >= 0)
861 {
862 ld->row_prelight += ld->row_start - old_s;
863 }
864
865 list_draw_rows(ld, pb, ui, 0, ld->row_end - ld->row_start, TRUE);
866 }
867
list_row_scroll(ListData * ld,GdkPixbuf * pb,UIData * ui,const gchar * key,gfloat val)868 static void list_row_scroll(ListData *ld, GdkPixbuf *pb, UIData *ui, const gchar *key, gfloat val)
869 {
870 gint row;
871 gint vis;
872
873 vis = list_rows_visible(ld);
874
875 if (ld->row_count <= vis) return;
876
877 row = CLAMP(val * (ld->row_count - vis), 0, ld->row_count - vis);
878
879 list_row_scroll_by_row(ld, pb, ui, key, row - ld->row_start);
880 }
881
882 /*
883 *-----------------------------
884 * selection, misc
885 *-----------------------------
886 */
887
list_row_prelight_set(ListData * ld,GdkPixbuf * pb,UIData * ui,gint row)888 static void list_row_prelight_set(ListData *ld, GdkPixbuf *pb, UIData *ui, gint row)
889 {
890 gint old_r;
891
892 if (ld->row_prelight == row) return;
893
894 old_r = ld->row_prelight;
895 ld->row_prelight = row;
896
897 if (row >= 0) ld->row_press = -1;
898
899 if (old_r >= 0) list_redraw_row(ld, pb, ui, old_r - ld->row_start);
900 if (ld->row_prelight >= 0) list_redraw_row(ld, pb, ui, ld->row_prelight - ld->row_start);
901 }
902
list_row_press_set(ListData * ld,GdkPixbuf * pb,UIData * ui,gint row)903 static void list_row_press_set(ListData *ld, GdkPixbuf *pb, UIData *ui, gint row)
904 {
905 gint old_r;
906
907 if (ld->row_press == row) return;
908
909 old_r = ld->row_press;
910 ld->row_press = row;
911
912 if (row >= 0) ld->row_prelight = -1;
913
914 if (old_r >= 0) list_redraw_row(ld, pb, ui, old_r - ld->row_start);
915 if (ld->row_press >= 0) list_redraw_row(ld, pb, ui, ld->row_press - ld->row_start);
916 }
917
list_test_proximity(ListData * ld,gint x,gint y)918 static gint list_test_proximity(ListData *ld, gint x, gint y)
919 {
920 if (!ld) return FALSE;
921
922 /* we only test region that is useful */
923 if (x < ld->x + ld->border_left || x >= ld->x + ld->border_left + ld->region_width ||
924 y < ld->y + ld->border_top || y >= ld->y + ld->border_top + ld->region_height) return FALSE;
925
926 return TRUE;
927 }
928
list_row_find_proximity(ListData * ld,gint x,gint y)929 static gint list_row_find_proximity(ListData *ld, gint x, gint y)
930 {
931 if (ld->row_count < 1 || ld->row_height < 1 ||
932 y < ld->y + ld->border_top ||
933 y >= ld->y + ld->border_top + (ld->row_end - ld->row_start + 1) * ld->row_height) return -1;
934
935 return ld->row_start + ((y - ld->y - ld->border_top) / ld->row_height);
936 }
937
938 /*
939 *-----------------------------
940 * ui funcs
941 *-----------------------------
942 */
943
list_draw(gpointer data,const gchar * key,gint update,gint force,GdkPixbuf * pb,UIData * ui)944 static void list_draw(gpointer data, const gchar *key, gint update, gint force, GdkPixbuf *pb, UIData *ui)
945 {
946 ListData *ld = data;
947
948 if (update)
949 {
950 ListCallbackData *cd;
951 gint length = 0;
952
953 cd = ui_get_registered_callbacks(ui, key, type_id);
954 if (cd && cd->length_request_func)
955 {
956 length = cd->length_request_func(ld, key, cd->length_request_data);
957 }
958 list_length_sync(ld, length, FALSE);
959 list_row_sync_all(ld, ui, key, cd);
960 }
961 if (force)
962 {
963 list_draw_all(ld, pb, ui);
964 }
965 else if (update)
966 {
967 list_draw_all_rows(ld, pb, ui, TRUE);
968 }
969 }
970
list_reset(gpointer data,const gchar * key,GdkPixbuf * pb,UIData * ui)971 static void list_reset(gpointer data, const gchar *key, GdkPixbuf *pb, UIData *ui)
972 {
973 ListData *ld = data;
974
975 list_row_prelight_set(ld, pb, ui, -1);
976 }
977
list_motion(gpointer data,const gchar * key,gint x,gint y,GdkPixbuf * pb,UIData * ui)978 static void list_motion(gpointer data, const gchar *key, gint x, gint y, GdkPixbuf *pb, UIData *ui)
979 {
980 ListData *ld = data;
981 gint old_prelight;
982
983 if (ld->pressed)
984 {
985 gint row;
986
987 row = list_row_find_proximity(ld, x, y);
988 if (row == ld->press_row || ld->menu_style_select)
989 {
990 gint changed = (row != ld->row_press);
991
992 list_row_press_set(ld, pb, ui, row);
993
994 if (changed && ld->menu_style_select)
995 {
996 ListCallbackData *cd;
997
998 cd = ui_get_registered_callbacks(ui, key, type_id);
999 if (cd && cd->menu_move_func)
1000 {
1001 cd->menu_move_func(ld, key, row, FALSE, FALSE, cd->menu_move_data);
1002 }
1003 }
1004
1005 }
1006 else
1007 {
1008 list_row_press_set(ld, pb, ui, -1);
1009 }
1010
1011 return;
1012 }
1013
1014 old_prelight = ld->row_prelight;
1015
1016 if (list_test_proximity(ld, x, y))
1017 {
1018 gint row;
1019
1020 row = list_row_find_proximity(ld, x, y);
1021 list_row_prelight_set(ld, pb, ui, row);
1022 }
1023 else if (ld->row_prelight != -1)
1024 {
1025 list_row_prelight_set(ld, pb, ui, -1);
1026 }
1027
1028 if (old_prelight != ld->row_prelight && ld->menu_style_select)
1029 {
1030 ListCallbackData *cd;
1031
1032 cd = ui_get_registered_callbacks(ui, key, type_id);
1033 if (cd && cd->menu_move_func)
1034 {
1035 cd->menu_move_func(ld, key, ld->row_prelight, FALSE, FALSE, cd->menu_move_data);
1036 }
1037 }
1038 }
1039
list_press(gpointer data,const gchar * key,gint x,gint y,GdkPixbuf * pb,UIData * ui)1040 static gint list_press(gpointer data, const gchar *key, gint x, gint y, GdkPixbuf *pb, UIData *ui)
1041 {
1042 ListData *ld = data;
1043
1044 if (list_test_proximity(ld, x, y))
1045 {
1046 ListRowData *rd;
1047 GdkEvent *event;
1048 guint32 t;
1049 gint row;
1050
1051 row = list_row_find_proximity(ld, x, y);
1052 if (row == -1) return FALSE;
1053
1054 ld->pressed = TRUE;
1055 ld->press_x = x;
1056 ld->press_y = y;
1057 ld->in_drag = FALSE;
1058
1059 /* peek at current event's time */
1060 event = gtk_get_current_event();
1061 if (event)
1062 {
1063 t = gdk_event_get_time(event);
1064 gdk_event_free(event);
1065 }
1066 else
1067 {
1068 t = 0;
1069 }
1070
1071 rd = g_list_nth_data(ld->row_list, row - ld->row_start);
1072 if (rd)
1073 {
1074 ListCallbackData *cd;
1075
1076 cd = ui_get_registered_callbacks(ui, key, type_id);
1077
1078 if (row == ld->press_row && t - ld->click_time < UI2_LIST_SELECT_TIME)
1079 {
1080 if (cd && cd->row_select_func)
1081 {
1082 cd->row_select_func(ld, key, row, NULL, cd->row_select_data);
1083 }
1084 t = 0;
1085 }
1086 }
1087 else
1088 {
1089 return FALSE;
1090 }
1091
1092 if (row != ld->focus_row)
1093 {
1094 gint old_row;
1095
1096 old_row = ld->focus_row;
1097 ld->focus_row = row;
1098
1099 if (old_row >= 0 && old_row >= ld->row_start && old_row <= ld->row_end)
1100 {
1101 list_draw_row(ld, pb, ui, old_row - ld->row_start, TRUE);
1102 }
1103
1104 if (ld->menu_style_select)
1105 {
1106 ListCallbackData *cd;
1107
1108 cd = ui_get_registered_callbacks(ui, key, type_id);
1109 if (cd && cd->menu_move_func)
1110 {
1111 cd->menu_move_func(ld, key, row, FALSE, FALSE, cd->menu_move_data);
1112 }
1113 }
1114 }
1115
1116 ld->press_row = row;
1117 list_row_press_set(ld, pb, ui, row);
1118 ld->click_time = t;
1119
1120 return TRUE;
1121 }
1122
1123 return FALSE;
1124 }
1125
list_release(gpointer data,const gchar * key,gint x,gint y,GdkPixbuf * pb,UIData * ui)1126 static void list_release(gpointer data, const gchar *key, gint x, gint y, GdkPixbuf *pb, UIData *ui)
1127 {
1128 ListData *ld = data;
1129
1130 if (!ld->pressed) return;
1131
1132 if (list_test_proximity(ld, x, y))
1133 {
1134 gint row;
1135
1136 row = list_row_find_proximity(ld, x, y);
1137 if (row != ld->row_press)
1138 {
1139 list_row_press_set(ld, pb, ui, -1);
1140 }
1141 else if (row >= 0)
1142 {
1143 ListCallbackData *cd;
1144
1145 cd = ui_get_registered_callbacks(ui, key, type_id);
1146
1147 if (cd && cd->row_click_func)
1148 {
1149 cd->row_click_func(ld, key, row, NULL, 1, cd->row_click_data);
1150 }
1151 }
1152
1153 list_row_prelight_set(ld, pb, ui, row);
1154 }
1155 else
1156 {
1157 list_row_press_set(ld, pb, ui, -1);
1158 }
1159
1160 ld->pressed = FALSE;
1161 ld->in_drag = FALSE;
1162 }
1163
list_back_set(gpointer data,GdkPixbuf * pb)1164 static void list_back_set(gpointer data, GdkPixbuf *pb)
1165 {
1166 ListData *ld = data;
1167
1168 list_sync(ld);
1169
1170 if (!ld->overlay || gdk_pixbuf_get_has_alpha(ld->overlay))
1171 {
1172 pixbuf_copy_area(pb, ld->x, ld->y,
1173 ld->pixbuf, 0, 0, ld->width, ld->height, TRUE);
1174 }
1175
1176 pixbuf_copy_fill_border_alpha(ld->overlay, ld->pixbuf,
1177 0, 0,
1178 gdk_pixbuf_get_width(ld->pixbuf), gdk_pixbuf_get_height(ld->pixbuf),
1179 ld->border_left, FALSE,
1180 ld->border_right, FALSE,
1181 ld->border_top, FALSE,
1182 ld->border_bottom, FALSE,
1183 ld->stretch, 255);
1184 }
1185
list_key_event_cb(gpointer widget,const gchar * key,GdkEventKey * event,GdkPixbuf * pb,UIData * ui)1186 static gint list_key_event_cb(gpointer widget, const gchar *key, GdkEventKey *event, GdkPixbuf *pb, UIData *ui)
1187 {
1188 ListData *ld = widget;
1189 gint ret = FALSE;
1190 gint new_row;
1191 gint old_row;
1192
1193 if (event->state & GDK_CONTROL_MASK) return FALSE;
1194
1195 old_row = new_row = ld->focus_row;
1196
1197 switch (event->keyval)
1198 {
1199 case GDK_space:
1200 if (new_row >= 0)
1201 {
1202 ListCallbackData *cd;
1203
1204 cd = ui_get_registered_callbacks(ui, key, type_id);
1205 if (cd && cd->row_click_func)
1206 {
1207 cd->row_click_func(ld, key, new_row, NULL, 0, cd->row_click_data);
1208 }
1209 }
1210 ret = TRUE;
1211 break;
1212 case GDK_Return:
1213 case GDK_KP_Enter:
1214 if (new_row >= 0)
1215 {
1216 ListCallbackData *cd;
1217
1218 cd = ui_get_registered_callbacks(ui, key, type_id);
1219 if (cd && cd->row_select_func)
1220 {
1221 cd->row_select_func(ld, key, new_row, NULL, cd->row_select_data);
1222 }
1223 }
1224 ret = TRUE;
1225 break;
1226 case GDK_Left:
1227 case GDK_KP_Left:
1228 case GDK_Right:
1229 case GDK_KP_Right:
1230 if (ld->menu_style_select)
1231 {
1232 ListCallbackData *cd;
1233
1234 cd = ui_get_registered_callbacks(ui, key, type_id);
1235 if (cd && cd->menu_move_func)
1236 {
1237 gint up;
1238
1239 up = (event->keyval == GDK_Right || event->keyval == GDK_KP_Right);
1240 ret = cd->menu_move_func(ld, key, new_row, TRUE, up, cd->menu_move_data);
1241 }
1242 }
1243 break;
1244 case GDK_Up:
1245 case GDK_KP_Up:
1246 new_row--;
1247 break;
1248 case GDK_Down:
1249 case GDK_KP_Down:
1250 new_row++;
1251 break;
1252 case GDK_Page_Up:
1253 case GDK_KP_Page_Up:
1254 new_row -= MAX((list_rows_visible(ld) - 1), 1);
1255 ret = TRUE;
1256 break;
1257 case GDK_Page_Down:
1258 case GDK_KP_Page_Down:
1259 new_row += MAX((list_rows_visible(ld) - 1), 1);
1260 ret = TRUE;
1261 break;
1262 case GDK_Home:
1263 case GDK_KP_Home:
1264 new_row = 0;
1265 ret = TRUE;
1266 break;
1267 case GDK_End:
1268 case GDK_KP_End:
1269 new_row = ld->row_count - 1;
1270 ret = TRUE;
1271 break;
1272 default:
1273 break;
1274 }
1275
1276 if (new_row > ld->row_count - 1)
1277 {
1278 new_row = ld->row_count - 1;
1279 }
1280 else if (new_row < 0 && ld->row_count > 0)
1281 {
1282 new_row = 0;
1283 }
1284
1285 ret = (ret || (ld->focus_row != new_row));
1286 ld->focus_row = new_row;
1287
1288 if (new_row >= 0)
1289 {
1290 if (new_row < ld->row_start)
1291 {
1292 list_row_scroll_by_row(ld, pb, ui, key, new_row - ld->row_start);
1293 }
1294 else if (new_row > ld->row_end)
1295 {
1296 list_row_scroll_by_row(ld, pb, ui, key, new_row - ld->row_end);
1297 }
1298 else
1299 {
1300 /* scrolling handles redraws, no scroll do it ourselves */
1301 if (old_row >= ld->row_start && old_row <= ld->row_end)
1302 {
1303 list_draw_row(ld, pb, ui, old_row - ld->row_start, TRUE);
1304 }
1305 list_draw_row(ld, pb, ui, new_row - ld->row_start, TRUE);
1306 }
1307
1308 if (ld->menu_style_select)
1309 {
1310 ListCallbackData *cd;
1311
1312 cd = ui_get_registered_callbacks(ui, key, type_id);
1313 if (cd && cd->menu_move_func)
1314 {
1315 cd->menu_move_func(ld, key, new_row, FALSE, FALSE, cd->menu_move_data);
1316 }
1317 }
1318 }
1319
1320 return ret;
1321 }
1322
list_focus_draw_cb(gpointer widget,const gchar * key,gint x,gint y,gint w,gint h,GdkPixbuf * pb,UIData * ui)1323 static gint list_focus_draw_cb(gpointer widget, const gchar *key,
1324 gint x, gint y, gint w, gint h, GdkPixbuf *pb, UIData *ui)
1325 {
1326 ListData *ld = widget;
1327 gint rx, ry, rw, rh;
1328
1329 if (ld->focus_row < 0 ||
1330 ld->focus_row < ld->row_start ||
1331 ld->focus_row > ld->row_end) return TRUE;
1332
1333 rx = ld->border_left;
1334 ry = (ld->focus_row - ld->row_start) * ld->row_height + ld->border_top;
1335 rw = ld->region_width;
1336 rh = ld->row_height;
1337
1338 ui_display_draw_focus(ui, pb, ld->x + rx, ld->y + ry, rw, rh,
1339 x, y, w, h, NULL);
1340
1341 return TRUE;
1342 }
1343
list_get_geometry(gpointer widget,gint * x,gint * y,gint * w,gint * h)1344 static gint list_get_geometry(gpointer widget, gint *x, gint *y, gint *w, gint *h)
1345 {
1346 ListData *ld = widget;
1347
1348 *x = ld->x;
1349 *y = ld->y;
1350 *w = ld->width;
1351 *h = ld->height;
1352
1353 return TRUE;
1354 }
1355
list_set_coord(gpointer widget,gint x,gint y)1356 static void list_set_coord(gpointer widget, gint x, gint y)
1357 {
1358 ListData *ld = widget;
1359
1360 ld->x = x;
1361 ld->y = y;
1362 }
1363
list_set_size(gpointer widget,gint dev_w,gint dev_h)1364 static void list_set_size(gpointer widget, gint dev_w, gint dev_h)
1365 {
1366 ListData *ld = widget;
1367 WidgetData *wd;
1368
1369 if (!ld->sizeable) return;
1370
1371 if (ld->skin)
1372 {
1373 wd = skin_widget_get_by_widget(ld->skin, ld);
1374 }
1375 else
1376 {
1377 wd = NULL;
1378 }
1379
1380 if (!wd || !wd->anchor_right)
1381 {
1382 ld->width = MAX(ld->width + dev_w,
1383 ld->border_left + ld->border_right + ld->row_border_left + ld->row_border_right + 4);
1384 }
1385 if (!wd || !wd->anchor_bottom)
1386 {
1387 ld->height = MAX(ld->height + dev_h, ld->border_top + ld->border_bottom + ld->row_height);
1388 }
1389
1390 list_sync(ld);
1391 }
1392
list_parse(SkinData * skin,GList * list,const gchar * skin_dir,const gchar * key,gint edit)1393 static WidgetData *list_parse(SkinData *skin, GList *list, const gchar *skin_dir, const gchar *key, gint edit)
1394 {
1395 WidgetData *wd = NULL;
1396 ListData *ld;
1397 gint x, y;
1398 gint w, h;
1399 gint sizeable;
1400 gint border_top;
1401 gint border_right;
1402 gint border_bottom;
1403 gint border_left;
1404 gint center_stretch;
1405 gint columns;
1406 gint columns_right_justify;
1407 gchar *filename;
1408 gchar *row_filename;
1409 gchar *divider_filename;
1410 gchar *flag_filename;
1411 gchar *text_filename;
1412 const gchar *font_desc;
1413 gint r, g, b, a;
1414 gint flag_sections;
1415 gint flag_column;
1416 gint row_prelight;
1417 gint row_press;
1418 gint row_stretch;
1419 gint row_border_left;
1420 gint row_border_right;
1421 gint text_extended;
1422
1423
1424 /* req */
1425 if (!key_list_read_int(list, "x", &x)) return NULL;
1426 if (!key_list_read_int(list, "y", &y)) return NULL;
1427
1428 if (!key_list_read_int(list, "width", &w)) return NULL;
1429 if (!key_list_read_int(list, "height", &h)) return NULL;
1430
1431 if (!key_list_read_int(list, "border_top", &border_top)) return NULL;
1432 if (!key_list_read_int(list, "border_right", &border_right)) return NULL;
1433 if (!key_list_read_int(list, "border_bottom", &border_bottom)) return NULL;
1434 if (!key_list_read_int(list, "border_left", &border_left)) return NULL;
1435
1436 if (!key_list_read_int(list, "row_border_left", &row_border_left)) return NULL;
1437 if (!key_list_read_int(list, "row_border_right", &row_border_right)) return NULL;
1438
1439 if (!key_list_read_int(list, "columns", &columns)) return NULL;
1440 if (columns < 1) return NULL;
1441
1442 filename = key_list_read_path(list, "image", skin_dir);
1443 row_filename = key_list_read_path(list, "row_image", skin_dir);
1444 text_filename = key_list_read_path(list, "text_image", skin_dir);
1445 font_desc = key_list_read_chars(list, "text_font", NULL);
1446 if (!filename || !row_filename || (!text_filename && !font_desc) )
1447 {
1448 g_free(filename);
1449 g_free(row_filename);
1450 g_free(text_filename);
1451 return NULL;
1452 }
1453
1454 /* opt */
1455 sizeable = key_list_read_bool(list, "sizeable");
1456 center_stretch = key_list_read_bool(list, "center_stretch");
1457
1458 row_prelight = key_list_read_bool(list, "row_prelight");
1459 row_press = key_list_read_bool(list, "row_pressable");
1460 row_stretch = key_list_read_bool(list, "row_stretch");
1461
1462 divider_filename = key_list_read_path(list, "divider_image", skin_dir);
1463 flag_filename = key_list_read_path(list, "flag_image", skin_dir);
1464 if (!key_list_read_int(list, "flag_sections", &flag_sections)) flag_sections = 1;
1465 if (!key_list_read_int(list, "flag_column", &flag_column)) flag_column = 0;
1466
1467 columns_right_justify = key_list_read_bool(list, "columns_right_justify");
1468
1469 text_extended = key_list_read_bool(list, "text_extended");
1470
1471 if (!key_list_read_int(list, "text_red", &r)) r = 0;
1472 if (!key_list_read_int(list, "text_green", &g)) g = 0;
1473 if (!key_list_read_int(list, "text_blue", &b)) b = 0;
1474 if (!key_list_read_int(list, "text_alpha", &a)) a = 255;
1475
1476 ld = list_new(util_pixbuf_new_from_file(filename), x, y, w, h, sizeable, columns,
1477 border_top, border_right, border_bottom, border_left, center_stretch);
1478 if (ld)
1479 {
1480 gint i;
1481
1482 list_image_row(ld, util_pixbuf_new_from_file(row_filename), row_press, row_prelight,
1483 row_border_left, row_border_right, row_stretch,
1484 divider_filename ? util_pixbuf_new_from_file(divider_filename) : NULL);
1485
1486 if (text_filename)
1487 {
1488 list_set_font(ld, NULL, util_pixbuf_new_from_file(text_filename), text_extended, r, g, b, a);
1489 }
1490 else
1491 {
1492 list_set_font(ld, font_desc, NULL, FALSE, r, g, b, a);
1493 }
1494
1495 if (flag_filename) list_image_row_flag(ld, util_pixbuf_new_from_file(flag_filename), flag_sections, flag_column);
1496
1497 list_set_column_justify(ld, columns_right_justify);
1498
1499 for (i = 0; i < columns; i++)
1500 {
1501 gchar *buf;
1502 gint length;
1503 ListColumnFlags flags = 0;
1504 const gchar *key;
1505
1506 buf = g_strdup_printf("column_%d_key", i);
1507 key = key_list_read_chars(list, buf, NULL);
1508 g_free(buf);
1509
1510 buf = g_strdup_printf("column_%d_width", i);
1511 if (!key_list_read_int(list, buf, &length)) length = 1;
1512 g_free(buf);
1513
1514 buf = g_strdup_printf("column_%d_proportional", i);
1515 if (key_list_read_bool(list, buf))
1516 flags |= UI_LIST_COLUMN_SIZE_PROPORTIONAL;
1517 else
1518 flags |= UI_LIST_COLUMN_SIZE_FIXED;
1519 g_free(buf);
1520
1521 buf = g_strdup_printf("column_%d_right_justify", i);
1522 if (key_list_read_bool(list, buf)) flags |= UI_LIST_COLUMN_JUSTIFY_RIGHT;
1523 g_free(buf);
1524
1525 list_set_column_attributes(ld, i, length, flags, key);
1526 }
1527
1528 if (!ld->row_overlay || !ld->font)
1529 {
1530 if (!ld->font) printf("list warning: failed to load font.\n");
1531 if (!ld->row_overlay) printf("list warning: failed to load row image.\n");
1532
1533 list_free(ld);
1534 ld = NULL;
1535 }
1536 }
1537
1538 if (ld)
1539 {
1540 wd = list_register(skin, ld, key, NULL);
1541
1542 if (edit)
1543 {
1544 ui_widget_set_data(wd, "image", filename);
1545 ui_widget_set_data(wd, "row_image", row_filename);
1546 ui_widget_set_data(wd, "text_image", text_filename);
1547 ui_widget_set_data(wd, "divider_image", divider_filename);
1548 ui_widget_set_data(wd, "flag_image", flag_filename);
1549 }
1550 }
1551
1552 g_free(filename);
1553 g_free(row_filename);
1554 g_free(text_filename);
1555 g_free(divider_filename);
1556 g_free(flag_filename);
1557
1558 return wd;
1559 }
1560
1561 /*
1562 *-----------------------------
1563 * register ui / app side
1564 *-----------------------------
1565 */
1566
list_register(SkinData * skin,ListData * ld,const gchar * key,const gchar * text_id)1567 WidgetData *list_register(SkinData *skin, ListData *ld, const gchar *key, const gchar *text_id)
1568 {
1569 if (!ld || !ld->font)
1570 {
1571 printf("warning: attempt to register list \"%s\" will NULL font.\n", key);
1572 }
1573 if (ld) ld->skin = skin;
1574
1575 return skin_register_widget(skin, key, text_id, type_id, ld);
1576 }
1577
list_register_key(const gchar * key,UIData * ui,gint (* length_request_func)(ListData * list,const gchar * key,gpointer data),gpointer length_request_data,gint (* row_info_func)(ListData * list,const gchar * key,gint row,ListRowData * rd,gpointer data),gpointer row_info_data,void (* row_click_func)(ListData * list,const gchar * key,gint row,ListRowData * rd,gint button,gpointer data),gpointer row_click_data,void (* row_select_func)(ListData * list,const gchar * key,gint row,ListRowData * rd,gpointer data),gpointer row_select_data,gint (* row_move_func)(ListData * list,const gchar * key,gint source_row,gint dest_row,gpointer data),gpointer row_move_data)1578 RegisterData *list_register_key(const gchar *key, UIData *ui,
1579 gint (*length_request_func)(ListData *list, const gchar *key, gpointer data), gpointer length_request_data,
1580 gint (*row_info_func)(ListData *list, const gchar *key, gint row, ListRowData *rd, gpointer data), gpointer row_info_data,
1581 void (*row_click_func)(ListData *list, const gchar *key, gint row, ListRowData *rd, gint button, gpointer data), gpointer row_click_data,
1582 void (*row_select_func)(ListData *list, const gchar *key, gint row, ListRowData *rd, gpointer data), gpointer row_select_data,
1583 gint (*row_move_func)(ListData *list, const gchar *key, gint source_row, gint dest_row, gpointer data), gpointer row_move_data)
1584 {
1585 ListCallbackData *cd;
1586
1587 list_type_init();
1588
1589 cd = g_new0(ListCallbackData, 1);
1590
1591 cd->length_request_func = length_request_func;
1592 cd->row_info_func = row_info_func;
1593 cd->row_click_func = row_click_func;
1594 cd->row_select_func = row_select_func;
1595 cd->row_move_func = row_move_func;
1596
1597 cd->length_request_data = length_request_data;
1598 cd->row_info_data = row_info_data;
1599 cd->row_click_data = row_click_data;
1600 cd->row_select_data = row_select_data;
1601 cd->row_move_data = row_move_data;
1602
1603 cd ->menu_move_func = NULL;
1604 cd ->menu_move_data = NULL;
1605
1606 return ui_register_key(ui, key, type_id, cd, sizeof(ListCallbackData));
1607 }
1608
list_register_menu_funcs(const gchar * key,UIData * ui,gint (* func)(ListData * list,const gchar * key,gint row,gint activated,gint up,gpointer data),gpointer data)1609 void list_register_menu_funcs(const gchar *key, UIData *ui,
1610 gint (*func)(ListData *list, const gchar *key, gint row, gint activated, gint up, gpointer data),
1611 gpointer data)
1612 {
1613 ListCallbackData *cd;
1614
1615 cd = ui_get_registered_callbacks(ui, key, type_id);
1616
1617 if (cd)
1618 {
1619 cd ->menu_move_func = func;
1620 cd ->menu_move_data = data;
1621 }
1622 }
1623
1624 /*
1625 *-----------------------------
1626 * app funcs
1627 *-----------------------------
1628 */
1629
list_row_insert_cb(WidgetData * wd,gpointer data,GdkPixbuf * pb,UIData * ui)1630 static void list_row_insert_cb(WidgetData *wd, gpointer data, GdkPixbuf *pb, UIData *ui)
1631 {
1632 ListData *ld;
1633 gint row;
1634
1635 ld = wd->widget;
1636 row = GPOINTER_TO_INT(data);
1637
1638 if (list_length_sync(ld, ld->row_count + 1, FALSE))
1639 {
1640 list_row_sync_n(ld, ui, wd->key, 0, ld->row_end - ld->row_start, NULL);
1641 list_draw_rows(ld, pb, ui, 0, ld->row_end - ld->row_start, TRUE);
1642 }
1643 else if (row < ld->row_start)
1644 {
1645 list_row_scroll_by_row(ld, pb, ui, wd->key, 1);
1646 }
1647 else if (row <= ld->row_end)
1648 {
1649 list_row_sync_n(ld, ui, wd->key, row - ld->row_start, ld->row_end - ld->row_start, NULL);
1650 list_draw_rows(ld, pb, ui, row - ld->row_start, ld->row_end - ld->row_start, TRUE);
1651 }
1652 }
1653
list_row_insert(const gchar * key,UIData * ui,gint row)1654 gint list_row_insert(const gchar *key, UIData *ui, gint row)
1655 {
1656 return skin_widget_for_each_key(ui, key, type_id, list_row_insert_cb, GINT_TO_POINTER(row));
1657 }
1658
list_row_remove_cb(WidgetData * wd,gpointer data,GdkPixbuf * pb,UIData * ui)1659 static void list_row_remove_cb(WidgetData *wd, gpointer data, GdkPixbuf *pb, UIData *ui)
1660 {
1661 ListData *ld;
1662 gint row;
1663
1664 ld = wd->widget;
1665 row = GPOINTER_TO_INT(data);
1666
1667 if (ld->row_count > 0)
1668 {
1669 if (list_length_sync(ld, ld->row_count - 1, FALSE))
1670 {
1671 list_row_sync_n(ld, ui, wd->key, 0, ld->row_end - ld->row_start, NULL);
1672 list_draw_all_rows(ld, pb, ui, TRUE);
1673 }
1674 else if (row < ld->row_start)
1675 {
1676 list_row_scroll_by_row(ld, pb, ui, wd->key, -1);
1677 }
1678 else if (row <= ld->row_end)
1679 {
1680 list_row_sync_n(ld, ui, wd->key, row - ld->row_start, ld->row_end - ld->row_start, NULL);
1681 list_draw_rows(ld, pb, ui, row - ld->row_start, ld->row_end - ld->row_start, TRUE);
1682 list_draw_empty_rows(ld, pb, ui, TRUE);
1683 }
1684 }
1685 }
1686
list_row_remove(const gchar * key,UIData * ui,gint row)1687 gint list_row_remove(const gchar *key, UIData *ui, gint row)
1688 {
1689 return skin_widget_for_each_key(ui, key, type_id, list_row_remove_cb, GINT_TO_POINTER(row));
1690 }
1691
list_row_update_cb(WidgetData * wd,gpointer data,GdkPixbuf * pb,UIData * ui)1692 static void list_row_update_cb(WidgetData *wd, gpointer data, GdkPixbuf *pb, UIData *ui)
1693 {
1694 ListData *ld;
1695 gint row;
1696
1697 ld = wd->widget;
1698 row = GPOINTER_TO_INT(data);
1699
1700 if (row < ld->row_start || row > ld->row_end) return;
1701
1702 list_row_sync(ld, ui, wd->key, row);
1703 list_redraw_row(ld, pb, ui, row - ld->row_start);
1704 }
1705
list_row_update(const gchar * key,UIData * ui,gint row)1706 gint list_row_update(const gchar *key, UIData *ui, gint row)
1707 {
1708 return skin_widget_for_each_key(ui, key, type_id, list_row_update_cb, GINT_TO_POINTER(row));
1709 }
1710
list_refresh_cb(WidgetData * wd,gpointer data,GdkPixbuf * pb,UIData * ui)1711 static void list_refresh_cb(WidgetData *wd, gpointer data, GdkPixbuf *pb, UIData *ui)
1712 {
1713 ListData *ld;
1714 ListCallbackData *cd;
1715 gint length = 0;
1716
1717 ld = wd->widget;
1718
1719 cd = ui_get_registered_callbacks(ui, wd->key, type_id);
1720 if (cd && cd->length_request_func)
1721 {
1722 length = cd->length_request_func(ld, wd->key, cd->length_request_data);
1723 }
1724
1725 ld->row_count = length;
1726 list_length_sync(ld, length, TRUE);
1727 list_row_sync_n(ld, ui, wd->key, 0, ld->row_end - ld->row_start, cd);
1728 list_draw_all_rows(ld, pb, ui, FALSE);
1729
1730 ui_display_render_area(ui, ld->x + ld->border_left, ld->y + ld->border_top,
1731 ld->region_width, ld->region_height, ld->wd);
1732 }
1733
list_refresh(const gchar * key,UIData * ui)1734 gint list_refresh(const gchar *key, UIData *ui)
1735 {
1736 return skin_widget_for_each_key(ui, key, type_id, list_refresh_cb, NULL);
1737 }
1738
list_scroll_row_cb(WidgetData * wd,gpointer data,GdkPixbuf * pb,UIData * ui)1739 static void list_scroll_row_cb(WidgetData *wd, gpointer data, GdkPixbuf *pb, UIData *ui)
1740 {
1741 ListData *ld;
1742 gint rows;
1743
1744 ld = wd->widget;
1745 rows = GPOINTER_TO_INT(data);
1746
1747 list_row_scroll_by_row(ld, pb, ui, wd->key, rows);
1748 }
1749
list_scroll_row(const gchar * key,UIData * ui,gint rows)1750 gint list_scroll_row(const gchar *key, UIData *ui, gint rows)
1751 {
1752 return skin_widget_for_each_key(ui, key, type_id, list_scroll_row_cb, GINT_TO_POINTER(rows));
1753 }
1754
list_scroll_to_cb(WidgetData * wd,gpointer data,GdkPixbuf * pb,UIData * ui)1755 static void list_scroll_to_cb(WidgetData *wd, gpointer data, GdkPixbuf *pb, UIData *ui)
1756 {
1757 ListData *ld;
1758 gint row;
1759
1760 ld = wd->widget;
1761 row = GPOINTER_TO_INT(data);
1762
1763 list_row_scroll_by_row(ld, pb, ui, wd->key, row - ld->row_start);
1764 }
1765
list_scroll_to(const gchar * key,UIData * ui,gint row)1766 gint list_scroll_to(const gchar *key, UIData *ui, gint row)
1767 {
1768 return skin_widget_for_each_key(ui, key, type_id, list_scroll_to_cb, GINT_TO_POINTER(row));
1769 }
1770
list_set_menu_style(ListData * ld,gint menu_style)1771 void list_set_menu_style(ListData *ld, gint menu_style)
1772 {
1773 if (ld) ld->menu_style_select = menu_style;
1774 }
1775
1776 /*
1777 *-----------------------------
1778 * internal signals
1779 *-----------------------------
1780 */
1781
list_scroll_timeout_cancel(ListData * ld)1782 static void list_scroll_timeout_cancel(ListData *ld)
1783 {
1784 if (ld->timeout_id != -1)
1785 {
1786 g_source_remove(ld->timeout_id);
1787 ld->timeout_id = -1;
1788 }
1789 ld->scroll_count = 0;
1790 }
1791
list_scroll_button_down_delay(gpointer data)1792 static gint list_scroll_button_down_delay(gpointer data)
1793 {
1794 ListData *ld = data;
1795
1796 list_row_scroll_by_row(ld, skin_get_pixbuf(ld->ui->skin), ld->ui, ld->wd->key, 1);
1797
1798 if (ld->scroll_count < UI2_LIST_SCROLL_SPEEDUP)
1799 {
1800 ld->scroll_count++;
1801 if (ld->scroll_count >= UI2_LIST_SCROLL_SPEEDUP)
1802 {
1803 ld->timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, UI2_LIST_SCROLL_DELAY_FAST,
1804 list_scroll_button_down_delay, ld, NULL);
1805 return FALSE;
1806 }
1807 }
1808
1809 return TRUE;
1810 }
1811
list_scroll_button_down_press(ButtonData * button,const gchar * key,gpointer data)1812 static void list_scroll_button_down_press(ButtonData *button, const gchar *key, gpointer data)
1813 {
1814 ListData *ld = data;
1815
1816 list_row_scroll_by_row(ld, skin_get_pixbuf(ld->ui->skin), ld->ui, ld->wd->key, 1);
1817 list_scroll_timeout_cancel(ld);
1818 ld->timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, UI2_LIST_SCROLL_DELAY,
1819 list_scroll_button_down_delay, ld, NULL);
1820 }
1821
list_scroll_button_down_release(ButtonData * button,const gchar * key,gpointer data)1822 static void list_scroll_button_down_release(ButtonData *button, const gchar *key, gpointer data)
1823 {
1824 ListData *ld = data;
1825
1826 list_scroll_timeout_cancel(ld);
1827 }
1828
list_scroll_button_up_delay(gpointer data)1829 static gint list_scroll_button_up_delay(gpointer data)
1830 {
1831 ListData *ld = data;
1832
1833 list_row_scroll_by_row(ld, skin_get_pixbuf(ld->ui->skin), ld->ui, ld->wd->key, -1);
1834
1835 if (ld->scroll_count < UI2_LIST_SCROLL_SPEEDUP)
1836 {
1837 ld->scroll_count++;
1838 if (ld->scroll_count >= UI2_LIST_SCROLL_SPEEDUP)
1839 {
1840 ld->timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, UI2_LIST_SCROLL_DELAY_FAST,
1841 list_scroll_button_up_delay, ld, NULL);
1842 return FALSE;
1843 }
1844 }
1845
1846 return TRUE;
1847 }
1848
list_scroll_button_up_press(ButtonData * button,const gchar * key,gpointer data)1849 static void list_scroll_button_up_press(ButtonData *button, const gchar *key, gpointer data)
1850 {
1851 ListData *ld = data;
1852
1853 list_row_scroll_by_row(ld, skin_get_pixbuf(ld->ui->skin), ld->ui, ld->wd->key, -1);
1854 list_scroll_timeout_cancel(ld);
1855 ld->timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, UI2_LIST_SCROLL_DELAY,
1856 list_scroll_button_up_delay, ld, NULL);
1857 }
1858
list_scroll_button_up_release(ButtonData * button,const gchar * key,gpointer data)1859 static void list_scroll_button_up_release(ButtonData *button, const gchar *key, gpointer data)
1860 {
1861 ListData *ld = data;
1862
1863 list_scroll_timeout_cancel(ld);
1864 }
1865
list_scroll_position(ListData * ld)1866 static gfloat list_scroll_position(ListData *ld)
1867 {
1868 gint vis = list_rows_visible(ld);
1869
1870 if (ld->row_start == 0 || ld->row_count <= vis) return 0.0;
1871
1872 return (float)ld->row_start / (ld->row_count - vis);
1873 }
1874
list_scroll_slider_status(SliderData * slider,const gchar * key,gpointer data)1875 static gfloat list_scroll_slider_status(SliderData *slider, const gchar *key, gpointer data)
1876 {
1877 ListData *ld = data;
1878
1879 return list_scroll_position(ld);
1880 }
1881
list_scroll_idle_cb(gpointer data)1882 static gint list_scroll_idle_cb(gpointer data)
1883 {
1884 ListData *ld = data;
1885
1886 if (ld->scroll_idle_id == -1) return FALSE;
1887
1888 list_row_scroll(ld, skin_get_pixbuf(ld->ui->skin), ld->ui, ld->wd->key, ld->scroll_idle_value);
1889
1890 ld->scroll_idle_id = -1;
1891 return FALSE;
1892 }
1893
list_scroll_slider_drag(SliderData * slider,const gchar * key,gfloat value,gpointer data)1894 static void list_scroll_slider_drag(SliderData *slider, const gchar *key, gfloat value, gpointer data)
1895 {
1896 ListData *ld = data;
1897
1898 ld->scroll_idle_value = value;
1899 if (ld->scroll_idle_id == -1) ld->scroll_idle_id = g_idle_add(list_scroll_idle_cb, ld);
1900 }
1901
list_init(gpointer widget,const gchar * key,UIData * ui)1902 static void list_init(gpointer widget, const gchar *key, UIData *ui)
1903 {
1904 ListData *ld = widget;
1905 RegisterData *rd;
1906 gchar *buf;
1907 WidgetData *wd;
1908
1909 wd = skin_widget_get_by_widget(ui->skin, widget);
1910 ld->wd = wd;
1911 ld->ui = ui;
1912
1913 buf = g_strdup_printf("list_%s_scroll_down", key);
1914 rd = button_register_key(buf, ui,
1915 NULL, NULL,
1916 NULL, NULL,
1917 list_scroll_button_down_press, ld,
1918 list_scroll_button_down_release, ld);
1919 rd->private = TRUE;
1920 rd->private_widget = ld;
1921 g_free(buf);
1922
1923 buf = g_strdup_printf("list_%s_scroll_up", key);
1924 rd = button_register_key(buf, ui,
1925 NULL, NULL,
1926 NULL, NULL,
1927 list_scroll_button_up_press, ld,
1928 list_scroll_button_up_release, ld);
1929 rd->private = TRUE;
1930 rd->private_widget = ld;
1931 g_free(buf);
1932
1933 buf = g_strdup_printf("list_%s_scroll", key);
1934 rd = slider_register_key(buf, ui,
1935 list_scroll_slider_status, ld,
1936 list_scroll_slider_drag, ld,
1937 NULL, NULL,
1938 list_scroll_slider_drag, ld);
1939 rd->private = TRUE;
1940 rd->private_widget = ld;
1941 g_free(buf);
1942 }
1943
list_scroll_update_widgets(ListData * ld)1944 static void list_scroll_update_widgets(ListData *ld)
1945 {
1946 gchar *buf;
1947 gint total;
1948 gint vis;
1949
1950 if (!ld->ui) return;
1951
1952 vis = list_rows_visible(ld);
1953 total = ld->row_count - vis;
1954
1955 buf = g_strdup_printf("list_%s_scroll", ld->wd->key);
1956 slider_value_set(buf, ld->ui, list_scroll_position(ld));
1957 slider_step_size_set(buf, ld->ui,
1958 (total > 0) ? (1.0 / (float)total) : 0.1,
1959 (vis > 1) ? vis - 1 : vis);
1960 g_free(buf);
1961 }
1962
1963 /*
1964 *-----------------------------
1965 * init
1966 *-----------------------------
1967 */
1968
list_type_id(void)1969 WidgetType list_type_id(void)
1970 {
1971 return type_id;
1972 }
1973
list_type_init(void)1974 void list_type_init(void)
1975 {
1976 WidgetObjectData *od;
1977
1978 if (type_id != -1) return;
1979
1980 od = ui_widget_type_new("list");
1981 type_id = od->type;
1982
1983 od->func_draw = list_draw;
1984 od->func_reset = list_reset;
1985 od->func_press = list_press;
1986 od->func_release = list_release;
1987 od->func_motion = list_motion;
1988 od->func_back = list_back_set;
1989 od->func_free = list_free_cb;
1990
1991 od->func_focus_key_event = list_key_event_cb;
1992 od->func_focus_draw = list_focus_draw_cb;
1993
1994 od->func_get_geometry = list_get_geometry;
1995 od->func_set_coord = list_set_coord;
1996 od->func_set_size = list_set_size;
1997
1998 od->func_parse = list_parse;
1999 od->func_init = list_init;
2000
2001 list_type_init_edit(od);
2002 }
2003
2004