diff options
author | Thomas White <taw@bitwiz.org.uk> | 2013-03-02 23:56:05 +0100 |
---|---|---|
committer | Thomas White <taw@bitwiz.org.uk> | 2013-03-02 23:56:05 +0100 |
commit | 5f85864f4d82a42f30160299d7897720e865c454 (patch) | |
tree | 7d7298d480f16706a547520bac908a638c098313 /src | |
parent | 59c7b765c44ee2ae3e81366bea2fc149e2466d13 (diff) |
New wrapping stuff
Diffstat (limited to 'src')
-rw-r--r-- | src/frame.h | 29 | ||||
-rw-r--r-- | src/mainwindow.c | 14 | ||||
-rw-r--r-- | src/render.c | 416 | ||||
-rw-r--r-- | src/render.h | 2 | ||||
-rw-r--r-- | src/wrap.c | 319 | ||||
-rw-r--r-- | src/wrap.h | 96 |
6 files changed, 492 insertions, 384 deletions
diff --git a/src/frame.h b/src/frame.h index 832473c..6c643ae 100644 --- a/src/frame.h +++ b/src/frame.h @@ -74,35 +74,6 @@ struct layout_parameters }; -enum wrap_box_type -{ - WRAP_BOX_PANGO, -}; - - -struct wrap_box -{ - enum wrap_box_type type; - int width; /* Pango units */ - - /* For type == WRAP_BOX_PANGO */ - PangoGlyphItem *glyph_item; - char *text; -}; - - -struct wrap_line -{ - int width; - int height; /* Pango units */ - int ascent; /* Pango units */ - - int n_boxes; - int max_boxes; - struct wrap_box *boxes; -}; - - struct frame { struct frame **children; diff --git a/src/mainwindow.c b/src/mainwindow.c index 4eb3549..05f5a3d 100644 --- a/src/mainwindow.c +++ b/src/mainwindow.c @@ -769,20 +769,15 @@ static void draw_editing_box(cairo_t *cr, struct frame *fr) static void draw_caret(cairo_t *cr, struct frame *fr, int pos) { -#if 0 - double xposd, yposd, cx; - double clow, chigh; + double xposd, yposd, line_height; + double cx, clow, chigh; const double t = 1.8; - pango_layout_get_cursor_pos(o->layout, - o->insertion_point+o->insertion_trail, - &pos, NULL); + get_cursor_pos(fr, pos, &xposd, &yposd, &line_height); - xposd = pos.x/PANGO_SCALE; cx = fr->x + xposd; - yposd = pos.y/PANGO_SCALE; clow = fr->y + yposd; - chigh = clow + (pos.height/PANGO_SCALE); + chigh = clow + line_height; cairo_move_to(cr, cx, clow); cairo_line_to(cr, cx, chigh); @@ -800,7 +795,6 @@ static void draw_caret(cairo_t *cr, struct frame *fr, int pos) cairo_set_source_rgb(cr, 0.86, 0.0, 0.0); cairo_set_line_width(cr, 1.0); cairo_stroke(cr); -#endif } diff --git a/src/render.c b/src/render.c index 0650f96..3077c36 100644 --- a/src/render.c +++ b/src/render.c @@ -38,293 +38,22 @@ #include "presentation.h" #include "frame.h" #include "render.h" +#include "wrap.h" -struct renderstuff +static void render_glyph_box(cairo_t *cr, struct wrap_box *box) { - cairo_t *cr; - PangoContext *pc; - PangoFontMap *fontmap; - PangoAttrList *attrs; - - /* Text for the block currently being processed */ - const char *cur_text; - int cur_len; - - int wrap_w; /* Pango units */ - - struct frame *fr; -}; - - -static void free_line_bits(struct wrap_line *l) -{ - int i; - for ( i=0; i<l->n_boxes; i++ ) { - - switch ( l->boxes[i].type ) { - - case WRAP_BOX_PANGO : - pango_glyph_item_free(l->boxes[i].glyph_item); - free(l->boxes[i].text); - break; - - } - - } - - free(l->boxes); -} - - -static void alloc_lines(struct frame *fr) -{ - struct wrap_line *lines_new; - - lines_new = realloc(fr->lines, fr->max_lines * sizeof(struct wrap_line)); - if ( lines_new == NULL ) { - fprintf(stderr, "Couldn't allocate memory for lines!\n"); - return; - } - - fr->lines = lines_new; -} - - -static void alloc_boxes(struct wrap_line *l) -{ - struct wrap_box *boxes_new; - - boxes_new = realloc(l->boxes, l->max_boxes * sizeof(struct wrap_box)); - if ( boxes_new == NULL ) { - fprintf(stderr, "Couldn't allocate memory for boxes!\n"); - return; - } - - l->boxes = boxes_new; -} - - -static void add_glyph_box_to_line(struct wrap_line *line, PangoGlyphItem *gi, - char *text) -{ - PangoRectangle rect; - int ascent; - - if ( line->n_boxes == line->max_boxes ) { - line->max_boxes += 32; - alloc_boxes(line); - if ( line->n_boxes == line->max_boxes ) return; - } - - pango_glyph_string_extents(gi->glyphs, gi->item->analysis.font, - NULL, &rect); - - line->boxes[line->n_boxes].type = WRAP_BOX_PANGO; - line->boxes[line->n_boxes].glyph_item = gi; - line->boxes[line->n_boxes].text = text; - line->boxes[line->n_boxes].width = rect.width; - line->n_boxes++; - - line->width += rect.width; - if ( line->height < rect.height ) line->height = rect.height; - - ascent = PANGO_ASCENT(rect); - if ( ascent > line->ascent ) line->ascent = ascent; -} - - -static const char *add_chars_to_line(struct renderstuff *s, - PangoGlyphItem *orig, int n, - const char *cur_text_ptr) -{ - int split_len; - char *split_ptr; - char *before_text; - - split_ptr = g_utf8_offset_to_pointer(cur_text_ptr, n); - before_text = strndup(cur_text_ptr, split_ptr-cur_text_ptr); - if ( before_text == NULL ) { - fprintf(stderr, "Failed to split text\n"); - /* But continue */ - } - - if ( n < orig->item->num_chars ) { - - PangoGlyphItem *before; - - split_len = split_ptr - cur_text_ptr; - - before = pango_glyph_item_split(orig, cur_text_ptr, split_len); - - add_glyph_box_to_line(&s->fr->lines[s->fr->n_lines], - before, before_text); - - orig->item->offset = 0; - - } else { - - PangoGlyphItem *copy; - copy = pango_glyph_item_copy(orig); - add_glyph_box_to_line(&s->fr->lines[s->fr->n_lines], - copy, before_text); - - } - - return split_ptr; -} - - -static void initialise_line(struct wrap_line *l) -{ - l->n_boxes = 0; - l->max_boxes = 32; - l->boxes = NULL; - l->width = 0; - l->height = 0; - l->ascent = 0; - alloc_boxes(l); -} - - -static void dispatch_line(struct renderstuff *s) -{ - s->fr->n_lines++; - - if ( s->fr->n_lines == s->fr->max_lines ) { - s->fr->max_lines += 32; - alloc_lines(s->fr); - if ( s->fr->n_lines == s->fr->max_lines ) return; - } - - initialise_line(&s->fr->lines[s->fr->n_lines]); -} - - -static void wrap_text(gpointer data, gpointer user_data) -{ - struct renderstuff *s = user_data; - PangoItem *item = data; - PangoGlyphString *glyphs; - PangoLogAttr *log_attrs; - PangoGlyphItem gitem; - int *log_widths; - int width_remain; - int width_used; - int i, pos, n; - const char *ptr; - - log_attrs = calloc(item->num_chars+1, sizeof(PangoLogAttr)); - if ( log_attrs == NULL ) { - fprintf(stderr, "Failed to allocate memory for log attrs\n"); - return; - } - - log_widths = calloc(item->num_chars+1, sizeof(int)); - if ( log_widths == NULL ) { - fprintf(stderr, "Failed to allocate memory for log widths\n"); - return; - } - - pango_get_log_attrs(s->cur_text, s->cur_len, -1, - pango_language_get_default(), - log_attrs, item->num_chars+1); - - glyphs = pango_glyph_string_new(); - pango_shape(s->cur_text+item->offset, item->length, &item->analysis, - glyphs); - - pango_glyph_string_get_logical_widths(glyphs, s->cur_text+item->offset, - item->length, 0, log_widths); - gitem.glyphs = glyphs; - gitem.item = item; - - /* FIXME: Replace this with a real typesetting algorithm */ - width_remain = s->wrap_w*PANGO_SCALE - - s->fr->lines[s->fr->n_lines].width; - width_used = 0; - pos = 0; - n = item->num_chars; - ptr = s->cur_text; - for ( i=0; i<n; i++ ) { - - if ( !log_attrs[i].is_char_break ) { - width_used += log_widths[i]; - pos++; - continue; - } - - if ( log_attrs[i].is_mandatory_break - || (log_widths[i] + width_used > width_remain) ) { - - ptr = add_chars_to_line(s, &gitem, pos, ptr); - - /* New line */ - dispatch_line(s); - width_remain = s->wrap_w * PANGO_SCALE; - width_used = 0; - pos = 0; - - } - - pos++; - width_used += log_widths[i]; - - } - ptr = add_chars_to_line(s, &gitem, pos, ptr); - - /* Don't dispatch the last line, because the next item might add - * more text to it, or the next SC block might add something else. */ - - free(log_widths); - free(log_attrs); -} - - -static void process_sc_block(struct renderstuff *s, const char *sc_name, - const char *sc_options, const char *sc_contents) -{ - size_t len; - GList *item_list; - - /* Only process textual blocks, for now */ - if ( sc_name != NULL ) return; - if ( sc_options != NULL ) { - fprintf(stderr, "Block has options. WTF?\n"); - return; - } - - /* Empty block? */ - if ( sc_contents == NULL ) return; - - len = strlen(sc_contents); - if ( len == 0 ) return; - - /* Create glyph string */ - item_list = pango_itemize(s->pc, sc_contents, 0, len, s->attrs, NULL); - s->cur_text = sc_contents; - s->cur_len = len; - g_list_foreach(item_list, wrap_text, s); - - g_list_free(item_list); -} - - -static double render_glyph_box(cairo_t *cr, struct wrap_box *box) -{ - double box_w; - if ( box->glyph_item == NULL ) { + if ( box->glyphs == NULL ) { fprintf(stderr, "Box %p has NULL pointer.\n", box); - return 0.0; + return; } - cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0); /* FIXME: Colour */ - pango_cairo_show_glyph_item(cr, box->text, box->glyph_item); - box_w = pango_glyph_string_get_width(box->glyph_item->glyphs); - return box_w; + cairo_set_source_rgba(cr, box->col[0], box->col[1], box->col[2], + box->col[3]); + pango_cairo_glyph_string_path(cr, box->font, box->glyphs); } -static void render_boxes(struct wrap_line *line, struct renderstuff *s) +static void render_boxes(struct wrap_line *line, cairo_t *cr) { int j; double x_pos = 0.0; @@ -333,65 +62,89 @@ static void render_boxes(struct wrap_line *line, struct renderstuff *s) struct wrap_box *box; - cairo_save(s->cr); + cairo_save(cr); box = &line->boxes[j]; - cairo_rel_move_to(s->cr, x_pos, 0.0); + cairo_rel_move_to(cr, x_pos, 0.0); switch ( line->boxes[j].type ) { case WRAP_BOX_PANGO : - render_glyph_box(s->cr, box); + render_glyph_box(cr, box); + break; + + case WRAP_BOX_IMAGE : + /* FIXME ! */ break; } x_pos += (double)line->boxes[j].width / PANGO_SCALE; - cairo_restore(s->cr); + cairo_restore(cr); } } -static void render_lines(struct renderstuff *s) +static void render_lines(struct frame *fr, cairo_t *cr) { int i; double y_pos = 0.0; - for ( i=0; i<s->fr->n_lines; i++ ) { + for ( i=0; i<fr->n_lines; i++ ) { - double asc = s->fr->lines[i].ascent/PANGO_SCALE; + double asc = fr->lines[i].ascent/PANGO_SCALE; - //cairo_move_to(s->cr, 0, y_pos+asc+0.5); - //cairo_line_to(s->cr, s->lines[i].width, y_pos+asc+0.5); - //cairo_set_source_rgb(s->cr, 0.0, 0.0, 0.0); - //cairo_set_line_width(s->cr, 1.0); - //cairo_stroke(s->cr); + //cairo_move_to(cr, 0, y_pos+asc+0.5); + //cairo_line_to(cr, s->lines[i].width, y_pos+asc+0.5); + //cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + //cairo_set_line_width(cr, 1.0); + //cairo_stroke(cr); /* Move to beginning of the line */ - cairo_move_to(s->cr, 0.0, asc+y_pos); + cairo_move_to(cr, 0.0, asc+y_pos); /* Render the line */ - render_boxes(&s->fr->lines[i], s); + render_boxes(&fr->lines[i], cr); /* FIXME: line spacing */ - y_pos += s->fr->lines[i].height/PANGO_SCALE + 0.0; + y_pos += fr->lines[i].height/PANGO_SCALE + 0.0; + + } +} + + +static void free_line_bits(struct wrap_line *l) +{ + int i; + for ( i=0; i<l->n_boxes; i++ ) { + + switch ( l->boxes[i].type ) { + + case WRAP_BOX_PANGO : + pango_glyph_string_free(l->boxes[i].glyphs); + free(l->boxes[i].text); + break; + + case WRAP_BOX_IMAGE : + break; + + } } + + free(l->boxes); } /* Render Level 1 Storycode (no subframes) */ static int render_sc(struct frame *fr) { - PangoFontDescription *fontdesc; - struct renderstuff s; - PangoAttribute *attr_font; - SCBlockList *bl; - SCBlockListIterator *iter; - struct scblock *b; int i; + cairo_t *cr; + PangoFontMap *fontmap; + PangoContext *pc; for ( i=0; i<fr->n_lines; i++ ) { free_line_bits(&fr->lines[i]); @@ -403,62 +156,37 @@ static int render_sc(struct frame *fr) if ( fr->sc == NULL ) return 0; - bl = sc_find_blocks(fr->sc, NULL); - - if ( bl == NULL ) { - printf("Failed to find blocks.\n"); - return 0; - } - - s.wrap_w = fr->w - fr->lop.pad_l - fr->lop.pad_r; - s.fr = fr; - s.fr->lines = NULL; - s.fr->n_lines = 0; - s.fr->max_lines = 64; - alloc_lines(s.fr); - initialise_line(&s.fr->lines[0]); - - /* Find and load font */ - s.fontmap = pango_cairo_font_map_get_default(); - s.pc = pango_font_map_create_context(s.fontmap); - fontdesc = pango_font_description_from_string("Sorts Mill Goudy 16"); - - /* Set up attribute list to use the font */ - s.attrs = pango_attr_list_new(); - attr_font = pango_attr_font_desc_new(fontdesc); - pango_attr_list_insert_before(s.attrs, attr_font); - pango_font_description_free(fontdesc); - - /* Iterate through SC blocks and send each one in turn for processing */ - for ( b = sc_block_list_first(bl, &iter); - b != NULL; - b = sc_block_list_next(bl, iter) ) - { - process_sc_block(&s, b->name, b->options, b->contents); - } - sc_block_list_free(bl); - dispatch_line(&s); - - /* Create surface and render the contents */ + /* Create surface and Cairo stuff */ if ( fr->contents != NULL ) cairo_surface_destroy(fr->contents); fr->contents = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, fr->w, fr->h); - s.cr = cairo_create(fr->contents); + cr = cairo_create(fr->contents); cairo_font_options_t *fopts; fopts = cairo_font_options_create(); cairo_font_options_set_hint_style(fopts, CAIRO_HINT_STYLE_NONE); cairo_font_options_set_hint_metrics(fopts, CAIRO_HINT_METRICS_DEFAULT); cairo_font_options_set_antialias(fopts, CAIRO_ANTIALIAS_GRAY); - cairo_set_font_options(s.cr, fopts); + cairo_set_font_options(cr, fopts); - cairo_translate(s.cr, fr->lop.pad_l, fr->lop.pad_t); - render_lines(&s); + /* Find and load font */ + fontmap = pango_cairo_font_map_get_default(); + pc = pango_font_map_create_context(fontmap); + /* Set up lines */ + if ( wrap_contents(fr, pc) ) { + fprintf(stderr, "Failed to wrap lines.\n"); + return 1; + } + + /* Actually render the lines */ + cairo_translate(cr, fr->lop.pad_l, fr->lop.pad_t); + render_lines(fr, cr); + + /* Tidy up */ cairo_font_options_destroy(fopts); - cairo_destroy(s.cr); - pango_attr_list_unref(s.attrs); - g_object_unref(s.pc); + cairo_destroy(cr); + g_object_unref(pc); return 0; } diff --git a/src/render.h b/src/render.h index 1ce9176..2502590 100644 --- a/src/render.h +++ b/src/render.h @@ -3,7 +3,7 @@ * * Colloquium - A tiny presentation program * - * Copyright (c) 2011 Thomas White <taw@bitwiz.org.uk> + * Copyright (c) 2011-2013 Thomas White <taw@bitwiz.org.uk> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/wrap.c b/src/wrap.c new file mode 100644 index 0000000..9948f70 --- /dev/null +++ b/src/wrap.c @@ -0,0 +1,319 @@ +/* + * wrap.c + * + * Colloquium - A tiny presentation program + * + * Copyright (c) 2012 Thomas White <taw@bitwiz.org.uk> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <pango/pangocairo.h> + +#include <storycode.h> + +#include "wrap.h" +#include "frame.h" + + +static void alloc_lines(struct frame *fr) +{ + struct wrap_line *lines_new; + + lines_new = realloc(fr->lines, fr->max_lines * sizeof(struct wrap_line)); + if ( lines_new == NULL ) { + fprintf(stderr, "Couldn't allocate memory for lines!\n"); + return; + } + + fr->lines = lines_new; +} + + +static void alloc_boxes(struct wrap_line *l) +{ + struct wrap_box *boxes_new; + + boxes_new = realloc(l->boxes, l->max_boxes * sizeof(struct wrap_box)); + if ( boxes_new == NULL ) { + fprintf(stderr, "Couldn't allocate memory for boxes!\n"); + return; + } + + l->boxes = boxes_new; +} + + +static void initialise_line(struct wrap_line *l) +{ + l->n_boxes = 0; + l->max_boxes = 32; + l->boxes = NULL; + l->width = 0; + l->height = 0; + l->ascent = 0; + alloc_boxes(l); +} + + +void get_cursor_pos(struct frame *fr, size_t pos, + double *xposd, double *yposd, double *line_height) +{ + signed int line; + int i; + + *xposd = 0; + *yposd = 0; + + line = 0; + for ( i=0; i<fr->n_lines; i++ ) { + line = i; + if ( fr->lines[i].sc_offset > pos ) { + line = i-1; + break; + } + *yposd += fr->lines[i].height; + *line_height = fr->lines[i].height / PANGO_SCALE; + } + assert(line >= 0); + + *xposd += fr->lop.pad_l; + + *yposd /= PANGO_SCALE; + *yposd += fr->lop.pad_t; +} + + +static void shape_and_measure(gpointer data, gpointer user_data) +{ + struct wrap_box *box = user_data; + PangoItem *item = data; + PangoRectangle rect; + + /* FIXME: Don't assume only one run per wrap box */ + box->glyphs = pango_glyph_string_new(); + + pango_shape(box->text+item->offset, item->length, &item->analysis, + box->glyphs); + + pango_glyph_string_extents(box->glyphs, box->font, NULL, &rect); + + box->width += rect.width; + if ( rect.height > box->height ) { + box->height = rect.height; + } + if ( PANGO_ASCENT(rect) > box->ascent ) { + box->ascent = PANGO_ASCENT(rect); + } +} + + +static void calc_line_geometry(struct wrap_line *line) +{ + int i; + + line->width = 0; + + for ( i=0; i<line->n_boxes; i++ ) { + struct wrap_box *box = &line->boxes[i]; + line->width += box->width; + if ( box->height > line->height ) line->height = box->height; + if ( box->ascent > line->ascent ) line->ascent = box->ascent; + } +} + + +/* Add "text", followed by a space of type "space", to "line" */ +static int add_wrap_box(struct wrap_line *line, char *text, + enum wrap_box_space space, PangoContext *pc, + PangoFont *font, double col[4]) +{ + GList *pango_items; + struct wrap_box *box; + + if ( line->n_boxes == line->max_boxes ) { + line->max_boxes += 32; + alloc_boxes(line); + if ( line->n_boxes == line->max_boxes ) return 1; + } + + box = &line->boxes[line->n_boxes]; + box->type = WRAP_BOX_PANGO; + box->text = text; + box->space = space; + box->font = font; + box->width = 0; + box->ascent = 0; + box->height = 0; + line->n_boxes++; + + pango_items = pango_itemize(pc, text, 0, strlen(text), NULL, NULL); + g_list_foreach(pango_items, shape_and_measure, box); + g_list_free(pango_items); + + return 0; +} + + +static int split_words(struct wrap_line *boxes, PangoContext *pc, char *sc, + PangoFont *font, double col[4]) +{ + PangoLogAttr *log_attrs; + size_t len; + size_t i, start; + + /* Empty block? */ + if ( sc == NULL ) return 1; + + len = strlen(sc); + if ( len == 0 ) return 1; + + log_attrs = malloc((len+1)*sizeof(PangoLogAttr)); + if ( log_attrs == NULL ) return 1; + + /* Create glyph string */ + pango_get_log_attrs(sc, len, -1, pango_language_get_default(), + log_attrs, len+1); + + start = 0; + for ( i=0; i<len; i++ ) { + + if ( log_attrs[i].is_line_break ) { + + char *word; + enum wrap_box_space type; + + /* Stuff up to (but not including) sc[i] forms a + * wap box */ + word = strndup(sc+start, i-start); + if ( word == NULL ) { + fprintf(stderr, "strndup() failed.\n"); + free(log_attrs); + return 1; + } + + if ( log_attrs[i].is_mandatory_break ) { + type = WRAP_SPACE_EOP; + } else if ( log_attrs[i].is_expandable_space ) { + type = WRAP_SPACE_INTERWORD; + } else { + type = WRAP_SPACE_NONE; + } + + add_wrap_box(boxes, word, type, pc, font, col); + start = i; + + } + + } + if ( i > start ) { + + char *word; + word = strndup(sc+start, i-start); + if ( word == NULL ) { + fprintf(stderr, "strndup() failed.\n"); + free(log_attrs); + return 1; + } + + add_wrap_box(boxes, word, WRAP_SPACE_NONE, pc, font, col); + + } + + free(log_attrs); + return 0; +} + + +static struct wrap_line *sc_to_wrap_boxes(const char *sc, PangoContext *pc) +{ + struct wrap_line *boxes; + SCBlockList *bl; + SCBlockListIterator *iter; + struct scblock *b; + PangoFontDescription *fontdesc; + PangoFont *font; + double col[4]; + + boxes = malloc(sizeof(struct wrap_line)); + if ( boxes == NULL ) { + fprintf(stderr, "Failed to allocate boxes.\n"); + return NULL; + } + initialise_line(boxes); + + bl = sc_find_blocks(sc, NULL); + + if ( bl == NULL ) { + printf("Failed to find blocks.\n"); + return NULL; + } + + /* FIXME: Determine the proper font to use */ + fontdesc = pango_font_description_from_string("Sorts Mill Goudy 16"); + font = pango_font_map_load_font(pango_context_get_font_map(pc), + pc, fontdesc); + pango_font_description_free(fontdesc); + col[0] = 0.0; col[1] = 0.0; col[2] = 0.0; col[3] = 1.0; + + /* Iterate through SC blocks and send each one in turn for processing */ + for ( b = sc_block_list_first(bl, &iter); + b != NULL; + b = sc_block_list_next(bl, iter) ) + { + if ( b->name == NULL ) { + if ( split_words(boxes, pc, b->contents, font, col) ) { + fprintf(stderr, "Splitting failed.\n"); + } + } + + /* FIXME: Handle images */ + } + sc_block_list_free(bl); + + return boxes; +} + + +/* Wrap the StoryCode inside "fr->sc" so that it fits within width "fr->w", + * and generate fr->lines */ +int wrap_contents(struct frame *fr, PangoContext *pc) +{ + struct wrap_line *boxes; + + /* Turn the StoryCode into wrap boxes, all on one line */ + boxes = sc_to_wrap_boxes(fr->sc, pc); + if ( boxes == NULL ) { + fprintf(stderr, "Failed to create wrap boxes.\n"); + return 1; + } + + /* FIXME: Hack for test purposes */ + calc_line_geometry(boxes); + fr->lines = boxes; + fr->n_lines = 1; + fr->max_lines = 1; + + return 0; +} + diff --git a/src/wrap.h b/src/wrap.h new file mode 100644 index 0000000..85609a3 --- /dev/null +++ b/src/wrap.h @@ -0,0 +1,96 @@ +/* + * wrap.h + * + * Colloquium - A tiny presentation program + * + * Copyright (c) 2012 Thomas White <taw@bitwiz.org.uk> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef WRAP_H +#define WRAP_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "frame.h" + + +enum wrap_box_type +{ + WRAP_BOX_PANGO, + WRAP_BOX_IMAGE +}; + + +/* Possible types of space following a wrap box */ +enum wrap_box_space +{ + WRAP_SPACE_INTERWORD, /* Normal inter-word space */ + WRAP_SPACE_NONE, /* Box ends with an explicit hyphen or an SC + * block boundary */ + WRAP_SPACE_EOP /* End of paragraph */ + /* TODO: Space between sentences etc */ +}; + + +/* A wrap box is a run of content - could be text, an image or so one - that is + * one logical unit as far as Colloquium is concerned. It might consist of + * multiple units, for example, in Pango's mind. */ +struct wrap_box +{ + enum wrap_box_type type; + + /* Pango units */ + int width; + int height; + int ascent; + + enum wrap_box_space space; /* Type of "space" following box */ + + /* For type == WRAP_BOX_PANGO */ + PangoGlyphString *glyphs; + PangoFont *font; + char *text; + double col[4]; /* rgba colour */ + + /* For type == WRAP_BOX_IMAGE */ + /* Nothing yet */ +}; + + +struct wrap_line +{ + int width; + int height; /* Pango units */ + int ascent; /* Pango units */ + + int n_boxes; + int max_boxes; + struct wrap_box *boxes; + + size_t sc_offset; +}; + + +extern int wrap_contents(struct frame *fr, PangoContext *pc); + +extern void get_cursor_pos(struct frame *fr, size_t pos, + double *xposd, double *yposd, double *line_height); + + +#endif /* WRAP_H */ |