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"
29 #include "view-highlight.h"
30 #include "wdgt-text-entry.h"
31 #include "wdgt-text-props.h"
32 #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 update_dialog_from_move_cb (glLabelObject *object,
103 glViewText *view_text);
105 static void draw_hacktext (glViewText *view_text);
108 /*****************************************************************************/
109 /* Boilerplate object stuff. */
110 /*****************************************************************************/
112 gl_view_text_get_type (void)
114 static GType type = 0;
118 sizeof (glViewTextClass),
121 (GClassInitFunc) gl_view_text_class_init,
126 (GInstanceInitFunc) gl_view_text_instance_init,
129 type = g_type_register_static (GL_TYPE_VIEW_OBJECT,
130 "glViewText", &info, 0);
137 gl_view_text_class_init (glViewTextClass *klass)
139 GObjectClass *object_class = (GObjectClass *) klass;
141 gl_debug (DEBUG_VIEW, "START");
143 parent_class = g_type_class_peek_parent (klass);
145 object_class->finalize = gl_view_text_finalize;
147 gl_debug (DEBUG_VIEW, "END");
151 gl_view_text_instance_init (glViewText *view_text)
153 gl_debug (DEBUG_VIEW, "START");
155 view_text->private = g_new0 (glViewTextPrivate, 1);
157 gl_debug (DEBUG_VIEW, "END");
161 gl_view_text_finalize (GObject *object)
165 gl_debug (DEBUG_VIEW, "START");
167 g_return_if_fail (object && GL_IS_VIEW_TEXT (object));
169 G_OBJECT_CLASS (parent_class)->finalize (object);
171 gl_debug (DEBUG_VIEW, "END");
174 /*****************************************************************************/
175 /* NEW text object view. */
176 /*****************************************************************************/
178 gl_view_text_new (glLabelText *object,
181 glViewText *view_text;
184 gl_debug (DEBUG_VIEW, "START");
185 g_return_if_fail (object && GL_IS_LABEL_TEXT (object));
186 g_return_if_fail (view && GL_IS_VIEW (view));
188 view_text = g_object_new (gl_view_text_get_type(), NULL);
190 gl_view_object_set_view (GL_VIEW_OBJECT(view_text), view);
191 gl_view_object_set_object (GL_VIEW_OBJECT(view_text),
192 GL_LABEL_OBJECT(object),
193 GL_VIEW_HIGHLIGHT_SIMPLE);
195 /* Create analogous canvas item. */
196 draw_hacktext (view_text);
198 g_signal_connect (G_OBJECT (object), "changed",
199 G_CALLBACK (update_view_text_cb), view_text);
201 /* Create a dialog for controlling/viewing object properties. */
202 gl_view_object_set_dlg_constructor (GL_VIEW_OBJECT(view_text),
203 GL_VIEW_OBJECT_DLG_CONSTRUCTOR(construct_properties_dialog));
205 gl_debug (DEBUG_VIEW, "END");
207 return GL_VIEW_OBJECT (view_text);
210 /*---------------------------------------------------------------------------*/
211 /* PRIVATE. label object "changed" callback. */
212 /*---------------------------------------------------------------------------*/
214 update_view_text_cb (glLabelObject *object,
215 glViewText *view_text)
217 gl_debug (DEBUG_VIEW, "START");
219 /* Adjust appearance of analogous canvas item. */
220 draw_hacktext (view_text);
222 gl_debug (DEBUG_VIEW, "END");
225 /*****************************************************************************/
226 /* Create a properties dialog for a text object. */
227 /*****************************************************************************/
229 construct_properties_dialog (glViewText *view_text)
231 GtkWidget *dialog, *wsection, *wbutton;
232 glLabelObject *object;
233 gdouble x, y, w, h, label_width, label_height;
237 GnomeFontWeight font_weight;
238 gboolean font_italic_flag;
240 GtkJustification just;
242 GtkSizeGroup *label_size_group;
245 gl_debug (DEBUG_VIEW, "START");
247 /* retrieve object and query parameters */
248 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_text));
249 gl_label_object_get_position (GL_LABEL_OBJECT(object), &x, &y);
250 lines = gl_label_text_get_lines(GL_LABEL_TEXT(object));
251 gl_label_text_get_props (GL_LABEL_TEXT(object),
252 &font_family, &font_size,
253 &font_weight, &font_italic_flag,
255 gl_label_get_size (GL_LABEL(object->parent),
256 &label_width, &label_height);
257 merge = gl_label_get_merge (GL_LABEL(object->parent));
259 /*-----------------------------------------------------------------*/
261 /*-----------------------------------------------------------------*/
262 window = gtk_widget_get_toplevel (
263 GTK_WIDGET(gl_view_object_get_view(GL_VIEW_OBJECT(view_text))));
264 dialog = gl_hig_dialog_new_with_buttons ( _("Edit text object properties"),
266 GTK_DIALOG_DESTROY_WITH_PARENT,
270 gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
271 g_signal_connect (G_OBJECT (dialog), "response",
272 G_CALLBACK (response_cb), view_text);
274 label_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
276 /*---------------------------*/
278 /*---------------------------*/
279 wsection = gl_hig_category_new (_("Text"));
280 gl_hig_dialog_add_widget (GL_HIG_DIALOG(dialog), wsection);
281 view_text->private->text_entry =
282 gl_wdgt_text_entry_new (merge->field_defs);
283 gl_wdgt_text_entry_set_label_size_group (GL_WDGT_TEXT_ENTRY(view_text->private->text_entry),
285 gl_wdgt_text_entry_set_text (GL_WDGT_TEXT_ENTRY(view_text->private->text_entry),
286 (merge->type != GL_MERGE_NONE),
288 gl_hig_category_add_widget (GL_HIG_CATEGORY(wsection),
289 view_text->private->text_entry);
290 g_signal_connect ( G_OBJECT(view_text->private->text_entry),
291 "changed", G_CALLBACK (text_entry_changed_cb),
295 /*---------------------------*/
296 /* Text Properties section */
297 /*---------------------------*/
298 wsection = gl_hig_category_new (_("Properties"));
299 gl_hig_dialog_add_widget (GL_HIG_DIALOG(dialog), wsection);
300 view_text->private->text_props = gl_wdgt_text_props_new ();
301 gl_wdgt_text_props_set_label_size_group (GL_WDGT_TEXT_PROPS(view_text->private->text_props),
303 gl_wdgt_text_props_set_params (GL_WDGT_TEXT_PROPS(view_text->private->text_props),
304 font_family, font_size, font_weight,
305 font_italic_flag, color, just);
306 gl_hig_category_add_widget (GL_HIG_CATEGORY(wsection),
307 view_text->private->text_props);
308 g_signal_connect ( G_OBJECT(view_text->private->text_props),
309 "changed", G_CALLBACK (text_props_changed_cb),
313 /*----------------------------*/
314 /* Position section */
315 /*----------------------------*/
316 wsection = gl_hig_category_new (_("Position"));
317 gl_hig_dialog_add_widget (GL_HIG_DIALOG(dialog), wsection);
318 view_text->private->position = gl_wdgt_position_new ();
319 gl_wdgt_position_set_label_size_group (GL_WDGT_POSITION(view_text->private->position),
321 gl_wdgt_position_set_params (GL_WDGT_POSITION (view_text->private->position),
323 label_width, label_height);
324 gl_hig_category_add_widget (GL_HIG_CATEGORY(wsection),
325 view_text->private->position);
326 g_signal_connect (G_OBJECT (view_text->private->position),
328 G_CALLBACK(position_changed_cb), view_text);
331 /*----------------------------*/
332 /* Track object changes. */
333 /*----------------------------*/
334 g_signal_connect (G_OBJECT (object), "changed",
335 G_CALLBACK (update_dialog_cb), view_text);
336 g_signal_connect (G_OBJECT (object), "moved",
337 G_CALLBACK (update_dialog_from_move_cb), view_text);
339 gl_debug (DEBUG_VIEW, "END");
344 /*---------------------------------------------------------------------------*/
345 /* PRIVATE. "Response" callback. */
346 /*---------------------------------------------------------------------------*/
348 response_cb (GtkDialog *dialog,
350 glViewText *view_text)
352 gl_debug (DEBUG_VIEW, "START");
354 g_return_if_fail(dialog != NULL);
355 g_return_if_fail(GTK_IS_DIALOG(dialog));
358 case GTK_RESPONSE_CLOSE:
359 gtk_widget_hide (GTK_WIDGET(dialog));
361 case GTK_RESPONSE_DELETE_EVENT:
364 g_print ("response = %d", response);
365 g_assert_not_reached();
368 gl_debug (DEBUG_VIEW, "END");
371 /*---------------------------------------------------------------------------*/
372 /* PRIVATE. text_entry "changed" callback. */
373 /*---------------------------------------------------------------------------*/
375 text_entry_changed_cb (glWdgtTextEntry *text_entry,
376 glViewText *view_text)
378 glLabelObject *object;
381 gl_debug (DEBUG_VIEW, "START");
383 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_text));
385 lines = gl_wdgt_text_entry_get_text (text_entry);
387 g_signal_handlers_block_by_func (G_OBJECT(object),
388 update_dialog_cb, view_text);
389 gl_label_text_set_lines (GL_LABEL_TEXT(object), lines);
390 g_signal_handlers_unblock_by_func (G_OBJECT(object),
391 update_dialog_cb, view_text);
393 gl_text_node_lines_free (&lines);
395 gl_debug (DEBUG_VIEW, "END");
398 /*---------------------------------------------------------------------------*/
399 /* PRIVATE. text_props "changed" callback. */
400 /*---------------------------------------------------------------------------*/
402 text_props_changed_cb (glWdgtTextProps *text_props,
403 glViewText *view_text)
405 glLabelObject *object;
408 GnomeFontWeight font_weight;
409 gboolean font_italic_flag;
411 GtkJustification just;
414 gl_debug (DEBUG_VIEW, "START");
416 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_text));
418 gl_wdgt_text_props_get_params (text_props,
419 &font_family, &font_size, &font_weight,
423 g_signal_handlers_block_by_func (G_OBJECT(object),
424 update_dialog_cb, view_text);
425 gl_label_text_set_props (GL_LABEL_TEXT(object),
426 font_family, font_size, font_weight,
429 g_signal_handlers_unblock_by_func (G_OBJECT(object),
430 update_dialog_cb, view_text);
432 g_free (font_family);
434 gl_debug (DEBUG_VIEW, "END");
437 /*---------------------------------------------------------------------------*/
438 /* PRIVATE. position "changed" callback. */
439 /*---------------------------------------------------------------------------*/
441 position_changed_cb (glWdgtPosition *position,
442 glViewText *view_text)
444 glLabelObject *object;
447 gl_debug (DEBUG_VIEW, "START");
449 gl_wdgt_position_get_position (GL_WDGT_POSITION (position), &x, &y);
451 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_text));
453 g_signal_handlers_block_by_func (G_OBJECT(object),
454 update_dialog_cb, view_text);
455 gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y);
456 g_signal_handlers_unblock_by_func (G_OBJECT(object),
457 update_dialog_cb, view_text);
459 gl_debug (DEBUG_VIEW, "END");
462 /*---------------------------------------------------------------------------*/
463 /* PRIVATE. label object "changed" callback. */
464 /*---------------------------------------------------------------------------*/
466 update_dialog_cb (glLabelObject *object,
467 glViewText *view_text)
474 GnomeFontWeight font_weight;
475 gboolean font_italic_flag;
477 GtkJustification just;
479 gl_debug (DEBUG_VIEW, "START");
481 /* Query properties of object. */
482 lines = gl_label_text_get_lines(GL_LABEL_TEXT(object));
483 gl_label_text_get_props (GL_LABEL_TEXT(object),
484 &font_family, &font_size,
485 &font_weight, &font_italic_flag,
487 gl_label_object_get_position (GL_LABEL_OBJECT(object), &x, &y);
488 merge = gl_label_get_merge (GL_LABEL(object->parent));
490 /* Block widget handlers to prevent recursion */
491 g_signal_handlers_block_by_func (G_OBJECT(view_text->private->text_entry),
492 text_entry_changed_cb, view_text);
493 g_signal_handlers_block_by_func (G_OBJECT(view_text->private->text_props),
494 text_props_changed_cb, view_text);
495 g_signal_handlers_block_by_func (G_OBJECT(view_text->private->position),
496 position_changed_cb, view_text);
498 /* Update widgets in property dialog */
500 gl_wdgt_text_entry_set_text (GL_WDGT_TEXT_ENTRY(view_text->private->text_entry),
501 (merge->type != GL_MERGE_NONE),
503 gl_wdgt_text_entry_set_field_defs (GL_WDGT_TEXT_ENTRY(view_text->private->text_entry),
505 gl_wdgt_text_props_set_params (GL_WDGT_TEXT_PROPS(view_text->private->text_props),
506 font_family, font_size, font_weight,
507 font_italic_flag, color, just);
508 gl_wdgt_position_set_position (GL_WDGT_POSITION(view_text->private->position),
511 /* Unblock widget handlers */
512 g_signal_handlers_unblock_by_func (G_OBJECT(view_text->private->text_entry),
513 text_entry_changed_cb, view_text);
514 g_signal_handlers_unblock_by_func (G_OBJECT(view_text->private->text_props),
515 text_props_changed_cb, view_text);
516 g_signal_handlers_unblock_by_func (G_OBJECT(view_text->private->position),
517 position_changed_cb, view_text);
519 gl_text_node_lines_free (&lines);
521 gl_debug (DEBUG_VIEW, "END");
524 /*---------------------------------------------------------------------------*/
525 /* PRIVATE. label object "moved" callback. */
526 /*---------------------------------------------------------------------------*/
528 update_dialog_from_move_cb (glLabelObject *object,
531 glViewText *view_text)
535 gl_debug (DEBUG_VIEW, "START");
537 /* Query properties of object. */
538 gl_label_object_get_position (GL_LABEL_OBJECT(object), &x, &y);
540 /* Block widget handlers to prevent recursion */
541 g_signal_handlers_block_by_func (G_OBJECT(view_text->private->position),
542 position_changed_cb, view_text);
544 /* Update widgets in property dialog */
545 gl_wdgt_position_set_position (GL_WDGT_POSITION(view_text->private->position),
548 /* Unblock widget handlers */
549 g_signal_handlers_unblock_by_func (G_OBJECT(view_text->private->position),
550 position_changed_cb, view_text);
552 gl_debug (DEBUG_VIEW, "END");
555 /*****************************************************************************/
556 /* Return apropos cursor for create object mode. */
557 /*****************************************************************************/
559 gl_view_text_get_create_cursor (void)
561 static GdkCursor *cursor = NULL;
562 GdkPixmap *pixmap_data, *pixmap_mask;
563 GdkColor fg = { 0, 0, 0, 0 };
564 GdkColor bg = { 0, 65535, 65535, 65535 };
566 gl_debug (DEBUG_VIEW, "START");
569 pixmap_data = gdk_bitmap_create_from_data (NULL,
573 pixmap_mask = gdk_bitmap_create_from_data (NULL,
574 cursor_text_mask_bits,
575 cursor_text_mask_width,
576 cursor_text_mask_height);
578 gdk_cursor_new_from_pixmap (pixmap_data, pixmap_mask, &fg,
579 &bg, cursor_text_x_hot,
583 gl_debug (DEBUG_VIEW, "END");
588 /*****************************************************************************/
589 /* Canvas event handler for creating text objects. */
590 /*****************************************************************************/
592 gl_view_text_create_event_handler (GnomeCanvas *canvas,
596 static gdouble x0, y0;
597 static gboolean dragging = FALSE;
598 static glViewObject *view_text;
599 static GObject *object;
603 gl_debug (DEBUG_VIEW, "");
605 switch (event->type) {
607 case GDK_BUTTON_PRESS:
608 gl_debug (DEBUG_VIEW, "BUTTON_PRESS");
609 switch (event->button.button) {
612 gnome_canvas_item_grab (canvas->root,
613 GDK_POINTER_MOTION_MASK |
614 GDK_BUTTON_RELEASE_MASK |
615 GDK_BUTTON_PRESS_MASK,
616 NULL, event->button.time);
617 gnome_canvas_window_to_world (canvas,
619 event->button.y, &x, &y);
620 object = gl_label_text_new (view->label);
621 gl_label_object_set_position (GL_LABEL_OBJECT(object),
623 gl_label_text_set_props (GL_LABEL_TEXT(object),
624 gl_prefs->default_font_family,
625 gl_prefs->default_font_size,
626 gl_prefs->default_font_weight,
627 gl_prefs->default_font_italic_flag,
628 gl_color_set_opacity (gl_prefs->default_text_color, 0.5),
629 gl_prefs->default_text_alignment);
630 lines = gl_text_node_lines_new_from_text (_("Text"));
631 gl_label_text_set_lines (GL_LABEL_TEXT(object), lines);
632 view_text = gl_view_text_new (GL_LABEL_TEXT(object),
642 case GDK_BUTTON_RELEASE:
643 gl_debug (DEBUG_VIEW, "BUTTON_RELEASE");
644 switch (event->button.button) {
647 gnome_canvas_item_ungrab (canvas->root, event->button.time);
648 gnome_canvas_window_to_world (canvas,
650 event->button.y, &x, &y);
651 gl_label_object_set_position (GL_LABEL_OBJECT(object),
653 gl_label_text_set_props (GL_LABEL_TEXT(object),
654 gl_prefs->default_font_family,
655 gl_prefs->default_font_size,
656 gl_prefs->default_font_weight,
657 gl_prefs->default_font_italic_flag,
658 gl_prefs->default_text_color,
659 gl_prefs->default_text_alignment);
660 gl_view_unselect_all (view);
661 gl_view_object_select (GL_VIEW_OBJECT(view_text));
662 gl_view_arrow_mode (view);
669 case GDK_MOTION_NOTIFY:
670 gl_debug (DEBUG_VIEW, "MOTION_NOTIFY");
671 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
672 gnome_canvas_window_to_world (canvas,
674 event->motion.y, &x, &y);
675 gl_label_object_set_position (GL_LABEL_OBJECT(object),
688 /*--------------------------------------------------------------------------*/
689 /* PRIVATE. Draw hacktext to item (group). */
690 /*--------------------------------------------------------------------------*/
692 draw_hacktext (glViewText *view_text)
694 glLabelObject *object;
695 GnomeCanvasItem *item;
699 GnomeFontWeight font_weight;
700 gboolean font_italic_flag;
703 GtkJustification just;
705 GnomeGlyphList *glyphlist;
708 gdouble x_offset, y_offset, w, object_w, object_h;
713 gl_debug (DEBUG_VIEW, "START");
715 /* Query label object and properties */
716 object = gl_view_object_get_object (GL_VIEW_OBJECT(view_text));
717 gl_label_object_get_size (object, &object_w, &object_h);
718 gl_label_text_get_props (GL_LABEL_TEXT(object),
719 &font_family, &font_size,
720 &font_weight, &font_italic_flag,
722 lines = gl_label_text_get_lines(GL_LABEL_TEXT(object));
723 text = gl_text_node_lines_expand (lines, NULL);
724 line = g_strsplit (text, "\n", -1);
726 /* remove previous items from group. */
727 for (li = view_text->private->item_list; li != NULL; li = li->next) {
728 gl_debug (DEBUG_VIEW, "in loop");
729 gtk_object_destroy (GTK_OBJECT (li->data));
731 gl_debug (DEBUG_VIEW, "1");
732 g_list_free (view_text->private->item_list);
733 view_text->private->item_list = NULL;
734 gl_debug (DEBUG_VIEW, "2");
737 font = gnome_font_find_closest_from_weight_slant (font_family,
741 art_affine_identity (affine);
743 /* render to group, one item per line. */
744 for (i = 0; line[i] != NULL; i++) {
746 glyphlist = gnome_glyphlist_from_text_dumb (font, color,
750 gnome_glyphlist_bbox (glyphlist, affine, 0, &bbox);
754 case GTK_JUSTIFY_LEFT:
757 case GTK_JUSTIFY_CENTER:
758 x_offset = (object_w - w) / 2.0;
760 case GTK_JUSTIFY_RIGHT:
761 x_offset = object_w - w;
765 break; /* shouldn't happen */
769 (i + 1) * font_size + gnome_font_get_descender (font);
771 item = gl_view_object_item_new (GL_VIEW_OBJECT(view_text),
772 gl_canvas_hacktext_get_type (),
775 "glyphlist", glyphlist, NULL);
776 view_text->private->item_list =
777 g_list_prepend (view_text->private->item_list, item);
783 gl_text_node_lines_free (&lines);
786 gl_debug (DEBUG_VIEW, "END");