aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/text
diff options
context:
space:
mode:
Diffstat (limited to 'widgets/text')
-rw-r--r--widgets/text/e-text.c264
1 files changed, 95 insertions, 169 deletions
diff --git a/widgets/text/e-text.c b/widgets/text/e-text.c
index 4fc8437732..349b2d40b8 100644
--- a/widgets/text/e-text.c
+++ b/widgets/text/e-text.c
@@ -950,200 +950,126 @@ text_draw_with_objects (ETextModel *model,
}
}
-#define IS_BREAKCHAR(text,c) ((text)->break_characters && g_utf8_strchr ((text)->break_characters, (c)))
-/* Splits the text of the text item into lines */
-static void
-split_into_lines (EText *text)
+typedef void (*LineSplitterFn) (int line_num, const char *start, int length, gpointer user_data);
+
+#define IS_BREAK_CHAR(break_chars, c) (g_unichar_isspace (c) || ((break_chars) && g_utf8_strchr ((break_chars), (c))))
+
+static gint
+line_splitter (ETextModel *model, EFont *font, EFontStyle style,
+ const char *break_characters,
+ gboolean wrap_lines, double clip_width, gint max_lines,
+ LineSplitterFn split_cb, gpointer user_data)
{
- const char *p, *cp;
- struct line *lines;
- int len;
- int line_num;
- const char *laststart;
- const char *lastend;
+ const char *curr;
+ const char *text;
const char *linestart;
- double clip_width;
+ const char *last_breakpoint;
+ gint line_count = 0;
+
gunichar unival;
+ if (max_lines < 1)
+ max_lines = G_MAXINT;
- if (text->text == NULL)
- return;
+ text = e_text_model_get_text (model);
+ linestart = NULL;
+ last_breakpoint = text;
- /* Free old array of lines */
- e_text_free_lines(text);
+ for (curr = text; curr && *curr && line_count < max_lines; curr = g_utf8_next_char (curr)) {
- /* First, count the number of lines */
+ unival = g_utf8_get_char (curr);
- lastend = text->text;
- laststart = text->text;
- linestart = text->text;
+ if (linestart == NULL)
+ linestart = curr;
- clip_width = text->clip_width;
- if (clip_width >= 0 && text->draw_borders) {
- clip_width -= 6;
- if (clip_width < 0)
- clip_width = 0;
- }
+ if (unival == '\n') { /* We always break on newline */
- cp = text->text;
-
- for (p = e_unicode_get_utf8 (cp, &unival); (unival && p); cp = p, p = e_unicode_get_utf8 (p, &unival)) {
- if (text->line_wrap
- && (g_unichar_isspace (unival) || unival == '\n')
- && e_text_model_get_object_at_pointer (text->model, cp) == -1) { /* don't break mid-object */
- if (laststart != lastend
- && clip_width < text_width_with_objects (text->model,
- text->font, text->style,
- linestart, cp - linestart)) {
- text->num_lines ++;
-
- linestart = laststart;
- laststart = p;
- lastend = cp;
- } else if (g_unichar_isspace (unival)) {
- laststart = p;
- lastend = cp;
- }
- } else if (text->line_wrap
- && IS_BREAKCHAR (text, unival)) {
+ if (split_cb)
+ split_cb (line_count, linestart, curr - linestart, user_data);
+ ++line_count;
+ linestart = NULL;
+
+ } else if (wrap_lines) {
- if (laststart != lastend
- && g_utf8_pointer_to_offset (linestart, cp) != 1
- && clip_width < text_width_with_objects (text->model,
- text->font, text->style,
- linestart, p - linestart)) {
- text->num_lines ++;
+ if (clip_width < text_width_with_objects (model, font, style, linestart, curr - linestart)
+ && last_breakpoint > linestart) {
- linestart = laststart;
- laststart = p;
- lastend = p;
- } else {
- laststart = p;
- lastend = p;
+ if (split_cb)
+ split_cb (line_count, linestart, last_breakpoint - linestart, user_data);
+ ++line_count;
+ linestart = NULL;
+ curr = last_breakpoint;
+
+ } else if (IS_BREAK_CHAR (break_characters, unival)
+ && e_text_model_get_object_at_pointer (model, curr) == -1) { /* don't break mid-object */
+ last_breakpoint = curr;
}
}
+ }
- if (unival == '\n') {
- text->num_lines ++;
+ /* Handle any leftover text. */
+ if (linestart) {
+
+ if (clip_width < text_width_with_objects (model, font, style, linestart, strlen (linestart))
+ && last_breakpoint > linestart) {
- lastend = p;
- laststart = p;
- linestart = p;
- }
- }
+ if (split_cb)
+ split_cb (line_count, linestart, last_breakpoint - linestart, user_data);
- if ( text->line_wrap
- && p
- && laststart != lastend
- && clip_width < text_width_with_objects (text->model,
- text->font, text->style,
- linestart, cp - linestart)) {
- text->num_lines ++;
- }
+ ++line_count;
+ linestart = g_utf8_next_char (last_breakpoint);
+ }
- text->num_lines++;
+ if (split_cb)
+ split_cb (line_count, linestart, strlen (linestart), user_data);
+ ++line_count;
- if ( (!text->editing) && text->max_lines != -1 && text->num_lines > text->max_lines ) {
- text->num_lines = text->max_lines;
}
+
+ return line_count;
+}
- /* Allocate array of lines and calculate split positions */
-
- text->lines = lines = g_new0 (struct line, text->num_lines);
- len = 0;
- line_num = 1;
- lastend = text->text;
- laststart = text->text;
-
- cp = text->text;
-
- for (p = e_unicode_get_utf8 (cp, &unival); p && unival && line_num < text->num_lines; cp = p, p = e_unicode_get_utf8 (p, &unival)) {
- gboolean handled = FALSE;
-
- if (len == 0)
- lines->text = cp;
- if (text->line_wrap
- && (g_unichar_isspace (unival) || unival == '\n')
- && e_text_model_get_object_at_pointer (text->model, cp) == -1) { /* don't break mid-object */
- if (clip_width < text_width_with_objects (text->model,
- text->font, text->style,
- lines->text, cp - lines->text)
- && laststart != lastend) {
-
- lines->length = lastend - lines->text;
-
- lines++;
- line_num++;
- len = cp - laststart;
- lines->text = laststart;
- laststart = p;
- lastend = cp;
- } else if (g_unichar_isspace (unival)) {
- laststart = p;
- lastend = cp;
- len ++;
- }
- handled = TRUE;
- } else if (text->line_wrap
- && IS_BREAKCHAR(text, unival)
- && e_text_model_get_object_at_pointer (text->model, cp) == -1) {
- if (laststart != lastend
- && g_utf8_pointer_to_offset (lines->text, cp) != 1
- && clip_width < text_width_with_objects (text->model,
- text->font, text->style,
- lines->text, p - lines->text)) {
-
- lines->length = lastend - lines->text;
-
- lines++;
- line_num++;
- len = p - laststart;
- lines->text = laststart;
- laststart = p;
- lastend = p;
- } else {
- laststart = p;
- lastend = p;
- len ++;
- }
- }
- if (line_num >= text->num_lines)
- break;
- if (unival == '\n') {
+static void
+line_split_cb (int line_num, const char *start, int length, gpointer user_data)
+{
+ EText *text = user_data;
+ struct line *line = &((struct line *)text->lines)[line_num];
- lines->length = cp - lines->text;
-
- lines++;
- line_num++;
- len = 0;
- lastend = p;
- laststart = p;
- handled = TRUE;
- }
- if (!handled)
- len++;
- }
+ line->text = start;
+ line->length = length;
+}
+
+static void
+split_into_lines (EText *text)
+{
+ double clip_width;
- if ( line_num < text->num_lines && text->line_wrap ) {
- if (clip_width < text_width_with_objects (text->model,
- text->font, text->style,
- lines->text, cp - lines->text)
- && laststart != lastend ) {
+ if (text->text == NULL)
+ return;
- lines->length = lastend - lines->text;
+ /* Free old array of lines */
+ e_text_free_lines (text);
- lines++;
- line_num++;
- len = cp - laststart;
- lines->text = laststart;
- laststart = p;
- lastend = cp;
- }
- }
-
- if (len == 0)
- lines->text = cp;
- lines->length = strlen (lines->text);
+ clip_width = text->clip_width;
+ if (clip_width >= 0 && text->draw_borders) {
+ clip_width -= 6;
+ if (clip_width < 0)
+ clip_width = 0;
+ }
+
+ /* First, count the number of lines */
+ text->num_lines = line_splitter (text->model, text->font, text->style,
+ text->break_characters,
+ text->line_wrap, text->clip_width, -1,
+ NULL, NULL);
+
+ /* Allocate our array of lines */
+ text->lines = g_new0 (struct line, text->num_lines);
+
+ text->num_lines = line_splitter (text->model, text->font, text->style,
+ text->break_characters,
+ text->line_wrap, text->clip_width, text->num_lines,
+ line_split_cb, text);
}
/* Convenience function to set the text's GC's foreground color */