1 /*
2 * Copyright (C) 2002-2003 Stefan Holst
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA.
17 *
18 * otk - the osd toolkit
19 */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <math.h>
27 #include <errno.h>
28 #include "oxine.h"
29 #include "odk.h"
30 #include "otk.h"
31 #include "list.h"
32 #include "utils.h"
33
34 /*
35 #define LOG
36 */
37
38 #define OTK_WIDGET_WINDOW (1)
39 #define OTK_WIDGET_BUTTON (2)
40 #define OTK_WIDGET_LABEL (3)
41 #define OTK_WIDGET_LIST (4)
42 #define OTK_WIDGET_LISTENTRY (5)
43 #define OTK_WIDGET_SLIDER (6)
44 #define OTK_WIDGET_SELECTOR (7)
45 #define OTK_WIDGET_LAYOUT (8)
46 #define OTK_WIDGET_SCROLLBAR (9)
47
48 #define OTK_BUTTON_TEXT (1)
49 #define OTK_BUTTON_PIXMAP (2)
50
51 typedef struct otk_button_s otk_button_t;
52 typedef struct otk_label_s otk_label_t;
53 typedef struct otk_window_s otk_window_t;
54 typedef struct otk_list_s otk_list_t;
55 typedef struct otk_listentry_s otk_listentry_t;
56 typedef struct otk_slider_s otk_slider_t;
57 typedef struct otk_scrollbar_s otk_scrollbar_t;
58 typedef struct otk_selector_s otk_selector_t;
59 typedef struct otk_layout_s otk_layout_t;
60
61 struct otk_widget_s {
62
63 int widget_type;
64
65 int x, y, w, h;
66 int focus;
67 int selectable;
68 int needupdate;
69 int needcalc; /* used by layout container */
70 int major; /* if parent otk_window_t should draw/destroy this widget set this to 0 */
71
72 otk_t *otk;
73 odk_t *odk;
74
75 otk_widget_t *win;
76
77 void (*draw) (otk_widget_t *this);
78 void (*destroy) (otk_widget_t *this);
79 void (*select_cb) (otk_widget_t *this);
80
81 };
82
83 struct otk_layout_s {
84 otk_widget_t widget;
85 g_list_t *subs;
86 int rows, columns;
87 };
88
89 struct otk_slider_s {
90 otk_widget_t widget;
91
92 int old_pos;
93 otk_slider_cb_t get_value;
94 };
95
96 struct otk_scrollbar_s {
97 otk_widget_t widget;
98
99 int pos_start;
100 int pos_end;
101
102 otk_button_cb_t cb_up;
103 otk_button_cb_t cb_down;
104 void *cb_data;
105 };
106
107 struct otk_button_s {
108
109 otk_widget_t widget;
110
111 char *text;
112 uint8_t *pixmap;
113 otk_button_cb_t cb;
114 otk_button_uc_t uc;
115 void *cb_data;
116 void *uc_data;
117 int type;
118 };
119
120 struct otk_selector_s {
121
122 otk_widget_t widget;
123
124 g_list_t *items;
125 otk_selector_cb_t cb;
126 void *cb_data;
127 int pos;
128 };
129
130 struct otk_listentry_s {
131
132 otk_widget_t widget;
133
134 char *text;
135 otk_list_t *list;
136
137 int pos;
138 int number;
139 int visible;
140 int isfirst, islast;
141
142 void *data;
143 };
144
145 struct otk_list_s {
146
147 otk_widget_t widget;
148
149 g_list_t *entries; /* of otk_listentry_t */
150 int position;
151
152 int entry_height;
153 int entries_visible;
154 int num_entries;
155 int last_selected;
156
157 int font_size;
158 char *font;
159
160 otk_list_cb_t cb;
161 void *cb_data;
162
163 otk_widget_t *scrollbar;
164 };
165
166 struct otk_label_s {
167
168 otk_widget_t widget;
169
170 char *text;
171 int alignment;
172 int font_size;
173 };
174
175 struct otk_window_s {
176
177 otk_widget_t widget;
178
179 int fill_color;
180 g_list_t *subs;
181 };
182
183 struct otk_s {
184
185 odk_t *odk;
186
187 g_list_t *windows;
188
189 otk_widget_t *focus_ptr;
190
191 int showing;
192
193 int textcolor_win;
194 int textcolor_but;
195 int col_sl1, col_sl2, col_sl1f, col_sl2f;
196
197 int button_font_size;
198 char *button_font;
199
200 char *label_font;
201 int label_color;
202 int label_font_size;
203 char *title_font;
204 int title_font_size;
205
206 int update_job;
207
208 int (*event_handler)(void *data, oxine_event_t *ev);
209 void *event_handler_data;
210
211
212 pthread_mutex_t draw_mutex;
213 };
214
215
216 /*
217 * private utilities
218 */
219
220 /* truncate the text to a fixed width */
check_text_width(odk_t * odk,char * text,int width)221 static void check_text_width(odk_t *odk, char *text, int width) {
222 int textwidth, num;
223 odk_get_text_size(odk, text, &textwidth, &num);
224
225 if (textwidth > width) {
226 int i=strlen(text)-4;
227
228 if (i<0) return;
229
230 text[i]=text[i+1]=text[i+2]='.';text[i+3]=0;
231
232 odk_get_text_size(odk, text, &textwidth, &num);
233 while ((textwidth > width) && (i>0)) {
234 i--;
235 text[i]='.';
236 text[i+3]=0;
237 odk_get_text_size(odk, text, &textwidth, &num);
238 }
239 }
240 }
241
is_correct_widget(otk_widget_t * widget,int expected)242 static int is_correct_widget(otk_widget_t *widget, int expected) {
243
244 if (!widget) {
245 #ifdef LOG
246 printf("otk: got widget NULL\n");
247 #endif
248 return 0;
249 }
250 if (widget->widget_type != expected) {
251 #ifdef LOG
252 printf("otk: bad widget type %d; expecting %d\n", widget->widget_type, expected);
253 #endif
254 return 0;
255 }
256 return 1;
257 }
258
remove_widget_from_win(otk_widget_t * widget)259 static void remove_widget_from_win(otk_widget_t *widget) {
260
261 otk_window_t *win = (otk_window_t *) widget->win;
262 otk_layout_t *lay = (otk_layout_t *) widget->win;
263
264 if(is_correct_widget(widget->win, OTK_WIDGET_WINDOW)) {
265
266 win->subs = g_list_remove(win->subs, widget);
267
268 }else if (is_correct_widget(widget->win, OTK_WIDGET_LAYOUT)) {
269 otk_window_t *parent = (otk_window_t *) lay->widget.win;
270
271 lay->subs = g_list_remove(lay->subs, widget);
272 parent->subs = g_list_remove(parent->subs, widget);
273 }
274 }
275
276 /*
277 * callback utilities
278 */
279
find_widget_xy(otk_t * otk,int x,int y)280 static otk_widget_t *find_widget_xy (otk_t *otk, int x, int y) {
281
282 g_list_t *cur, *cur2;
283
284 cur = g_list_first (otk->windows);
285
286 while (cur && cur->data) {
287
288 otk_window_t *win = cur->data;
289
290 cur2 = g_list_first (win->subs);
291 while (cur2 && cur2->data) {
292
293 otk_widget_t *widget = cur2->data;
294
295 if ( (widget->x<=x) && (widget->y <= y)
296 && ((widget->x + widget->w) >= x)
297 && ((widget->y + widget->h) >= y)
298 && (widget->selectable) )
299 return widget;
300
301 cur2 = g_list_next (cur2);
302 }
303
304 cur = g_list_next (cur);
305 }
306 return NULL;
307 }
308
309 #define ABS(x) ((x)<0?-(x):(x))
310
get_distance(otk_widget_t * base,otk_widget_t * target)311 static int get_distance(otk_widget_t *base, otk_widget_t *target) {
312
313 int x1 = (base->x+base->w/2)/10;
314 int y1 = (base->y+base->h/2)/10;
315 int x2 = (target->x+target->w/2)/10;
316 int y2 = (target->y+target->h/2)/10;
317 int dist = (int) sqrt (pow((x1-x2),2) + pow((y1-y2),2));
318
319 #ifdef LOG
320 printf("distance: returning: %i\n ", dist);
321 #endif
322
323 return dist;
324 }
325
get_vertical_angle(otk_widget_t * base,otk_widget_t * target)326 static double get_vertical_angle(otk_widget_t *base, otk_widget_t *target) {
327
328 int x1 = base->x+base->w/2;
329 int y1 = base->y+base->h/2;
330 int x2 = target->x+target->w/2;
331 int y2 = target->y+target->h/2;
332 int x = ABS(x1-x2);
333 int y = ABS(y1-y2);
334 double a;
335
336 if (x == 0)
337 a = 0;
338 else
339 a = atan((double)y/(double)x)+1;
340
341 #ifdef LOG
342 printf("vangle: returning: %f\n ", a);
343 #endif
344
345 return a;
346 }
347
get_horizontal_angle(otk_widget_t * base,otk_widget_t * target)348 static double get_horizontal_angle(otk_widget_t *base, otk_widget_t *target) {
349
350 int x1 = base->x+base->w/2;
351 int y1 = base->y+base->h/2;
352 int x2 = target->x+target->w/2;
353 int y2 = target->y+target->h/2;
354 int x = ABS(x1-x2);
355 int y = ABS(y1-y2);
356 double a;
357
358 if (y == 0)
359 a = 0;
360 else
361 a = atan((double)x/(double)y)+1;
362
363 #ifdef LOG
364 printf("hangle: returning: %f\n ", a);
365 #endif
366
367 return a;
368 }
369
370 #define UP 1
371 #define DOWN 2
372 #define LEFT 3
373 #define RIGHT 4
374
find_neighbour(otk_t * otk,int direction)375 static otk_widget_t *find_neighbour (otk_t *otk, int direction) {
376
377 otk_widget_t *neighbour = NULL;
378 int neighbour_ratio = 0;
379 int x = otk->focus_ptr->x+otk->focus_ptr->w/2;
380 int y = otk->focus_ptr->y+otk->focus_ptr->h/2;
381 g_list_t *cur, *cur2;
382
383 cur = g_list_first (otk->windows);
384
385 while (cur && cur->data) {
386
387 otk_window_t *win = cur->data;
388
389 cur2 = g_list_first (win->subs);
390
391 while (cur2 && cur2->data) {
392 otk_widget_t *widget = cur2->data;
393
394 if ( (widget != otk->focus_ptr) && (widget->selectable) ) {
395
396 int ratio = 0;
397 int nx = widget->x+widget->w/2;
398 int ny = widget->y+widget->h/2;
399
400 switch(direction) {
401 case UP:
402 if ((y-ny)<0) break;
403 ratio = get_distance(otk->focus_ptr, widget)
404 * get_horizontal_angle(otk->focus_ptr, widget);
405 break;
406 case DOWN:
407 if ((ny-y)<0) break;
408 ratio = get_distance(otk->focus_ptr, widget)
409 * get_horizontal_angle(otk->focus_ptr, widget);
410 break;
411 case LEFT:
412 if ((x-nx)<0) break;
413 ratio = get_distance(otk->focus_ptr, widget)
414 * get_vertical_angle(otk->focus_ptr, widget);
415 break;
416 case RIGHT:
417 if ((nx-x)<0) break;
418 ratio = get_distance(otk->focus_ptr, widget)
419 * get_vertical_angle(otk->focus_ptr, widget);
420 break;
421 }
422 #ifdef LOG
423 {
424 otk_button_t *but = (otk_button_t*)widget;
425 printf("%s %i\n", but->text, ratio);
426 }
427 #endif
428 if (ratio>0)
429 if((ratio<neighbour_ratio) || !neighbour_ratio ) {
430 neighbour_ratio = ratio;
431 neighbour = widget;
432 }
433 }
434 cur2 = g_list_next (cur2);
435 }
436
437 cur = g_list_next (cur);
438 }
439 #ifdef LOG
440 printf("\n");
441 #endif
442 return neighbour;
443 }
444
445 /*
446 * global callbacks
447 */
448
motion_handler(otk_t * otk,oxine_event_t * ev)449 static void motion_handler (otk_t *otk, oxine_event_t *ev) {
450
451 otk_widget_t *b;
452
453 b = find_widget_xy (otk, ev->x, ev->y);
454
455 if (!b)
456 return;
457
458 if (b->focus)
459 return;
460
461 otk_set_focus(b);
462
463 otk_draw_all (otk);
464 }
465
466 static void list_pgdown (otk_list_t *list);
467 static void list_pgup (otk_list_t *list);
468
button_handler(otk_t * otk,oxine_event_t * ev)469 static void button_handler (otk_t *otk, oxine_event_t *ev) {
470
471 otk_widget_t *b;
472
473 b = find_widget_xy (otk, ev->x, ev->y);
474
475 if (!b)
476 return;
477
478 if(ev->key == OXINE_KEY_NULL) {
479 /*printf("event already processed\n");*/
480 return;
481 }
482
483 switch( ev->key){
484 case OXINE_BUTTON1:
485 if (b->select_cb)
486 b->select_cb (b);
487 break;
488 case OXINE_BUTTON4:
489 if( otk->focus_ptr) {
490 if( otk->focus_ptr->widget_type == OTK_WIDGET_LISTENTRY){
491 otk_listentry_t *entry = (otk_listentry_t*) otk->focus_ptr;
492 list_pgup(entry->list);
493 otk_draw_all(otk);
494 }
495 }
496 break;
497 case OXINE_BUTTON5:
498 if( otk->focus_ptr) {
499 if( otk->focus_ptr->widget_type == OTK_WIDGET_LISTENTRY){
500 otk_listentry_t *entry = (otk_listentry_t*) otk->focus_ptr;
501 list_pgdown(entry->list);
502 otk_draw_all(otk);
503 }
504 }
505 break;
506 }
507 }
508
key_handler(otk_t * otk,oxine_event_t * ev)509 static void key_handler (otk_t *otk, oxine_event_t *ev) {
510
511 otk_widget_t *new = NULL;
512
513 if (otk->event_handler) {
514 otk->event_handler(otk->event_handler_data, ev);
515 }
516
517 if(ev->key == OXINE_KEY_NULL) {
518 /*printf("event already processed\n");*/
519 return;
520 }
521
522 /* we only handle key events if we have a focus */
523 if(!otk->focus_ptr) {
524 return;
525 }
526
527 switch(ev->key) {
528 case OXINE_KEY_UP:
529 if (otk->focus_ptr->widget_type == OTK_WIDGET_LISTENTRY) {
530 otk_listentry_t *entry = (otk_listentry_t*) otk->focus_ptr;
531
532 if(entry->isfirst) {
533 list_pgup(entry->list);
534 otk_draw_all(otk);
535 }
536 }
537 if (otk->focus_ptr->widget_type == OTK_WIDGET_SCROLLBAR) {
538 otk_scrollbar_t *scrollbar = (otk_scrollbar_t*) otk->focus_ptr;
539
540 if(scrollbar->cb_up) {
541 scrollbar->cb_up(scrollbar->cb_data);
542 otk_draw_all(otk);
543 }
544 } else
545 new = find_neighbour(otk, UP);
546 break;
547 case OXINE_KEY_DOWN:
548 if (otk->focus_ptr->widget_type == OTK_WIDGET_LISTENTRY) {
549 otk_listentry_t *entry = (otk_listentry_t*) otk->focus_ptr;
550
551 if(entry->islast) {
552 list_pgdown(entry->list);
553 otk_draw_all(otk);
554 } else
555 new = find_neighbour(otk, DOWN);
556 }
557 if (otk->focus_ptr->widget_type == OTK_WIDGET_SCROLLBAR) {
558 otk_scrollbar_t *scrollbar = (otk_scrollbar_t*) otk->focus_ptr;
559
560 if(scrollbar->cb_down) {
561 scrollbar->cb_down(scrollbar->cb_data);
562 otk_draw_all(otk);
563 }
564 } else
565 new = find_neighbour(otk, DOWN);
566 break;
567 case OXINE_KEY_LEFT:
568 new = find_neighbour(otk, LEFT);
569 break;
570 case OXINE_KEY_RIGHT:
571 new = find_neighbour(otk, RIGHT);
572 break;
573 case OXINE_KEY_SELECT:
574 if (otk->focus_ptr->select_cb)
575 otk->focus_ptr->select_cb (otk->focus_ptr);
576 return;
577 break;
578 case OXINE_KEY_PRIOR:
579 if( otk->focus_ptr) {
580 if( otk->focus_ptr->widget_type == OTK_WIDGET_LISTENTRY){
581 otk_listentry_t *entry = (otk_listentry_t*) otk->focus_ptr;
582 list_pgup(entry->list);
583 otk_draw_all(otk);
584 }
585 }
586 break;
587 case OXINE_KEY_NEXT:
588 if( otk->focus_ptr) {
589 if( otk->focus_ptr->widget_type == OTK_WIDGET_LISTENTRY){
590 otk_listentry_t *entry = (otk_listentry_t*) otk->focus_ptr;
591 list_pgdown(entry->list);
592 otk_draw_all(otk);
593 }
594 }
595 break;
596
597 case OXINE_KEY_1:
598 printf("got key 1\n");
599 break;
600 case OXINE_KEY_2:
601 printf("got key 2\n");
602 break;
603 case OXINE_KEY_3:
604 printf("got key 3\n");
605 break;
606 }
607 if (new && (new != otk->focus_ptr)) {
608 otk_set_focus(new);
609 otk_draw_all(otk);
610 }
611 }
612
otk_event_handler(void * this,oxine_event_t * ev)613 static int otk_event_handler(void *this, oxine_event_t *ev) {
614
615 otk_t *otk = (otk_t*) this;
616
617 switch (ev->type) {
618 case OXINE_EVENT_KEY:
619 key_handler(otk, ev);
620 return 1;
621 case OXINE_EVENT_MOTION:
622 motion_handler(otk, ev);
623 return 1;
624 case OXINE_EVENT_BUTTON:
625 button_handler(otk, ev);
626 return 1;
627 case OXINE_EVENT_FORMAT_CHANGED:
628 otk_draw_all(otk);
629 return 1;
630 default:
631 if (otk->event_handler) {
632 return otk->event_handler(otk->event_handler_data, ev);
633 }
634 }
635
636 return 0;
637 }
638
otk_send_event(otk_t * otk,oxine_event_t * ev)639 int otk_send_event(otk_t *otk, oxine_event_t *ev) {
640
641 return odk_send_event(otk->odk, ev);
642 }
643
644 /*
645 * button widget
646 */
647
648 /* FIXME : free displayed_text somewhere */
649
button_draw(otk_widget_t * this)650 static void button_draw(otk_widget_t *this) {
651
652 otk_button_t *button = (otk_button_t*) this;
653 char *displayed_text;
654
655 if (!is_correct_widget(this, OTK_WIDGET_BUTTON)) return;
656
657 switch(button->type) {
658 case OTK_BUTTON_TEXT:
659 odk_set_font(this->odk, this->otk->button_font, this->otk->button_font_size);
660 displayed_text = strdup(button->text);
661 check_text_width(this->odk, displayed_text, button->widget.w);
662
663 if (this->focus) {
664 odk_draw_rect (this->odk, this->x, this->y,
665 this->x+this->w, this->y+this->h, 1, this->otk->textcolor_but+1);
666
667 odk_draw_text (this->odk, this->x+this->w/2,
668 this->y+this->h/2,
669 displayed_text, ODK_ALIGN_CENTER | ODK_ALIGN_VCENTER,
670 this->otk->textcolor_but);
671 } else
672
673 odk_draw_text (this->odk, this->x+this->w/2,
674 this->y+this->h/2,
675 displayed_text, ODK_ALIGN_CENTER | ODK_ALIGN_VCENTER,
676 this->otk->textcolor_win);
677 free(displayed_text);
678 break;
679 case OTK_BUTTON_PIXMAP:
680 printf("OTK_BUTTON_PIXMAP..\n");
681
682 if (this->focus) {
683 odk_draw_rect (this->odk, this->x, this->y,
684 this->x+this->w, this->y+this->h, 1, this->otk->textcolor_but+1);
685
686
687 odk_draw_bitmap(this->odk, button->pixmap, this->x - this->w*2, this->y - this->h*2, 10, 10, NULL);
688
689 } else
690
691 odk_draw_bitmap(this->odk, button->pixmap, this->x - this->w*2, this->y - this->h*2, 10, 10, NULL);
692
693 break;
694 default:
695 printf("OTK_BUTTON_TYPE : %d not supported\n", button->type);
696 break;
697 }
698 }
699
slider_draw_graphic(otk_widget_t * this)700 static void slider_draw_graphic(otk_widget_t *this) {
701
702 otk_slider_t *slider = (otk_slider_t*) this;
703 int value;
704
705 if (!is_correct_widget(this, OTK_WIDGET_SLIDER)) return;
706
707 value = (slider->get_value(this->odk));
708 if(value == -1) value = slider->old_pos;
709 slider->old_pos = value;
710
711 value = (value*this->w-20)/100;
712
713 if (this->focus) {
714 odk_draw_rect (this->odk, this->x, this->y,
715 this->x+this->w, this->y+this->h, 1, this->otk->textcolor_but+1);
716
717 odk_draw_rect (this->odk, this->x, this->y+(this->h)/2-5,
718 this->x+this->w , this->y+(this->h)/2+5 , 1, this->otk->col_sl1f);
719
720 odk_draw_rect (this->odk, this->x+value+5, this->y+(this->h)/2-15,
721 this->x+value+15 , this->y+(this->h)/2+15 , 1, this->otk->col_sl2f);
722
723 } else {
724 odk_draw_rect (this->odk, this->x, this->y,
725 this->x+this->w, this->y+this->h, 1, this->otk->textcolor_win+1);
726
727 odk_draw_rect (this->odk, this->x, this->y+(this->h)/2-5,
728 this->x+this->w , this->y+(this->h)/2+5, 1, this->otk->col_sl1);
729
730 odk_draw_rect (this->odk, this->x+value+5, this->y+(this->h)/2-15,
731 this->x+value+15 , this->y+(this->h)/2+15 , 1, this->otk->col_sl2);
732 }
733 }
734
slider_destroy(otk_widget_t * this)735 static void slider_destroy(otk_widget_t *this) {
736 otk_slider_t *slider = (otk_slider_t*) this;
737 if (!is_correct_widget(this, OTK_WIDGET_SLIDER)) return;
738
739 remove_widget_from_win(this);
740 if (this->otk->focus_ptr == this) this->otk->focus_ptr = NULL;
741 ho_free(slider);
742 }
743
scrollbar_draw(otk_widget_t * this)744 static void scrollbar_draw(otk_widget_t *this) {
745
746 otk_scrollbar_t *scrollbar = (otk_scrollbar_t*) this;
747 int value1, value2;
748 int color[3];
749
750 if (!is_correct_widget(this, OTK_WIDGET_SCROLLBAR)) return;
751
752 value1 = ( scrollbar->pos_start * (this->h-10) ) / 100;
753 value2 = ( scrollbar->pos_end * (this->h-10) ) / 100;
754
755 if (this->focus) {
756 color[0] = this->otk->textcolor_but+1;
757 color[1] = this->otk->col_sl1f;
758 color[2] = this->otk->col_sl2f;
759 } else {
760 color[0] = this->otk->textcolor_win+1;
761 color[1] = this->otk->col_sl1;
762 color[2] = this->otk->col_sl2;
763 }
764
765 odk_draw_rect (this->odk, this->x, this->y,
766 this->x+this->w, this->y+this->h, 1, color[0]);
767
768 /*
769 odk_draw_rect (this->odk, this->x, this->y,
770 this->x+this->w, this->y+this->h, 0, color[1]);
771 */
772
773 odk_draw_rect (this->odk, this->x+5, this->y+5+value1,
774 this->x+this->w-5, this->y+5+value2, 1, color[2]);
775 }
776
scrollbar_destroy(otk_widget_t * this)777 static void scrollbar_destroy(otk_widget_t *this) {
778 otk_scrollbar_t *scrollbar = (otk_scrollbar_t*) this;
779 if (!is_correct_widget(this, OTK_WIDGET_SCROLLBAR)) return;
780
781 remove_widget_from_win(this);
782 if (this->otk->focus_ptr == this) this->otk->focus_ptr = NULL;
783 ho_free(scrollbar);
784 }
785
button_destroy(otk_widget_t * this)786 static void button_destroy(otk_widget_t *this) {
787
788 otk_button_t *button = (otk_button_t*) this;
789
790 if (!is_correct_widget(this, OTK_WIDGET_BUTTON)) return;
791
792 if(button->type == OTK_BUTTON_PIXMAP)
793 free(button->pixmap);
794
795 remove_widget_from_win(this);
796 if (this->otk->focus_ptr == this)
797 this->otk->focus_ptr = NULL;
798 ho_free(button->text);
799 ho_free(button);
800 }
801
button_selected(otk_widget_t * this)802 static void button_selected(otk_widget_t *this) {
803
804 otk_button_t *button = (otk_button_t*) this;
805
806 if (!is_correct_widget(this, OTK_WIDGET_BUTTON)) return;
807
808 if (button->cb)
809 button->cb(button->cb_data);
810 }
811
812 /*void button_list_scroll_up (otk_list_t *list)*/
813
814 #if 0
815 /* I've added this function because i don't want to break existing code. *
816 * When we'll remage otk and odk it's better to select button type in otk_button_new *
817 * and then pass text or pixmap */
818 static void otk_button_add_pixmap (otk_button_t *button, uint8_t *pixmap) {
819
820 if (!is_correct_widget((otk_widget_t *)button, OTK_WIDGET_BUTTON)) return ;
821
822 button->type = OTK_BUTTON_PIXMAP;
823 button->pixmap = pixmap;
824 return ;
825 }
826 #endif
827 /* slider widget */
828
otk_slider_grid_new(otk_slider_cb_t cb)829 otk_widget_t *otk_slider_grid_new (otk_slider_cb_t cb) {
830 otk_slider_t *slider;
831
832 slider = ho_new(otk_slider_t);
833
834 slider->widget.widget_type = OTK_WIDGET_SLIDER;
835 slider->widget.selectable = 1;
836 slider->widget.select_cb = NULL; /*slider_selected;*/
837 slider->widget.draw = slider_draw_graphic;
838 slider->widget.destroy = slider_destroy;
839 slider->widget.needupdate = 0;
840 slider->widget.needcalc = 1;
841 slider->widget.major = 1;
842 slider->old_pos = 0;
843 slider->get_value = cb;
844
845 return (otk_widget_t*) slider;
846 }
847
otk_button_grid_new(const char * text,otk_button_cb_t cb,void * cb_data)848 otk_widget_t *otk_button_grid_new (const char *text,
849 otk_button_cb_t cb,
850 void *cb_data) {
851 otk_button_t *button;
852
853 button = ho_new(otk_button_t);
854
855 button->widget.widget_type = OTK_WIDGET_BUTTON;
856 button->text = ho_strdup(text);
857 button->type = OTK_BUTTON_TEXT;
858 button->widget.selectable = 1;
859 button->widget.select_cb = button_selected;
860 button->widget.draw = button_draw;
861 button->widget.destroy = button_destroy;
862 button->widget.needupdate = 0;
863 button->widget.needcalc = 1;
864 button->widget.major = 1;
865 button->cb = cb;
866 button->cb_data = cb_data;
867 button->uc = NULL;
868
869 return (otk_widget_t*) button;
870 }
871
otk_button_new(otk_widget_t * win,int x,int y,int w,int h,const char * text,otk_button_cb_t cb,void * cb_data)872 otk_widget_t *otk_button_new (otk_widget_t *win, int x, int y,
873 int w, int h, const char *text,
874 otk_button_cb_t cb,
875 void *cb_data) {
876 otk_button_t *button;
877 otk_window_t *window = (otk_window_t*) win;
878
879 if (!is_correct_widget(win, OTK_WIDGET_WINDOW)) return NULL;
880
881 button = ho_new(otk_button_t);
882
883 button->widget.widget_type = OTK_WIDGET_BUTTON;
884 button->widget.x = win->x+x;
885 button->widget.y = win->y+y;
886 button->widget.w = w;
887 button->widget.h = h;
888 button->text = ho_strdup(text);
889 button->type = OTK_BUTTON_TEXT;
890 button->widget.win = win;
891 button->widget.otk = win->otk;
892 button->widget.odk = win->otk->odk;
893 button->widget.selectable = 1;
894 button->widget.select_cb = button_selected;
895 button->widget.draw = button_draw;
896 button->widget.destroy = button_destroy;
897 button->widget.needupdate = 0;
898 button->widget.major = 0;
899 button->cb = cb;
900 button->cb_data = cb_data;
901 button->uc = NULL;
902
903 window->subs = g_list_append (window->subs, button);
904
905 return (otk_widget_t*) button;
906 }
907
otk_scrollbar_new(otk_widget_t * win,int x,int y,int w,int h,otk_button_cb_t cb_up,otk_button_cb_t cb_down,void * user_data)908 otk_widget_t *otk_scrollbar_new (otk_widget_t *win, int x, int y,
909 int w, int h,
910 otk_button_cb_t cb_up, otk_button_cb_t cb_down,
911 void *user_data) {
912
913 otk_scrollbar_t *scrollbar;
914 otk_window_t *window = (otk_window_t*) win;
915
916 if (!is_correct_widget(win, OTK_WIDGET_WINDOW)) return NULL;
917
918 scrollbar = ho_new(otk_scrollbar_t);
919
920 scrollbar->widget.widget_type = OTK_WIDGET_SCROLLBAR;
921 scrollbar->widget.x = win->x+x;
922 scrollbar->widget.y = win->y+y;
923 scrollbar->widget.w = w;
924 scrollbar->widget.h = h;
925 scrollbar->widget.win = win;
926 scrollbar->widget.otk = win->otk;
927 scrollbar->widget.odk = win->otk->odk;
928 scrollbar->widget.selectable = 1;
929 scrollbar->widget.select_cb = NULL;
930 scrollbar->widget.draw = scrollbar_draw;
931 scrollbar->widget.destroy = scrollbar_destroy;
932 scrollbar->widget.needupdate = 0;
933 scrollbar->widget.major = 0;
934 scrollbar->cb_up = cb_up;
935 scrollbar->cb_down = cb_down;
936 scrollbar->cb_data = user_data;
937 scrollbar->pos_start = 0;
938 scrollbar->pos_end = 100;
939
940 window->subs = g_list_append (window->subs, scrollbar);
941
942 return (otk_widget_t*) scrollbar;
943 }
944
otk_scrollbar_set(otk_widget_t * this,int pos_start,int pos_end)945 void otk_scrollbar_set(otk_widget_t *this, int pos_start, int pos_end)
946 {
947 otk_scrollbar_t *scrollbar = (otk_scrollbar_t*) this;
948
949 if (!is_correct_widget(this, OTK_WIDGET_SCROLLBAR)) return;
950
951 if(pos_start < 0 ) pos_start = 0;
952 if(pos_start > 100 ) pos_start = 100;
953 scrollbar->pos_start = pos_start;
954
955 if(pos_end < pos_start ) pos_end = pos_start;
956 if(pos_end > 100 ) pos_end = 100;
957 scrollbar->pos_end = pos_end;
958 }
959
otk_button_uc_set(otk_widget_t * this,otk_button_cb_t uc,void * uc_data)960 void otk_button_uc_set(otk_widget_t *this, otk_button_cb_t uc, void *uc_data) {
961 otk_button_t *button = (otk_button_t *)this;
962
963 if (!is_correct_widget(this, OTK_WIDGET_BUTTON)) return;
964
965 button->uc = uc;
966 button->widget.needupdate = 1;
967 button->uc_data = uc_data;
968
969 }
970
971 /*
972 * list widget
973 */
974
975 /* FIXME : free displayed_text somewhere.. */
listentry_draw(otk_widget_t * this)976 static void listentry_draw (otk_widget_t *this) {
977 otk_listentry_t *listentry = (otk_listentry_t*) this;
978 char *displayed_text;
979
980 if (!is_correct_widget(this, OTK_WIDGET_LISTENTRY)) return;
981
982 #ifdef LOG
983 printf("otk: draw listentry\n");
984 #endif
985
986 if (!listentry->visible) return;
987
988 odk_set_font(this->odk, listentry->list->font, listentry->list->font_size);
989 displayed_text = strdup(listentry->text);
990 check_text_width(listentry->widget.odk, displayed_text, listentry->widget.w);
991
992 /* printf("%d %d\n", this->x, this->y+this->h/2); */
993
994 if (this->focus) {
995 odk_draw_rect (this->odk, this->x, this->y,
996 this->x+this->w, this->y+this->h, 1, this->otk->textcolor_but+1);
997
998 odk_draw_text (this->odk, this->x,
999 this->y+this->h/2,
1000 displayed_text, ODK_ALIGN_LEFT | ODK_ALIGN_VCENTER,
1001 this->otk->textcolor_but);
1002 } else
1003
1004 odk_draw_text (this->odk, this->x,
1005 this->y+this->h/2,
1006 displayed_text, ODK_ALIGN_LEFT | ODK_ALIGN_VCENTER,
1007 this->otk->textcolor_win);
1008 free(displayed_text);
1009 }
1010
listentry_select(otk_widget_t * this)1011 static void listentry_select(otk_widget_t *this) {
1012
1013 otk_listentry_t *listentry = (otk_listentry_t*) this;
1014
1015 if (!is_correct_widget(this, OTK_WIDGET_LISTENTRY)) return;
1016
1017 listentry->list->last_selected = listentry->number;
1018
1019 if (listentry->list->cb)
1020 listentry->list->cb(listentry->list->cb_data,listentry->data);
1021 }
1022
listentry_destroy(otk_widget_t * this)1023 static void listentry_destroy(otk_widget_t *this) {
1024
1025 otk_listentry_t *listentry = (otk_listentry_t*) this;
1026
1027 if (!is_correct_widget(this, OTK_WIDGET_LISTENTRY)) return;
1028
1029 if (this->otk->focus_ptr == this)
1030 this->otk->focus_ptr = NULL;
1031
1032 remove_widget_from_win(this);
1033 ho_free(listentry->text);
1034 ho_free(listentry);
1035 }
1036
1037
otk_listentry_set_pos(otk_listentry_t * entry,int pos)1038 static void otk_listentry_set_pos (otk_listentry_t *entry, int pos) {
1039
1040 if ((pos <= 0) || (pos > entry->list->entries_visible)) {
1041 entry->visible = 0;
1042 entry->widget.selectable = 0;
1043 entry->isfirst = 0;
1044 entry->islast = 0;
1045 return;
1046 }
1047 entry->pos = pos;
1048 entry->isfirst = 0;
1049 entry->islast = 0;
1050
1051 entry->widget.y = entry->list->widget.y + entry->list->entry_height*(pos-1);
1052 entry->visible = 1;
1053 entry->widget.selectable = 1;
1054
1055 /* we grab focus if nothing is selected */
1056 if (pos == 1) {
1057 entry->isfirst = 1;
1058 if (!entry->widget.otk->focus_ptr) {
1059 entry->widget.otk->focus_ptr = (otk_widget_t*)entry;
1060 entry->widget.focus = 1;
1061 }
1062 }
1063 if (pos == entry->list->entries_visible) entry->islast = 1;
1064 }
1065
list_adapt_entries(otk_list_t * list)1066 static void list_adapt_entries(otk_list_t *list) {
1067
1068 int i=1;
1069 g_list_t *cur;
1070
1071 cur = g_list_first (list->entries);
1072 while (cur && cur->data) {
1073 otk_listentry_t *entry = cur->data;
1074
1075 entry->number = i;
1076 otk_listentry_set_pos (entry, i-list->position);
1077 cur = g_list_next (cur);
1078 i++;
1079 }
1080
1081 if(list->num_entries)
1082 otk_scrollbar_set(list->scrollbar,
1083 (list->position) * 100 / list->num_entries,
1084 (list->position+list->entries_visible) * 100 / list->num_entries);
1085 }
1086
otk_add_listentry(otk_widget_t * this,const char * text,void * data,int pos)1087 void otk_add_listentry(otk_widget_t *this, const char *text, void *data, int pos) {
1088
1089 otk_list_t *list = (otk_list_t*) this;
1090 otk_listentry_t *entry;
1091 int num;
1092 otk_window_t *win;
1093
1094 if (!is_correct_widget(this, OTK_WIDGET_LIST)) abort();
1095
1096 #ifdef LOG
1097 printf("otk: add_listentry %s\n", text);
1098 #endif
1099
1100 entry = ho_new(otk_listentry_t);
1101
1102 entry->widget.widget_type = OTK_WIDGET_LISTENTRY;
1103 entry->widget.w = list->widget.w - 25;
1104 entry->widget.h = list->entry_height;
1105 entry->widget.x = list->widget.x;
1106 entry->widget.win = list->widget.win;
1107 entry->widget.otk = list->widget.otk;
1108 entry->widget.odk = list->widget.odk;
1109 entry->widget.selectable = 0;
1110 entry->widget.select_cb = listentry_select;
1111 entry->widget.draw = listentry_draw;
1112 entry->widget.destroy = listentry_destroy;
1113 entry->widget.needupdate = 0;
1114 entry->widget.major = 0;
1115 entry->list = list;
1116 entry->text = ho_strdup(text);
1117 entry->data = data;
1118
1119
1120 odk_set_font(entry->widget.odk, entry->list->font, entry->list->font_size);
1121 win = (otk_window_t *)list->widget.win;
1122 win->subs = g_list_append (win->subs, entry);
1123
1124 /* determine the real position the entry is inserted */
1125
1126 if (pos >= 0) {
1127 num = pos;
1128 if (num > list->num_entries)
1129 num = list->num_entries;
1130 } else {
1131 num = list->num_entries + pos + 1;
1132 if (num < 0)
1133 num = 0;
1134 }
1135
1136 /* now add new entry to the list */
1137
1138 list->entries = g_list_insert(list->entries, entry, num);
1139
1140 /*
1141 cur = list_first_content(list->entries);
1142 if (cur) {
1143 for (i=0; i<num; i++)
1144 cur = list_next_content(list->entries);
1145 }
1146 if (cur)
1147 list_insert_content(list->entries, entry);
1148 else
1149 list_append_content(list->entries, entry);
1150
1151 */
1152 list->num_entries++;
1153
1154 list_adapt_entries(list);
1155 }
1156
otk_remove_listentries(otk_widget_t * this)1157 void otk_remove_listentries(otk_widget_t *this) {
1158
1159 otk_list_t *list = (otk_list_t*) this;
1160 g_list_t *cur;
1161
1162 if (!is_correct_widget(this, OTK_WIDGET_LIST)) return;
1163
1164 cur = g_list_first (list->entries);
1165 while (cur && cur->data) {
1166 otk_listentry_t *entry = cur->data;
1167
1168 entry->widget.destroy((otk_widget_t*)entry);
1169 list->entries = g_list_remove_link(list->entries, cur);
1170 cur = g_list_first (list->entries);
1171 }
1172
1173 list->num_entries = 0;
1174 }
1175
list_scroll_down(void * this)1176 static void list_scroll_down (void *this) {
1177 otk_list_t *list = (otk_list_t *)this;
1178
1179 list_pgdown(list);
1180 otk_draw_all(list->widget.otk);
1181 }
1182
list_scroll_up(void * this)1183 static void list_scroll_up (void *this) {
1184 otk_list_t *list = (otk_list_t *)this;
1185
1186 list_pgup(list);
1187 otk_draw_all(list->widget.otk);
1188 }
1189
list_pgdown(otk_list_t * list)1190 static void list_pgdown (otk_list_t *list) {
1191
1192 int newpos;
1193 g_list_t *cur;
1194
1195 newpos = list->position + list->entries_visible / 2;
1196
1197 if ((list->num_entries-newpos) < list->entries_visible)
1198 newpos = list->num_entries - list->entries_visible;
1199
1200 if (newpos < 0) newpos = 0;
1201
1202 list->position = newpos;
1203
1204 list_adapt_entries(list);
1205
1206 /* set focus to first entry if we lost it */
1207 if (list->widget.otk->focus_ptr->widget_type == OTK_WIDGET_LISTENTRY) {
1208 otk_listentry_t *e = (otk_listentry_t*) list->widget.otk->focus_ptr;
1209 if ((e->list == list) && (e->visible == 0)) {
1210 e->widget.focus = 0;
1211 cur = g_list_first(list->entries);
1212 e = NULL;
1213 while (cur && cur->data) {
1214 e = cur->data;
1215 if (e->isfirst) break;
1216 cur = g_list_next(cur);
1217 }
1218 if (e) {
1219 list->widget.otk->focus_ptr = (otk_widget_t*) e;
1220 e->widget.focus = 1;
1221 }
1222 }
1223 }
1224 }
1225
list_pgup(otk_list_t * list)1226 static void list_pgup (otk_list_t *list) {
1227
1228 int newpos;
1229 g_list_t *cur;
1230
1231 newpos = list->position - list->entries_visible / 2;
1232
1233 if (newpos < 0) newpos = 0;
1234
1235 list->position = newpos;
1236
1237 list_adapt_entries(list);
1238
1239 /* set focus to last entry if we lost it */
1240 if (list->widget.otk->focus_ptr->widget_type == OTK_WIDGET_LISTENTRY) {
1241 otk_listentry_t *e = (otk_listentry_t*) list->widget.otk->focus_ptr;
1242 if ((e->list == list) && (e->visible == 0)) {
1243 e->widget.focus = 0;
1244 e = NULL;
1245 cur = g_list_first(list->entries);
1246 while (cur && cur->data) {
1247 e = cur->data;
1248 if (e->islast) break;
1249 cur = g_list_next(cur);
1250 }
1251 if (e) {
1252 list->widget.otk->focus_ptr = (otk_widget_t*) e;
1253 e->widget.focus = 1;
1254 }
1255 }
1256 }
1257 }
1258
1259 /*static void list_add_scroolbar(otk_list_t *list) {
1260 }
1261 */
1262
otk_list_get_entry_number(otk_widget_t * this)1263 int otk_list_get_entry_number(otk_widget_t *this) {
1264 otk_list_t *list = (otk_list_t *) this;
1265
1266 if (!is_correct_widget(this, OTK_WIDGET_LIST)) return -1;
1267
1268 return list->last_selected;
1269 }
1270
otk_list_set_pos(otk_widget_t * this,int newpos)1271 void otk_list_set_pos(otk_widget_t *this, int newpos) {
1272 otk_list_t *list = (otk_list_t *) this;
1273
1274 if (!is_correct_widget(this, OTK_WIDGET_LIST)) return;
1275
1276 if ((list->num_entries-newpos) < list->entries_visible)
1277 newpos = list->num_entries - list->entries_visible;
1278 if (newpos < 0) newpos = 0;
1279 list->position = newpos;
1280
1281 list_adapt_entries(list);
1282 }
1283
otk_list_get_pos(otk_widget_t * this)1284 int otk_list_get_pos(otk_widget_t *this) {
1285
1286 otk_list_t *list = (otk_list_t *) this;
1287
1288 if (!is_correct_widget(this, OTK_WIDGET_LIST)) return -1;
1289
1290 return list->position;
1291 }
1292
list_draw(otk_widget_t * this)1293 static void list_draw (otk_widget_t *this) {
1294
1295 otk_list_t *list = (otk_list_t*) this;
1296 g_list_t *cur;
1297
1298 if (!is_correct_widget(this, OTK_WIDGET_LIST)) return;
1299
1300 #ifdef LOG
1301 printf("otk: draw list\n");
1302 #endif
1303
1304 cur = g_list_first (list->entries);
1305 while (cur && cur->data) {
1306 otk_listentry_t *entry = cur->data;
1307
1308 entry->widget.draw((otk_widget_t*)entry);
1309 cur = g_list_next (cur);
1310 }
1311 }
1312
list_destroy(otk_widget_t * this)1313 static void list_destroy(otk_widget_t *this) {
1314
1315 otk_list_t *list = (otk_list_t*) this;
1316
1317 if (!is_correct_widget(this, OTK_WIDGET_LIST)) return;
1318
1319 /* do not destroy listentries here; this is done by window destructor */
1320 /*otk_remove_listentries(this);*/
1321
1322 g_list_free(list->entries);
1323
1324 remove_widget_from_win(this);
1325 ho_free(list);
1326 }
1327
otk_list_new(otk_widget_t * win,int x,int y,int w,int h,otk_list_cb_t cb,void * cb_data)1328 otk_widget_t *otk_list_new (otk_widget_t *win, int x, int y, int w, int h,
1329 otk_list_cb_t cb,
1330 void *cb_data) {
1331
1332 otk_list_t *list;
1333 otk_window_t *window = (otk_window_t*) win;
1334
1335 if (!is_correct_widget(win, OTK_WIDGET_WINDOW)) return NULL;
1336
1337 list = ho_new(otk_list_t);
1338
1339 list->widget.widget_type = OTK_WIDGET_LIST;
1340 list->widget.x = win->x+x;
1341 list->widget.y = win->y+y;
1342 list->widget.w = w;
1343 list->widget.h = h;
1344 list->widget.win = win;
1345 list->widget.otk = win->otk;
1346 list->widget.odk = win->otk->odk;
1347 list->widget.selectable = 0;
1348 list->widget.draw = list_draw;
1349 list->widget.destroy = list_destroy;
1350 list->widget.needupdate = 0;
1351 list->widget.major = 0;
1352 list->position = 0;
1353 list->cb = cb;
1354 list->cb_data = cb_data;
1355 list->entries = NULL; //g_list_new ();
1356 list->font = strdup("sans");
1357 list->font_size = 30;
1358 list->num_entries = 0;
1359 list->entry_height = 32;
1360
1361 list->entries_visible = list->widget.h / list->entry_height;
1362 list->widget.h = list->entries_visible * list->entry_height;
1363
1364
1365 list->scrollbar = otk_scrollbar_new (win, x + list->widget.w - 25, y,
1366 27, list->widget.h,
1367 list_scroll_up, list_scroll_down,
1368 list);
1369
1370 window->subs = g_list_append(window->subs, list);
1371
1372 return (otk_widget_t*) list;
1373 }
1374
1375
1376 /*
1377 * label widget
1378 */
1379
label_draw(otk_widget_t * this)1380 static void label_draw (otk_widget_t *this) {
1381
1382 otk_label_t *label = (otk_label_t*) this;
1383 char *displayed_text;
1384
1385 if (!is_correct_widget(this, OTK_WIDGET_LABEL)) return;
1386
1387 displayed_text = strdup(label->text);
1388
1389 odk_set_font (this->odk, this->otk->label_font,
1390 (label->font_size) ? label->font_size : this->otk->label_font_size);
1391 check_text_width(this->odk, displayed_text, this->win->w );
1392 odk_draw_text (this->odk, this->x, this->y, displayed_text, label->alignment,
1393 this->otk->label_color);
1394
1395 free(displayed_text);
1396 }
1397
label_destroy(otk_widget_t * this)1398 static void label_destroy (otk_widget_t *this) {
1399
1400 otk_label_t *label = (otk_label_t*) this;
1401
1402 if (!is_correct_widget(this, OTK_WIDGET_LABEL)) return;
1403
1404 remove_widget_from_win(this);
1405 ho_free(label->text);
1406 ho_free(label);
1407 }
1408
otk_label_new(otk_widget_t * win,int x,int y,int alignment,const char * text)1409 otk_widget_t *otk_label_new (otk_widget_t *win, int x, int y, int alignment, const char *text) {
1410
1411 otk_label_t *label;
1412 otk_window_t *window = (otk_window_t*) win;
1413
1414 if (!is_correct_widget(win, OTK_WIDGET_WINDOW)) return NULL;
1415
1416 label = ho_new(otk_label_t);
1417
1418 label->widget.widget_type = OTK_WIDGET_LABEL;
1419 label->widget.x = win->x+x;
1420 label->widget.y = win->y+y;
1421 label->widget.win = win;
1422 label->widget.otk = win->otk;
1423 label->widget.odk = win->otk->odk;
1424 label->widget.draw = label_draw;
1425 label->widget.destroy = label_destroy;
1426 label->widget.needupdate = 0;
1427 label->widget.major = 0;
1428 label->alignment = alignment;
1429 label->text = ho_strdup(text);
1430 label->font_size = 0; /* use default */
1431
1432 window->subs = g_list_append (window->subs, label);
1433
1434 return (otk_widget_t*) label;
1435 }
1436
otk_label_set_font_size(otk_widget_t * this,int font_size)1437 void otk_label_set_font_size(otk_widget_t *this, int font_size)
1438 {
1439 otk_label_t *label = (otk_label_t *) this;
1440 label->font_size = font_size;
1441 }
1442
1443
1444 /*
1445 * layout widget
1446 */
1447
layout_draw(otk_widget_t * this)1448 static void layout_draw (otk_widget_t *this) {
1449
1450 otk_widget_t *widget;
1451 otk_layout_t *lay = (otk_layout_t*) this;
1452 unsigned int sizey, sizex;
1453 g_list_t *cur;
1454
1455 if (!is_correct_widget(this, OTK_WIDGET_LAYOUT)) return;
1456
1457 sizey = lay->widget.h / lay->rows;
1458 sizex = lay->widget.w / lay->columns;
1459
1460 cur = g_list_first (lay->subs);
1461 while (cur && cur->data) {
1462 widget = cur->data;
1463 if(widget->needcalc) {
1464 widget->x = lay->widget.x + widget->x * sizex;
1465 widget->y = lay->widget.y + widget->y * sizey;
1466 widget->w = sizex * widget->w;
1467 widget->h = sizey * widget->h;
1468 widget->needcalc = 0;
1469 }
1470 widget->draw(widget);
1471 cur = g_list_next (cur);
1472 }
1473 }
1474
layout_destroy(otk_widget_t * this)1475 static void layout_destroy(otk_widget_t *this) {
1476
1477 otk_widget_t *widget;
1478 otk_layout_t *lay = (otk_layout_t*) this;
1479 g_list_t *cur;
1480
1481 if (!is_correct_widget(this, OTK_WIDGET_LAYOUT)) return;
1482
1483 cur = g_list_first (lay->subs);
1484 while (cur && cur->data) {
1485 widget = cur->data;
1486 widget->destroy(widget);
1487 cur = g_list_first (lay->subs);
1488 }
1489 g_list_free(lay->subs);
1490
1491 remove_widget_from_win(this);
1492 ho_free(lay);
1493 }
1494
otk_layout_add_widget(otk_widget_t * layout,otk_widget_t * widget,int x,int y,int w,int h)1495 void otk_layout_add_widget(otk_widget_t *layout, otk_widget_t *widget, int x, int y, int w, int h) {
1496 otk_layout_t *lay = (otk_layout_t*) layout;
1497 otk_window_t *win = (otk_window_t*) layout;
1498
1499 if(is_correct_widget(layout, OTK_WIDGET_LAYOUT)) {
1500 otk_window_t *parent = (otk_window_t *) lay->widget.win;
1501 widget->x = x;
1502 widget->y = y;
1503 widget->w = w;
1504 widget->h = h;
1505 widget->win = layout;
1506 widget->otk = lay->widget.otk;
1507 widget->odk = lay->widget.odk;
1508
1509 lay->subs = g_list_append(lay->subs, widget);
1510 parent->subs = g_list_append(parent->subs, widget);
1511 }
1512 else if(is_correct_widget(layout, OTK_WIDGET_WINDOW)) {
1513 widget->x = win->widget.x + x;
1514 widget->y = win->widget.y + y;
1515 widget->w = w;
1516 widget->h = h;
1517 widget->win = (otk_widget_t*) win;
1518 widget->otk = win->widget.otk;
1519 widget->odk = win->widget.odk;
1520
1521 win->subs = g_list_append(win->subs, widget);
1522 }
1523 else return;
1524 }
1525
otk_layout_new(otk_widget_t * win,int x,int y,int w,int h,int rows,int columns)1526 otk_widget_t *otk_layout_new(otk_widget_t *win, int x, int y, int w, int h, int rows, int columns) {
1527 otk_layout_t *layout;
1528 otk_window_t *window = (otk_window_t *) win;
1529
1530 if (!is_correct_widget(win, OTK_WIDGET_WINDOW)) return NULL;
1531
1532 layout = ho_new(otk_layout_t);
1533
1534 layout->widget.widget_type = OTK_WIDGET_LAYOUT;
1535 layout->widget.x = window->widget.x+x;
1536 layout->widget.y = window->widget.y+y;
1537 layout->widget.w = w;
1538 layout->widget.h = h;
1539 layout->widget.win = win;
1540 layout->widget.otk = win->otk;
1541 layout->widget.odk = win->odk;
1542 layout->widget.draw = layout_draw;
1543 layout->widget.destroy = layout_destroy;
1544 layout->widget.selectable = 0;
1545 layout->widget.needupdate = 0;
1546 layout->widget.major = 0;
1547 layout->rows = rows;
1548 layout->columns = columns;
1549 layout->subs = NULL; //g_list_new();
1550
1551 window->subs = g_list_append (window->subs, layout);
1552
1553 return (otk_widget_t*) layout;
1554 }
1555
1556 /*
1557 * selector widget
1558 */
1559
selector_draw(otk_widget_t * this)1560 static void selector_draw (otk_widget_t *this) {
1561
1562 otk_selector_t *selector = (otk_selector_t*) this;
1563 char *text;
1564 g_list_t *cur;
1565
1566 if (!is_correct_widget(this, OTK_WIDGET_SELECTOR)) return;
1567
1568 cur = g_list_nth(selector->items, selector->pos-1);
1569 text = cur->data;
1570
1571 odk_set_font(this->odk, this->otk->button_font, this->otk->button_font_size);
1572
1573 if (this->focus) {
1574 odk_draw_rect (this->odk, this->x, this->y,
1575 this->x+this->w, this->y+this->h, 1, this->otk->textcolor_but+1);
1576
1577 odk_draw_text (this->odk, this->x+this->w/2,
1578 this->y+this->h/2,
1579 text, ODK_ALIGN_CENTER | ODK_ALIGN_VCENTER,
1580 this->otk->textcolor_but);
1581 } else
1582
1583 odk_draw_text (this->odk, this->x+this->w/2,
1584 this->y+this->h/2,
1585 text, ODK_ALIGN_CENTER | ODK_ALIGN_VCENTER,
1586 this->otk->textcolor_win);
1587
1588 }
1589
selector_destroy(otk_widget_t * this)1590 static void selector_destroy (otk_widget_t *this) {
1591
1592 otk_selector_t *selector = (otk_selector_t*) this;
1593 char *i;
1594 g_list_t *cur;
1595
1596 if (!is_correct_widget(this, OTK_WIDGET_SELECTOR)) return;
1597
1598 remove_widget_from_win(this);
1599 if (this->otk->focus_ptr == this)
1600 this->otk->focus_ptr = NULL;
1601
1602 cur = g_list_first(selector->items);
1603
1604 while (cur && cur->data) {
1605 i = cur->data;
1606 free(i);
1607 cur = g_list_next(cur);
1608 }
1609 g_list_free(selector->items);
1610
1611 ho_free(selector);
1612 }
1613
selector_selected(otk_widget_t * this)1614 static void selector_selected (otk_widget_t *this) {
1615
1616 otk_selector_t *selector = (otk_selector_t*) this;
1617 /* char *i; */
1618
1619 if (!is_correct_widget(this, OTK_WIDGET_SELECTOR)) return;
1620
1621 selector->pos++;
1622 if (selector->pos > g_list_length(selector->items)) selector->pos = 1;
1623
1624 selector_draw(this);
1625 odk_show (this->odk);
1626
1627 if (selector->cb)
1628 selector->cb(selector->cb_data, selector->pos);
1629
1630 }
1631
otk_selector_grid_new(const char * const * items,int num,otk_selector_cb_t cb,void * cb_data)1632 otk_widget_t *otk_selector_grid_new (const char *const *items, int num,
1633 otk_selector_cb_t cb,
1634 void *cb_data) {
1635 otk_selector_t *selector;
1636 int i;
1637
1638 selector = ho_new(otk_selector_t);
1639
1640 selector->widget.widget_type = OTK_WIDGET_SELECTOR;
1641 selector->widget.selectable = 1;
1642 selector->widget.select_cb = selector_selected;
1643 selector->widget.draw = selector_draw;
1644 selector->widget.destroy = selector_destroy;
1645 selector->widget.needupdate = 0;
1646 selector->widget.needcalc = 1;
1647 selector->widget.major = 1;
1648 selector->cb = cb;
1649 selector->cb_data = cb_data;
1650 selector->items = NULL; //g_list_new();
1651
1652 for (i=0; i<num; i++)
1653 selector->items = g_list_append(selector->items, strdup(items[i]));
1654
1655 selector->pos = 1;
1656
1657 return (otk_widget_t*) selector;
1658 }
1659
otk_selector_new(otk_widget_t * win,int x,int y,int w,int h,const char * const * items,int num,otk_selector_cb_t cb,void * cb_data)1660 otk_widget_t *otk_selector_new(otk_widget_t *win,int x, int y,
1661 int w, int h, const char *const *items, int num,
1662 otk_selector_cb_t cb,
1663 void *cb_data) {
1664 otk_selector_t *selector;
1665 otk_window_t *window = (otk_window_t*) win;
1666 int i;
1667
1668 if (!is_correct_widget(win, OTK_WIDGET_WINDOW)) return NULL;
1669
1670 selector = ho_new(otk_selector_t);
1671
1672 selector->widget.widget_type = OTK_WIDGET_SELECTOR;
1673 selector->widget.x = win->x+x;
1674 selector->widget.y = win->y+y;
1675 selector->widget.w = w;
1676 selector->widget.h = h;
1677 selector->items = NULL; //g_list_new();
1678 selector->widget.win = win;
1679 selector->widget.otk = win->otk;
1680 selector->widget.odk = win->otk->odk;
1681 selector->widget.selectable = 1;
1682 selector->widget.select_cb = selector_selected;
1683 selector->widget.draw = selector_draw;
1684 selector->widget.destroy = selector_destroy;
1685 selector->widget.needupdate = 0;
1686 selector->widget.major = 0;
1687 selector->cb = cb;
1688 selector->cb_data = cb_data;
1689
1690 for (i=0; i<num; i++)
1691 selector->items = g_list_append(selector->items, strdup(items[i]));
1692
1693 selector->pos = 1;
1694
1695 window->subs = g_list_append (window->subs, selector);
1696
1697 return (otk_widget_t*) selector;
1698
1699 }
1700
otk_selector_set(otk_widget_t * this,int pos)1701 void otk_selector_set(otk_widget_t *this, int pos) {
1702
1703 otk_selector_t *selector = (otk_selector_t*) this;
1704
1705 if (!is_correct_widget(this, OTK_WIDGET_SELECTOR)) return;
1706
1707 if (pos < 1 ) pos = 1;
1708 if (pos > g_list_length(selector->items)) pos = g_list_length(selector->items);
1709 selector->pos = pos;
1710
1711 }
1712 /*
1713 * window widget
1714 */
1715
window_draw(otk_widget_t * this)1716 static void window_draw (otk_widget_t *this) {
1717
1718 otk_window_t *win = (otk_window_t*) this;
1719 g_list_t *cur;
1720
1721 if (!is_correct_widget(this, OTK_WIDGET_WINDOW)) return;
1722
1723 odk_draw_rect (this->odk, this->x, this->y,
1724 this->x+this->w, this->y+this->h, 1,
1725 win->fill_color);
1726
1727 cur = g_list_first (win->subs);
1728 while (cur && cur->data) {
1729 otk_widget_t *widget = cur->data;
1730
1731 if(!widget->major) widget->draw(widget);
1732 cur = g_list_next (cur);
1733 }
1734 }
1735
window_destroy(otk_widget_t * this)1736 static void window_destroy(otk_widget_t *this) {
1737
1738 otk_window_t *win = (otk_window_t*) this;
1739 g_list_t *cur;
1740
1741 if (!is_correct_widget(this, OTK_WIDGET_WINDOW)) return;
1742
1743 cur = g_list_first (win->subs);
1744 while (cur && cur->data) {
1745 otk_widget_t *widget = cur->data;
1746 if(!widget->major) widget->destroy(widget);
1747 cur = g_list_first (win->subs);
1748 }
1749 g_list_free(win->subs);
1750
1751 win->widget.otk->windows = g_list_remove(win->widget.otk->windows, win);
1752 ho_free(win);
1753 }
1754
otk_window_new(otk_t * otk,const char * title,int x,int y,int w,int h)1755 otk_widget_t *otk_window_new (otk_t *otk, const char *title, int x, int y,
1756 int w, int h) {
1757
1758 otk_window_t *window;
1759
1760 window = ho_new(otk_window_t);
1761
1762 window->widget.widget_type = OTK_WIDGET_WINDOW;
1763 window->widget.x = x;
1764 window->widget.y = y;
1765 window->widget.w = w;
1766 window->widget.h = h;
1767 window->widget.otk = otk;
1768 window->widget.odk = otk->odk;
1769 window->widget.draw = NULL;
1770 window->widget.draw = window_draw;
1771 window->widget.destroy = window_destroy;
1772 window->widget.needupdate = 0;
1773 window->widget.major = 0;
1774 window->fill_color = otk->textcolor_win+1;
1775
1776 window->subs = NULL; //g_list_new ();
1777
1778 otk->windows = g_list_append (otk->windows, window);
1779
1780 return (otk_widget_t*) window;
1781 }
1782
1783 /*
1784 * other global functions
1785 */
1786
otk_draw_all(otk_t * otk)1787 void otk_draw_all (otk_t *otk) {
1788
1789 g_list_t *cur;
1790
1791 pthread_mutex_lock(&otk->draw_mutex);
1792
1793 odk_clear (otk->odk);
1794 cur = g_list_first (otk->windows);
1795
1796 if (!cur) {
1797 odk_hide (otk->odk);
1798 pthread_mutex_unlock(&otk->draw_mutex);
1799 return;
1800 }
1801
1802 while (cur && cur->data) {
1803 otk_window_t *win = cur->data;
1804
1805 win->widget.draw((otk_widget_t*)win);
1806 cur = g_list_next (cur);
1807 }
1808
1809 odk_show (otk->odk);
1810 pthread_mutex_unlock(&otk->draw_mutex);
1811 }
1812
otk_destroy_widget(otk_widget_t * widget)1813 void otk_destroy_widget (otk_widget_t *widget) {
1814
1815 widget->destroy(widget);
1816 }
1817
otk_clear(otk_t * otk)1818 void otk_clear(otk_t *otk) {
1819
1820 g_list_t *cur;
1821
1822 if (!otk) return;
1823
1824 cur = g_list_first (otk->windows);
1825 while (cur && cur->data) {
1826 otk_window_t *win = cur->data;
1827
1828 win->widget.destroy((otk_widget_t*)win);
1829 cur = g_list_first (otk->windows);
1830 }
1831
1832 g_list_free(otk->windows);
1833 otk->windows = NULL; //g_list_new();
1834 otk_draw_all (otk);
1835 }
1836
otk_set_focus(otk_widget_t * widget)1837 void otk_set_focus(otk_widget_t *widget) {
1838
1839 if (widget->selectable) {
1840 if(widget->otk) {
1841 if (widget->otk->focus_ptr)
1842 widget->otk->focus_ptr->focus = 0;
1843 widget->otk->focus_ptr = widget;
1844 widget->otk->focus_ptr->focus = 1;
1845 }
1846 }
1847 }
1848
otk_set_event_handler(otk_t * otk,int (* cb)(void * data,oxine_event_t * ev),void * data)1849 void otk_set_event_handler(otk_t *otk, int (*cb)(void *data, oxine_event_t *ev), void *data) {
1850
1851 otk->event_handler = cb;
1852 otk->event_handler_data = data;
1853 }
1854
otk_set_update(otk_widget_t * this,int update)1855 void otk_set_update(otk_widget_t *this, int update) {
1856
1857 if (update)
1858 this->needupdate=1;
1859 else
1860 this->needupdate=0;
1861 }
1862
1863
1864 /* FIXME: is this really thread safe?
1865 * check if all otk updates need lock_job_mutex()
1866 */
1867 #ifdef ENABLE_UPDATE_JOB
otk_update_job(void * data)1868 static void otk_update_job(void *data) {
1869 otk_t *otk = (otk_t *) data;
1870 int changed = 0;
1871 g_list_t *cur, *cur2;
1872
1873 cur = g_list_first (otk->windows);
1874 while (cur && cur->data) {
1875 otk_window_t *win = cur->data;
1876
1877 cur2 = g_list_first (win->subs);
1878 while (cur2 && cur2->data) {
1879 otk_widget_t *widget = cur2->data;
1880
1881 if(widget->needupdate) {
1882 changed = 1;
1883 switch (widget->widget_type) {
1884 case OTK_WIDGET_SLIDER:
1885 {
1886 otk_slider_t *slider = (otk_slider_t *) widget;
1887 if(slider->get_value) {
1888 slider->old_pos = slider->get_value(widget->odk);
1889 }
1890 widget->draw(widget);
1891 break;
1892 }
1893 case OTK_WIDGET_BUTTON:
1894 {
1895 otk_button_t *button = (otk_button_t *) widget;
1896 if(button->uc) {
1897 button->uc(button->uc_data);
1898 widget->draw(widget);
1899 }
1900 break;
1901 }
1902 default:
1903 widget->draw(widget);
1904 }
1905 }
1906 cur2 = g_list_next (cur2);
1907 }
1908 cur = g_list_next (cur);
1909 }
1910 if (changed) { odk_show(otk->odk); }
1911 otk->update_job = schedule_job(100, otk_update_job, otk);
1912 }
1913 #endif
1914
otk_init(odk_t * odk)1915 otk_t *otk_init (odk_t *odk) {
1916
1917 otk_t *otk;
1918 /* int err; */
1919 uint32_t c[3];
1920 uint8_t t[3];
1921
1922 otk = ho_new_tagged(otk_t,"otk object");
1923
1924 otk->odk = odk;
1925
1926 otk->windows = NULL; //g_list_new ();
1927
1928 odk_set_event_handler(odk, otk_event_handler, otk);
1929
1930 c[0] = 0xffff00; t[0] = 15;
1931 c[1] = 0x0080c0; t[1] = 15;
1932 c[2] = 0x008000; t[2] = 15;
1933 odk_user_color(odk, "text_foreground", &c[0], &t[0]);
1934 odk_user_color(odk, "text_window", &c[1], &t[1]);
1935 odk_user_color(odk, "text_border", &c[2], &t[2]);
1936 otk->textcolor_win = odk_alloc_text_palette(odk, c[0], t[0], c[1], t[1], c[2], t[2]);
1937
1938 c[0] = 0xff8080; t[0] = 15;
1939 c[1] = 0x8080c0; t[1] = 15;
1940 c[2] = 0x808080; t[2] = 15;
1941 odk_user_color(odk, "focused_text_foreground", &c[0], &t[0]);
1942 odk_user_color(odk, "focused_button", &c[1], &t[1]);
1943 odk_user_color(odk, "focused_text_border", &c[2], &t[2]);
1944 otk->textcolor_but = odk_alloc_text_palette(odk, c[0], t[0], c[1], t[1], c[2], t[2]);
1945
1946 c[0] = 0xc08080; t[0] = 15;
1947 c[1] = 0x0080c0; t[1] = 15;
1948 c[2] = 0x0080c0; t[2] = 15;
1949 odk_user_color(odk, "label_foreground", &c[0], &t[0]);
1950 odk_user_color(odk, "label_window", &c[1], &t[1]);
1951 odk_user_color(odk, "label_border", &c[2], &t[2]);
1952 otk->label_color = odk_alloc_text_palette(odk, c[0], t[0], c[1], t[1], c[2], t[2]);
1953
1954 c[0] = 0x008000; t[0] = 15;
1955 odk_user_color(odk, "slider", &c[0], &t[0]);
1956 otk->col_sl1 = odk_get_color(odk, c[0], t[0]);
1957 c[0] = 0xffff00; t[0] = 15;
1958 odk_user_color(odk, "slider_knob", &c[0], &t[0]);
1959 otk->col_sl2 = odk_get_color(odk, c[0], t[0]);
1960 c[0] = 0x808080; t[0] = 15;
1961 odk_user_color(odk, "focused_slider", &c[0], &t[0]);
1962 otk->col_sl1f = odk_get_color(odk, c[0], t[0]);
1963 c[0] = 0xff8080; t[0] = 15;
1964 odk_user_color(odk, "focused_slider_knob", &c[0], &t[0]);
1965 otk->col_sl2f = odk_get_color(odk, c[0], t[0]);
1966 otk->title_font = strdup("sans");
1967 otk->title_font_size = 40;
1968 otk->label_font = otk->title_font;
1969 otk->label_font_size = 40;
1970 otk->button_font = strdup("cetus");
1971 otk->button_font_size = 40;
1972
1973 pthread_mutex_init(&otk->draw_mutex, NULL);
1974 #ifdef ENABLE_UPDATE_JOB
1975 otk->update_job = schedule_job(1000, otk_update_job, otk);
1976 #else
1977 otk->update_job = 0;
1978 #endif
1979
1980 return otk;
1981 }
1982
otk_free(otk_t * otk)1983 void otk_free (otk_t *otk) {
1984
1985 lock_job_mutex();
1986 if(otk->update_job)
1987 cancel_job(otk->update_job);
1988 unlock_job_mutex();
1989
1990 otk_clear(otk);
1991
1992 g_list_free(otk->windows);
1993
1994 if (otk->title_font) free(otk->title_font);
1995 if (otk->button_font) free(otk->button_font);
1996
1997 odk_set_event_handler(otk->odk, NULL, NULL);
1998
1999 pthread_mutex_destroy(&otk->draw_mutex);
2000 ho_free (otk);
2001 }
2002