]> git.sur5r.net Git - glabels/blob - glabels2/src/object-editor.c
2007-05-09 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / src / object-editor.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
3 /**
4  *  (GLABELS) Label and Business Card Creation program for GNOME
5  *
6  *  object-editor.c:  object properties editor module
7  *
8  *  Copyright (C) 2003  Jim Evins <evins@snaught.com>.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23  */
24 #include <config.h>
25
26 #include "object-editor.h"
27
28 #include <glib/gi18n.h>
29 #include <glade/glade-xml.h>
30 #include <gtk/gtklabel.h>
31 #include <gtk/gtknotebook.h>
32 #include <gtk/gtkcombobox.h>
33 #include <gtk/gtktogglebutton.h>
34
35 #include <math.h>
36
37 #include "prefs.h"
38 #include "mygal/widget-color-combo.h"
39 #include "color.h"
40 #include "wdgt-chain-button.h"
41 #include "marshal.h"
42 #include "util.h"
43
44 #include "object-editor-private.h"
45
46 #include "debug.h"
47
48 /*===========================================*/
49 /* Private macros                            */
50 /*===========================================*/
51
52 /*===========================================*/
53 /* Private data types                        */
54 /*===========================================*/
55
56 typedef void (*ChangedSignal) (GObject * object, gpointer data);
57
58 /*===========================================*/
59 /* Private globals                           */
60 /*===========================================*/
61
62 gint gl_object_editor_signals[LAST_SIGNAL] = { 0 };
63
64 /*===========================================*/
65 /* Local function prototypes                 */
66 /*===========================================*/
67
68 static void gl_object_editor_finalize           (GObject              *object);
69
70 static void gl_object_notebook_construct_valist (glObjectEditor       *editor,
71                                                  glObjectEditorOption  first_option,
72                                                  va_list               args);
73
74 static void prefs_changed_cb                    (glObjectEditor       *editor);
75
76 \f
77 /*****************************************************************************/
78 /* Boilerplate object stuff.                                                 */
79 /*****************************************************************************/
80 G_DEFINE_TYPE (glObjectEditor, gl_object_editor, GTK_TYPE_VBOX);
81
82 static void
83 gl_object_editor_class_init (glObjectEditorClass *class)
84 {
85         GObjectClass *object_class = G_OBJECT_CLASS (class);
86
87         gl_debug (DEBUG_EDITOR, "START");
88         
89         gl_object_editor_parent_class = g_type_class_peek_parent (class);
90
91         object_class->finalize = gl_object_editor_finalize;     
92
93         gl_object_editor_signals[CHANGED] =
94             g_signal_new ("changed",
95                           G_OBJECT_CLASS_TYPE(object_class),
96                           G_SIGNAL_RUN_LAST,
97                           G_STRUCT_OFFSET (glObjectEditorClass, changed),
98                           NULL, NULL,
99                           gl_marshal_VOID__VOID,
100                           G_TYPE_NONE, 0);
101
102         gl_object_editor_signals[SIZE_CHANGED] =
103             g_signal_new ("size_changed",
104                           G_OBJECT_CLASS_TYPE(object_class),
105                           G_SIGNAL_RUN_LAST,
106                           G_STRUCT_OFFSET (glObjectEditorClass, size_changed),
107                           NULL, NULL,
108                           gl_marshal_VOID__VOID,
109                           G_TYPE_NONE, 0);
110
111         gl_debug (DEBUG_EDITOR, "END");
112 }
113
114 static void
115 gl_object_editor_init (glObjectEditor *editor)
116 {
117         gl_debug (DEBUG_EDITOR, "START");
118         
119         editor->priv = g_new0 (glObjectEditorPrivate, 1);
120
121         editor->priv->gui = glade_xml_new (GLABELS_GLADE_DIR "object-editor.glade",
122                                            "editor_vbox",
123                                            NULL);
124
125         if (!editor->priv->gui) {
126                 g_critical ("Could not open object-editor.glade. gLabels may not be installed correctly!");
127                 return;
128         }
129
130         editor->priv->editor_vbox = glade_xml_get_widget (editor->priv->gui,
131                                                           "editor_vbox");
132         gtk_box_pack_start (GTK_BOX(editor),
133                             editor->priv->editor_vbox,
134                             FALSE, FALSE, 0);
135
136         editor->priv->title_image = glade_xml_get_widget (editor->priv->gui,
137                                                           "title_image");
138         editor->priv->title_label = glade_xml_get_widget (editor->priv->gui,
139                                                           "title_label");
140         editor->priv->notebook    = glade_xml_get_widget (editor->priv->gui,
141                                                           "notebook");
142
143         gtk_widget_show_all (GTK_WIDGET(editor));
144
145         /* Hide all notebook pages to start with. */
146         gtk_widget_hide_all (editor->priv->notebook);
147         gtk_widget_set_no_show_all (editor->priv->notebook, TRUE);
148
149         gl_debug (DEBUG_EDITOR, "END");
150 }
151
152 static void 
153 gl_object_editor_finalize (GObject *object)
154 {
155         glObjectEditor* editor = GL_OBJECT_EDITOR (object);;
156         
157         gl_debug (DEBUG_EDITOR, "START");
158         
159         g_return_if_fail (object != NULL);
160         g_return_if_fail (GL_IS_OBJECT_EDITOR (editor));
161         g_return_if_fail (editor->priv != NULL);
162
163         g_free (editor->priv);
164
165         g_signal_handlers_disconnect_by_func (G_OBJECT(gl_prefs),
166                                               prefs_changed_cb, editor);
167
168         G_OBJECT_CLASS (gl_object_editor_parent_class)->finalize (object);
169
170         gl_debug (DEBUG_EDITOR, "END");
171 }
172
173 /*****************************************************************************/
174 /* NEW object editor.                                                      */
175 /*****************************************************************************/
176 GtkWidget*
177 gl_object_editor_new (gchar                *image,
178                       gchar                *label,
179                       glObjectEditorOption  first_option, ...)
180 {
181         glObjectEditor *editor;
182         va_list         args;
183
184         gl_debug (DEBUG_EDITOR, "START");
185
186         editor = GL_OBJECT_EDITOR (g_object_new (GL_TYPE_OBJECT_EDITOR, NULL));
187
188         if (image) {
189                 gtk_image_set_from_stock (GTK_IMAGE(editor->priv->title_image),
190                                           image,
191                                           GTK_ICON_SIZE_LARGE_TOOLBAR);
192         }
193
194         if (label) {
195                 gchar *s;
196
197                 s = g_strdup_printf ("<span weight=\"bold\">%s</span>",
198                                      label);
199                 gtk_label_set_text (GTK_LABEL(editor->priv->title_label), s);
200                 g_free (s);
201
202                 gtk_label_set_use_markup (GTK_LABEL(editor->priv->title_label), TRUE);
203                                           
204         }
205
206         gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK(editor->priv->notebook), TRUE);
207
208         va_start (args, first_option);
209         gl_object_notebook_construct_valist (editor, first_option, args);
210         va_end (args);
211
212         if (editor->priv->gui) {
213                 g_object_unref (G_OBJECT (editor->priv->gui));
214         }
215
216         gl_debug (DEBUG_EDITOR, "END");
217
218         return GTK_WIDGET(editor);
219 }
220
221 /*--------------------------------------------------------------------------*/
222 /* PRIVATE.  Construct notebook.                                            */
223 /*--------------------------------------------------------------------------*/
224 static void
225 gl_object_notebook_construct_valist (glObjectEditor       *editor,
226                                      glObjectEditorOption  first_option,
227                                      va_list               args)
228 {
229         glObjectEditorOption option;
230         gint pages = 0;
231
232         gl_debug (DEBUG_EDITOR, "START");
233
234         option = first_option;
235
236         for ( option=first_option; option; option=va_arg (args, glObjectEditorOption) ) {
237
238                 switch (option) {
239
240                 case GL_OBJECT_EDITOR_EMPTY:
241                         gtk_widget_set_sensitive (editor->priv->title_image, FALSE);
242                         gtk_widget_set_sensitive (editor->priv->title_label, FALSE);
243                         break;
244
245                 case GL_OBJECT_EDITOR_POSITION_PAGE:
246                         gl_object_editor_prepare_position_page (editor);
247                         pages++;
248                         break;
249
250                 case GL_OBJECT_EDITOR_SIZE_PAGE:
251                 case GL_OBJECT_EDITOR_SIZE_IMAGE_PAGE:
252                         gl_object_editor_prepare_size_page (editor, option);
253                         pages++;
254                         break;
255
256                 case GL_OBJECT_EDITOR_SIZE_LINE_PAGE:
257                         gl_object_editor_prepare_lsize_page (editor);
258                         pages++;
259                         break;
260
261                 case GL_OBJECT_EDITOR_FILL_PAGE:
262                         gl_object_editor_prepare_fill_page (editor);
263                         pages++;
264                         break;
265
266                 case GL_OBJECT_EDITOR_LINE_PAGE:
267                         gl_object_editor_prepare_line_page (editor);
268                         pages++;
269                         break;
270
271                 case GL_OBJECT_EDITOR_IMAGE_PAGE:
272                         gl_object_editor_prepare_image_page (editor);
273                         pages++;
274                         break;
275
276                 case GL_OBJECT_EDITOR_TEXT_PAGE:
277                         gl_object_editor_prepare_text_page (editor);
278                         pages++;
279                         break;
280
281                 case GL_OBJECT_EDITOR_EDIT_PAGE:
282                         gl_object_editor_prepare_edit_page (editor);
283                         pages++;
284                         break;
285
286                 case GL_OBJECT_EDITOR_BC_PAGE:
287                         gl_object_editor_prepare_bc_page (editor);
288                         pages++;
289                         break;
290
291                 case GL_OBJECT_EDITOR_DATA_PAGE:
292                         gl_object_editor_prepare_data_page (editor);
293                         pages++;
294                         break;
295
296                 case GL_OBJECT_EDITOR_SHADOW_PAGE:
297                         gl_object_editor_prepare_shadow_page (editor);
298                         pages++;
299                         break;
300
301                 default:
302                         g_message ("option = %d", option);
303                         g_assert_not_reached ();
304                 }
305                 
306         }
307         if (pages) {
308                 gtk_widget_show (editor->priv->notebook);
309         }
310
311         g_signal_connect_swapped (G_OBJECT (gl_prefs), "changed",
312                                   G_CALLBACK (prefs_changed_cb),
313                                   editor);
314
315         gl_debug (DEBUG_EDITOR, "END");
316 }
317
318 /*--------------------------------------------------------------------------*/
319 /* PRIVATE. Widget changed callback.  Emit our "changed" signal.            */
320 /*--------------------------------------------------------------------------*/
321 void
322 gl_object_editor_changed_cb (glObjectEditor *editor)
323 {
324         if (editor->priv->stop_signals) return;
325
326         gl_debug (DEBUG_EDITOR, "START");
327
328         /* Emit our "changed" signal */
329         g_signal_emit (G_OBJECT (editor), gl_object_editor_signals[CHANGED], 0);
330
331         gl_debug (DEBUG_EDITOR, "END");
332 }
333
334 /*--------------------------------------------------------------------------*/
335 /* PRIVATE. Widget size changed callback.  Emit our "size-changed" signal.  */
336 /*--------------------------------------------------------------------------*/
337 void
338 gl_object_editor_size_changed_cb (glObjectEditor *editor)
339 {
340         if (editor->priv->stop_signals) return;
341
342         gl_debug (DEBUG_EDITOR, "START");
343
344         /* Emit our "size_changed" signal */
345         g_signal_emit (G_OBJECT (editor), gl_object_editor_signals[SIZE_CHANGED], 0);
346
347         gl_debug (DEBUG_EDITOR, "END");
348 }
349
350 /*****************************************************************************/
351 /* Set possible key names from merge object.                                 */
352 /*****************************************************************************/
353 void
354 gl_object_editor_set_key_names (glObjectEditor      *editor,
355                                 glMerge             *merge)
356 {
357         GList     *keys;
358         GtkWidget *combo;
359         gboolean   fixed_flag;
360         gboolean   state;
361  
362         gl_debug (DEBUG_EDITOR, "START");
363
364         if (editor->priv->edit_key_label) {
365                 gtk_widget_set_sensitive (editor->priv->edit_key_label, merge != NULL);
366         }
367  
368         if (editor->priv->edit_key_combo) {
369                 gtk_widget_set_sensitive (editor->priv->edit_key_combo, merge != NULL);
370         }
371  
372         if (editor->priv->text_auto_shrink_check) {
373                 gtk_widget_set_sensitive (editor->priv->text_auto_shrink_check,
374                                           merge != NULL);
375         }
376  
377         if (editor->priv->text_page_vbox) {
378                 gtk_widget_set_sensitive (editor->priv->text_color_key_radio, merge != NULL);
379                 if (merge == NULL) {
380                         gtk_toggle_button_set_active (
381                                 GTK_TOGGLE_BUTTON(editor->priv->text_color_radio), TRUE);
382                         gtk_widget_set_sensitive (editor->priv->text_color_combo, TRUE);
383                         gtk_widget_set_sensitive (editor->priv->text_color_key_combo, FALSE);
384                 } else {
385                         state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->priv->text_color_key_radio));
386                         gtk_widget_set_sensitive (editor->priv->text_color_combo, !state);
387                         gtk_widget_set_sensitive (editor->priv->text_color_key_combo, state);
388                                                   
389                 }
390         }
391
392         if (editor->priv->edit_insert_field_button) {
393                 gtk_widget_set_sensitive (editor->priv->edit_insert_field_button,
394                                           merge != NULL);
395         }
396
397         if (editor->priv->img_key_combo) {
398                 gtk_widget_set_sensitive (editor->priv->img_key_combo, merge != NULL);
399         }
400  
401         if (editor->priv->img_key_radio) {
402                 gtk_widget_set_sensitive (editor->priv->img_key_radio, merge != NULL);
403                 if (merge == NULL) {
404                         gtk_toggle_button_set_active (
405                                 GTK_TOGGLE_BUTTON(editor->priv->img_file_radio), TRUE);
406                 }
407         }
408
409         if (editor->priv->data_key_combo) {
410                 gtk_widget_set_sensitive (editor->priv->data_key_combo, merge != NULL);
411         }
412  
413         if (editor->priv->data_key_radio) {
414                 gtk_widget_set_sensitive (editor->priv->data_key_radio, merge != NULL);
415                 if (merge == NULL) {
416                         gtk_toggle_button_set_active (
417                                 GTK_TOGGLE_BUTTON(editor->priv->data_literal_radio), TRUE);
418                 }
419         }
420         
421         fixed_flag = editor->priv->data_format_fixed_flag;
422         if (editor->priv->data_format_label) {
423                 gtk_widget_set_sensitive (editor->priv->data_format_label,
424                                           (merge != NULL));
425         }
426         if (editor->priv->data_ex_label) {
427                 gtk_widget_set_sensitive (editor->priv->data_ex_label,
428                                           (merge != NULL));
429         }
430         if (editor->priv->data_digits_label) {
431                 gtk_widget_set_sensitive (editor->priv->data_digits_label,
432                                           (merge != NULL) && !fixed_flag);
433         }
434         if (editor->priv->data_digits_spin) {
435                 gtk_widget_set_sensitive (editor->priv->data_digits_spin,
436                                           (merge != NULL) && !fixed_flag);
437         }
438
439         if (editor->priv->fill_page_vbox) {
440                 gtk_widget_set_sensitive (editor->priv->fill_key_radio, merge != NULL);
441                 if (merge == NULL) {
442                         gtk_toggle_button_set_active (
443                                 GTK_TOGGLE_BUTTON(editor->priv->fill_color_radio), TRUE);
444                         gtk_widget_set_sensitive (editor->priv->fill_color_combo, TRUE);
445                         gtk_widget_set_sensitive (editor->priv->fill_key_combo, FALSE);
446                 } else {
447                         state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->priv->fill_key_radio));
448                         gtk_widget_set_sensitive (editor->priv->fill_color_combo, !state);
449                         gtk_widget_set_sensitive (editor->priv->fill_key_combo, state);
450                                                   
451                 }
452         }
453
454         if (editor->priv->line_page_vbox) {
455                 gtk_widget_set_sensitive (editor->priv->line_key_radio, merge != NULL);
456                 if (merge == NULL) {
457                         gtk_toggle_button_set_active (
458                                 GTK_TOGGLE_BUTTON(editor->priv->line_color_radio), TRUE);
459                         gtk_widget_set_sensitive (editor->priv->line_color_combo, TRUE);
460                         gtk_widget_set_sensitive (editor->priv->line_key_combo, FALSE);
461                 } else {
462                         state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->priv->line_key_radio));
463                         gtk_widget_set_sensitive (editor->priv->line_color_combo, !state);
464                         gtk_widget_set_sensitive (editor->priv->line_key_combo, state);
465                                                   
466                 }
467         }
468
469         if (editor->priv->bc_page_vbox) {
470                 gtk_widget_set_sensitive (editor->priv->bc_key_radio, merge != NULL);
471                 if (merge == NULL) {
472                         gtk_toggle_button_set_active (
473                                 GTK_TOGGLE_BUTTON(editor->priv->bc_color_radio), TRUE);
474                         gtk_widget_set_sensitive (editor->priv->bc_color_combo, TRUE);
475                         gtk_widget_set_sensitive (editor->priv->bc_key_combo, FALSE);
476                 } else {
477                         state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->priv->bc_key_radio));
478                         gtk_widget_set_sensitive (editor->priv->bc_color_combo, !state);
479                         gtk_widget_set_sensitive (editor->priv->bc_key_combo, state);
480                                                   
481                 }
482         }
483
484         if (editor->priv->shadow_page_vbox) {
485                 gtk_widget_set_sensitive (editor->priv->shadow_key_radio, merge != NULL);
486                 if (merge == NULL) {
487                         gtk_toggle_button_set_active (
488                                 GTK_TOGGLE_BUTTON(editor->priv->shadow_color_radio), TRUE);
489                         gtk_widget_set_sensitive (editor->priv->shadow_color_combo, TRUE);
490                         gtk_widget_set_sensitive (editor->priv->shadow_key_combo, FALSE);
491                 } else {
492                         state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->priv->shadow_key_radio));
493                         gtk_widget_set_sensitive (editor->priv->shadow_color_combo, !state);
494                         gtk_widget_set_sensitive (editor->priv->shadow_key_combo, state);
495                                                   
496                 }
497         }
498
499         keys = gl_merge_get_key_list (merge);
500         if ( keys == NULL ) {
501                 keys = g_list_append (keys, g_strdup (""));
502         }
503
504         combo = editor->priv->img_key_combo;
505         if (combo) {
506                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
507         }
508
509         combo = editor->priv->edit_key_combo;
510         if (combo) {
511                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
512         }
513
514         combo = editor->priv->data_key_combo;
515         if (combo) {
516                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
517         }
518                 
519         combo = editor->priv->fill_key_combo;
520         if (combo) {
521                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
522         }
523
524         combo = editor->priv->text_color_key_combo;
525         if (combo) {
526                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
527         }
528
529         combo = editor->priv->line_key_combo;
530         if (combo) {
531                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
532         }
533                 
534         combo = editor->priv->bc_key_combo;
535         if (combo) {
536                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
537         }
538                 
539         combo = editor->priv->shadow_key_combo;
540         if (combo) {
541                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
542         }
543
544         gl_merge_free_key_list (&keys);
545  
546         gl_debug (DEBUG_EDITOR, "END");
547 }
548
549 /*****************************************************************************/
550 /* Construct color combo "Custom widget".                                    */
551 /*****************************************************************************/
552 GtkWidget *
553 gl_object_editor_construct_color_combo (gchar *name,
554                                         gchar *string1,
555                                         gchar *string2,
556                                         gint   int1,
557                                         gint   int2)
558 {
559         GtkWidget  *color_combo;
560         ColorGroup *cg;
561         gchar      *cg_name;
562         guint       color;
563         GdkColor   *gdk_color;
564         gchar      *no_color;
565
566         switch (int1) {
567
568         case 3:
569                 cg_name  = "shadow_color_group";
570                 color    = GL_COLOR_SHADOW_DEFAULT;
571                 no_color = _("Default");
572                 break;
573
574         case 2:
575                 cg_name  = "text_color_group";
576                 color    = gl_prefs->default_text_color;
577                 no_color = _("Default");
578                 break;
579
580         case 1:
581                 cg_name  = "line_color_group";
582                 color    = gl_prefs->default_line_color;
583                 no_color = _("No line");
584                 break;
585
586         case 0:
587         default:
588                 cg_name  = "fill_color_group";
589                 color    = gl_prefs->default_fill_color;
590                 no_color = _("No fill");
591                 break;
592
593         }
594
595         cg = color_group_fetch (cg_name, NULL);
596         gdk_color = gl_color_to_gdk_color (color);
597         color_combo = color_combo_new (NULL, no_color, gdk_color, cg);
598         g_free (gdk_color);
599
600         color_combo_box_set_preview_relief (COLOR_COMBO(color_combo), GTK_RELIEF_NORMAL);
601
602         return color_combo;
603 }
604
605 /*****************************************************************************/
606 /* Construct chain button "Custom widget".                                   */
607 /*****************************************************************************/
608 GtkWidget *
609 gl_object_editor_construct_chain_button (gchar *name,
610                                          gchar *string1,
611                                          gchar *string2,
612                                          gint   int1,
613                                          gint   int2)
614 {
615         GtkWidget  *chain_button;
616
617         chain_button = gl_wdgt_chain_button_new (GL_WDGT_CHAIN_RIGHT);
618         gl_wdgt_chain_button_set_active (GL_WDGT_CHAIN_BUTTON(chain_button), TRUE);
619
620         return chain_button;
621 }
622
623 /*--------------------------------------------------------------------------*/
624 /* PRIVATE. Prefs changed callback.  Update units related items.            */
625 /*--------------------------------------------------------------------------*/
626 static void
627 prefs_changed_cb (glObjectEditor *editor)
628 {
629
630         gl_debug (DEBUG_EDITOR, "START");
631
632         if (editor->priv->lsize_r_spin) {
633                 lsize_prefs_changed_cb (editor);
634         }
635                 
636         if (editor->priv->size_w_spin) {
637                 size_prefs_changed_cb (editor);
638         }
639                 
640         if (editor->priv->pos_x_spin) {
641                 position_prefs_changed_cb (editor);
642         }
643
644         if (editor->priv->shadow_x_spin) {
645                 shadow_prefs_changed_cb (editor);
646         }
647
648         gl_debug (DEBUG_EDITOR, "END");
649 }