Compare commits
2 Commits
2eec1fb710
...
fe6f32c769
| Author | SHA1 | Date | |
|---|---|---|---|
| fe6f32c769 | |||
| a512fe6c71 |
@ -79,6 +79,7 @@ struct GlyphIterator {
|
||||
|
||||
Codepoint cp;
|
||||
Glyph* gp;
|
||||
short adv; // prev advance
|
||||
Point o;
|
||||
Rect str_bounds;
|
||||
}
|
||||
@ -239,6 +240,8 @@ fn Rect? GlyphIterator.next(&self)
|
||||
|
||||
Rect b = {.x = self.o.x, .y = self.o.y};
|
||||
|
||||
Point prev_o = self.o;
|
||||
self.adv = 0;
|
||||
switch {
|
||||
case self.cp == '\n':
|
||||
if (self.anchor == TOP_LEFT) {
|
||||
@ -265,6 +268,7 @@ fn Rect? GlyphIterator.next(&self)
|
||||
}
|
||||
}
|
||||
self.o.x += self.gp.adv;
|
||||
self.adv = self.o.x - prev_o.x;
|
||||
}
|
||||
|
||||
return b;
|
||||
@ -476,7 +480,7 @@ fn void? Ctx.draw_string_selection(&ctx, String text, Rect bounds, Anchor anchor
|
||||
if (sel_line != -1) {
|
||||
ctx.push_rect(sel_rect, z_index, &&{.bg = hue})!;
|
||||
}
|
||||
sel_rect = {.x = gi.o.x - b.w, .y = gi.o.y, .w = 0, .h = gi.line_height};
|
||||
sel_rect = {.x = gi.o.x - gi.adv, .y = gi.o.y, .w = 0, .h = gi.line_height};
|
||||
sel_line = line;
|
||||
}
|
||||
if (in_selection) {
|
||||
|
||||
@ -25,32 +25,47 @@ fn bool Ctx.text_edit(&ctx, TextEdit* te)
|
||||
|
||||
// handle backspace and delete
|
||||
if (mod.bkspc) {
|
||||
te.remove_character(false);
|
||||
if (mod & KMOD_CTRL) {
|
||||
te.remove_word(false);
|
||||
} else {
|
||||
te.remove_character(false);
|
||||
}
|
||||
}
|
||||
if (mod.del) {
|
||||
te.remove_character(true);
|
||||
if (mod & KMOD_CTRL) {
|
||||
te.remove_word(true);
|
||||
} else {
|
||||
te.remove_character(true);
|
||||
}
|
||||
}
|
||||
|
||||
// handle arrow keys
|
||||
if (mod.left) {
|
||||
te.move_cursor(false, !!(mod & KMOD_SHIFT));
|
||||
if (mod & KMOD_CTRL) {
|
||||
te.move_cursor_word(false, !!(mod & KMOD_SHIFT));
|
||||
} else {
|
||||
te.move_cursor(false, !!(mod & KMOD_SHIFT));
|
||||
}
|
||||
}
|
||||
if (mod.right) {
|
||||
te.move_cursor(true, !!(mod & KMOD_SHIFT));
|
||||
if (mod & KMOD_CTRL) {
|
||||
te.move_cursor_word(true, !!(mod & KMOD_SHIFT));
|
||||
} else {
|
||||
te.move_cursor(true, !!(mod & KMOD_SHIFT));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: up, down
|
||||
// TODO: mod.home
|
||||
// TODO: mod.end
|
||||
// TODO: selection with shift+arrows
|
||||
|
||||
println("cursor: ", te.cursor, " sel_len: ", te.sel_len);
|
||||
return te.chars < te.buffer.len;
|
||||
}
|
||||
|
||||
module ugui::textedit::te;
|
||||
|
||||
import std::core::string;
|
||||
import std::ascii;
|
||||
|
||||
// returns the offset of the next codepoint in the buffer from the cursor
|
||||
fn usz TextEdit.next_char_off(&te)
|
||||
@ -119,6 +134,32 @@ fn void TextEdit.set_cursor(&te, usz cur, bool select)
|
||||
}
|
||||
}
|
||||
|
||||
fn void TextEdit.move_cursor_word(&te, bool forward, bool select)
|
||||
{
|
||||
// moving out of selection, snap to the end
|
||||
if (!select && te.sel_len != 0) {
|
||||
te.move_cursor(forward, select);
|
||||
return;
|
||||
}
|
||||
|
||||
usz prev_cur = te.cursor;
|
||||
while (te.cursor <= te.chars) {
|
||||
char c;
|
||||
if (forward) {
|
||||
if (te.cursor == te.chars) break;
|
||||
c = te.buffer[te.cursor];
|
||||
} else {
|
||||
if (te.cursor == 0) break;
|
||||
c = te.buffer[te.cursor-1];
|
||||
}
|
||||
if (ascii::is_space(c) || ascii::is_punct(c)) break;
|
||||
te.move_cursor(forward, select);
|
||||
}
|
||||
|
||||
// move at least one character
|
||||
if (prev_cur == te.cursor) te.move_cursor(forward, select);
|
||||
}
|
||||
|
||||
fn void TextEdit.delete_selection(&te)
|
||||
{
|
||||
if (te.sel_len == 0) return;
|
||||
@ -160,6 +201,33 @@ fn void TextEdit.remove_character(&te, bool forward)
|
||||
}
|
||||
}
|
||||
|
||||
// remove the word before or after the cursor up until the next punctuation or space
|
||||
fn void TextEdit.remove_word(&te, bool forward)
|
||||
{
|
||||
// if there is a selection active then delete that selection
|
||||
if (te.sel_len) {
|
||||
te.delete_selection();
|
||||
return;
|
||||
}
|
||||
|
||||
usz prev_cur = te.cursor;
|
||||
while (te.chars > 0) {
|
||||
char c;
|
||||
if (forward) {
|
||||
if (te.cursor == te.chars) break;
|
||||
c = te.buffer[te.cursor];
|
||||
} else {
|
||||
if (te.cursor == 0) break;
|
||||
c = te.buffer[te.cursor-1];
|
||||
}
|
||||
if (ascii::is_space(c) || ascii::is_punct(c)) break;
|
||||
te.remove_character(forward);
|
||||
}
|
||||
|
||||
// delete at least one character
|
||||
if (prev_cur == te.cursor) te.remove_character(forward);
|
||||
}
|
||||
|
||||
// insert a character at the cursor and update the cursor
|
||||
fn void TextEdit.insert_character(&te, uint cp)
|
||||
{
|
||||
|
||||
@ -86,7 +86,8 @@ fn ElemEvents? Ctx.text_box_id(&ctx, Id id, Size w, Size h, TextEdit* te, Anchor
|
||||
if (elem.events.has_focus) {
|
||||
if (elem.events.mouse_press || elem.events.mouse_hold) {
|
||||
usz cur = ctx.hit_test_string(s, text_bounds, text_alignment, ctx.input.mouse.pos, reflow)!;
|
||||
te.set_cursor(cur, elem.events.mouse_hold & !elem.events.mouse_press);
|
||||
bool select = (elem.events.mouse_hold && !elem.events.mouse_press) || (ctx.get_mod() & KMOD_SHIFT);
|
||||
te.set_cursor(cur, select);
|
||||
}
|
||||
Rect cur = ctx.get_cursor_position(s, text_bounds, text_alignment, te.cursor, reflow)!;
|
||||
cur.w = 2;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user