1 /*
2  * Copyright (C) 2005 Hiroyuki Ikezoe <poincare@ikezoe.net>
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 /*
19  * The original code is gimpfgbgeditor.c in GIMP-2.3.2.
20  * Copyright (C) 2004 Michael Natterer <mitch@gimp.org>
21  */
22 
23 #ifdef HAVE_CONFIG_H
24   #include <config.h>
25 #endif
26 
27 #include <string.h>
28 
29 #include "scim_anthy_color_button.h"
30 #include "scim_anthy_intl.h"
31 
32 
33 enum
34 {
35   PROP_0,
36   PROP_ACTIVE_COLOR
37 };
38 
39 enum
40 {
41   COLOR_CHANGED,
42   LAST_SIGNAL
43 };
44 
45 typedef enum
46 {
47     INVALID_AREA,
48     FOREGROUND_AREA,
49     BACKGROUND_AREA,
50     SWAP_AREA,
51     DEFAULT_AREA
52 } FgBgTarget;
53 
54 
55 #define WIDGET_WIDTH 32
56 #define WIDGET_HEIGHT 32
57 
58 static void     scim_anthy_color_button_class_init     (ScimAnthyColorButtonClass *klass);
59 static void     scim_anthy_color_button_init           (ScimAnthyColorButton      *object);
60 
61 static void     scim_anthy_color_button_destroy        (GtkObject      *object);
62 static gboolean scim_anthy_color_button_expose         (GtkWidget      *widget,
63 							GdkEventExpose *eevent);
64 static gboolean scim_anthy_color_button_button_press   (GtkWidget      *widget,
65 							GdkEventButton *bevent);
66 static gboolean scim_anthy_color_button_button_release (GtkWidget      *widget,
67 							GdkEventButton *bevent);
68 
69 
70 static guint  button_signals[LAST_SIGNAL] = { 0 };
71 
72 static GtkDrawingAreaClass *parent_class = NULL;
73 
74 GType
scim_anthy_color_button_get_type(void)75 scim_anthy_color_button_get_type (void)
76 {
77     static GType type = 0;
78 
79     if (!type) {
80         static const GTypeInfo info = {
81             sizeof (ScimAnthyColorButtonClass),
82             NULL,           /* base_init */
83             NULL,           /* base_finalize */
84             (GClassInitFunc) scim_anthy_color_button_class_init,
85             NULL,           /* class_finalize */
86             NULL,           /* class_data */
87             sizeof (ScimAnthyColorButton),
88             0,              /* n_preallocs */
89             (GInstanceInitFunc) scim_anthy_color_button_init,
90         };
91 
92         type = g_type_register_static (GTK_TYPE_DRAWING_AREA,
93                                        "ScimAnthyColorButton",
94                                        &info, (GTypeFlags) 0);
95     }
96 
97     return type;
98 }
99 
100 static void
scim_anthy_color_button_class_init(ScimAnthyColorButtonClass * klass)101 scim_anthy_color_button_class_init (ScimAnthyColorButtonClass *klass)
102 {
103     GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (klass);
104     GtkWidgetClass *widget_class     = GTK_WIDGET_CLASS (klass);
105 
106     parent_class = (GtkDrawingAreaClass *) g_type_class_peek_parent (klass);
107 
108     button_signals[COLOR_CHANGED] =
109       g_signal_new ("color-changed",
110   		  G_TYPE_FROM_CLASS (klass),
111   		  G_SIGNAL_RUN_FIRST,
112   		  G_STRUCT_OFFSET (ScimAnthyColorButtonClass, color_changed),
113   		  NULL, NULL,
114   		  g_cclosure_marshal_VOID__VOID,
115   		  G_TYPE_NONE, 0);
116 
117     gtk_object_class->destroy          = scim_anthy_color_button_destroy;
118 
119     widget_class->expose_event         = scim_anthy_color_button_expose;
120     widget_class->button_press_event   = scim_anthy_color_button_button_press;
121     widget_class->button_release_event = scim_anthy_color_button_button_release;
122 }
123 
124 static void
scim_anthy_color_button_init(ScimAnthyColorButton * object)125 scim_anthy_color_button_init (ScimAnthyColorButton *object)
126 {
127     /*set default color */
128     gdk_color_parse ("#000000", &object->fg_color);
129     gdk_color_parse ("#ffffff", &object->bg_color);
130 
131     gtk_widget_add_events (GTK_WIDGET (object),
132                     GDK_BUTTON_PRESS_MASK |
133                     GDK_BUTTON_RELEASE_MASK);
134 }
135 
136 
137 static void
scim_anthy_color_button_destroy(GtkObject * object)138 scim_anthy_color_button_destroy (GtkObject *object)
139 {
140     ScimAnthyColorButton *button = SCIM_ANTHY_COLOR_BUTTON (object);
141 
142     if (button->render_buf) {
143         g_free (button->render_buf);
144         button->render_buf = NULL;
145         button->render_buf_size = 0;
146     }
147 
148     if (button->swap_icon) {
149         g_object_unref (button->swap_icon);
150         button->swap_icon = NULL;
151     }
152 
153     GTK_OBJECT_CLASS (parent_class)->destroy (object);
154 }
155 
156 static void
scim_anthy_color_button_draw_rect(ScimAnthyColorButton * button,GdkDrawable * drawable,GdkGC * gc,gint x,gint y,gint width,gint height,GdkColor * color)157 scim_anthy_color_button_draw_rect (ScimAnthyColorButton *button,
158                              GdkDrawable    *drawable,
159                              GdkGC          *gc,
160                              gint            x,
161                              gint            y,
162                              gint            width,
163                              gint            height,
164                              GdkColor        *color)
165 {
166     gint    rowstride;
167     guchar  r, g, b;
168     gint    xx, yy;
169     guchar *bp;
170 
171     g_return_if_fail (width > 0 && height > 0);
172 
173     r = (color->red >> 8);
174     g = (color->green >> 8);
175     b = (color->blue >> 8);
176 
177     rowstride = 3 * ((width + 3) & -4);
178 
179     if (! button->render_buf || button->render_buf_size < height * rowstride) {
180         button->render_buf_size = rowstride * height;
181 
182         g_free (button->render_buf);
183         button->render_buf = (guchar *) g_malloc (button->render_buf_size);
184     }
185 
186     bp = button->render_buf;
187     for (xx = 0; xx < width; xx++) {
188         *bp++ = r;
189         *bp++ = g;
190         *bp++ = b;
191     }
192 
193     bp = button->render_buf;
194 
195     for (yy = 1; yy < height; yy++) {
196         bp += rowstride;
197         memcpy (bp, button->render_buf, rowstride);
198     }
199 
200     gdk_draw_rgb_image (drawable, gc, x, y, width, height,
201                         GDK_RGB_DITHER_MAX,
202                         button->render_buf,
203                         rowstride);
204 }
205 
206 static gboolean
scim_anthy_color_button_expose(GtkWidget * widget,GdkEventExpose * eevent)207 scim_anthy_color_button_expose (GtkWidget      *widget,
208                           GdkEventExpose *eevent)
209 {
210     ScimAnthyColorButton *button = SCIM_ANTHY_COLOR_BUTTON (widget);
211     gint            width, height;
212     gint            swap_w = 0, swap_h = 0;
213     gint            rect_w, rect_h;
214 
215     if (!GTK_WIDGET_DRAWABLE (widget))
216         return FALSE;
217 
218     width  = widget->allocation.width;
219     height = widget->allocation.height;
220 
221     /*  draw the swap colors pixbuf  */
222     if (!button->swap_icon) {
223         button->swap_icon
224 	  = gdk_pixbuf_new_from_file (SCIM_ICONDIR"/scim-anthy-swap-colors.png",
225 				      NULL);
226     }
227 
228     if (button->swap_icon) {
229       swap_w = gdk_pixbuf_get_width  (button->swap_icon);
230       swap_h = gdk_pixbuf_get_height (button->swap_icon);
231     }
232 
233     if (swap_w < width / 2 && swap_h < height / 2) {
234         gdk_draw_pixbuf (widget->window, NULL, button->swap_icon,
235                          0, 0, width - swap_w, 0, swap_w, swap_h,
236                          GDK_RGB_DITHER_NORMAL, 0, 0);
237     } else {
238         swap_w = swap_h = 0;
239     }
240 
241     rect_h = height - swap_h - 2;
242     rect_w = width  - swap_w - 4;
243 
244     if (rect_h > (height * 3 / 4)) {
245         rect_w = MAX (rect_w - (rect_h - ((height * 3 / 4))),
246                       width * 2 / 3);
247     }
248 
249     button->rect_width  = rect_w;
250     button->rect_height = rect_h;
251 
252 
253     /*  draw the background area  */
254     scim_anthy_color_button_draw_rect (button,
255                                  widget->window,
256                                  widget->style->fg_gc[0],
257                                  (width - rect_w),
258                                  (height - rect_h),
259                                  rect_w, rect_h,
260                                  &button->bg_color);
261 
262     gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL,
263                       GTK_SHADOW_IN,
264                       NULL, widget, NULL,
265                       (width - rect_w),
266                       (height - rect_h),
267                       rect_w, rect_h);
268 
269 
270     /*  draw the foreground area  */
271     scim_anthy_color_button_draw_rect (button,
272                                  widget->window,
273                                  widget->style->fg_gc[0],
274                                  0, 0,
275                                  rect_w, rect_h,
276                                  &button->fg_color);
277 
278     gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL,
279                       GTK_SHADOW_IN,
280                       NULL, widget, NULL,
281                       0, 0,
282                       rect_w, rect_h);
283 
284     return TRUE;
285 }
286 
287 static FgBgTarget
scim_anthy_color_button_target(ScimAnthyColorButton * button,gint x,gint y)288 scim_anthy_color_button_target (ScimAnthyColorButton *button,
289                           gint            x,
290                           gint            y)
291 {
292     gint width  = GTK_WIDGET (button)->allocation.width;
293     gint height = GTK_WIDGET (button)->allocation.height;
294     gint rect_w = button->rect_width;
295     gint rect_h = button->rect_height;
296 
297     if (x > 0 && x < rect_w && y > 0 && y < rect_h)
298         return FOREGROUND_AREA;
299     else if (x > (width - rect_w)  && x < width  &&
300              y > (height - rect_h) && y < height)
301         return BACKGROUND_AREA;
302     else if (x > 0      && x < (width - rect_w) &&
303              y > rect_h && y < height)
304         return DEFAULT_AREA;
305     else if (x > rect_w && x < width &&
306              y > 0      && y < (height - rect_h))
307         return SWAP_AREA;
308 
309     return INVALID_AREA;
310 }
311 
312 static void
scim_anthy_color_button_open_color_dialog(ScimAnthyColorButton * button,gboolean fg)313 scim_anthy_color_button_open_color_dialog (ScimAnthyColorButton *button, gboolean fg)
314 {
315     GtkWidget *dialog;
316     const gchar *title;
317     GdkColor *color;
318     gint result;
319 
320     title = fg ? _("Foreground color") : _("Background color");
321     color = fg ? &button->fg_color : &button->bg_color;
322 
323     dialog = gtk_color_selection_dialog_new (title);
324 
325     gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dialog)->colorsel),
326                                            color);
327     gtk_widget_show (dialog);
328 
329     result = gtk_dialog_run (GTK_DIALOG (dialog));
330 
331     switch (result) {
332         case GTK_RESPONSE_OK:
333             gtk_color_selection_get_current_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dialog)->colorsel),
334                                                    color);
335             g_signal_emit (button, button_signals[COLOR_CHANGED], 0);
336             break;
337         default:
338             break;
339     }
340 
341     gtk_widget_destroy (dialog);
342     gtk_widget_queue_draw (GTK_WIDGET (button));
343 }
344 
345 static void
scim_anthy_color_button_swap_color(ScimAnthyColorButton * button)346 scim_anthy_color_button_swap_color (ScimAnthyColorButton *button)
347 {
348     GdkColor tmp;
349     tmp.red   = button->fg_color.red;
350     tmp.green = button->fg_color.green;
351     tmp.blue  = button->fg_color.blue;
352 
353     button->fg_color.red   = button->bg_color.red;
354     button->fg_color.green = button->bg_color.green;
355     button->fg_color.blue  = button->bg_color.blue;
356 
357     button->bg_color.red   = tmp.red;
358     button->bg_color.green = tmp.green;
359     button->bg_color.blue  = tmp.blue;
360     g_signal_emit (button, button_signals[COLOR_CHANGED], 0);
361 }
362 
363 static gboolean
scim_anthy_color_button_button_press(GtkWidget * widget,GdkEventButton * bevent)364 scim_anthy_color_button_button_press (GtkWidget      *widget,
365                                 GdkEventButton *bevent)
366 {
367     ScimAnthyColorButton *button = SCIM_ANTHY_COLOR_BUTTON (widget);
368     if (bevent->button == 1 && bevent->type == GDK_BUTTON_PRESS) {
369         FgBgTarget target = scim_anthy_color_button_target (button,
370                                                       (gint) bevent->x, (gint) bevent->y);
371 
372         button->click_target = INVALID_AREA;
373 
374         switch (target) {
375             case FOREGROUND_AREA:
376               button->click_target = FOREGROUND_AREA;
377               scim_anthy_color_button_open_color_dialog (button, TRUE);
378               break;
379 
380             case BACKGROUND_AREA:
381               button->click_target = BACKGROUND_AREA;
382               scim_anthy_color_button_open_color_dialog (button, FALSE);
383               break;
384 
385             case SWAP_AREA:
386               scim_anthy_color_button_swap_color (button);
387               gtk_widget_queue_draw (GTK_WIDGET (button));
388               break;
389 
390             case DEFAULT_AREA:
391               break;
392 
393             default:
394               break;
395           }
396       }
397 
398     return FALSE;
399 }
400 
401 static gboolean
scim_anthy_color_button_button_release(GtkWidget * widget,GdkEventButton * bevent)402 scim_anthy_color_button_button_release (GtkWidget      *widget,
403                                   GdkEventButton *bevent)
404 {
405     ScimAnthyColorButton *button = SCIM_ANTHY_COLOR_BUTTON (widget);
406 
407     if (bevent->button == 1) {
408         FgBgTarget target = scim_anthy_color_button_target (button,
409                                                       (gint) bevent->x, (gint) bevent->y);
410 
411         if (target == button->click_target) {
412             switch (target)
413               {
414               case FOREGROUND_AREA:
415                 break;
416 
417               case BACKGROUND_AREA:
418                 break;
419 
420               default:
421                 break;
422               }
423         }
424 
425         button->click_target = INVALID_AREA;
426     }
427 
428     return FALSE;
429 }
430 
431 
432 /*  public functions  */
433 
434 GtkWidget *
scim_anthy_color_button_new(void)435 scim_anthy_color_button_new (void)
436 {
437     return GTK_WIDGET(g_object_new (SCIM_ANTHY_TYPE_COLOR_BUTTON,
438                                     NULL));
439 }
440 
441 gboolean
scim_anthy_color_button_get_colors(ScimAnthyColorButton * button,String * fg_value,String * bg_value)442 scim_anthy_color_button_get_colors (ScimAnthyColorButton *button,
443                               String *fg_value,
444                               String *bg_value)
445 {
446     gchar fg_color_str[8], bg_color_str[8];
447 
448     g_snprintf (fg_color_str, G_N_ELEMENTS (fg_color_str),
449                 "#%02X%02X%02X",
450                 ((button->fg_color.red)>>8),
451                 ((button->fg_color.green)>>8),
452                 ((button->fg_color.blue)>>8));
453     g_snprintf (bg_color_str, G_N_ELEMENTS (bg_color_str),
454                 "#%02X%02X%02X",
455                 ((button->bg_color.red)>>8),
456                 ((button->bg_color.green)>>8),
457                 ((button->bg_color.blue)>>8));
458     *fg_value = String (fg_color_str);
459     *bg_value = String (bg_color_str);
460 
461     return TRUE;
462 }
463 
464 gboolean
scim_anthy_color_button_set_colors(ScimAnthyColorButton * button,const String & fg_value,const String & bg_value)465 scim_anthy_color_button_set_colors (ScimAnthyColorButton *button,
466 				    const String &fg_value,
467 				    const String &bg_value)
468 {
469     GdkColor fg_color, bg_color;
470     gdk_color_parse (fg_value.c_str (), &fg_color);
471     gdk_color_parse (bg_value.c_str (), &bg_color);
472     button->fg_color.red   = fg_color.red;
473     button->fg_color.green = fg_color.green;
474     button->fg_color.blue  = fg_color.blue;
475 
476     button->bg_color.red   = bg_color.red;
477     button->bg_color.green = bg_color.green;
478     button->bg_color.blue  = bg_color.blue;
479 
480     return TRUE;
481 }
482 
483 /*
484 vi:ts=4:nowrap:ai:expandtab
485 */
486