1 /**
2  * Copyright (C) 2012 hejian <hejian.he@gmail.com>
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 3 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, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <libgimp/gimp.h>
19 #include <libgimp/gimpui.h>
20 
21 #define PLUG_IN_PROC   "plug-in-text-font"
22 #define PLUG_IN_BINARY "text-font"
23 #define PLUG_IN_ROLE   "gimp-text-font"
24 
25 #define PREVIEW_SIZE  480
26 #define THUMBNAIL_SIZE  80
27 
28 #ifndef MIN
29 #define MIN(a, b) ((a) < (b) ? (a) : (b))
30 #endif
31 
32 typedef struct
33 {
34   gchar* font;
35 } TextFontValues;
36 
37 static void     query    (void);
38 static void     run      (const gchar      *name,
39                           gint              nparams,
40                           const GimpParam  *param,
41                           gint             *nreturn_vals,
42                           GimpParam       **return_vals);
43 
44 static void     text_font (GimpDrawable *drawable);
45 
46 static gboolean text_font_dialog (gint32        image_ID,
47                                   GimpDrawable *drawable);
48 
49 static gboolean select_font (GtkWidget      *event_box,
50                              GdkEventButton *event,
51                              gchar          *font);
52 
53 const GimpPlugInInfo PLUG_IN_INFO =
54 {
55   NULL,  /* init_proc  */
56   NULL,  /* quit_proc  */
57   query, /* query_proc */
58   run,   /* run_proc   */
59 };
60 
61 static TextFontValues tfvals =
62 {
63   0,  /* font */
64 };
65 
66 static gint32     image_ID         = 0;
67 static gint       width;
68 static gint       height;
69 
70 static GtkWidget *preview          = NULL;
71 static gint32     preview_image    = 0;
72 
MAIN()73 MAIN ()
74 
75 static void
76 query (void)
77 {
78   static const GimpParamDef args[] =
79   {
80     { GIMP_PDB_INT32,    "run-mode",   "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
81     { GIMP_PDB_IMAGE,    "image",      "Input image" },
82     { GIMP_PDB_DRAWABLE, "drawable",   "Input drawable" },
83   };
84 
85   gimp_install_procedure (PLUG_IN_PROC,
86                           "Easy text font select.",
87                           "Easy text font select.",
88                           "Hejian <hejian.he@gmail.com>",
89                           "Hejian <hejian.he@gmail.com>",
90                           "2012",
91                           "_Text font select...",
92                           "RGB*, GRAY*",
93                           GIMP_PLUGIN,
94                           G_N_ELEMENTS (args), 0,
95                           args, NULL);
96 
97   gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Tools/Beautify");
98 }
99 
100 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)101 run (const gchar      *name,
102      gint              nparams,
103      const GimpParam  *param,
104      gint             *nreturn_vals,
105      GimpParam       **return_vals)
106 {
107   static GimpParam   values[2];
108   GimpDrawable      *drawable;
109   GimpRunMode        run_mode;
110   GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
111 
112   run_mode = param[0].data.d_int32;
113 
114   *nreturn_vals = 1;
115   *return_vals  = values;
116 
117   values[0].type          = GIMP_PDB_STATUS;
118   values[0].data.d_status = status;
119 
120   image_ID = param[1].data.d_image;
121   drawable = gimp_drawable_get (param[2].data.d_drawable);
122 
123   if (!gimp_item_is_text_layer (drawable->drawable_id)) {
124     status = GIMP_PDB_EXECUTION_ERROR;
125     *nreturn_vals = 2;
126     values[0].data.d_status = status;
127     values[1].type = GIMP_PDB_STRING;
128     values[1].data.d_string = ("This plugin only can process text layer.");
129     return;
130   }
131 
132   width = gimp_image_width (image_ID);
133   height = gimp_image_height (image_ID);
134 
135   switch (run_mode)
136   {
137     case GIMP_RUN_INTERACTIVE:
138       if (! text_font_dialog (image_ID, drawable))
139         return;
140       break;
141 
142     case GIMP_RUN_NONINTERACTIVE:
143       break;
144 
145     case GIMP_RUN_WITH_LAST_VALS:
146       break;
147 
148     default:
149       break;
150   }
151 
152   if ((status == GIMP_PDB_SUCCESS) &&
153       gimp_item_is_text_layer(drawable->drawable_id) &&
154       (gimp_drawable_is_rgb(drawable->drawable_id) ||
155        gimp_drawable_is_gray(drawable->drawable_id)))
156     {
157       /* Run! */
158       gimp_image_undo_group_start (image_ID);
159       text_font (drawable);
160       gimp_image_undo_group_end (image_ID);
161 
162       /* If run mode is interactive, flush displays */
163       if (run_mode != GIMP_RUN_NONINTERACTIVE)
164         gimp_displays_flush ();
165 
166       /* Store data */
167       if (run_mode == GIMP_RUN_INTERACTIVE)
168         gimp_set_data (PLUG_IN_PROC, &tfvals, sizeof (TextFontValues));
169 
170     }
171 
172   gimp_drawable_detach (drawable);
173 }
174 
175 static void
text_font(GimpDrawable * drawable)176 text_font (GimpDrawable *drawable)
177 {
178   if (tfvals.font != 0) {
179     gimp_text_layer_set_font (drawable->drawable_id, tfvals.font);
180   }
181 }
182 
183 static void
preview_update(GtkWidget * preview)184 preview_update (GtkWidget *preview)
185 {
186   gint preview_size = PREVIEW_SIZE;
187   gint max_size = height;
188   if (height < width)
189     max_size = width;
190   if (preview_size > max_size)
191     preview_size = max_size;
192   GdkPixbuf *pixbuf = gimp_image_get_thumbnail (preview_image, preview_size, preview_size, GIMP_PIXBUF_SMALL_CHECKS);
193   gtk_image_set_from_pixbuf (GTK_IMAGE(preview), pixbuf);
194 }
195 
196 static gboolean
text_font_dialog(gint32 image_ID,GimpDrawable * drawable)197 text_font_dialog (gint32        image_ID,
198                   GimpDrawable *drawable)
199 {
200   GtkWidget *dialog;
201   GtkWidget *main_hbox;
202   GtkWidget *left_vbox;
203   GtkWidget *middle_vbox;
204   GtkWidget *right_vbox;
205   GtkWidget *label;
206 
207   gimp_ui_init (PLUG_IN_BINARY, FALSE);
208 
209   dialog = gimp_dialog_new ("Text font select", PLUG_IN_ROLE,
210                             NULL, 0,
211                             gimp_standard_help_func, PLUG_IN_PROC,
212 
213                             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
214                             GTK_STOCK_OK,     GTK_RESPONSE_OK,
215 
216                             NULL);
217 
218   gimp_window_set_transient (GTK_WINDOW (dialog));
219 
220   gtk_widget_show (dialog);
221 
222   main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
223   gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 12);
224   gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
225                       main_hbox, TRUE, TRUE, 0);
226   gtk_widget_show (main_hbox);
227 
228   left_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
229   gtk_container_set_border_width (GTK_CONTAINER (left_vbox), 12);
230   gtk_box_pack_start (GTK_BOX (main_hbox), left_vbox, TRUE, TRUE, 0);
231   gtk_widget_show (left_vbox);
232 
233   middle_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
234   gtk_container_set_border_width (GTK_CONTAINER (middle_vbox), 12);
235   gtk_box_pack_start (GTK_BOX (main_hbox), middle_vbox, TRUE, TRUE, 0);
236   gtk_widget_show (middle_vbox);
237 
238   right_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
239   gtk_container_set_border_width (GTK_CONTAINER (right_vbox), 12);
240   gtk_box_pack_start (GTK_BOX (main_hbox), right_vbox, TRUE, TRUE, 0);
241   gtk_widget_show (right_vbox);
242 
243   /* preview */
244   label = gtk_label_new ("Preview");
245   gtk_box_pack_start (GTK_BOX (middle_vbox), label, FALSE, FALSE, 0);
246   gtk_widget_show (label);
247 
248   preview_image = gimp_image_duplicate (image_ID);
249 
250   preview = gtk_image_new();
251   preview_update (preview);
252 
253   gtk_box_pack_start (GTK_BOX (middle_vbox), preview, TRUE, TRUE, 0);
254   gtk_widget_show (preview);
255 
256   /* fonts */
257   label = gtk_label_new ("Select font");
258   gtk_box_pack_start (GTK_BOX (right_vbox), label, FALSE, FALSE, 0);
259   gtk_widget_show (label);
260 
261   GtkWidget *scrolled_win = gtk_scrolled_window_new (NULL, NULL);
262   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
263                                   GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
264   gtk_box_pack_start (GTK_BOX (right_vbox), scrolled_win, TRUE, TRUE, 0);
265   gtk_widget_show (scrolled_win);
266 
267   gint rows = 5;
268   gint cols = 3;
269   GtkWidget *table = gtk_table_new (rows, cols, FALSE);
270   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
271   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
272   //gtk_container_add (GTK_CONTAINER (scrolled_win), table);
273   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_win), table);
274   gtk_widget_show (table);
275 
276   gint num_fonts;
277   gchar **fonts = gimp_fonts_get_list (NULL, &num_fonts);
278 
279   gint32 text_image = gimp_image_duplicate (image_ID);
280 
281   gint offset_x, offset_y;
282   gimp_drawable_offsets (drawable->drawable_id, &offset_x, &offset_y);
283   gint text_width = gimp_drawable_width(drawable->drawable_id);
284   gint text_height = gimp_drawable_height(drawable->drawable_id);
285   text_width += 20;
286   text_height += 20;
287   offset_x -= 10;
288   offset_y -= 10;
289   /*if (offset_x < 0)
290     offset_x = 0;
291   if (offset_y < 0)
292     offset_y = 0;
293   if (offset_x + text_width > width)
294     text_width = width - offset_x;
295   if (offset_y + text_height > height)
296     text_height = height - offset_y;*/
297   gimp_image_crop (text_image, text_width, text_height, offset_x, offset_y);
298   gint thumb_width = MIN (text_width, 192);
299   gint thumb_height = MIN (text_height, 48);
300   gint32 text_layer = gimp_image_get_active_layer (text_image);
301 
302   gint row = 1;
303   gint col = 1;
304 
305   int i;
306   for (i = 0; i < num_fonts; i++) {
307     gimp_text_layer_set_font (text_layer, fonts[i]);
308     GdkPixbuf *pixbuf = gimp_image_get_thumbnail (text_image, thumb_width, thumb_height, GIMP_PIXBUF_SMALL_CHECKS);
309 
310     GtkWidget *image = gtk_image_new_from_pixbuf (pixbuf);
311     GtkWidget *event_box = gtk_event_box_new ();
312     gtk_container_add (GTK_CONTAINER (event_box), image);
313     gtk_widget_show (image);
314     gtk_table_attach_defaults (GTK_TABLE (table), event_box, col - 1, col, row - 1, row);
315     gtk_widget_show (event_box);
316 
317     col++;
318     if (col > cols)
319     {
320       row++;
321       col = 1;
322     }
323 
324     g_signal_connect (event_box, "button_press_event", G_CALLBACK (select_font), fonts[i]);
325   }
326 
327   gboolean run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
328 
329   gtk_widget_destroy (dialog);
330 
331   return run;
332 }
333 
334 static gboolean
select_font(GtkWidget * event_box,GdkEventButton * event,gchar * font)335 select_font (GtkWidget *event_box, GdkEventButton *event, gchar* font)
336 {
337   tfvals.font = font;
338   gint32 text_layer = gimp_image_get_active_layer (preview_image);
339   gimp_text_layer_set_font (text_layer, tfvals.font);
340   preview_update (preview);
341 }
342