]> git.sur5r.net Git - glabels/blob - glabels2/src/view-text.c
Created generic "get" methods for text, fill and line properties for all label object...
[glabels] / glabels2 / src / view-text.c
1 /*
2  *  (GLABELS) Label and Business Card Creation program for GNOME
3  *
4  *  view_text.c:  GLabels label text object widget
5  *
6  *  Copyright (C) 2001-2003  Jim Evins <evins@snaught.com>.
7  *
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.
12  *
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.
17  *
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
21  */
22
23 #include <glib.h>
24
25 #include <libgnomeprint/gnome-glyphlist.h>
26
27 #include "view-text.h"
28 #include "canvas-hacktext.h"
29 #include "view-highlight.h"
30
31 #include "color.h"
32 #include "object-editor.h"
33 #include "stock.h"
34
35 #include "pixmaps/cursor_text.xbm"
36 #include "pixmaps/cursor_text_mask.xbm"
37
38 #include "debug.h"
39
40 /*========================================================*/
41 /* Private macros and constants.                          */
42 /*========================================================*/
43
44 #define CURSOR_COLOR    GL_COLOR_A (0, 0, 255, 128)
45
46 #define CURSOR_ON_TIME  800
47 #define CURSOR_OFF_TIME 400
48
49 /*========================================================*/
50 /* Private types.                                         */
51 /*========================================================*/
52
53 struct _glViewTextPrivate {
54
55         GList           *item_list;
56
57         GnomeCanvasItem *cursor;
58         gboolean         cursor_visible;
59         gboolean         cursor_state;
60         guint            cursor_timeout;
61
62 };
63
64 /*========================================================*/
65 /* Private globals.                                       */
66 /*========================================================*/
67
68 static glViewObjectClass *parent_class = NULL;
69
70
71 /*========================================================*/
72 /* Private function prototypes.                           */
73 /*========================================================*/
74
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);
78
79 static GtkWidget *construct_properties_editor        (glViewObject     *view_object);
80
81 static void       update_canvas_item_from_object_cb  (glLabelObject    *object,
82                                                       glViewText       *view_text);
83
84 static void       update_object_from_editor_cb       (glObjectEditor   *editor,
85                                                       glLabelObject    *object);
86
87 static void       update_editor_from_object_cb       (glLabelObject    *object,
88                                                       glObjectEditor   *editor);
89
90 static void       update_editor_from_move_cb         (glLabelObject    *object,
91                                                       gdouble           dx,
92                                                       gdouble           dy,
93                                                       glObjectEditor   *editor);
94
95 static void       update_editor_from_label_cb        (glLabel          *label,
96                                                       glObjectEditor   *editor);
97
98 static void       draw_hacktext                      (glViewText       *view_text);
99
100 static void       draw_cursor                        (glViewText       *view_text);
101
102 static void       mark_set_cb                        (GtkTextBuffer    *textbuffer,
103                                                       GtkTextIter      *iter,
104                                                       GtkTextMark      *mark,
105                                                       glViewText       *view_text);
106
107 static void       blink_start                        (glViewText       *view_text);
108 static void       blink_stop                         (glViewText       *view_text);
109 static gboolean   blink_cb                           (glViewText       *view_text);
110
111 static gint       item_event_cb                      (GnomeCanvasItem  *item,
112                                                       GdkEvent         *event,
113                                                       glViewObject     *view_object);
114
115
116 \f
117 /*****************************************************************************/
118 /* Boilerplate object stuff.                                                 */
119 /*****************************************************************************/
120 GType
121 gl_view_text_get_type (void)
122 {
123         static GType type = 0;
124
125         if (!type) {
126                 GTypeInfo info = {
127                         sizeof (glViewTextClass),
128                         NULL,
129                         NULL,
130                         (GClassInitFunc) gl_view_text_class_init,
131                         NULL,
132                         NULL,
133                         sizeof (glViewText),
134                         0,
135                         (GInstanceInitFunc) gl_view_text_instance_init,
136                 };
137
138                 type = g_type_register_static (GL_TYPE_VIEW_OBJECT,
139                                                "glViewText", &info, 0);
140         }
141
142         return type;
143 }
144
145 static void
146 gl_view_text_class_init (glViewTextClass *klass)
147 {
148         GObjectClass      *object_class      = (GObjectClass *) klass;
149         glViewObjectClass *view_object_class = (glViewObjectClass *) klass;
150
151         gl_debug (DEBUG_VIEW, "START");
152
153         parent_class = g_type_class_peek_parent (klass);
154
155         object_class->finalize = gl_view_text_finalize;
156
157         view_object_class->construct_editor = construct_properties_editor;
158
159         gl_debug (DEBUG_VIEW, "END");
160 }
161
162 static void
163 gl_view_text_instance_init (glViewText *view_text)
164 {
165         gl_debug (DEBUG_VIEW, "START");
166
167         view_text->private = g_new0 (glViewTextPrivate, 1);
168
169         gl_debug (DEBUG_VIEW, "END");
170 }
171
172 static void
173 gl_view_text_finalize (GObject *object)
174 {
175         glLabel       *parent;
176
177         gl_debug (DEBUG_VIEW, "START");
178
179         g_return_if_fail (object && GL_IS_VIEW_TEXT (object));
180
181         G_OBJECT_CLASS (parent_class)->finalize (object);
182
183         gl_debug (DEBUG_VIEW, "END");
184 }
185
186 /*****************************************************************************/
187 /* NEW text object view.                                                     */
188 /*****************************************************************************/
189 glViewObject *
190 gl_view_text_new (glLabelText *object,
191                   glView      *view)
192 {
193         glViewText         *view_text;
194         GtkMenu            *menu;
195         GtkTextBuffer      *buffer;
196         GnomeCanvasItem    *group;
197
198         gl_debug (DEBUG_VIEW, "START");
199         g_return_if_fail (object && GL_IS_LABEL_TEXT (object));
200         g_return_if_fail (view && GL_IS_VIEW (view));
201         
202         view_text = g_object_new (gl_view_text_get_type(), NULL);
203
204         gl_view_object_set_view (GL_VIEW_OBJECT(view_text), view);
205         gl_view_object_set_object (GL_VIEW_OBJECT(view_text),
206                                    GL_LABEL_OBJECT(object),
207                                    GL_VIEW_HIGHLIGHT_BOX_RESIZABLE);
208
209         group = gl_view_object_get_group (GL_VIEW_OBJECT(view_text));
210
211         /* Create analogous canvas item. */
212         draw_hacktext (view_text);
213         draw_cursor (view_text);
214
215         g_signal_connect (G_OBJECT (object), "changed",
216                           G_CALLBACK (update_canvas_item_from_object_cb), view_text);
217
218         g_signal_connect (G_OBJECT (group), "event",
219                           G_CALLBACK (item_event_cb), view_text);
220
221         buffer = gl_label_text_get_buffer (object);
222         g_signal_connect (G_OBJECT (buffer), "mark-set",
223                           G_CALLBACK (mark_set_cb), view_text);
224
225         gl_debug (DEBUG_VIEW, "END");
226
227         return GL_VIEW_OBJECT (view_text);
228 }
229
230 /*****************************************************************************/
231 /* Create a properties editor for a text object.                             */
232 /*****************************************************************************/
233 static GtkWidget *
234 construct_properties_editor (glViewObject *view_object)
235 {
236         GtkWidget          *editor;
237         glViewText          *view_text = (glViewText *)view_object;
238         glLabelObject      *object;
239         GtkTextBuffer      *buffer;
240
241         gl_debug (DEBUG_VIEW, "START");
242
243         object = gl_view_object_get_object (GL_VIEW_OBJECT(view_text));
244
245         /* Build editor. */
246         editor = gl_object_editor_new (GL_STOCK_TEXT, _("Text object properties"),
247                                        GL_OBJECT_EDITOR_POSITION_PAGE,
248                                        GL_OBJECT_EDITOR_SIZE_PAGE,
249                                        GL_OBJECT_EDITOR_TEXT_PAGE,
250                                        GL_OBJECT_EDITOR_EDIT_PAGE,
251                                        0);
252
253         buffer = gl_label_text_get_buffer (GL_LABEL_TEXT(object));
254         gl_object_editor_set_text_buffer (GL_OBJECT_EDITOR(editor), buffer);
255         
256         /* Update */
257         update_editor_from_object_cb (object, GL_OBJECT_EDITOR(editor));
258         update_editor_from_move_cb (object, 0, 0, GL_OBJECT_EDITOR(editor));
259         update_editor_from_label_cb (object->parent, GL_OBJECT_EDITOR(editor));
260
261         /* Connect signals. */
262         g_signal_connect (G_OBJECT (editor), "changed",
263                           G_CALLBACK(update_object_from_editor_cb), object);
264         g_signal_connect (G_OBJECT (object), "changed",
265                           G_CALLBACK (update_editor_from_object_cb), editor);
266         g_signal_connect (G_OBJECT (object), "moved",
267                           G_CALLBACK (update_editor_from_move_cb), editor);
268         g_signal_connect (G_OBJECT (object->parent), "size_changed",
269                           G_CALLBACK (update_editor_from_label_cb), editor);
270         g_signal_connect (G_OBJECT (object->parent), "merge_changed",
271                           G_CALLBACK (update_editor_from_label_cb), editor);
272
273         gl_debug (DEBUG_VIEW, "END");
274
275         return editor;
276 }
277
278 /*---------------------------------------------------------------------------*/
279 /* PRIVATE. label object "changed" callback.                                 */
280 /*---------------------------------------------------------------------------*/
281 static void
282 update_canvas_item_from_object_cb (glLabelObject *object,
283                                    glViewText    *view_text)
284 {
285         gl_debug (DEBUG_VIEW, "START");
286
287         /* Adjust appearance of analogous canvas item. */
288         draw_hacktext (view_text);
289         draw_cursor (view_text);
290
291         gl_debug (DEBUG_VIEW, "END");
292 }
293
294 /*---------------------------------------------------------------------------*/
295 /* PRIVATE.  editor "changed" callback.                                      */
296 /*---------------------------------------------------------------------------*/
297 static void
298 update_object_from_editor_cb (glObjectEditor *editor,
299                               glLabelObject  *object)
300 {
301         gdouble            x, y, w, h;
302         gchar             *font_family;
303         gdouble            font_size;
304         GnomeFontWeight    font_weight;
305         gboolean           font_italic_flag;
306         guint              color;
307         GtkJustification   just;
308
309         gl_debug (DEBUG_VIEW, "START");
310
311         g_signal_handlers_block_by_func (G_OBJECT(object),
312                                          update_editor_from_object_cb,
313                                          editor);
314         g_signal_handlers_block_by_func (G_OBJECT(object),
315                                          update_editor_from_move_cb,
316                                          editor);
317
318
319         gl_object_editor_get_position (editor, &x, &y);
320         gl_object_editor_get_size (editor, &w, &h);
321         font_family = gl_object_editor_get_font_family (editor);
322         font_size = gl_object_editor_get_font_size (editor);
323         font_weight = gl_object_editor_get_font_weight (editor);
324         font_italic_flag = gl_object_editor_get_font_italic_flag (editor);
325         color = gl_object_editor_get_text_color (editor);
326         just = gl_object_editor_get_text_alignment (editor);
327
328         gl_label_object_set_position (object, x, y);
329         gl_label_object_set_size (object, w, h);
330         gl_label_object_set_font_family (object, font_family);
331         gl_label_object_set_font_size (object, font_size);
332         gl_label_object_set_font_weight (object, font_weight);
333         gl_label_object_set_font_italic_flag (object, font_italic_flag);
334         gl_label_object_set_text_color (object, color);
335         gl_label_object_set_text_alignment (object, just);
336
337         g_free (font_family);
338
339         g_signal_handlers_unblock_by_func (G_OBJECT(object),
340                                            update_editor_from_object_cb,
341                                            editor);
342         g_signal_handlers_unblock_by_func (G_OBJECT(object),
343                                            update_editor_from_move_cb,
344                                            editor);
345
346         gl_debug (DEBUG_VIEW, "END");
347 }
348
349 /*---------------------------------------------------------------------------*/
350 /* PRIVATE. label object "changed" callback.                                 */
351 /*---------------------------------------------------------------------------*/
352 static void
353 update_editor_from_object_cb (glLabelObject  *object,
354                               glObjectEditor *editor)
355 {
356         gdouble            w, h;
357         gchar             *font_family;
358         gdouble            font_size;
359         GnomeFontWeight    font_weight;
360         gboolean           font_italic_flag;
361         guint              color;
362         GtkJustification   just;
363
364         gl_debug (DEBUG_VIEW, "START");
365
366         gl_label_object_get_size (object, &w, &h);
367         gl_object_editor_set_size (editor, w, h);
368
369         font_family      = gl_label_object_get_font_family (object);
370         font_size        = gl_label_object_get_font_size (object);
371         font_weight      = gl_label_object_get_font_weight (object);
372         font_italic_flag = gl_label_object_get_font_italic_flag (object);
373         color            = gl_label_object_get_text_color (object);
374         just             = gl_label_object_get_text_alignment (object);
375
376         gl_object_editor_set_font_family (editor, font_family);
377         gl_object_editor_set_font_size (editor, font_size);
378         gl_object_editor_set_font_weight (editor, font_weight);
379         gl_object_editor_set_font_italic_flag (editor, font_italic_flag);
380         gl_object_editor_set_text_color (editor, color);
381         gl_object_editor_set_text_alignment (editor, just);
382
383         g_free (font_family);
384
385         gl_debug (DEBUG_VIEW, "END");
386 }
387
388 /*---------------------------------------------------------------------------*/
389 /* PRIVATE. label object "moved" callback.                                   */
390 /*---------------------------------------------------------------------------*/
391 static void
392 update_editor_from_move_cb (glLabelObject    *object,
393                             gdouble           dx,
394                             gdouble           dy,
395                             glObjectEditor   *editor)
396 {
397         gdouble            x, y;
398
399         gl_debug (DEBUG_VIEW, "START");
400
401         gl_label_object_get_position (object, &x, &y);
402         gl_object_editor_set_position (editor, x, y);
403
404         gl_debug (DEBUG_VIEW, "END");
405 }
406
407 /*---------------------------------------------------------------------------*/
408 /* PRIVATE. label "changed" callback.                                        */
409 /*---------------------------------------------------------------------------*/
410 static void
411 update_editor_from_label_cb (glLabel        *label,
412                              glObjectEditor *editor)
413 {
414         gdouble            label_width, label_height;
415         glMerge           *merge;
416
417         gl_debug (DEBUG_VIEW, "START");
418
419         gl_label_get_size (label, &label_width, &label_height);
420         gl_object_editor_set_max_position (GL_OBJECT_EDITOR (editor),
421                                            label_width, label_height);
422         gl_object_editor_set_max_size (GL_OBJECT_EDITOR (editor),
423                                        label_width, label_height);
424
425         merge = gl_label_get_merge (label);
426         gl_object_editor_set_key_names (editor, merge);
427
428         gl_debug (DEBUG_VIEW, "END");
429 }
430
431 /*****************************************************************************/
432 /* Return apropos cursor for create object mode.                             */
433 /*****************************************************************************/
434 GdkCursor *
435 gl_view_text_get_create_cursor (void)
436 {
437         static GdkCursor *cursor = NULL;
438         GdkPixmap        *pixmap_data, *pixmap_mask;
439         GdkColor         fg = { 0, 0, 0, 0 };
440         GdkColor         bg = { 0, 65535, 65535, 65535 };
441
442         gl_debug (DEBUG_VIEW, "START");
443
444         if (!cursor) {
445                 pixmap_data = gdk_bitmap_create_from_data (NULL,
446                                                            cursor_text_bits,
447                                                            cursor_text_width,
448                                                            cursor_text_height);
449                 pixmap_mask = gdk_bitmap_create_from_data (NULL,
450                                                            cursor_text_mask_bits,
451                                                            cursor_text_mask_width,
452                                                            cursor_text_mask_height);
453                 cursor =
454                     gdk_cursor_new_from_pixmap (pixmap_data, pixmap_mask, &fg,
455                                                 &bg, cursor_text_x_hot,
456                                                 cursor_text_y_hot);
457         }
458
459         gl_debug (DEBUG_VIEW, "END");
460
461         return cursor;
462 }
463
464 /*****************************************************************************/
465 /* Canvas event handler for creating text objects.                           */
466 /*****************************************************************************/
467 int
468 gl_view_text_create_event_handler (GnomeCanvas *canvas,
469                                    GdkEvent    *event,
470                                    glView      *view)
471 {
472         static gdouble      x0, y0;
473         static gboolean     dragging = FALSE;
474         static glViewObject *view_text;
475         static GObject      *object;
476         gdouble             x, y;
477         GList               *lines;
478         gchar               *family;
479
480         gl_debug (DEBUG_VIEW, "");
481
482         switch (event->type) {
483
484         case GDK_BUTTON_PRESS:
485                 gl_debug (DEBUG_VIEW, "BUTTON_PRESS");
486                 switch (event->button.button) {
487                 case 1:
488                         dragging = TRUE;
489                         gnome_canvas_item_grab (canvas->root,
490                                                 GDK_POINTER_MOTION_MASK |
491                                                 GDK_BUTTON_RELEASE_MASK |
492                                                 GDK_BUTTON_PRESS_MASK,
493                                                 NULL, event->button.time);
494                         gnome_canvas_window_to_world (canvas,
495                                                       event->button.x,
496                                                       event->button.y, &x, &y);
497                         object = gl_label_text_new (view->label);
498                         gl_label_object_set_position (GL_LABEL_OBJECT(object),
499                                                      x, y);
500                         family = gl_view_get_default_font_family (view);
501                         gl_label_object_set_font_family (GL_LABEL_OBJECT(object), family);
502                         gl_label_object_set_font_size (GL_LABEL_OBJECT(object),
503                                                        gl_view_get_default_font_size (view));
504                         gl_label_object_set_font_weight (GL_LABEL_OBJECT(object),
505                                                          gl_view_get_default_font_weight (view));
506                         gl_label_object_set_font_italic_flag (GL_LABEL_OBJECT(object),
507                                                               gl_view_get_default_font_italic_flag (view));
508                         gl_label_object_set_text_color (GL_LABEL_OBJECT(object),
509                                                         gl_color_set_opacity (gl_view_get_default_text_color (view), 0.5));
510                         gl_label_object_set_text_alignment (GL_LABEL_OBJECT(object),
511                                                             gl_view_get_default_text_alignment (view));
512                         g_free (family);
513                         lines = gl_text_node_lines_new_from_text (_("Text"));
514                         gl_label_text_set_lines (GL_LABEL_TEXT(object), lines);
515                         view_text = gl_view_text_new (GL_LABEL_TEXT(object),
516                                                       view);
517                         x0 = x;
518                         y0 = y;
519                         return TRUE;
520
521                 default:
522                         return FALSE;
523                 }
524
525         case GDK_BUTTON_RELEASE:
526                 gl_debug (DEBUG_VIEW, "BUTTON_RELEASE");
527                 switch (event->button.button) {
528                 case 1:
529                         dragging = FALSE;
530                         gnome_canvas_item_ungrab (canvas->root, event->button.time);
531                         gnome_canvas_window_to_world (canvas,
532                                                       event->button.x,
533                                                       event->button.y, &x, &y);
534                         gl_label_object_set_position (GL_LABEL_OBJECT(object),
535                                                       x, y);
536                         family = gl_view_get_default_font_family (view);
537                         gl_label_object_set_font_family (GL_LABEL_OBJECT(object), family);
538                         gl_label_object_set_font_size (GL_LABEL_OBJECT(object),
539                                                        gl_view_get_default_font_size (view));
540                         gl_label_object_set_font_weight (GL_LABEL_OBJECT(object),
541                                                          gl_view_get_default_font_weight (view));
542                         gl_label_object_set_font_italic_flag (GL_LABEL_OBJECT(object),
543                                                               gl_view_get_default_font_italic_flag (view));
544                         gl_label_object_set_text_color (GL_LABEL_OBJECT(object),
545                                                         gl_view_get_default_text_color (view));
546                         gl_label_object_set_text_alignment (GL_LABEL_OBJECT(object),
547                                                             gl_view_get_default_text_alignment (view));
548                         g_free (family);
549                         gl_view_unselect_all (view);
550                         gl_view_object_select (GL_VIEW_OBJECT(view_text));
551                         gl_view_arrow_mode (view);
552                         return TRUE;
553
554                 default:
555                         return FALSE;
556                 }
557
558         case GDK_MOTION_NOTIFY:
559                 gl_debug (DEBUG_VIEW, "MOTION_NOTIFY");
560                 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
561                         gnome_canvas_window_to_world (canvas,
562                                                       event->motion.x,
563                                                       event->motion.y, &x, &y);
564                         gl_label_object_set_position (GL_LABEL_OBJECT(object),
565                                                       x, y);
566                         return TRUE;
567                 } else {
568                         return FALSE;
569                 }
570
571         default:
572                 return FALSE;
573         }
574
575 }
576
577 /*--------------------------------------------------------------------------*/
578 /* PRIVATE.  Draw hacktext to item (group).                                 */
579 /*--------------------------------------------------------------------------*/
580 static void
581 draw_hacktext (glViewText *view_text)
582 {
583         glLabelObject     *object;
584         GnomeCanvasItem   *item;
585         GtkTextBuffer     *buffer;
586         GtkTextIter        start, end;
587         gchar             *text;
588         gchar             *font_family;
589         GnomeFontWeight    font_weight;
590         gboolean           font_italic_flag;
591         gdouble            font_size;
592         guint              color;
593         GtkJustification   just;
594         GnomeFont         *font;
595         GnomeGlyphList    *glyphlist;
596         ArtDRect           bbox;
597         gdouble            affine[6];
598         gdouble            x_offset, y_offset, w, object_w, object_h;
599         gint               i;
600         gchar            **line;
601         GList             *li;
602
603         gl_debug (DEBUG_VIEW, "START");
604
605         /* Query label object and properties */
606         object = gl_view_object_get_object (GL_VIEW_OBJECT(view_text));
607         gl_label_object_get_size (object, &object_w, &object_h);
608         font_family = gl_label_object_get_font_family (object);
609         font_size = gl_label_object_get_font_size (object);
610         font_weight = gl_label_object_get_font_weight (object);
611         font_italic_flag = gl_label_object_get_font_italic_flag (object);
612         color = gl_label_object_get_text_color (object);
613         just = gl_label_object_get_text_alignment (object);
614         buffer = gl_label_text_get_buffer(GL_LABEL_TEXT(object));
615         gtk_text_buffer_get_bounds (buffer, &start, &end);
616         text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
617         line = g_strsplit (text, "\n", -1);
618
619         /* remove previous items from group. */
620         for (li = view_text->private->item_list; li != NULL; li = li->next) {
621                 gl_debug (DEBUG_VIEW, "in loop");
622                 gtk_object_destroy (GTK_OBJECT (li->data));
623         }
624         gl_debug (DEBUG_VIEW, "1");
625         g_list_free (view_text->private->item_list);
626         view_text->private->item_list = NULL;
627         gl_debug (DEBUG_VIEW, "2");
628
629         /* get Gnome Font */
630         font = gnome_font_find_closest_from_weight_slant (font_family,
631                                                           font_weight,
632                                                           font_italic_flag,
633                                                           font_size);
634         art_affine_identity (affine);
635
636         /* render to group, one item per line. */
637         for (i = 0; line[i] != NULL; i++) {
638
639                 glyphlist = gnome_glyphlist_from_text_dumb (font, color,
640                                                             0.0, 0.0,
641                                                             line[i]);
642
643                 gnome_glyphlist_bbox (glyphlist, affine, 0, &bbox);
644                 w = bbox.x1;
645
646                 switch (just) {
647                 case GTK_JUSTIFY_LEFT:
648                         x_offset = GL_LABEL_TEXT_MARGIN;
649                         break;
650                 case GTK_JUSTIFY_CENTER:
651                         x_offset = (object_w - GL_LABEL_TEXT_MARGIN - w) / 2.0;
652                         break;
653                 case GTK_JUSTIFY_RIGHT:
654                         x_offset = object_w - GL_LABEL_TEXT_MARGIN - w;
655                         break;
656                 default:
657                         x_offset = 0.0;
658                         break;  /* shouldn't happen */
659                 }
660
661                 y_offset = GL_LABEL_TEXT_MARGIN +
662                         (i + 1) * font_size + gnome_font_get_descender (font);
663
664                 item = gl_view_object_item_new (GL_VIEW_OBJECT(view_text),
665                                                 gl_canvas_hacktext_get_type (),
666                                                 "x", x_offset,
667                                                 "y", y_offset,
668                                                 "glyphlist", glyphlist, NULL);
669                 view_text->private->item_list =
670                         g_list_prepend (view_text->private->item_list, item);
671
672         }
673
674         /* clean up */
675         g_strfreev (line);
676         g_free (text);
677
678         gl_debug (DEBUG_VIEW, "END");
679 }
680
681 /*--------------------------------------------------------------------------*/
682 /* PRIVATE.  Draw cursor to item (group).                                   */
683 /*--------------------------------------------------------------------------*/
684 static void
685 draw_cursor (glViewText *view_text)
686 {
687         glLabelObject     *object;
688         GnomeCanvasItem   *item;
689         GtkTextBuffer     *buffer;
690         GtkTextIter        start, end;
691         gchar             *text;
692         gchar             *font_family;
693         GnomeFontWeight    font_weight;
694         gboolean           font_italic_flag;
695         gdouble            font_size;
696         guint              color;
697         GtkJustification   just;
698         GnomeFont         *font;
699         GnomeGlyphList    *glyphlist;
700         ArtDRect           bbox;
701         gdouble            affine[6];
702         gdouble            x_offset, w, object_w, object_h;
703         gint               i;
704         gchar            **line;
705         GList             *li;
706         GtkTextMark       *cursor_mark, *bound_mark;
707         GtkTextIter        cursor_iter, bound_iter;
708         gint               cursor_line, cursor_char, bound_line, bound_char;
709         gboolean           selection_flag;
710
711         gl_debug (DEBUG_VIEW, "START");
712
713         /* Query label object and properties */
714         object = gl_view_object_get_object (GL_VIEW_OBJECT(view_text));
715         gl_label_object_get_size (object, &object_w, &object_h);
716         font_family = gl_label_object_get_font_family (object);
717         font_size = gl_label_object_get_font_size (object);
718         font_weight = gl_label_object_get_font_weight (object);
719         font_italic_flag = gl_label_object_get_font_italic_flag (object);
720         color = gl_label_object_get_text_color (object);
721         just = gl_label_object_get_text_alignment (object);
722         buffer = gl_label_text_get_buffer(GL_LABEL_TEXT(object));
723         gtk_text_buffer_get_bounds (buffer, &start, &end);
724         text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
725         line = g_strsplit (text, "\n", -1);
726
727         /* Get cursor and selection information. */
728         cursor_mark = gtk_text_buffer_get_insert (buffer);
729         bound_mark  = gtk_text_buffer_get_selection_bound (buffer);
730         gtk_text_buffer_get_iter_at_mark (buffer, &cursor_iter, cursor_mark);
731         gtk_text_buffer_get_iter_at_mark (buffer, &bound_iter, bound_mark);
732         cursor_line = gtk_text_iter_get_line (&cursor_iter);
733         cursor_char = gtk_text_iter_get_visible_line_index (&cursor_iter);
734         bound_line = gtk_text_iter_get_line (&bound_iter);
735         bound_char = gtk_text_iter_get_visible_line_index (&bound_iter);
736         selection_flag = !gtk_text_iter_equal (&cursor_iter, &bound_iter);
737
738         /* get Gnome Font */
739         font = gnome_font_find_closest_from_weight_slant (font_family,
740                                                           font_weight,
741                                                           font_italic_flag,
742                                                           font_size);
743         art_affine_identity (affine);
744
745         for (i = 0; line[i] != NULL; i++) {
746
747                 if ( i == cursor_line ) {
748                         GnomeCanvasPoints *points;
749                         
750                         glyphlist = gnome_glyphlist_from_text_dumb (font, color,
751                                                                     0.0, 0.0,
752                                                                     line[i]);
753
754                         gnome_glyphlist_bbox (glyphlist, affine, 0, &bbox);
755                         gnome_glyphlist_unref (glyphlist);
756                         w = bbox.x1;
757
758                         switch (just) {
759                         case GTK_JUSTIFY_LEFT:
760                                 x_offset = GL_LABEL_TEXT_MARGIN;
761                                 break;
762                         case GTK_JUSTIFY_CENTER:
763                                 x_offset = (object_w - GL_LABEL_TEXT_MARGIN - w) / 2.0;
764                                 break;
765                         case GTK_JUSTIFY_RIGHT:
766                                 x_offset = object_w - GL_LABEL_TEXT_MARGIN - w;
767                                 break;
768                         default:
769                                 x_offset = 0.0;
770                                 break;  /* shouldn't happen */
771                         }
772
773                         glyphlist = gnome_glyphlist_from_text_sized_dumb (font, color,
774                                                                           0.0, 0.0,
775                                                                           line[i],
776                                                                           cursor_char);
777                         gnome_glyphlist_bbox (glyphlist, affine, 0, &bbox);
778                         gnome_glyphlist_unref (glyphlist);
779                         x_offset += bbox.x1;
780
781                         points = gnome_canvas_points_new (2);
782                         points->coords[0] = x_offset;
783                         points->coords[1] = GL_LABEL_TEXT_MARGIN + i*font_size;
784                         points->coords[2] = x_offset;
785                         points->coords[3] = GL_LABEL_TEXT_MARGIN + (i+1)*font_size;
786                         
787                         if (view_text->private->cursor) {
788                                 gtk_object_destroy (GTK_OBJECT (view_text->private->cursor));
789                         }
790                         view_text->private->cursor =
791                                 gl_view_object_item_new (GL_VIEW_OBJECT(view_text),
792                                                          gnome_canvas_line_get_type (),
793                                                          "points", points,
794                                                          "fill_color_rgba", CURSOR_COLOR,
795                                                          "width_pixels", 2,
796                                                          NULL);
797                         gnome_canvas_points_free (points);
798
799                         if ( !view_text->private->cursor_visible ) {
800                                 gnome_canvas_item_hide (view_text->private->cursor);
801                         }
802
803                 }
804
805         }
806
807         /* clean up */
808         g_strfreev (line);
809         g_free (text);
810
811         gl_debug (DEBUG_VIEW, "END");
812 }
813
814 /*--------------------------------------------------------------------------*/
815 /* PRIVATE.  Text buffer "mark-set" callback.  Tracks cursor position.      */
816 /*--------------------------------------------------------------------------*/
817 static void
818 mark_set_cb (GtkTextBuffer   *textbuffer,
819              GtkTextIter     *iter,
820              GtkTextMark     *mark,
821              glViewText      *view_text)
822 {
823         const gchar *mark_name;
824
825         mark_name = gtk_text_mark_get_name (mark);
826
827         if ( mark_name && !strcmp (mark_name, "insert") ) {
828                 draw_cursor (view_text);
829         }
830 }
831
832
833
834 /*--------------------------------------------------------------------------*/
835 /* PRIVATE.  Start the cursor blinking.                                     */
836 /*--------------------------------------------------------------------------*/
837 static void
838 blink_start (glViewText *view_text)
839 {
840         if ( !view_text->private->cursor_visible ) return;
841
842         view_text->private->cursor_state = TRUE;
843         gnome_canvas_item_show (view_text->private->cursor);
844         view_text->private->cursor_timeout =
845                 gtk_timeout_add (CURSOR_ON_TIME, (GtkFunction)blink_cb, view_text);
846 }
847
848 /*--------------------------------------------------------------------------*/
849 /* PRIVATE.  Stop the cursor blinking.                                      */
850 /*--------------------------------------------------------------------------*/
851 static void
852 blink_stop (glViewText *view_text)
853 {
854         if ( view_text->private->cursor_timeout ) {
855                 gtk_timeout_remove (view_text->private->cursor_timeout);
856                 view_text->private->cursor_timeout = 0;
857         }
858
859         gnome_canvas_item_hide (view_text->private->cursor);
860 }
861
862 /*--------------------------------------------------------------------------*/
863 /* PRIVATE.  Blink cursor timeout callback.                                 */
864 /*--------------------------------------------------------------------------*/
865 static gboolean
866 blink_cb (glViewText *view_text)
867 {
868         if ( view_text->private->cursor_visible ) {
869
870                 view_text->private->cursor_state =
871                         !view_text->private->cursor_state;
872
873
874                 if ( view_text->private->cursor_state ) {
875                         gnome_canvas_item_show (view_text->private->cursor);
876                         view_text->private->cursor_timeout =
877                                 gtk_timeout_add (CURSOR_ON_TIME,
878                                                  (GtkFunction)blink_cb, view_text);
879                 } else {
880                         gnome_canvas_item_hide (view_text->private->cursor);
881                         view_text->private->cursor_timeout =
882                                 gtk_timeout_add (CURSOR_OFF_TIME,
883                                                  (GtkFunction)blink_cb, view_text);
884                 }
885
886         }
887
888         return FALSE;
889 }
890
891 /*--------------------------------------------------------------------------*/
892 /* PRIVATE.  Item event callback.                                           */
893 /*--------------------------------------------------------------------------*/
894 static gint
895 item_event_cb (GnomeCanvasItem *item,
896                GdkEvent        *event,
897                glViewObject    *view_object)
898 {
899         gl_debug (DEBUG_VIEW, "");
900 }
901