2 * (GLABELS) Label and Business Card Creation program for GNOME
4 * view_text.c: GLabels label text object widget
6 * Copyright (C) 2001-2002 Jim Evins <evins@snaught.com>.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <libgnomeprint/gnome-glyphlist.h>
27 #include "view-text.h"
28 #include "canvas-hacktext.h"
30 #include "view-highlight.h"
33 #include "wdgt-text-entry.h"
34 #include "wdgt-text-props.h"
35 #include "wdgt-position.h"
37 #include "pixmaps/cursor_text.xbm"
38 #include "pixmaps/cursor_text_mask.xbm"
42 /*========================================================*/
43 /* Private macros and constants. */
44 /*========================================================*/
46 /*========================================================*/
48 /*========================================================*/
50 struct _glViewTextPrivate {
55 GtkWidget *text_entry;
58 GtkWidget *text_props;
64 /*========================================================*/
65 /* Private globals. */
66 /*========================================================*/
68 static glViewObjectClass *parent_class = NULL;
71 /*========================================================*/
72 /* Private function prototypes. */
73 /*========================================================*/
75 static void gl_view_text_class_init (glViewTextClass *klass);
76 static void gl_view_text_instance_init (glViewText *view_text);
77 static void gl_view_text_finalize (GObject *object);
79 static void update_view_text_cb (glLabelObject *object,
80 glViewText *view_text);
82 static GtkWidget *construct_properties_dialog (glViewText *view_text);
84 static void response_cb (GtkDialog *dialog,
86 glViewText *view_text);
88 static void text_entry_changed_cb (glWdgtTextEntry *text_entry,
89 glViewText *view_text);
91 static void text_props_changed_cb (glWdgtTextProps *text_props,
92 glViewText *view_text);
94 static void position_changed_cb (glWdgtPosition *position,
95 glViewText *view_text);
97 static void update_dialog_cb (glLabelObject *object,
98 glViewText *view_text);
100 static void draw_hacktext (glViewText *view_text);
103 /*****************************************************************************/
104 /* Boilerplate object stuff. */
105 /*****************************************************************************/
107 gl_view_text_get_type (void)
109 static GType type = 0;
113 sizeof (glViewTextClass),
116 (GClassInitFunc) gl_view_text_class_init,
121 (GInstanceInitFunc) gl_view_text_instance_init,
124 type = g_type_register_static (GL_TYPE_VIEW_OBJECT,
125 "glViewText", &info, 0);
132 gl_view_text_class_init (glViewTextClass *klass)
134 GObjectClass *object_class = (GObjectClass *) klass;
136 gl_debug (DEBUG_VIEW, "START");
138 parent_class = g_type_class_peek_parent (klass);
140 object_class->finalize = gl_view_text_finalize;
142 gl_debug (DEBUG_VIEW, "END");
146 gl_view_text_instance_init (glViewText *view_text)
148 gl_debug (DEBUG_VIEW, "START");
150 view_text->private = g_new0 (glViewTextPrivate, 1);
152 gl_debug (DEBUG_VIEW, "END");
156 gl_view_text_finalize (GObject *object)
160 gl_debug (DEBUG_VIEW, "START");
162 g_return_if_fail (object && GL_IS_VIEW_TEXT (object));
164 G_OBJECT_CLASS (parent_class)->finalize (object);
166 gl_debug (DEBUG_VIEW, "END");
169 /*****************************************************************************/
170 /* NEW text object view. */
171 /*****************************************************************************/
173 gl_view_text_new (glLabelText *object,
176 glViewText *view_text;
180 gl_debug (DEBUG_VIEW, "START");
181 g_return_if_fail (object && GL_IS_LABEL_TEXT (object));
182 g_return_if_fail (view && GL_IS_VIEW (view));
184 view_text = g_object_new (gl_view_text_get_type(), NULL);
186 gl_view_object_set_view (GL_VIEW_OBJECT(view_text), view);
187 gl_view_object_set_object (GL_VIEW_OBJECT(view_text),
188 GL_LABEL_OBJECT(object),
189 GL_VIEW_HIGHLIGHT_SIMPLE);
191 /* Create analogous canvas item. */
192 draw_hacktext (view_text);
194 g_signal_connect (G_OBJECT (object), "changed",
195 G_CALLBACK (update_view_text_cb), view_text);
197 /* Create a dialog for controlling/viewing object properties. */
198 dialog = construct_properties_dialog (view_text);
199 gl_view_object_set_dialog (GL_VIEW_OBJECT(view_text), dialog);
201 gl_debug (DEBUG_VIEW, "END");
203 return GL_VIEW_OBJECT (view_text);
206 /*---------------------------------------------------------------------------*/
207 /* PRIVATE. label object "changed" callback. */
208 /*---------------------------------------------------------------------------*/
210 update_view_text_cb (glLabelObject *object,
211 glViewText *view_text)
215 gl_debug (DEBUG_VIEW, "START");
217 view = gl_view_object_get_view (GL_VIEW_OBJECT(view_text));
219 /* Adjust appearance of analogous canvas item. */
220 draw_hacktext (view_text);
222 /* Adjust highlight */
223 gl_view_object_update_highlight (GL_VIEW_OBJECT(view_text));
225 gl_debug (DEBUG_VIEW, "END");
228 /*****************************************************************************/
229 /* Create a properties dialog for a text object. */
230 /*****************************************************************************/
232 construct_properties_dialog (glViewText *view_text)
234 GtkWidget *dialog, *notebook, *wvbox, *wbutton;
235 BonoboWindow *win = glabels_get_active_window ();
236 glLabelObject *object;
237 gdouble x, y, w, h, label_width, label_height;
241 GnomeFontWeight font_weight;
242 gboolean font_italic_flag;
244 GtkJustification just;
247 gl_debug (DEBUG_VIEW, "START");
249 /* retrieve object and query parameters */
250 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_text));
251 gl_label_object_get_position (GL_LABEL_OBJECT(object), &x, &y);
252 lines = gl_label_text_get_lines(GL_LABEL_TEXT(object));
253 gl_label_text_get_props (GL_LABEL_TEXT(object),
254 &font_family, &font_size,
255 &font_weight, &font_italic_flag,
257 gl_label_get_size (GL_LABEL(object->parent),
258 &label_width, &label_height);
259 merge = gl_label_get_merge (GL_LABEL(object->parent));
261 /*-----------------------------------------------------------------*/
262 /* Build dialog with notebook. */
263 /*-----------------------------------------------------------------*/
264 gl_debug (DEBUG_VIEW, "Creating dialog...");
265 dialog = gtk_dialog_new_with_buttons ( _("Edit text object properties"),
267 GTK_DIALOG_DESTROY_WITH_PARENT,
271 g_signal_connect (G_OBJECT (dialog), "response",
272 G_CALLBACK (response_cb), view_text);
274 notebook = gtk_notebook_new ();
275 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
276 notebook, TRUE, TRUE, 0);
278 /*---------------------------*/
279 /* Text Notebook Tab */
280 /*---------------------------*/
281 gl_debug (DEBUG_VIEW, "Creating text tab...");
282 wvbox = gtk_vbox_new (FALSE, GNOME_PAD);
283 gtk_container_set_border_width (GTK_CONTAINER (wvbox), 10);
284 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), wvbox,
285 gtk_label_new (_("Text")));
288 gl_debug (DEBUG_VIEW, "Creating text entry...");
289 view_text->private->text_entry =
290 gl_wdgt_text_entry_new ("Text", merge->field_defs);
291 gl_debug (DEBUG_VIEW, "1");
292 gl_wdgt_text_entry_set_text (GL_WDGT_TEXT_ENTRY(view_text->private->text_entry),
293 (merge->type != GL_MERGE_NONE),
295 gl_debug (DEBUG_VIEW, "2");
296 gtk_box_pack_start (GTK_BOX (wvbox), view_text->private->text_entry,
298 gl_debug (DEBUG_VIEW, "3");
299 g_signal_connect ( G_OBJECT(view_text->private->text_entry),
300 "changed", G_CALLBACK (text_entry_changed_cb),
304 /*---------------------------*/
305 /* Text Props Notebook Tab */
306 /*---------------------------*/
307 gl_debug (DEBUG_VIEW, "Creating props tab...");
308 wvbox = gtk_vbox_new (FALSE, GNOME_PAD);
309 gtk_container_set_border_width (GTK_CONTAINER (wvbox), 10);
310 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), wvbox,
311 gtk_label_new (_("Appearance")));
313 /* text props entry */
314 gl_debug (DEBUG_VIEW, "Creating props entry...");
315 view_text->private->text_props =
316 gl_wdgt_text_props_new ("Text Properties");
317 gl_wdgt_text_props_set_params (GL_WDGT_TEXT_PROPS(view_text->private->text_props),
318 font_family, font_size, font_weight,
319 font_italic_flag, color, just);
320 gtk_box_pack_start (GTK_BOX (wvbox), view_text->private->text_props,
322 g_signal_connect ( G_OBJECT(view_text->private->text_props),
323 "changed", G_CALLBACK (text_props_changed_cb),
327 /*----------------------------*/
328 /* Position/Size Notebook Tab */
329 /*----------------------------*/
330 gl_debug (DEBUG_VIEW, "Creating position tab...");
331 wvbox = gtk_vbox_new (FALSE, GNOME_PAD);
332 gtk_container_set_border_width (GTK_CONTAINER (wvbox), 10);
333 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), wvbox,
334 gtk_label_new (_("Position")));
336 /* ------ Position Frame ------ */
337 gl_debug (DEBUG_VIEW, "Creating position entry...");
338 view_text->private->position = gl_wdgt_position_new (_("Position"));
339 gl_wdgt_position_set_params (GL_WDGT_POSITION (view_text->private->position),
341 label_width, label_height);
342 gtk_box_pack_start (GTK_BOX (wvbox),
343 view_text->private->position,
345 g_signal_connect (G_OBJECT (view_text->private->position),
347 G_CALLBACK(position_changed_cb), view_text);
350 /*----------------------------*/
351 /* Track object changes. */
352 /*----------------------------*/
353 g_signal_connect (G_OBJECT (object), "changed",
354 G_CALLBACK (update_dialog_cb), view_text);
356 gl_debug (DEBUG_VIEW, "END");
361 /*---------------------------------------------------------------------------*/
362 /* PRIVATE. "Response" callback. */
363 /*---------------------------------------------------------------------------*/
365 response_cb (GtkDialog *dialog,
367 glViewText *view_text)
369 gl_debug (DEBUG_VIEW, "START");
371 g_return_if_fail(dialog != NULL);
372 g_return_if_fail(GTK_IS_DIALOG(dialog));
375 case GTK_RESPONSE_CLOSE:
376 gtk_widget_hide (GTK_WIDGET(dialog));
379 g_assert_not_reached();
382 gl_debug (DEBUG_VIEW, "END");
385 /*---------------------------------------------------------------------------*/
386 /* PRIVATE. text_entry "changed" callback. */
387 /*---------------------------------------------------------------------------*/
389 text_entry_changed_cb (glWdgtTextEntry *text_entry,
390 glViewText *view_text)
392 glLabelObject *object;
395 gl_debug (DEBUG_VIEW, "START");
397 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_text));
399 lines = gl_wdgt_text_entry_get_text (text_entry);
401 g_signal_handlers_block_by_func (G_OBJECT(object),
402 update_dialog_cb, view_text);
403 gl_label_text_set_lines (GL_LABEL_TEXT(object), lines);
404 g_signal_handlers_unblock_by_func (G_OBJECT(object),
405 update_dialog_cb, view_text);
407 gl_text_node_lines_free (&lines);
409 gl_debug (DEBUG_VIEW, "END");
412 /*---------------------------------------------------------------------------*/
413 /* PRIVATE. text_props "changed" callback. */
414 /*---------------------------------------------------------------------------*/
416 text_props_changed_cb (glWdgtTextProps *text_props,
417 glViewText *view_text)
419 glLabelObject *object;
422 GnomeFontWeight font_weight;
423 gboolean font_italic_flag;
425 GtkJustification just;
428 gl_debug (DEBUG_VIEW, "START");
430 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_text));
432 gl_wdgt_text_props_get_params (text_props,
433 &font_family, &font_size, &font_weight,
437 g_signal_handlers_block_by_func (G_OBJECT(object),
438 update_dialog_cb, view_text);
439 gl_label_text_set_props (GL_LABEL_TEXT(object),
440 font_family, font_size, font_weight,
443 g_signal_handlers_unblock_by_func (G_OBJECT(object),
444 update_dialog_cb, view_text);
446 g_free (font_family);
448 gl_debug (DEBUG_VIEW, "END");
451 /*---------------------------------------------------------------------------*/
452 /* PRIVATE. position "changed" callback. */
453 /*---------------------------------------------------------------------------*/
455 position_changed_cb (glWdgtPosition *position,
456 glViewText *view_text)
458 glLabelObject *object;
461 gl_debug (DEBUG_VIEW, "START");
463 gl_wdgt_position_get_position (GL_WDGT_POSITION (position), &x, &y);
465 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_text));
467 g_signal_handlers_block_by_func (G_OBJECT(object),
468 update_dialog_cb, view_text);
469 gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y);
470 g_signal_handlers_unblock_by_func (G_OBJECT(object),
471 update_dialog_cb, view_text);
473 gl_debug (DEBUG_VIEW, "END");
476 /*---------------------------------------------------------------------------*/
477 /* PRIVATE. label object "changed" callback. */
478 /*---------------------------------------------------------------------------*/
480 update_dialog_cb (glLabelObject *object,
481 glViewText *view_text)
488 GnomeFontWeight font_weight;
489 gboolean font_italic_flag;
491 GtkJustification just;
493 gl_debug (DEBUG_VIEW, "START");
495 /* Query properties of object. */
496 lines = gl_label_text_get_lines(GL_LABEL_TEXT(object));
497 gl_label_text_get_props (GL_LABEL_TEXT(object),
498 &font_family, &font_size,
499 &font_weight, &font_italic_flag,
501 gl_label_object_get_position (GL_LABEL_OBJECT(object), &x, &y);
502 merge = gl_label_get_merge (GL_LABEL(object->parent));
504 /* Block widget handlers to prevent recursion */
505 g_signal_handlers_block_by_func (G_OBJECT(view_text->private->text_entry),
506 text_entry_changed_cb, view_text);
507 g_signal_handlers_block_by_func (G_OBJECT(view_text->private->text_props),
508 text_props_changed_cb, view_text);
509 g_signal_handlers_block_by_func (G_OBJECT(view_text->private->position),
510 position_changed_cb, view_text);
512 /* Update widgets in property dialog */
514 gl_wdgt_text_entry_set_text (GL_WDGT_TEXT_ENTRY(view_text->private->text_entry),
515 (merge->type != GL_MERGE_NONE),
517 gl_wdgt_text_props_set_params (GL_WDGT_TEXT_PROPS(view_text->private->text_props),
518 font_family, font_size, font_weight,
519 font_italic_flag, color, just);
520 gl_wdgt_position_set_position (GL_WDGT_POSITION(view_text->private->position),
523 /* Unblock widget handlers */
524 g_signal_handlers_unblock_by_func (G_OBJECT(view_text->private->text_entry),
525 text_entry_changed_cb, view_text);
526 g_signal_handlers_unblock_by_func (G_OBJECT(view_text->private->text_props),
527 text_props_changed_cb, view_text);
528 g_signal_handlers_unblock_by_func (G_OBJECT(view_text->private->position),
529 position_changed_cb, view_text);
531 gl_text_node_lines_free (&lines);
533 gl_debug (DEBUG_VIEW, "END");
536 /*****************************************************************************/
537 /* Return apropos cursor for create object mode. */
538 /*****************************************************************************/
540 gl_view_text_get_create_cursor (void)
542 static GdkCursor *cursor = NULL;
543 GdkPixmap *pixmap_data, *pixmap_mask;
544 GdkColor fg = { 0, 0, 0, 0 };
545 GdkColor bg = { 0, 65535, 65535, 65535 };
547 gl_debug (DEBUG_VIEW, "START");
550 pixmap_data = gdk_bitmap_create_from_data (NULL,
554 pixmap_mask = gdk_bitmap_create_from_data (NULL,
555 cursor_text_mask_bits,
556 cursor_text_mask_width,
557 cursor_text_mask_height);
559 gdk_cursor_new_from_pixmap (pixmap_data, pixmap_mask, &fg,
560 &bg, cursor_text_x_hot,
564 gl_debug (DEBUG_VIEW, "END");
569 /*****************************************************************************/
570 /* Canvas event handler for creating text objects. */
571 /*****************************************************************************/
573 gl_view_text_create_event_handler (GnomeCanvas *canvas,
577 static gdouble x0, y0;
578 static gboolean dragging = FALSE;
579 static glViewObject *view_text;
580 static GObject *object;
584 gl_debug (DEBUG_VIEW, "");
586 switch (event->type) {
588 case GDK_BUTTON_PRESS:
589 gl_debug (DEBUG_VIEW, "BUTTON_PRESS");
590 switch (event->button.button) {
593 gdk_pointer_grab (GTK_WIDGET (view->canvas)->window,
595 GDK_POINTER_MOTION_MASK |
596 GDK_BUTTON_RELEASE_MASK |
597 GDK_BUTTON_PRESS_MASK,
598 NULL, NULL, event->button.time);
599 gnome_canvas_window_to_world (canvas,
601 event->button.y, &x, &y);
602 object = gl_label_text_new (view->label);
603 gl_label_object_set_position (GL_LABEL_OBJECT(object),
605 lines = gl_text_node_lines_new_from_text (_("Text"));
606 gl_label_text_set_lines (GL_LABEL_TEXT(object), lines);
607 view_text = gl_view_text_new (GL_LABEL_TEXT(object),
617 case GDK_BUTTON_RELEASE:
618 gl_debug (DEBUG_VIEW, "BUTTON_RELEASE");
619 switch (event->button.button) {
622 gdk_pointer_ungrab (event->button.time);
623 gnome_canvas_window_to_world (canvas,
625 event->button.y, &x, &y);
626 gl_label_object_set_position (GL_LABEL_OBJECT(object),
628 gl_view_unselect_all (view);
629 gl_view_object_select (GL_VIEW_OBJECT(view_text));
630 gl_view_arrow_mode (view);
637 case GDK_MOTION_NOTIFY:
638 gl_debug (DEBUG_VIEW, "MOTION_NOTIFY");
639 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
640 gnome_canvas_window_to_world (canvas,
642 event->button.y, &x, &y);
643 gl_label_object_set_position (GL_LABEL_OBJECT(object),
656 /*--------------------------------------------------------------------------*/
657 /* PRIVATE. Draw hacktext to item (group). */
658 /*--------------------------------------------------------------------------*/
660 draw_hacktext (glViewText *view_text)
662 glLabelObject *object;
663 GnomeCanvasItem *group, *item;
667 GnomeFontWeight font_weight;
668 gboolean font_italic_flag;
671 GtkJustification just;
673 GnomeGlyphList *glyphlist;
676 gdouble x_offset, y_offset, w, object_w, object_h;
681 gl_debug (DEBUG_VIEW, "START");
683 /* Query label object and properties */
684 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_text));
685 gl_label_object_get_size (object, &object_w, &object_h);
686 gl_label_text_get_props (GL_LABEL_TEXT(object),
687 &font_family, &font_size,
688 &font_weight, &font_italic_flag,
690 lines = gl_label_text_get_lines(GL_LABEL_TEXT(object));
691 text = gl_text_node_lines_expand (lines, NULL);
692 line = g_strsplit (text, "\n", -1);
694 /* get parent item/group to render to. */
695 group = gl_view_object_get_group (GL_VIEW_OBJECT(view_text));
697 /* remove previous items from group. */
698 for (li = view_text->private->item_list; li != NULL; li = li->next) {
699 gl_debug (DEBUG_VIEW, "in loop");
700 gtk_object_destroy (GTK_OBJECT (li->data));
702 gl_debug (DEBUG_VIEW, "1");
703 g_list_free (view_text->private->item_list);
704 view_text->private->item_list = NULL;
705 gl_debug (DEBUG_VIEW, "2");
708 font = gnome_font_find_closest_from_weight_slant (font_family,
712 art_affine_identity (affine);
714 /* render to group, one item per line. */
715 for (i = 0; line[i] != NULL; i++) {
717 glyphlist = gnome_glyphlist_from_text_dumb (font, color,
721 gnome_glyphlist_bbox (glyphlist, affine, 0, &bbox);
725 case GTK_JUSTIFY_LEFT:
728 case GTK_JUSTIFY_CENTER:
729 x_offset = (object_w - w) / 2.0;
731 case GTK_JUSTIFY_RIGHT:
732 x_offset = object_w - w;
736 break; /* shouldn't happen */
740 (i + 1) * font_size + gnome_font_get_descender (font);
742 item = gnome_canvas_item_new (GNOME_CANVAS_GROUP (group),
743 gl_canvas_hacktext_get_type (),
746 "glyphlist", glyphlist, NULL);
747 view_text->private->item_list =
748 g_list_prepend (view_text->private->item_list, item);
754 gl_text_node_lines_free (&lines);
757 gl_debug (DEBUG_VIEW, "END");