aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@bitwiz.me.uk>2019-03-10 15:06:07 +0100
committerThomas White <taw@bitwiz.me.uk>2019-03-10 15:06:07 +0100
commit0e88cfed0e00a34436c4db3c9b2b8ad422c5a2df (patch)
tree9d221e5db2b6a123adf21271f61fe3d88d3871e2
parent528d0c29049546e130ab61dcc3f67d0ebc9a38cc (diff)
Implement selection
-rw-r--r--libstorycode/gtk/gtknarrativeview.c97
-rw-r--r--libstorycode/gtk/gtknarrativeview.h10
-rw-r--r--libstorycode/narrative_render_cairo.c109
-rw-r--r--libstorycode/narrative_render_cairo.h13
4 files changed, 170 insertions, 59 deletions
diff --git a/libstorycode/gtk/gtknarrativeview.c b/libstorycode/gtk/gtknarrativeview.c
index bf0d22c..211da32 100644
--- a/libstorycode/gtk/gtknarrativeview.c
+++ b/libstorycode/gtk/gtknarrativeview.c
@@ -139,7 +139,7 @@ static void rewrap_range(GtkNarrativeView *e, int min, int max)
presentation_get_stylesheet(e->p),
lang, pc, e->w,
presentation_get_imagestore(e->p),
- min, max);
+ min, max, e->sel_start, e->sel_end);
}
@@ -722,6 +722,35 @@ static void cursor_moveh(Narrative *n, struct edit_pos *cp, signed int dir)
}
+static void unset_selection(GtkNarrativeView *e)
+{
+ int a, b;
+
+ 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_start.para = 0;
+ e->sel_start.pos = 0;
+ e->sel_start.trail = 0;
+ e->sel_end.para = 0;
+ e->sel_end.pos = 0;
+ e->sel_end.trail = 0;
+ rewrap_range(e, a, b);
+}
+
+
+static int positions_equal(struct edit_pos a, struct edit_pos b)
+{
+ if ( a.para != b.para ) return 0;
+ if ( a.pos != b.pos ) return 0;
+ if ( a.trail != b.trail ) return 0;
+ return 1;
+}
+
+
static void do_backspace(GtkNarrativeView *e, signed int dir)
{
Narrative *n;
@@ -730,7 +759,7 @@ static void do_backspace(GtkNarrativeView *e, signed int dir)
n = presentation_get_narrative(e->p);
- if ( e->sel_active ) {
+ if ( !positions_equal(e->sel_start, e->sel_end) ) {
/* Block delete */
p1 = e->sel_start;
@@ -749,13 +778,13 @@ static void do_backspace(GtkNarrativeView *e, signed int dir)
o2 = pos_trail_to_offset(&n->items[p2.para], p2.pos, p2.trail);
narrative_delete_block(n, p1.para, o1, p2.para, o2);
e->cpos = p1;
- e->sel_active = 0;
/* The only paragraphs which still exist and might have been
* affected by the deletion are sel_start.para and the one
* immediately afterwards. */
rewrap_range(e, p1.para, p1.para+1);
update_size(e);
+ unset_selection(e);
emit_change_sig(e);
redraw(e);
}
@@ -780,7 +809,7 @@ static void insert_text(char *t, GtkNarrativeView *e)
Narrative *n;
struct narrative_item *item;
- if ( e->sel_active ) {
+ if ( !positions_equal(e->sel_start, e->sel_end) ) {
do_backspace(e, 0);
}
@@ -826,22 +855,6 @@ static gboolean im_commit_sig(GtkIMContext *im, gchar *str,
}
-static void unset_selection(GtkNarrativeView *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;
-}
-
-
static int find_cursor(Narrative *n, double x, double y, struct edit_pos *pos)
{
double cur_y;
@@ -891,21 +904,47 @@ static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event,
}
+static void sorti(int *a, int *b)
+{
+ if ( *a > *b ) {
+ int tmp = *a;
+ *a = *b;
+ *b = tmp;
+ }
+}
+
+
static gboolean motion_sig(GtkWidget *da, GdkEventMotion *event,
GtkNarrativeView *e)
{
+ Narrative *n;
+ gdouble x, y;
+ struct edit_pos old_sel_end;
+ int minp, maxp;
+
+ x = event->x;
+ y = event->y + e->scroll_pos;
+
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;
}
- //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);
+ old_sel_end = e->sel_end;
+ n = presentation_get_narrative(e->p);
+ find_cursor(n, x, y, &e->sel_end);
+
+ minp = e->sel_start.para;
+ maxp = e->sel_end.para;
+ sorti(&minp, &maxp);
+ if ( !positions_equal(e->sel_start, old_sel_end) ) {
+ if ( old_sel_end.para > maxp ) maxp = old_sel_end.para;
+ if ( old_sel_end.para < minp ) minp = old_sel_end.para;
+ }
+
+ rewrap_range(e, minp, maxp);
+ find_cursor(n, x, y, &e->cpos);
redraw(e);
gdk_event_request_motions(event);
@@ -1044,12 +1083,6 @@ static gint realise_sig(GtkWidget *da, GtkNarrativeView *e)
}
-static void update_size_request(GtkNarrativeView *e)
-{
- gtk_widget_set_size_request(GTK_WIDGET(e), 0, e->h);
-}
-
-
GtkNarrativeView *gtk_narrative_view_new(Presentation *p)
{
GtkNarrativeView *nview;
diff --git a/libstorycode/gtk/gtknarrativeview.h b/libstorycode/gtk/gtknarrativeview.h
index 13400db..942044e 100644
--- a/libstorycode/gtk/gtknarrativeview.h
+++ b/libstorycode/gtk/gtknarrativeview.h
@@ -34,6 +34,7 @@
#include <narrative.h>
#include <presentation.h>
#include <imagestore.h>
+#include <narrative_render_cairo.h>
#define GTK_TYPE_NARRATIVE_VIEW (gtk_narrative_view_get_type())
@@ -70,14 +71,6 @@ enum drag_status
};
-struct edit_pos
-{
- int para; /* Paragraph number (corresponding to narrative items) */
- int pos; /* Byte position within paragraph (yes, really) */
- int trail; /* 1 = end of character, 0 = before */
-};
-
-
struct _gtknarrativeview
{
GtkDrawingArea parent_instance;
@@ -105,7 +98,6 @@ struct _gtknarrativeview
/* Rubber band boxes and related stuff */
enum drag_status drag_status;
- int sel_active;
struct edit_pos sel_start; /* Where the user dragged from */
struct edit_pos sel_end;
};
diff --git a/libstorycode/narrative_render_cairo.c b/libstorycode/narrative_render_cairo.c
index 6293c44..dc5fb2a 100644
--- a/libstorycode/narrative_render_cairo.c
+++ b/libstorycode/narrative_render_cairo.c
@@ -38,6 +38,7 @@
#include "stylesheet.h"
#include "imagestore.h"
#include "slide_render_cairo.h"
+#include "narrative_render_cairo.h"
#include "narrative_priv.h"
@@ -66,7 +67,8 @@ static PangoAlignment to_pangoalignment(enum alignment align)
static void wrap_text(struct narrative_item *item, PangoContext *pc,
- Stylesheet *ss, enum style_element el, double w)
+ Stylesheet *ss, enum style_element el, double w,
+ size_t sel_start, size_t sel_end)
{
PangoAlignment palignment;
PangoRectangle rect;
@@ -109,6 +111,15 @@ static void wrap_text(struct narrative_item *item, PangoContext *pc,
attr = pango_attr_foreground_new(r, g, b);
pango_attr_list_insert(attrs, attr);
+ /* Add attributes for selected text */
+ if ( sel_start > 0 || sel_end > 0 ) {
+ PangoAttribute *attr;
+ attr = pango_attr_background_new(42919, 58853, 65535);
+ attr->start_index = sel_start;
+ attr->end_index = sel_end;
+ pango_attr_list_insert(attrs, attr);
+ }
+
if ( item->layout == NULL ) {
item->layout = pango_layout_new(pc);
}
@@ -189,12 +200,59 @@ static void wrap_slide(struct narrative_item *item, Stylesheet *ss, ImageStore *
}
+static size_t pos_trail_to_offset(struct narrative_item *item, int offs, int trail)
+{
+ glong char_offs;
+ char *ptr;
+
+ if ( item->type == NARRATIVE_ITEM_SLIDE ) {
+ return offs;
+ }
+
+ char_offs = g_utf8_pointer_to_offset(item->text, item->text+offs);
+ char_offs += trail;
+ ptr = g_utf8_offset_to_pointer(item->text, char_offs);
+ return ptr - item->text;
+}
+
+
+static int positions_equal(struct edit_pos a, struct edit_pos b)
+{
+ if ( a.para != b.para ) return 0;
+ if ( a.pos != b.pos ) return 0;
+ if ( a.trail != b.trail ) return 0;
+ return 1;
+}
+
+
+static void sort_positions(struct edit_pos *a, struct edit_pos *b)
+{
+ if ( a->para > b->para ) {
+ size_t tpos;
+ int tpara, ttrail;
+ tpara = b->para; tpos = b->pos; ttrail = b->trail;
+ b->para = a->para; b->pos = a->pos; b->trail = a->trail;
+ a->para = tpara; a->pos = tpos; a->trail = ttrail;
+ }
+
+ if ( (a->para == b->para) && (a->pos > b->pos) )
+ {
+ size_t tpos = b->pos;
+ int ttrail = b->trail;
+ b->pos = a->pos; b->trail = a->trail;
+ a->pos = tpos; a->trail = ttrail;
+ }
+}
+
+
int narrative_wrap_range(Narrative *n, Stylesheet *stylesheet, PangoLanguage *lang,
PangoContext *pc, double w, ImageStore *is,
- int min, int max)
+ int min, int max,
+ struct edit_pos sel_start, struct edit_pos sel_end)
{
int i;
struct length pad[4];
+ int sel_s, sel_e;
if ( stylesheet_get_padding(stylesheet, STYEL_NARRATIVE, pad) ) return 1;
n->space_l = lcalc(pad[0], w);
@@ -205,23 +263,56 @@ int narrative_wrap_range(Narrative *n, Stylesheet *stylesheet, PangoLanguage *la
n->w = w;
w -= n->space_l + n->space_r;
+ sort_positions(&sel_start, &sel_end);
+
+ if ( !positions_equal(sel_start, sel_end) ) {
+ struct narrative_item *item;
+ item = &n->items[sel_start.para];
+ sel_s = pos_trail_to_offset(item, sel_start.pos, sel_start.trail);
+ item = &n->items[sel_end.para];
+ sel_e = pos_trail_to_offset(item, sel_end.pos, sel_end.trail);
+ } else {
+ sel_s = 0;
+ sel_e = 0;
+ }
+
for ( i=min; i<=max; i++ ) {
+ size_t srt, end;
+ if ( i >= sel_start.para && i <= sel_end.para ) {
+ 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;
+ }
+
switch ( n->items[i].type ) {
case NARRATIVE_ITEM_TEXT :
wrap_text(&n->items[i], pc, stylesheet,
- STYEL_NARRATIVE, w);
+ STYEL_NARRATIVE, w, srt, end);
break;
case NARRATIVE_ITEM_BP :
wrap_text(&n->items[i], pc, stylesheet,
- STYEL_NARRATIVE_BP, w);
+ STYEL_NARRATIVE_BP, w, srt, end);
break;
case NARRATIVE_ITEM_PRESTITLE :
wrap_text(&n->items[i], pc, stylesheet,
- STYEL_NARRATIVE_PRESTITLE, w);
+ STYEL_NARRATIVE_PRESTITLE, w, srt, end);
break;
case NARRATIVE_ITEM_SLIDE :
@@ -238,14 +329,6 @@ int narrative_wrap_range(Narrative *n, Stylesheet *stylesheet, PangoLanguage *la
}
-int narrative_wrap(Narrative *n, Stylesheet *stylesheet, PangoLanguage *lang,
- PangoContext *pc, double w, ImageStore *is)
-{
- return narrative_wrap_range(n, stylesheet, lang, pc, w, is,
- 0, n->n_items-1);
-}
-
-
double narrative_get_height(Narrative *n)
{
int i;
diff --git a/libstorycode/narrative_render_cairo.h b/libstorycode/narrative_render_cairo.h
index 93941df..690517d 100644
--- a/libstorycode/narrative_render_cairo.h
+++ b/libstorycode/narrative_render_cairo.h
@@ -30,14 +30,17 @@
#include "presentation.h"
#include "imagestore.h"
+struct edit_pos
+{
+ int para; /* Paragraph number (corresponding to narrative items) */
+ int pos; /* Byte position within paragraph (yes, really) */
+ int trail; /* 1 = end of character, 0 = before */
+};
extern int narrative_wrap_range(Narrative *n, Stylesheet *stylesheet,
PangoLanguage *lang, PangoContext *pc, double w,
- ImageStore *is, int min, int max);
-
-extern int narrative_wrap(Narrative *n, Stylesheet *stylesheet,
- PangoLanguage *lang, PangoContext *pc, double w,
- ImageStore *is);
+ ImageStore *is, int min, int max,
+ struct edit_pos sel_start, struct edit_pos sel_end);
extern double narrative_get_height(Narrative *n);