reimplement key ui with own written gtk_vkb_button widget
[fvkbd:fvkbd.git] / ui / gtk / fvkbd-key-ui-gtk.c
1 /*
2  * fvkbd-key-ui-gtk.c key unit gtk ui for fvkbd  
3  *
4  * Copyright (C) 2009, Intel Corporation.
5  *
6  * Author: Raymond Liu <raymond.liu@intel.com>
7  * 
8  * 
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * version 2.1 as published by the Free Software Foundation.
12  * 
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  * 
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  */
23
24
25 #include <gtk/gtk.h>
26 #include "fvkbd.h"
27 #include "fvkbd-keyboard.h"
28 #include "misc-utility.h"
29 #include "gtk-misc-utility.h"
30 #include "gtk-vkb-button.h"
31
32 #include "fvkbd-key.h"
33
34 typedef struct _KeyUI KeyUI;
35 struct _KeyUI {
36         GtkWidget *main_label;
37         GtkWidget *sub_label;
38         GtkWidget *img;
39
40         PangoFontDescription *font_desc;
41         PangoFontDescription *efont_desc;
42         PangoFontDescription *ofont_desc;
43 };
44
45 typedef struct _CandidateItem CandidateItem;
46 struct _CandidateItem {
47         GtkWidget *widget;
48         KeyActionType type;
49         gchar *disp;
50         union 
51         {
52                 gchar *string;
53                 KeySym sym;
54                 FvkbdKeyFunc func;
55         } u;
56 };
57
58 #define MAX_CANDIDATE_ITEMS 10
59
60 static guint longpress_timeout_id = 0;
61 static guint longpress_timeout_val = 800;
62 static guint pop_window_hide_timeout_id = 0;
63 static guint pop_window_hide_timeout_val = 5000;
64
65 static GtkWidget *pop_window = NULL;
66 static CandidateItem candidate_items[MAX_CANDIDATE_ITEMS];
67
68 static gboolean key_mode_do_switch_lock = FALSE;
69
70
71 static void set_candidate_item_string(gint n, gchar *disp, gchar *str, PangoFontDescription *desc);
72 static void candidate_item_clicked_cb(GtkButton *button, CandidateItem *item);
73 static void init_candidate_items(void);
74 static void update_candidate_item_none(void);
75 static void update_candidate_item_string(gchar *disp, gchar *str, PangoFontDescription *desc, gboolean reverse);
76 static void update_candidate_item_string_group(gchar **strs, PangoFontDescription *desc, gboolean reverse);
77 static void update_candidate_item_sym(gchar *disp, KeySym sym, PangoFontDescription *desc, gboolean reverse);
78 static GtkWidget *get_pop_window(void);
79 static void settle_pop_window(FvkbdKey *key, gint number, gboolean reverse);
80 static void show_pop_window(FvkbdKey *key, gboolean longpress);
81 static void hide_pop_window(void);
82 static gboolean hide_pop_window_cb(FvkbdKey *key);
83 static gboolean longpress_detected_cb(FvkbdKey *key);
84 static PangoFontDescription * get_key_pango_font_description (FvkbdUnit *unit, KbdFontType type);
85
86
87 static void
88 set_candidate_item_dummy(gint n)
89 {
90         GtkWidget *button;
91
92         if (n >= MAX_CANDIDATE_ITEMS)
93                 return;
94
95         candidate_items[n].type = KEY_ACTION_NONE;
96         button = candidate_items[n].widget;
97         gtk_button_set_label(GTK_BUTTON(button), "");
98 }
99
100
101 static void
102 set_candidate_item_string(gint n, gchar *disp, gchar *str, PangoFontDescription *desc)
103 {
104         GtkWidget *button;
105         GtkWidget *key_label;
106         if (str == NULL || n >= MAX_CANDIDATE_ITEMS)
107                 return;
108
109         candidate_items[n].type = KEY_ACTION_STRING;
110         candidate_items[n].u.string = str;
111         button = candidate_items[n].widget;
112         gtk_button_set_label(GTK_BUTTON(button), disp);
113         key_label = gtk_bin_get_child(GTK_BIN(button));
114         gtk_widget_modify_font(key_label, desc);
115 }
116
117
118 static void
119 set_candidate_item_color(gint n, KbdColorType type, GdkColor *color)
120 {
121         GtkWidget *button;
122         GtkWidget *label;
123
124         if (n >= MAX_CANDIDATE_ITEMS)
125                 return;
126
127         if ((type != KBD_COLOR_TYPE_KEY_POP_BG) && (type != KBD_COLOR_TYPE_KEY_POP_FG))
128                 return;
129
130         button = candidate_items[n].widget;
131         if (type == KBD_COLOR_TYPE_KEY_POP_BG) {
132                 gtk_widget_modify_bg(button, GTK_STATE_NORMAL, color);
133                 gtk_widget_modify_bg(button, GTK_STATE_PRELIGHT, color);
134                 gtk_widget_modify_bg(button, GTK_STATE_ACTIVE, color);
135         } else if (type == KBD_COLOR_TYPE_KEY_POP_FG){
136                 label = gtk_bin_get_child(GTK_BIN(button));
137                 if (label) {
138                         gtk_widget_modify_fg(label, GTK_STATE_NORMAL, color);
139                         gtk_widget_modify_fg(label, GTK_STATE_PRELIGHT, color);
140                         gtk_widget_modify_fg(label, GTK_STATE_ACTIVE, color);
141                 }
142         }
143 }
144
145
146 static void
147 candidate_item_clicked_cb(GtkButton *button, CandidateItem *item)
148 {
149         switch (item->type) {
150
151         case KEY_ACTION_STRING:
152                 fvkbd_key_send_utf8_string(item->u.string);
153                 break;
154
155         case KEY_ACTION_SYM:
156                 fvkbd_key_send_xkeysym(item->u.sym);
157                 break;
158
159         default:
160                 break;
161         }
162
163         if (pop_window_hide_timeout_id != 0) {
164                 g_source_remove(pop_window_hide_timeout_id);
165                 pop_window_hide_timeout_id = 0;
166                 hide_pop_window();
167         }
168
169         if (fvkbd_in_temp_mode())
170                 fvkbd_keyboard_resume_default_mode();
171 }
172
173
174 static void
175 init_candidate_items(void)
176 {
177         int i;
178         for (i = 0; i < MAX_CANDIDATE_ITEMS; i++) {
179                 candidate_items[i].widget = gtk_button_new();
180                 gtk_button_set_relief(GTK_BUTTON(candidate_items[i].widget), GTK_RELIEF_NONE);
181                 g_signal_connect(G_OBJECT(candidate_items[i].widget), "clicked",
182                         G_CALLBACK(candidate_item_clicked_cb), &candidate_items[i]);
183         }
184 }
185
186
187 static void
188 set_candidate_items_size(int width, int height)
189 {
190         int i;
191         for (i = 0; i < MAX_CANDIDATE_ITEMS; i++) {
192                 gtk_widget_set_size_request(candidate_items[i].widget,
193                                                 width, height);
194         }
195 }
196
197
198 static void
199 update_candidate_item_none(void)
200 {
201         int i;
202
203         for (i = 0; i < MAX_CANDIDATE_ITEMS; i++)
204                 gtk_widget_hide(candidate_items[i].widget);
205 }
206
207
208 static void
209 update_candidate_item_string(gchar *disp, gchar *str, PangoFontDescription *desc,
210                                 gboolean reverse)
211 {
212         int i;
213
214         if (!reverse) {
215                 set_candidate_item_dummy(0);
216                 set_candidate_item_string(1, disp, str, desc);
217         } else {
218                 set_candidate_item_string(0, disp, str, desc);
219                 set_candidate_item_dummy(1);
220         }
221
222         gtk_widget_show(candidate_items[0].widget);
223         gtk_widget_show(candidate_items[1].widget);
224
225         for (i = 2; i < MAX_CANDIDATE_ITEMS; i++)
226                 gtk_widget_hide(candidate_items[i].widget);
227
228 }
229
230
231 static void
232 update_candidate_item_string_group(gchar **strs, PangoFontDescription *desc,
233                                         gboolean reverse)
234 {
235         int i;
236         int n = 0;
237         gchar **tmp;
238
239         if (strs == NULL)
240                 return;
241
242         for (i = 0, tmp = strs; (i < (MAX_CANDIDATE_ITEMS - 1)) && *tmp; i++, tmp++)
243                 n++;
244
245         if (!reverse) {
246                 set_candidate_item_dummy(0);
247                 gtk_widget_show(candidate_items[0].widget);
248
249                 for (i = 1; i <= n; i++, strs++) {
250                         set_candidate_item_string(i, *strs, *strs, desc);
251                         gtk_widget_show(candidate_items[i].widget);
252                 }
253         } else {
254                 for (i = 0; i < n; i++, strs++) {
255                         set_candidate_item_string(n - 1 - i, *strs, *strs, desc);
256                         gtk_widget_show(candidate_items[n - 1 - i].widget);
257                 }
258                 set_candidate_item_dummy(n);
259                 gtk_widget_show(candidate_items[n].widget);     
260
261         }
262
263         for (i = n + 1; i < MAX_CANDIDATE_ITEMS; i++)
264                 gtk_widget_hide(candidate_items[i].widget);
265 }
266
267
268 static void
269 update_candidate_item_sym(gchar *disp, KeySym sym, PangoFontDescription *desc,
270                                 gboolean reverse)
271 {
272         int i;
273         GtkWidget *button;
274         GtkWidget *key_label;
275
276         if (!reverse) {
277                 set_candidate_item_dummy(0);
278                 i = 1;
279         } else {
280                 set_candidate_item_dummy(1);
281                 i = 0;
282         }
283
284         gtk_widget_show(candidate_items[0].widget);
285         gtk_widget_show(candidate_items[1].widget);
286
287         candidate_items[i].type = KEY_ACTION_SYM;
288         candidate_items[i].u.sym = sym;
289         button = candidate_items[i].widget;
290         gtk_button_set_label(GTK_BUTTON(button), disp);
291         key_label = gtk_bin_get_child(GTK_BIN(button));
292         gtk_widget_modify_font(key_label, desc);
293         gtk_widget_show(button);
294
295         for (i = 2; i < MAX_CANDIDATE_ITEMS; i++)
296                 gtk_widget_hide(candidate_items[i].widget);
297 }
298
299
300 static GtkWidget *
301 get_pop_window(void)
302 {
303         if (pop_window == NULL) {
304                 GtkWidget *hbox, *frame;
305                 int i;
306
307                 pop_window = gtk_window_new(GTK_WINDOW_POPUP);
308                 gtk_window_set_accept_focus(GTK_WINDOW(pop_window), FALSE);
309                 gtk_window_set_resizable(GTK_WINDOW(pop_window), FALSE);
310
311                 frame = gtk_frame_new(NULL);
312                 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
313
314                 hbox = gtk_hbox_new(FALSE, 0);
315
316                 gtk_container_add (GTK_CONTAINER (frame), hbox);
317
318                 init_candidate_items();
319                 for (i = 0; i < MAX_CANDIDATE_ITEMS; i++) {
320                         gtk_box_pack_start(GTK_BOX(hbox), candidate_items[i].widget,
321                                                 FALSE, FALSE, 0);
322                 }
323
324                 gtk_widget_show_all(frame);
325
326                 gtk_container_add (GTK_CONTAINER (pop_window), frame);
327         }
328
329         return pop_window;
330 }
331
332
333 static void
334 settle_pop_window_color(FvkbdKey *key, gint number)
335 {
336         GtkWidget *w = get_pop_window();
337         GdkColor bgcolor, fgcolor;
338         int i;
339
340         get_gdkcolor(FVKBD_UNIT(key), KBD_COLOR_TYPE_KEY_POP_BG, &bgcolor);
341         get_gdkcolor(FVKBD_UNIT(key), KBD_COLOR_TYPE_KEY_POP_FG, &fgcolor);
342
343         gtk_widget_modify_bg(w, GTK_STATE_NORMAL, &bgcolor);
344
345         for (i = 0; i < number; i++) {
346                 set_candidate_item_color(i, KBD_COLOR_TYPE_KEY_POP_BG, &bgcolor);
347                 set_candidate_item_color(i, KBD_COLOR_TYPE_KEY_POP_FG, &fgcolor);
348         }
349 }
350
351
352 static void
353 settle_pop_window(FvkbdKey *key, gint number, gboolean reverse)
354 {
355         GtkWidget *w = get_pop_window();
356         GdkWindow *keywindow;
357
358         int pop_w = 0, pop_h = 0;
359         int x, y;
360         int ux, uy, uw, uh;
361         int ww, wh;
362         gfloat x_ratio, y_ratio;
363         GtkWidget *key_widget;
364
365         key_widget = fvkbd_unit_get_widget(FVKBD_UNIT(key));
366         keywindow = gtk_widget_get_window(key_widget);
367
368         gdk_window_get_origin(keywindow, &x, &y);
369         gtk_window_get_size(GTK_WINDOW(w), &pop_w, &pop_h);
370
371         /* If key_widget don't have it's own gdk window, then gdk_window_get_origin will get the position
372             of it's parent window, say panel window, then we need to do some offset to gain the right position */
373         if (GTK_WIDGET_NO_WINDOW(key_widget)) {
374                 fvkbd_unit_get_position(FVKBD_UNIT(key), &ux, &uy);
375         } else {
376                 ux = 0;
377                 uy = 0;
378         }
379
380         if ((fvkbd_unit_get_size(FVKBD_UNIT(key), &uw, &uh) == 0) &&
381                 (fvkbd_unit_get_ratio(FVKBD_UNIT(key), &x_ratio, &y_ratio) == 0)) {
382                 if (!reverse) {
383                         x += (ux * x_ratio);
384                         y += (uy * y_ratio);
385                 } else {
386                         gtk_window_get_size(GTK_WINDOW(w), &ww, &wh);
387                         x += ((ux + uw) * x_ratio - ww);
388                         y += (uy * y_ratio);
389                 }
390         }
391
392         gtk_window_move(GTK_WINDOW(w), x, y);
393 }
394
395
396 static void
397 show_pop_window(FvkbdKey *key, gboolean longpress)
398 {
399         FvkbdKeyAction *action;
400         GtkWidget *w = get_pop_window();
401         int item_number = 1;
402         int i;
403         int ux, uy, uw, uh, pw, ph;
404         gfloat x_ratio, y_ratio;
405         gboolean reverse = FALSE;
406
407         fvkbd_unit_get_size(fvkbd_unit_get_parent(FVKBD_UNIT(key)), &pw, &ph);
408         if ((fvkbd_unit_get_position(FVKBD_UNIT(key), &ux, &uy) == 0)) {
409                 if (ux <= (pw / 2))
410                         reverse = FALSE;
411                 else
412                         reverse = TRUE;
413         }
414
415         fvkbd_unit_get_ratio(FVKBD_UNIT(key), &x_ratio, &y_ratio);
416         fvkbd_unit_get_size(FVKBD_UNIT(key), &uw, &uh);
417
418         action = fvkbd_key_get_current_action(key);
419         KeyUI *ui_data = fvkbd_unit_get_ui_data(FVKBD_UNIT(key));
420         PangoFontDescription *desc;
421
422         if (!ui_data->ofont_desc) {
423                 desc = get_key_pango_font_description(FVKBD_UNIT(key), KBD_FONT_TYPE_POP);
424         } else
425                 desc = ui_data->ofont_desc;
426
427         switch (action->type) {
428
429         case KEY_ACTION_STRING:
430                 update_candidate_item_string(action->disp, action->u.string, desc, reverse);
431                 item_number = 2;
432                 break;
433
434         case KEY_ACTION_STRING_GROUP:
435                 if (!longpress) {
436                         update_candidate_item_string(action->disp, action->u.string, desc, reverse);
437                         item_number = 2;
438                 } else {
439                         update_candidate_item_string_group(action->u.string_group, desc, reverse);
440                         for (i = 0; (i < MAX_CANDIDATE_ITEMS) && *(action->u.string_group + i); i++)
441                                 item_number++;
442                 }
443                 break;
444
445         case KEY_ACTION_SYM:
446                 update_candidate_item_sym(action->disp, action->u.sym, desc, reverse);
447                 item_number = 2;
448                 break;
449
450         default:
451                 update_candidate_item_none();
452                 hide_pop_window();
453                 return;
454         }
455
456         set_candidate_items_size(uw * x_ratio, uh * y_ratio);
457         settle_pop_window_color(key, item_number);
458         // well, hiding pop window here, just wish the window size will be retrived
459         // correctly by gtk_window_get_size later in settle_pop_window.
460         hide_pop_window();
461         settle_pop_window(key, item_number, reverse);
462         if (!GTK_WIDGET_VISIBLE(w))
463                 gtk_widget_show(w);
464 }
465
466
467 static void
468 hide_pop_window(void)
469 {
470         GtkWidget *w = get_pop_window();
471         if (GTK_WIDGET_VISIBLE(w))
472                 gtk_widget_hide(w);
473 }
474
475
476 static gboolean
477 hide_pop_window_cb(FvkbdKey *key)
478 {
479         hide_pop_window();
480         pop_window_hide_timeout_id = 0;
481         
482         return FALSE;
483 }
484
485
486 static gboolean
487 longpress_detected_cb(FvkbdKey *key)
488 {
489         FvkbdKeyAction *action;
490
491         action = fvkbd_key_get_current_action(key);
492
493         switch (action->type) {
494
495         case KEY_ACTION_STRING:
496         case KEY_ACTION_STRING_GROUP:
497         case KEY_ACTION_SYM:
498                 show_pop_window(key, TRUE);
499                 pop_window_hide_timeout_id = g_timeout_add(pop_window_hide_timeout_val,
500                                                 (GSourceFunc)hide_pop_window_cb, key);
501
502                 break;
503         case KEY_ACTION_FUNC:
504                 switch (action->u.func.type) {
505                 case FVKBD_KEY_FUNC_MODE_SELECT:
506                         key_mode_do_switch_lock = TRUE;
507                         break;
508
509                 default:
510                         break;
511                 }
512
513                 break;
514         default:
515                 break;
516         }
517
518         longpress_timeout_id = 0;
519         
520         return FALSE;
521 }
522
523
524 static void
525 fvkbd_key_gtk_pressed_cb(GtkButton *button, FvkbdKey *key)
526 {
527         if (longpress_timeout_id != 0) {
528                 g_source_remove(longpress_timeout_id);
529                 longpress_timeout_id = 0;
530         }
531
532         if (pop_window_hide_timeout_id != 0) {
533                 g_source_remove(pop_window_hide_timeout_id);
534                 pop_window_hide_timeout_id = 0;
535                 hide_pop_window();
536         }
537
538         longpress_timeout_id = g_timeout_add(longpress_timeout_val,
539                                         (GSourceFunc)longpress_detected_cb, key);
540
541         show_pop_window(key, FALSE);
542 }
543
544
545 static void
546 fvkbd_key_gtk_released_cb(GtkButton *button, FvkbdKey *key)
547 {
548         FvkbdKeyAction *action;
549         gboolean need_reset_default_mode = TRUE;
550
551         /* if the candiate window is shown, then we do nothing and return */
552         if (pop_window_hide_timeout_id != 0) {
553                 return;
554         }
555
556         if (longpress_timeout_id != 0) {
557                 g_source_remove(longpress_timeout_id);
558                 longpress_timeout_id = 0;
559         }
560
561         hide_pop_window();
562
563         if ((action = fvkbd_key_get_current_action(key)) == NULL)
564                 return;
565
566         switch (action->type) {
567         case KEY_ACTION_STRING:
568                 fvkbd_key_send_utf8_string(action->u.string);
569                 break;
570
571         case KEY_ACTION_STRING_GROUP:
572                 fvkbd_key_send_utf8_string(action->u.string_group[0]);
573                 break;
574
575         case KEY_ACTION_SYM:
576                 fvkbd_key_send_xkeysym(action->u.sym);
577                 break;
578
579         case KEY_ACTION_FUNC:
580                 switch (action->u.func.type) {
581                 case FVKBD_KEY_FUNC_MODE_SELECT:
582                         fvkbd_key_func_handlers(key, action, &key_mode_do_switch_lock);
583                         need_reset_default_mode = FALSE;
584                         key_mode_do_switch_lock = FALSE;
585                         break;
586
587                 default:
588                         fvkbd_key_func_handlers(key, action, NULL);
589                 }
590
591                 break;
592
593         case KEY_ACTION_SCRIPT:
594                 fvkbd_do_script(action->u.string);
595                 break;
596
597         default:
598                 break;
599         }
600
601         if (fvkbd_in_temp_mode() && need_reset_default_mode)
602                 fvkbd_keyboard_resume_default_mode();
603
604 }
605
606
607 static void
608 fvkbd_key_settle_color (FvkbdUnit *unit, GtkWidget *key_widget, gboolean lock)
609 {
610         KeyUI *ui_data = fvkbd_unit_get_ui_data(unit);
611         GdkColor color;
612         GtkWidget *label;
613
614         // set key background color
615         if (!lock) {
616                 if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_BG, &color)) {
617                         vkb_button_set_bg(key_widget, GTK_STATE_NORMAL, &color);
618                         vkb_button_set_bg(key_widget, GTK_STATE_PRELIGHT, &color);
619                 }
620
621                 if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_FG, &color)) {
622                         vkb_button_set_bg(key_widget, GTK_STATE_ACTIVE, &color);
623                 }
624         } else {
625                 if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_FG, &color)) {
626                         vkb_button_set_bg(key_widget, GTK_STATE_NORMAL, &color);
627                         vkb_button_set_bg(key_widget, GTK_STATE_PRELIGHT, &color);
628                 }
629
630                 if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_BG, &color)) {
631                         vkb_button_set_bg(key_widget, GTK_STATE_ACTIVE, &color);
632                 }
633         }
634
635         // set main label color
636         label = ui_data->main_label;
637         if (label) {
638                 if (!lock) {
639                         if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_FG, &color)) {
640                                 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &color);
641                                 gtk_widget_modify_fg(label, GTK_STATE_PRELIGHT, &color);
642                         }
643
644                         if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_BG, &color)) {
645                                 gtk_widget_modify_fg(label, GTK_STATE_ACTIVE, &color);
646                         }
647                 } else {
648                         if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_BG, &color)) {
649                                 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &color);
650                                 gtk_widget_modify_fg(label, GTK_STATE_PRELIGHT, &color);
651                         }
652
653                         if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_FG, &color)) {
654                                 gtk_widget_modify_fg(label, GTK_STATE_ACTIVE, &color);
655                         }
656                 }
657         }
658
659         // set sub label color
660         label = ui_data->sub_label;
661         if (label) {
662                 if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_EXTRA_FG, &color)) {
663                         gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &color);
664                         gtk_widget_modify_fg(label, GTK_STATE_PRELIGHT, &color);
665                 }
666
667                 if (get_gdkcolor(unit, KBD_COLOR_TYPE_KEY_BG, &color)) {
668                         gtk_widget_modify_fg(label, GTK_STATE_ACTIVE, &color);
669                 }
670         }
671 }
672
673
674 static PangoFontDescription *
675 get_key_pango_font_description (FvkbdUnit *unit, KbdFontType type)
676 {
677         gfloat x_ratio, y_ratio, ratio;
678         int dpi_xres, dpi_yres;
679         KeyUI *ui_data = fvkbd_unit_get_ui_data(unit);
680         gchar *font_family = fvkbd_key_get_font_family(unit, type);
681         gchar *font_weight = fvkbd_key_get_font_weight(unit, type);
682         gint font_size = fvkbd_key_get_font_size(unit, type);
683
684         PangoFontDescription *desc = NULL;
685
686         fvkbd_unit_get_ratio(unit, &x_ratio, &y_ratio);
687         get_resolution(&dpi_xres, &dpi_yres);
688
689         x_ratio = x_ratio * DEFAULT_DPI / dpi_xres;
690         y_ratio = y_ratio * DEFAULT_DPI / dpi_yres;
691
692         ratio = (x_ratio < y_ratio) ? x_ratio : y_ratio;
693         font_size = font_size * ratio;
694
695         switch (type) {
696                 case KBD_FONT_TYPE_NORMAL:
697                         if (!ui_data->font_desc)
698                                 ui_data->font_desc = get_pango_font_description_from_info(font_family, font_weight, font_size);
699                         desc = ui_data->font_desc;
700                         break;
701
702                 case KBD_FONT_TYPE_EXTRA:
703                         if (!ui_data->efont_desc)
704                                 ui_data->efont_desc = get_pango_font_description_from_info(font_family, font_weight, font_size);
705                         desc = ui_data->efont_desc;
706                         break;
707
708                 case KBD_FONT_TYPE_POP:
709                         if (!ui_data->ofont_desc)
710                                 ui_data->ofont_desc = get_pango_font_description_from_info(font_family, font_weight, font_size);
711                         desc = ui_data->ofont_desc;
712                         break;
713
714                 default:
715                         break;
716         }
717
718         return desc;
719 }
720
721
722 static void
723 fvkbd_key_settle_font (FvkbdUnit *unit, GtkWidget *key_widget)
724 {
725         KeyUI *ui_data = fvkbd_unit_get_ui_data(unit);
726         PangoFontDescription *desc;
727         GtkWidget *label;
728
729         // set main label font
730         label = ui_data->main_label;
731         if (label) {
732                 if (!ui_data->font_desc) {
733                         desc = get_key_pango_font_description(unit, KBD_FONT_TYPE_NORMAL);
734                 } else
735                         desc = ui_data->font_desc;
736
737                 gtk_widget_modify_font(label, desc);
738         }
739
740         // set sub label font
741         label = ui_data->sub_label;
742         if (label) {
743                 if (!ui_data->efont_desc) {
744                         desc = get_key_pango_font_description(unit, KBD_FONT_TYPE_EXTRA);
745                 } else
746                         desc = ui_data->efont_desc;
747
748                         gtk_widget_modify_font(label, desc);
749         }
750 }
751
752
753 static GtkWidget *
754 _create_key_label (FvkbdUnit *unit, gint id)
755 {
756         FvkbdKey *key;
757         FvkbdKeyAction *action;
758         KeyUI *ui_data = fvkbd_unit_get_ui_data(unit);
759         gint w,h;
760         GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
761         GtkWidget *label = NULL, *sub_label = NULL, *img = NULL;
762
763         g_return_val_if_fail(FVKBD_IS_KEY(unit), FALSE);
764         key = FVKBD_KEY(unit);
765
766         fvkbd_unit_get_size(unit, &w, &h);
767
768         if ((action = fvkbd_key_get_current_action(key)) == NULL)
769                 goto done;
770
771         if (action->img != NULL) {
772                 img = gtk_image_new_from_file(action->img);
773                 goto done;
774         }
775
776         if (action->type == KEY_ACTION_STRING_GROUP) {
777                 gchar *label_str = NULL;
778
779                 #if 0
780                 // show all the optional characters
781                 label_str = g_strjoinv(" ", &(action->u.string_group[1]));
782                 #else
783                 // only show the first optional character
784                 label_str = g_strdup(action->u.string_group[1]);
785                 #endif
786
787                 sub_label = gtk_label_new(label_str);
788                 g_free(label_str);
789                 label = gtk_label_new(fvkbd_key_get_disp(key, id));
790         } else if (action->type == KEY_ACTION_STRING ||
791                 action->type == KEY_ACTION_SYM ||
792                 action->type == KEY_ACTION_FUNC ||
793                 action->type == KEY_ACTION_SCRIPT) {
794
795                 sub_label = gtk_label_new(NULL);
796                 label = gtk_label_new(fvkbd_key_get_disp(key, id));
797         }
798
799 done:
800
801         ui_data->sub_label = sub_label;
802         if (sub_label)
803                 gtk_box_pack_start(GTK_BOX(vbox), sub_label, FALSE, FALSE, 0);
804
805         ui_data->main_label = label;
806         if (label)
807                 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
808
809         ui_data->img = img;
810         if (img)
811                 gtk_box_pack_start(GTK_BOX(vbox), img, TRUE, TRUE, 0);
812
813         gtk_widget_show_all(vbox);
814         return vbox;
815 }
816
817
818 static void
819 _update_key_label (FvkbdUnit *unit, gint id)
820 {
821         GtkWidget *key_widget;
822         GtkWidget *key_label;
823
824         key_widget = fvkbd_unit_get_widget(unit);
825         
826         key_label = gtk_bin_get_child(GTK_BIN(key_widget));
827
828         if (key_label) {
829                 gtk_widget_destroy(key_label);
830                 key_label = NULL;
831         }
832
833         key_label = _create_key_label(unit, id);
834         gtk_container_add(GTK_CONTAINER(key_widget), key_label);
835 }
836
837
838 static void
839 _set_key_label_tmp_mode (FvkbdUnit *unit)
840 {
841         KeyUI *ui_data = fvkbd_unit_get_ui_data(unit);
842         GtkWidget *label;
843         gchar *disp;
844
845         label = ui_data->main_label;
846         disp = g_strconcat("<u>", gtk_label_get_text(GTK_LABEL(label)), "</u>", NULL);
847         gtk_label_set_text(GTK_LABEL(label), disp);
848         gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
849         g_free(disp);
850 }
851
852
853 gboolean
854 fvkbd_key_build_ui (FvkbdUnit *unit, gpointer *widget)
855 {
856         FvkbdKey *key;
857         KeyUI *ui_data;
858         gint w,h;
859         gboolean ret = TRUE;
860
861         GtkWidget *key_widget;
862         GtkWidget *key_label;
863
864         g_return_val_if_fail(FVKBD_IS_KEY(unit), FALSE);
865         key = FVKBD_KEY(unit);
866
867         key_widget = gtk_vkb_button_new();
868
869         ui_data = g_new0(KeyUI, 1);
870         fvkbd_unit_set_ui_data(unit, ui_data);
871         ui_data->main_label = NULL;
872         ui_data->sub_label = NULL;
873         ui_data->font_desc = NULL;
874         ui_data->efont_desc = NULL;
875         ui_data->ofont_desc = NULL;
876
877         fvkbd_unit_get_size(unit, &w, &h);
878         gtk_widget_set_size_request(key_widget, w, h);
879
880         key_label = _create_key_label(unit, 0);
881         gtk_container_add(GTK_CONTAINER(key_widget), key_label);
882
883         // set color
884         fvkbd_key_settle_color(unit, key_widget, FALSE);
885
886         // set font
887         fvkbd_key_settle_font(unit, key_widget);
888
889         g_signal_connect(G_OBJECT(key_widget), "pressed",
890                         G_CALLBACK(fvkbd_key_gtk_pressed_cb), key);
891         g_signal_connect(G_OBJECT(key_widget), "released",
892                         G_CALLBACK(fvkbd_key_gtk_released_cb), key);
893
894         if (widget != NULL)
895                 *widget = key_widget;
896         fvkbd_unit_set_widget(unit, key_widget);
897         return ret;
898 }
899
900
901 gboolean
902 fvkbd_key_resize_ui (FvkbdUnit *unit, gfloat x_ratio, gfloat y_ratio)
903 {
904         FvkbdKey *key;
905         KeyUI *ui_data;
906         GtkWidget *key_widget;
907         //GtkWidget *key_label;
908         int tmp_w, tmp_h;
909         int new_w, new_h;
910
911         g_return_val_if_fail(FVKBD_IS_KEY(unit), FALSE);
912         key = FVKBD_KEY(unit);
913
914         ui_data = fvkbd_unit_get_ui_data(unit);
915         key_widget = fvkbd_unit_get_widget(unit);
916
917         if (fvkbd_unit_get_size(unit, &tmp_w, &tmp_h) == 0) {
918                 new_w = tmp_w * x_ratio;
919                 new_h = tmp_h * y_ratio;
920                 gtk_widget_set_size_request(key_widget, new_w, new_h);
921
922         } else
923                 return FALSE;
924
925         if (ui_data->font_desc) {
926                 pango_font_description_free(ui_data->font_desc);
927                 ui_data->font_desc = NULL;
928         }
929         if (ui_data->efont_desc) {
930                 pango_font_description_free(ui_data->efont_desc);
931                 ui_data->efont_desc = NULL;
932         }
933         if (ui_data->ofont_desc) {
934                 pango_font_description_free(ui_data->ofont_desc);
935                 ui_data->ofont_desc = NULL;
936         }
937
938         fvkbd_unit_set_ratio(unit, x_ratio, y_ratio);
939         fvkbd_key_settle_font(unit, key_widget);
940
941         return TRUE;
942 }
943
944
945 gboolean
946 fvkbd_key_destroy_ui (FvkbdUnit *unit)
947 {
948         FvkbdKey *key;
949         KeyUI *ui_data;
950         gboolean ret = TRUE;
951
952         GtkWidget *key_widget;
953
954         g_return_val_if_fail(FVKBD_IS_KEY(unit), FALSE);
955         key = FVKBD_KEY(unit);
956
957         key_widget = fvkbd_unit_get_widget(unit);
958
959         gtk_widget_hide_all(key_widget);
960         gtk_widget_destroy(key_widget);
961
962         fvkbd_unit_set_widget(unit, NULL);
963
964         ui_data = fvkbd_unit_get_ui_data(unit);
965         if (ui_data->font_desc)
966                 pango_font_description_free(ui_data->font_desc);
967         if (ui_data->efont_desc)
968                 pango_font_description_free(ui_data->efont_desc);
969         if (ui_data->ofont_desc)
970                 pango_font_description_free(ui_data->ofont_desc);
971         g_free(ui_data);
972         fvkbd_unit_set_ui_data(unit, NULL);
973
974         return ret;
975 }
976
977
978 gint
979 fvkbd_key_set_mode (FvkbdUnit *unit, gint id)
980 {
981         FvkbdKey *key;
982         FvkbdKeyAction *action;
983         GtkWidget *key_widget;
984         gboolean show_lock_mode = FALSE;
985
986         g_return_val_if_fail(FVKBD_IS_KEY(unit), -1);
987         key = FVKBD_KEY(unit);
988
989         key_widget = fvkbd_unit_get_widget(unit);
990
991         // Yes, we get the default action here to handle disp diffirently for tmply mode change
992         action = fvkbd_key_get_action(key, 0);
993
994         if ((action->type == KEY_ACTION_FUNC) &&
995                 (action->u.func.type == FVKBD_KEY_FUNC_MODE_SELECT)) {
996                 if ((fvkbd_in_temp_mode()) && ((*((int *)action->u.func.data)) == id)) {
997                         _update_key_label(unit, 0);
998                         _set_key_label_tmp_mode(unit);
999                 } else {
1000                         _update_key_label(unit, id);
1001                         if ((*((int *)action->u.func.data)) == id)
1002                                 show_lock_mode = TRUE;
1003                 }
1004         } else {
1005                 _update_key_label(unit, id);
1006         }
1007
1008         // set color
1009         fvkbd_key_settle_color(unit, key_widget, show_lock_mode);
1010
1011         // set font
1012         fvkbd_key_settle_font(unit, key_widget);
1013
1014         return 0;
1015 }
1016