comparison console/libgnt/gnttextview.c @ 15172:a00712d0522e

[gaim-migrate @ 17957] Show 'ABC is typing...' in the conversation window for typing notification. seanegan suggested this, and it sounded like an interesting thing to do. The change in gnttextview.c will need some more work if it is to be used for some other task, but its current use should be OK. committer: Tailor Script <tailor@pidgin.im>
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Mon, 11 Dec 2006 06:02:15 +0000
parents 5228f8cf2a6a
children e9963b2cfcaf
comparison
equal deleted inserted replaced
15171:b7f83eba6029 15172:a00712d0522e
20 { 20 {
21 GList *segments; /* A list of GntTextSegments */ 21 GList *segments; /* A list of GntTextSegments */
22 int length; /* The current length of the line so far (ie. onscreen width) */ 22 int length; /* The current length of the line so far (ie. onscreen width) */
23 gboolean soft; /* TRUE if it's an overflow from prev. line */ 23 gboolean soft; /* TRUE if it's an overflow from prev. line */
24 } GntTextLine; 24 } GntTextLine;
25
26 typedef struct
27 {
28 char *name;
29 int start;
30 int end;
31 } GntTextTag;
25 32
26 static GntWidgetClass *parent_class = NULL; 33 static GntWidgetClass *parent_class = NULL;
27 34
28 static void 35 static void
29 gnt_text_view_draw(GntWidget *widget) 36 gnt_text_view_draw(GntWidget *widget)
132 g_list_free(line->segments); 139 g_list_free(line->segments);
133 g_free(line); 140 g_free(line);
134 } 141 }
135 142
136 static void 143 static void
144 free_tag(gpointer data, gpointer null)
145 {
146 GntTextTag *tag = data;
147 g_free(tag->name);
148 g_free(tag);
149 }
150
151 static void
137 gnt_text_view_destroy(GntWidget *widget) 152 gnt_text_view_destroy(GntWidget *widget)
138 { 153 {
139 GntTextView *view = GNT_TEXT_VIEW(widget); 154 GntTextView *view = GNT_TEXT_VIEW(widget);
140 view->list = g_list_first(view->list); 155 view->list = g_list_first(view->list);
141 g_list_foreach(view->list, free_text_line, NULL); 156 g_list_foreach(view->list, free_text_line, NULL);
142 g_list_free(view->list); 157 g_list_free(view->list);
158 g_list_foreach(view->tags, free_tag, NULL);
159 g_list_free(view->tags);
143 g_string_free(view->string, TRUE); 160 g_string_free(view->string, TRUE);
144 } 161 }
145 162
146 static gboolean 163 static gboolean
147 gnt_text_view_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) 164 gnt_text_view_clicked(GntWidget *widget, GntMouseEvent event, int x, int y)
295 return widget; 312 return widget;
296 } 313 }
297 314
298 void gnt_text_view_append_text_with_flags(GntTextView *view, const char *text, GntTextFormatFlags flags) 315 void gnt_text_view_append_text_with_flags(GntTextView *view, const char *text, GntTextFormatFlags flags)
299 { 316 {
317 gnt_text_view_append_text_with_tag(view, text, flags, NULL);
318 }
319
320 void gnt_text_view_append_text_with_tag(GntTextView *view, const char *text,
321 GntTextFormatFlags flags, const char *tagname)
322 {
300 GntWidget *widget = GNT_WIDGET(view); 323 GntWidget *widget = GNT_WIDGET(view);
301 int fl = 0; 324 int fl = 0;
302 const char *start, *end; 325 const char *start, *end;
303 GList *list = view->list; 326 GList *list = view->list;
304 GntTextLine *line; 327 GntTextLine *line;
309 332
310 fl = gnt_text_format_flag_to_chtype(flags); 333 fl = gnt_text_format_flag_to_chtype(flags);
311 334
312 len = view->string->len; 335 len = view->string->len;
313 view->string = g_string_append(view->string, text); 336 view->string = g_string_append(view->string, text);
337
338 if (tagname) {
339 GntTextTag *tag = g_new0(GntTextTag, 1);
340 tag->name = g_strdup(tagname);
341 tag->start = len;
342 tag->end = view->string->len;
343 view->tags = g_list_append(view->tags, tag);
344 }
314 345
315 view->list = g_list_first(view->list); 346 view->list = g_list_first(view->list);
316 347
317 start = end = view->string->str + len; 348 start = end = view->string->str + len;
318 349
469 while ((list = list->next)) 500 while ((list = list->next))
470 ++above; 501 ++above;
471 return above; 502 return above;
472 } 503 }
473 504
505 /**
506 * XXX: There are quite possibly more than a few bugs here.
507 */
508 int gnt_text_view_tag_change(GntTextView *view, const char *name, const char *text, gboolean all)
509 {
510 GList *list, *next, *iter, *inext;
511 int count = 0;
512 for (list = view->tags; list; list = next) {
513 GntTextTag *tag = list->data;
514 next = list->next;
515 if (strcmp(tag->name, name) == 0) {
516 int change;
517 char *before, *after;
518
519 count++;
520
521 before = g_strndup(view->string->str, tag->start);
522 after = g_strdup(view->string->str + tag->end);
523 change = (tag->end - tag->start) - (text ? strlen(text) : 0);
524
525 g_string_printf(view->string, "%s%s%s", before, text ? text : "", after);
526 g_free(before);
527 g_free(after);
528
529 /* Update the offsets of the next tags */
530 for (iter = next; iter; iter = iter->next) {
531 GntTextTag *t = iter->data;
532 t->start -= change;
533 t->end -= change;
534 }
535
536 /* Update the offsets of the segments */
537 for (iter = view->list; iter; iter = inext) {
538 GList *segs, *snext;
539 GntTextLine *line = iter->data;
540 inext = iter->next;
541 for (segs = line->segments; segs; segs = snext) {
542 GntTextSegment *seg = segs->data;
543 snext = segs->next;
544 if (seg->start >= tag->end) {
545 seg->start -= change;
546 seg->end -= change;
547 continue;
548 }
549 if (seg->end < tag->start)
550 continue;
551
552 if (seg->start >= tag->start && seg->end <= tag->end) {
553 free_text_segment(seg, NULL);
554 line->segments = g_list_delete_link(line->segments, segs);
555 if (line->segments == NULL) {
556 free_text_line(line, NULL);
557 view->list = g_list_delete_link(view->list, iter);
558 }
559 }
560 /* XXX: handle the rest of the conditions */
561 }
562 }
563 if (text == NULL) {
564 /* Remove the tag */
565 view->tags = g_list_delete_link(view->tags, list);
566 free_tag(tag, NULL);
567 }
568 if (!all)
569 break;
570 }
571 }
572 return count;
573 }
574