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