move cursor with mouse
This commit is contained in:
parent
e3c0bac9ca
commit
05a6d4803e
@ -77,8 +77,6 @@ fn void? Ctx.layout_string(&ctx, String text, Rect bounds, Anchor anchor, int z_
|
|||||||
// TODO: Following improvements
|
// TODO: Following improvements
|
||||||
// [ ] implement a macro to fetch and layout each character, this can be used to reduce code
|
// [ ] implement a macro to fetch and layout each character, this can be used to reduce code
|
||||||
// repetition both here and in measure_string
|
// repetition both here and in measure_string
|
||||||
// [ ] the cursor position can be determined by a separate function like get_cursor_position()
|
|
||||||
// this way the function can terminate early if the cursor position is found
|
|
||||||
// [ ] implement a function hit_test_string() to get the character position at point, this can
|
// [ ] implement a function hit_test_string() to get the character position at point, this can
|
||||||
// be used to implement mouse interactions, like cursor movement and selection
|
// be used to implement mouse interactions, like cursor movement and selection
|
||||||
<*
|
<*
|
||||||
@ -281,6 +279,9 @@ fn void? Ctx.layout_string_topleft(&ctx, String text, Rect bounds, int z_index,
|
|||||||
// ---------------------------------------------------------------------------------- //
|
// ---------------------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: get_cursor_position and hit_test_string can be implemented with a glyph_iterator that
|
||||||
|
// returns the position and offset in the string of each glyph
|
||||||
|
|
||||||
fn Rect? Ctx.get_cursor_position(&ctx, String text, Rect bounds, Anchor anchor, usz cursor, bool reflow = false)
|
fn Rect? Ctx.get_cursor_position(&ctx, String text, Rect bounds, Anchor anchor, usz cursor, bool reflow = false)
|
||||||
{
|
{
|
||||||
if (anchor != TOP_LEFT) {
|
if (anchor != TOP_LEFT) {
|
||||||
@ -348,6 +349,132 @@ fn Rect? Ctx.get_cursor_position(&ctx, String text, Rect bounds, Anchor anchor,
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<*
|
||||||
|
@param [&in] ctx
|
||||||
|
@param [in] text
|
||||||
|
*>
|
||||||
|
fn usz? Ctx.hit_test_string(&ctx, String text, Rect bounds, Anchor anchor, Point p, bool reflow = false)
|
||||||
|
{
|
||||||
|
if (text == "") return 0;
|
||||||
|
if (bounds.w <= 0 || bounds.h <= 0) return 0;
|
||||||
|
|
||||||
|
Font* font = &ctx.font;
|
||||||
|
Id texture_id = font.id;
|
||||||
|
short line_height = (short)font.line_height();
|
||||||
|
short baseline = (short)font.ascender;
|
||||||
|
short line_gap = (short)font.linegap;
|
||||||
|
short space_width = font.get_glyph(' ').adv!;
|
||||||
|
short tab_width = space_width * TAB_SIZE;
|
||||||
|
|
||||||
|
Point origin = bounds.position();
|
||||||
|
|
||||||
|
LineStack lines;
|
||||||
|
lines.init(tmem, 1);
|
||||||
|
|
||||||
|
Rect str_bounds;
|
||||||
|
|
||||||
|
usz line_start;
|
||||||
|
LineInfo li;
|
||||||
|
Point o;
|
||||||
|
StringIterator ti = text.iterator();
|
||||||
|
for (Codepoint cp; ti.has_next();) {
|
||||||
|
// FIXME: what if the interface changes?
|
||||||
|
cp = ti.next()!;
|
||||||
|
usz off = ti.current;
|
||||||
|
Glyph* gp = font.get_glyph(cp)!;
|
||||||
|
bool push = false;
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case cp == '\n':
|
||||||
|
push = true;
|
||||||
|
case cp == '\t':
|
||||||
|
o.x += tab_width;
|
||||||
|
case ascii::is_cntrl((char)cp):
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (off == line_start) li.first_off = gp.ox;
|
||||||
|
|
||||||
|
Rect b = {
|
||||||
|
.x = o.x + gp.ox,
|
||||||
|
.y = o.y + gp.oy + baseline,
|
||||||
|
.w = gp.w,
|
||||||
|
.h = gp.h,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (reflow && b.x + b.w > bounds.w) {
|
||||||
|
li.width += gp.ox + gp.w;
|
||||||
|
li.height = line_height;
|
||||||
|
push = true;
|
||||||
|
} else {
|
||||||
|
o.x += gp.adv;
|
||||||
|
li.width += gp.adv;
|
||||||
|
li.height = line_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (push) {
|
||||||
|
li.start = line_start;
|
||||||
|
li.end = off;
|
||||||
|
lines.push(li);
|
||||||
|
str_bounds.w = max(str_bounds.w, li.width);
|
||||||
|
str_bounds.h += li.height;
|
||||||
|
|
||||||
|
o.x = 0;
|
||||||
|
o.y += line_height;
|
||||||
|
line_start = off;
|
||||||
|
|
||||||
|
li.height = 0;
|
||||||
|
li.width = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FIXME: crap
|
||||||
|
li.start = line_start;
|
||||||
|
li.end = ti.current;
|
||||||
|
lines.push(li);
|
||||||
|
str_bounds.w = max(str_bounds.w, li.width);
|
||||||
|
str_bounds.h += li.height;
|
||||||
|
|
||||||
|
// account for the line gap
|
||||||
|
str_bounds.h += (short)(lines.len() - 1)*line_gap;
|
||||||
|
|
||||||
|
o = bounds.position();
|
||||||
|
o.y += bounds.y_off(str_bounds.h, anchor);
|
||||||
|
foreach (idx, line : lines) {
|
||||||
|
o.x = bounds.x + bounds.x_off(line.width, anchor) - line.first_off;
|
||||||
|
|
||||||
|
StringIterator s = text[line.start:line.end-line.start].iterator();
|
||||||
|
usz prev;
|
||||||
|
for (Codepoint cp; s.has_next(); prev = s.current) {
|
||||||
|
cp = s.next()!;
|
||||||
|
Glyph* gp = font.get_glyph(cp)!;
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case cp == '\n':
|
||||||
|
break;
|
||||||
|
case cp == '\t':
|
||||||
|
o.x += tab_width;
|
||||||
|
case ascii::is_cntrl((char)cp):
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Rect b = {
|
||||||
|
.x = o.x + gp.ox,
|
||||||
|
.y = o.y + gp.oy + baseline,
|
||||||
|
.w = gp.w,
|
||||||
|
.h = gp.h,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: skip lines if p is not inside them
|
||||||
|
Rect r = { .x = b.x, .y = b.y - gp.ox, .w = b.w, .h = line.height};
|
||||||
|
if (p.in_rect(r)) return line.start + prev;
|
||||||
|
|
||||||
|
o.x += gp.adv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o.y += line.height + line_gap;
|
||||||
|
}
|
||||||
|
return text.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------- //
|
// ---------------------------------------------------------------------------------- //
|
||||||
// TEXT MEASUREMENT //
|
// TEXT MEASUREMENT //
|
||||||
|
@ -80,6 +80,9 @@ fn ElemEvents? Ctx.text_box_id(&ctx, Id id, Size w, Size h, TextEdit* te, Anchor
|
|||||||
|
|
||||||
// draw the cursor if the element has focus
|
// draw the cursor if the element has focus
|
||||||
if (elem.events.has_focus) {
|
if (elem.events.has_focus) {
|
||||||
|
if (elem.events.mouse_press) {
|
||||||
|
elem.text.te.cursor = ctx.hit_test_string(elem.text.te.to_string(), text_bounds, text_alignment, ctx.input.mouse.pos, reflow)!;
|
||||||
|
}
|
||||||
Rect cur = ctx.get_cursor_position(elem.text.te.to_string(), text_bounds, text_alignment, elem.text.te.cursor, reflow)!;
|
Rect cur = ctx.get_cursor_position(elem.text.te.to_string(), text_bounds, text_alignment, elem.text.te.cursor, reflow)!;
|
||||||
cur.w = 2;
|
cur.w = 2;
|
||||||
ctx.push_rect(cur, parent.z_index, &&(Style){.bg = style.fg})!;
|
ctx.push_rect(cur, parent.z_index, &&(Style){.bg = style.fg})!;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user