From 9f6c13a9509e06dd260b5c19eaf6e2ba40379cd5 Mon Sep 17 00:00:00 2001 From: ske Date: Sat, 3 Feb 2024 11:15:15 -0300 Subject: [PATCH] (feature) #143 shortcuts - delete, home, end, ctrl+left, ctrl+right, ctrl+c, ctrl+v --- src/staembed.c | 86 ++++++++++++++++++++++++++++++++++++++++---------- umka/ui.um | 83 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 139 insertions(+), 30 deletions(-) diff --git a/src/staembed.c b/src/staembed.c index eff9e2aa..5bade244 100644 --- a/src/staembed.c +++ b/src/staembed.c @@ -2942,6 +2942,7 @@ const char *th_em_modulesrc[] = { "\t\"rect.um\"\n" "\t\"th.um\"\n" "\t\"utf8.um\"\n" +"\t\"window.um\"\n" ")\n" "\n" "//~~struct BoxStyle\n" @@ -3609,8 +3610,8 @@ const char *th_em_modulesrc[] = { "// * right-to-left unicode is not supported.\n" "// * no selection\n" "// * multiline\n" -"// * copy paste\n" -"// * stuff like home and end\n" +"// * copy paste (now implemented but in a limited way due to the lack of selection)\n" +"// * common input shortcuts\n" "fn (gui: ^Gui) textBox*(tb: ^TextBox, cfg: TextBoxConfig = {}) {\n" "//~~\n" "\tgui.idx++\n" @@ -3637,18 +3638,7 @@ const char *th_em_modulesrc[] = { "\t\t\treturn\n" "\t\t}\n" "\n" -"\t\tif input.isJustPressed(input.key_left) ||\n" -"\t\t\tinput.isPressedRepeat(input.key_left) {\n" -"\t\t\tif tb.cursor > 0 { tb.cursor-- }\n" -"\t\t}\n" -"\n" -"\t\tif input.isJustPressed(input.key_right) ||\n" -"\t\t\tinput.isPressedRepeat(input.key_right) {\n" -"\t\t\tif tb.cursor < len(tb.buffer) { tb.cursor++ }\n" -"\t\t}\n" -"\n" -"\t\tif input.isJustPressed(input.key_backspace) ||\n" -"\t\t\tinput.isPressedRepeat(input.key_backspace) {\n" +"\t\tif input.isPressedRepeat(input.key_backspace) {\n" "\n" "\t\t\tif tb.cursor > 0 {\n" "\t\t\t\ttb.buffer = append(slice(tb.buffer, 0, tb.cursor - 1), slice(tb.buffer, tb.cursor))\n" @@ -3656,13 +3646,77 @@ const char *th_em_modulesrc[] = { "\t\t\t}\n" "\t\t}\n" "\n" +"\t\tif input.isPressedRepeat(input.key_delete) {\n" +"\n" +"\t\t\tif tb.cursor >= 0 && tb.cursor < len(tb.buffer) {\n" +"\t\t\t\ttb.buffer = append(slice(tb.buffer, 0, tb.cursor), slice(tb.buffer, tb.cursor+1))\n" +"\t\t\t}\n" +"\t\t}\n" +"\n" +"\t\tif input.isPressedRepeat(input.key_home) {\n" +"\t\t\ttb.cursor = 0\n" +"\t\t}\n" +"\n" +"\t\tif input.isPressedRepeat(input.key_end) {\n" +"\t\t\ttb.cursor = len(tb.buffer)\n" +"\t\t}\n" +"\n" "\t\tv := true\n" "\n" +"\t\tif input.isPressed(input.key_ctrl) && input.isJustPressedc(\'v\') {\n" +"\t\t\ttoInsert := utf8.decode(window.getClipboard())\n" +"\n" +"\t\t\ttb.buffer = append(append(slice(tb.buffer, 0, tb.cursor), toInsert), slice(tb.buffer, tb.cursor))\n" +"\t\t\ttb.cursor += len(toInsert)\n" +"\t\t\tv = false\n" +"\t\t}\n" +"\n" +"\t\tif input.isPressed(input.key_ctrl) && input.isJustPressedc(\'c\') {\n" +"\t\t\twindow.setClipboard(utf8.encode(tb.buffer))\n" +"\t\t\tv = false\n" +"\t\t}\n" +"\n" "\t\tif input.isPressed(input.key_ctrl) && input.isJustPressedc(\'u\') {\n" "\t\t\ttb.clear()\n" "\t\t\tv = false\n" "\t\t}\n" "\n" +"\t\tconst isRuneSpace = fn (r: utf8.Rune): bool {\n" +"\t\t\treturn r == utf8.Rune(\' \') || r == utf8.Rune(\'\\t\') || r == utf8.Rune(\'\\n\')\n" +"\t\t}\n" +"\n" +"\t\tif input.isPressed(input.key_ctrl) && input.isPressedRepeat(input.key_left) {\n" +"\t\t\t// skip spaces\n" +"\t\t\tfor tb.cursor > 0 && isRuneSpace(tb.buffer[tb.cursor-1]) {\n" +"\t\t\t\ttb.cursor--\n" +"\t\t\t}\n" +"\n" +"\t\t\tfor tb.cursor > 0 && !isRuneSpace(tb.buffer[tb.cursor-1]) {\n" +"\t\t\t\ttb.cursor--\n" +"\t\t\t}\n" +"\t\t\tv = false\n" +"\t\t}\n" +"\n" +"\t\tif input.isPressed(input.key_ctrl) && input.isPressedRepeat(input.key_right) {\n" +"\t\t\t// skip spaces\n" +"\t\t\tfor tb.cursor < len(tb.buffer) && isRuneSpace(tb.buffer[tb.cursor]) {\n" +"\t\t\t\ttb.cursor++\n" +"\t\t\t}\n" +"\n" +"\t\t\tfor tb.cursor < len(tb.buffer) && !isRuneSpace(tb.buffer[tb.cursor]) {\n" +"\t\t\t\ttb.cursor++\n" +"\t\t\t}\n" +"\t\t\tv = false\n" +"\t\t}\n" +"\n" +"\t\tif input.isPressedRepeat(input.key_left) && v {\n" +"\t\t\tif tb.cursor > 0 { tb.cursor-- }\n" +"\t\t}\n" +"\n" +"\t\tif input.isPressedRepeat(input.key_right) && v {\n" +"\t\t\tif tb.cursor < len(tb.buffer) { tb.cursor++ }\n" +"\t\t}\n" +"\n" "\t\trunes := utf8.decode(input.getStr())\n" "\t\tif len(runes) > 0 && v {\n" "\t\t\ttb.buffer = append(append(slice(tb.buffer, 0, tb.cursor), runes), slice(tb.buffer, tb.cursor))\n" @@ -6846,8 +6900,8 @@ const char *th_em_moduledocs[] = { "* right-to-left unicode is not supported.\n" "* no selection\n" "* multiline\n" -"* copy paste\n" -"* stuff like home and end\n" +"* copy paste (now implemented but in a limited way due to the lack of selection)\n" +"* common input shortcuts\n" "\n" "\n" "## struct ImageConfig\n" diff --git a/umka/ui.um b/umka/ui.um index fa23ef1a..8156b47c 100644 --- a/umka/ui.um +++ b/umka/ui.um @@ -13,6 +13,7 @@ import ( "rect.um" "th.um" "utf8.um" + "window.um" ) //~~struct BoxStyle @@ -680,8 +681,9 @@ fn (this: ^TextBox) setBuf*(s: str) { // * right-to-left unicode is not supported. // * no selection // * multiline -// * copy paste -// * stuff like home and end +// * copy paste (now implemented but in a limited way due to the lack of selection) +// * common input shortcuts +// - ctrl+delete / ctrl+backspace (delete word) fn (gui: ^Gui) textBox*(tb: ^TextBox, cfg: TextBoxConfig = {}) { //~~ gui.idx++ @@ -708,18 +710,7 @@ fn (gui: ^Gui) textBox*(tb: ^TextBox, cfg: TextBoxConfig = {}) { return } - if input.isJustPressed(input.key_left) || - input.isPressedRepeat(input.key_left) { - if tb.cursor > 0 { tb.cursor-- } - } - - if input.isJustPressed(input.key_right) || - input.isPressedRepeat(input.key_right) { - if tb.cursor < len(tb.buffer) { tb.cursor++ } - } - - if input.isJustPressed(input.key_backspace) || - input.isPressedRepeat(input.key_backspace) { + if input.isPressedRepeat(input.key_backspace) { if tb.cursor > 0 { tb.buffer = append(slice(tb.buffer, 0, tb.cursor - 1), slice(tb.buffer, tb.cursor)) @@ -727,13 +718,77 @@ fn (gui: ^Gui) textBox*(tb: ^TextBox, cfg: TextBoxConfig = {}) { } } + if input.isPressedRepeat(input.key_delete) { + + if tb.cursor >= 0 && tb.cursor < len(tb.buffer) { + tb.buffer = append(slice(tb.buffer, 0, tb.cursor), slice(tb.buffer, tb.cursor+1)) + } + } + + if input.isPressedRepeat(input.key_home) { + tb.cursor = 0 + } + + if input.isPressedRepeat(input.key_end) { + tb.cursor = len(tb.buffer) + } + v := true + if input.isPressed(input.key_ctrl) && input.isJustPressedc('v') { + toInsert := utf8.decode(window.getClipboard()) + + tb.buffer = append(append(slice(tb.buffer, 0, tb.cursor), toInsert), slice(tb.buffer, tb.cursor)) + tb.cursor += len(toInsert) + v = false + } + + if input.isPressed(input.key_ctrl) && input.isJustPressedc('c') { + window.setClipboard(utf8.encode(tb.buffer)) + v = false + } + if input.isPressed(input.key_ctrl) && input.isJustPressedc('u') { tb.clear() v = false } + const isRuneSpace = fn (r: utf8.Rune): bool { + return r == utf8.Rune(' ') || r == utf8.Rune('\t') || r == utf8.Rune('\n') + } + + if input.isPressed(input.key_ctrl) && input.isPressedRepeat(input.key_left) { + // skip spaces + for tb.cursor > 0 && isRuneSpace(tb.buffer[tb.cursor-1]) { + tb.cursor-- + } + + for tb.cursor > 0 && !isRuneSpace(tb.buffer[tb.cursor-1]) { + tb.cursor-- + } + v = false + } + + if input.isPressed(input.key_ctrl) && input.isPressedRepeat(input.key_right) { + // skip spaces + for tb.cursor < len(tb.buffer) && isRuneSpace(tb.buffer[tb.cursor]) { + tb.cursor++ + } + + for tb.cursor < len(tb.buffer) && !isRuneSpace(tb.buffer[tb.cursor]) { + tb.cursor++ + } + v = false + } + + if input.isPressedRepeat(input.key_left) && v { + if tb.cursor > 0 { tb.cursor-- } + } + + if input.isPressedRepeat(input.key_right) && v { + if tb.cursor < len(tb.buffer) { tb.cursor++ } + } + runes := utf8.decode(input.getStr()) if len(runes) > 0 && v { tb.buffer = append(append(slice(tb.buffer, 0, tb.cursor), runes), slice(tb.buffer, tb.cursor))