diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/boxvec.c | 149 | ||||
-rw-r--r-- | src/boxvec.h | 70 | ||||
-rw-r--r-- | src/frame.c | 227 | ||||
-rw-r--r-- | src/frame.h | 40 | ||||
-rw-r--r-- | src/presentation.c | 1 | ||||
-rw-r--r-- | src/render.c | 251 | ||||
-rw-r--r-- | src/render.h | 5 | ||||
-rw-r--r-- | src/sc_editor.c | 614 | ||||
-rw-r--r-- | src/sc_editor.h | 5 | ||||
-rw-r--r-- | src/sc_interp.c | 63 | ||||
-rw-r--r-- | src/sc_interp.h | 6 | ||||
-rw-r--r-- | src/shape.c | 423 | ||||
-rw-r--r-- | src/shape.h | 50 | ||||
-rw-r--r-- | src/slide_window.c | 1 | ||||
-rw-r--r-- | src/wrap.c | 1032 | ||||
-rw-r--r-- | src/wrap.h | 144 |
16 files changed, 397 insertions, 2684 deletions
diff --git a/src/boxvec.c b/src/boxvec.c deleted file mode 100644 index e065a91..0000000 --- a/src/boxvec.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * boxvec.c - * - * Copyright © 2016 Thomas White <taw@bitwiz.org.uk> - * - * This file is part of Colloquium. - * - * Colloquium 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 <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> - -#include "boxvec.h" - - -int bv_len(struct boxvec *vec) -{ - return vec->n_boxes; -} - - -extern struct boxvec *bv_new() -{ - struct boxvec *n = malloc(sizeof(struct boxvec)); - if ( n == NULL ) return NULL; - - n->n_boxes = 0; - n->max_boxes = 0; - n->boxes = NULL; - - return n; -} - - -int bv_ensure_space(struct boxvec *vec, int n) -{ - struct wrap_box **t; - if ( vec == NULL ) return 1; - if ( vec->max_boxes > n ) return 0; - - n = (n/32)*32 + 32; - t = realloc(vec->boxes, n*sizeof(struct wrap_box *)); - if ( t == NULL ) return 1; - - vec->boxes = t; - return 0; -} - - -int bv_add(struct boxvec *vec, struct wrap_box *bx) -{ - if ( vec == NULL ) return 1; - if ( bv_ensure_space(vec, vec->n_boxes+1) ) return 1; - vec->boxes[vec->n_boxes++] = bx; - return 0; -} - - -static int find_box(struct boxvec *vec, struct wrap_box *bx) -{ - int i = 0; - while ( (i<vec->n_boxes) && (vec->boxes[i] != bx) ) i++; - return i; -} - - -void bv_del(struct boxvec *vec, struct wrap_box *bx) -{ - int n = find_box(vec, bx); - if ( n == vec->n_boxes ) { - fprintf(stderr, "Couldn't find box to delete it!\n"); - return; - } - assert(vec->boxes[n] == bx); - if ( n < vec->n_boxes-1 ) { - memmove(&vec->boxes[n], &vec->boxes[n+1], - (vec->n_boxes-n-1)*sizeof(struct wrap_box *)); - } - vec->n_boxes--; -} - - -int bv_add_after(struct boxvec *vec, struct wrap_box *bx, struct wrap_box *add) -{ - int n = find_box(vec, bx); - if ( n == vec->n_boxes ) { - fprintf(stderr, "Couldn't find box to add after!\n"); - return 1; - } - assert(vec->boxes[n] == bx); - - n++; - bv_ensure_space(vec, vec->n_boxes+1); - - if ( n < vec->n_boxes-1 ) { - memmove(&vec->boxes[n+1], &vec->boxes[n], - (vec->n_boxes-n)*sizeof(struct wrap_box *)); - } /* otherwise there's nothing to move */ - - vec->boxes[n] = add; - vec->n_boxes++; - - return 0; -} - - -struct wrap_box *bv_box(struct boxvec *vec, int i) -{ - assert(vec != NULL); - if ( i >= vec->n_boxes ) return NULL; - return vec->boxes[i]; -} - - -struct wrap_box *bv_last(struct boxvec *vec) -{ - if ( vec == NULL ) return NULL; - if ( vec->boxes == NULL ) return NULL; - return vec->boxes[vec->n_boxes-1]; -} - - -void bv_free(struct boxvec *vec) -{ - if ( vec == NULL ) return; - free(vec->boxes); - free(vec); -} - diff --git a/src/boxvec.h b/src/boxvec.h deleted file mode 100644 index 9538a35..0000000 --- a/src/boxvec.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * boxvec.h - * - * Copyright © 2016 Thomas White <taw@bitwiz.org.uk> - * - * This file is part of Colloquium. - * - * Colloquium 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 BOXVEC_H -#define BOXVEC_H - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdlib.h> -#include <string.h> -#include <assert.h> - - -/* A vector of boxes */ -struct boxvec -{ - int n_boxes; - int max_boxes; - struct wrap_box **boxes; -}; - - -/* Length of a boxvec */ -extern int bv_len(struct boxvec *vec); - -/* Create a bxvec or boxvec */ -extern struct boxvec *bv_new(void); - -/* Ensure space in a bxvec or boxvec */ -extern int bv_ensure_space(struct boxvec *vec, int n); - -/* Add to a bxvec or boxvec */ -extern int bv_add(struct boxvec *vec, struct wrap_box *bx); - -/* (Find and then) delete a box from a boxvec */ -extern void bv_del(struct boxvec *vec, struct wrap_box *bx); - -/* Add a new box after the specified one */ -extern int bv_add_after(struct boxvec *vec, struct wrap_box *bx, - struct wrap_box *add); - -/* Get a box from a boxvec or bxvec */ -extern struct wrap_box *bv_box(struct boxvec *vec, int i); -extern struct wrap_box *bv_last(struct boxvec *vec); - -/* Free a bxvec or boxvec */ -extern void bv_free(struct boxvec *vec); - -#endif /* BOXVEC_H */ diff --git a/src/frame.c b/src/frame.c index 7f41a41..c21589f 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1,7 +1,7 @@ /* * frame.c * - * Copyright © 2013 Thomas White <taw@bitwiz.org.uk> + * Copyright © 2013-2016 Thomas White <taw@bitwiz.org.uk> * * This file is part of Colloquium. * @@ -31,8 +31,38 @@ #include "sc_parse.h" #include "frame.h" -#include "wrap.h" -#include "boxvec.h" + + +struct text_run +{ + SCBlock *scblock; + size_t offs_bytes; + size_t len_bytes; + PangoFontDescription *fontdesc; +}; + + +struct _paragraph +{ + int n_runs; + struct text_run *runs; + int open; + + PangoLayout *layout; + double height; +}; + + +PangoLayout *paragraph_layout(Paragraph *para) +{ + return para->layout; +} + + +double paragraph_height(Paragraph *para) +{ + return para->height; +} static int alloc_ro(struct frame *fr) @@ -66,42 +96,38 @@ struct frame *frame_new() n->num_children = 0; n->scblocks = NULL; - n->n_paragraphs = 0; - n->paragraphs = NULL; - n->paragraph_start_lines = NULL; - n->lines = NULL; - n->n_lines = 0; - - n->boxes = bv_new(); + n->n_paras = 0; + n->paras = NULL; return n; } +static void free_paragraph(Paragraph *para) +{ + int i; + + for ( i=0; i<para->n_runs; i++ ) { + pango_font_description_free(para->runs[i].fontdesc); + } + free(para->runs); + if ( para->layout != NULL ) g_object_unref(para->layout); + free(para); +} + + void frame_free(struct frame *fr) { int i; if ( fr == NULL ) return; - /* Free all lines */ - for ( i=0; i<fr->n_lines; i++ ) { - wrap_line_free(&fr->lines[i]); - } - free(fr->lines); - /* Free paragraphs */ - if ( fr->paragraphs != NULL ) { - for ( i=0; i<fr->n_paragraphs; i++ ) { - free(fr->paragraphs[i]->boxes); - free(fr->paragraphs[i]); + if ( fr->paras != NULL ) { + for ( i=0; i<fr->n_paras; i++ ) { + free_paragraph(fr->paras[i]); } - free(fr->paragraphs); - } - /* Free unwrapped boxes */ - if ( fr->boxes != NULL ) { - free(fr->boxes->boxes); - free(fr->boxes); + free(fr->paras); } /* Free all children */ @@ -201,6 +227,7 @@ void delete_subframe(struct frame *top, struct frame *fr) parent->num_children--; } + struct frame *find_frame_with_scblocks(struct frame *fr, SCBlock *scblocks) { int i; @@ -215,3 +242,151 @@ struct frame *find_frame_with_scblocks(struct frame *fr, SCBlock *scblocks) return NULL; } + + +void wrap_paragraph(Paragraph *para, PangoContext *pc, double w) +{ + size_t total_len = 0; + int i; + char *text; + PangoAttrList *attrs; + PangoRectangle rect; + size_t pos = 0; + + for ( i=0; i<para->n_runs; i++ ) { + total_len += para->runs[i].len_bytes; + } + + /* Allocate the complete text */ + text = malloc(total_len+1); + if ( text == NULL ) { + fprintf(stderr, "Couldn't allocate combined text\n"); + return; + } + + /* Allocate the attributes */ + attrs = pango_attr_list_new(); + + /* Put all of the text together */ + text[0] = '\0'; + for ( i=0; i<para->n_runs; i++ ) { + + PangoAttribute *attr; + const char *run_text; + + run_text = sc_block_contents(para->runs[i].scblock) + + para->runs[i].offs_bytes; + + attr = pango_attr_font_desc_new(para->runs[i].fontdesc); + attr->start_index = pos; + attr->end_index = pos + para->runs[i].len_bytes; + pos += para->runs[i].len_bytes; + + strncat(text, run_text, para->runs[i].len_bytes); + pango_attr_list_insert(attrs, attr); + + } + + if ( para->layout == NULL ) { + para->layout = pango_layout_new(pc); + } + pango_layout_set_width(para->layout, pango_units_from_double(w)); + pango_layout_set_text(para->layout, text, total_len); + pango_layout_set_attributes(para->layout, attrs); + free(text); + pango_attr_list_unref(attrs); + + pango_layout_get_extents(para->layout, NULL, &rect); + para->height = pango_units_to_double(rect.height); +} + + +void add_run(Paragraph *para, SCBlock *scblock, size_t offs_bytes, + size_t len_bytes, PangoFontDescription *fdesc, int eop) +{ + struct text_run *runs_new; + + if ( !para->open ) { + fprintf(stderr, "Adding a run to a closed paragraph!\n"); + return; + } + + runs_new = realloc(para->runs, + (para->n_runs+1)*sizeof(struct text_run)); + if ( runs_new == NULL ) { + fprintf(stderr, "Failed to add run.\n"); + return; + } + + para->runs = runs_new; + para->runs[para->n_runs].scblock = scblock; + para->runs[para->n_runs].offs_bytes = offs_bytes; + para->runs[para->n_runs].len_bytes = len_bytes; + para->runs[para->n_runs].fontdesc = pango_font_description_copy(fdesc); + para->n_runs++; + + if ( eop ) para->open = 0; +} + + +void add_callback_para(struct frame *fr, double w, double h, + SCCallbackDrawFunc draw_func, + SCCallbackClickFunc click_func, void *bvp, + void *vp) +{ + /* FIXME */ +} + + +void add_image_para(struct frame *fr, const char *filename, + double w, double h, int editable) +{ + /* FIXME */ +} + + +double total_height(struct frame *fr) +{ + int i; + double t = 0.0; + for ( i=0; i<fr->n_paras; i++ ) { + t += fr->paras[i]->height + 20.0; + } + return t; +} + + +Paragraph *last_open_para(struct frame *fr) +{ + Paragraph **paras_new; + Paragraph *pnew; + + if ( (fr->paras != NULL) && (fr->paras[fr->n_paras-1]->open) ) { + return fr->paras[fr->n_paras-1]; + } + + /* No open paragraph found, create a new one */ + paras_new = realloc(fr->paras, (fr->n_paras+1)*sizeof(Paragraph *)); + if ( paras_new == NULL ) return NULL; + + pnew = calloc(1, sizeof(struct _paragraph)); + if ( pnew == NULL ) return NULL; + + fr->paras = paras_new; + fr->paras[fr->n_paras++] = pnew; + + pnew->open = 1; + pnew->n_runs = 0; + pnew->runs = NULL; + pnew->layout = NULL; + pnew->height = 0.0; + + return pnew; +} + + +void close_last_paragraph(struct frame *fr) +{ + if ( fr->paras == NULL ) return; + fr->paras[fr->n_paras-1]->open = 0; +} diff --git a/src/frame.h b/src/frame.h index 8b1a645..99e5df4 100644 --- a/src/frame.h +++ b/src/frame.h @@ -1,7 +1,7 @@ /* * frame.h * - * Copyright © 2013-2015 Thomas White <taw@bitwiz.org.uk> + * Copyright © 2013-2016 Thomas White <taw@bitwiz.org.uk> * * This file is part of Colloquium. * @@ -31,6 +31,7 @@ #include <cairo.h> #include "sc_parse.h" +#include "sc_interp.h" typedef enum @@ -47,6 +48,7 @@ typedef enum GRAD_VERT } GradientType; +typedef struct _paragraph Paragraph; struct frame { @@ -55,16 +57,10 @@ struct frame int max_children; SCBlock *scblocks; - struct boxvec *boxes; /* The unwrapped boxes */ - int visited; - int n_paragraphs; - struct boxvec **paragraphs; - int *paragraph_start_lines; - - int n_lines; - int max_lines; - struct wrap_line *lines; + Paragraph **paras; + int n_paras; + int max_paras; /* The font which will be used by default for this frame */ PangoFontDescription *fontdesc; @@ -94,9 +90,6 @@ struct frame /* True if this frame can be resized and moved */ int resizable; - - /* True if wrapping failed for this frame */ - int trouble; }; @@ -108,4 +101,25 @@ extern void delete_subframe(struct frame *top, struct frame *fr); extern struct frame *find_frame_with_scblocks(struct frame *top, SCBlock *scblocks); +extern double total_height(struct frame *fr); + +extern Paragraph *last_open_para(struct frame *fr); +extern void close_last_paragraph(struct frame *fr); + +extern PangoLayout *paragraph_layout(Paragraph *para); +extern double paragraph_height(Paragraph *para); + +extern void add_run(Paragraph *para, SCBlock *scblock, size_t offs_bytes, + size_t len_bytes, PangoFontDescription *fdesc, int eop); + +extern void add_callback_para(struct frame *fr, double w, double h, + SCCallbackDrawFunc draw_func, + SCCallbackClickFunc click_func, void *bvp, + void *vp); + +extern void add_image_para(struct frame *fr, const char *filename, + double w, double h, int editable); + +extern void wrap_paragraph(Paragraph *para, PangoContext *pc, double w); + #endif /* FRAME_H */ diff --git a/src/presentation.c b/src/presentation.c index 98f9ecc..60c27f8 100644 --- a/src/presentation.c +++ b/src/presentation.c @@ -34,7 +34,6 @@ #include "slide_window.h" #include "frame.h" #include "imagestore.h" -#include "wrap.h" #include "notes.h" #include "inhibit_screensaver.h" #include "render.h" diff --git a/src/render.c b/src/render.c index 506863d..b91509f 100644 --- a/src/render.c +++ b/src/render.c @@ -40,30 +40,10 @@ #include "presentation.h" #include "frame.h" #include "render.h" -#include "wrap.h" #include "imagestore.h" -#include "boxvec.h" - - -static void render_glyph_box(cairo_t *cr, struct wrap_box *box) -{ - int i; - - cairo_new_path(cr); - cairo_move_to(cr, 0.0, 0.0); - if ( box->segs == NULL ) { - fprintf(stderr, "Box %p has NULL pointer.\n", box); - return; - } - cairo_set_source_rgba(cr, box->col[0], box->col[1], box->col[2], - box->col[3]); - for ( i=0; i<box->n_segs; i++ ) { - pango_cairo_show_glyph_string(cr, box->font, - box->segs[i].glyphs); - } -} +#if 0 static void render_callback_box(cairo_t *cr, struct wrap_box *box) { double ascd; @@ -112,8 +92,10 @@ static void render_callback_box(cairo_t *cr, struct wrap_box *box) cairo_surface_destroy(surf); } +#endif +#if 0 static void render_image_box(cairo_t *cr, struct wrap_box *box, ImageStore *is, enum is_size isz) { @@ -160,172 +142,9 @@ static void render_image_box(cairo_t *cr, struct wrap_box *box, ImageStore *is, cairo_fill(cr); cairo_restore(cr); } +#endif -static void UNUSED draw_outline(cairo_t *cr, struct wrap_box *box) -{ - double asc, desc; - - if ( box->type == WRAP_BOX_SENTINEL ) return; - - asc = pango_units_to_double(box->ascent); - desc = pango_units_to_double(box->height) - asc; - - cairo_rectangle(cr, 0.0, -asc, pango_units_to_double(box->width), - asc + desc); - if ( box->type == WRAP_BOX_NOTHING ) { - cairo_set_source_rgb(cr, 0.0, 0.0, 1.0); - cairo_set_line_width(cr, 0.1); - } else if ( box->type == WRAP_BOX_SENTINEL ) { - cairo_set_source_rgb(cr, 1.0, 0.0, 1.0); - cairo_set_line_width(cr, 0.5); - } else { - cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); - cairo_set_line_width(cr, 0.1); - } - cairo_stroke(cr); - - cairo_rectangle(cr, pango_units_to_double(box->width), -asc, - pango_units_to_double(box->sp), asc + desc); - cairo_set_source_rgba(cr, 0.7, 0.4, 0.7, 0.2); - cairo_fill(cr); -} - - -static void render_boxes(struct wrap_line *line, cairo_t *cr, ImageStore *is, - enum is_size isz) -{ - int j; - double x_pos = 0.0; - - for ( j=0; j<bv_len(line->boxes); j++ ) { - - struct wrap_box *box; - - cairo_save(cr); - - box = bv_box(line->boxes, j); - cairo_translate(cr, x_pos, 0.0); - - draw_outline(cr, box); - - switch ( box->type ) { - - case WRAP_BOX_PANGO : - render_glyph_box(cr, box); - break; - - case WRAP_BOX_IMAGE : - render_image_box(cr, box, is, isz); - break; - - case WRAP_BOX_CALLBACK: - render_callback_box(cr, box); - break; - - case WRAP_BOX_NOTHING : - break; - - case WRAP_BOX_SENTINEL : - /* Do nothing */ - break; - - } - - x_pos += pango_units_to_double(box->width); - x_pos += pango_units_to_double(box->sp); - - cairo_restore(cr); - - } -} - - -static void draw_overfull_marker(cairo_t *cr, struct frame *fr, int i) -{ - cairo_move_to(cr, fr->w - fr->pad_l- fr->pad_r, 0.0); - cairo_line_to(cr, fr->w - fr->pad_l - fr->pad_r, - pango_units_to_double(fr->lines[i].height)); - cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); - cairo_set_line_width(cr, 4.0); - cairo_stroke(cr); -} - - -static void draw_underfull_marker(cairo_t *cr, struct frame *fr, int i) -{ - cairo_move_to(cr, fr->w - fr->pad_l- fr->pad_r, 0.0); - cairo_line_to(cr, fr->w - fr->pad_l - fr->pad_r, - pango_units_to_double(fr->lines[i].height)); - cairo_set_source_rgb(cr, 0.0, 0.0, 1.0); - cairo_set_line_width(cr, 4.0); - cairo_stroke(cr); -} - - -static void render_lines(struct frame *fr, cairo_t *cr, ImageStore *is, - enum is_size isz, double min_y, double max_y) -{ - int i; - double y_pos = 0.0; - const int debug = 0; - - for ( i=0; i<fr->n_lines; i++ ) { - - /* FIXME: Line spacing */ - double lh = pango_units_to_double(fr->lines[i].height); - - if ( y_pos+lh < min_y ) { - y_pos += lh; - continue; - } - - if ( y_pos > max_y ) break; - - cairo_save(cr); - - /* Move to beginning of the line */ - cairo_translate(cr, 0.0, y_pos); - - if ( debug ) { - cairo_move_to(cr, - 0.0, - 0.5+pango_units_to_double(fr->lines[i].ascent)); - cairo_line_to(cr, - pango_units_to_double(fr->lines[i].width), - 0.5+pango_units_to_double(fr->lines[i].ascent)); - cairo_set_source_rgb(cr, 0.0, 0.0, 1.0); - cairo_set_line_width(cr, 1.0); - cairo_stroke(cr); - - cairo_move_to(cr, 0.0, 0.0); - cairo_line_to(cr, 0.0, - pango_units_to_double(fr->lines[i].height)); - cairo_set_line_width(cr, 3.0); - cairo_set_source_rgb(cr, 0.0, 1.0, 0.0); - cairo_stroke(cr); - } - - /* Render the line */ - cairo_save(cr); - cairo_translate(cr, 0.0, - pango_units_to_double(fr->lines[i].ascent)); - render_boxes(&fr->lines[i], cr, is, isz); - cairo_restore(cr); - - if ( debug && fr->lines[i].overfull ) { - draw_overfull_marker(cr, fr, i); - } - if ( debug && fr->lines[i].underfull ) { - draw_underfull_marker(cr, fr, i); - } - - y_pos += lh; - - cairo_restore(cr); - - } -} static void do_background(cairo_t *cr, struct frame *fr) @@ -375,23 +194,34 @@ static void do_background(cairo_t *cr, struct frame *fr) } +static void render_paragraph(cairo_t *cr, Paragraph *para) +{ + PangoLayout *layout = paragraph_layout(para); + cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0); + pango_cairo_update_layout(cr, layout); + pango_cairo_show_layout(cr, layout); + cairo_fill(cr); +} + + static int draw_frame(cairo_t *cr, struct frame *fr, ImageStore *is, enum is_size isz, double min_y, double max_y) { + int i; + double hpos = 0.0; + cairo_save(cr); do_background(cr, fr); - if ( fr->trouble ) { - cairo_new_path(cr); - cairo_rectangle(cr, 0.0, 0.0, fr->w, fr->h); - cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); - cairo_set_line_width(cr, 2.0); - cairo_stroke(cr); - } - - /* Actually render the lines */ + /* Actually render the contents */ cairo_translate(cr, fr->pad_l, fr->pad_t); - render_lines(fr, cr, is, isz, min_y, max_y); + for ( i=0; i<fr->n_paras; i++ ) { + cairo_save(cr); + cairo_translate(cr, 0.0, hpos); + render_paragraph(cr, fr->paras[i]); + hpos += paragraph_height(fr->paras[i]) + 20.0; + cairo_restore(cr); + } cairo_restore(cr); return 0; @@ -419,15 +249,24 @@ int recursive_draw(struct frame *fr, cairo_t *cr, } -int recursive_wrap(struct frame *fr, ImageStore *is, enum is_size isz) +void wrap_frame(struct frame *fr, PangoContext *pc) +{ + int i; + + for ( i=0; i<fr->n_paras; i++ ) { + wrap_paragraph(fr->paras[i], pc, fr->w - fr->pad_l - fr->pad_r); + } +} + + +int recursive_wrap(struct frame *fr, PangoContext *pc) { int i; - /* Wrap boxes -> wrap lines */ - wrap_contents(fr); + wrap_frame(fr, pc); for ( i=0; i<fr->num_children; i++ ) { - recursive_wrap(fr->children[i], is, isz); + recursive_wrap(fr->children[i], pc); } return 0; @@ -498,7 +337,8 @@ static struct frame *render_sc_to_surface(SCBlock *scblocks, cairo_surface_t *su cairo_t *cr, double log_w, double log_h, SCBlock **stylesheets, SCCallbackList *cbl, ImageStore *is, enum is_size isz, - int slide_number, PangoLanguage *lang) + int slide_number, PangoLanguage *lang, + PangoContext *pc) { struct frame *top; @@ -509,7 +349,7 @@ static struct frame *render_sc_to_surface(SCBlock *scblocks, cairo_surface_t *su top = interp_and_shape(scblocks, stylesheets, cbl, is, isz, slide_number, cr, log_w, log_h, lang); - recursive_wrap(top, is, isz); + recursive_wrap(top, pc); recursive_draw(top, cr, is, isz, 0.0, log_h); @@ -527,13 +367,15 @@ cairo_surface_t *render_sc(SCBlock *scblocks, int w, int h, cairo_surface_t *surf; cairo_t *cr; struct frame *top; + PangoContext *pc; surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); cr = cairo_create(surf); + pc = pango_cairo_create_context(cr); cairo_scale(cr, w/log_w, h/log_h); top = render_sc_to_surface(scblocks, surf, cr, log_w, log_h, stylesheets, cbl, is, isz,slide_number, - lang); + lang, pc); cairo_destroy(cr); *ptop = top; @@ -551,6 +393,7 @@ int export_pdf(struct presentation *p, const char *filename) cairo_t *cr; SCBlock *bl; int i; + PangoContext *pc; r = p->slide_height / p->slide_width; @@ -562,6 +405,7 @@ int export_pdf(struct presentation *p, const char *filename) cr = cairo_create(surf); scale = w / p->slide_width; + pc = pango_cairo_create_context(cr); i = 1; while ( bl != NULL ) { @@ -586,7 +430,7 @@ int export_pdf(struct presentation *p, const char *filename) render_sc_to_surface(sc_block_child(bl), surf, cr, p->slide_width, p->slide_height, stylesheets, NULL, - p->is, ISZ_SLIDESHOW, i, p->lang); + p->is, ISZ_SLIDESHOW, i, p->lang, pc); cairo_restore(cr); @@ -597,6 +441,7 @@ int export_pdf(struct presentation *p, const char *filename) } + g_object_unref(pc); cairo_surface_finish(surf); cairo_destroy(cr); diff --git a/src/render.h b/src/render.h index 486f129..be9bfd8 100644 --- a/src/render.h +++ b/src/render.h @@ -1,7 +1,7 @@ /* * render.h * - * Copyright © 2013-2015 Thomas White <taw@bitwiz.org.uk> + * Copyright © 2013-2016 Thomas White <taw@bitwiz.org.uk> * * This file is part of Colloquium. * @@ -50,7 +50,8 @@ extern struct frame *interp_and_shape(SCBlock *scblocks, SCBlock **stylesheets, int slide_number, cairo_t *cr, double w, double h, PangoLanguage *lang); -extern int recursive_wrap(struct frame *fr, ImageStore *is, enum is_size isz); +extern void wrap_frame(struct frame *fr, PangoContext *pc); +extern int recursive_wrap(struct frame *fr, PangoContext *pc); extern int export_pdf(struct presentation *p, const char *filename); diff --git a/src/sc_editor.c b/src/sc_editor.c index 27ab849..9b81980 100644 --- a/src/sc_editor.c +++ b/src/sc_editor.c @@ -38,13 +38,10 @@ #include "slide_window.h" #include "render.h" #include "frame.h" -#include "wrap.h" #include "sc_parse.h" #include "sc_interp.h" #include "sc_editor.h" #include "slideshow.h" -#include "shape.h" -#include "boxvec.h" static void scroll_interface_init(GtkScrollable *iface) @@ -118,12 +115,17 @@ static void update_size(SCEditor *e) static gboolean resize_sig(GtkWidget *widget, GdkEventConfigure *event, SCEditor *e) { + PangoContext *pc; + cairo_t *cr; + + cr = gdk_cairo_create(gtk_widget_get_window(widget)); + pc = pango_cairo_create_context(cr); + e->visible_height = event->height; e->visible_width = event->width; /* Interpret and shape, if not already done */ if ( e->top == NULL ) { - cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(widget)); double w, h; if ( e->flow ) { w = event->width; @@ -135,8 +137,7 @@ static gboolean resize_sig(GtkWidget *widget, GdkEventConfigure *event, e->top = interp_and_shape(e->scblocks, e->stylesheets, e->cbl, e->is, ISZ_EDITOR, 0, cr, w, h, e->lang); - recursive_wrap(e->top, e->is, ISZ_EDITOR); - cairo_destroy(cr); + recursive_wrap(e->top, pc); } if ( e->flow ) { @@ -145,11 +146,15 @@ static gboolean resize_sig(GtkWidget *widget, GdkEventConfigure *event, e->top->h = 0.0; /* To be updated in a moment */ e->top->x = 0.0; e->top->y = 0.0; - wrap_contents(e->top); /* Only the top level needs to be wrapped */ + /* Only the top level needs to be wrapped */ + wrap_frame(e->top, pc); } update_size(e); + g_object_unref(pc); + cairo_destroy(cr); + return FALSE; } @@ -301,7 +306,7 @@ void sc_editor_set_background(SCEditor *e, double r, double g, double b) void sc_editor_remove_cursor(SCEditor *e) { e->cursor_frame = NULL; - e->cursor_line = 0; + e->cursor_para = 0; e->cursor_pos = 0; e->selection = NULL; } @@ -312,26 +317,30 @@ void sc_editor_remove_cursor(SCEditor *e) * invalid. The cursor position will be unset. */ static void full_rerender(SCEditor *e) { + cairo_t *cr; + PangoContext *pc; + frame_free(e->top); - e->cursor_frame = NULL; - e->cursor_line = 0; - e->cursor_pos = 0; - e->selection = NULL; + sc_editor_remove_cursor(e); + + cr = gdk_cairo_create(gtk_widget_get_window(GTK_WIDGET(e))); + pc = pango_cairo_create_context(cr); - cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(GTK_WIDGET(e))); e->top = interp_and_shape(e->scblocks, e->stylesheets, e->cbl, e->is, ISZ_EDITOR, 0, cr, e->w, 0.0, e->lang); - cairo_destroy(cr); e->top->x = 0.0; e->top->y = 0.0; e->top->w = e->w; e->top->h = 0.0; /* To be updated in a moment */ - recursive_wrap(e->top, e->is, ISZ_EDITOR); + recursive_wrap(e->top, pc); update_size(e); sc_editor_redraw(e); + + g_object_unref(pc); + cairo_destroy(cr); } @@ -353,182 +362,24 @@ void sc_editor_delete_selected_frame(SCEditor *e) } -static void move_cursor_back(SCEditor *e) +static int find_cursor(struct frame *fr, double x, double y, + int *ppara, int *ppos) { - int retreat = 0; - signed int cp, cb, cl; - struct wrap_line *line; - struct wrap_box *box; - - cp = e->cursor_pos; - cb = e->cursor_box; - cl = e->cursor_line; - - line = &e->cursor_frame->lines[e->cursor_line]; - box = bv_box(line->boxes, e->cursor_box); - if ( box->type == WRAP_BOX_PANGO ) { - - if ( cp == 0 ) { - retreat = 1; - } else { - cp--; - } - - } else { - cp--; - if ( cp < 0 ) retreat = 1; - } - - if ( retreat ) { - - do { - - cb--; - - if ( cb < 0 ) { - cl--; - if ( cl < 0 ) return; - e->cursor_line = cl; - line = &e->cursor_frame->lines[cl]; - cb = bv_len(line->boxes) - 1; - } - - } while ( !bv_box(line->boxes, cb)->editable ); - - e->cursor_box = cb; - box = bv_box(line->boxes, cb); - if ( box->type == WRAP_BOX_PANGO ) { - cp = box->len_chars; - if ( box->space == WRAP_SPACE_NONE ) { - cp--; - } - } else { - cp = 0; - } - - } - e->cursor_pos = cp; + *ppara = 0; + *ppos = 0; + return 0; } -void cur_box_diag(SCEditor *e) +static void move_cursor_back(SCEditor *e) { - int sln, sbx, sps; - struct frame *fr; - - fr = e->cursor_frame; - sln = e->cursor_line; - sbx = e->cursor_box; - sps = e->cursor_pos; - - if ( fr->lines == NULL ) { - printf("Current frame has no lines!\n"); - return; - } - - if ( fr->lines[sln].boxes == NULL ) { - printf("line %i of %i, but it has no boxes\n", - sln, fr->n_lines); - return; - } - - struct wrap_box *sbox = bv_box(fr->lines[sln].boxes, sbx); - - if ( sbox == NULL ) { - printf("line/box: [%i of %i]/[%i of %i]/NULL box\n", - sln, fr->n_lines, sbx, - bv_len(e->cursor_frame->lines[sln].boxes)); - return; - } - - printf("line/box/pos: [%i of %i]/[%i of %i]/[%i of %i]\n", - sln, fr->n_lines, sbx, bv_len(e->cursor_frame->lines[sln].boxes), - sps, sbox->len_chars); - printf("box type is %i, space type is %i\n", sbox->type, sbox->space); - if ( sbox->type == WRAP_BOX_NOTHING ) { - printf("Warning: in a nothing box!\n"); - } - - struct wrap_line *ln = &fr->lines[sln]; - int i; - for ( i=0; i<bv_len(ln->boxes); i++ ) { - char pp = '['; - char pq = ']'; - struct wrap_box *bx = bv_box(ln->boxes, i); - if ( i == sbx ) { pp = '<'; pq = '>'; } - printf("%c%i %i %i%c", pp, bx->offs_char, bx->len_chars, - bx->n_segs, pq); - } - printf("\n"); + /* FIXME */ } void advance_cursor(SCEditor *e) { - int advance = 0; - signed int cp, cb, cl; - struct wrap_line *line = &e->cursor_frame->lines[e->cursor_line]; - struct wrap_box *box = bv_box(line->boxes, e->cursor_box); - - cp = e->cursor_pos; - cb = e->cursor_box; - cl = e->cursor_line; - - /* FIXME: For Pango boxes, we should be counting cursor positions, not - * characters */ - - switch ( box->type ) { - - case WRAP_BOX_PANGO: - if ( cp+1 > box->len_chars ) { - advance = 1; - } else { - cp++; - } - break; - - case WRAP_BOX_NOTHING: - case WRAP_BOX_SENTINEL: - advance = 1; - break; - - case WRAP_BOX_IMAGE: - case WRAP_BOX_CALLBACK: - cp++; - if ( cp > 1 ) advance = 1; - break; - - } - - if ( advance ) { - - do { - - cb++; - cp = 0; - - if ( box->space == WRAP_SPACE_NONE ) { - cp = 1; - } - - if ( cb >= bv_len(line->boxes) ) { - cl++; - if ( cl >= e->cursor_frame->n_lines ) { - /* Give up - could not move */ - return; - } - line = &e->cursor_frame->lines[cl]; - cb = 0; - cp = 0; - } - - } while ( !bv_box(line->boxes, cb)->editable ); - - e->cursor_line = cl; - e->cursor_box = cb; - - } - e->cursor_pos = cp; + /* FIXME */ } @@ -569,39 +420,23 @@ static void draw_editing_box(cairo_t *cr, struct frame *fr) } -static void draw_caret(cairo_t *cr, struct frame *fr, - int cursor_line, int cursor_box, int cursor_pos) +static void draw_caret(cairo_t *cr, struct frame *fr) { - double xposd, yposd, line_height; - double cx, clow, chigh; +#if 0 + double xposd, yposd, cx; + double clow, chigh; + PangoRectangle pos; const double t = 1.8; - struct wrap_box *box; - int i; - if ( fr == NULL ) return; - if ( fr->n_lines == 0 ) return; - if ( fr->lines == NULL ) return; - if ( fr->lines[cursor_line].boxes == NULL ) return; - - /* Locate the cursor in a "logical" and "geographical" sense */ - box = bv_box(fr->lines[cursor_line].boxes, cursor_box); - get_cursor_pos(box, cursor_pos, &xposd, &yposd, &line_height); - xposd += fr->pad_l; - yposd += fr->pad_t; - - for ( i=0; i<cursor_line; i++ ) { - yposd += pango_units_to_double(fr->lines[i].height); - } - - for ( i=0; i<cursor_box; i++ ) { - int w = bv_box(fr->lines[cursor_line].boxes, i)->width; - w += bv_box(fr->lines[cursor_line].boxes, i)->sp; - xposd += pango_units_to_double(w); - } + pango_layout_get_cursor_pos(o->layout, + o->insertion_point+o->insertion_trail, + &pos, NULL); - cx = fr->x + xposd; - clow = fr->y + yposd; - chigh = clow + line_height; + xposd = pos.x/PANGO_SCALE; + cx = o->base.x - o->offs_x + xposd; + yposd = pos.y/PANGO_SCALE; + clow = o->base.y - o->offs_y + yposd; + chigh = clow + (pos.height/PANGO_SCALE); cairo_move_to(cr, cx, clow); cairo_line_to(cr, cx, chigh); @@ -619,6 +454,7 @@ static void draw_caret(cairo_t *cr, struct frame *fr, cairo_set_source_rgb(cr, 0.86, 0.0, 0.0); cairo_set_line_width(cr, 1.0); cairo_stroke(cr); +#endif } @@ -652,8 +488,7 @@ static void draw_overlay(cairo_t *cr, SCEditor *e) draw_resize_handle(cr, x+w-20.0, y+h-20.0); } - draw_caret(cr, e->cursor_frame, e->cursor_line, e->cursor_box, - e->cursor_pos); + draw_caret(cr, e->cursor_frame); } @@ -726,49 +561,6 @@ static gboolean draw_sig(GtkWidget *da, cairo_t *cr, SCEditor *e) } -static void fixup_cursor(SCEditor *e) -{ - struct frame *fr; - struct wrap_line *sline; - struct wrap_box *sbox; - - fr = e->cursor_frame; - - if ( e->cursor_line >= fr->n_lines ) { - /* We find ourselves on a line which doesn't exist */ - e->cursor_line = fr->n_lines-1; - e->cursor_box = bv_len(fr->lines[fr->n_lines-1].boxes)-1; - } - - sline = &fr->lines[e->cursor_line]; - - if ( e->cursor_box >= bv_len(sline->boxes) ) { - - /* We find ourselves in a box which doesn't exist */ - - if ( e->cursor_line < fr->n_lines-1 ) { - /* This isn't the last line, so go to the first box of - * the next line */ - e->cursor_line++; - e->cursor_box = 0; - sline = &e->cursor_frame->lines[e->cursor_line]; - } else { - /* There are no more lines, so just go to the end */ - e->cursor_line = fr->n_lines-1; - sline = &e->cursor_frame->lines[e->cursor_line]; - e->cursor_box = bv_len(sline->boxes)-1; - } - } - - assert(e->cursor_box < bv_len(sline->boxes)); - sbox = bv_box(sline->boxes, e->cursor_box); - - if ( e->cursor_pos > sbox->len_chars ) { - advance_cursor(e); - } -} - - static void move_cursor(SCEditor *e, signed int x, signed int y) { if ( x > 0 ) { @@ -781,6 +573,8 @@ static void move_cursor(SCEditor *e, signed int x, signed int y) void insert_scblock(SCBlock *scblock, SCEditor *e) { +#if 0 + /* FIXME: Insert "scblock" at the cursor */ int sln, sbx, sps; struct wrap_box *sbox; struct frame *fr = e->cursor_frame; @@ -804,303 +598,21 @@ void insert_scblock(SCBlock *scblock, SCEditor *e) //fixup_cursor(e); //advance_cursor(e); //sc_editor_redraw(e); +#endif } -static void shift_box_offsets(struct frame *fr, struct wrap_box *box, int n) -{ - int i; - int sn = 0; - - for ( i=0; i<fr->boxes->n_boxes; i++ ) { - if ( bv_box(fr->boxes, i) == box ) { - sn = i+1; - break; - } - } - - assert(sn > 0); /* Lowest it can possibly be is 1 */ - - for ( i=sn; i<fr->boxes->n_boxes; i++ ) { - bv_box(fr->boxes, i)->offs_char += n; - } -} - - -static void maybe_downgrade_box(struct wrap_box *box) -{ - if ( box->len_chars == 0 ) { - - printf("Downgrading box.\n"); - box->type = WRAP_BOX_NOTHING; - } -} - - -static void split_boxes(struct wrap_box *sbox, PangoLogAttr *log_attrs, - int offs, int cursor_pos, struct boxvec *boxes, - PangoContext *pc) -{ - struct wrap_box *nbox; - - printf("Adding line break (new box) at pos %i\n", offs); - printf("offset %i into box\n", cursor_pos); - - /* Add a new box containing the text after the break */ - nbox = calloc(1, sizeof(struct wrap_box)); - if ( nbox == NULL ) { - fprintf(stderr, "Failed to allocate a text box.\n"); - return; - } - bv_add_after(boxes, sbox, nbox); - nbox->type = WRAP_BOX_PANGO; - nbox->space = sbox->space; - nbox->len_chars = sbox->len_chars - cursor_pos; - if ( nbox->len_chars == 0 ) { - printf("WARNING! Zero-length box!\n"); - } - nbox->offs_char = sbox->offs_char + cursor_pos; - nbox->scblock = sbox->scblock; - nbox->fontdesc = pango_font_description_copy(sbox->fontdesc); - nbox->col[0] = sbox->col[0]; - nbox->col[1] = sbox->col[1]; - nbox->col[2] = sbox->col[2]; - nbox->col[3] = sbox->col[3]; - nbox->editable = sbox->editable; - - /* Shorten the text in the first box */ - sbox->len_chars = cursor_pos; - if ( log_attrs[offs].is_expandable_space ) { - sbox->space = WRAP_SPACE_INTERWORD; - nbox->len_chars--; - nbox->offs_char++; - maybe_downgrade_box(nbox); - } else if ( log_attrs[offs+1].is_mandatory_break ) { - sbox->space = WRAP_SPACE_EOP; - printf("New paragraph!\n"); - nbox->offs_char++; - nbox->len_chars--; - maybe_downgrade_box(nbox); - } else { - sbox->space = WRAP_SPACE_NONE; - printf("two boxes.\n"); - } - - printf("boxes: <%i %i %i>[%i %i %i]\n", - sbox->offs_char, sbox->len_chars, sbox->n_segs, - nbox->offs_char, nbox->len_chars, nbox->n_segs); - - itemize_and_shape(nbox, pc); - /* sbox will get done in just a moment */ -} - - -static void fixup_line_breaks(struct wrap_box *sbox, struct boxvec *boxes, - int cursor_pos, PangoLanguage *lang, - PangoContext *pc) -{ - const char *text; - size_t len_bytes; - int len_chars; - PangoLogAttr *log_attrs; - int offs; - - /* Run pango_get_log_attrs on the entire SCBlock, to get good context */ - text = sc_block_contents(sbox->scblock); - len_bytes = strlen(text); - len_chars = g_utf8_strlen(text, -1); - if ( len_chars <= 1 ) return; - log_attrs = malloc((len_chars+1)*sizeof(PangoLogAttr)); - if ( log_attrs == NULL ) return; - pango_get_log_attrs(text, len_bytes, -1, lang, - log_attrs, len_chars+1); - - /* Take a peek at the situation near where we just typed */ - offs = sbox->offs_char + cursor_pos; - if ( log_attrs[offs+1].is_line_break ) { - - /* If there just happens to be two boxes without a space - * between them, just tweak the space. */ - if ( (cursor_pos == sbox->len_chars-1) - && (sbox->space == WRAP_SPACE_NONE) ) - { - printf("Easy case! :D\n"); - if ( log_attrs[offs].is_expandable_space ) { - sbox->space = WRAP_SPACE_INTERWORD; - sbox->len_chars--; - } else if ( log_attrs[offs+1].is_mandatory_break ) { - sbox->space = WRAP_SPACE_EOP; - sbox->len_chars--; - } else { - printf("WTF space type?\n"); - } - } else { - split_boxes(sbox, log_attrs, offs, cursor_pos, - boxes, pc); - } - - - } else { - if ( log_attrs[offs].is_expandable_space ) { - printf("Space at end!\n"); - if ( sbox->space == WRAP_SPACE_NONE ) { - sbox->space = WRAP_SPACE_INTERWORD; - } - } - } - - free(log_attrs); -} - static void insert_text(char *t, SCEditor *e) { - int sln, sbx, sps; - struct wrap_box *sbox; - struct frame *fr = e->cursor_frame; - - printf("insert! ---------------------------------------------------\n"); - - if ( fr == NULL ) return; - - /* If this is, say, the top level frame, do nothing */ - if ( fr->boxes == NULL ) return; - - sln = e->cursor_line; - sbx = e->cursor_box; - sps = e->cursor_pos; - sbox = bv_box(e->cursor_frame->lines[sln].boxes, sbx); - - if ( sbox->type == WRAP_BOX_NOTHING ) { - printf("Upgrading nothing box %p to Pango box\n", sbox); - sbox->type = WRAP_BOX_PANGO; - sbox->col[0] = fr->col[0]; - sbox->col[1] = fr->col[1]; - sbox->col[2] = fr->col[2]; - sbox->col[3] = fr->col[3]; - sbox->fontdesc = pango_font_description_copy(fr->fontdesc); - sbox->segs = NULL; - } - - cur_box_diag(e); - printf("sps=%i, offs_char=%i\n", sps, sbox->offs_char); - if ( sbox->type == WRAP_BOX_NOTHING ) { - printf("Editing a nothing box!\n"); - return; - } - - sc_insert_text(sbox->scblock, sps+sbox->offs_char, t); - sbox->len_chars += 1; - - /* Tweak the offsets of all the subsequent boxes */ - shift_box_offsets(fr, sbox, 1); - - fixup_line_breaks(sbox, e->cursor_frame->boxes, e->cursor_pos, - e->lang, e->pc); - - /* The box must be analysed by Pango again, because the segments - * might have changed */ - itemize_and_shape(sbox, e->pc); - - fr->empty = 0; - - wrap_contents(e->cursor_frame); - update_size(e); - fixup_cursor(e); - printf("done! -----------------------------------------------------\n"); - - advance_cursor(e); - + /* FIXME: Insert "t" at the cursor */ sc_editor_redraw(e); } static void do_backspace(struct frame *fr, SCEditor *e) { - int sln, sbx, sps; - - if ( fr == NULL ) return; - - /* If this is, say, the top level frame, do nothing */ - if ( fr->n_lines == 0 ) return; - - printf("Backspace! ------------------------------------------------\n"); - printf("sbox:\n"); - cur_box_diag(e); - sln = e->cursor_line; - sbx = e->cursor_box; - sps = e->cursor_pos; - struct wrap_box *sbox = bv_box(e->cursor_frame->lines[sln].boxes, sbx); - - move_cursor_back(e); - printf("fbox:\n"); - cur_box_diag(e); - - /* Delete may cross wrap boxes and maybe SCBlock boundaries */ - struct wrap_line *fline = &e->cursor_frame->lines[e->cursor_line]; - struct wrap_box *fbox = bv_box(fline->boxes, e->cursor_box); - - if ( (fbox->scblock == NULL) || (sbox->scblock == NULL) ) return; - sc_delete_text(fbox->scblock, e->cursor_pos+fbox->offs_char, - sbox->scblock, sps+sbox->offs_char); - - if ( (sps == 0) && (fbox->space == WRAP_SPACE_INTERWORD) ) { - - /* We are deleting an interword space. - * It's enough just to change the space type, and leave two - * boxes butted up with no space. */ - fbox->space = WRAP_SPACE_NONE; - shift_box_offsets(fr, fbox, -1); - itemize_and_shape(fbox, e->pc); - - } else if ( (sps == 0) && (fbox->space == WRAP_SPACE_NONE) ) { - - /* We are deleting across a box boundary, but there is no - * space to delete */ - if ( fbox->len_chars == 0 ) { - printf("Deleting a zero-length box\n"); - - } else { - fbox->len_chars -= 1; - shift_box_offsets(fr, fbox, -1); - itemize_and_shape(fbox, e->pc); - } - - } else if ( (sps == 0) && (fbox->space == WRAP_SPACE_EOP) ) { - - /* We are deleting the newline between paragraphs */ - fbox->space = WRAP_SPACE_NONE; - shift_box_offsets(fr, fbox, -1); - itemize_and_shape(fbox, e->pc); - - } else { - - sbox->len_chars -= 1; - shift_box_offsets(fr, sbox, -1); - if ( sbox->len_chars == 0 ) { - - if ( sbox->space == WRAP_SPACE_NONE ) { - printf("deleting box.\n"); - bv_del(e->cursor_frame->boxes, sbox); - free(sbox); - } else { - printf("downgrading box.\n"); - sbox->type = WRAP_BOX_NOTHING; - sbox->width = 0; - } - - } else { - itemize_and_shape(sbox, e->pc); - } - - } - - wrap_contents(e->cursor_frame); - update_size(e); - fixup_cursor(e); - cur_box_diag(e); - printf("done! -----------------------------------------------------\n"); - + /* FIXME: Delete at the cursor */ sc_editor_redraw(e); } @@ -1296,14 +808,10 @@ static void calculate_box_size(struct frame *fr, SCEditor *e, } -static struct wrap_box *cbox(struct frame *fr, int ln, int bn) -{ - return bv_box(fr->lines[ln].boxes, bn);; -} - - static int callback_click(SCEditor *e, struct frame *fr, double x, double y) { +#if 0 +/* FIXME */ int ln, bn, pn; struct wrap_box *bx; @@ -1315,6 +823,7 @@ static int callback_click(SCEditor *e, struct frame *fr, double x, double y) if ( bx->type == WRAP_BOX_CALLBACK ) { return bx->click_func(x, y, bx->bvp, bx->vp); } +#endif return 0; } @@ -1372,8 +881,7 @@ static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event, e->cursor_frame = clicked; find_cursor(clicked, x-fr->x, y-fr->y, - &e->cursor_line, &e->cursor_box, - &e->cursor_pos); + &e->cursor_para, &e->cursor_pos); e->start_corner_x = event->x - e->border_offs_x; e->start_corner_y = event->y - e->border_offs_y; @@ -1406,8 +914,7 @@ static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event, e->selection = clicked; e->cursor_frame = clicked; find_cursor(clicked, x-clicked->x, y-clicked->y, - &e->cursor_line, &e->cursor_box, - &e->cursor_pos); + &e->cursor_para, &e->cursor_pos); } @@ -1568,10 +1075,8 @@ static gboolean button_release_sig(GtkWidget *da, GdkEventButton *event, e->drag_corner_y - e->start_corner_y); e->selection = fr; e->cursor_frame = fr; - e->cursor_line = 0; - e->cursor_box = 0; + e->cursor_para = 0; e->cursor_pos = 0; - cur_box_diag(e); break; case DRAG_REASON_IMPORT : @@ -1664,9 +1169,6 @@ static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event, full_rerender(e); break; - case GDK_KEY_F6 : - cur_box_diag(e); - } if ( claim ) return TRUE; diff --git a/src/sc_editor.h b/src/sc_editor.h index 166e640..99afa50 100644 --- a/src/sc_editor.h +++ b/src/sc_editor.h @@ -117,9 +117,8 @@ struct _sceditor /* Location of the cursor */ struct frame *cursor_frame; - int cursor_line; - int cursor_box; - int cursor_pos; /* characters into box */ + int cursor_para; /* paragraph index */ + int cursor_pos; /* character offset into paragraph */ /* Border surrounding actual slide within drawingarea */ double border_offs_x; diff --git a/src/sc_interp.c b/src/sc_interp.c index 35531b6..3291725 100644 --- a/src/sc_interp.c +++ b/src/sc_interp.c @@ -33,8 +33,7 @@ #include "sc_parse.h" #include "sc_interp.h" -#include "shape.h" -#include "wrap.h" +#include "presentation.h" struct macro @@ -217,9 +216,9 @@ static void do_callback(SCInterpreter *scin, SCBlock *bl, const char *name) if ( strcmp(cbl->names[i], name) != 0 ) continue; r = cbl->box_funcs[i](scin, bl, &w, &h, &bvp, cbl->vps[i]); if ( !r ) return; - add_callback_box(sc_interp_get_frame(scin)->boxes, w, h, - cbl->draw_funcs[i], cbl->click_funcs[i], - bvp, cbl->vps[i]); + add_callback_para(sc_interp_get_frame(scin), w, h, + cbl->draw_funcs[i], cbl->click_funcs[i], + bvp, cbl->vps[i]); return; } @@ -812,6 +811,52 @@ static int in_macro(SCInterpreter *scin) } +/* Add the SCBlock to the text in 'frame', at the end */ +static int add_text(struct frame *fr, PangoContext *pc, SCBlock *bl, + PangoLanguage *lang, int editable, SCInterpreter *scin) +{ + glong len_chars; + const char *text = sc_block_contents(bl); + size_t start, len_bytes; + PangoFontDescription *fontdesc; + + /* Empty block? */ + if ( text == NULL ) return 1; + + /* Zero-length block? */ + len_chars = g_utf8_strlen(text, -1); + if ( len_chars == 0 ) return 1; + + fontdesc = sc_interp_get_fontdesc(scin); + + len_bytes = strlen(text); + start = 0; + do { + + char *para_end; + size_t len; + + para_end = strchr(text+start, '\n'); + if ( para_end == NULL ) { + len = strlen(text+start); + } else { + len = para_end - (text+start); + } + + if ( text[start] == '\n' ) { + close_last_paragraph(fr); + } else { + Paragraph *para = last_open_para(fr); + add_run(para, bl, start, len, fontdesc, 0); + } + start += len + 1; + + } while ( start < len_bytes ); + + return 0; +} + + static int check_outputs(SCBlock *bl, SCInterpreter *scin) { const char *name = sc_block_name(bl); @@ -819,8 +864,8 @@ static int check_outputs(SCBlock *bl, SCInterpreter *scin) SCBlock *child = sc_block_child(bl); if ( name == NULL ) { - split_words(sc_interp_get_frame(scin)->boxes, - scin->pc, bl, scin->lang, 1, scin); + add_text(sc_interp_get_frame(scin), + scin->pc, bl, scin->lang, 1, scin); } else if ( strcmp(name, "image")==0 ) { double w, h; @@ -828,8 +873,8 @@ static int check_outputs(SCBlock *bl, SCInterpreter *scin) if ( parse_image_options(options, sc_interp_get_frame(scin), &w, &h, &filename) == 0 ) { - add_image_box(sc_interp_get_frame(scin)->boxes, - filename, w, h, 1); + add_image_para(sc_interp_get_frame(scin), + filename, w, h, 1); free(filename); } else { fprintf(stderr, "Invalid image options '%s'\n", diff --git a/src/sc_interp.h b/src/sc_interp.h index e5f4d0a..54e2233 100644 --- a/src/sc_interp.h +++ b/src/sc_interp.h @@ -1,7 +1,7 @@ /* * sc_interp.h * - * Copyright © 2014-2015 Thomas White <taw@bitwiz.org.uk> + * Copyright © 2014-2016 Thomas White <taw@bitwiz.org.uk> * * This file is part of Colloquium. * @@ -29,7 +29,7 @@ #include <pango/pangocairo.h> -#include "frame.h" +struct frame; struct presentation; typedef struct _scinterp SCInterpreter; @@ -39,6 +39,8 @@ typedef int (*SCCallbackBoxFunc)(SCInterpreter *scin, SCBlock *bl, typedef cairo_surface_t *(*SCCallbackDrawFunc)(int w, int h, void *, void *); typedef int (*SCCallbackClickFunc)(double x, double y, void *, void *); +#include "frame.h" + extern SCInterpreter *sc_interp_new(PangoContext *pc, PangoLanguage *lang, struct frame *top); extern void sc_interp_destroy(SCInterpreter *scin); diff --git a/src/shape.c b/src/shape.c deleted file mode 100644 index 44e9256..0000000 --- a/src/shape.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * shape.c - * - * Copyright © 2014-2015 Thomas White <taw@bitwiz.org.uk> - * - * This file is part of Colloquium. - * - * Colloquium 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 "wrap.h" -#include "sc_interp.h" -#include "shape.h" -#include "boxvec.h" - - -static void shape_segment(struct wrap_box *box, struct text_seg *seg) -{ - PangoRectangle rect; - const char *tp; - const char *ep; - - if ( seg->len_chars == 0 ) { - fprintf(stderr, "Shaping a zero-length segment\n"); - return; - } - - tp = g_utf8_offset_to_pointer(sc_block_contents(box->scblock), - box->offs_char + seg->offs_char); - ep = g_utf8_offset_to_pointer(sc_block_contents(box->scblock), - box->offs_char + seg->offs_char - + seg->len_chars); - - if ( seg->glyphs != NULL ) { - pango_glyph_string_free(seg->glyphs); - } - //printf("shaping '%s' (%i chars)\n", tp, seg->len_chars); - seg->glyphs = pango_glyph_string_new(); - pango_shape(tp, ep-tp, &seg->analysis, seg->glyphs); - - pango_glyph_string_extents(seg->glyphs, box->font, NULL, &rect); - - seg->width = rect.width; - seg->height = rect.height; - seg->ascent = PANGO_ASCENT(rect); -} - - -static void calc_box_geometry(struct wrap_box *box) -{ - int i; - - if ( box->type != WRAP_BOX_PANGO ) return; - - box->width = 0; - box->height = 0; - box->ascent = 0; - - for ( i=0; i<box->n_segs; i++ ) { - struct text_seg *seg = &box->segs[i]; - box->width += seg->width; - if ( seg->height > box->height ) box->height = seg->height; - if ( seg->ascent > box->ascent ) box->ascent = seg->ascent; - } -} - - -void shape_box(struct wrap_box *box) -{ - int i; - printf("shaping box %p! n_segs=%i\n", box, box->n_segs); - - for ( i=0; i<box->n_segs; i++ ) { - shape_segment(box, &box->segs[i]); - } - - calc_box_geometry(box); -} - - -static void add_nothing_box(struct boxvec *boxes, SCBlock *scblock, - int editable, enum wrap_box_space sp, - SCInterpreter *scin, size_t offs) -{ - struct wrap_box *box; - - box = calloc(1, sizeof(struct wrap_box)); - if ( box == NULL ) { - fprintf(stderr, "Failed to allocate a nothing box.\n"); - return; - } - box->type = WRAP_BOX_NOTHING; - box->scblock = scblock; - box->offs_char = offs; - box->space = sp; - box->width = 0; - box->len_chars = 0; - box->ascent = sc_interp_get_ascent(scin); - box->height = sc_interp_get_height(scin); - box->filename = NULL; - box->editable = editable; - box->segs = NULL; - box->n_segs = 0; - bv_add(boxes, box); -} - - -static UNUSED char *swizzle(const char *inp, size_t len) -{ - int i; - char *out = malloc(len+1); - strncpy(out, inp, len); - out[len] = '\0'; - for ( i=0; i<len; i++ ) { - if ( out[i] == '\n' ) out[i] = '`'; - } - return out; -} - - -static UNUSED void debug_log_attrs(size_t len_chars, const char *text, - PangoLogAttr *log_attrs) -{ - int i; - const gchar *p = text; - - if ( !g_utf8_validate(text, -1, NULL) ) { - fprintf(stderr, "Invalid UTF8!\n"); - return; - } - - for ( i=0; i<len_chars; i++ ) { - gunichar c = g_utf8_get_char(p); - p = g_utf8_next_char(p); - if ( c == '\n' ) { - printf("`"); - } else { - printf("%lc", c); - } - } - printf("\n"); - for ( i=0; i<=len_chars; i++ ) { - if ( log_attrs[i].is_line_break ) { - if ( log_attrs[i].is_mandatory_break ) { - printf("n"); - } else { - printf("b"); - } - } else { - printf("."); - } - } - printf("\n"); -} - - -static void add_seg(gpointer vi, gpointer vb) -{ - PangoItem *item = vi; - struct wrap_box *box = vb; - - box->segs[box->n_segs].analysis = item->analysis; - box->segs[box->n_segs].glyphs = NULL; - box->segs[box->n_segs].offs_char = item->offset; - box->segs[box->n_segs].len_chars = item->num_chars; - shape_segment(box, &box->segs[box->n_segs++]); -} - - -int itemize_and_shape(struct wrap_box *box, PangoContext *pc) -{ - GList *pango_items; - PangoAttrList *attrs; - PangoAttribute *attr; - char *tptr; - char *eptr; - const char *text; - int nseg; - - text = sc_block_contents(box->scblock); - tptr = g_utf8_offset_to_pointer(text, box->offs_char); - eptr = g_utf8_offset_to_pointer(tptr, box->len_chars); - - /* Fill in the font, needed later for rendering */ - box->font = pango_font_map_load_font(pango_context_get_font_map(pc), - pc, box->fontdesc); - - attrs = pango_attr_list_new(); - attr = pango_attr_font_desc_new(box->fontdesc); - pango_attr_list_insert_before(attrs, attr); - pango_items = pango_itemize(pc, tptr, 0, eptr-tptr, attrs, NULL); - nseg = g_list_length(pango_items); - box->segs = malloc(nseg * sizeof(struct text_seg)); - if ( box->segs == NULL ) return 1; - - box->n_segs = 0; - g_list_foreach(pango_items, add_seg, box); - g_list_free(pango_items); - pango_attr_list_unref(attrs); - - calc_box_geometry(box); - - return 0; -} - - -/* Add "text", followed by a space of type "space", to "line" */ -static int add_text_box(struct boxvec *boxes, - enum wrap_box_space space, PangoContext *pc, - SCInterpreter *scin, SCBlock *bl, size_t offs, - size_t len, int editable) -{ - struct wrap_box *box; - const char *tp; - double *col; - - while ( len==0 ) { - add_nothing_box(boxes, bl, editable, space, scin, offs); - return 0; - } - - /* Create the box */ - box = calloc(1, sizeof(struct wrap_box)); - if ( box == NULL ) { - fprintf(stderr, "Failed to allocate a text box.\n"); - return 1; - } - - box->type = WRAP_BOX_PANGO; - box->space = space; - box->fontdesc = pango_font_description_copy(sc_interp_get_fontdesc(scin)); - box->width = 0; - box->editable = editable; - box->ascent = sc_interp_get_ascent(scin); - box->height = sc_interp_get_height(scin); - - /* Link to the actual text */ - box->scblock = bl; - tp = sc_block_contents(bl); - box->offs_char = g_utf8_pointer_to_offset(tp, tp+offs); - box->len_chars = g_utf8_strlen(tp+offs, len); - - col = sc_interp_get_fgcol(scin); - box->col[0] = col[0]; /* Red */ - box->col[1] = col[1]; /* Green */ - box->col[2] = col[2]; /* Blue */ - box->col[3] = col[3]; /* Alpha */ - - if ( itemize_and_shape(box, pc) == 0 ) { - bv_add(boxes, box); - } else { - fprintf(stderr, "Shaping error!\n"); - return 1; - } - - return 0; -} - - -void add_callback_box(struct boxvec *boxes, double w, double h, - SCCallbackDrawFunc draw_func, - SCCallbackClickFunc click_func, void *bvp, void *vp) -{ - struct wrap_box *box; - - box = calloc(1, sizeof(struct wrap_box)); - if ( box == NULL ) { - fprintf(stderr, "Failed to allocate a callback box.\n"); - return; - } - - box->type = WRAP_BOX_CALLBACK; - box->scblock = NULL; - box->offs_char = 0; - box->space = WRAP_SPACE_NONE; - box->width = pango_units_from_double(w); - box->ascent = pango_units_from_double(h); - box->height = pango_units_from_double(h); - box->draw_func = draw_func; - box->click_func = click_func; - box->bvp = bvp; - box->vp = vp; - box->editable = 0; - bv_add(boxes, box); -} - - -void add_image_box(struct boxvec *boxes, const char *filename, - int w, int h, int editable) -{ - struct wrap_box *box; - - box = calloc(1, sizeof(struct wrap_box)); - if ( box == NULL ) { - fprintf(stderr, "Failed to allocate a callback box.\n"); - return; - } - - box->type = WRAP_BOX_IMAGE; - box->scblock = NULL; - box->offs_char = 0; - box->space = WRAP_SPACE_NONE; - box->width = pango_units_from_double(w); - box->ascent = pango_units_from_double(h); - box->height = pango_units_from_double(h); - box->filename = strdup(filename); - box->editable = editable; - bv_add(boxes, box); -} - - -int split_words(struct boxvec *boxes, PangoContext *pc, SCBlock *bl, - PangoLanguage *lang, int editable, SCInterpreter *scin) -{ - PangoLogAttr *log_attrs; - glong len_chars, i; - size_t len_bytes, start; - int chars_done; - const char *text = sc_block_contents(bl); - - /* Empty block? */ - if ( text == NULL ) return 1; - - len_chars = g_utf8_strlen(text, -1); - if ( len_chars == 0 ) { - add_text_box(boxes, WRAP_SPACE_NONE, pc, scin, bl, - 0, 0, editable); - return 1; - } - - len_bytes = strlen(text); - - log_attrs = malloc((len_chars+1)*sizeof(PangoLogAttr)); - if ( log_attrs == NULL ) return 1; - - pango_get_log_attrs(text, len_bytes, -1, lang, log_attrs, len_chars+1); - - //debug_log_attrs(len_chars, text, log_attrs); - - start = 0; - chars_done = 0; - for ( i=0; i<len_chars; i++ ) { - - if ( log_attrs[i].is_line_break ) { - - enum wrap_box_space type; - size_t len; - char *ptr; - size_t offs; - - ptr = g_utf8_offset_to_pointer(text, i); - offs = ptr - text; - - /* Stuff up to (but not including) sc[i] forms a - * wrap box */ - len = offs - start; - if ( log_attrs[i].is_mandatory_break ) { - type = WRAP_SPACE_EOP; - if ( (i>0) && (g_utf8_prev_char(ptr)[0]=='\n') ) len--; - } else if ( (i>0) - && log_attrs[i-1].is_expandable_space ) { - type = WRAP_SPACE_INTERWORD; - len--; - } else { - type = WRAP_SPACE_NONE; - } - - if ( add_text_box(boxes, type, pc, scin, bl, - start, len, editable) ) { - fprintf(stderr, "Failed to add wrap box.\n"); - } - start = offs; - chars_done = i; - - } - - } - - /* Add the stuff left over at the end */ - if ( i > chars_done ) { - - size_t l = strlen(text+start); - - if ( (text[start+l-1] == '\n') ) { - - /* There is a newline at the end of the SC */ - add_text_box(boxes, WRAP_SPACE_EOP, pc, scin, bl, - start, l-1, editable); - - } else { - - add_text_box(boxes, WRAP_SPACE_NONE, pc, scin, bl, - start, l, editable); - - } - - } - - free(log_attrs); - return 0; -} diff --git a/src/shape.h b/src/shape.h deleted file mode 100644 index f9e1758..0000000 --- a/src/shape.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * shape.h - * - * Copyright © 2014-2015 Thomas White <taw@bitwiz.org.uk> - * - * This file is part of Colloquium. - * - * Colloquium 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 SHAPE_H -#define SHAPE_H - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <pango/pangocairo.h> - -#include "wrap.h" - -extern void shape_box(struct wrap_box *box); - -extern int split_words(struct boxvec *boxes, PangoContext *pc, - SCBlock *bl, PangoLanguage *lang, - int editable, SCInterpreter *scin); - -extern int itemize_and_shape(struct wrap_box *box, PangoContext *pc); - -extern void add_image_box(struct boxvec *line, const char *filename, - int w, int h, int editable); - -extern void add_callback_box(struct boxvec *boxes, double w, double h, - SCCallbackDrawFunc draw_func, - SCCallbackClickFunc click_func, - void *bvp, void *vp); - -#endif /* SHAPE_H */ diff --git a/src/slide_window.c b/src/slide_window.c index 478deb5..b232e58 100644 --- a/src/slide_window.c +++ b/src/slide_window.c @@ -38,7 +38,6 @@ #include "render.h" #include "frame.h" #include "slideshow.h" -#include "wrap.h" #include "notes.h" #include "pr_clock.h" #include "sc_parse.h" diff --git a/src/wrap.c b/src/wrap.c deleted file mode 100644 index 6d0ea60..0000000 --- a/src/wrap.c +++ /dev/null @@ -1,1032 +0,0 @@ -/* - * wrap.c - * - * Text wrapping, hyphenation, justification etc - * - * Copyright © 2013-2016 Thomas White <taw@bitwiz.org.uk> - * - * This file is part of Colloquium. - * - * Colloquium 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 <math.h> -#include <gdk/gdk.h> - -#include "sc_parse.h" -#include "sc_interp.h" -#include "wrap.h" -#include "frame.h" -#include "presentation.h" -#include "boxvec.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; -} - - -void initialise_line(struct wrap_line *l) -{ - l->width = 0; - l->height = 0; - l->ascent = 0; - l->last_line = 0; - l->overfull = 0; - l->boxes = bv_new(); -} - - -#if 0 -static struct wrap_line *get_cursor_line(struct frame *fr, size_t pos, - double *yposd) -{ - int line = 0; - int i; - int found = 0; - - *yposd = 0; - - for ( i=0; i<fr->n_lines; i++ ) { - if ( fr->lines[i].sc_offset > pos ) { - line = i-1; - found = 1; - break; - } - } - if ( !found ) { - /* Cursor is on the last line */ - line = fr->n_lines-1; - } - if ( line < 0 ) { - printf("Couldn't find cursor.\n"); - return NULL; - } - for ( i=0; i<line; i++ ) { - *yposd += fr->lines[i].height; - } - - *yposd /= PANGO_SCALE; - *yposd += fr->pad_t; - - return &fr->lines[line]; -} -#endif - - -int which_segment(struct wrap_box *box, int pos, int *err) -{ - int i = 0; - int ch = 0; - - if ( box->type != WRAP_BOX_PANGO ) { - fprintf(stderr, "which_segment() called on wrong box type.\n"); - *err = 1; - return 0; - } - - do { - if ( ch + box->segs[i].len_chars >= pos ) break; - ch += box->segs[i++].len_chars; - } while ( i < box->n_segs ); - - if ( i == box->n_segs ) { - fprintf(stderr, "Position not found in box!\n"); - *err = 1; - return 0; - } - - *err = 0; - return i; -} - - -/* Return the horizontal position of "pos" within "box", in cairo units */ -static double text_box_index_to_x(struct wrap_box *box, int pos) -{ - double x = 0.0; - int nseg; - struct text_seg *seg; - const char *seg_text; - const char *ep; - int p; - int i; - int err; - ptrdiff_t offs_p; - - nseg = which_segment(box, pos, &err); - if ( err ) return 0.0; - - for ( i=0; i<nseg; i++ ) { - PangoRectangle rect; - pango_glyph_string_extents(box->segs[i].glyphs, - box->font, NULL, &rect); - x += rect.width; - } - - /* We are in "seg" inside "box" */ - seg = &box->segs[nseg]; - seg_text = g_utf8_offset_to_pointer(sc_block_contents(box->scblock), - box->offs_char + seg->offs_char); - ep = g_utf8_offset_to_pointer(seg_text, seg->len_chars); - - /* Make character position relative to segment start (not box start) */ - pos -= seg->offs_char; - - /* Convert the character position to a byte offset */ - offs_p = g_utf8_offset_to_pointer(seg_text, pos) - seg_text; - - pango_glyph_string_index_to_x(seg->glyphs, (char *)seg_text, - ep - seg_text, &seg->analysis, - offs_p, FALSE, &p); - - return pango_units_to_double(x+p); -} - - -void get_cursor_pos(struct wrap_box *box, int pos, - double *xposd, double *yposd, double *line_height) -{ - *xposd = 0.0; - *yposd = 0.0; - *line_height = 20.0; - - if ( box == NULL ) return; - - *line_height = pango_units_to_double(box->height); - - if ( !box->editable ) { - *xposd += pango_units_to_double(box->width); - return; - } - - switch ( box->type ) { - - case WRAP_BOX_PANGO : - *xposd += text_box_index_to_x(box, pos); - break; - - case WRAP_BOX_IMAGE : - if ( pos > 0 ) { - *xposd += pango_units_to_double(box->width); - } /* else zero */ - break; - - case WRAP_BOX_CALLBACK : - if ( pos > 0 ) { - *xposd += pango_units_to_double(box->width); - } - break; - - case WRAP_BOX_NOTHING : - case WRAP_BOX_SENTINEL : - *xposd = 0.0; - break; - - } -} - - -static int find_cursor_line(struct frame *fr, double yposd, int *end) -{ - int i; - double y = fr->pad_t; - - *end = 0; - - for ( i=0; i<fr->n_lines; i++ ) { - double height = pango_units_to_double(fr->lines[i].height); - if ( yposd < y + height ) { - return i; - } - y += height; - } - - *end = 1; - return fr->n_lines-1; -} - - -static int find_cursor_box(struct frame *fr, struct wrap_line *l, - double xposd, double *x_pos, int *end) -{ - int i; - double x = fr->pad_l; - - *end = 0; - - for ( i=0; i<l->boxes->n_boxes; i++ ) { - double width = pango_units_to_double(bv_box(l->boxes, i)->width); - width += pango_units_to_double(bv_box(l->boxes, i)->sp); - if ( xposd < x + width ) { - *x_pos = xposd - x; - return i; - } - x += width; - } - - *end = 1; - *x_pos = x; - return bv_len(l->boxes)-1; -} - - -void find_cursor(struct frame *fr, double xposd, double yposd, - int *line, int *box, int *pos) -{ - struct wrap_line *l; - struct wrap_box *b; - int end; - double x_pos = 0.0; - int idx, trail; - int x_pos_i; - size_t offs; - int ln, bn; - const char *block_text; - const char *box_text; - - if ( fr->n_lines == 0 ) { - *line = 0; - *box = 0; - *pos = 0; - return; - } - - ln = find_cursor_line(fr, yposd, &end); - l = &fr->lines[ln]; - *line = ln; - - if ( end ) { - bn = l->boxes->n_boxes-1; - } else { - bn = find_cursor_box(fr, l, xposd, &x_pos, &end); - } - b = bv_box(l->boxes, bn); - *box = bn; - if ( end ) { - *pos = b->len_chars; - return; - } - - if ( !b->editable ) { - *pos = 0; - return; - } - - switch ( b->type ) { - - case WRAP_BOX_NOTHING: - case WRAP_BOX_SENTINEL: - case WRAP_BOX_IMAGE: - case WRAP_BOX_CALLBACK: - offs = 0; - break; - - case WRAP_BOX_PANGO: - x_pos_i = pango_units_from_double(x_pos); - if ( x_pos_i < b->width ) { - block_text = sc_block_contents(b->scblock); - box_text = g_utf8_offset_to_pointer(block_text, - b->offs_char); - printf("box text '%s'\n", box_text); - /* cast because this function is not const-clean */ - /* FIXME: Assumes one segment per box! */ - pango_glyph_string_x_to_index(b->segs[0].glyphs, - (char *)box_text, - strlen(box_text), - &b->segs[0].analysis, - x_pos_i, &idx, &trail); - offs = idx + trail; - /* FIXME: Bug in Pango? */ - if ( offs > b->len_chars ) offs = b->len_chars; - } else { - offs = 0; - }; - break; - - default: - fprintf(stderr, "find_cursor(): box %i\n", b->type); - offs = 0; - break; - - } - - *pos = offs; -} - - -static void calc_line_geometry(struct wrap_line *line) -{ - int i; - - line->width = 0; - line->ascent = 0; - line->height = 0; - - for ( i=0; i<line->boxes->n_boxes; i++ ) { - - struct wrap_box *box = bv_box(line->boxes, i); - - line->width += box->width; - if ( box->space == WRAP_SPACE_EOP ) box->sp = 0.0; - line->width += box->sp; - if ( box->height > line->height ) line->height = box->height; - if ( box->ascent > line->ascent ) line->ascent = box->ascent; - - } - - line->height *= 1.07; -} - - -/* Normal width of space */ -static double sp_x(enum wrap_box_space s) -{ - switch ( s ) { - - case WRAP_SPACE_INTERWORD : - return 10.0*PANGO_SCALE; - - case WRAP_SPACE_EOP : - return 0.0; - - default: - case WRAP_SPACE_NONE : - return 0.0; - - } -} - - -/* Stretchability of space */ -static double sp_y(enum wrap_box_space s) -{ - switch ( s ) { - - case WRAP_SPACE_INTERWORD : - return 10.0*PANGO_SCALE; - - case WRAP_SPACE_EOP : - return INFINITY; - - default: - case WRAP_SPACE_NONE : - return 0.0; - - } -} - - -/* Shrinkability of space */ -static double sp_z(enum wrap_box_space s) -{ - switch ( s ) { - - case WRAP_SPACE_INTERWORD : - return 7.0*PANGO_SCALE; - - case WRAP_SPACE_EOP : - return 0.0; - - default: - case WRAP_SPACE_NONE : - return 0.0; - - } -} - - -/* Minimum width of space */ -static double sp_zp(enum wrap_box_space s) -{ - return sp_x(s) - sp_z(s); -} - - -/* Maximum width of space */ -static double sp_yp(enum wrap_box_space s, double rho) -{ - return sp_x(s) + rho*sp_y(s); -} - - -static void consider_break(double sigma_prime, double sigma_prime_max, - double sigma_prime_min, double line_length, - double *s, int j, double *dprime, int *jprime, - double rho) -{ - double r; - double d; - - if ( sigma_prime < line_length ) { - r = rho*(line_length - sigma_prime) - / (sigma_prime_max - sigma_prime); - } else if ( sigma_prime > line_length ) { - r = rho*(line_length - sigma_prime) - / (sigma_prime - sigma_prime_min); - } else { - r = 0.0; - } - - d = s[j] + pow(1.0 + 100.0 * pow(abs(r),3.0), 2.0); - if ( d < *dprime ) { - *dprime = d; - *jprime = j; - } -} - - -static double width(struct boxvec *boxes, int i) -{ - /* Indices in Knuth paper go from 1...n. Indices in array go - * from 0...n-1 */ - return bv_box(boxes, i-1)->width; -} - - -static enum wrap_box_space space(struct boxvec *boxes, int i) -{ - /* Indices in Knuth paper go from 1...n. Indices in array go - * from 0...n-1 */ - return bv_box(boxes, i-1)->space; -} - - -static void UNUSED distribute_spaces(struct wrap_line *line, double l, - double rho) -{ - int i; - double L, Y, Z, r; - int overfull = 0; - int underfull = 0; - - l = pango_units_from_double(l); - - L = 0.0; Y = 0.0; Z = 0.0; - for ( i=0; i<bv_len(line->boxes); i++ ) { - L += bv_box(line->boxes, i)->width; - L += sp_x(bv_box(line->boxes, i)->space); - Y += sp_y(bv_box(line->boxes, i)->space); - Z += sp_z(bv_box(line->boxes, i)->space); - } - L += bv_last(line->boxes)->width; - - if ( L < l ) { - r = (l - L)/Y; - } else if ( L > l ) { - r = (l - L)/Z; - } else { - r = 0.0; - } - - if ( r >= 0.0 ) { - for ( i=0; i<bv_len(line->boxes)-1; i++ ) { - bv_box(line->boxes, i)->sp = sp_x(bv_box(line->boxes, i)->space); - bv_box(line->boxes, i)->sp += r*sp_y(bv_box(line->boxes, i)->space); - } - } else { - for ( i=0; bv_len(line->boxes)-1; i++ ) { - bv_box(line->boxes, i)->sp = sp_x(bv_box(line->boxes, i)->space); - bv_box(line->boxes, i)->sp += r*sp_z(bv_box(line->boxes, i)->space); - } - } - - bv_box(line->boxes, bv_len(line->boxes)-1)->sp = 0.0; - line->overfull = overfull; - line->underfull = underfull; -} - - -static void output_line(int q, int s, struct frame *fr, struct boxvec *boxes) -{ - struct wrap_line *l; - int j; - - l = &fr->lines[fr->n_lines]; - fr->n_lines++; - initialise_line(l); - - bv_ensure_space(l->boxes, s-q); - for ( j=q; j<s; j++ ) { - bv_add(l->boxes, bv_box(boxes, j)); - } -} - - -static void output(int a, int i, int *p, struct frame *fr, struct boxvec *boxes) -{ - int q = i; - int r; - int s = 0; - - if ( fr->n_lines + (i-a) + 1 > fr->max_lines ) { - fr->max_lines += 32; - alloc_lines(fr); - if ( fr->n_lines == fr->max_lines ) return; - } - - while ( q != a ) { - r = p[q]; - p[q] = s; - s = q; - q = r; - } - - while ( q != i ) { - - output_line(q, s, fr, boxes); - - q = s; - s = p[q]; - - } - -} - - -/* This is the "suboptimal fit" algorithm from Knuth and Plass, Software - - * Practice and Experience 11 (1981) p1119-1184. Despite the name, it's - * supposed to work as well as the full TeX algorithm in almost all of the cases - * that we care about here. */ -static void UNUSED knuth_suboptimal_fit(struct boxvec *boxes, - double line_length, struct frame *fr, - double rho) -{ - int a = 0; - int *p; - double *s; - struct wrap_box *box; - int j; - double sigma_prime, sigma_max_prime, sigma_min_prime; - double dprime; - int n; - int reject; - - n = boxes->n_boxes; - - /* Set the space for the last box to be "end of paragraph" */ - bv_last(boxes)->space = WRAP_SPACE_EOP; - - /* Add empty zero-width box at end */ - box = malloc(sizeof(struct wrap_box)); - if ( box== NULL ) { - fprintf(stderr, "Couldn't allocate sentinel box\n"); - return; - } - box->type = WRAP_BOX_SENTINEL; - box->space = WRAP_SPACE_NONE; - box->font = NULL; - box->width = 0; - box->ascent = 0; - box->height = 0; - box->editable = 1; - box->scblock = NULL; - box->offs_char = 0; - bv_add(boxes, box); - - line_length *= PANGO_SCALE; - - reject = 0; - for ( j=0; j<bv_len(boxes); j++ ) { - if ( bv_box(boxes, j)->width > line_length ) { - fprintf(stderr, "ERROR: Box %i too long (%i %f)\n", j, - bv_box(boxes, j)->width, line_length); - fr->trouble = 1; - reject = 1; - } - } - if ( reject ) return; - - p = malloc((n+2) * sizeof(int)); /* p[0]..p[n+1] inclusive */ - if ( p == NULL ) { - fprintf(stderr, "Failed to allocate p_k\n"); - return; - } - - s = malloc((n+2) * sizeof(double)); /* s[0]..s[n+1] inclusive */ - if ( s == NULL ) { - fprintf(stderr, "Failed to allocate s_k\n"); - return; - } - - do { - - int i = a; - int k = i+1; - double sigma = width(boxes, k); - double sigma_min = sigma; - double sigma_max = sigma; - int m = 1; - int jprime = 999; - - s[i] = 0; - - do { - - while ( sigma_min > line_length ) { - - /* Begin <advance i by 1> */ - if ( s[i] < INFINITY ) m--; - i++; - sigma -= width(boxes, i); - sigma -= sp_z(space(boxes, i)); - - sigma_max -= width(boxes, i); - sigma_max -= sp_yp(space(boxes, i), rho); - - sigma_min -= width(boxes, i); - sigma_min -= sp_zp(space(boxes, i)); - /* End */ - - } - - /* Begin <examine all feasible lines ending at k> */ - j = i; - sigma_prime = sigma; - sigma_max_prime = sigma_max; - sigma_min_prime = sigma_min; - dprime = INFINITY; - while ( sigma_max_prime >= line_length ) { - if ( s[j] < INFINITY ) { - consider_break(sigma_prime, - sigma_max_prime, - sigma_min_prime, - line_length, s, j, - &dprime, &jprime, - rho); - } - j++; - sigma_prime -= width(boxes, j); - sigma_prime -= sp_x(space(boxes, j)); - - sigma_max_prime -= width(boxes, j); - sigma_max_prime -= sp_yp(space(boxes, j), - rho); - - sigma_min_prime -= width(boxes, j); - sigma_min_prime -= sp_zp(space(boxes, j)); - } - /* End */ - - s[k] = dprime; - if ( dprime < INFINITY ) { - m++; - p[k] = jprime; - } - if ( (m == 0) || (k > n) ) break; - sigma += width(boxes, k+1); - sigma += sp_x(space(boxes, k)); - - sigma_max += width(boxes, k+1); - sigma_max += sp_yp(space(boxes, k), rho); - - sigma_min += width(boxes, k+1); - sigma_min += sp_zp(space(boxes, k)); - k++; - - } while ( 1 ); - - if ( k > n ) { - output(a, n+1, p, fr, boxes); - break; - } else { - - /* Begin <try hyphenation> */ - do { - - sigma += width(boxes, i); - sigma += sp_x(space(boxes, i)); - - sigma_max += width(boxes, i); - sigma_max += sp_yp(space(boxes, i), rho); - - sigma_min += width(boxes, i); - sigma_min += sp_zp(space(boxes, i)); - i--; - - } while ( s[i] >= INFINITY ); - output(a, i, p, fr, boxes); - - /* Begin <split box k at the best place> */ - jprime = 0; - dprime = INFINITY; - /* Test hyphenation points here */ - /* End */ - - /* Begin <output and adjust w_k> */ - output_line(i, k-1, fr, boxes); - /* End */ - - /* End */ - - a = k-1; - - } - - } while ( 1 ); - - fr->lines[fr->n_lines-1].last_line = 1; - - free(p); - free(s); - free(box); /* The sentinel box */ -} - - -static struct wrap_line *new_line(struct frame *fr) -{ - struct wrap_line *l; - - if ( fr->n_lines + 1 > fr->max_lines ) { - fr->max_lines += 32; - alloc_lines(fr); - if ( fr->n_lines == fr->max_lines ) return NULL; - } - - l = &fr->lines[fr->n_lines]; - fr->n_lines++; - initialise_line(l); - return l; -} - - -static void first_fit(struct boxvec *boxes, double line_length, - struct frame *fr) -{ - struct wrap_line *line; - double len; - int j = 0; - - line_length *= PANGO_SCALE; - - line = new_line(fr); - len = 0.0; - - do { - - bv_box(boxes, j)->sp = sp_x(bv_box(boxes, j)->space); - - len += bv_box(boxes, j)->width; - - if ( len > line_length ) { - line = new_line(fr); - len = bv_box(boxes, j)->width; - } - bv_add(line->boxes, bv_box(boxes, j)); - j++; - - if ( (j > 0) && (bv_box(boxes, j-1)->type != WRAP_BOX_SENTINEL) ) - { - len += sp_x(bv_box(boxes, j-1)->space); - } - - } while ( j < boxes->n_boxes ); - - fr->lines[fr->n_lines-1].last_line = 1; -} - - -void wrap_line_free(struct wrap_line *l) -{ - bv_free(l->boxes); -} - - -static struct boxvec *split_paragraph(struct boxvec *boxes, int *n, int *eop) -{ - int i; - int start = *n; - int end; - - if ( start >= bv_len(boxes) ) return NULL; - - *eop = 0; - for ( i=start; i<bv_len(boxes); i++ ) { - if ( bv_box(boxes, i)->space == WRAP_SPACE_EOP ) { - *eop = 1; - break; - } - } - end = i + 1; - *n = end; - if ( i == bv_len(boxes) ) end--; - - if ( end-start > 0 ) { - struct boxvec *para = bv_new(); - bv_ensure_space(para, end-start); - for ( i=start; i<end; i++ ) { - bv_add(para, bv_box(boxes, i)); - } - return para; - } - - return NULL; -} - - -void show_boxes(struct boxvec *boxes) -{ - int i; - - if ( boxes == NULL ) { - printf("Empty line.\n"); - return; - } - - for ( i=0; i<bv_len(boxes); i++ ) { - struct wrap_box *box = bv_box(boxes, i); - char *box_text; - printf("%3i", i); - if ( box->scblock != NULL ) { - const char *block_text = sc_block_contents(box->scblock); - box_text = g_utf8_offset_to_pointer(block_text, - box->offs_char); - } else if ( box->type == WRAP_BOX_IMAGE ) { - box_text = box->filename; - } else { - box_text = NULL; - } - printf(" t=%i s=%i %10i %5i %8.2f '%s'\n", - box->type, box->space, box->width, box->offs_char, - box->sp, box_text); - } -} - - -static int wrap_everything(struct frame *fr, double wrap_w) -{ - int i; - - fr->paragraph_start_lines = malloc(fr->n_paragraphs*sizeof(int)); - if ( fr->paragraph_start_lines == NULL ) { - fprintf(stderr, "Failed to allocate paragraph start lines\n"); - return 1; - } - - /* Split paragraphs into lines */ - fr->paragraph_start_lines[0] = 0; - for ( i=0; i<fr->n_paragraphs; i++ ) { - - //int n; - - /* Choose wrapping algorithm here */ - //knuth_suboptimal_fit(para, wrap_w, fr, rho); - first_fit(fr->paragraphs[i], wrap_w, fr); - - //fr->paragraph_start_lines = n; - - } - - return 0; -} - - -/* Wrap the StoryCode inside "fr->sc" so that it fits within width "fr->w", - * and generate fr->lines */ -int wrap_contents(struct frame *fr) -{ - struct boxvec *para; - int i, eop = 0; - //const double rho = 2.0; - const double wrap_w = fr->w - fr->pad_l - fr->pad_r; - int max_para = 64; - - /* Clear lines */ - fr->n_lines = 0; - fr->max_lines = 32; - fr->lines = NULL; - fr->trouble = 0; - alloc_lines(fr); - - for ( i=0; i<fr->n_paragraphs; i++ ) { - bv_free(fr->paragraphs[i]); - } - free(fr->paragraphs); - free(fr->paragraph_start_lines); - for ( i=0; i<fr->n_lines; i++ ) { - wrap_line_free(&fr->lines[i]); - } - - /* Split text into paragraphs */ - i = 0; - fr->n_paragraphs = 0; - fr->paragraphs = malloc(max_para * sizeof(struct boxvec *)); - if ( fr->paragraphs == NULL ) { - fprintf(stderr, "Failed to allocate paragraphs\n"); - return 1; - } - do { - para = split_paragraph(fr->boxes, &i, &eop); - if ( para != NULL ) { - fr->paragraphs[fr->n_paragraphs++] = para; - } - if ( fr->n_paragraphs == max_para ) { - max_para += 64; - fr->paragraphs = realloc(fr->paragraphs, - max_para*sizeof(struct boxvec *)); - if ( fr->paragraphs == NULL ) { - fprintf(stderr, "Failed to allocate space" - " for paragraphs\n"); - return 1; - } - } - } while ( para != NULL ); - - if ( fr->n_paragraphs > 0 ) { - if ( wrap_everything(fr, wrap_w) ) return 1; - } else { - fr->paragraph_start_lines = NULL; - return 0; - } - - for ( i=0; i<fr->n_lines; i++ ) { - - struct wrap_line *line = &fr->lines[i]; - - //distribute_spaces(line, wrap_w, rho); - - /* Strip any sentinel boxes added by the wrapping algorithm */ - if ( (bv_last(line->boxes) != NULL) - && (bv_last(line->boxes)->type == WRAP_BOX_SENTINEL) ) - { - line->boxes->n_boxes--; - } - - } - - for ( i=0; i<fr->n_lines; i++ ) { - calc_line_geometry(&fr->lines[i]); - } - - return 0; -} - - -double total_height(struct frame *fr) -{ - int i; - double tot = 0.0; - - if ( fr == NULL ) return 0.0; - - for ( i=0; i<fr->n_lines; i++ ) { - tot += fr->lines[i].height; - } - - return pango_units_to_double(tot); -} - - -/* Insert a new box, which will be at position 'pos' */ -int insert_box(struct wrap_line *l, int pos) -{ - int i; - -/* FIXME ! */ -#if 0 - if ( l->n_boxes == l->max_boxes ) { - l->max_boxes += 32; - if ( alloc_boxes(l) ) return 1; - } - - /* Shuffle the boxes along */ - for ( i=l->n_boxes; i>pos+1; i-- ) { - l->boxes[i] = l->boxes[i-1]; - } - - l->n_boxes++; -#endif -return 1; - - return 0; -} diff --git a/src/wrap.h b/src/wrap.h deleted file mode 100644 index f3df4e4..0000000 --- a/src/wrap.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * wrap.h - * - * Text wrapping, hyphenation, justification and shaping - * - * Copyright © 2014-2016 Thomas White <taw@bitwiz.org.uk> - * - * This file is part of Colloquium. - * - * Colloquium 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" -#include "sc_interp.h" -#include "presentation.h" - - -enum wrap_box_type -{ - WRAP_BOX_NOTHING, - WRAP_BOX_SENTINEL, - WRAP_BOX_PANGO, - WRAP_BOX_IMAGE, - WRAP_BOX_CALLBACK -}; - - -/* 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 */ -}; - - -struct text_seg -{ - PangoGlyphString *glyphs; - PangoAnalysis analysis; - - /* Offset of this text segment into the wrap box */ - int offs_char; - int len_chars; - - /* Pango units */ - int width; - int height; - int ascent; -}; - - -/* 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; - int editable; - - SCBlock *scblock; - int offs_char; /* offset (in characters, not bytes) into scblock */ - - /* Pango units */ - int width; - int height; - int ascent; - - enum wrap_box_space space; /* Type of "space" following box */ - double sp; /* Calculated space (Pango units) after box */ - - /* For type == WRAP_BOX_PANGO */ - PangoFont *font; - PangoFontDescription *fontdesc; - double col[4]; /* rgba colour */ - int len_chars; - int n_segs; - struct text_seg *segs; - - /* For type == WRAP_BOX_IMAGE */ - char *filename; - - /* For type == WRAP_BOX_CALLBACK */ - SCCallbackDrawFunc draw_func; - SCCallbackClickFunc click_func; - void *bvp; - void *vp; -}; - - -/* An actual wrap line, with geometry etc */ -struct wrap_line -{ - struct boxvec *boxes; - - int width; /* Pango units */ - int height; /* Pango units */ - int ascent; /* Pango units */ - - int overfull; - int underfull; - int last_line; -}; - -extern int wrap_contents(struct frame *fr); - -extern void get_cursor_pos(struct wrap_box *box, int pos, - double *xposd, double *yposd, double *line_height); - -extern void find_cursor(struct frame *fr, double xposd, double yposd, - int *line, int *box, int *pos); - -extern int alloc_boxes(struct wrap_line *l); -extern void initialise_line(struct wrap_line *l); - -extern void wrap_line_free(struct wrap_line *l); -extern void show_boxes(struct boxvec *boxes); -extern double total_height(struct frame *fr); - -extern int insert_box(struct wrap_line *l, int pos); -extern int which_segment(struct wrap_box *box, int pos, int *err); - -#endif /* WRAP_H */ |