1 /*
2  * Copyright (C) 2000-2019 the xine project
3  *
4  * This file is part of xine, a unix video player.
5  *
6  * xine is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * xine is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  *
20  */
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <stdio.h>
26 
27 #include "_xitk.h"
28 
29 
30 static void tabs_arrange(xitk_widget_t *);
31 
32 /*
33  *
34  */
enability(xitk_widget_t * w)35 static void enability(xitk_widget_t *w) {
36 
37   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_TABS) &&
38 	   (w->type & WIDGET_GROUP_WIDGET))) {
39     tabs_private_data_t *private_data = (tabs_private_data_t *) w->private_data;
40     int                  i;
41 
42     if(w->enable == WIDGET_ENABLE) {
43       xitk_enable_and_show_widget(private_data->left);
44       xitk_enable_and_show_widget(private_data->right);
45       for(i = 0; i < private_data->num_entries; i++)
46 	xitk_enable_widget(private_data->tabs[i]);
47     }
48     else {
49       xitk_disable_widget(private_data->left);
50       xitk_disable_widget(private_data->right);
51       for(i = 0; i < private_data->num_entries; i++) {
52 	xitk_disable_widget(private_data->tabs[i]);
53       }
54     }
55   }
56 }
57 
notify_destroy(xitk_widget_t * w)58 static void notify_destroy(xitk_widget_t *w) {
59   tabs_private_data_t *private_data;
60 
61   if(w && (((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_TABS) &&
62 	   (w->type & WIDGET_GROUP_WIDGET))) {
63     int i;
64 
65     private_data = (tabs_private_data_t *) w->private_data;
66 
67     for(i = 0; i <= private_data->num_entries; i++)
68       XITK_FREE(private_data->bt[i]);
69 
70     XITK_FREE(private_data->skin_element_name);
71     XITK_FREE(private_data);
72   }
73 }
74 
75 /*
76  *
77  */
tabs_arrange(xitk_widget_t * w)78 static void tabs_arrange(xitk_widget_t *w) {
79   tabs_private_data_t  *private_data;
80 
81   if(w && ((((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_TABS) &&
82 	    (w->type & WIDGET_GROUP_WIDGET)) && w->visible == 1)) {
83     int i = 0, width, x;
84 
85     private_data = (tabs_private_data_t*) w->private_data;
86 
87     if(private_data->offset != private_data->old_offset) {
88 
89       for(i = 0; i < private_data->num_entries; i++)
90 	xitk_hide_widget(private_data->tabs[i]);
91 
92       i = private_data->offset;
93       width = 0;
94       x = private_data->x;
95 
96       do {
97 	if((width + xitk_get_widget_width(private_data->tabs[i])) <= private_data->width - 40) {
98 	  xitk_set_widget_pos(private_data->tabs[i], x, private_data->y);
99 	  width += xitk_get_widget_width(private_data->tabs[i]);
100 	  x += xitk_get_widget_width(private_data->tabs[i]);
101 	  xitk_show_widget(private_data->tabs[i]);
102 	}
103 	else
104 	  break;
105 
106 	i++;
107 
108       } while((i < private_data->num_entries) && (width < (private_data->width - 40)));
109       private_data->gap_widthstart = width;
110     }
111     /*
112      * Fill gap
113      */
114     if((((private_data->width - 40) - private_data->gap_widthstart) * 3) > 0) {
115       xitk_image_t *p;
116       GC            gc;
117       XGCValues     gcv;
118 
119       p = xitk_image_create_image(private_data->imlibdata,
120 				  ((private_data->width - 40) - private_data->gap_widthstart) * 3,
121 				  private_data->bheight>>1);
122 
123       if(p) {
124 	gcv.graphics_exposures = False;
125 
126 	draw_flat(private_data->imlibdata, p->image, p->width, p->height);
127 
128         XLOCK (private_data->imlibdata->x.x_lock_display, private_data->imlibdata->x.disp);
129 	gc = XCreateGC(private_data->imlibdata->x.disp,
130 		       p->image->pixmap, GCGraphicsExposures, &gcv);
131 	XCopyArea(private_data->imlibdata->x.disp,
132 		  p->image->pixmap, private_data->parent_wlist->win, gc,
133 		  0, 0, p->width/3, p->height,
134 		  private_data->x + private_data->gap_widthstart, private_data->y);
135         XUNLOCK (private_data->imlibdata->x.x_unlock_display, private_data->imlibdata->x.disp);
136 
137 	draw_tab(private_data->imlibdata, p);
138 
139         XLOCK (private_data->imlibdata->x.x_lock_display, private_data->imlibdata->x.disp);
140 	XCopyArea(private_data->imlibdata->x.disp,
141 		  p->image->pixmap, private_data->parent_wlist->win, gc,
142 		  0, 0, p->width/3, p->height,
143 		  private_data->x + private_data->gap_widthstart, private_data->y + p->height);
144 	XFreeGC(private_data->imlibdata->x.disp, gc);
145         XUNLOCK (private_data->imlibdata->x.x_unlock_display, private_data->imlibdata->x.disp);
146 
147 	xitk_image_free_image(private_data->imlibdata, &p);
148       }
149     }
150 
151     if(private_data->offset != private_data->old_offset) {
152       if(i < private_data->num_entries)
153 	xitk_start_widget(private_data->right);
154       else
155 	xitk_stop_widget(private_data->right);
156 
157       if(private_data->offset == 0)
158 	xitk_stop_widget(private_data->left);
159       else
160 	xitk_start_widget(private_data->left);
161     }
162 
163     private_data->old_offset = private_data->offset;
164   }
165 }
166 
167 /*
168  *
169  */
paint(xitk_widget_t * w)170 static void paint(xitk_widget_t *w) {
171 
172   if(w && (((w->type & WIDGET_GROUP_MASK) == WIDGET_GROUP_TABS) &&
173 	   (w->type & WIDGET_GROUP_WIDGET))) {
174 
175     if(w->visible == 1) {
176       tabs_arrange(w);
177     }
178   }
179 }
180 
notify_event(xitk_widget_t * w,widget_event_t * event,widget_event_result_t * result)181 static int notify_event(xitk_widget_t *w, widget_event_t *event, widget_event_result_t *result) {
182   int retval = 0;
183 
184   switch(event->type) {
185   case WIDGET_EVENT_PAINT:
186     paint(w);
187     break;
188   case WIDGET_EVENT_DESTROY:
189     notify_destroy(w);
190     break;
191   case WIDGET_EVENT_ENABLE:
192     enability(w);
193     break;
194   }
195 
196   return retval;
197 }
198 
199 /*
200  *
201  */
tabs_select(xitk_widget_t * w,void * data,int select)202 static void tabs_select(xitk_widget_t *w, void *data, int select) {
203   tabs_private_data_t *private_data = (tabs_private_data_t*) ((btnlist_t*)data)->itemlist->private_data;
204 
205   if(select) {
206     private_data->old_selected = private_data->selected;
207     private_data->selected = (int)((btnlist_t*)data)->sel;
208 
209     xitk_labelbutton_set_state(private_data->tabs[private_data->old_selected], 0);
210 
211 
212     //    tabs_arrange(private_data->widget);
213     if(private_data->callback)
214       private_data->callback(private_data->widget, private_data->userdata, private_data->selected);
215   }
216   else {
217     xitk_labelbutton_set_state(private_data->tabs[private_data->selected], 1);
218   }
219 
220 }
221 
222 /*
223  *
224  */
tabs_select_prev(xitk_widget_t * w,void * data)225 static void tabs_select_prev(xitk_widget_t *w, void *data) {
226   xitk_widget_t *t = (xitk_widget_t *)data;
227   tabs_private_data_t *private_data = (tabs_private_data_t*)t->private_data;
228 
229   if(private_data->offset > 0) {
230     private_data->old_offset = private_data->offset;
231     private_data->offset--;
232     tabs_arrange(private_data->widget);
233   }
234 }
235 
236 /*
237  *
238  */
tabs_select_next(xitk_widget_t * w,void * data)239 static void tabs_select_next(xitk_widget_t *w, void *data) {
240   xitk_widget_t *t = (xitk_widget_t *)data;
241   tabs_private_data_t *private_data = (tabs_private_data_t*)t->private_data;
242 
243   if(private_data->offset < (private_data->num_entries - 1)) {
244     private_data->old_offset = private_data->offset;
245     private_data->offset++;
246     tabs_arrange(private_data->widget);
247   }
248 }
249 
250 /*
251  *
252  */
xitk_tabs_set_current_selected(xitk_widget_t * w,int select)253 void xitk_tabs_set_current_selected(xitk_widget_t *w, int select) {
254   tabs_private_data_t *private_data;
255 
256   if(!w)
257     XITK_WARNING("%s(): widget is NULL\n", __FUNCTION__);
258 
259   if(w && (((w->type & WIDGET_GROUP_MASK) == WIDGET_GROUP_TABS) &&
260 	   (w->type & WIDGET_GROUP_WIDGET))) {
261 
262     private_data = (tabs_private_data_t*)w->private_data;
263 
264     if(select <= private_data->num_entries) {
265       private_data->old_selected = private_data->selected;
266       private_data->selected = select;
267       tabs_arrange(w);
268     }
269 
270   }
271 }
272 
273 /*
274  *
275  */
xitk_tabs_get_current_selected(xitk_widget_t * w)276 int xitk_tabs_get_current_selected(xitk_widget_t *w) {
277   tabs_private_data_t *private_data;
278 
279   if(!w) {
280     XITK_WARNING("%s(): widget is NULL\n", __FUNCTION__);
281     return -1;
282   }
283 
284   if(((w->type & WIDGET_GROUP_MASK) == WIDGET_GROUP_TABS) &&
285      (w->type & WIDGET_GROUP_WIDGET)) {
286 
287     private_data = (tabs_private_data_t*)w->private_data;
288     return (private_data->selected);
289   }
290 
291 
292   return -1;
293 }
294 
295 /*
296  *
297  */
xitk_tabs_get_current_tab_selected(xitk_widget_t * w)298 const char *xitk_tabs_get_current_tab_selected(xitk_widget_t *w) {
299   tabs_private_data_t *private_data;
300 
301   if(!w) {
302     XITK_WARNING("%s(): widget is NULL\n", __FUNCTION__);
303     return NULL;
304   }
305 
306   if(((w->type & WIDGET_GROUP_MASK) == WIDGET_GROUP_TABS) &&
307      (w->type & WIDGET_GROUP_WIDGET)) {
308 
309     private_data = (tabs_private_data_t*)w->private_data;
310     return ((xitk_labelbutton_get_label(private_data->tabs[private_data->selected])));
311   }
312 
313   return NULL;
314 }
315 
316 /*
317  *
318  */
xitk_noskin_tabs_create(xitk_widget_list_t * wl,xitk_tabs_widget_t * t,int x,int y,int width,const char * fontname)319 xitk_widget_t *xitk_noskin_tabs_create(xitk_widget_list_t *wl,
320 				       xitk_tabs_widget_t *t,
321                                        int x, int y, int width,
322                                        const char *fontname) {
323   xitk_widget_t         *mywidget;
324   tabs_private_data_t   *private_data;
325 
326   XITK_CHECK_CONSTITENCY(t);
327 
328   if((t->entries == NULL) || (t->num_entries == 0))
329     XITK_DIE("%s(): entries should be non NULL.\n", __FUNCTION__);
330 
331   mywidget = (xitk_widget_t *) xitk_xmalloc(sizeof(xitk_widget_t));
332   private_data = (tabs_private_data_t *) xitk_xmalloc(sizeof(tabs_private_data_t));
333 
334   private_data->imlibdata   = t->imlibdata;
335   private_data->widget      = mywidget;
336 
337   private_data->entries     = t->entries;
338   private_data->num_entries = t->num_entries;
339 
340   private_data->parent_wlist = t->parent_wlist;
341 
342   private_data->x           = x;
343   private_data->y           = y;
344   private_data->width       = width;
345 
346   private_data->callback    = t->callback;
347   private_data->userdata    = t->userdata;
348 
349   private_data->skin_element_name = (t->skin_element_name == NULL) ? NULL : strdup(t->skin_element_name);
350 
351   {
352     xitk_font_t               *fs;
353     int                        fwidth, fheight, i;
354     xitk_labelbutton_widget_t  lb;
355     xitk_button_widget_t       b;
356     int                        xx = x;
357 
358     fs = xitk_font_load_font(t->imlibdata->x.disp, fontname);
359 
360     xitk_font_set_font(fs, t->parent_wlist->gc);
361     fheight = xitk_font_get_string_height(fs, " ");
362 
363     XITK_WIDGET_INIT(&lb, t->imlibdata);
364     XITK_WIDGET_INIT(&b, t->imlibdata);
365 
366     private_data->bheight = fheight + 18;
367 
368     for(i = 0; i < t->num_entries; i++) {
369 
370       private_data->bt[i]           = (btnlist_t *) xitk_xmalloc(sizeof(btnlist_t));
371       private_data->bt[i]->itemlist = mywidget;
372       private_data->bt[i]->sel      = i;
373 
374       fwidth = xitk_font_get_string_length(fs, t->entries[i]);
375 
376       lb.skin_element_name = NULL;
377       lb.button_type       = RADIO_BUTTON;
378       lb.align             = ALIGN_CENTER;
379       lb.label             = t->entries[i];
380       lb.callback          = NULL;
381       lb.state_callback    = tabs_select;
382       lb.userdata          = (void *) (private_data->bt[i]);
383       private_data->tabs[i] = xitk_noskin_labelbutton_create (t->parent_wlist, &lb, xx, y, fwidth + 20,
384         private_data->bheight, "Black", "Black", "Black", fontname);
385       xitk_dlist_add_tail (&t->parent_wlist->list, &private_data->tabs[i]->node);
386       private_data->tabs[i]->type |= WIDGET_GROUP | WIDGET_GROUP_TABS;
387       xx += fwidth + 20;
388 
389       xitk_hide_widget(private_data->tabs[i]);
390       draw_tab(t->imlibdata, (xitk_get_widget_foreground_skin(private_data->tabs[i])));
391 
392     }
393 
394     /*
395        Add left/rigth arrows
396     */
397     {
398       xitk_image_t  *wimage;
399 
400       b.skin_element_name = NULL;
401       b.callback          = tabs_select_prev;
402       b.userdata          = (void *)mywidget;
403       private_data->left = xitk_noskin_button_create (t->parent_wlist, &b, (private_data->x + width) - 40,
404         (y-1) + (private_data->bheight - 20), 20, 20);
405       xitk_dlist_add_tail (&t->parent_wlist->list, &private_data->left->node);
406       private_data->left->type |= WIDGET_GROUP | WIDGET_GROUP_TABS;
407 
408       wimage = xitk_get_widget_foreground_skin(private_data->left);
409       if(wimage)
410 	draw_arrow_left(t->imlibdata, wimage);
411 
412       xx += 20;
413       b.skin_element_name = NULL;
414       b.callback          = tabs_select_next;
415       b.userdata          = (void *)mywidget;
416       private_data->right = xitk_noskin_button_create (t->parent_wlist, &b, (private_data->x + width) - 20,
417         (y-1) + (private_data->bheight - 20), 20, 20);
418         xitk_dlist_add_tail (&t->parent_wlist->list, &private_data->right->node);
419       private_data->right->type |= WIDGET_GROUP | WIDGET_GROUP_TABS;
420 
421       wimage = xitk_get_widget_foreground_skin(private_data->right);
422       if(wimage)
423 	draw_arrow_right(t->imlibdata, wimage);
424 
425     }
426 
427     private_data->old_selected = private_data->selected = 0;
428     private_data->offset = 0;
429     private_data->old_offset = -2;
430 
431     xitk_font_unload_font(fs);
432   }
433 
434   mywidget->private_data          = private_data;
435 
436   mywidget->wl                    = wl;
437 
438   mywidget->enable                = 1;
439   mywidget->running               = 0;
440   mywidget->visible               = 0;
441 
442   mywidget->have_focus            = FOCUS_LOST;
443   mywidget->imlibdata             = private_data->imlibdata;
444   mywidget->x = mywidget->y       = 0;
445   mywidget->width                 = private_data->width;
446   mywidget->height                = private_data->bheight;
447   mywidget->type                  = WIDGET_GROUP | WIDGET_GROUP_WIDGET | WIDGET_GROUP_TABS;
448   mywidget->event                 = notify_event;
449   mywidget->tips_timeout          = 0;
450   mywidget->tips_string           = NULL;
451 
452   xitk_labelbutton_set_state(private_data->tabs[private_data->selected], 1);
453 
454   return mywidget;
455 }
456