summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2019-08-25 09:30:35 +0300
committerdefanor <defanor@uberspace.net>2019-08-25 09:30:35 +0300
commit153125149d217d866d6347f76f65345db46257c2 (patch)
tree80e50043aa5a01093f5c8dab114a66b3afa6f825
parentf308e319f3170a2949624e211adf75002ee5d3f1 (diff)
downloadwwwlite-153125149d217d866d6347f76f65345db46257c2.zip
wwwlite-153125149d217d866d6347f76f65345db46257c2.tar.gz
wwwlite-153125149d217d866d6347f76f65345db46257c2.tar.bz2
Merge search and selection
This reduces code and state duplication, though it may be useful to refactor them further, possibly using a model similar to Emacs marks.
-rw-r--r--src/documentbox.c150
-rw-r--r--src/documentbox.h6
-rw-r--r--src/inlinebox.c36
-rw-r--r--src/inlinebox.h3
4 files changed, 96 insertions, 99 deletions
diff --git a/src/documentbox.c b/src/documentbox.c
index f8a8e2b..0f4d1df 100644
--- a/src/documentbox.c
+++ b/src/documentbox.c
@@ -187,58 +187,56 @@ static gint compare_positions(GtkAllocation *a1, guint i1,
}
}
-
+/* Updates InlineBox widgets to render selection appropriately. */
static void
selection_update (GtkWidget *widget, SelectionState *st)
{
- GtkAllocation alloc;
+ if (st->selection_start == NULL ||
+ st->selection_end == NULL ||
+ st->selection_prev == NULL) {
+ return;
+ }
+ GtkAllocation alloc, alloc_start, alloc_end, alloc_prev;
gtk_widget_get_allocation(widget, &alloc);
- if (widget_is_affected(&alloc, &st->selection_start->alloc,
- &st->selection_end->alloc) ||
- widget_is_affected(&alloc, &st->selection_start->alloc,
- &st->selection_prev->alloc) ||
- widget_is_affected(&alloc, &st->selection_end->alloc,
- &st->selection_prev->alloc)) {
+ gtk_widget_get_allocation(GTK_WIDGET(st->selection_start), &alloc_start);
+ gtk_widget_get_allocation(GTK_WIDGET(st->selection_end), &alloc_end);
+ gtk_widget_get_allocation(GTK_WIDGET(st->selection_prev), &alloc_prev);
+ if (widget_is_affected(&alloc, &alloc_start, &alloc_end) ||
+ widget_is_affected(&alloc, &alloc_start, &alloc_prev) ||
+ widget_is_affected(&alloc, &alloc_end, &alloc_prev)) {
if (IS_INLINE_BOX(widget)) {
InlineBox *ib = INLINE_BOX(widget);
ib->selection_end = 0;
ib->selection_start = 0;
- GList *ti;
- guint text_position = 0;
-
- for (ti = ib->children; ti; ti = ti->next) {
- if (IS_IB_TEXT(ti->data)) {
- IBText *ibt = IB_TEXT(ti->data);
- gint direction = compare_positions(&st->selection_start->alloc,
- st->selection_start_index,
- &st->selection_end->alloc,
- st->selection_end_index);
- if (direction == -1) {
- if (st->selection_start == ibt) {
- ib->selection_start = st->selection_start_index + text_position;
- st->selecting = TRUE;
- }
- if (st->selecting && st->selection_end == ibt) {
- ib->selection_end = st->selection_end_index + text_position;
- st->selecting = FALSE;
- }
- } else if (direction == 1) {
- if (st->selection_end == ibt) {
- ib->selection_start = st->selection_end_index + text_position;
- st->selecting = TRUE;
- }
- if (st->selecting && st->selection_start == ibt) {
- ib->selection_end = st->selection_start_index + text_position;
- st->selecting = FALSE;
- }
- }
- text_position += strlen(pango_layout_get_text(ibt->layout));
- gtk_widget_queue_draw (widget);
+ gint direction = compare_positions(&alloc_start,
+ st->selection_start_index,
+ &alloc_end,
+ st->selection_end_index);
+ if (direction == -1) {
+ if (st->selection_start == ib) {
+ ib->selection_start = st->selection_start_index;
+ st->selecting = TRUE;
+ }
+ if (st->selecting && st->selection_end == ib) {
+ ib->selection_end = st->selection_end_index;
+ st->selecting = FALSE;
+ }
+ } else if (direction == 1) {
+ if (st->selection_end == ib) {
+ ib->selection_start = st->selection_end_index;
+ st->selecting = TRUE;
+ }
+ if (st->selecting && st->selection_start == ib) {
+ ib->selection_end = st->selection_start_index;
+ st->selecting = FALSE;
}
}
+
if (st->selecting) {
- ib->selection_end = text_position;
+ ib->selection_end = inline_box_get_text_length(ib);
}
+
+ gtk_widget_queue_draw (widget);
} else if (GTK_IS_CONTAINER(widget)) {
gtk_container_foreach(GTK_CONTAINER(widget),
(GtkCallback)selection_update, st);
@@ -352,12 +350,12 @@ button_press_event_cb (GtkWidget *widget,
selection_update(widget, &db->sel);
}
- if (ss.ibt) {
+ if (ss.ib) {
db->sel.selection_active = TRUE;
- db->sel.selection_start = ss.ibt;
- db->sel.selection_start_index = ss.index;
- db->sel.selection_end = ss.ibt;
- db->sel.selection_end_index = ss.index;
+ db->sel.selection_start = ss.ib;
+ db->sel.selection_start_index = ss.ib_index;
+ db->sel.selection_end = ss.ib;
+ db->sel.selection_end_index = ss.ib_index;
/* todo: grab focus when any non-widget space is clicked, not
just texts */
gtk_widget_grab_focus(GTK_WIDGET(db));
@@ -380,11 +378,11 @@ motion_notify_event_cb (GtkWidget *widget,
ss.x = ev_orig_x - orig_x + event->x;
ss.y = ev_orig_y - orig_y + event->y;
text_at_position(widget, &ss);
- if (ss.ibt && db->sel.selection_active) {
+ if (ss.ib && db->sel.selection_active) {
db->sel.selection_prev = db->sel.selection_end;
db->sel.selection_prev_index = db->sel.selection_end_index;
- db->sel.selection_end = ss.ibt;
- db->sel.selection_end_index = ss.index;
+ db->sel.selection_end = ss.ib;
+ db->sel.selection_end_index = ss.ib_index;
db->sel.selecting = FALSE;
selection_update(widget, &db->sel);
}
@@ -495,51 +493,61 @@ DocumentBox *document_box_new ()
}
static void
-document_box_search (GtkWidget *widget, TextSearchState *tss) {
+document_box_search (GtkWidget *widget, DocumentBox *db) {
/* todo: backwards search */
- if (tss->state == FOUND) {
+ if (db->search.state == FOUND) {
return;
}
- if (tss->state == START && (tss->ib == NULL || GTK_WIDGET(tss->ib) == widget)) {
+ if (db->search.state == START &&
+ (db->search.ib == NULL || GTK_WIDGET(db->search.ib) == widget)) {
/* No previous position or found the widget */
- tss->state = LOOKING;
- if (tss->ib != NULL) {
- tss->ib->match_start = 0;
- tss->ib->match_end = 0;
- gtk_widget_queue_draw(GTK_WIDGET(tss->ib));
+ db->search.state = LOOKING;
+ if (db->search.ib != NULL) {
+ db->sel.selection_prev = db->search.ib;
}
}
- if (tss->state == LOOKING &&
- (tss->ib == NULL || GTK_WIDGET(tss->ib) != widget)) {
- tss->start = 0;
- tss->end = -1;
+ if (db->search.state == LOOKING &&
+ (db->search.ib == NULL || GTK_WIDGET(db->search.ib) != widget)) {
+ db->search.start = 0;
+ db->search.end = -1;
}
- if (tss->state == LOOKING && IS_INLINE_BOX(widget)) {
+ if (db->search.state == LOOKING && IS_INLINE_BOX(widget)) {
InlineBox *ib = INLINE_BOX(widget);
- gint pos = inline_box_search(ib, tss->start, tss->end, tss->str);
+ gint pos = inline_box_search(ib, db->search.start, db->search.end, db->search.str);
if (pos != -1) {
- tss->state = FOUND;
- tss->ib = ib;
- tss->start = pos;
- tss->end = pos + strlen(tss->str);
- ib->match_start = tss->start;
- ib->match_end = tss->end;
+ db->search.state = FOUND;
+ db->search.ib = ib;
+ db->search.start = pos;
+ db->search.end = pos + strlen(db->search.str);
+
+ db->sel.selection_start = db->search.ib;
+ db->sel.selection_start_index = db->search.start;
+ db->sel.selection_end = db->search.ib;
+ db->sel.selection_end_index = db->search.end;
+ selection_update(widget, &db->sel);
gtk_widget_queue_draw(widget);
}
- } else if (tss->state != FOUND && GTK_IS_CONTAINER(widget)) {
+ } else if (db->search.state != FOUND && GTK_IS_CONTAINER(widget)) {
gtk_container_foreach(GTK_CONTAINER(widget),
- (GtkCallback)document_box_search, tss);
+ (GtkCallback)document_box_search, db);
}
}
gboolean
document_box_find (DocumentBox *db, const gchar *str)
{
+ /* Cleanup selection */
+ db->sel.selection_prev = db->sel.selection_end;
+ db->sel.selection_prev_index = db->sel.selection_end_index + 1;
+ db->sel.selection_end = db->sel.selection_start;
+ db->sel.selection_end_index = db->sel.selection_start_index;
+ selection_update(GTK_WIDGET(db), &db->sel);
+
/* todo: backwards search */
db->search.str = str;
db->search.state = START;
db->search.end = -1;
- document_box_search(GTK_WIDGET(db), &(db->search));
+ document_box_search(GTK_WIDGET(db), db);
if (db->search.state == FOUND) {
gtk_widget_grab_focus(GTK_WIDGET(db->search.ib));
return TRUE;
diff --git a/src/documentbox.h b/src/documentbox.h
index 64a2320..37b2909 100644
--- a/src/documentbox.h
+++ b/src/documentbox.h
@@ -36,11 +36,11 @@ typedef struct _DocumentBoxClass DocumentBoxClass;
typedef struct _SelectionState SelectionState;
struct _SelectionState
{
- IBText *selection_start;
+ InlineBox *selection_start;
guint selection_start_index;
- IBText *selection_end;
+ InlineBox *selection_end;
guint selection_end_index;
- IBText *selection_prev;
+ InlineBox *selection_prev;
guint selection_prev_index;
gboolean selection_active;
gboolean selecting;
diff --git a/src/inlinebox.c b/src/inlinebox.c
index 7eeaeae..f500114 100644
--- a/src/inlinebox.c
+++ b/src/inlinebox.c
@@ -165,29 +165,6 @@ inline_box_draw (GtkWidget *widget,
sel_width, ibt->alloc.height);
gtk_style_context_remove_class(styleCtx, "rubberband");
}
- /* duplication here (todo) */
- if (ib->match_start <= text_position + text_len &&
- ib->match_end >= text_position) {
- guint sel_start = ibt->alloc.x, sel_width = ibt->alloc.width;
- gint x_pos;
- if (ib->match_start > text_position) {
- pango_layout_index_to_line_x(ibt->layout,
- ib->match_start - text_position,
- FALSE, NULL, &x_pos);
- sel_start += x_pos / PANGO_SCALE;
- sel_width -= x_pos / PANGO_SCALE;
- }
- if (ib->match_end < text_position + text_len) {
- pango_layout_index_to_line_x(ibt->layout,
- ib->match_end - text_position,
- FALSE, NULL, &x_pos);
- sel_width -= ibt->alloc.width - x_pos / PANGO_SCALE;
- }
- gtk_style_context_add_class(styleCtx, "rubberband");
- gtk_render_background(styleCtx, cr, sel_start, ibt->alloc.y,
- sel_width, ibt->alloc.height);
- gtk_style_context_remove_class(styleCtx, "rubberband");
- }
gtk_render_layout(styleCtx, cr, ibt->alloc.x, ibt->alloc.y, ibt->layout);
@@ -624,6 +601,19 @@ inline_box_get_text (InlineBox *ib)
return result;
}
+guint
+inline_box_get_text_length (InlineBox *ib)
+{
+ GList *child;
+ guint len = 0;
+ for (child = ib->children; child; child = child->next) {
+ if (IS_IB_TEXT(child->data)) {
+ len += strlen(pango_layout_get_text(IB_TEXT(child->data)->layout));
+ }
+ }
+ return len;
+}
+
gint
inline_box_search (InlineBox *ib,
guint start,
diff --git a/src/inlinebox.h b/src/inlinebox.h
index 24c11d3..e3009f2 100644
--- a/src/inlinebox.h
+++ b/src/inlinebox.h
@@ -101,8 +101,6 @@ struct _InlineBox
GObject *focused_object;
guint selection_start;
guint selection_end;
- guint match_start;
- guint match_end;
gboolean wrap;
};
@@ -117,6 +115,7 @@ void inline_box_add_text (InlineBox *container, IBText *text);
void inline_box_break (InlineBox *container);
gchar *inline_box_get_text (InlineBox *ib);
gint inline_box_search (InlineBox *ib, guint start, gint end, const gchar *str);
+guint inline_box_get_text_length (InlineBox *ib);
G_END_DECLS