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