http://mulliner.org/bluetooth/xkbdbthid-0.1_src.tar.gz
[xkbdbthid.git] / xkbd-0.8.15_bthid / src / button.c
1 /* 
2    xkbd - xlib based onscreen keyboard.
3
4    Copyright (C) 2001 Matthew Allum
5
6    This program 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, or (at your option)
9    any later version.
10
11    This program 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
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #ifdef USE_XPM
22 #include <X11/xpm.h>
23 #endif
24 #include <X11/keysymdef.h>
25 #include "structs.h"
26 #include "button.h"
27
28
29
30 int max3( int a, int b, int c ) 
31
32   int rval; 
33   rval = a; 
34   if( b>rval ) rval=b; 
35   if( c>rval ) rval=c; 
36   return( rval );
37 }
38
39 GC _createGC(Display *display, Window win)
40 {
41   GC gc;
42   unsigned long valuemask = 0;
43   XGCValues values;             
44   unsigned int line_width = 1;  
45   int line_style = LineSolid;   
46   int cap_style = CapRound;     
47   int join_style = JoinRound;   
48
49
50   gc = XCreateGC(display, win, valuemask, &values);
51   XSetForeground(display, gc, 
52                  BlackPixel(display, DefaultScreen(display) ));
53   XSetBackground(display, gc, 
54                  WhitePixel(display, DefaultScreen(display) ));
55   
56   XSetLineAttributes(display, gc, line_width, line_style, 
57                      cap_style, join_style );
58
59   XSetFillStyle(display, gc, FillSolid);
60
61   return gc;
62 }
63
64
65 int _XColorFromStr(Display *display, XColor *col, const char *defstr)
66 {
67   char *str;
68   const char delim[] = ",:";
69   char *token;
70   XColor exact;
71   str = strdup(defstr);
72
73   if ((strchr(defstr, delim[0]) != NULL)
74       || (strchr(defstr, delim[1]) != NULL) )
75   {
76      token = strsep (&str, delim); 
77      col->red = ( atoi(token) * 65535 ) / 255; 
78      token = strsep (&str, delim); 
79      col->green = ( atoi(token) * 65535 ) / 255;
80      token = strsep (&str, delim); 
81      col->blue = ( atoi(token) * 65535 ) / 255;
82
83      return XAllocColor(display,
84                         DefaultColormap(display, DefaultScreen(display)),
85                         col);
86   } else {
87           return XAllocNamedColor(display,
88                              DefaultColormap(display, DefaultScreen(display)),
89                              defstr, col, &exact);
90   }
91 }
92
93
94 void button_set_bg_col(button *b, char *txt)
95 {
96   XColor col;
97   b->bg_gc = _createGC(b->kb->display, b->kb->win);
98   if (_XColorFromStr(b->kb->display, &col, txt) == 0)
99     {
100       perror("color allocation failed\n");
101       exit(1);
102     }
103   XSetForeground(b->kb->display, b->bg_gc, col.pixel );
104
105 }
106
107 void button_set_fg_col(button *b, char *txt)
108 {
109   XColor col;
110   b->fg_gc = _createGC(b->kb->display, b->kb->win);
111   if (_XColorFromStr(b->kb->display, &col, txt) == 0)
112     {
113       perror("color allocation failed\n");
114       exit(1);
115     }
116   XSetForeground(b->kb->display, b->fg_gc, col.pixel );
117
118 }
119
120 #ifdef USE_XPM
121 void button_set_pixmap(button *b, char *filename)
122 {
123   XpmAttributes attrib;
124   //XGCValues gc_vals;
125   //unsigned long valuemask = 0;
126
127   b->pixmap = malloc(sizeof(Pixmap));
128   b->mask = malloc(sizeof(Pixmap));
129
130   attrib.valuemask = XpmCloseness;
131   attrib.closeness = 40000;
132
133   if (XpmReadFileToPixmap( b->kb->display, b->kb->win, filename,
134                        b->pixmap, b->mask, &attrib)
135       != XpmSuccess )
136     {
137           fprintf(stderr, "xkbd: failed loading image '%s'\n", filename);
138           exit(1);
139     }
140
141   /* we'll also be needing a gc for transparency */
142   b->mask_gc = _createGC(b->kb->display,b->kb->win);
143   /*
144   gc_vals.clip_mask = *(b->mask);
145   valuemask = GCClipMask;
146   XChangeGC(b->kb->display, b->mask_gc, valuemask, &gc_vals);
147   */
148   XSetForeground(b->kb->display, b->mask_gc, 
149                  WhitePixel(b->kb->display, DefaultScreen(b->kb->display) ));
150   XSetBackground(b->kb->display, b->mask_gc, 
151                  BlackPixel(b->kb->display, DefaultScreen(b->kb->display) ));
152   
153   XSetClipMask(b->kb->display, b->mask_gc, *(b->mask));
154
155   b->c_width  = attrib.width;
156   b->c_height = attrib.height;
157 }
158 #endif
159
160 void button_set_layout(button *b, char *txt)
161 {
162   b->layout_switch = atoi(txt);
163 }
164
165 void button_set_txt(button *b, char *txt)
166 {
167   b->default_txt = malloc(sizeof(char)*(strlen(txt)+1));
168   strcpy(b->default_txt,txt);
169 }
170
171 void button_set_txt_ks(button *b, char *txt)
172 {
173   if (strcmp(txt, "Caps_Lock") == 0 )
174     b->modifier = BUT_CAPS;
175   else if (strncmp(txt, "Shift", 5) == 0 )
176     b->modifier = BUT_SHIFT;
177   else if (strncmp(txt, "Control", 7) == 0 )
178     b->modifier = BUT_CTRL;
179   else if (strncmp(txt, "Alt", 3) == 0 )
180       b->modifier = BUT_ALT;
181   else if (strncmp(txt, "Meta", 4) == 0 )
182       b->modifier = BUT_META;
183   else if (strncmp(txt, "!Mod", 3) == 0 )
184   { b->modifier = BUT_MOD; b->default_ks = 0; return; }
185
186   if ((b->default_ks = XStringToKeysym(txt)) == (KeySym)NULL)
187     fprintf(stderr, "Cant find keysym for %s \n", txt); 
188
189   /* for backwards compatibility */
190   if (b->default_ks >= 0x061 && b->default_ks <= 0x07a)
191     b->options |= OPT_OBEYCAPS;
192 }
193
194 void button_set_shift_txt(button *b, char *txt)
195 {
196   b->shift_txt = malloc(sizeof(char)*(strlen(txt)+1));
197   strcpy(b->shift_txt,txt);
198 }
199
200 void button_set_shift_ks(button *b, char *txt)
201 {
202   if ((b->shift_ks = XStringToKeysym(txt)) == (KeySym)NULL)
203     fprintf(stderr, "Cant find keysym for %s \n", txt); 
204 }
205
206 void button_set_slide_ks(button *b, char *txt, int dir)
207 {
208   KeySym tmp_ks;
209   if ( (tmp_ks = XStringToKeysym(txt)) == 0) /* NoSymbol ?? */
210     {
211       fprintf(stderr, "Cant find keysym for %s \n", txt); 
212       return;
213     }
214
215   switch(dir)
216     {
217       case UP    : b->slide_up_ks = tmp_ks; break;
218       case DOWN  : b->slide_down_ks = tmp_ks; break;
219       case LEFT  : b->slide_left_ks = tmp_ks; break;
220       case RIGHT : b->slide_right_ks = tmp_ks; break;
221     }
222 }
223
224 void button_set_scancode(button *b, char *txt)
225 {
226         b->scancode = atoi(txt);
227 }
228
229 void button_set_mod_txt(button *b, char *txt)
230 {
231   b->mod_txt = malloc(sizeof(char)*(strlen(txt)+1));
232   strcpy(b->mod_txt,txt);
233 }
234
235 void button_set_mod_ks(button *b, char *txt)
236 {
237   if ((b->mod_ks = XStringToKeysym(txt)) == (KeySym)NULL)
238     fprintf(stderr, "Cant find keysym for %s \n", txt); 
239 }
240
241 int _button_get_txt_size(button *b, char *txt)
242 {
243 #ifdef USE_XFT          
244   if (b->kb->render_type == xft)
245     {
246       XGlyphInfo       extents;
247       XftTextExtentsUtf8(b->kb->display, b->kb->xftfont,
248                          (unsigned char *) txt, strlen(txt),
249                          &extents);
250       return extents.width;
251
252     } else {
253 #endif
254       return XTextWidth(b->kb->font_info, txt, strlen(txt));
255 #ifdef USE_XFT          
256     }
257 #endif
258 }
259
260 int button_calc_c_width(button *b)
261 {
262   int i = 0, j = 0, k = 0; // ouch - gotta be a better way
263
264   if (b->pixmap != NULL || b->c_width ) 
265     return b->c_width; /* already calculated from image or width_param */ 
266
267   if (b->default_txt != NULL)
268     i = _button_get_txt_size(b, b->default_txt);
269   if (b->shift_txt != NULL)
270     j = _button_get_txt_size(b, b->shift_txt);
271   if (b->mod_txt != NULL)
272     k = _button_get_txt_size(b, b->mod_txt);
273
274   b->c_width = max3( i,j,k );
275   return b->c_width;
276 }
277  
278 int button_calc_c_height(button *b)
279 {
280
281   if (b->pixmap != NULL || b->c_height ) 
282     return b->c_height; /*already calculated from image or height param */ 
283
284 #ifdef USE_XFT          
285   if (b->kb->render_type == xft)
286     {
287       b->c_height =
288         b->kb->xftfont->height;
289     } else {
290 #endif
291       b->c_height = b->kb->font_info->ascent + b->kb->font_info->descent;
292 #ifdef USE_XFT          
293     }
294 #endif
295   return b->c_height;
296 }
297
298 int button_get_c_height(button *b)
299 {
300    return b->c_height;
301 }
302
303 int button_set_b_size(button *b, int size)
304 {
305    b->b_size = size;
306    return size;
307 }
308
309 void button_render(button *b, int mode)
310 {
311   /*
312     set up a default gc to point to whatevers gc is not NULL
313      moving up via button -> box -> keyboard 
314   */
315   GC gc_txt;
316   GC gc_solid; 
317
318 #ifdef USE_XFT          
319   XftColor tmp_col;
320 #endif
321
322   int x,y;
323   char *txt = NULL;
324
325   x = button_get_abs_x(b) - b->kb->vbox->x;
326   y = button_get_abs_y(b) - b->kb->vbox->y;
327
328
329   if (mode == BUTTON_PRESSED)
330     { 
331       gc_solid = b->fg_gc;         
332       gc_txt   = b->kb->txt_gc;
333 #ifdef USE_XFT          
334       tmp_col  = b->kb->color_bg;
335 #endif
336     }
337   else if(mode == BUTTON_LOCKED)
338     { 
339       gc_solid = b->fg_gc;         
340       gc_txt   = b->kb->txt_rev_gc; 
341 #ifdef USE_XFT          
342       tmp_col  = b->kb->color_bg;
343 #endif
344     }
345   else  /* BUTTON_RELEASED */
346     { 
347       gc_solid = b->bg_gc; 
348       gc_txt   = b->kb->txt_gc; 
349 #ifdef USE_XFT          
350       tmp_col = b->kb->color_fg;
351 #endif
352     }
353
354
355   /* figure out what text to display 
356      via keyboard state              */
357   if ( b->kb->state != KB_STATE_NORMAL ) 
358     {
359       if ( (b->kb->state & KB_STATE_SHIFT 
360             || b->kb->state & KB_STATE_CAPS )
361            && b->shift_txt != NULL )
362         {
363            if (b->kb->state & KB_STATE_CAPS
364                && b->kb->state & KB_STATE_SHIFT)
365            {
366               if (b->options & OPT_OBEYCAPS)
367                 txt = b->default_txt;
368               else
369                 txt = b->shift_txt;
370            } 
371            else if (b->kb->state & KB_STATE_CAPS) 
372            {
373               if (b->options & OPT_OBEYCAPS)
374                  txt = b->shift_txt;
375
376            }
377            else txt = b->shift_txt;
378         } 
379       else if ( b->kb->state & KB_STATE_MOD 
380                 && b->mod_txt != NULL )
381         {
382           txt = b->mod_txt;
383         }
384     }
385
386   if (txt == NULL) txt = b->default_txt;
387
388   if (!(b->default_ks || b->shift_ks || b->mod_ks) &&
389       ( b->default_txt == NULL && b->shift_txt == NULL && b->mod_txt == NULL)  
390       ) 
391     return;  /* its a 'blank' button - just a spacer */
392
393   /* -- but color  gc1*/
394   XFillRectangle( b->kb->display, b->kb->backing, gc_solid, 
395                   x, y, b->act_width, b->act_height );
396
397   /* -- kb gc */
398   if (b->kb->theme != plain)
399     XDrawRectangle( b->kb->display, b->kb->backing, b->kb->bdr_gc, 
400                     x, y, b->act_width, b->act_height );
401   
402   if (b->kb->theme == rounded)
403     {
404       XDrawPoint( b->kb->display, b->kb->backing, b->kb->bdr_gc, x+1, y+1);
405       XDrawPoint( b->kb->display, b->kb->backing, 
406                   b->kb->bdr_gc, x+b->act_width-1, y+1);
407       XDrawPoint( b->kb->display, b->kb->backing, 
408                   b->kb->bdr_gc, x+1, y+b->act_height-1);
409       XDrawPoint( b->kb->display, b->kb->backing, 
410                   b->kb->bdr_gc, x+b->act_width-1,
411                   y+b->act_height-1);
412     }
413
414   if (b->pixmap != NULL)
415     {
416       /* TODO: improve alignment of images, kinda hacked at the mo ! */
417       XGCValues gc_vals;
418       unsigned long valuemask = 0;
419       
420
421       XSetClipMask(b->kb->display, b->mask_gc,*(b->mask));
422       
423       gc_vals.clip_x_origin = x+(b->x_pad/2)+b->b_size;
424       gc_vals.clip_y_origin = y+b->c_height+(b->y_pad/2) +
425                                       b->b_size-b->c_height +2;
426       valuemask =  GCClipXOrigin | GCClipYOrigin ;
427       XChangeGC(b->kb->display, b->mask_gc, valuemask, &gc_vals);
428
429       XCopyArea(b->kb->display, *(b->pixmap), b->kb->backing, b->mask_gc, 
430                 0, 0, b->c_width, 
431                 b->c_height, x+(b->x_pad/2)+b->b_size,
432                 y +b->c_height+(b->y_pad/2) -b->c_height + b->b_size+2 
433       );
434       return; /* imgs cannot have text aswell ! */
435     }
436   if (txt != NULL)
437     {
438        int xspace;
439        //if (b->c_width > _button_get_txt_size(b,txt))
440        xspace = x+((b->act_width - _button_get_txt_size(b,txt))/2);
441           //else
442           //xspace = x+((b->c_width)/2);
443           //xspace = x+(b->x_pad/2)+b->b_size;
444 #ifdef USE_XFT          
445     if (b->kb->render_type == xft)
446       {
447         int y_offset = ((b->c_height + b->y_pad) - b->kb->xftfont->height)/2;
448          XftDrawStringUtf8(b->kb->xftdraw, &tmp_col, b->kb->xftfont,
449                         /*x+(b->x_pad/2)+b->b_size, */
450                         xspace,
451                         /* y + b->c_height + b->b_size + (b->y_pad/2) - 4 */
452                         y + y_offset + b->kb->xftfont->ascent ,
453                        /* y+b->c_height+(b->y_pad/2)-b->b_size, */
454                        (unsigned char *) txt, strlen(txt));
455       }
456     else
457 #endif
458       {
459         XDrawString(
460                     b->kb->display, b->kb->backing, gc_txt,  
461                     /*x+(b->x_pad/2)+b->b_size,*/
462                     xspace,
463                     y+b->c_height+(b->y_pad/2)+b->b_size
464                     -4, 
465                     txt, strlen(txt)
466                     );
467       }
468     }
469
470 }
471
472 void button_paint(button *b)
473 {
474   /* use the vbox offsets for the location within the window */
475   int x = button_get_abs_x(b) - b->kb->vbox->x;
476   int y = button_get_abs_y(b) - b->kb->vbox->y;
477
478   XCopyArea(b->kb->display, b->kb->backing, b->kb->win, b->kb->gc, 
479             x, y, b->act_width, b->act_height, 
480             x+b->kb->vbox->x, y+b->kb->vbox->y);
481 }
482
483 int button_get_abs_x(button *b)
484 {
485   int total = b->x;
486   box *tmp_box = b->parent;
487   while (tmp_box != NULL)
488     {      
489       total += tmp_box->x;
490       tmp_box = tmp_box->parent;
491     }
492   /* total = total - b->kb->vbox->x;  HACK ! */
493
494   return total;
495 }
496
497 int button_get_abs_y(button *b)
498 {
499   int total = b->y;
500   box *tmp_box = b->parent;
501   while (tmp_box != NULL)
502     {      
503       total += tmp_box->y;
504       tmp_box = tmp_box->parent;
505     }
506
507   return total;
508 }
509
510 button* button_new(keyboard *k)
511 {
512   button *b = NULL;
513   b = malloc(sizeof(button));
514   b->kb = k;
515   b->default_txt = NULL;
516   b->shift_txt   = NULL;
517   b->mod_txt     = NULL;
518
519   b->default_ks     = 0; /* I hope 0 is safe ! */
520   b->shift_ks       = 0 ;  
521   b->mod_ks         = 0;
522
523   b->slide_up_ks    = 0;
524   b->slide_down_ks  = 0;
525   b->slide_left_ks  = 0;
526   b->slide_right_ks = 0;
527
528   b->c_width        = 0;
529   b->c_height       = 0;
530   b->is_width_spec  = False;
531   b->key_span_width = 0;
532   
533   b->slide = none;
534
535   b->modifier    = BUT_NORMAL;
536   b->options = OPT_NORMAL;  
537   b->b_size = 0;
538   b->pixmap      = NULL;
539   b->mask        = NULL;
540   b->fg_gc      = k->gc;
541   b->bg_gc      = k->rev_gc;
542
543   b->layout_switch = -1;
544
545   b->parent = NULL;
546   return b;
547 }
548
549
550
551
552
553