From 269526b1b6aeadb57033ab0e02d20b900d71a690 Mon Sep 17 00:00:00 2001 From: Thomas White Date: Tue, 26 Feb 2019 22:41:41 +0100 Subject: Skeleton GtkNarrativeView --- libstorycode/gtk/gtknarrativeview.c | 2261 ++++++++++------------------------- libstorycode/gtk/gtknarrativeview.h | 124 +- meson.build | 25 +- src/narrative_window.c | 12 +- 4 files changed, 706 insertions(+), 1716 deletions(-) diff --git a/libstorycode/gtk/gtknarrativeview.c b/libstorycode/gtk/gtknarrativeview.c index 8e79fd8..3900f3a 100644 --- a/libstorycode/gtk/gtknarrativeview.c +++ b/libstorycode/gtk/gtknarrativeview.c @@ -1,7 +1,7 @@ /* - * sc_editor.c + * gtknarrativeview.c * - * Copyright © 2013-2018 Thomas White + * Copyright © 2013-2019 Thomas White * * This file is part of Colloquium. * @@ -33,17 +33,11 @@ #include #include -#include "colloquium.h" -#include "presentation.h" -#include "slide_window.h" -#include "render.h" -#include "frame.h" -#include "sc_parse.h" -#include "sc_interp.h" -#include "sc_editor.h" -#include "slideshow.h" -#include "debugger.h" -#include "utils.h" +#include + +//#include "slide_window.h" +#include "gtknarrativeview.h" +//#include "slideshow.h" static void scroll_interface_init(GtkScrollable *iface) @@ -53,38 +47,36 @@ static void scroll_interface_init(GtkScrollable *iface) enum { - SCEDITOR_0, - SCEDITOR_VADJ, - SCEDITOR_HADJ, - SCEDITOR_VPOL, - SCEDITOR_HPOL, + GTKNARRATIVEVIEW_0, + GTKNARRATIVEVIEW_VADJ, + GTKNARRATIVEVIEW_HADJ, + GTKNARRATIVEVIEW_VPOL, + GTKNARRATIVEVIEW_HPOL, }; -G_DEFINE_TYPE_WITH_CODE(SCEditor, sc_editor, GTK_TYPE_DRAWING_AREA, +G_DEFINE_TYPE_WITH_CODE(GtkNarrativeView, gtk_narrative_view, + GTK_TYPE_DRAWING_AREA, G_IMPLEMENT_INTERFACE(GTK_TYPE_SCROLLABLE, scroll_interface_init)) -static void debug_paragraphs(SCEditor *e) +static void redraw(GtkNarrativeView *e) { - struct frame *fr = e->cursor_frame; - int i; - - printf("Paragraphs in current frame:\n"); - for ( i=0; in_paras; i++ ) { - show_para(fr->paras[i]); - } + gint w, h; + w = gtk_widget_get_allocated_width(GTK_WIDGET(e)); + h = gtk_widget_get_allocated_height(GTK_WIDGET(e)); + gtk_widget_queue_draw_area(GTK_WIDGET(e), 0, 0, w, h); } -static void horizontal_adjust(GtkAdjustment *adj, SCEditor *e) +static void horizontal_adjust(GtkAdjustment *adj, GtkNarrativeView *e) { e->h_scroll_pos = gtk_adjustment_get_value(adj); - sc_editor_redraw(e); + redraw(e); } -static void set_horizontal_params(SCEditor *e) +static void set_horizontal_params(GtkNarrativeView *e) { if ( e->hadj == NULL ) return; gtk_adjustment_configure(e->hadj, e->h_scroll_pos, 0, e->w, 100, @@ -92,14 +84,14 @@ static void set_horizontal_params(SCEditor *e) } -static void vertical_adjust(GtkAdjustment *adj, SCEditor *e) +static void vertical_adjust(GtkAdjustment *adj, GtkNarrativeView *e) { e->scroll_pos = gtk_adjustment_get_value(adj); - sc_editor_redraw(e); + redraw(e); } -static void set_vertical_params(SCEditor *e) +static void set_vertical_params(GtkNarrativeView *e) { double page; @@ -129,88 +121,68 @@ static void set_vertical_params(SCEditor *e) } -static void update_size(SCEditor *e) +static void update_size(GtkNarrativeView *e) { - if ( e->flow ) { - - double total = total_height(e->top); - - e->w = e->top->w; - e->h = total + e->top->pad_t + e->top->pad_b; - - e->log_w = e->w; - e->log_h = e->h; - e->top->h = e->h; - } else { - e->top->w = e->log_w; - e->top->h = e->log_h; - } - - if ( e->flow && (e->top->h < e->visible_height) ) { - e->top->h = e->visible_height; - } - - set_vertical_params(e); - set_horizontal_params(e); +// if ( e->flow ) { +// +// double total = total_height(e->top); +// +// e->w = e->top->w; +// e->h = total + e->top->pad_t + e->top->pad_b; +// +// e->log_w = e->w; +// e->log_h = e->h; +// e->top->h = e->h; +// } else { +// e->top->w = e->log_w; +// e->top->h = e->log_h; +// } +// +// if ( e->flow && (e->top->h < e->visible_height) ) { +// e->top->h = e->visible_height; +// } +// +// set_vertical_params(e); +// set_horizontal_params(e); } static gboolean resize_sig(GtkWidget *widget, GdkEventConfigure *event, - SCEditor *e) + GtkNarrativeView *e) { PangoContext *pc; pc = gdk_pango_context_get(); - if ( e->scale ) { - - double sx, sy; - double aw, ah; - - e->w = event->width; - e->h = event->height; - sx = (double)e->w / e->log_w; - sy = (double)e->h / e->log_h; - e->view_scale = (sx < sy) ? sx : sy; - - /* Actual size (in device units) */ - aw = e->view_scale * e->log_w; - ah = e->view_scale * e->log_h; - - e->border_offs_x = (event->width - aw)/2.0; - e->border_offs_y = (event->height - ah)/2.0; - - } - e->visible_height = event->height; e->visible_width = event->width; - /* Interpret and shape, if not already done */ - if ( e->top == NULL ) { - double w, h; - if ( e->flow ) { - w = event->width; - h = 0.0; - } else { - w = e->log_w; - h = e->log_h; - } - e->top = interp_and_shape(e->scblocks, e->stylesheet, e->cbl, - e->is, e->slidenum, pc, - w, h, e->lang); - e->top->scblocks = e->scblocks; - recursive_wrap(e->top, pc); - } - - if ( e->flow ) { - /* Wrap using current width */ - e->top->w = event->width; - e->top->h = 0.0; /* To be updated in a moment */ - e->top->x = 0.0; - e->top->y = 0.0; - /* Only the top level needs to be wrapped */ - wrap_frame(e->top, pc); - } +// /* Interpret and shape, if not already done */ +// if ( e->top == NULL ) { +// double w, h; +// if ( e->flow ) { +// w = event->width; +// h = 0.0; +// } else { +// w = e->log_w; +// h = e->log_h; +// } +// e->top = interp_and_shape(e->scblocks, e->stylesheet, e->cbl, +// e->is, e->slidenum, pc, +// w, h, e->lang); +// e->top->scblocks = e->scblocks; +// recursive_wrap(e->top, pc); +// } +// +// if ( e->flow ) { +// /* Wrap using current width */ +// e->top->w = event->width; +// e->top->h = 0.0; /* To be updated in a moment */ +// e->top->x = 0.0; +// e->top->y = 0.0; +// /* Only the top level needs to be wrapped */ +// wrap_frame(e->top, pc); +// } update_size(e); @@ -220,13 +192,13 @@ static gboolean resize_sig(GtkWidget *widget, GdkEventConfigure *event, } -static void emit_change_sig(SCEditor *e) +static void emit_change_sig(GtkNarrativeView *e) { g_signal_emit_by_name(e, "changed"); } -void sc_editor_set_flow(SCEditor *e, int flow) +void sc_editor_set_flow(GtkNarrativeView *e, int flow) { e->flow = flow; } @@ -235,19 +207,19 @@ void sc_editor_set_flow(SCEditor *e, int flow) static void sc_editor_set_property(GObject *obj, guint id, const GValue *val, GParamSpec *spec) { - SCEditor *e = SC_EDITOR(obj); + GtkNarrativeView *e = GTK_NARRATIVE_VIEW(obj); switch ( id ) { - case SCEDITOR_VPOL : + case GTKNARRATIVEVIEW_VPOL : e->vpol = g_value_get_enum(val); break; - case SCEDITOR_HPOL : + case GTKNARRATIVEVIEW_HPOL : e->hpol = g_value_get_enum(val); break; - case SCEDITOR_VADJ : + case GTKNARRATIVEVIEW_VADJ : e->vadj = g_value_get_object(val); set_vertical_params(e); if ( e->vadj != NULL ) { @@ -256,7 +228,7 @@ static void sc_editor_set_property(GObject *obj, guint id, const GValue *val, } break; - case SCEDITOR_HADJ : + case GTKNARRATIVEVIEW_HADJ : e->hadj = g_value_get_object(val); set_horizontal_params(e); if ( e->hadj != NULL ) { @@ -276,23 +248,23 @@ static void sc_editor_set_property(GObject *obj, guint id, const GValue *val, static void sc_editor_get_property(GObject *obj, guint id, GValue *val, GParamSpec *spec) { - SCEditor *e = SC_EDITOR(obj); + GtkNarrativeView *e = GTK_NARRATIVE_VIEW(obj); switch ( id ) { - case SCEDITOR_VADJ : + case GTKNARRATIVEVIEW_VADJ : g_value_set_object(val, e->vadj); break; - case SCEDITOR_HADJ : + case GTKNARRATIVEVIEW_HADJ : g_value_set_object(val, e->hadj); break; - case SCEDITOR_VPOL : + case GTKNARRATIVEVIEW_VPOL : g_value_set_enum(val, e->vpol); break; - case SCEDITOR_HPOL : + case GTKNARRATIVEVIEW_HPOL : g_value_set_enum(val, e->hpol); break; @@ -312,7 +284,7 @@ static GtkSizeRequestMode get_request_mode(GtkWidget *widget) static void get_preferred_width(GtkWidget *widget, gint *min, gint *natural) { - SCEditor *e = SC_EDITOR(widget); + GtkNarrativeView *e = GTK_NARRATIVE_VIEW(widget); if ( e->flow ) { *min = 100; *natural = 640; @@ -325,7 +297,7 @@ static void get_preferred_width(GtkWidget *widget, gint *min, gint *natural) static void get_preferred_height(GtkWidget *widget, gint *min, gint *natural) { - SCEditor *e = SC_EDITOR(widget); + GtkNarrativeView *e = GTK_NARRATIVE_VIEW(widget); if ( e->flow ) { *min = 1000; *natural = 1000; @@ -336,27 +308,27 @@ static void get_preferred_height(GtkWidget *widget, gint *min, gint *natural) } -static void sc_editor_class_init(SCEditorClass *klass) +static void gtk_narrative_view_class_init(GtkNarrativeViewClass *klass) { GObjectClass *goc = G_OBJECT_CLASS(klass); goc->set_property = sc_editor_set_property; goc->get_property = sc_editor_get_property; - g_object_class_override_property(goc, SCEDITOR_VADJ, "vadjustment"); - g_object_class_override_property(goc, SCEDITOR_HADJ, "hadjustment"); - g_object_class_override_property(goc, SCEDITOR_VPOL, "vscroll-policy"); - g_object_class_override_property(goc, SCEDITOR_HPOL, "hscroll-policy"); + g_object_class_override_property(goc, GTKNARRATIVEVIEW_VADJ, "vadjustment"); + g_object_class_override_property(goc, GTKNARRATIVEVIEW_HADJ, "hadjustment"); + g_object_class_override_property(goc, GTKNARRATIVEVIEW_VPOL, "vscroll-policy"); + g_object_class_override_property(goc, GTKNARRATIVEVIEW_HPOL, "hscroll-policy"); GTK_WIDGET_CLASS(klass)->get_request_mode = get_request_mode; GTK_WIDGET_CLASS(klass)->get_preferred_width = get_preferred_width; GTK_WIDGET_CLASS(klass)->get_preferred_height = get_preferred_height; GTK_WIDGET_CLASS(klass)->get_preferred_height_for_width = NULL; - g_signal_new("changed", SC_TYPE_EDITOR, G_SIGNAL_RUN_LAST, 0, + g_signal_new("changed", GTK_TYPE_NARRATIVE_VIEW, G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); } -static void sc_editor_init(SCEditor *e) +static void gtk_narrative_view_init(GtkNarrativeView *e) { e->vpol = GTK_SCROLL_NATURAL; e->hpol = GTK_SCROLL_NATURAL; @@ -365,134 +337,64 @@ static void sc_editor_init(SCEditor *e) } -void sc_editor_set_background(SCEditor *e, double r, double g, double b) -{ - e->bgcol[0] = r; - e->bgcol[1] = g; - e->bgcol[2] = b; -} - - -void sc_editor_ensure_cursor(SCEditor *e) -{ - if ( e->cursor_frame != NULL ) return; - e->cursor_frame = e->top; - e->cpos.para = 0; - e->cpos.pos = 0; - e->cpos.trail = 0; - e->selection = NULL; -} - - -static void sc_editor_remove_cursor(SCEditor *e) -{ - e->cursor_frame = NULL; - e->cpos.para = 0; - e->cpos.pos = 0; - e->cpos.trail = 0; - e->selection = NULL; -} - - -/* (Re-)run the entire rendering pipeline. - * NB "full" means "full". All frame, line and box handles will become - * invalid. The cursor position will be unset. */ -static void full_rerender(SCEditor *e) -{ - PangoContext *pc; - - frame_free(e->top); - sc_editor_remove_cursor(e); - - pc = gdk_pango_context_get(); - - e->top = interp_and_shape(e->scblocks, e->stylesheet, e->cbl, - e->is, e->slidenum, - pc, e->log_w, 0.0, e->lang); - - 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, pc); - update_size(e); - - sc_editor_redraw(e); - - g_object_unref(pc); -} - - -void sc_editor_redraw(SCEditor *e) -{ - gint w, h; - - w = gtk_widget_get_allocated_width(GTK_WIDGET(e)); - h = gtk_widget_get_allocated_height(GTK_WIDGET(e)); - - gtk_widget_queue_draw_area(GTK_WIDGET(e), 0, 0, w, h); -} - - static void paste_storycode_received(GtkClipboard *cb, GtkSelectionData *seldata, gpointer vp) { - SCEditor *e = vp; - SCBlock *nf; - const guchar *t; - - t = gtk_selection_data_get_data(seldata); - - printf("received storycode paste\n"); - printf("'%s'\n", t); - if ( t == NULL ) return; - - /* FIXME: It might not be a new frame */ - nf = sc_parse((char *)t); - show_sc_blocks(nf); - sc_block_append_block(sc_block_child(e->scblocks), nf); - full_rerender(e); +// GtkNarrativeView *e = vp; +// SCBlock *nf; +// const guchar *t; +// +// t = gtk_selection_data_get_data(seldata); +// +// printf("received storycode paste\n"); +// printf("'%s'\n", t); +// if ( t == NULL ) return; +// +// /* FIXME: It might not be a new frame */ +// nf = sc_parse((char *)t); +// show_sc_blocks(nf); +// sc_block_append_block(sc_block_child(e->scblocks), nf); +// full_rerender(e); } static void paste_text_received(GtkClipboard *cb, GtkSelectionData *seldata, gpointer vp) { - SCEditor *e = vp; - SCBlock *bl; - guchar *t; - SCBlock *cur_bl; - size_t cur_sc_pos; - size_t offs; - Paragraph *para; - - t = gtk_selection_data_get_text(seldata); - - printf("received text paste\n"); - printf("'%s'\n", t); - if ( t == NULL ) return; - - bl = sc_parse((char *)t); - - if ( e->cursor_frame == NULL ) { - fprintf(stderr, _("No frame selected for paste\n")); - return; - } - - para = e->cursor_frame->paras[e->cpos.para]; - offs = pos_trail_to_offset(para, e->cpos.pos, e->cpos.trail); - - get_sc_pos(e->cursor_frame, e->cpos.para, offs, &cur_bl, &cur_sc_pos); - sc_insert_block(cur_bl, cur_sc_pos, bl); - full_rerender(e); +// GtkNarrativeView *e = vp; +// SCBlock *bl; +// guchar *t; +// SCBlock *cur_bl; +// size_t cur_sc_pos; +// size_t offs; +// Paragraph *para; +// +// t = gtk_selection_data_get_text(seldata); +// +// printf("received text paste\n"); +// printf("'%s'\n", t); +// if ( t == NULL ) return; +// +// bl = sc_parse((char *)t); +// +// if ( e->cursor_frame == NULL ) { +// fprintf(stderr, _("No frame selected for paste\n")); +// return; +// } +// +// para = e->cursor_frame->paras[e->cpos.para]; +// offs = pos_trail_to_offset(para, e->cpos.pos, e->cpos.trail); +// +// get_sc_pos(e->cursor_frame, e->cpos.para, offs, &cur_bl, &cur_sc_pos); +// sc_insert_block(cur_bl, cur_sc_pos, bl); +// full_rerender(e); } static void paste_targets_received(GtkClipboard *cb, GdkAtom *targets, gint n_targets, gpointer vp) { - SCEditor *e = vp; + GtkNarrativeView *e = vp; int i; int have_sc = 0; int index_sc, index_text; @@ -530,7 +432,7 @@ static void paste_targets_received(GtkClipboard *cb, GdkAtom *targets, } -void sc_editor_paste(SCEditor *e) +void sc_editor_paste(GtkNarrativeView *e) { GtkClipboard *cb; GdkAtom atom; @@ -544,15 +446,6 @@ void sc_editor_paste(SCEditor *e) } -void sc_editor_add_storycode(SCEditor *e, const char *sc) -{ - SCBlock *nf; - nf = sc_parse(sc); - sc_block_append_block(sc_block_child(e->scblocks), nf); - full_rerender(e); -} - - static void clipboard_get(GtkClipboard *cb, GtkSelectionData *seldata, guint info, gpointer data) { @@ -582,239 +475,110 @@ static void clipboard_clear(GtkClipboard *cb, gpointer data) } -void sc_editor_copy_selected_frame(SCEditor *e) -{ - char *t; - GtkClipboard *cb; - GdkAtom atom; - GtkTargetEntry targets[1]; - - if ( e->selection == NULL ) return; - - atom = gdk_atom_intern("CLIPBOARD", FALSE); - if ( atom == GDK_NONE ) return; - - cb = gtk_clipboard_get(atom); - - targets[0].target = "text/x-storycode"; - targets[0].flags = 0; - targets[0].info = 0; - - /* FIXME: Offer image, PDF etc? */ - - printf("copying frame\n"); - - t = serialise_sc_block(e->selection->scblocks); - - gtk_clipboard_set_with_data(cb, targets, 1, - clipboard_get, clipboard_clear, t); -} - - -static void copy_selection(SCEditor *e) -{ - char *t; - GtkClipboard *cb; - GdkAtom atom; - GtkTargetEntry targets[1]; - SCBlock *bl; - - if ( e->selection == NULL ) return; - - atom = gdk_atom_intern("CLIPBOARD", FALSE); - if ( atom == GDK_NONE ) return; - - cb = gtk_clipboard_get(atom); - - - targets[0].target = "text/x-storycode"; - targets[0].flags = 0; - targets[0].info = 0; - - printf("copying selection\n"); - - bl = block_at_cursor(e->cursor_frame, e->cpos.para, 0); - if ( bl == NULL ) return; - - t = serialise_sc_block(bl); - - gtk_clipboard_set_with_data(cb, targets, 1, - clipboard_get, clipboard_clear, t); -} - - -void sc_editor_delete_selected_frame(SCEditor *e) +static void copy_selection(GtkNarrativeView *e) { - SCBlock *scb_old = e->scblocks; - sc_block_delete(&e->scblocks, e->selection->scblocks); - assert(scb_old == e->scblocks); - full_rerender(e); - emit_change_sig(e); +// char *t; +// GtkClipboard *cb; +// GdkAtom atom; +// GtkTargetEntry targets[1]; +// +// atom = gdk_atom_intern("CLIPBOARD", FALSE); +// if ( atom == GDK_NONE ) return; +// +// cb = gtk_clipboard_get(atom); +// +// targets[0].target = "text/x-storycode"; +// targets[0].flags = 0; +// targets[0].info = 0; +// +// printf("copying selection\n"); +// +// bl = block_at_cursor(e->cursor_frame, e->cpos.para, 0); +// if ( bl == NULL ) return; +// +// t = serialise_sc_block(bl); +// +// gtk_clipboard_set_with_data(cb, targets, 1, +// clipboard_get, clipboard_clear, t); } -static gint destroy_sig(GtkWidget *window, SCEditor *e) +static gint destroy_sig(GtkWidget *window, GtkNarrativeView *e) { return 0; } -static void draw_editing_box(cairo_t *cr, struct frame *fr) -{ - const double dash[] = {2.0, 2.0}; - double xmin, ymin, width, height; - double ptot_w, ptot_h; - - xmin = fr->x; - ymin = fr->y; - width = fr->w; - height = fr->h; - - cairo_new_path(cr); - cairo_rectangle(cr, xmin, ymin, width, height); - cairo_set_source_rgb(cr, 0.0, 0.69, 1.0); - cairo_set_line_width(cr, 0.5); - cairo_stroke(cr); - - cairo_new_path(cr); - ptot_w = fr->pad_l + fr->pad_r; - ptot_h = fr->pad_t + fr->pad_b; - cairo_rectangle(cr, xmin+fr->pad_l, ymin+fr->pad_t, - width-ptot_w, height-ptot_h); - cairo_set_dash(cr, dash, 2, 0.0); - cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); - cairo_set_line_width(cr, 0.1); - cairo_stroke(cr); - - cairo_set_dash(cr, NULL, 0, 0.0); -} - - -static void draw_para_highlight(cairo_t *cr, struct frame *fr, int cursor_para) -{ - double cx, cy, w, h; - - if ( get_para_highlight(fr, cursor_para, &cx, &cy, &w, &h) != 0 ) { - return; - } - - cairo_new_path(cr); - cairo_rectangle(cr, cx+fr->x, cy+fr->y, w, h); - cairo_set_source_rgba(cr, 0.7, 0.7, 1.0, 0.5); - cairo_set_line_width(cr, 5.0); - cairo_stroke(cr); -} - - -static void draw_caret(cairo_t *cr, struct frame *fr, struct edit_pos cpos, - int hgh) -{ - double cx, clow, chigh, h; - const double t = 1.8; - size_t offs; - Paragraph *para; - - if ( hgh ) { - draw_para_highlight(cr, fr, cpos.para); - return; - } - - assert(fr != NULL); - - para = fr->paras[cpos.para]; - if ( para_type(para) != PARA_TYPE_TEXT ) { - draw_para_highlight(cr, fr, cpos.para); - return; - } - - offs = pos_trail_to_offset(para, cpos.pos, cpos.trail); - get_cursor_pos(fr, cpos.para, offs, &cx, &clow, &h); - - cx += fr->x; - clow += fr->y; - chigh = clow + h; - - cairo_move_to(cr, cx, clow); - cairo_line_to(cr, cx, chigh); - - cairo_move_to(cr, cx-t, clow-t); - cairo_line_to(cr, cx, clow); - cairo_move_to(cr, cx+t, clow-t); - cairo_line_to(cr, cx, clow); - - cairo_move_to(cr, cx-t, chigh+t); - cairo_line_to(cr, cx, chigh); - cairo_move_to(cr, cx+t, chigh+t); - cairo_line_to(cr, cx, chigh); - - cairo_set_source_rgb(cr, 0.86, 0.0, 0.0); - cairo_set_line_width(cr, 1.0); - cairo_stroke(cr); -} - - -static void draw_resize_handle(cairo_t *cr, double x, double y) -{ - cairo_new_path(cr); - cairo_rectangle(cr, x, y, 20.0, 20.0); - cairo_set_source_rgba(cr, 0.9, 0.9, 0.9, 0.5); - cairo_fill(cr); -} - - -static void draw_overlay(cairo_t *cr, SCEditor *e) -{ - if ( e->selection != NULL ) { - - double x, y, w, h; - - draw_editing_box(cr, e->selection); - - x = e->selection->x; - y = e->selection->y; - w = e->selection->w; - h = e->selection->h; - - if ( e->selection->resizable ) { - /* Draw resize handles */ - draw_resize_handle(cr, x, y+h-20.0); - draw_resize_handle(cr, x+w-20.0, y); - draw_resize_handle(cr, x, y); - draw_resize_handle(cr, x+w-20.0, y+h-20.0); - } - - draw_caret(cr, e->cursor_frame, e->cpos, e->para_highlight); - - } - - if ( (e->drag_status == DRAG_STATUS_DRAGGING) - && ((e->drag_reason == DRAG_REASON_CREATE) - || (e->drag_reason == DRAG_REASON_IMPORT)) ) - { - cairo_new_path(cr); - cairo_rectangle(cr, e->start_corner_x, e->start_corner_y, - e->drag_corner_x - e->start_corner_x, - e->drag_corner_y - e->start_corner_y); - cairo_set_source_rgb(cr, 0.5, 0.5, 0.5); - cairo_set_line_width(cr, 0.5); - cairo_stroke(cr); - } - - if ( (e->drag_status == DRAG_STATUS_DRAGGING) - && ((e->drag_reason == DRAG_REASON_RESIZE) - || (e->drag_reason == DRAG_REASON_MOVE)) ) - { - cairo_new_path(cr); - cairo_rectangle(cr, e->box_x, e->box_y, - e->box_width, e->box_height); - cairo_set_source_rgb(cr, 0.5, 0.5, 0.5); - cairo_set_line_width(cr, 0.5); - cairo_stroke(cr); - } -} - - -static gboolean draw_sig(GtkWidget *da, cairo_t *cr, SCEditor *e) +//static void draw_para_highlight(cairo_t *cr, struct frame *fr, int cursor_para) +//{ +// double cx, cy, w, h; +// +// if ( get_para_highlight(fr, cursor_para, &cx, &cy, &w, &h) != 0 ) { +// return; +// } +// +// cairo_new_path(cr); +// cairo_rectangle(cr, cx+fr->x, cy+fr->y, w, h); +// cairo_set_source_rgba(cr, 0.7, 0.7, 1.0, 0.5); +// cairo_set_line_width(cr, 5.0); +// cairo_stroke(cr); +//} + + +//static void draw_caret(cairo_t *cr, struct frame *fr, struct edit_pos cpos, +// int hgh) +//{ +// double cx, clow, chigh, h; +// const double t = 1.8; +// size_t offs; +// Paragraph *para; +// +// if ( hgh ) { +// draw_para_highlight(cr, fr, cpos.para); +// return; +// } +// +// assert(fr != NULL); +// +// para = fr->paras[cpos.para]; +// if ( para_type(para) != PARA_TYPE_TEXT ) { +// draw_para_highlight(cr, fr, cpos.para); +// return; +// } +// +// offs = pos_trail_to_offset(para, cpos.pos, cpos.trail); +// get_cursor_pos(fr, cpos.para, offs, &cx, &clow, &h); +// +// cx += fr->x; +// clow += fr->y; +// chigh = clow + h; +// +// cairo_move_to(cr, cx, clow); +// cairo_line_to(cr, cx, chigh); +// +// cairo_move_to(cr, cx-t, clow-t); +// cairo_line_to(cr, cx, clow); +// cairo_move_to(cr, cx+t, clow-t); +// cairo_line_to(cr, cx, clow); +// +// cairo_move_to(cr, cx-t, chigh+t); +// cairo_line_to(cr, cx, chigh); +// cairo_move_to(cr, cx+t, chigh+t); +// cairo_line_to(cr, cx, chigh); +// +// cairo_set_source_rgb(cr, 0.86, 0.0, 0.0); +// cairo_set_line_width(cr, 1.0); +// cairo_stroke(cr); +//} + + +static void draw_overlay(cairo_t *cr, GtkNarrativeView *e) +{ + //draw_caret(cr, e->cursor_frame, e->cpos, e->para_highlight); +} + + +static gboolean draw_sig(GtkWidget *da, cairo_t *cr, GtkNarrativeView *e) { /* Ultimate background */ if ( e->bg_pixbuf != NULL ) { @@ -837,9 +601,6 @@ static gboolean draw_sig(GtkWidget *da, cairo_t *cr, SCEditor *e) cairo_fill(cr); /* Contents */ - recursive_draw(e->top, cr, e->is, - e->scroll_pos/e->view_scale, - (e->scroll_pos + e->visible_height)/e->view_scale); /* Editing overlay */ draw_overlay(cr, e); @@ -848,831 +609,387 @@ static gboolean draw_sig(GtkWidget *da, cairo_t *cr, SCEditor *e) } -SCBlock *split_paragraph_at_cursor(SCEditor *e) -{ - size_t offs; - Paragraph *para; - - if ( e->cursor_frame == NULL ) return NULL; +static void check_cursor_visible(GtkNarrativeView *e) +{ +// double x, y, h; +// size_t offs; +// Paragraph *para; +// +// if ( e->cursor_frame == NULL ) return; +// +// para = e->cursor_frame->paras[e->cpos.para]; +// offs = pos_trail_to_offset(para, e->cpos.pos, e->cpos.trail); +// get_cursor_pos(e->cursor_frame, e->cpos.para, offs, &x, &y, &h); +// +// /* Off the bottom? */ +// if ( y - e->scroll_pos + h > e->visible_height ) { +// e->scroll_pos = y + h - e->visible_height; +// e->scroll_pos += e->cursor_frame->pad_b; +// } +// +// /* Off the top? */ +// if ( y < e->scroll_pos ) { +// e->scroll_pos = y - e->cursor_frame->pad_t; +// } +} + + +static void do_backspace(GtkNarrativeView *e) +{ +// double wrapw = e->cursor_frame->w - e->cursor_frame->pad_l - e->cursor_frame->pad_r; +// +// if ( e->sel_active ) { +// +// /* Delete the selected block */ +// delete_text_from_frame(e->cursor_frame, e->sel_start, e->sel_end, wrapw); +// +// /* Cursor goes at start of deletion */ +// sort_positions(&e->sel_start, &e->sel_end); +// e->cpos = e->sel_start; +// e->sel_active = 0; +// +// } else { +// +// if ( para_type(e->cursor_frame->paras[e->cpos.para]) == PARA_TYPE_TEXT ) { +// +// /* Delete one character */ +// struct edit_pos p1, p2; +// +// p1 = e->cpos; +// +// p2 = p1; +// +// cursor_moveh(e->cursor_frame, &p2, -1); +// show_edit_pos(p1); +// show_edit_pos(p2); +// +// delete_text_from_frame(e->cursor_frame, p1, p2, wrapw); +// e->cpos = p2; +// +// } else { +// +// /* FIXME: Implement this */ +// fprintf(stderr, "Deleting non-text paragraph\n"); +// +// } +// +// } - para = e->cursor_frame->paras[e->cpos.para]; - offs = pos_trail_to_offset(para, e->cpos.pos, e->cpos.trail); - return split_paragraph(e->cursor_frame, e->cpos.para, offs, e->pc); + emit_change_sig(e); + redraw(e); +} + + +static void insert_text(char *t, GtkNarrativeView *e) +{ +// Paragraph *para; +// +// if ( e->cursor_frame == NULL ) return; +// +// if ( e->sel_active ) { +// do_backspace(e->cursor_frame, e); +// } +// +// if ( strcmp(t, "\n") == 0 ) { +// split_paragraph_at_cursor(e); +// if ( e->flow ) update_size(e); +// cursor_moveh(e->cursor_frame, &e->cpos, +1); +// check_cursor_visible(e); +// emit_change_sig(e); +// redraw(e); +// return; +// } +// +// para = e->cursor_frame->paras[e->cpos.para]; +// +// /* Is this paragraph even a text one? */ +// if ( para_type(para) == PARA_TYPE_TEXT ) { +// +// size_t off; +// +// /* Yes. The "easy" case */ +// +// if ( !position_editable(e->cursor_frame, e->cpos) ) { +// fprintf(stderr, "Position not editable\n"); +// return; +// } +// +// off = pos_trail_to_offset(para, e->cpos.pos, e->cpos.trail); +// insert_text_in_paragraph(para, off, t); +// wrap_paragraph(para, NULL, +// e->cursor_frame->w - e->cursor_frame->pad_l +// - e->cursor_frame->pad_r, 0, 0); +// if ( e->flow ) update_size(e); +// +// cursor_moveh(e->cursor_frame, &e->cpos, +1); +// +// } else { +// +// SCBlock *bd; +// SCBlock *ad; +// Paragraph *pnew; +// +// bd = para_scblock(para); +// if ( bd == NULL ) { +// fprintf(stderr, "No SCBlock for para\n"); +// return; +// } +// +// /* No. Create a new text paragraph straight afterwards */ +// ad = sc_block_insert_after(bd, NULL, NULL, strdup(t)); +// if ( ad == NULL ) { +// fprintf(stderr, "Failed to add SCBlock\n"); +// return; +// } +// +// pnew = insert_paragraph(e->cursor_frame, e->cpos.para); +// if ( pnew == NULL ) { +// fprintf(stderr, "Failed to insert paragraph\n"); +// return; +// } +// add_run(pnew, ad, e->cursor_frame->fontdesc, +// e->cursor_frame->col, NULL); +// +// wrap_frame(e->cursor_frame, e->pc); +// +// e->cpos.para += 1; +// e->cpos.pos = 0; +// e->cpos.trail = 1; +// +// } +// + emit_change_sig(e); + check_cursor_visible(e); + redraw(e); } -static void check_cursor_visible(SCEditor *e) +static gboolean im_commit_sig(GtkIMContext *im, gchar *str, + GtkNarrativeView *e) { - double x, y, h; - size_t offs; - Paragraph *para; + insert_text(str, e); + return FALSE; +} - if ( e->cursor_frame == NULL ) return; - para = e->cursor_frame->paras[e->cpos.para]; - offs = pos_trail_to_offset(para, e->cpos.pos, e->cpos.trail); - get_cursor_pos(e->cursor_frame, e->cpos.para, offs, &x, &y, &h); +static void unset_selection(GtkNarrativeView *e) +{ + int a, b; - /* Off the bottom? */ - if ( y - e->scroll_pos + h > e->visible_height ) { - e->scroll_pos = y + h - e->visible_height; - e->scroll_pos += e->cursor_frame->pad_b; - } + if ( !e->sel_active ) return; - /* Off the top? */ - if ( y < e->scroll_pos ) { - e->scroll_pos = y - e->cursor_frame->pad_t; + a = e->sel_start.para; + b = e->sel_end.para; + if ( a > b ) { + a = e->sel_end.para; + b = e->sel_start.para; } + e->sel_active = 0; } -static void do_backspace(struct frame *fr, SCEditor *e) -{ - double wrapw = e->cursor_frame->w - e->cursor_frame->pad_l - e->cursor_frame->pad_r; - - if ( e->sel_active ) { - - /* Delete the selected block */ - delete_text_from_frame(e->cursor_frame, e->sel_start, e->sel_end, wrapw); +static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event, + GtkNarrativeView *e) +{ +// enum corner c; +// gdouble x, y; +// struct frame *clicked; +// int shift; +// +// x = event->x - e->border_offs_x; +// y = event->y - e->border_offs_y + e->scroll_pos; +// x /= e->view_scale; +// y /= e->view_scale; +// shift = event->state & GDK_SHIFT_MASK; +// +// /* Clicked within the currently selected frame +// * -> resize, move or select text */ +// if ( (e->selection != NULL) && (clicked == e->selection) ) { +// +// struct frame *fr; +// +// fr = e->selection; +// +// /* Within the resizing region? */ +// c = which_corner(x, y, fr); +// if ( (c != CORNER_NONE) && fr->resizable && shift ) { +// +// e->drag_reason = DRAG_REASON_RESIZE; +// e->drag_corner = c; +// +// e->start_corner_x = x; +// e->start_corner_y = y; +// e->diagonal_length = pow(fr->w, 2.0); +// e->diagonal_length += pow(fr->h, 2.0); +// e->diagonal_length = sqrt(e->diagonal_length); +// +// calculate_box_size(fr, e, x, y); +// +// e->drag_status = DRAG_STATUS_COULD_DRAG; +// e->drag_reason = DRAG_REASON_RESIZE; +// +// } else { +// +// /* Position cursor and prepare for possible drag */ +// e->cursor_frame = clicked; +// check_paragraph(e->cursor_frame, e->pc, sc_block_child(fr->scblocks)); +// find_cursor(clicked, x-fr->x, y-fr->y, &e->cpos); +// ensure_run(e->cursor_frame, e->cpos); +// +// e->start_corner_x = x; +// e->start_corner_y = y; +// +// if ( event->type == GDK_2BUTTON_PRESS ) { +// check_callback_click(e->cursor_frame, e->cpos.para); +// } +// +// if ( fr->resizable && shift ) { +// e->drag_status = DRAG_STATUS_COULD_DRAG; +// e->drag_reason = DRAG_REASON_MOVE; +// } else if ( !e->para_highlight ) { +// e->drag_status = DRAG_STATUS_COULD_DRAG; +// e->drag_reason = DRAG_REASON_TEXTSEL; +// unset_selection(e); +// find_cursor(clicked, x-fr->x, y-fr->y, &e->sel_start); +// } +// +// } +// +// } else if ( (clicked == NULL) +// || ( !e->top_editable && (clicked == e->top) ) ) +// { +// /* Clicked no object. Deselect old object. +// * If shift held, set up for creating a new one. */ +// e->selection = NULL; +// unset_selection(e); +// +// if ( shift ) { +// e->start_corner_x = x; +// e->start_corner_y = y; +// e->drag_status = DRAG_STATUS_COULD_DRAG; +// e->drag_reason = DRAG_REASON_CREATE; +// } else { +// e->drag_status = DRAG_STATUS_NONE; +// e->drag_reason = DRAG_REASON_NONE; +// } +// +// } else { +// +// /* Clicked an existing frame, no immediate dragging */ +// e->drag_status = DRAG_STATUS_COULD_DRAG; +// e->drag_reason = DRAG_REASON_TEXTSEL; +// unset_selection(e); +// find_cursor(clicked, x-clicked->x, y-clicked->y, +// &e->sel_start); +// find_cursor(clicked, x-clicked->x, y-clicked->y, +// &e->sel_end); +// e->selection = clicked; +// e->cursor_frame = clicked; +// if ( clicked == e->top ) { +// 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->cpos); +// ensure_run(e->cursor_frame, e->cpos); +// +// } - /* Cursor goes at start of deletion */ - sort_positions(&e->sel_start, &e->sel_end); - e->cpos = e->sel_start; - e->sel_active = 0; + gtk_widget_grab_focus(GTK_WIDGET(da)); + redraw(e); + return FALSE; +} - } else { - if ( para_type(e->cursor_frame->paras[e->cpos.para]) == PARA_TYPE_TEXT ) { +static gboolean motion_sig(GtkWidget *da, GdkEventMotion *event, + GtkNarrativeView *e) +{ + gdouble x, y; - /* Delete one character */ - struct edit_pos p1, p2; + x = event->x - e->border_offs_x; + y = event->y - e->border_offs_y + e->scroll_pos; + x /= e->view_scale; + y /= e->view_scale; - p1 = e->cpos; + if ( e->drag_status == DRAG_STATUS_COULD_DRAG ) { - p2 = p1; + /* We just got a motion signal, and the status was "could drag", + * therefore the drag has started. */ + e->drag_status = DRAG_STATUS_DRAGGING; - cursor_moveh(e->cursor_frame, &p2, -1); - show_edit_pos(p1); - show_edit_pos(p2); + } - delete_text_from_frame(e->cursor_frame, p1, p2, wrapw); - e->cpos = p2; + switch ( e->drag_reason ) { - } else { + case DRAG_REASON_NONE : + break; - /* FIXME: Implement this */ - fprintf(stderr, "Deleting non-text paragraph\n"); + case DRAG_REASON_IMPORT : + /* Do nothing, handled by dnd_motion() */ + break; - } + case DRAG_REASON_TEXTSEL : + //unset_selection(e); + //find_cursor(fr, x-fr->x, y-fr->y, &e->sel_end); + //rewrap_paragraph_range(fr, e->sel_start.para, e->sel_end.para, + // e->sel_start, e->sel_end, 1); + //find_cursor(fr, x-fr->x, y-fr->y, &e->cpos); + //e->sel_active = !positions_equal(e->sel_start, e->sel_end); + redraw(e); + break; } - emit_change_sig(e); - sc_editor_redraw(e); + gdk_event_request_motions(event); + return FALSE; } -static void insert_text(char *t, SCEditor *e) +static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event, + GtkNarrativeView *e) { - Paragraph *para; - - if ( e->cursor_frame == NULL ) return; - - if ( e->sel_active ) { - do_backspace(e->cursor_frame, e); - } + gboolean r; + int claim = 0; - if ( strcmp(t, "\n") == 0 ) { - split_paragraph_at_cursor(e); - if ( e->flow ) update_size(e); - cursor_moveh(e->cursor_frame, &e->cpos, +1); - check_cursor_visible(e); - emit_change_sig(e); - sc_editor_redraw(e); - return; - } + /* Throw the event to the IM context and let it sort things out */ + r = gtk_im_context_filter_keypress(GTK_IM_CONTEXT(e->im_context), + event); + if ( r ) return FALSE; /* IM ate it */ - para = e->cursor_frame->paras[e->cpos.para]; + switch ( event->keyval ) { - /* Is this paragraph even a text one? */ - if ( para_type(para) == PARA_TYPE_TEXT ) { + case GDK_KEY_Escape : + if ( !e->para_highlight ) { + //sc_editor_remove_cursor(e); + redraw(e); + claim = 1; + } + break; - size_t off; + case GDK_KEY_Left : + //cursor_moveh(e->cursor_frame, &e->cpos, -1); + redraw(e); + claim = 1; + break; - /* Yes. The "easy" case */ + case GDK_KEY_Right : + //cursor_moveh(e->cursor_frame, &e->cpos, +1); + redraw(e); + claim = 1; + break; - if ( !position_editable(e->cursor_frame, e->cpos) ) { - fprintf(stderr, "Position not editable\n"); - return; - } + case GDK_KEY_Up : + //cursor_moveh(e->cursor_frame, &e->cpos, -1); + redraw(e); + claim = 1; + break; - off = pos_trail_to_offset(para, e->cpos.pos, e->cpos.trail); - insert_text_in_paragraph(para, off, t); - wrap_paragraph(para, NULL, - e->cursor_frame->w - e->cursor_frame->pad_l - - e->cursor_frame->pad_r, 0, 0); - if ( e->flow ) update_size(e); - - cursor_moveh(e->cursor_frame, &e->cpos, +1); - - } else { - - SCBlock *bd; - SCBlock *ad; - Paragraph *pnew; - - bd = para_scblock(para); - if ( bd == NULL ) { - fprintf(stderr, "No SCBlock for para\n"); - return; - } - - /* No. Create a new text paragraph straight afterwards */ - ad = sc_block_insert_after(bd, NULL, NULL, strdup(t)); - if ( ad == NULL ) { - fprintf(stderr, "Failed to add SCBlock\n"); - return; - } - - pnew = insert_paragraph(e->cursor_frame, e->cpos.para); - if ( pnew == NULL ) { - fprintf(stderr, "Failed to insert paragraph\n"); - return; - } - add_run(pnew, ad, e->cursor_frame->fontdesc, - e->cursor_frame->col, NULL); - - wrap_frame(e->cursor_frame, e->pc); - - e->cpos.para += 1; - e->cpos.pos = 0; - e->cpos.trail = 1; - - } - - emit_change_sig(e); - check_cursor_visible(e); - sc_editor_redraw(e); -} - - -static gboolean im_commit_sig(GtkIMContext *im, gchar *str, - SCEditor *e) -{ - insert_text(str, e); - return FALSE; -} - - -static int within_frame(struct frame *fr, double x, double y) -{ - if ( fr == NULL ) return 0; - if ( x < fr->x ) return 0; - if ( y < fr->y ) return 0; - if ( x > fr->x + fr->w ) return 0; - if ( y > fr->y + fr->h ) return 0; - return 1; -} - - -static struct frame *find_frame_at_position(struct frame *fr, - double x, double y) -{ - int i; - - for ( i=0; inum_children; i++ ) { - - if ( within_frame(fr->children[i], x, y) ) { - return find_frame_at_position(fr->children[i], x, y); - } - - } - - if ( within_frame(fr, x, y) ) return fr; - return NULL; -} - - -static enum corner which_corner(double xp, double yp, struct frame *fr) -{ - double x, y; /* Relative to object position */ - - x = xp - fr->x; - y = yp - fr->y; - - if ( x < 0.0 ) return CORNER_NONE; - if ( y < 0.0 ) return CORNER_NONE; - if ( x > fr->w ) return CORNER_NONE; - if ( y > fr->h ) return CORNER_NONE; - - /* Top left? */ - if ( (x<20.0) && (y<20.0) ) return CORNER_TL; - if ( (x>fr->w-20.0) && (y<20.0) ) return CORNER_TR; - if ( (x<20.0) && (y>fr->h-20.0) ) return CORNER_BL; - if ( (x>fr->w-20.0) && (y>fr->h-20.0) ) return CORNER_BR; - - return CORNER_NONE; -} - - -static void calculate_box_size(struct frame *fr, SCEditor *e, - double x, double y) -{ - double ddx, ddy, dlen, mult; - double vx, vy, dbx, dby; - - ddx = x - e->start_corner_x; - ddy = y - e->start_corner_y; - - if ( !fr->is_image ) { - - switch ( e->drag_corner ) { - - case CORNER_BR : - e->box_x = fr->x; - e->box_y = fr->y; - e->box_width = fr->w + ddx; - e->box_height = fr->h + ddy; - break; - - case CORNER_BL : - e->box_x = fr->x + ddx; - e->box_y = fr->y; - e->box_width = fr->w - ddx; - e->box_height = fr->h + ddy; - break; - - case CORNER_TL : - e->box_x = fr->x + ddx; - e->box_y = fr->y + ddy; - e->box_width = fr->w - ddx; - e->box_height = fr->h - ddy; - break; - - case CORNER_TR : - e->box_x = fr->x; - e->box_y = fr->y + ddy; - e->box_width = fr->w + ddx; - e->box_height = fr->h - ddy; - break; - - case CORNER_NONE : - break; - - } - return; - - - } - - switch ( e->drag_corner ) { - - case CORNER_BR : - vx = fr->w; - vy = fr->h; - break; - - case CORNER_BL : - vx = -fr->w; - vy = fr->h; - break; - - case CORNER_TL : - vx = -fr->w; - vy = -fr->h; - break; - - case CORNER_TR : - vx = fr->w; - vy = -fr->h; - break; - - case CORNER_NONE : - default: - vx = 0.0; - vy = 0.0; - break; - - } - - dlen = (ddx*vx + ddy*vy) / e->diagonal_length; - mult = (dlen+e->diagonal_length) / e->diagonal_length; - - e->box_width = fr->w * mult; - e->box_height = fr->h * mult; - dbx = e->box_width - fr->w; - dby = e->box_height - fr->h; - - if ( e->box_width < 40.0 ) { - mult = 40.0 / fr->w; - } - if ( e->box_height < 40.0 ) { - mult = 40.0 / fr->h; - } - e->box_width = fr->w * mult; - e->box_height = fr->h * mult; - dbx = e->box_width - fr->w; - dby = e->box_height - fr->h; - - switch ( e->drag_corner ) { - - case CORNER_BR : - e->box_x = fr->x; - e->box_y = fr->y; - break; - - case CORNER_BL : - e->box_x = fr->x - dbx; - e->box_y = fr->y; - break; - - case CORNER_TL : - e->box_x = fr->x - dbx; - e->box_y = fr->y - dby; - break; - - case CORNER_TR : - e->box_x = fr->x; - e->box_y = fr->y - dby; - break; - - case CORNER_NONE : - break; - - } -} - - -static void check_paragraph(struct frame *fr, PangoContext *pc, - SCBlock *scblocks) -{ - if ( fr->n_paras > 0 ) return; - Paragraph *para = last_para(fr); - - if ( scblocks == NULL ) { - /* We have no SCBlocks at all! Better create one... */ - scblocks = sc_parse(""); - fr->scblocks = scblocks; - } - - /* 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); - } - scblocks = sc_block_append(scblocks, NULL, NULL, strdup(""), NULL); - - add_run(para, scblocks, fr->fontdesc, fr->col, NULL); - wrap_paragraph(para, pc, fr->w - fr->pad_l - fr->pad_r, 0, 0); -} - - -static void rewrap_paragraph_range(struct frame *fr, int a, int b, - struct edit_pos sel_start, - struct edit_pos sel_end, - int sel_active) -{ - int i; - int sel_s, sel_e; - Paragraph *para; - - if ( a > b ) { - int t = a; - a = b; b = t; - } - - if ( fr == NULL ) return; - if ( fr->paras == NULL ) return; - - sort_positions(&sel_start, &sel_end); - - //printf("frame %p\n", fr); - //printf("start: "); - //show_edit_pos(sel_start); - //printf(" end: "); - //show_edit_pos(sel_end); - - para = fr->paras[sel_start.para]; - sel_s = pos_trail_to_offset(para, sel_start.pos, sel_start.trail); - para = fr->paras[sel_end.para]; - sel_e = pos_trail_to_offset(para, sel_end.pos, sel_end.trail); - - for ( i=a; i<=b; i++ ) { - size_t srt, end; - if ( sel_active ) { - if ( i == sel_start.para ) { - srt = sel_s; - } else { - srt = 0; - } - if ( i == sel_end.para ) { - end = sel_e; - } else { - end = G_MAXUINT; - } - if ( i > sel_start.para && i < sel_end.para ) { - end = G_MAXUINT; - } - } else { - srt = 0; - end = 0; - } - wrap_paragraph(fr->paras[i], NULL, - fr->w - fr->pad_l - fr->pad_r, srt, end); - } -} - - -static void unset_selection(SCEditor *e) -{ - int a, b; - - if ( !e->sel_active ) return; - - a = e->sel_start.para; - b = e->sel_end.para; - if ( a > b ) { - a = e->sel_end.para; - b = e->sel_start.para; - } - e->sel_active = 0; - rewrap_paragraph_range(e->cursor_frame, a, b, e->sel_start, e->sel_end, 0); -} - - -static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event, - SCEditor *e) -{ - enum corner c; - gdouble x, y; - struct frame *clicked; - int shift; - - x = event->x - e->border_offs_x; - y = event->y - e->border_offs_y + e->scroll_pos; - x /= e->view_scale; - y /= e->view_scale; - shift = event->state & GDK_SHIFT_MASK; - - if ( within_frame(e->selection, x, y) ) { - clicked = e->selection; - } else { - clicked = find_frame_at_position(e->top, x, y); - } - - /* Clicked within the currently selected frame - * -> resize, move or select text */ - if ( (e->selection != NULL) && (clicked == e->selection) ) { - - struct frame *fr; - - fr = e->selection; - - /* Within the resizing region? */ - c = which_corner(x, y, fr); - if ( (c != CORNER_NONE) && fr->resizable && shift ) { - - e->drag_reason = DRAG_REASON_RESIZE; - e->drag_corner = c; - - e->start_corner_x = x; - e->start_corner_y = y; - e->diagonal_length = pow(fr->w, 2.0); - e->diagonal_length += pow(fr->h, 2.0); - e->diagonal_length = sqrt(e->diagonal_length); - - calculate_box_size(fr, e, x, y); - - e->drag_status = DRAG_STATUS_COULD_DRAG; - e->drag_reason = DRAG_REASON_RESIZE; - - } else { - - /* Position cursor and prepare for possible drag */ - e->cursor_frame = clicked; - check_paragraph(e->cursor_frame, e->pc, sc_block_child(fr->scblocks)); - find_cursor(clicked, x-fr->x, y-fr->y, &e->cpos); - ensure_run(e->cursor_frame, e->cpos); - - e->start_corner_x = x; - e->start_corner_y = y; - - if ( event->type == GDK_2BUTTON_PRESS ) { - check_callback_click(e->cursor_frame, e->cpos.para); - } - - if ( fr->resizable && shift ) { - e->drag_status = DRAG_STATUS_COULD_DRAG; - e->drag_reason = DRAG_REASON_MOVE; - } else if ( !e->para_highlight ) { - e->drag_status = DRAG_STATUS_COULD_DRAG; - e->drag_reason = DRAG_REASON_TEXTSEL; - unset_selection(e); - find_cursor(clicked, x-fr->x, y-fr->y, &e->sel_start); - } - - } - - } else if ( (clicked == NULL) - || ( !e->top_editable && (clicked == e->top) ) ) - { - /* Clicked no object. Deselect old object. - * If shift held, set up for creating a new one. */ - e->selection = NULL; - unset_selection(e); - - if ( shift ) { - e->start_corner_x = x; - e->start_corner_y = y; - e->drag_status = DRAG_STATUS_COULD_DRAG; - e->drag_reason = DRAG_REASON_CREATE; - } else { - e->drag_status = DRAG_STATUS_NONE; - e->drag_reason = DRAG_REASON_NONE; - } - - } else { - - /* Clicked an existing frame, no immediate dragging */ - e->drag_status = DRAG_STATUS_COULD_DRAG; - e->drag_reason = DRAG_REASON_TEXTSEL; - unset_selection(e); - find_cursor(clicked, x-clicked->x, y-clicked->y, - &e->sel_start); - find_cursor(clicked, x-clicked->x, y-clicked->y, - &e->sel_end); - e->selection = clicked; - e->cursor_frame = clicked; - if ( clicked == e->top ) { - 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->cpos); - ensure_run(e->cursor_frame, e->cpos); - - } - - gtk_widget_grab_focus(GTK_WIDGET(da)); - sc_editor_redraw(e); - return FALSE; -} - - -static gboolean motion_sig(GtkWidget *da, GdkEventMotion *event, - SCEditor *e) -{ - struct frame *fr = e->selection; - gdouble x, y; - - x = event->x - e->border_offs_x; - y = event->y - e->border_offs_y + e->scroll_pos; - x /= e->view_scale; - y /= e->view_scale; - - if ( e->drag_status == DRAG_STATUS_COULD_DRAG ) { - - /* We just got a motion signal, and the status was "could drag", - * therefore the drag has started. */ - e->drag_status = DRAG_STATUS_DRAGGING; - - } - - switch ( e->drag_reason ) { - - case DRAG_REASON_NONE : - break; - - case DRAG_REASON_CREATE : - e->drag_corner_x = x; - e->drag_corner_y = y; - sc_editor_redraw(e); - break; - - case DRAG_REASON_IMPORT : - /* Do nothing, handled by dnd_motion() */ - break; - - case DRAG_REASON_RESIZE : - calculate_box_size(fr, e, x, y); - sc_editor_redraw(e); - break; - - case DRAG_REASON_MOVE : - e->box_x = (fr->x - e->start_corner_x) + x; - e->box_y = (fr->y - e->start_corner_y) + y; - e->box_width = fr->w; - e->box_height = fr->h; - sc_editor_redraw(e); - break; - - case DRAG_REASON_TEXTSEL : - unset_selection(e); - find_cursor(fr, x-fr->x, y-fr->y, &e->sel_end); - rewrap_paragraph_range(fr, e->sel_start.para, e->sel_end.para, - e->sel_start, e->sel_end, 1); - find_cursor(fr, x-fr->x, y-fr->y, &e->cpos); - e->sel_active = !positions_equal(e->sel_start, e->sel_end); - sc_editor_redraw(e); - break; - - } - - gdk_event_request_motions(event); - return FALSE; -} - - -static struct frame *create_frame(SCEditor *e, double x, double y, - double w, double h) -{ - struct frame *parent; - struct frame *fr; - SCBlock *scblocks; - - parent = e->top; - - if ( w < 0.0 ) { - x += w; - w = -w; - } - - if ( h < 0.0 ) { - y += h; - h = -h; - } - - /* Add to frame structure */ - fr = add_subframe(parent); - - /* Add to SC */ - scblocks = sc_block_append_end(sc_block_child(e->scblocks), "f", NULL, NULL); - fr->scblocks = scblocks; - sc_block_append_inside(scblocks, NULL, NULL, strdup("")); - - fr->x = x; - fr->y = y; - fr->w = w; - fr->h = h; - fr->is_image = 0; - fr->empty = 1; - fr->resizable = 1; - - update_geom(fr); - - full_rerender(e); - return find_frame_with_scblocks(e->top, scblocks); -} - - -static void do_resize(SCEditor *e, double x, double y, double w, double h) -{ - struct frame *fr; - - assert(e->selection != NULL); - - if ( w < 0.0 ) { - w = -w; - x -= w; - } - - if ( h < 0.0 ) { - h = -h; - y -= h; - } - - fr = e->selection; - fr->x = x; - fr->y = y; - fr->w = w; - fr->h = h; - update_geom(fr); - - full_rerender(e); - sc_editor_redraw(e); -} - - -static gboolean button_release_sig(GtkWidget *da, GdkEventButton *event, - SCEditor *e) -{ - gdouble x, y; - struct frame *fr; - - x = event->x - e->border_offs_x; - y = event->y - e->border_offs_y; - x /= e->view_scale; - y /= e->view_scale; - - /* Not dragging? Then I don't care. */ - if ( e->drag_status != DRAG_STATUS_DRAGGING ) return FALSE; - - e->drag_corner_x = x; - e->drag_corner_y = y; - e->drag_status = DRAG_STATUS_NONE; - - switch ( e->drag_reason ) - { - - case DRAG_REASON_NONE : - printf("Release on pointless drag.\n"); - break; - - case DRAG_REASON_CREATE : - fr = create_frame(e, e->start_corner_x, e->start_corner_y, - e->drag_corner_x - e->start_corner_x, - e->drag_corner_y - e->start_corner_y); - if ( fr != NULL ) { - check_paragraph(fr, e->pc, sc_block_child(fr->scblocks)); - e->selection = fr; - e->cursor_frame = fr; - e->cpos.para = 0; - e->cpos.pos = 0; - e->cpos.trail = 0; - } else { - fprintf(stderr, _("Failed to create frame!\n")); - } - break; - - case DRAG_REASON_IMPORT : - /* Do nothing, handled in dnd_drop() or dnd_leave() */ - break; - - case DRAG_REASON_RESIZE : - do_resize(e, e->box_x, e->box_y, e->box_width, e->box_height); - break; - - case DRAG_REASON_MOVE : - do_resize(e, e->box_x, e->box_y, e->box_width, e->box_height); - break; - - case DRAG_REASON_TEXTSEL : - /* Do nothing (text is already selected) */ - break; - - } - - e->drag_reason = DRAG_REASON_NONE; - - gtk_widget_grab_focus(GTK_WIDGET(da)); - sc_editor_redraw(e); - return FALSE; -} - - -static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event, - SCEditor *e) -{ - gboolean r; - int claim = 0; - - /* Throw the event to the IM context and let it sort things out */ - r = gtk_im_context_filter_keypress(GTK_IM_CONTEXT(e->im_context), - event); - if ( r ) return FALSE; /* IM ate it */ - - switch ( event->keyval ) { - - case GDK_KEY_Escape : - if ( !e->para_highlight ) { - sc_editor_remove_cursor(e); - sc_editor_redraw(e); - claim = 1; - } - break; - - case GDK_KEY_Left : - if ( e->selection != NULL ) { - cursor_moveh(e->cursor_frame, &e->cpos, -1); - sc_editor_redraw(e); - } - claim = 1; - break; - - case GDK_KEY_Right : - if ( e->selection != NULL ) { - cursor_moveh(e->cursor_frame, &e->cpos, +1); - sc_editor_redraw(e); - } - claim = 1; - break; - - case GDK_KEY_Up : - if ( e->selection != NULL ) { - cursor_moveh(e->cursor_frame, &e->cpos, -1); - sc_editor_redraw(e); - } - claim = 1; - break; - - case GDK_KEY_Down : - if ( e->selection != NULL ) { - cursor_moveh(e->cursor_frame, &e->cpos, +1); - sc_editor_redraw(e); - } - claim = 1; - break; + case GDK_KEY_Down : + //cursor_moveh(e->cursor_frame, &e->cpos, +1); + redraw(e); + claim = 1; + break; case GDK_KEY_Return : @@ -1681,38 +998,8 @@ static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event, break; case GDK_KEY_BackSpace : - if ( e->selection != NULL ) { - do_backspace(e->selection, e); - claim = 1; - } - break; - - case GDK_KEY_F5 : - full_rerender(e); - break; - - case GDK_KEY_F6 : - show_edit_pos(e->cpos); - break; - - case GDK_KEY_F7 : - if ( e->cursor_frame != NULL ) { - if ( event->state & GDK_CONTROL_MASK ) { - debug_paragraphs(e); - } else if ( event->state & GDK_SHIFT_MASK ) { - printf("Cursor frame block = %p\n", e->cursor_frame->scblocks); - printf("Editor top block = %p\n", e->scblocks); - show_sc_block(e->cursor_frame->scblocks, ""); - } else { - open_debugger(e->cursor_frame); - } - } else { - if ( event->state & GDK_SHIFT_MASK ) { - printf("Debugging the top frame:\n"); - printf("Editor top block = %p\n", e->scblocks); - show_sc_block(e->top->scblocks, ""); - } - } + //do_backspace(e->selection, e); + claim = 1; break; case GDK_KEY_C : @@ -1738,7 +1025,7 @@ static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event, static gboolean dnd_motion(GtkWidget *widget, GdkDragContext *drag_context, - gint x, gint y, guint time, SCEditor *e) + gint x, gint y, guint time, GtkNarrativeView *e) { GdkAtom target; @@ -1765,7 +1052,7 @@ static gboolean dnd_motion(GtkWidget *widget, GdkDragContext *drag_context, e->drag_corner_x = x + e->import_width/2.0; e->drag_corner_y = y + e->import_height/2.0; - sc_editor_redraw(e); + redraw(e); } @@ -1774,7 +1061,7 @@ static gboolean dnd_motion(GtkWidget *widget, GdkDragContext *drag_context, static gboolean dnd_drop(GtkWidget *widget, GdkDragContext *drag_context, - gint x, gint y, guint time, SCEditor *e) + gint x, gint y, guint time, GtkNarrativeView *e) { GdkAtom target; @@ -1791,7 +1078,7 @@ static gboolean dnd_drop(GtkWidget *widget, GdkDragContext *drag_context, /* Scale the image down if it's a silly size */ -static void check_import_size(SCEditor *e) +static void check_import_size(GtkNarrativeView *e) { if ( e->import_width > e->w ) { @@ -1819,141 +1106,25 @@ static void check_import_size(SCEditor *e) static void dnd_receive(GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *seldata, - guint info, guint time, SCEditor *e) + guint info, guint time, GtkNarrativeView *e) { - if ( e->drag_preview_pending ) { - - gchar *filename = NULL; - GdkPixbufFormat *f; - gchar **uris; - int w, h; - - e->have_drag_data = 1; - e->drag_preview_pending = 0; - uris = gtk_selection_data_get_uris(seldata); - if ( uris != NULL ) { - filename = g_filename_from_uri(uris[0], NULL, NULL); - } - g_strfreev(uris); - - if ( filename == NULL ) { - - /* This doesn't even look like a sensible URI. - * Bail out. */ - gdk_drag_status(drag_context, 0, time); - if ( e->drag_highlight ) { - gtk_drag_unhighlight(widget); - e->drag_highlight = 0; - } - e->import_acceptable = 0; - return; - - } - chomp(filename); - - f = gdk_pixbuf_get_file_info(filename, &w, &h); - g_free(filename); - - e->import_width = w; - e->import_height = h; - - if ( f == NULL ) { - - gdk_drag_status(drag_context, 0, time); - if ( e->drag_highlight ) { - gtk_drag_unhighlight(widget); - e->drag_highlight = 0; - } - e->drag_status = DRAG_STATUS_NONE; - e->drag_reason = DRAG_REASON_NONE; - e->import_acceptable = 0; - - } else { - - /* Looks like a sensible image */ - gdk_drag_status(drag_context, GDK_ACTION_PRIVATE, time); - e->import_acceptable = 1; - - if ( !e->drag_highlight ) { - gtk_drag_highlight(widget); - e->drag_highlight = 1; - } - - check_import_size(e); - e->drag_reason = DRAG_REASON_IMPORT; - e->drag_status = DRAG_STATUS_DRAGGING; - - } - - } else { - - gchar **uris; - char *filename = NULL; - - uris = gtk_selection_data_get_uris(seldata); - if ( uris != NULL ) { - filename = g_filename_from_uri(uris[0], NULL, NULL); - } - g_strfreev(uris); - - if ( filename != NULL ) { - - struct frame *fr; - char *opts; - size_t len; - int w, h; - - gtk_drag_finish(drag_context, TRUE, FALSE, time); - chomp(filename); - - w = e->drag_corner_x - e->start_corner_x; - h = e->drag_corner_y - e->start_corner_y; - - len = strlen(filename)+64; - opts = malloc(len); - if ( opts == NULL ) { - free(filename); - fprintf(stderr, "Failed to allocate SC\n"); - return; - } - snprintf(opts, len, "1fx1f+0+0,filename=\"%s\"", - filename); - - fr = create_frame(e, e->start_corner_x, - e->start_corner_y, w, h); - fr->is_image = 1; - fr->empty = 0; - sc_block_set_name(sc_block_child(fr->scblocks), strdup("image")); - sc_block_set_options(sc_block_child(fr->scblocks), opts); - full_rerender(e); - sc_editor_remove_cursor(e); - sc_editor_redraw(e); - free(filename); - - } else { - - gtk_drag_finish(drag_context, FALSE, FALSE, time); - - } - - } } static void dnd_leave(GtkWidget *widget, GdkDragContext *drag_context, - guint time, SCEditor *sceditor) + guint time, GtkNarrativeView *nview) { - if ( sceditor->drag_highlight ) { + if ( nview->drag_highlight ) { gtk_drag_unhighlight(widget); } - sceditor->have_drag_data = 0; - sceditor->drag_highlight = 0; - sceditor->drag_status = DRAG_STATUS_NONE; - sceditor->drag_reason = DRAG_REASON_NONE; + nview->have_drag_data = 0; + nview->drag_highlight = 0; + nview->drag_status = DRAG_STATUS_NONE; + nview->drag_reason = DRAG_REASON_NONE; } -static gint realise_sig(GtkWidget *da, SCEditor *e) +static gint realise_sig(GtkWidget *da, GtkNarrativeView *e) { GdkWindow *win; @@ -1972,226 +1143,78 @@ static gint realise_sig(GtkWidget *da, SCEditor *e) } -void sc_editor_set_scblock(SCEditor *e, SCBlock *scblocks) -{ - e->scblocks = scblocks; - full_rerender(e); -} - - -static void update_size_request(SCEditor *e) +static void update_size_request(GtkNarrativeView *e) { gtk_widget_set_size_request(GTK_WIDGET(e), 0, e->h + 2.0*e->min_border); } -void sc_editor_set_logical_size(SCEditor *e, double w, double h) -{ - e->log_w = w; - e->log_h = h; - if ( gtk_widget_get_mapped(GTK_WIDGET(e)) ) { - full_rerender(e); - sc_editor_redraw(e); - } -} - - -void sc_editor_set_slidenum(SCEditor *e, int slidenum) -{ - e->slidenum = slidenum; -} - - -void sc_editor_set_min_border(SCEditor *e, double min_border) -{ - e->min_border = min_border; - update_size_request(e); -} - - -void sc_editor_set_top_frame_editable(SCEditor *e, int top_frame_editable) -{ - e->top_editable = top_frame_editable; -} - - -void sc_editor_set_stylesheet(SCEditor *e, Stylesheet *stylesheet) -{ - e->stylesheet = stylesheet; -} - - -void sc_editor_set_callbacks(SCEditor *e, SCCallbackList *cbl) -{ - if ( e->cbl != NULL ) sc_callback_list_free(e->cbl); - e->cbl = cbl; -} - - -void sc_editor_set_para_highlight(SCEditor *e, int para_highlight) -{ - e->para_highlight = para_highlight; - sc_editor_redraw(e); -} - -int sc_editor_get_cursor_para(SCEditor *e) -{ - if ( e->cursor_frame == NULL ) return 0; - return e->cpos.para; -} - - -void *sc_editor_get_cursor_bvp(SCEditor *e) -{ - Paragraph *para; - if ( e->cursor_frame == NULL ) return 0; - para = e->cursor_frame->paras[e->cpos.para]; - return get_para_bvp(para); -} - - -void sc_editor_set_cursor_para(SCEditor *e, signed int pos) -{ - double h; - int i; - - if ( e->cursor_frame == NULL ) { - e->cursor_frame = e->top; - e->selection = e->top; - } - - if ( pos < 0 ) { - e->cpos.para = e->cursor_frame->n_paras - 1; - } else if ( pos >= e->cursor_frame->n_paras ) { - e->cpos.para = e->cursor_frame->n_paras - 1; - } else { - e->cpos.para = pos; - } - e->cpos.pos = 0; - e->cpos.trail = 0; - - h = 0; - for ( i=0; icpos.para; i++ ) { - h += paragraph_height(e->cursor_frame->paras[i]); - } - h += (paragraph_height(e->cursor_frame->paras[e->cpos.para]))/2; - e->scroll_pos = h - (e->visible_height/2); - set_vertical_params(e); - - sc_editor_redraw(e); -} - - -int sc_editor_get_num_paras(SCEditor *e) -{ - if ( e->cursor_frame == NULL ) return 1; - return e->cursor_frame->n_paras; -} - - -void sc_editor_set_scale(SCEditor *e, int scale) -{ - e->scale = scale; - if ( !scale ) { - e->view_scale = 1.0; - } -} - - -void sc_editor_set_imagestore(SCEditor *e, ImageStore *is) +GtkNarrativeView *gtk_narrative_view_new(Presentation *p, PangoLanguage *lang, + const char *storename) { - if ( e->is != NULL ) { - fprintf(stderr, "WARNING: Changing imagestore\n"); - } - e->is = is; -} - - -SCEditor *sc_editor_new(SCBlock *scblocks, Stylesheet *stylesheet, - PangoLanguage *lang, const char *storename) -{ - SCEditor *sceditor; + GtkNarrativeView *nview; GtkTargetEntry targets[1]; - GError *err; - - sceditor = g_object_new(SC_TYPE_EDITOR, NULL); - - sceditor->scblocks = scblocks; - sceditor->w = 100; - sceditor->h = 100; - sceditor->log_w = 100; - sceditor->log_h = 100; - sceditor->border_offs_x = 0; - sceditor->border_offs_y = 0; - sceditor->is = NULL; - sceditor->slidenum = 0; - sceditor->min_border = 0.0; - sceditor->top_editable = 0; - sceditor->cbl = NULL; - sceditor->scroll_pos = 0; - sceditor->flow = 0; - sceditor->scale = 0; - sceditor->view_scale = 1.0; - sceditor->lang = lang; - - sceditor->para_highlight = 0; - sc_editor_remove_cursor(sceditor); - - sceditor->stylesheet = stylesheet; - - err = NULL; - sceditor->bg_pixbuf = gdk_pixbuf_new_from_resource("/uk/me/bitwiz/Colloquium/sky.png", - &err); - if ( sceditor->bg_pixbuf == NULL ) { - fprintf(stderr, _("Failed to load background: %s\n"), - err->message); - } - gtk_widget_set_size_request(GTK_WIDGET(sceditor), - sceditor->w, sceditor->h); - - g_signal_connect(G_OBJECT(sceditor), "destroy", - G_CALLBACK(destroy_sig), sceditor); - g_signal_connect(G_OBJECT(sceditor), "realize", - G_CALLBACK(realise_sig), sceditor); - g_signal_connect(G_OBJECT(sceditor), "button-press-event", - G_CALLBACK(button_press_sig), sceditor); - g_signal_connect(G_OBJECT(sceditor), "button-release-event", - G_CALLBACK(button_release_sig), sceditor); - g_signal_connect(G_OBJECT(sceditor), "motion-notify-event", - G_CALLBACK(motion_sig), sceditor); - g_signal_connect(G_OBJECT(sceditor), "configure-event", - G_CALLBACK(resize_sig), sceditor); + nview = g_object_new(GTK_TYPE_NARRATIVE_VIEW, NULL); + + nview->w = 100; + nview->h = 100; + nview->log_w = 100; + nview->log_h = 100; + nview->border_offs_x = 0; + nview->border_offs_y = 0; + nview->min_border = 0.0; + nview->scroll_pos = 0; + nview->flow = 0; + nview->scale = 0; + nview->view_scale = 1.0; + nview->lang = lang; + + nview->para_highlight = 0; + + gtk_widget_set_size_request(GTK_WIDGET(nview), + nview->w, nview->h); + + g_signal_connect(G_OBJECT(nview), "destroy", + G_CALLBACK(destroy_sig), nview); + g_signal_connect(G_OBJECT(nview), "realize", + G_CALLBACK(realise_sig), nview); + g_signal_connect(G_OBJECT(nview), "button-press-event", + G_CALLBACK(button_press_sig), nview); + g_signal_connect(G_OBJECT(nview), "motion-notify-event", + G_CALLBACK(motion_sig), nview); + g_signal_connect(G_OBJECT(nview), "configure-event", + G_CALLBACK(resize_sig), nview); /* Drag and drop */ targets[0].target = "text/uri-list"; targets[0].flags = 0; targets[0].info = 1; - gtk_drag_dest_set(GTK_WIDGET(sceditor), 0, targets, 1, + gtk_drag_dest_set(GTK_WIDGET(nview), 0, targets, 1, GDK_ACTION_PRIVATE); - g_signal_connect(sceditor, "drag-data-received", - G_CALLBACK(dnd_receive), sceditor); - g_signal_connect(sceditor, "drag-motion", - G_CALLBACK(dnd_motion), sceditor); - g_signal_connect(sceditor, "drag-drop", - G_CALLBACK(dnd_drop), sceditor); - g_signal_connect(sceditor, "drag-leave", - G_CALLBACK(dnd_leave), sceditor); - - gtk_widget_set_can_focus(GTK_WIDGET(sceditor), TRUE); - gtk_widget_add_events(GTK_WIDGET(sceditor), + g_signal_connect(nview, "drag-data-received", + G_CALLBACK(dnd_receive), nview); + g_signal_connect(nview, "drag-motion", + G_CALLBACK(dnd_motion), nview); + g_signal_connect(nview, "drag-drop", + G_CALLBACK(dnd_drop), nview); + g_signal_connect(nview, "drag-leave", + G_CALLBACK(dnd_leave), nview); + + gtk_widget_set_can_focus(GTK_WIDGET(nview), TRUE); + gtk_widget_add_events(GTK_WIDGET(nview), GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_SCROLL_MASK); - g_signal_connect(G_OBJECT(sceditor), "draw", - G_CALLBACK(draw_sig), sceditor); + g_signal_connect(G_OBJECT(nview), "draw", + G_CALLBACK(draw_sig), nview); - gtk_widget_grab_focus(GTK_WIDGET(sceditor)); + gtk_widget_grab_focus(GTK_WIDGET(nview)); - gtk_widget_show(GTK_WIDGET(sceditor)); + gtk_widget_show(GTK_WIDGET(nview)); - return sceditor; + return nview; } diff --git a/libstorycode/gtk/gtknarrativeview.h b/libstorycode/gtk/gtknarrativeview.h index d3c111b..ba007e5 100644 --- a/libstorycode/gtk/gtknarrativeview.h +++ b/libstorycode/gtk/gtknarrativeview.h @@ -1,7 +1,7 @@ /* - * sc_editor.h + * gtknarrativeview.h * - * Copyright © 2014-2018 Thomas White + * Copyright © 2014-2019 Thomas White * * This file is part of Colloquium. * @@ -20,8 +20,8 @@ * */ -#ifndef SC_EDITOR_H -#define SC_EDITOR_H +#ifndef GTK_NARRATIVE_VIEW_H +#define GTK_NARRATIVE_VIEW_H #ifdef HAVE_CONFIG_H #include @@ -30,37 +30,31 @@ #include #include -#include "frame.h" -#include "sc_interp.h" -#include "stylesheet.h" +#include +#include +#include -struct presentation; +#define GTK_TYPE_NARRATIVE_VIEW (gtk_narrative_view_get_type()) +#define GTK_NARRATIVE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GTK_TYPE_NARRATIVE_VIEW, GtkNarrativeView)) -#define SC_TYPE_EDITOR (sc_editor_get_type()) +#define GTK_IS_NARRATIVE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \ + GTK_TYPE_NARRATIVE_VIEW)) -#define SC_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ - SC_TYPE_EDITOR, SCEditor)) +#define GTK_NARRATIVE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((obj), \ + GTK_TYPE_NARRATIVE_VIEW, GtkNarrativeViewClass)) -#define SC_IS_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \ - SC_TYPE_EDITOR)) +#define GTK_IS_NARRATIVE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((obj), \ + GTK_TYPE_NARRATIVE_VIEW)) -#define SC_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((obj), \ - SC_TYPE_EDITOR, SCEditorClass)) - -#define SC_IS_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((obj), \ - SC_TYPE_EDITOR)) - -#define SC_EDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ - SC_TYPE_EDITOR, SCEditorClass)) +#define GTK_NARRATIVE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GTK_TYPE_NARRATIVE_VIEW, GtkNarrativeViewClass)) enum drag_reason { DRAG_REASON_NONE, - DRAG_REASON_CREATE, DRAG_REASON_IMPORT, - DRAG_REASON_RESIZE, - DRAG_REASON_MOVE, DRAG_REASON_TEXTSEL }; @@ -83,22 +77,28 @@ enum drag_status }; -struct _sceditor +struct edit_pos +{ + int para; /* Paragraph number */ + size_t pos; /* Byte position within paragraph + * Yes, really. See pango_layout_xy_to_index */ + int trail; +}; + + +struct _gtknarrativeview { GtkDrawingArea parent_instance; - PangoLanguage *lang; /*< private >*/ GtkIMContext *im_context; + PangoContext *pc; + PangoLanguage *lang; + int w; /* Surface size in pixels */ int h; double log_w; /* Size of surface in "SC units" */ double log_h; - SCBlock *scblocks; - Stylesheet *stylesheet; - ImageStore *is; - SCCallbackList *cbl; - struct frame *top; int para_highlight; /* Redraw/scroll stuff */ @@ -111,17 +111,10 @@ struct _sceditor int visible_height; int visible_width; int flow; - int scale; /* Whether the SCEditor should scale to fit */ + int scale; /* Whether the GtkNarrativeView should scale to fit */ double view_scale; /* The scale factor, if scale=1 */ - /* Pointers to the frame currently being edited */ - struct frame *selection; - int top_editable; - - PangoContext *pc; - /* Location of the cursor */ - struct frame *cursor_frame; struct edit_pos cpos; /* Border surrounding actual slide within drawingarea */ @@ -155,45 +148,26 @@ struct _sceditor double import_width; double import_height; int import_acceptable; - - /* Stuff that doesn't really belong here */ - int slidenum; }; -struct _sceditorclass +struct _gtknarrativeviewclass { GtkDrawingAreaClass parent_class; }; -typedef struct _sceditor SCEditor; -typedef struct _sceditorclass SCEditorClass; - -extern void sc_editor_set_scblock(SCEditor *e, SCBlock *scblocks); -extern void sc_editor_set_stylesheet(SCEditor *e, Stylesheet *stylesheet); -extern SCEditor *sc_editor_new(SCBlock *scblocks, Stylesheet *stylesheet, - PangoLanguage *lang, const char *storename); -extern void sc_editor_set_logical_size(SCEditor *e, double w, double h); -extern void sc_editor_set_flow(SCEditor *e, int flow); -extern void sc_editor_set_scale(SCEditor *e, int scale); -extern void sc_editor_redraw(SCEditor *e); -extern void sc_editor_set_background(SCEditor *e, double r, double g, double b); -extern void sc_editor_set_slidenum(SCEditor *e, int slidenum); -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 sc_editor_paste(SCEditor *e); -extern void sc_editor_add_storycode(SCEditor *e, const char *sc); -extern void sc_editor_copy_selected_frame(SCEditor *e); -extern void sc_editor_delete_selected_frame(SCEditor *e); -extern void sc_editor_ensure_cursor(SCEditor *e); -extern SCBlock *split_paragraph_at_cursor(SCEditor *e); - -extern void sc_editor_set_imagestore(SCEditor *e, ImageStore *is); -extern void sc_editor_set_para_highlight(SCEditor *e, int para_highlight); -extern int sc_editor_get_cursor_para(SCEditor *e); -extern void *sc_editor_get_cursor_bvp(SCEditor *e); -extern void sc_editor_set_cursor_para(SCEditor *e, signed int pos); -extern int sc_editor_get_num_paras(SCEditor *e); - -#endif /* SC_EDITOR_H */ +typedef struct _gtknarrativeview GtkNarrativeView; +typedef struct _gtknarrativeviewclass GtkNarrativeViewClass; + +extern GtkNarrativeView *gtk_narrative_view_new(Presentation *p, + PangoLanguage *lang, + const char *storename); + +extern void gtk_narrative_view_set_logical_size(GtkNarrativeView *e, double w, double h); + +extern void gtk_narrative_view_paste(GtkNarrativeView *e); + +extern void gtk_narrative_view_set_para_highlight(GtkNarrativeView *e, int para_highlight); +extern int gtk_narrative_view_get_cursor_para(GtkNarrativeView *e); +extern void gtk_narrative_view_set_cursor_para(GtkNarrativeView *e, signed int pos); + +#endif /* GTK_NARRATIVE_VIEW_H */ diff --git a/meson.build b/meson.build index a7d517e..6badf9d 100644 --- a/meson.build +++ b/meson.build @@ -83,19 +83,16 @@ libstorycode_dep = declare_dependency(include_directories : libstorycode_include # libstorycode-gtk -#libstorycode_gtk_includes = include_directories('libstorycode/gtk') -# -#libstorycode_gtk = library('storycode-gtk', -# ['libstorycode/gtk/gtknarrativeview.c', -# 'libstorycode/gtk/gtkslideview.c', -# ], -# include_directories : libstorycode_gtk_includes, -# dependencies : [gtk_dep, libstorycode_dep, -# libstorycode_cairo_dep], -# install : true) -# -#libstorycode_gtk_dep = declare_dependency(include_directories : libstorycode_gtk_includes, -# link_with : libstorycode_gtk) +libgtkstorycode_includes = include_directories('libstorycode/gtk') + +libgtkstorycode = library('storycode-gtk', + ['libstorycode/gtk/gtknarrativeview.c'], + include_directories : libgtkstorycode_includes, + dependencies : [gtk_dep, libstorycode_dep], + install : true) + +libgtkstorycode_dep = declare_dependency(include_directories : libgtkstorycode_includes, + link_with : libgtkstorycode) # pdfstorycode @@ -118,7 +115,7 @@ executable('colloquium', # 'src/stylesheet_editor.c', ], gresources, - dependencies : [gtk_dep, mdep, libstorycode_dep], + dependencies : [gtk_dep, mdep, libstorycode_dep, libgtkstorycode_dep], install : true) diff --git a/src/narrative_window.c b/src/narrative_window.c index f864fa2..45f20c5 100644 --- a/src/narrative_window.c +++ b/src/narrative_window.c @@ -34,6 +34,7 @@ #define _(x) gettext(x) #include +#include #include "colloquium.h" #include "narrative_window.h" @@ -41,7 +42,6 @@ //#include "pr_clock.h" //#include "print.h" //#include "stylesheet_editor.h" -typedef struct _nw GtkNarrativeView; /* FIXME placeholder */ typedef struct _ss SCSlideshow; /* FIXME placeholder */ typedef struct _sw SlideWindow; /* FIXME placeholder */ typedef struct _pc PRClock; /* FIXME placeholder */ @@ -681,11 +681,6 @@ NarrativeWindow *narrative_window_new(Presentation *p, GApplication *papp) GtkWidget *image; Colloquium *app = COLLOQUIUM(papp); -// if ( p->narrative_window != NULL ) { -// fprintf(stderr, "Narrative window is already open!\n"); -// return NULL; -// } - nw = calloc(1, sizeof(NarrativeWindow)); if ( nw == NULL ) return NULL; @@ -694,7 +689,6 @@ NarrativeWindow *narrative_window_new(Presentation *p, GApplication *papp) nw->n_slidewindows = 0; nw->window = gtk_application_window_new(GTK_APPLICATION(app)); -// p->narrative_window = nw; update_titlebar(nw); g_action_map_add_action_entries(G_ACTION_MAP(nw->window), nw_entries, @@ -703,7 +697,9 @@ NarrativeWindow *narrative_window_new(Presentation *p, GApplication *papp) vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_container_add(GTK_CONTAINER(nw->window), vbox); - nw->nv = NULL; //sc_editor_new(nw->dummy_top, p->stylesheet, p->lang, colloquium_get_imagestore(app)); + /* FIXME: Language should be a property of the presentation */ + nw->nv = gtk_narrative_view_new(p, pango_language_get_default(), + colloquium_get_imagestore(app)); toolbar = gtk_toolbar_new(); gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); -- cgit v1.2.3