]> git.sur5r.net Git - glabels/blob - glabels2/src/object-editor.c
2009-09-01 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         va_start (args, first_option);
230         gl_object_notebook_construct_valist (editor, label, first_option, args);
231         va_end (args);
232
233         gl_debug (DEBUG_EDITOR, "END");
234
235         return GTK_WIDGET(editor);
236 }
237
238
239 /*--------------------------------------------------------------------------*/
240 /* PRIVATE.  Construct notebook.                                            */
241 /*--------------------------------------------------------------------------*/
242 static void
243 gl_object_notebook_construct_valist (glObjectEditor       *editor,
244                                      glLabel              *label,
245                                      glObjectEditorOption  first_option,
246                                      va_list               args)
247 {
248         glObjectEditorOption option;
249         gint pages = 0;
250
251         gl_debug (DEBUG_EDITOR, "START");
252
253         editor->priv->label = label;
254
255         option = first_option;
256
257         for ( option=first_option; option; option=va_arg (args, glObjectEditorOption) ) {
258
259                 switch (option) {
260
261                 case GL_OBJECT_EDITOR_EMPTY:
262                         gtk_widget_set_sensitive (editor->priv->title_image, FALSE);
263                         gtk_widget_set_sensitive (editor->priv->title_label, FALSE);
264                         break;
265
266                 case GL_OBJECT_EDITOR_POSITION_PAGE:
267                         gl_object_editor_prepare_position_page (editor);
268                         pages++;
269                         break;
270
271                 case GL_OBJECT_EDITOR_SIZE_PAGE:
272                 case GL_OBJECT_EDITOR_SIZE_IMAGE_PAGE:
273                         gl_object_editor_prepare_size_page (editor, option);
274                         pages++;
275                         break;
276
277                 case GL_OBJECT_EDITOR_SIZE_LINE_PAGE:
278                         gl_object_editor_prepare_lsize_page (editor);
279                         pages++;
280                         break;
281
282                 case GL_OBJECT_EDITOR_FILL_PAGE:
283                         gl_object_editor_prepare_fill_page (editor);
284                         pages++;
285                         break;
286
287                 case GL_OBJECT_EDITOR_LINE_PAGE:
288                         gl_object_editor_prepare_line_page (editor);
289                         pages++;
290                         break;
291
292                 case GL_OBJECT_EDITOR_IMAGE_PAGE:
293                         gl_object_editor_prepare_image_page (editor);
294                         pages++;
295                         break;
296
297                 case GL_OBJECT_EDITOR_TEXT_PAGE:
298                         gl_object_editor_prepare_text_page (editor);
299                         pages++;
300                         break;
301
302                 case GL_OBJECT_EDITOR_EDIT_PAGE:
303                         gl_object_editor_prepare_edit_page (editor);
304                         pages++;
305                         break;
306
307                 case GL_OBJECT_EDITOR_BC_PAGE:
308                         gl_object_editor_prepare_bc_page (editor);
309                         pages++;
310                         break;
311
312                 case GL_OBJECT_EDITOR_DATA_PAGE:
313                         gl_object_editor_prepare_data_page (editor);
314                         pages++;
315                         break;
316
317                 case GL_OBJECT_EDITOR_SHADOW_PAGE:
318                         gl_object_editor_prepare_shadow_page (editor);
319                         pages++;
320                         break;
321
322                 default:
323                         g_message ("option = %d", option);
324                         g_assert_not_reached ();
325                 }
326                 
327         }
328         if (pages) {
329                 gtk_widget_show (editor->priv->notebook);
330         }
331
332         g_signal_connect_swapped (G_OBJECT (gl_prefs), "changed",
333                                   G_CALLBACK (prefs_changed_cb),
334                                   editor);
335         if (label)
336         {
337                 label_changed_cb (label, editor);
338                 g_signal_connect (G_OBJECT (label), "size_changed",
339                                   G_CALLBACK (label_changed_cb),
340                                   editor);
341                 g_signal_connect (G_OBJECT (label), "merge_changed",
342                                   G_CALLBACK (label_changed_cb),
343                                   editor);
344         }
345
346         gl_debug (DEBUG_EDITOR, "END");
347 }
348
349
350 /*--------------------------------------------------------------------------*/
351 /* PRIVATE. Widget changed callback.  Emit our "changed" signal.            */
352 /*--------------------------------------------------------------------------*/
353 void
354 gl_object_editor_changed_cb (glObjectEditor *editor)
355 {
356         if (editor->priv->stop_signals) return;
357
358         gl_debug (DEBUG_EDITOR, "START");
359
360         /* Emit our "changed" signal */
361         g_signal_emit (G_OBJECT (editor), gl_object_editor_signals[CHANGED], 0);
362
363         gl_debug (DEBUG_EDITOR, "END");
364 }
365
366
367 /*--------------------------------------------------------------------------*/
368 /* PRIVATE. Widget size changed callback.  Emit our "size-changed" signal.  */
369 /*--------------------------------------------------------------------------*/
370 void
371 gl_object_editor_size_changed_cb (glObjectEditor *editor)
372 {
373         if (editor->priv->stop_signals) return;
374
375         gl_debug (DEBUG_EDITOR, "START");
376
377         /* Emit our "size_changed" signal */
378         g_signal_emit (G_OBJECT (editor), gl_object_editor_signals[SIZE_CHANGED], 0);
379
380         gl_debug (DEBUG_EDITOR, "END");
381 }
382
383
384 /*****************************************************************************/
385 /* Set possible key names from merge object.                                 */
386 /*****************************************************************************/
387 void
388 gl_object_editor_set_key_names (glObjectEditor      *editor,
389                                 glMerge             *merge)
390 {
391         GList     *keys;
392         GtkWidget *combo;
393         GtkWidget *menu;
394         gboolean   fixed_flag;
395         gboolean   state;
396  
397         gl_debug (DEBUG_EDITOR, "START");
398
399         if (editor->priv->text_auto_shrink_check) {
400                 gtk_widget_set_sensitive (editor->priv->text_auto_shrink_check,
401                                           merge != NULL);
402         }
403  
404         if (editor->priv->text_page_vbox) {
405                 gtk_widget_set_sensitive (editor->priv->text_color_key_radio, merge != NULL);
406                 if (merge == NULL) {
407                         gtk_toggle_button_set_active (
408                                 GTK_TOGGLE_BUTTON(editor->priv->text_color_radio), TRUE);
409                         gtk_widget_set_sensitive (editor->priv->text_color_combo, TRUE);
410                         gtk_widget_set_sensitive (editor->priv->text_color_key_combo, FALSE);
411                 } else {
412                         state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->priv->text_color_key_radio));
413                         gtk_widget_set_sensitive (editor->priv->text_color_combo, !state);
414                         gtk_widget_set_sensitive (editor->priv->text_color_key_combo, state);
415                                                   
416                 }
417         }
418
419         if (editor->priv->edit_insert_field_button) {
420                 gtk_widget_set_sensitive (editor->priv->edit_insert_field_button,
421                                           merge != NULL);
422         }
423
424         if (editor->priv->img_key_combo) {
425                 gtk_widget_set_sensitive (editor->priv->img_key_combo, merge != NULL);
426         }
427  
428         if (editor->priv->img_key_radio) {
429                 gtk_widget_set_sensitive (editor->priv->img_key_radio, merge != NULL);
430                 if (merge == NULL) {
431                         gtk_toggle_button_set_active (
432                                 GTK_TOGGLE_BUTTON(editor->priv->img_file_radio), TRUE);
433                 }
434         }
435
436         if (editor->priv->data_key_combo) {
437                 gtk_widget_set_sensitive (editor->priv->data_key_combo, merge != NULL);
438         }
439  
440         if (editor->priv->data_key_radio) {
441                 gtk_widget_set_sensitive (editor->priv->data_key_radio, merge != NULL);
442                 if (merge == NULL) {
443                         gtk_toggle_button_set_active (
444                                 GTK_TOGGLE_BUTTON(editor->priv->data_literal_radio), TRUE);
445                 }
446         }
447         
448         fixed_flag = editor->priv->data_format_fixed_flag;
449         if (editor->priv->data_format_label) {
450                 gtk_widget_set_sensitive (editor->priv->data_format_label,
451                                           (merge != NULL));
452         }
453         if (editor->priv->data_ex_label) {
454                 gtk_widget_set_sensitive (editor->priv->data_ex_label,
455                                           (merge != NULL));
456         }
457         if (editor->priv->data_digits_label) {
458                 gtk_widget_set_sensitive (editor->priv->data_digits_label,
459                                           (merge != NULL) && !fixed_flag);
460         }
461         if (editor->priv->data_digits_spin) {
462                 gtk_widget_set_sensitive (editor->priv->data_digits_spin,
463                                           (merge != NULL) && !fixed_flag);
464         }
465
466         if (editor->priv->fill_page_vbox) {
467                 gtk_widget_set_sensitive (editor->priv->fill_key_radio, merge != NULL);
468                 if (merge == NULL) {
469                         gtk_toggle_button_set_active (
470                                 GTK_TOGGLE_BUTTON(editor->priv->fill_color_radio), TRUE);
471                         gtk_widget_set_sensitive (editor->priv->fill_color_combo, TRUE);
472                         gtk_widget_set_sensitive (editor->priv->fill_key_combo, FALSE);
473                 } else {
474                         state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->priv->fill_key_radio));
475                         gtk_widget_set_sensitive (editor->priv->fill_color_combo, !state);
476                         gtk_widget_set_sensitive (editor->priv->fill_key_combo, state);
477                                                   
478                 }
479         }
480
481         if (editor->priv->line_page_vbox) {
482                 gtk_widget_set_sensitive (editor->priv->line_key_radio, merge != NULL);
483                 if (merge == NULL) {
484                         gtk_toggle_button_set_active (
485                                 GTK_TOGGLE_BUTTON(editor->priv->line_color_radio), TRUE);
486                         gtk_widget_set_sensitive (editor->priv->line_color_combo, TRUE);
487                         gtk_widget_set_sensitive (editor->priv->line_key_combo, FALSE);
488                 } else {
489                         state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->priv->line_key_radio));
490                         gtk_widget_set_sensitive (editor->priv->line_color_combo, !state);
491                         gtk_widget_set_sensitive (editor->priv->line_key_combo, state);
492                                                   
493                 }
494         }
495
496         if (editor->priv->bc_page_vbox) {
497                 gtk_widget_set_sensitive (editor->priv->bc_key_radio, merge != NULL);
498                 if (merge == NULL) {
499                         gtk_toggle_button_set_active (
500                                 GTK_TOGGLE_BUTTON(editor->priv->bc_color_radio), TRUE);
501                         gtk_widget_set_sensitive (editor->priv->bc_color_combo, TRUE);
502                         gtk_widget_set_sensitive (editor->priv->bc_key_combo, FALSE);
503                 } else {
504                         state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->priv->bc_key_radio));
505                         gtk_widget_set_sensitive (editor->priv->bc_color_combo, !state);
506                         gtk_widget_set_sensitive (editor->priv->bc_key_combo, state);
507                                                   
508                 }
509         }
510
511         if (editor->priv->shadow_page_vbox) {
512                 gtk_widget_set_sensitive (editor->priv->shadow_key_radio, merge != NULL);
513                 if (merge == NULL) {
514                         gtk_toggle_button_set_active (
515                                 GTK_TOGGLE_BUTTON(editor->priv->shadow_color_radio), TRUE);
516                         gtk_widget_set_sensitive (editor->priv->shadow_color_combo, TRUE);
517                         gtk_widget_set_sensitive (editor->priv->shadow_key_combo, FALSE);
518                 } else {
519                         state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->priv->shadow_key_radio));
520                         gtk_widget_set_sensitive (editor->priv->shadow_color_combo, !state);
521                         gtk_widget_set_sensitive (editor->priv->shadow_key_combo, state);
522                                                   
523                 }
524         }
525
526         keys = gl_merge_get_key_list (merge);
527         if ( keys == NULL ) {
528                 keys = g_list_append (keys, g_strdup (""));
529         }
530
531         combo = editor->priv->img_key_combo;
532         if (combo) {
533                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
534         }
535
536         menu = editor->priv->edit_insert_field_menu;
537         if (menu) {
538                 gl_wdgt_merge_menu_set_fields (GL_WDGT_MERGE_MENU(menu), keys);
539         }
540
541         combo = editor->priv->data_key_combo;
542         if (combo) {
543                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
544         }
545                 
546         combo = editor->priv->fill_key_combo;
547         if (combo) {
548                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
549         }
550
551         combo = editor->priv->text_color_key_combo;
552         if (combo) {
553                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
554         }
555
556         combo = editor->priv->line_key_combo;
557         if (combo) {
558                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
559         }
560                 
561         combo = editor->priv->bc_key_combo;
562         if (combo) {
563                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
564         }
565                 
566         combo = editor->priv->shadow_key_combo;
567         if (combo) {
568                 gl_util_combo_box_set_strings (GTK_COMBO_BOX (combo), keys);
569         }
570
571         gl_merge_free_key_list (&keys);
572  
573         gl_debug (DEBUG_EDITOR, "END");
574 }
575
576
577 /*--------------------------------------------------------------------------*/
578 /* PRIVATE. Prefs changed callback.  Update units related items.            */
579 /*--------------------------------------------------------------------------*/
580 static void
581 prefs_changed_cb (glObjectEditor *editor)
582 {
583
584         gl_debug (DEBUG_EDITOR, "START");
585
586         if (editor->priv->lsize_r_spin) {
587                 lsize_prefs_changed_cb (editor);
588         }
589                 
590         if (editor->priv->size_w_spin) {
591                 size_prefs_changed_cb (editor);
592         }
593                 
594         if (editor->priv->pos_x_spin) {
595                 position_prefs_changed_cb (editor);
596         }
597
598         if (editor->priv->shadow_x_spin) {
599                 shadow_prefs_changed_cb (editor);
600         }
601
602         gl_debug (DEBUG_EDITOR, "END");
603 }
604
605
606 /*---------------------------------------------------------------------------*/
607 /* PRIVATE. label "changed" callback.                                        */
608 /*---------------------------------------------------------------------------*/
609 static void
610 label_changed_cb (glLabel        *label,
611                   glObjectEditor *editor)
612 {
613         gdouble   label_width, label_height;
614         glMerge  *merge;
615
616         gl_debug (DEBUG_EDITOR, "START");
617
618         gl_label_get_size (label, &label_width, &label_height);
619         gl_object_editor_set_max_position (GL_OBJECT_EDITOR (editor),
620                                            label_width, label_height);
621         gl_object_editor_set_max_size (GL_OBJECT_EDITOR (editor),
622                                        label_width, label_height);
623         gl_object_editor_set_max_lsize (GL_OBJECT_EDITOR (editor),
624                                        label_width, label_height);
625         gl_object_editor_set_max_shadow_offset (GL_OBJECT_EDITOR (editor),
626                                                 label_width, label_height);
627         
628         merge = gl_label_get_merge (label);
629         gl_object_editor_set_key_names (editor, merge);
630
631         gl_debug (DEBUG_EDITOR, "END");
632 }
633
634
635
636 /*
637  * Local Variables:       -- emacs
638  * mode: C                -- emacs
639  * c-basic-offset: 8      -- emacs
640  * tab-width: 8           -- emacs
641  * indent-tabs-mode: nil  -- emacs
642  * End:                   -- emacs
643  */