]> git.sur5r.net Git - glabels/blob - glabels2/src/object-editor.c
f237e6422bb4ab2405ad34affd13e590ebeaa939
[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 <gtk/gtkbuilder.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 "color-combo.h"
39 #include "color.h"
40 #include "wdgt-chain-button.h"
41 #include "wdgt-merge-menu.h"
42 #include "marshal.h"
43 #include "util.h"
44
45 #include "object-editor-private.h"
46
47 #include "debug.h"
48
49 /*===========================================*/
50 /* Private macros                            */
51 /*===========================================*/
52
53 /*===========================================*/
54 /* Private data types                        */
55 /*===========================================*/
56
57 typedef void (*ChangedSignal) (GObject * object, gpointer data);
58
59 /*===========================================*/
60 /* Private globals                           */
61 /*===========================================*/
62
63 gint gl_object_editor_signals[LAST_SIGNAL] = { 0 };
64
65 /*===========================================*/
66 /* Local function prototypes                 */
67 /*===========================================*/
68
69 static void gl_object_editor_finalize           (GObject              *object);
70
71 static void gl_object_notebook_construct_valist (glObjectEditor       *editor,
72                                                  glLabel              *label,
73                                                  glObjectEditorOption  first_option,
74                                                  va_list               args);
75
76 static void prefs_changed_cb                    (glObjectEditor       *editor);
77
78 static void label_changed_cb                    (glLabel              *label,
79                                                  glObjectEditor       *editor);
80
81 \f
82 /*****************************************************************************/
83 /* Boilerplate object stuff.                                                 */
84 /*****************************************************************************/
85 G_DEFINE_TYPE (glObjectEditor, gl_object_editor, GTK_TYPE_VBOX);
86
87 static void
88 gl_object_editor_class_init (glObjectEditorClass *class)
89 {
90         GObjectClass *object_class = G_OBJECT_CLASS (class);
91
92         gl_debug (DEBUG_EDITOR, "START");
93         
94         gl_object_editor_parent_class = g_type_class_peek_parent (class);
95
96         object_class->finalize = gl_object_editor_finalize;     
97
98         gl_object_editor_signals[CHANGED] =
99             g_signal_new ("changed",
100                           G_OBJECT_CLASS_TYPE(object_class),
101                           G_SIGNAL_RUN_LAST,
102                           G_STRUCT_OFFSET (glObjectEditorClass, changed),
103                           NULL, NULL,
104                           gl_marshal_VOID__VOID,
105                           G_TYPE_NONE, 0);
106
107         gl_object_editor_signals[SIZE_CHANGED] =
108             g_signal_new ("size_changed",
109                           G_OBJECT_CLASS_TYPE(object_class),
110                           G_SIGNAL_RUN_LAST,
111                           G_STRUCT_OFFSET (glObjectEditorClass, size_changed),
112                           NULL, NULL,
113                           gl_marshal_VOID__VOID,
114                           G_TYPE_NONE, 0);
115
116         gl_debug (DEBUG_EDITOR, "END");
117 }
118
119 static void
120 gl_object_editor_init (glObjectEditor *editor)
121 {
122         GError *error = NULL;
123
124         gl_debug (DEBUG_EDITOR, "START");
125         
126         editor->priv = g_new0 (glObjectEditorPrivate, 1);
127
128         editor->priv->gui = gtk_builder_new ();
129
130         gtk_builder_add_from_file (editor->priv->gui,
131                                    GLABELS_BUILDER_DIR "object-editor.builder",
132                                    &error);
133         if (error) {
134                 g_critical ("%s\n\ngLabels may not be installed correctly!", error->message);
135                 g_error_free (error);
136                 return;
137         }
138
139         gl_util_get_builder_widgets (editor->priv->gui,
140                                      "editor_vbox", &editor->priv->editor_vbox,
141                                      "title_image", &editor->priv->title_image,
142                                      "title_label", &editor->priv->title_label,
143                                      "notebook",    &editor->priv->notebook,
144                                      NULL);
145
146         gtk_box_pack_start (GTK_BOX(editor),
147                             editor->priv->editor_vbox,
148                             FALSE, FALSE, 0);
149
150         gtk_widget_show_all (GTK_WIDGET(editor));
151
152         /* Hide all notebook pages to start with. */
153         gtk_widget_hide_all (editor->priv->notebook);
154         gtk_widget_set_no_show_all (editor->priv->notebook, TRUE);
155
156         gl_debug (DEBUG_EDITOR, "END");
157 }
158
159 static void 
160 gl_object_editor_finalize (GObject *object)
161 {
162         glObjectEditor* editor = GL_OBJECT_EDITOR (object);;
163         
164         gl_debug (DEBUG_EDITOR, "START");
165         
166         g_return_if_fail (object != NULL);
167         g_return_if_fail (GL_IS_OBJECT_EDITOR (editor));
168         g_return_if_fail (editor->priv != NULL);
169
170         g_signal_handlers_disconnect_by_func (G_OBJECT(gl_prefs),
171                                               prefs_changed_cb, editor);
172         g_signal_handlers_disconnect_by_func (G_OBJECT(editor->priv->label),
173                                               label_changed_cb, editor);
174
175         g_object_unref (editor->priv->gui);
176         g_free (editor->priv);
177
178         G_OBJECT_CLASS (gl_object_editor_parent_class)->finalize (object);
179
180         gl_debug (DEBUG_EDITOR, "END");
181 }
182
183 /*****************************************************************************/
184 /* NEW object editor.                                                      */
185 /*****************************************************************************/
186 GtkWidget*
187 gl_object_editor_new (gchar                *image,
188                       gchar                *title,
189                       glLabel              *label,
190                       glObjectEditorOption  first_option, ...)
191 {
192         glObjectEditor *editor;
193         va_list         args;
194
195         gl_debug (DEBUG_EDITOR, "START");
196
197         editor = GL_OBJECT_EDITOR (g_object_new (GL_TYPE_OBJECT_EDITOR, NULL));
198
199         if (image) {
200                 gtk_image_set_from_stock (GTK_IMAGE(editor->priv->title_image),
201                                           image,
202                                           GTK_ICON_SIZE_LARGE_TOOLBAR);
203         }
204
205         if (title) {
206                 gchar *s;
207
208                 s = g_strdup_printf ("<span weight=\"bold\">%s</span>",
209                                      title);
210                 gtk_label_set_text (GTK_LABEL(editor->priv->title_label), s);
211                 g_free (s);
212
213                 gtk_label_set_use_markup (GTK_LABEL(editor->priv->title_label), TRUE);
214                                           
215         }
216
217         gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK(editor->priv->notebook), TRUE);
218
219         va_start (args, first_option);
220         gl_object_notebook_construct_valist (editor, label, first_option, args);
221         va_end (args);
222
223         gl_debug (DEBUG_EDITOR, "END");
224
225         return GTK_WIDGET(editor);
226 }
227
228 /*--------------------------------------------------------------------------*/
229 /* PRIVATE.  Construct notebook.                                            */
230 /*--------------------------------------------------------------------------*/
231 static void
232 gl_object_notebook_construct_valist (glObjectEditor       *editor,
233                                      glLabel              *label,
234                                      glObjectEditorOption  first_option,
235                                      va_list               args)
236 {
237         glObjectEditorOption option;
238         gint pages = 0;
239
240         gl_debug (DEBUG_EDITOR, "START");
241
242         editor->priv->label = label;
243
244         option = first_option;
245
246         for ( option=first_option; option; option=va_arg (args, glObjectEditorOption) ) {
247
248                 switch (option) {
249
250                 case GL_OBJECT_EDITOR_EMPTY:
251                         gtk_widget_set_sensitive (editor->priv->title_image, FALSE);
252                         gtk_widget_set_sensitive (editor->priv->title_label, FALSE);
253                         break;
254
255                 case GL_OBJECT_EDITOR_POSITION_PAGE:
256                         gl_object_editor_prepare_position_page (editor);
257                         pages++;
258                         break;
259
260                 case GL_OBJECT_EDITOR_SIZE_PAGE:
261                 case GL_OBJECT_EDITOR_SIZE_IMAGE_PAGE:
262                         gl_object_editor_prepare_size_page (editor, option);
263                         pages++;
264                         break;
265
266                 case GL_OBJECT_EDITOR_SIZE_LINE_PAGE:
267                         gl_object_editor_prepare_lsize_page (editor);
268                         pages++;
269                         break;
270
271                 case GL_OBJECT_EDITOR_FILL_PAGE:
272                         gl_object_editor_prepare_fill_page (editor);
273                         pages++;
274                         break;
275
276                 case GL_OBJECT_EDITOR_LINE_PAGE:
277                         gl_object_editor_prepare_line_page (editor);
278                         pages++;
279                         break;
280
281                 case GL_OBJECT_EDITOR_IMAGE_PAGE:
282                         gl_object_editor_prepare_image_page (editor);
283                         pages++;
284                         break;
285
286                 case GL_OBJECT_EDITOR_TEXT_PAGE:
287                         gl_object_editor_prepare_text_page (editor);
288                         pages++;
289                         break;
290
291                 case GL_OBJECT_EDITOR_EDIT_PAGE:
292                         gl_object_editor_prepare_edit_page (editor);
293                         pages++;
294                         break;
295
296                 case GL_OBJECT_EDITOR_BC_PAGE:
297                         gl_object_editor_prepare_bc_page (editor);
298                         pages++;
299                         break;
300
301                 case GL_OBJECT_EDITOR_DATA_PAGE:
302                         gl_object_editor_prepare_data_page (editor);
303                         pages++;
304                         break;
305
306                 case GL_OBJECT_EDITOR_SHADOW_PAGE:
307                         gl_object_editor_prepare_shadow_page (editor);
308                         pages++;
309                         break;
310
311                 default:
312                         g_message ("option = %d", option);
313                         g_assert_not_reached ();
314                 }
315                 
316         }
317         if (pages) {
318                 gtk_widget_show (editor->priv->notebook);
319         }
320
321         g_signal_connect_swapped (G_OBJECT (gl_prefs), "changed",
322                                   G_CALLBACK (prefs_changed_cb),
323                                   editor);
324         if (label)
325         {
326                 label_changed_cb (label, editor);
327                 g_signal_connect (G_OBJECT (label), "size_changed",
328                                   G_CALLBACK (label_changed_cb),
329                                   editor);
330                 g_signal_connect (G_OBJECT (label), "merge_changed",
331                                   G_CALLBACK (label_changed_cb),
332                                   editor);
333         }
334
335         gl_debug (DEBUG_EDITOR, "END");
336 }
337
338 /*--------------------------------------------------------------------------*/
339 /* PRIVATE. Widget changed callback.  Emit our "changed" signal.            */
340 /*--------------------------------------------------------------------------*/
341 void
342 gl_object_editor_changed_cb (glObjectEditor *editor)
343 {
344         if (editor->priv->stop_signals) return;
345
346         gl_debug (DEBUG_EDITOR, "START");
347
348         /* Emit our "changed" signal */
349         g_signal_emit (G_OBJECT (editor), gl_object_editor_signals[CHANGED], 0);
350
351         gl_debug (DEBUG_EDITOR, "END");
352 }
353
354 /*--------------------------------------------------------------------------*/
355 /* PRIVATE. Widget size changed callback.  Emit our "size-changed" signal.  */
356 /*--------------------------------------------------------------------------*/
357 void
358 gl_object_editor_size_changed_cb (glObjectEditor *editor)
359 {
360         if (editor->priv->stop_signals) return;
361
362         gl_debug (DEBUG_EDITOR, "START");
363
364         /* Emit our "size_changed" signal */
365         g_signal_emit (G_OBJECT (editor), gl_object_editor_signals[SIZE_CHANGED], 0);
366
367         gl_debug (DEBUG_EDITOR, "END");
368 }
369
370 /*****************************************************************************/
371 /* Set possible key names from merge object.                                 */
372 /*****************************************************************************/
373 void
374 gl_object_editor_set_key_names (glObjectEditor      *editor,
375                                 glMerge             *merge)
376 {
377         GList     *keys;
378         GtkWidget *combo;
379         GtkWidget *menu;
380         gboolean   fixed_flag;
381         gboolean   state;
382  
383         gl_debug (DEBUG_EDITOR, "START");
384
385         if (editor->priv->text_auto_shrink_check) {
386                 gtk_widget_set_sensitive (editor->priv->text_auto_shrink_check,
387                                           merge != NULL);
388         }
389  
390         if (editor->priv->text_page_vbox) {
391                 gtk_widget_set_sensitive (editor->priv->text_color_key_radio, merge != NULL);
392                 if (merge == NULL) {
393                         gtk_toggle_button_set_active (
394                                 GTK_TOGGLE_BUTTON(editor->priv->text_color_radio), TRUE);
395                         gtk_widget_set_sensitive (editor->priv->text_color_combo, TRUE);
396                         gtk_widget_set_sensitive (editor->priv->text_color_key_combo, FALSE);
397                 } else {
398                         state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->priv->text_color_key_radio));
399                         gtk_widget_set_sensitive (editor->priv->text_color_combo, !state);
400                         gtk_widget_set_sensitive (editor->priv->text_color_key_combo, state);
401                                                   
402                 }
403         }
404
405         if (editor->priv->edit_insert_field_button) {
406                 gtk_widget_set_sensitive (editor->priv->edit_insert_field_button,
407                                           merge != NULL);
408         }
409
410         if (editor->priv->img_key_combo) {
411                 gtk_widget_set_sensitive (editor->priv->img_key_combo, merge != NULL);
412         }
413  
414         if (editor->priv->img_key_radio) {
415                 gtk_widget_set_sensitive (editor->priv->img_key_radio, merge != NULL);
416                 if (merge == NULL) {
417                         gtk_toggle_button_set_active (
418                                 GTK_TOGGLE_BUTTON(editor->priv->img_file_radio), TRUE);
419                 }
420         }
421
422         if (editor->priv->data_key_combo) {
423                 gtk_widget_set_sensitive (editor->priv->data_key_combo, merge != NULL);
424         }
425  
426         if (editor->priv->data_key_radio) {
427                 gtk_widget_set_sensitive (editor->priv->data_key_radio, merge != NULL);
428                 if (merge == NULL) {
429                         gtk_toggle_button_set_active (
430                                 GTK_TOGGLE_BUTTON(editor->priv->data_literal_radio), TRUE);
431                 }
432         }
433         
434         fixed_flag = editor->priv->data_format_fixed_flag;
435         if (editor->priv->data_format_label) {
436                 gtk_widget_set_sensitive (editor->priv->data_format_label,
437                                           (merge != NULL));
438         }
439         if (editor->priv->data_ex_label) {
440                 gtk_widget_set_sensitive (editor->priv->data_ex_label,
441                                           (merge != NULL));
442         }
443         if (editor->priv->data_digits_label) {
444                 gtk_widget_set_sensitive (editor->priv->data_digits_label,
445                                           (merge != NULL) && !fixed_flag);
446         }
447         if (editor->priv->data_digits_spin) {
448                 gtk_widget_set_sensitive (editor->priv->data_digits_spin,
449                                           (merge != NULL) && !fixed_flag);
450         }
451
452         if (editor->priv->fill_page_vbox) {
453                 gtk_widget_set_sensitive (editor->priv->fill_key_radio, merge != NULL);
454                 if (merge == NULL) {
455                         gtk_toggle_button_set_active (
456                                 GTK_TOGGLE_BUTTON(editor->priv->fill_color_radio), TRUE);
457                         gtk_widget_set_sensitive (editor->priv->fill_color_combo, TRUE);
458                         gtk_widget_set_sensitive (editor->priv->fill_key_combo, FALSE);
459                 } else {
460                         state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->priv->fill_key_radio));
461                         gtk_widget_set_sensitive (editor->priv->fill_color_combo, !state);
462                         gtk_widget_set_sensitive (editor->priv->fill_key_combo, state);
463                                                   
464                 }
465         }
466
467         if (editor->priv->line_page_vbox) {
468                 gtk_widget_set_sensitive (editor->priv->line_key_radio, merge != NULL);
469                 if (merge == NULL) {
470                         gtk_toggle_button_set_active (
471                                 GTK_TOGGLE_BUTTON(editor->priv->line_color_radio), TRUE);
472                         gtk_widget_set_sensitive (editor->priv->line_color_combo, TRUE);
473                         gtk_widget_set_sensitive (editor->priv->line_key_combo, FALSE);
474                 } else {
475                         state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->priv->line_key_radio));
476                         gtk_widget_set_sensitive (editor->priv->line_color_combo, !state);
477                         gtk_widget_set_sensitive (editor->priv->line_key_combo, state);
478                                                   
479                 }
480         }
481
482         if (editor->priv->bc_page_vbox) {
483                 gtk_widget_set_sensitive (editor->priv->bc_key_radio, merge != NULL);
484                 if (merge == NULL) {
485                         gtk_toggle_button_set_active (
486                                 GTK_TOGGLE_BUTTON(editor->priv->bc_color_radio), TRUE);
487                         gtk_widget_set_sensitive (editor->priv->bc_color_combo, TRUE);
488                         gtk_widget_set_sensitive (editor->priv->bc_key_combo, FALSE);
489                 } else {
490                         state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->priv->bc_key_radio));
491                         gtk_widget_set_sensitive (editor->priv->bc_color_combo, !state);
492                         gtk_widget_set_sensitive (editor->priv->bc_key_combo, state);
493                                                   
494                 }
495         }
496
497         if (editor->priv->shadow_page_vbox) {
498                 gtk_widget_set_sensitive (editor->priv->shadow_key_radio, merge != NULL);
499                 if (merge == NULL) {
500                         gtk_toggle_button_set_active (
501                                 GTK_TOGGLE_BUTTON(editor->priv->shadow_color_radio), TRUE);
502                         gtk_widget_set_sensitive (editor->priv->shadow_color_combo, TRUE);
503                         gtk_widget_set_sensitive (editor->priv->shadow_key_combo, FALSE);
504                 } else {
505                         state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->priv->shadow_key_radio));
506                         gtk_widget_set_sensitive (editor->priv->shadow_color_combo, !state);
507                         gtk_widget_set_sensitive (editor->priv->shadow_key_combo, state);
508                                                   
509                 }
510         }
511
512         keys = gl_merge_get_key_list (merge);
513         if ( keys == NULL ) {
514                 keys = g_list_append (keys, g_strdup (""));
515         }
516
517         combo = editor->priv->img_key_combo;
518         if (combo) {
519                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
520         }
521
522         menu = editor->priv->edit_insert_field_menu;
523         if (menu) {
524                 gl_wdgt_merge_menu_set_fields (GL_WDGT_MERGE_MENU(menu), keys);
525         }
526
527         combo = editor->priv->data_key_combo;
528         if (combo) {
529                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
530         }
531                 
532         combo = editor->priv->fill_key_combo;
533         if (combo) {
534                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
535         }
536
537         combo = editor->priv->text_color_key_combo;
538         if (combo) {
539                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
540         }
541
542         combo = editor->priv->line_key_combo;
543         if (combo) {
544                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
545         }
546                 
547         combo = editor->priv->bc_key_combo;
548         if (combo) {
549                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
550         }
551                 
552         combo = editor->priv->shadow_key_combo;
553         if (combo) {
554                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
555         }
556
557         gl_merge_free_key_list (&keys);
558  
559         gl_debug (DEBUG_EDITOR, "END");
560 }
561
562
563 /*--------------------------------------------------------------------------*/
564 /* PRIVATE. Prefs changed callback.  Update units related items.            */
565 /*--------------------------------------------------------------------------*/
566 static void
567 prefs_changed_cb (glObjectEditor *editor)
568 {
569
570         gl_debug (DEBUG_EDITOR, "START");
571
572         if (editor->priv->lsize_r_spin) {
573                 lsize_prefs_changed_cb (editor);
574         }
575                 
576         if (editor->priv->size_w_spin) {
577                 size_prefs_changed_cb (editor);
578         }
579                 
580         if (editor->priv->pos_x_spin) {
581                 position_prefs_changed_cb (editor);
582         }
583
584         if (editor->priv->shadow_x_spin) {
585                 shadow_prefs_changed_cb (editor);
586         }
587
588         gl_debug (DEBUG_EDITOR, "END");
589 }
590
591 /*---------------------------------------------------------------------------*/
592 /* PRIVATE. label "changed" callback.                                        */
593 /*---------------------------------------------------------------------------*/
594 static void
595 label_changed_cb (glLabel        *label,
596                   glObjectEditor *editor)
597 {
598         gdouble   label_width, label_height;
599         glMerge  *merge;
600
601         gl_debug (DEBUG_EDITOR, "START");
602
603         gl_label_get_size (label, &label_width, &label_height);
604         gl_object_editor_set_max_position (GL_OBJECT_EDITOR (editor),
605                                            label_width, label_height);
606         gl_object_editor_set_max_size (GL_OBJECT_EDITOR (editor),
607                                        label_width, label_height);
608         gl_object_editor_set_max_lsize (GL_OBJECT_EDITOR (editor),
609                                        label_width, label_height);
610         gl_object_editor_set_max_shadow_offset (GL_OBJECT_EDITOR (editor),
611                                                 label_width, label_height);
612         
613         merge = gl_label_get_merge (label);
614         gl_object_editor_set_key_names (editor, merge);
615
616         gl_debug (DEBUG_EDITOR, "END");
617 }
618