editor: Add support for selection
Make it possible to select text and render the selection to the editor example. Signed-off-by: Jan Arne Petersen <jpetersen@openismus.com>
This commit is contained in:
committed by
Kristian Høgsberg
parent
09e7c96574
commit
0e5bd45100
@@ -50,6 +50,7 @@ struct text_entry {
|
|||||||
char *text;
|
char *text;
|
||||||
int active;
|
int active;
|
||||||
uint32_t cursor;
|
uint32_t cursor;
|
||||||
|
uint32_t anchor;
|
||||||
struct text_model *model;
|
struct text_model *model;
|
||||||
struct text_layout *layout;
|
struct text_layout *layout;
|
||||||
};
|
};
|
||||||
@@ -309,6 +310,7 @@ text_entry_create(struct editor *editor, const char *text)
|
|||||||
entry->text = strdup(text);
|
entry->text = strdup(text);
|
||||||
entry->active = 0;
|
entry->active = 0;
|
||||||
entry->cursor = strlen(text);
|
entry->cursor = strlen(text);
|
||||||
|
entry->anchor = entry->cursor;
|
||||||
entry->model = text_model_factory_create_text_model(editor->text_model_factory);
|
entry->model = text_model_factory_create_text_model(editor->text_model_factory);
|
||||||
text_model_add_listener(entry->model, &text_model_listener, entry);
|
text_model_add_listener(entry->model, &text_model_listener, entry);
|
||||||
|
|
||||||
@@ -418,6 +420,7 @@ text_entry_insert_at_cursor(struct text_entry *entry, const char *text)
|
|||||||
free(entry->text);
|
free(entry->text);
|
||||||
entry->text = new_text;
|
entry->text = new_text;
|
||||||
entry->cursor += strlen(text);
|
entry->cursor += strlen(text);
|
||||||
|
entry->anchor += strlen(text);
|
||||||
|
|
||||||
text_layout_set_text(entry->layout, entry->text);
|
text_layout_set_text(entry->layout, entry->text);
|
||||||
}
|
}
|
||||||
@@ -431,6 +434,50 @@ text_entry_set_cursor_position(struct text_entry *entry,
|
|||||||
widget_schedule_redraw(entry->widget);
|
widget_schedule_redraw(entry->widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
text_entry_set_anchor_position(struct text_entry *entry,
|
||||||
|
int32_t x, int32_t y)
|
||||||
|
{
|
||||||
|
entry->anchor = text_layout_xy_to_index(entry->layout, x, y);
|
||||||
|
|
||||||
|
widget_schedule_redraw(entry->widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
text_entry_draw_selection(struct text_entry *entry, cairo_t *cr)
|
||||||
|
{
|
||||||
|
cairo_text_extents_t extents;
|
||||||
|
uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
|
||||||
|
uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
|
||||||
|
cairo_rectangle_t start;
|
||||||
|
cairo_rectangle_t end;
|
||||||
|
|
||||||
|
if (entry->anchor == entry->cursor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
text_layout_extents(entry->layout, &extents);
|
||||||
|
|
||||||
|
text_layout_index_to_pos(entry->layout, start_index, &start);
|
||||||
|
text_layout_index_to_pos(entry->layout, end_index, &end);
|
||||||
|
|
||||||
|
cairo_save (cr);
|
||||||
|
|
||||||
|
cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 1.0);
|
||||||
|
cairo_rectangle(cr,
|
||||||
|
start.x, extents.y_bearing + extents.height + 2,
|
||||||
|
end.x - start.x, -extents.height - 4);
|
||||||
|
cairo_fill(cr);
|
||||||
|
|
||||||
|
cairo_rectangle(cr,
|
||||||
|
start.x, extents.y_bearing + extents.height,
|
||||||
|
end.x - start.x, -extents.height);
|
||||||
|
cairo_clip(cr);
|
||||||
|
cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
|
||||||
|
text_layout_draw(entry->layout, cr);
|
||||||
|
|
||||||
|
cairo_restore (cr);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
|
text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
|
||||||
{
|
{
|
||||||
@@ -484,6 +531,8 @@ text_entry_redraw_handler(struct widget *widget, void *data)
|
|||||||
cairo_translate(cr, 10, allocation.height / 2);
|
cairo_translate(cr, 10, allocation.height / 2);
|
||||||
text_layout_draw(entry->layout, cr);
|
text_layout_draw(entry->layout, cr);
|
||||||
|
|
||||||
|
text_entry_draw_selection(entry, cr);
|
||||||
|
|
||||||
text_entry_draw_cursor(entry, cr);
|
text_entry_draw_cursor(entry, cr);
|
||||||
|
|
||||||
cairo_pop_group_to_source(cr);
|
cairo_pop_group_to_source(cr);
|
||||||
@@ -493,6 +542,23 @@ text_entry_redraw_handler(struct widget *widget, void *data)
|
|||||||
cairo_surface_destroy(surface);
|
cairo_surface_destroy(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
text_entry_motion_handler(struct widget *widget,
|
||||||
|
struct input *input, uint32_t time,
|
||||||
|
float x, float y, void *data)
|
||||||
|
{
|
||||||
|
struct text_entry *entry = data;
|
||||||
|
struct rectangle allocation;
|
||||||
|
|
||||||
|
widget_get_allocation(entry->widget, &allocation);
|
||||||
|
|
||||||
|
text_entry_set_cursor_position(entry,
|
||||||
|
x - allocation.x,
|
||||||
|
y - allocation.y);
|
||||||
|
|
||||||
|
return CURSOR_IBEAM;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
text_entry_button_handler(struct widget *widget,
|
text_entry_button_handler(struct widget *widget,
|
||||||
struct input *input, uint32_t time,
|
struct input *input, uint32_t time,
|
||||||
@@ -518,6 +584,14 @@ text_entry_button_handler(struct widget *widget,
|
|||||||
struct wl_seat *seat = input_get_seat(input);
|
struct wl_seat *seat = input_get_seat(input);
|
||||||
|
|
||||||
text_entry_activate(entry, seat);
|
text_entry_activate(entry, seat);
|
||||||
|
|
||||||
|
text_entry_set_anchor_position(entry,
|
||||||
|
x - allocation.x,
|
||||||
|
y - allocation.y);
|
||||||
|
|
||||||
|
widget_set_motion_handler(entry->widget, text_entry_motion_handler);
|
||||||
|
} else {
|
||||||
|
widget_set_motion_handler(entry->widget, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user