diff options
author | Thomas White <taw@bitwiz.org.uk> | 2016-04-23 22:05:53 +0200 |
---|---|---|
committer | Thomas White <taw@bitwiz.org.uk> | 2016-04-23 22:05:53 +0200 |
commit | 94f0073b1c4fb1a6f19106c3c29400975b295f5e (patch) | |
tree | 9e4e40d545958192b4cbfd7b1bf8b6d5c5b99373 /src | |
parent | 890e5ac7b89f5cccf120d966dc488f9ddd516a3d (diff) | |
parent | 75df2646fe370bf2c29b965fc8330bdff7329484 (diff) |
Merge branch 'pangolayout'
Diffstat (limited to 'src')
-rw-r--r-- | src/frame.c | 132 | ||||
-rw-r--r-- | src/frame.h | 9 | ||||
-rw-r--r-- | src/narrative_window.c | 39 | ||||
-rw-r--r-- | src/presentation.c | 12 | ||||
-rw-r--r-- | src/sc_editor.c | 56 | ||||
-rw-r--r-- | src/sc_editor.h | 2 | ||||
-rw-r--r-- | src/sc_interp.c | 28 | ||||
-rw-r--r-- | src/sc_parse.c | 44 | ||||
-rw-r--r-- | src/sc_parse.h | 3 | ||||
-rw-r--r-- | src/slide_window.c | 9 |
10 files changed, 231 insertions, 103 deletions
diff --git a/src/frame.c b/src/frame.c index 3699b74..3713277 100644 --- a/src/frame.c +++ b/src/frame.c @@ -64,6 +64,9 @@ struct _paragraph PangoLayout *layout; size_t offset_last; + /* For anything other than PARA_TYPE_TEXT */ + SCBlock *scblock; + /* For PARA_TYPE_IMAGE */ char *filename; double image_w; @@ -288,7 +291,8 @@ void wrap_paragraph(Paragraph *para, PangoContext *pc, double w) /* Allocate the complete text */ text = malloc(total_len+1); if ( text == NULL ) { - fprintf(stderr, "Couldn't allocate combined text\n"); + fprintf(stderr, "Couldn't allocate combined text (%lli)\n", + (long long int)total_len); return; } @@ -388,7 +392,37 @@ static Paragraph *create_paragraph(struct frame *fr) } -void add_callback_para(struct frame *fr, double w, double h, +/* Create a new paragraph in 'fr' just after paragraph 'pos' */ +static Paragraph *insert_paragraph(struct frame *fr, int pos) +{ + Paragraph **paras_new; + Paragraph *pnew; + int i; + + if ( pos >= fr->n_paras ) { + fprintf(stderr, "insert_paragraph(): pos too high!\n"); + return NULL; + } + + 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->n_paras ++; + + for ( i=fr->n_paras-1; i>pos; i-- ) { + fr->paras[i] = fr->paras[i-1]; + } + fr->paras[pos+1] = pnew; + + return pnew; +} + + +void add_callback_para(struct frame *fr, SCBlock *bl, double w, double h, SCCallbackDrawFunc draw_func, SCCallbackClickFunc click_func, void *bvp, void *vp) @@ -402,6 +436,7 @@ void add_callback_para(struct frame *fr, double w, double h, } pnew->type = PARA_TYPE_CALLBACK; + pnew->scblock = bl; pnew->cb_w = w; pnew->cb_h = h; pnew->draw_func = draw_func; @@ -413,7 +448,7 @@ void add_callback_para(struct frame *fr, double w, double h, } -void add_image_para(struct frame *fr, const char *filename, +void add_image_para(struct frame *fr, SCBlock *scblock, const char *filename, double w, double h, int editable) { Paragraph *pnew; @@ -425,6 +460,7 @@ void add_image_para(struct frame *fr, const char *filename, } pnew->type = PARA_TYPE_IMAGE; + pnew->scblock = scblock; pnew->filename = strdup(filename); pnew->image_w = w; pnew->image_h = h; @@ -798,18 +834,43 @@ void delete_text_in_paragraph(Paragraph *para, size_t offs1, size_t offs2) } -static void split_text_paragraph(struct frame *fr, int pn, int pos, - PangoContext *pc) +static __attribute__((unused)) void show_para(Paragraph *p) +{ + int i; + printf("Paragraph %p\n", p); + printf("%i runs:\n", p->n_runs); + for ( i=0; i<p->n_runs; i++ ) { + printf(" Run %2i: para offs %lli, SCBlock %p offs %lli, len " + "%lli %s\n", i, (long long int)p->runs[i].para_offs_bytes, + p->runs[i].scblock, + (long long int)p->runs[i].scblock_offs_bytes, + (long long int)p->runs[i].len_bytes, + pango_font_description_to_string(p->runs[i].fontdesc)); + } +} + + +static char *s_strdup(const char *a) +{ + if ( a == NULL ) return NULL; + return strdup(a); +} + + +static SCBlock *split_text_paragraph(struct frame *fr, int pn, size_t pos, + PangoContext *pc) { Paragraph *pnew; - int i, j; + int i; + size_t offs, run_offs; int run; Paragraph *para = fr->paras[pn]; + struct text_run *rr; pnew = insert_paragraph(fr, pn); if ( pnew == NULL ) { fprintf(stderr, "Failed to insert paragraph\n"); - return; + return NULL; } /* Determine which run the cursor is in */ @@ -821,34 +882,67 @@ static void split_text_paragraph(struct frame *fr, int pn, int pos, pnew->runs = malloc(pnew->n_runs * sizeof(struct text_run)); if ( pnew->runs == NULL ) { fprintf(stderr, "Failed to allocate runs.\n"); - return; /* Badness is coming */ - } + return NULL; /* Badness is coming */ + } + + /* First run of the new paragraph contains the leftover text */ + rr = ¶->runs[run]; + pnew->runs[0].scblock = rr->scblock; + run_offs = pos - rr->para_offs_bytes; + pnew->runs[0].scblock_offs_bytes = rr->scblock_offs_bytes + run_offs; + pnew->runs[0].para_offs_bytes = 0; + pnew->runs[0].len_bytes = rr->len_bytes - run_offs; + pnew->runs[0].col[0] = rr->col[0]; + pnew->runs[0].col[1] = rr->col[1]; + pnew->runs[0].col[2] = rr->col[2]; + pnew->runs[0].col[3] = rr->col[3]; + pnew->runs[0].fontdesc = pango_font_description_copy(rr->fontdesc); + pnew->n_runs = 1; + + /* All later runs just get moved to the new paragraph */ + offs = pnew->runs[0].len_bytes; + for ( i=run+1; i<para->n_runs; i++ ) { + pnew->runs[pnew->n_runs] = para->runs[i]; + pnew->runs[pnew->n_runs].para_offs_bytes = offs; + pnew->n_runs++; + offs += rr->len_bytes; + } + + /* Truncate the first paragraph at the appropriate position */ + rr->len_bytes = run_offs; + para->n_runs = run+1; - /* If the position is right at the start of a run, the whole run - * gets moved to the next paragraph */ - if ( para->runs[run].para_offs_bytes ) { + /* If the first and second paragraphs have the same SCBlock, split it */ + if ( rr->scblock == pnew->runs[0].scblock ) { + size_t sc_offs; + sc_offs = rr->scblock_offs_bytes + run_offs; + pnew->runs[0].scblock = sc_block_split(rr->scblock, sc_offs); + pnew->runs[0].scblock_offs_bytes = 0; } - j = 0; - for ( i=run; i<para->n_runs; i++ ) { - pnew->runs[j++] = para->runs[i]; - } + /* Add a newline after the end of the first paragraph's SC */ + sc_block_append(rr->scblock, s_strdup(sc_block_name(rr->scblock)), + s_strdup(sc_block_options(rr->scblock)), + strdup("\n"), NULL); + pnew->open = para->open; para->open = 0; - para->n_runs = run+1; wrap_paragraph(para, pc, fr->w); wrap_paragraph(pnew, pc, fr->w); + + return sc_block_next(rr->scblock); } -void split_paragraph(struct frame *fr, int pn, int pos, PangoContext *pc) +SCBlock *split_paragraph(struct frame *fr, int pn, size_t pos, PangoContext *pc) { Paragraph *para = fr->paras[pn]; if ( para->type == PARA_TYPE_TEXT ) { - split_text_paragraph(fr, pn, pos, pc); + return split_text_paragraph(fr, pn, pos, pc); } else { /* Other types can't be split */ + return NULL; } } diff --git a/src/frame.h b/src/frame.h index d6d171c..2941411 100644 --- a/src/frame.h +++ b/src/frame.h @@ -115,12 +115,14 @@ extern void add_run(Paragraph *para, SCBlock *scblock, size_t offs_bytes, size_t len_bytes, PangoFontDescription *fdesc, double col[4]); -extern void add_callback_para(struct frame *fr, double w, double h, +extern void add_callback_para(struct frame *fr, SCBlock *scblock, + 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, +extern void add_image_para(struct frame *fr, SCBlock *scblock, + const char *filename, double w, double h, int editable); extern void wrap_paragraph(Paragraph *para, PangoContext *pc, double w); @@ -150,4 +152,7 @@ extern void insert_text_in_paragraph(Paragraph *para, size_t offs, extern void delete_text_in_paragraph(Paragraph *para, size_t offs1, size_t offs2); +extern SCBlock *split_paragraph(struct frame *fr, int pn, size_t pos, + PangoContext *pc); + #endif /* FRAME_H */ diff --git a/src/narrative_window.c b/src/narrative_window.c index 6e09d71..5a352f7 100644 --- a/src/narrative_window.c +++ b/src/narrative_window.c @@ -139,41 +139,36 @@ static void exportpdf_sig(GSimpleAction *action, GVariant *parameter, } -static void open_slidesorter_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) +static void open_slidesorter_sig(GSimpleAction *action, GVariant *parameter, + gpointer vp) { } -static void delete_frame_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) +static void delete_frame_sig(GSimpleAction *action, GVariant *parameter, + gpointer vp) { } -static void add_slide_sig(GSimpleAction *action, GVariant *parameter, gpointer vp) +static void add_slide_sig(GSimpleAction *action, GVariant *parameter, + gpointer vp) { - int n_slides; - SCBlock *block; SCBlock *nsblock; NarrativeWindow *nw = vp; - /* Link it into the SC structure */ - nsblock = sc_parse("\\slide{}"); - insert_scblock(nsblock, nw->sceditor); - - /* Iterate over blocks of presentation, counting \slides, until - * we reach the block we just added */ - block = nw->p->scblocks; - n_slides = 0; - while ( block != NULL ) { - const char *n = sc_block_name(block); - if ( n == NULL ) goto next; - if ( strcmp(n, "slide") == 0 ) { - if ( block == nsblock ) break; - n_slides++; - } -next: - block = sc_block_next(block); + /* Split the current paragraph */ + nsblock = split_paragraph_at_cursor(nw->sceditor); + + /* Link the new SCBlock in */ + if ( nsblock != NULL ) { + sc_block_append(nsblock, "slide", NULL, NULL, NULL); + } else { + fprintf(stderr, "Failed to split paragraph\n"); } + + sc_editor_set_scblock(nw->sceditor, + sc_editor_get_scblock(nw->sceditor)); } diff --git a/src/presentation.c b/src/presentation.c index 60c27f8..266535c 100644 --- a/src/presentation.c +++ b/src/presentation.c @@ -164,9 +164,15 @@ static char *fgets_long(FILE *fh, size_t *lp) r = fgetc(fh); if ( r == EOF ) { - free(line); - *lp = 0; - return NULL; + if ( l == 0 ) { + free(line); + *lp = 0; + return NULL; + } else { + line[l++] = '\0'; + *lp = l; + return line; + } } line[l++] = r; diff --git a/src/sc_editor.c b/src/sc_editor.c index 5549c54..e54e60a 100644 --- a/src/sc_editor.c +++ b/src/sc_editor.c @@ -555,38 +555,13 @@ static gboolean draw_sig(GtkWidget *da, cairo_t *cr, SCEditor *e) } -void insert_scblock(SCBlock *scblock, SCEditor *e) +SCBlock *split_paragraph_at_cursor(SCEditor *e) { -#if 0 - /* FIXME: Insert "scblock" at the cursor */ - int sln, sbx, sps; - struct wrap_box *sbox; - struct frame *fr = e->cursor_frame; - - 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); - - sc_insert_block(sbox->scblock, sps+sbox->offs_char, scblock); - - fr->empty = 0; - - full_rerender(e); /* FIXME: No need for full */ - - //fixup_cursor(e); - //advance_cursor(e); - //sc_editor_redraw(e); -#endif + return split_paragraph(e->cursor_frame, e->cursor_para, + e->cursor_pos+e->cursor_trail, e->pc); } - static void insert_text(char *t, SCEditor *e) { Paragraph *para; @@ -838,6 +813,13 @@ static void check_paragraph(struct frame *fr, PangoContext *pc, { if ( fr->n_paras > 0 ) return; Paragraph *para = last_open_para(fr); + + /* We are creating the first paragraph. It uses the last SCBlock + * in the chain */ + while ( sc_block_next(scblocks) != NULL ) { + scblocks = sc_block_next(scblocks); + } + add_run(para, scblocks, 0, 0, fr->fontdesc, fr->col); wrap_paragraph(para, pc, fr->w - fr->pad_l - fr->pad_r); } @@ -923,12 +905,18 @@ static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event, } else { - /* Selected top new frame, no immediate dragging */ + /* Clicked an existing frame, no immediate dragging */ e->drag_status = DRAG_STATUS_NONE; e->drag_reason = DRAG_REASON_NONE; e->selection = clicked; e->cursor_frame = clicked; - check_paragraph(e->cursor_frame, e->pc, e->scblocks); + if ( clicked == e->top ) { + show_sc_block(clicked->scblocks, ")>"); + check_paragraph(e->cursor_frame, e->pc, clicked->scblocks); + } else { + check_paragraph(e->cursor_frame, e->pc, + sc_block_child(clicked->scblocks)); + } find_cursor(clicked, x-clicked->x, y-clicked->y, &e->cursor_para, &e->cursor_pos, &e->cursor_trail); @@ -1545,7 +1533,6 @@ SCEditor *sc_editor_new(SCBlock *scblocks, SCBlock **stylesheets, { SCEditor *sceditor; GtkTargetEntry targets[1]; - GError *err; sceditor = g_object_new(SC_TYPE_EDITOR, NULL); @@ -1567,12 +1554,7 @@ SCEditor *sc_editor_new(SCBlock *scblocks, SCBlock **stylesheets, sceditor->stylesheets = copy_ss_list(stylesheets); - err = NULL; - sceditor->bg_pixbuf = gdk_pixbuf_new_from_file(DATADIR"/colloquium/sky.png", &err); - if ( sceditor->bg_pixbuf == NULL ) { - fprintf(stderr, "Failed to load background: %s\n", - err->message); - } + sceditor->bg_pixbuf = NULL; gtk_widget_set_size_request(GTK_WIDGET(sceditor), sceditor->w, sceditor->h); diff --git a/src/sc_editor.h b/src/sc_editor.h index 594f344..5e54cde 100644 --- a/src/sc_editor.h +++ b/src/sc_editor.h @@ -177,8 +177,8 @@ extern void sc_editor_set_min_border(SCEditor *e, double min_border); extern void sc_editor_set_top_frame_editable(SCEditor *e, int top_frame_editable); extern void sc_editor_set_callbacks(SCEditor *e, SCCallbackList *cbl); -extern void insert_scblock(SCBlock *scblock, SCEditor *e); extern void sc_editor_delete_selected_frame(SCEditor *e); extern void sc_editor_remove_cursor(SCEditor *e); +extern SCBlock *split_paragraph_at_cursor(SCEditor *e); #endif /* SC_EDITOR_H */ diff --git a/src/sc_interp.c b/src/sc_interp.c index 9899a95..993cb9e 100644 --- a/src/sc_interp.c +++ b/src/sc_interp.c @@ -216,7 +216,7 @@ 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_para(sc_interp_get_frame(scin), w, h, + add_callback_para(sc_interp_get_frame(scin), bl, w, h, cbl->draw_funcs[i], cbl->click_funcs[i], bvp, cbl->vps[i]); @@ -262,6 +262,21 @@ int sc_interp_get_height(SCInterpreter *scin) } +static void set_frame_default_style(struct frame *fr, SCInterpreter *scin) +{ + if ( fr == NULL ) return; + + if ( fr->fontdesc != NULL ) { + pango_font_description_free(fr->fontdesc); + } + fr->fontdesc = pango_font_description_copy(sc_interp_get_fontdesc(scin)); + fr->col[0] = sc_interp_get_fgcol(scin)[0]; + fr->col[1] = sc_interp_get_fgcol(scin)[1]; + fr->col[2] = sc_interp_get_fgcol(scin)[2]; + fr->col[3] = sc_interp_get_fgcol(scin)[3]; +} + + static void update_font(SCInterpreter *scin) { PangoFontMetrics *metrics; @@ -279,6 +294,7 @@ static void update_font(SCInterpreter *scin) st->ascent = pango_font_metrics_get_ascent(metrics); st->height = st->ascent + pango_font_metrics_get_descent(metrics); pango_font_metrics_unref(metrics); + set_frame_default_style(sc_interp_get_frame(scin), scin); } @@ -380,6 +396,7 @@ static void set_colour(SCInterpreter *scin, const char *colour) st->col[1] = col.green; st->col[2] = col.blue; st->col[3] = col.alpha; + set_frame_default_style(sc_interp_get_frame(scin), scin); } @@ -545,6 +562,7 @@ SCInterpreter *sc_interp_new(PangoContext *pc, PangoLanguage *lang, return NULL; } st->macro_contents = NULL; + st->fr = NULL; scin->lang = lang; @@ -883,7 +901,7 @@ static int check_outputs(SCBlock *bl, SCInterpreter *scin) if ( parse_image_options(options, sc_interp_get_frame(scin), &w, &h, &filename) == 0 ) { - add_image_para(sc_interp_get_frame(scin), + add_image_para(sc_interp_get_frame(scin), bl, filename, w, h, 1); free(filename); } else { @@ -907,11 +925,7 @@ static int check_outputs(SCBlock *bl, SCInterpreter *scin) return 1; } - fr->fontdesc = pango_font_description_copy(sc_interp_get_fontdesc(scin)); - fr->col[0] = sc_interp_get_fgcol(scin)[0]; - fr->col[1] = sc_interp_get_fgcol(scin)[1]; - fr->col[2] = sc_interp_get_fgcol(scin)[2]; - fr->col[3] = sc_interp_get_fgcol(scin)[3]; + set_frame_default_style(fr, scin); parse_frame_options(fr, sc_interp_get_frame(scin), options); diff --git a/src/sc_parse.c b/src/sc_parse.c index 95b5c76..c8eea6f 100644 --- a/src/sc_parse.c +++ b/src/sc_parse.c @@ -41,7 +41,6 @@ struct _scblock char *contents; SCBlock *next; - SCBlock *prev; SCBlock *child; }; @@ -103,11 +102,9 @@ SCBlock *sc_block_append(SCBlock *bl, char *name, char *opt, char *contents, bln->child = NULL; bln->next = NULL; - if ( bl == NULL ) { - bln->prev = NULL; - } else { + if ( bl != NULL ) { + bln->next = bl->next; bl->next = bln; - bln->prev = bl; } if ( (blfp != NULL) && (*blfp == NULL) ) { @@ -128,6 +125,7 @@ SCBlock *sc_block_append_end(SCBlock *bl, char *name, char *opt, char *contents) if ( bln == NULL ) return NULL; while ( bl->next != NULL ) { + bln->next = bl->next; bl = bl->next; }; @@ -162,11 +160,6 @@ SCBlock *sc_block_append_inside(SCBlock *parent, bln->child = NULL; bln->next = NULL; - if ( bl == NULL ) { - bln->prev = NULL; - } else { - bln->prev = bl; - } *ptr = bln; return bln; @@ -668,3 +661,34 @@ SCBlock *sc_block_copy(const SCBlock *bl) return first_copy; } + + +static char *s_strdup(const char *a) +{ + if ( a == NULL ) return NULL; + return strdup(a); +} + + +SCBlock *sc_block_split(SCBlock *bl, size_t pos) +{ + SCBlock *n = sc_block_new(); + + if ( bl->child != NULL ) { + fprintf(stderr, "Splitting a block with a child!\n"); + return NULL; + } + + /* Second block */ + n->name = s_strdup(bl->name); + n->options = s_strdup(bl->options); + n->contents = strdup(bl->contents+pos); + + /* Truncate the first block */ + bl->contents[pos] = '\0'; + + n->next = bl->next; + bl->next = n; + + return n; +} diff --git a/src/sc_parse.h b/src/sc_parse.h index 94bab30..dad797b 100644 --- a/src/sc_parse.h +++ b/src/sc_parse.h @@ -1,7 +1,7 @@ /* * sc_parse.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. * @@ -66,6 +66,7 @@ extern void sc_block_set_contents(SCBlock *bl, char *con); extern void sc_insert_text(SCBlock *b1, size_t o1, const char *t); extern void sc_insert_block(SCBlock *b1, int o1, SCBlock *ins); extern void sc_delete_text(SCBlock *b1, int o1, SCBlock *b2, int o2); +extern SCBlock *sc_block_split(SCBlock *bl, size_t pos); extern void show_sc_blocks(const SCBlock *bl); extern void show_sc_block(const SCBlock *bl, const char *prefix); diff --git a/src/slide_window.c b/src/slide_window.c index b232e58..659c0bd 100644 --- a/src/slide_window.c +++ b/src/slide_window.c @@ -533,6 +533,7 @@ SlideWindow *slide_window_open(struct presentation *p, SCBlock *scblocks) SlideWindow *sw; SCBlock *stylesheets[2]; GtkWidget *image; + SCBlock *ch; sw = calloc(1, sizeof(SlideWindow)); if ( sw == NULL ) return NULL; @@ -610,7 +611,13 @@ SlideWindow *slide_window_open(struct presentation *p, SCBlock *scblocks) "win.last"); stylesheets[0] = p->stylesheet; stylesheets[1] = NULL; - sw->sceditor = sc_editor_new(sc_block_child(scblocks), stylesheets, p->lang); + + ch = sc_block_child(scblocks); + if ( ch == NULL ) { + ch = sc_block_append_inside(scblocks, NULL, NULL, ""); + } + + sw->sceditor = sc_editor_new(ch, stylesheets, p->lang); scroll = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, |