]> git.sur5r.net Git - glabels/blob - glabels2/src/window.c
2005-05-15 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / src / window.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4  *  (GLABELS) Label and Business Card Creation program for GNOME
5  *
6  *  window.c:  a gLabels app window
7  *
8  *  Copyright (C) 2002  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
25 #include <config.h>
26
27 #include "window.h"
28
29 #include <glib/gi18n.h>
30 #include <gtk/gtkvbox.h>
31 #include <gtk/gtkhbox.h>
32 #include <gtk/gtklabel.h>
33 #include <gtk/gtkframe.h>
34 #include <gtk/gtkstatusbar.h>
35
36 #include "ui.h"
37 #include "ui-commands.h"
38 #include "util.h"
39 #include "xml-label.h"
40 #include "prefs.h"
41 #include "file.h"
42
43 #include "debug.h"
44
45 /*============================================================================*/
46 /* Private macros and constants.                                              */
47 /*============================================================================*/
48
49 #define DEFAULT_WINDOW_WIDTH  788
50 #define DEFAULT_WINDOW_HEIGHT 600
51
52 #define CURSOR_INFO_WIDTH     150
53 #define ZOOM_INFO_WIDTH        50
54
55 /*============================================================================*/
56 /* Private globals                                                            */
57 /*============================================================================*/
58 static GtkWindowClass *parent_class;
59
60 static GList *window_list = NULL;
61
62
63 /*============================================================================*/
64 /* Local function prototypes                                                  */
65 /*============================================================================*/
66
67 static void     gl_window_class_init   (glWindowClass *class);
68 static void     gl_window_init         (glWindow      *window);
69 static void     gl_window_finalize     (GObject       *object);
70 static void     gl_window_destroy      (GtkObject     *gtk_object);
71
72 static void     set_window_title       (glWindow *window,
73                                         glLabel  *label);
74
75 static gboolean window_delete_event_cb (glWindow      *window,
76                                         GdkEvent      *event,
77                                         gpointer       user_data);
78
79 static void     selection_changed_cb   (glView        *view,
80                                         glWindow      *window);
81
82 static void   context_menu_activate_cb (glView       *view,
83                                         gint          button,
84                                         guint32       activate_time,
85                                         glWindow     *window);
86
87 static void     zoom_changed_cb        (glView        *view,
88                                         gdouble        zoom,
89                                         glWindow      *window);
90
91 static void     pointer_moved_cb       (glView        *view,
92                                         gdouble        x,
93                                         gdouble        y,
94                                         glWindow      *window);
95
96 static void     pointer_exit_cb        (glView        *view,
97                                         glWindow      *window);
98
99 static void     name_changed_cb        (glLabel       *label,
100                                         glWindow      *window);
101
102 static void     modified_changed_cb    (glLabel       *label,
103                                         glWindow      *window);
104
105 \f
106 /****************************************************************************/
107 /* Boilerplate Object stuff.                                                */
108 /****************************************************************************/
109 GType
110 gl_window_get_type (void)
111 {
112         static GType type = 0;
113
114         if (!type) {
115                 static const GTypeInfo info = {
116                         sizeof (glWindowClass),
117                         NULL,
118                         NULL,
119                         (GClassInitFunc) gl_window_class_init,
120                         NULL,
121                         NULL,
122                         sizeof (glWindow),
123                         0,
124                         (GInstanceInitFunc) gl_window_init,
125                         NULL
126                 };
127
128                 type = g_type_register_static (GTK_TYPE_WINDOW,
129                                                "glWindow", &info, 0);
130         }
131
132         return type;
133 }
134
135 static void
136 gl_window_class_init (glWindowClass *class)
137 {
138         GObjectClass   *object_class     = (GObjectClass *) class;
139         GtkObjectClass *gtk_object_class = (GtkObjectClass *) class;
140
141         gl_debug (DEBUG_WINDOW, "START");
142
143         parent_class = g_type_class_peek_parent (class);
144
145         object_class->finalize = gl_window_finalize;
146
147         gtk_object_class->destroy = gl_window_destroy;
148
149         gl_debug (DEBUG_WINDOW, "END");
150 }
151
152 static void
153 gl_window_init (glWindow *window)
154 {
155         GtkWidget        *vbox1;
156         GtkUIManager     *ui;
157         GtkWidget        *status_hbox;
158
159         gl_debug (DEBUG_WINDOW, "START");
160
161         vbox1 = gtk_vbox_new (FALSE, 0);
162         gtk_container_add (GTK_CONTAINER (window), vbox1);
163
164         window->ui = ui = gl_ui_new (window);
165         gtk_box_pack_start (GTK_BOX (vbox1),
166                             gtk_ui_manager_get_widget (ui, "/MenuBar"),
167                             FALSE, FALSE, 0);
168         gtk_box_pack_start (GTK_BOX (vbox1),
169                             gtk_ui_manager_get_widget (ui, "/MainToolBar"),
170                             FALSE, FALSE, 0);
171         gtk_box_pack_start (GTK_BOX (vbox1),
172                             gtk_ui_manager_get_widget (ui, "/DrawingToolBar"),
173                             FALSE, FALSE, 0);
174
175         window->hbox = gtk_hbox_new (FALSE, 0);
176         gtk_box_pack_start (GTK_BOX (vbox1), window->hbox, TRUE, TRUE, 0);
177
178         window->sidebar = GL_UI_SIDEBAR (gl_ui_sidebar_new ());
179         gtk_box_pack_end (GTK_BOX (window->hbox), GTK_WIDGET (window->sidebar), FALSE, FALSE, 0);
180
181         window->property_bar = GL_UI_PROPERTY_BAR (gl_ui_property_bar_new ());
182         gtk_box_pack_start (GTK_BOX (vbox1), GTK_WIDGET (window->property_bar), FALSE, FALSE, 0);
183
184         status_hbox = gtk_hbox_new (FALSE, 0);
185         gtk_box_pack_start (GTK_BOX (vbox1), status_hbox, FALSE, FALSE, 0);
186
187         window->status_bar = gtk_statusbar_new ();
188         gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (window->status_bar), FALSE);
189         gtk_box_pack_start (GTK_BOX (status_hbox),
190                             window->status_bar,
191                             TRUE, TRUE, 0);
192         window->zoom_info = gtk_label_new (NULL);
193         gtk_widget_set_size_request (window->zoom_info, ZOOM_INFO_WIDTH, -1);
194         window->zoom_info_frame = gtk_frame_new (NULL);
195         gtk_frame_set_shadow_type (GTK_FRAME(window->zoom_info_frame), GTK_SHADOW_IN);
196         gtk_container_add (GTK_CONTAINER(window->zoom_info_frame), window->zoom_info);
197         gtk_widget_show_all (window->zoom_info_frame);
198         gtk_box_pack_end (GTK_BOX (status_hbox),
199                           window->zoom_info_frame,
200                           FALSE, FALSE, 0);
201
202         window->cursor_info = gtk_label_new (NULL);
203         gtk_widget_set_size_request (window->cursor_info, CURSOR_INFO_WIDTH, -1);
204         window->cursor_info_frame = gtk_frame_new (NULL);
205         gtk_frame_set_shadow_type (GTK_FRAME(window->cursor_info_frame), GTK_SHADOW_IN);
206         gtk_container_add (GTK_CONTAINER(window->cursor_info_frame), window->cursor_info);
207         gtk_widget_show_all (window->cursor_info_frame);
208         gtk_box_pack_end (GTK_BOX (status_hbox),
209                           window->cursor_info_frame,
210                           FALSE, FALSE, 0);
211
212         gtk_window_set_default_size (GTK_WINDOW (window),
213                                      DEFAULT_WINDOW_WIDTH,
214                                      DEFAULT_WINDOW_HEIGHT);
215
216         g_signal_connect (G_OBJECT(window), "delete-event",
217                           G_CALLBACK(window_delete_event_cb), NULL);
218         
219         window->menu_tips_context_id =
220                 gtk_statusbar_get_context_id (GTK_STATUSBAR (window->status_bar), "menu_tips");
221
222         window->print_dialog = NULL;
223         window->merge_dialog = NULL;
224         window->context_menu = GTK_MENU (gtk_ui_manager_get_widget (ui, "/ContextMenu"));
225         window->empty_selection_context_menu =
226                 GTK_MENU (gtk_ui_manager_get_widget (ui, "/EmptySelectionContextMenu"));
227
228         window->view = NULL;
229
230         window_list = g_list_append (window_list, window);
231
232         gl_debug (DEBUG_WINDOW, "END");
233 }
234
235 static void
236 gl_window_finalize (GObject *object)
237 {
238         glWindow *window;
239
240         gl_debug (DEBUG_WINDOW, "START");
241
242         g_return_if_fail (object != NULL);
243         g_return_if_fail (GL_IS_WINDOW (object));
244
245         window = GL_WINDOW (object);
246
247         G_OBJECT_CLASS (parent_class)->finalize (object);
248
249         gl_debug (DEBUG_WINDOW, "END");
250 }
251
252 static void
253 gl_window_destroy (GtkObject *gtk_object)
254 {
255         glWindow *window;
256
257         gl_debug (DEBUG_WINDOW, "START");
258
259         g_return_if_fail (gtk_object != NULL);
260         g_return_if_fail (GL_IS_WINDOW (gtk_object));
261
262         window = GL_WINDOW (gtk_object);
263         window_list = g_list_remove (window_list, window);
264
265         if (window->ui) {
266                 gl_ui_unref(window->ui);
267                 window->ui = NULL;
268         }
269
270         if (GTK_OBJECT_CLASS (parent_class)->destroy) {
271                 GTK_OBJECT_CLASS (parent_class)->destroy (gtk_object);
272         }
273
274         gl_debug (DEBUG_WINDOW, "END");
275 }
276
277
278 /****************************************************************************/
279 /** Create a glabels window.                                                */
280 /****************************************************************************/
281 GtkWidget *
282 gl_window_new (void)
283 {
284         glWindow *window;
285
286         gl_debug (DEBUG_WINDOW, "START");
287
288         window = g_object_new (GL_TYPE_WINDOW,
289                                "title",    _("(none) - gLabels"),
290                                NULL);
291
292         gl_debug (DEBUG_WINDOW, "window=%p", window);
293         gl_debug (DEBUG_WINDOW, "view=%p", window->view);
294
295         gl_debug (DEBUG_WINDOW, "END");
296
297         return GTK_WIDGET(window);
298 }
299
300 /****************************************************************************/
301 /** Create a glabels window from a label.                                   */
302 /****************************************************************************/
303 GtkWidget*
304 gl_window_new_from_label (glLabel *label)
305 {
306         glWindow *window;
307
308         gl_debug (DEBUG_WINDOW, "START");
309
310         window = GL_WINDOW (gl_window_new ());
311
312         gl_window_set_label (window, label);
313
314         gl_debug (DEBUG_WINDOW, "END");
315
316         return GTK_WIDGET(window);
317 }
318
319 /****************************************************************************/
320 /** Create a glabels window from a glabels file.                            */
321 /****************************************************************************/
322 GtkWidget*
323 gl_window_new_from_file (const gchar *filename)
324 {
325         glWindow         *window;
326         glLabel          *label;
327         gchar            *abs_filename;
328         glXMLLabelStatus  status;
329
330         gl_debug (DEBUG_WINDOW, "START");
331
332         window = GL_WINDOW (gl_window_new ());
333
334         abs_filename = gl_util_make_absolute (filename);
335         label = gl_xml_label_open (abs_filename, &status);
336         g_free (abs_filename);
337
338         gl_window_set_label (window, label);
339
340         gl_debug (DEBUG_WINDOW, "END");
341
342         return GTK_WIDGET(window);
343 }
344
345 /****************************************************************************/
346 /** Is window empty?                                                        */
347 /****************************************************************************/
348 gboolean
349 gl_window_is_empty (glWindow    *window)
350 {
351         g_return_val_if_fail (GL_IS_WINDOW (window), FALSE);
352
353         gl_debug (DEBUG_WINDOW, "return %d", (window->view == NULL) );
354         return ( window->view == NULL );
355 }
356
357 /****************************************************************************/
358 /** Create view from label and place in window.                             */
359 /****************************************************************************/
360 void
361 gl_window_set_label (glWindow    *window,
362                      glLabel     *label)
363 {
364         gchar *string;
365
366         gl_debug (DEBUG_WINDOW, "START");
367
368         g_return_if_fail (GL_IS_WINDOW (window));
369         g_return_if_fail (GL_IS_LABEL (label));
370
371         gl_label_clear_modified (label);
372
373         set_window_title (window, label);
374
375         if ( window->view != NULL ) {
376                 gtk_widget_destroy (window->view);
377                 window->view = NULL;
378         }
379
380         window->view = gl_view_new (label);
381         gtk_box_pack_start (GTK_BOX (window->hbox), window->view,TRUE, TRUE, 0);
382
383         gtk_widget_show_all (window->view);
384
385         gl_view_zoom_to_fit (GL_VIEW(window->view));
386
387         if (gl_prefs->grid_visible) {
388                 gl_view_show_grid (GL_VIEW(window->view));
389         } else {
390                 gl_view_hide_grid (GL_VIEW(window->view));
391         }
392
393         if (gl_prefs->markup_visible) {
394                 gl_view_show_markup (GL_VIEW(window->view));
395         } else {
396                 gl_view_hide_markup (GL_VIEW(window->view));
397         }
398
399         gl_ui_update_all (window->ui, GL_VIEW(window->view));
400
401         gl_ui_property_bar_set_view (window->property_bar, GL_VIEW(window->view));
402         gl_ui_sidebar_set_view (window->sidebar, GL_VIEW(window->view));
403
404         string = g_strdup_printf ("%3.0f%%",
405                                   100.0*gl_view_get_zoom (GL_VIEW(window->view)));
406         gtk_label_set_text (GTK_LABEL(window->zoom_info), string);
407         g_free (string);
408
409         g_signal_connect (G_OBJECT(window->view), "selection_changed",
410                           G_CALLBACK(selection_changed_cb), window);
411
412         g_signal_connect (G_OBJECT(window->view), "context_menu_activate",
413                           G_CALLBACK(context_menu_activate_cb), window);
414
415         g_signal_connect (G_OBJECT(window->view), "zoom_changed",
416                           G_CALLBACK(zoom_changed_cb), window);
417
418         g_signal_connect (G_OBJECT(window->view), "pointer_moved",
419                           G_CALLBACK(pointer_moved_cb), window);
420
421         g_signal_connect (G_OBJECT(window->view), "pointer_exit",
422                           G_CALLBACK(pointer_exit_cb), window);
423
424         g_signal_connect (G_OBJECT(label), "name_changed",
425                           G_CALLBACK(name_changed_cb), window);
426
427         g_signal_connect (G_OBJECT(label), "modified_changed",
428                           G_CALLBACK(modified_changed_cb), window);
429
430         gl_debug (DEBUG_WINDOW, "END");
431 }
432
433 /****************************************************************************/
434 /** Return list of glabels windows.                                         */
435 /****************************************************************************/
436 const GList *
437 gl_window_get_window_list (void)
438 {
439         gl_debug (DEBUG_WINDOW, "");
440         return window_list;
441 }
442
443 /*---------------------------------------------------------------------------*/
444 /** PRIVATE.  Set window title based on name and state of label.             */
445 /*---------------------------------------------------------------------------*/
446 static void 
447 set_window_title (glWindow *window,
448                   glLabel  *label)
449 {
450         gchar *name, *title;
451
452         gl_debug (DEBUG_WINDOW, "START");
453
454         g_return_if_fail (window && GL_IS_WINDOW (window));
455         g_return_if_fail (label && GL_IS_LABEL (label));
456
457         name = gl_label_get_short_name (label);
458         g_return_if_fail (name != NULL);
459
460         if (gl_label_is_modified (label)) {
461                 title = g_strdup_printf ("%s %s - gLabels",
462                                          name, _("(modified)"));
463         } else {
464                 title = g_strdup_printf ("%s - gLabels", name);
465         }
466
467         gtk_window_set_title (GTK_WINDOW(window), title);
468
469         g_free (name);
470         g_free (title);
471
472         gl_debug (DEBUG_WINDOW, "END");
473 }
474
475 /*-------------------------------------------------------------------------*/
476 /** PRIVATE.  Window "delete-event" callback.                              */
477 /*-------------------------------------------------------------------------*/
478 static gboolean
479 window_delete_event_cb (glWindow      *window,
480                         GdkEvent      *event,
481                         gpointer       user_data)
482 {
483         gl_debug (DEBUG_WINDOW, "START");
484
485         g_return_val_if_fail (window && GL_IS_WINDOW (window), TRUE);
486
487         gl_file_close (window);
488
489         gl_debug (DEBUG_WINDOW, "END");
490
491         return TRUE;
492 }
493
494 /*---------------------------------------------------------------------------*/
495 /** PRIVATE.  View "selection state changed" callback.                       */
496 /*---------------------------------------------------------------------------*/
497 static void 
498 selection_changed_cb (glView   *view,
499                       glWindow *window)
500 {
501         gl_debug (DEBUG_WINDOW, "START");
502
503         g_return_if_fail (view && GL_IS_VIEW (view));
504         g_return_if_fail (window && GL_IS_WINDOW (window));
505
506         gl_ui_update_selection_verbs (window->ui, view);
507
508         gl_debug (DEBUG_WINDOW, "END");
509 }
510
511 /*---------------------------------------------------------------------------*/
512 /** PRIVATE.  View "context menu activate" callback.                         */
513 /*---------------------------------------------------------------------------*/
514 static void
515 context_menu_activate_cb (glView       *view,
516                           gint          button,
517                           guint32       activate_time,
518                           glWindow     *window)
519 {
520         gl_debug (DEBUG_WINDOW, "START");
521
522         g_return_if_fail (view && GL_IS_VIEW (view));
523         g_return_if_fail (window && GL_IS_WINDOW (window));
524
525         if (gl_view_is_selection_empty (view)) {
526
527                 gtk_menu_popup (GTK_MENU (window->empty_selection_context_menu),
528                                 NULL, NULL, NULL, NULL, button, activate_time);
529
530         } else {
531
532                 gtk_menu_popup (GTK_MENU (window->context_menu),
533                                 NULL, NULL, NULL, NULL, button, activate_time);
534
535         }
536
537         gl_debug (DEBUG_WINDOW, "END");
538 }
539
540 /*---------------------------------------------------------------------------*/
541 /** PRIVATE.  View "zoom state changed" callback.                            */
542 /*---------------------------------------------------------------------------*/
543 static void 
544 zoom_changed_cb (glView   *view,
545                  gdouble   zoom,
546                  glWindow *window)
547 {
548         gchar *string;
549
550         gl_debug (DEBUG_WINDOW, "START");
551
552         g_return_if_fail (view && GL_IS_VIEW (view));
553         g_return_if_fail (window && GL_IS_WINDOW (window));
554
555         string = g_strdup_printf ("%3.0f%%", 100.0*zoom);
556         gtk_label_set_text (GTK_LABEL(window->zoom_info), string);
557         g_free (string);
558
559         gl_ui_update_zoom_verbs (window->ui, view);
560
561         gl_debug (DEBUG_WINDOW, "END");
562 }
563
564 /*---------------------------------------------------------------------------*/
565 /** PRIVATE.  View "pointer moved" callback.                                 */
566 /*---------------------------------------------------------------------------*/
567 static void
568 pointer_moved_cb (glView   *view,
569                   gdouble   x,
570                   gdouble   y,
571                   glWindow *window)
572 {
573         gchar *string;
574         gdouble units_per_point;
575         gint    units_precision;
576
577         gl_debug (DEBUG_WINDOW, "START");
578
579         g_return_if_fail (view && GL_IS_VIEW (view));
580         g_return_if_fail (window && GL_IS_WINDOW (window));
581
582         units_per_point = gl_prefs_get_units_per_point ();
583         units_precision = gl_prefs_get_units_precision ();
584
585         string = g_strdup_printf ("%.*f, %.*f",
586                                   units_precision, x*units_per_point,
587                                   units_precision, y*units_per_point);
588         gtk_label_set_text (GTK_LABEL(window->cursor_info), string);
589         g_free (string);
590
591         gl_debug (DEBUG_WINDOW, "END");
592 }
593
594 /*---------------------------------------------------------------------------*/
595 /** PRIVATE.  View "pointer exit" callback.                                  */
596 /*---------------------------------------------------------------------------*/
597 static void
598 pointer_exit_cb (glView   *view,
599                  glWindow *window)
600 {
601         gl_debug (DEBUG_WINDOW, "START");
602
603         g_return_if_fail (view && GL_IS_VIEW (view));
604         g_return_if_fail (window && GL_IS_WINDOW (window));
605
606         gtk_label_set_text (GTK_LABEL(window->cursor_info), "");
607
608         gl_debug (DEBUG_WINDOW, "END");
609 }
610
611 /*---------------------------------------------------------------------------*/
612 /** PRIVATE.  Label "name changed" callback.                                 */
613 /*---------------------------------------------------------------------------*/
614 static void 
615 name_changed_cb (glLabel  *label,
616                  glWindow *window)
617 {
618         gl_debug (DEBUG_WINDOW, "START");
619
620         g_return_if_fail (label && GL_IS_LABEL (label));
621         g_return_if_fail (window && GL_IS_WINDOW (window));
622
623         set_window_title (window, label);
624
625         gl_debug (DEBUG_WINDOW, "END");
626 }
627
628 /*---------------------------------------------------------------------------*/
629 /** PRIVATE.  Label "modified state changed" callback.                       */
630 /*---------------------------------------------------------------------------*/
631 static void 
632 modified_changed_cb (glLabel  *label,
633                      glWindow *window)
634 {
635         gl_debug (DEBUG_WINDOW, "START");
636
637         g_return_if_fail (label && GL_IS_LABEL (label));
638         g_return_if_fail (window && GL_IS_WINDOW (window));
639
640         set_window_title (window, label);
641
642         gl_ui_update_modified_verbs (window->ui, label);
643
644         gl_debug (DEBUG_WINDOW, "END");
645 }
646