Renamed every 'str' fiend and variable to 's'. Implemented edit_init.
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
* about **********************************************************************
|
## about
|
||||||
|
|
||||||
tim.h is a portable library to create simple terminal applications
|
tim.h is a portable library to create simple terminal applications
|
||||||
Demo video: https://asciinema.org/a/zn3p0dsVCOQOzwY1S9gDfyaxQ
|
Demo video: https://asciinema.org/a/zn3p0dsVCOQOzwY1S9gDfyaxQ
|
||||||
|
|
||||||
* quick start ****************************************************************
|
## quick start
|
||||||
|
|
||||||
#include "tim.h" // one header, no lib
|
#include "tim.h" // one header, no lib
|
||||||
int main(void) { //
|
int main(void) { //
|
||||||
@@ -20,7 +20,7 @@ int main(void) { //
|
|||||||
} // atexit cleanup
|
} // atexit cleanup
|
||||||
} //
|
} //
|
||||||
|
|
||||||
* layout *********************************************************************
|
## layout
|
||||||
|
|
||||||
The terminal's columns (x) and rows (y) are addressed by their coordinates,
|
The terminal's columns (x) and rows (y) are addressed by their coordinates,
|
||||||
the origin is in the top left corner.
|
the origin is in the top left corner.
|
||||||
@@ -56,7 +56,7 @@ take the full available space from parent.
|
|||||||
|
|
||||||
The layout automatically adopts to terminal window resize events.
|
The layout automatically adopts to terminal window resize events.
|
||||||
|
|
||||||
* colors *********************************************************************
|
## colors
|
||||||
|
|
||||||
Most elements have a uint64 color argument which holds up to eight colors.
|
Most elements have a uint64 color argument which holds up to eight colors.
|
||||||
Typically byte 0 is the text color and byte 1 is the background color.
|
Typically byte 0 is the text color and byte 1 is the background color.
|
||||||
@@ -71,7 +71,7 @@ should be used if consistency is important.
|
|||||||
xterm-256 color chart
|
xterm-256 color chart
|
||||||
https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg
|
https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg
|
||||||
|
|
||||||
* events *********************************************************************
|
## events
|
||||||
|
|
||||||
tim_run blocks until it observes an event. Mouse and key events are always
|
tim_run blocks until it observes an event. Mouse and key events are always
|
||||||
immediately followed by a draw event in order to make changes visible.
|
immediately followed by a draw event in order to make changes visible.
|
||||||
@@ -88,7 +88,7 @@ The current event is stored in tim.event.
|
|||||||
MOUSE_EVENT | mouse click
|
MOUSE_EVENT | mouse click
|
||||||
VOID_EVENT | consumed event
|
VOID_EVENT | consumed event
|
||||||
|
|
||||||
* elements *******************************************************************
|
## elements
|
||||||
|
|
||||||
frame (x, y, w, h, color)
|
frame (x, y, w, h, color)
|
||||||
|
|
||||||
@@ -115,11 +115,12 @@ button (str, x, y, w, h, color) -> bool
|
|||||||
x/y/w/h see layout documentation
|
x/y/w/h see layout documentation
|
||||||
color frame, background, text
|
color frame, background, text
|
||||||
|
|
||||||
edit (state, x, y, w, color) -> bool
|
edit (state, x, y, w, color) -> int
|
||||||
|
|
||||||
Draw text edit. Output is stored in state.str. Receives input events when
|
Draw text edit. Output is stored in state.s.
|
||||||
focused by mouse click. Escape or return relinquish focus. Returns true
|
Receives input events when focused by mouse click or by setting focus manually.
|
||||||
when return is pressed.
|
Escape or return relinquish focus.
|
||||||
|
Returns key id if received key input.
|
||||||
|
|
||||||
state pointer to persistent edit state struct
|
state pointer to persistent edit state struct
|
||||||
x/y/w see layout documentation
|
x/y/w see layout documentation
|
||||||
@@ -148,7 +149,7 @@ radio (str, state, v, x, y, w, color) -> bool
|
|||||||
x/y/w see layout documentation
|
x/y/w see layout documentation
|
||||||
color radio, background, text
|
color radio, background, text
|
||||||
|
|
||||||
* functions ******************************************************************
|
## functions
|
||||||
|
|
||||||
tim_run (fps) -> bool
|
tim_run (fps) -> bool
|
||||||
|
|
||||||
@@ -177,12 +178,12 @@ time_us () -> int64
|
|||||||
Returns monotonic clock value in microseconds. Not affected by summer
|
Returns monotonic clock value in microseconds. Not affected by summer
|
||||||
time or leap seconds.
|
time or leap seconds.
|
||||||
|
|
||||||
* useful links ***************************************************************
|
## useful links
|
||||||
|
|
||||||
https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||||
https://learn.microsoft.com/en-us/windows/console/
|
https://learn.microsoft.com/en-us/windows/console/
|
||||||
|
|
||||||
* bugs ***********************************************************************
|
## bugs
|
||||||
|
|
||||||
- Double buffering is still new, set ENABLE_DBUF to 0 if you see glitches
|
- Double buffering is still new, set ENABLE_DBUF to 0 if you see glitches
|
||||||
- Double width characters like 彁 are not fully supported. Terminals do not
|
- Double width characters like 彁 are not fully supported. Terminals do not
|
||||||
@@ -193,7 +194,7 @@ https://learn.microsoft.com/en-us/windows/console/
|
|||||||
- Zero width code points are not supported
|
- Zero width code points are not supported
|
||||||
- Windows cmd.exe resize events may be delayed
|
- Windows cmd.exe resize events may be delayed
|
||||||
|
|
||||||
* compatibility **************************************************************
|
## compatibility
|
||||||
|
|
||||||
emulator | support | remarks
|
emulator | support | remarks
|
||||||
------------------|---------|----------------------------------
|
------------------|---------|----------------------------------
|
||||||
@@ -222,7 +223,7 @@ https://learn.microsoft.com/en-us/windows/console/
|
|||||||
XTerm | full | XTerm is law
|
XTerm | full | XTerm is law
|
||||||
Zutty | full |
|
Zutty | full |
|
||||||
|
|
||||||
* license ********************************************************************
|
## license
|
||||||
|
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ int main(void) {
|
|||||||
TEST(scan_str("a").width == 1);
|
TEST(scan_str("a").width == 1);
|
||||||
TEST(scan_str("äß\no").width == 2);
|
TEST(scan_str("äß\no").width == 2);
|
||||||
|
|
||||||
struct line ln = {.str = "foo\nbar"};
|
struct line ln = {.s = "foo\nbar"};
|
||||||
TEST(next_line(&ln) == true);
|
TEST(next_line(&ln) == true);
|
||||||
TEST(!memcmp(ln.line, "foo", ln.size));
|
TEST(!memcmp(ln.line, "foo", ln.size));
|
||||||
TEST(next_line(&ln) == true);
|
TEST(next_line(&ln) == true);
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ static inline void test_screen(struct event* e) {
|
|||||||
label(buf, 2, 0, A, A, 0xf);
|
label(buf, 2, 0, A, A, 0xf);
|
||||||
sprintf(buf, "frame : [%c] %d", ": "[tim.frame & 1], tim.frame);
|
sprintf(buf, "frame : [%c] %d", ": "[tim.frame & 1], tim.frame);
|
||||||
label(buf, 2, 1, A, A, 0xf);
|
label(buf, 2, 1, A, A, 0xf);
|
||||||
sprintf(buf, "key : [%d] %s", ke.key, ke.str + (ke.key < 32));
|
sprintf(buf, "key : [%d] %s", ke.key, ke.s + (ke.key < 32));
|
||||||
label(buf, 2, 2, A, A, 0xf);
|
label(buf, 2, 2, A, A, 0xf);
|
||||||
sprintf(buf, "mouse : [%d] %d:%d", me.key, me.x, me.y);
|
sprintf(buf, "mouse : [%d] %d:%d", me.key, me.x, me.y);
|
||||||
label(buf, 2, 3, A, A, 0xf);
|
label(buf, 2, 3, A, A, 0xf);
|
||||||
sprintf(buf, "input : %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx",
|
sprintf(buf, "input : %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx",
|
||||||
e->str[0], e->str[1], e->str[2], e->str[3], e->str[4], e->str[5], e->str[6], e->str[7]);
|
e->s[0], e->s[1], e->s[2], e->s[3], e->s[4], e->s[5], e->s[6], e->s[7]);
|
||||||
label(buf, 2, 4, A, A, 0xf);
|
label(buf, 2, 4, A, A, 0xf);
|
||||||
|
|
||||||
// lower right
|
// lower right
|
||||||
@@ -63,13 +63,13 @@ static inline void test_screen(struct event* e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// edit
|
// edit
|
||||||
static struct edit ed1 = {.str = "Edit 1"};
|
static struct edit ed1 = {.s = "Edit 1"};
|
||||||
static struct edit ed2 = {0};
|
static struct edit ed2 = {0};
|
||||||
edit(&ed1, 1, 10, 32, 0xff00ff);
|
edit(&ed1, 1, 10, 32, 0xff00ff);
|
||||||
sprintf(buf, "cursor: %d length: %d", ed1.cursor, ed1.length);
|
sprintf(buf, "cursor: %d length: %d", ed1.cursor, ed1.length);
|
||||||
label(buf, 2, 13, A, A, 0xf);
|
label(buf, 2, 13, A, A, 0xf);
|
||||||
edit(&ed2, 1, 14, 32, 0xff00ff);
|
edit(&ed2, 1, 14, 32, 0xff00ff);
|
||||||
label(ed2.str, 2, 17, A, A, 0xf);
|
label(ed2.s, 2, 17, A, A, 0xf);
|
||||||
|
|
||||||
// checkbox
|
// checkbox
|
||||||
static int chk[2] = {-1, 1};
|
static int chk[2] = {-1, 1};
|
||||||
|
|||||||
135
tim.h
135
tim.h
@@ -117,9 +117,10 @@
|
|||||||
//
|
//
|
||||||
// edit (state, x, y, w, color) -> bool
|
// edit (state, x, y, w, color) -> bool
|
||||||
//
|
//
|
||||||
// Draw text edit. Output is stored in state.str. Receives input events when
|
// Draw text edit. Output is stored in state.s.
|
||||||
// focused by mouse click. Escape or return relinquish focus. Returns true
|
// Receives input events when focused by mouse click or by setting focus manually.
|
||||||
// when return is pressed.
|
// Escape or return relinquish focus.
|
||||||
|
// Returns key id if received key input.
|
||||||
//
|
//
|
||||||
// state pointer to persistent edit state struct
|
// state pointer to persistent edit state struct
|
||||||
// x/y/w see layout documentation
|
// x/y/w see layout documentation
|
||||||
@@ -357,7 +358,7 @@ struct text {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct line {
|
struct line {
|
||||||
const char* str; // input and parse state
|
const char* s; // input and parse state
|
||||||
const char* line; // line strings, not terminated
|
const char* line; // line strings, not terminated
|
||||||
int size; // line size in bytes
|
int size; // line size in bytes
|
||||||
int width; // line width in glyph
|
int width; // line width in glyph
|
||||||
@@ -368,13 +369,14 @@ struct event {
|
|||||||
int32_t key; // used by KEY_EVENT and MOUSE_EVENT
|
int32_t key; // used by KEY_EVENT and MOUSE_EVENT
|
||||||
int x; // used by MOUSE_EVENT
|
int x; // used by MOUSE_EVENT
|
||||||
int y; // used by MOUSE_EVENT
|
int y; // used by MOUSE_EVENT
|
||||||
char str[32]; // string representation of key
|
char s[32]; // string representation of key
|
||||||
};
|
};
|
||||||
|
|
||||||
struct edit {
|
struct edit {
|
||||||
int cursor; // cursor position (utf8)
|
int cursor; // cursor position (utf8)
|
||||||
int length; // string length (utf8)
|
int length; // string length (utf8)
|
||||||
char str[256]; // zero terminated buffer
|
int capacity; // buffer size
|
||||||
|
char* s; // zero terminated buffer
|
||||||
};
|
};
|
||||||
|
|
||||||
struct state {
|
struct state {
|
||||||
@@ -382,7 +384,7 @@ struct state {
|
|||||||
int h; // screen height
|
int h; // screen height
|
||||||
int frame; // frame counter
|
int frame; // frame counter
|
||||||
struct event event; // current event
|
struct event event; // current event
|
||||||
uintptr_t focus; // focused element
|
void* focus; // focused element
|
||||||
int loop_stage; // loop stage
|
int loop_stage; // loop stage
|
||||||
bool resized; // screen was resized
|
bool resized; // screen was resized
|
||||||
int scope; // current scope
|
int scope; // current scope
|
||||||
@@ -436,8 +438,12 @@ struct state tim = {
|
|||||||
|
|
||||||
// like strlen, returns 0 on NULL or int overflow
|
// like strlen, returns 0 on NULL or int overflow
|
||||||
static inline int ztrlen(const char* s) {
|
static inline int ztrlen(const char* s) {
|
||||||
size_t n = s ? strlen(s) : 0;
|
if(s == NULL)
|
||||||
return MAX((int)n, 0);
|
return 0;
|
||||||
|
int n = strlen(s);
|
||||||
|
if(n < 0)
|
||||||
|
n = 0;
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bit scan reverse, count leading zeros
|
// bit scan reverse, count leading zeros
|
||||||
@@ -494,8 +500,9 @@ static int utfpos(const char* s, int pos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// scan string for width and lines
|
// scan string for width and lines
|
||||||
static struct text scan_str(const char* str) {
|
static struct text scan_str(const char* s) {
|
||||||
const char* s = str ? str : "";
|
if(s == NULL)
|
||||||
|
s = "";
|
||||||
struct text t = {
|
struct text t = {
|
||||||
.width = 0,
|
.width = 0,
|
||||||
.lines = (s[0] != 0),
|
.lines = (s[0] != 0),
|
||||||
@@ -514,17 +521,17 @@ static struct text scan_str(const char* str) {
|
|||||||
|
|
||||||
// iterate through lines, false when end is reached
|
// iterate through lines, false when end is reached
|
||||||
static bool next_line(struct line* l) {
|
static bool next_line(struct line* l) {
|
||||||
if (!l->str || !l->str[0]) {
|
if (!l->s || !l->s[0]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
l->line = l->str;
|
l->line = l->s;
|
||||||
l->size = 0;
|
l->size = 0;
|
||||||
l->width = 0;
|
l->width = 0;
|
||||||
for (const char* s = l->str; s[0] && s[0] != '\n'; s++) {
|
for (const char* s = l->s; s[0] && s[0] != '\n'; s++) {
|
||||||
l->size += 1;
|
l->size += 1;
|
||||||
l->width += (s[0] & 192) != 128 && (uint8_t)s[0] > 31;
|
l->width += (s[0] & 192) != 128 && (uint8_t)s[0] > 31;
|
||||||
}
|
}
|
||||||
l->str += l->size + !!l->str[l->size];
|
l->s += l->size + !!l->s[l->size];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,7 +570,8 @@ static void signal_handler(int signal) {
|
|||||||
static void update_screen_size(void) {
|
static void update_screen_size(void) {
|
||||||
struct winsize ws = {0};
|
struct winsize ws = {0};
|
||||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != 0) {
|
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != 0) {
|
||||||
return;
|
printf("ERROR: can't get console buffer size\n");
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
int w = ws.ws_col;
|
int w = ws.ws_col;
|
||||||
int h = ws.ws_row;
|
int h = ws.ws_row;
|
||||||
@@ -601,9 +609,9 @@ static void reset_terminal(void) {
|
|||||||
write_str(S("\33[?1049l")); // exit alternate buffer
|
write_str(S("\33[?1049l")); // exit alternate buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse input stored in e->str
|
// parse input stored in e->s
|
||||||
static bool parse_input(struct event* restrict e, int n) {
|
static bool parse_input(struct event* restrict e, int n) {
|
||||||
char* s = e->str;
|
char* s = e->s;
|
||||||
|
|
||||||
if (n == 1 || s[0] != 27) {
|
if (n == 1 || s[0] != 27) {
|
||||||
// regular key press
|
// regular key press
|
||||||
@@ -694,7 +702,7 @@ static void read_event(int timeout_ms) {
|
|||||||
|
|
||||||
if (pfd[1].revents & POLLIN) {
|
if (pfd[1].revents & POLLIN) {
|
||||||
// received input
|
// received input
|
||||||
int n = read(STDIN_FILENO, e->str, sizeof(e->str) - 1);
|
int n = read(STDIN_FILENO, e->s, sizeof(e->s) - 1);
|
||||||
if (parse_input(e, n)) {
|
if (parse_input(e, n)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -727,7 +735,8 @@ static void update_screen_size(void) {
|
|||||||
HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
|
HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
|
CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
|
||||||
if (GetConsoleScreenBufferInfo(hout, &csbi) == 0) {
|
if (GetConsoleScreenBufferInfo(hout, &csbi) == 0) {
|
||||||
return;
|
printf("ERROR: can't get console buffer size\n");
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
int w = csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
int w = csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
||||||
int h = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
|
int h = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
|
||||||
@@ -839,7 +848,7 @@ static void read_event(int timeout_ms) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
e->key = chr;
|
e->key = chr;
|
||||||
WideCharToMultiByte(CP_UTF8, 0, &chr, 1, e->str, sizeof(e->str),
|
WideCharToMultiByte(CP_UTF8, 0, &chr, 1, e->s, sizeof(e->s),
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1076,16 +1085,16 @@ static inline void frame(int x, int y, int w, int h, uint64_t color) {
|
|||||||
// text label
|
// text label
|
||||||
// str : text - supports multiple lines
|
// str : text - supports multiple lines
|
||||||
// color: background, text
|
// color: background, text
|
||||||
static inline void label(const char* str, int x, int y, int w, int h,
|
static inline void label(const char* s, int x, int y, int w, int h,
|
||||||
uint64_t color) {
|
uint64_t color) {
|
||||||
if (tim.event.type == DRAW_EVENT) {
|
if (tim.event.type == DRAW_EVENT) {
|
||||||
struct text s = scan_str(str);
|
struct text t = scan_str(s);
|
||||||
w = (w == A) ? s.width : w;
|
w = (w == A) ? t.width : w;
|
||||||
h = (h == A) ? s.lines : h;
|
h = (h == A) ? t.lines : h;
|
||||||
struct rect r = abs_xywh(x, y, w, h);
|
struct rect r = abs_xywh(x, y, w, h);
|
||||||
struct cell c = cell(" ", color, color >> 8);
|
struct cell c = cell(" ", color, color >> 8);
|
||||||
draw_lot(c, r.x, r.y, r.w, r.h);
|
draw_lot(c, r.x, r.y, r.w, r.h);
|
||||||
struct line l = {.str = str, .line = ""};
|
struct line l = {.s = s, .line = ""};
|
||||||
for (int i = 0; next_line(&l); i++) {
|
for (int i = 0; next_line(&l); i++) {
|
||||||
draw_str(l.line, r.x, r.y + i, l.width, c.fg, c.bg);
|
draw_str(l.line, r.x, r.y + i, l.width, c.fg, c.bg);
|
||||||
}
|
}
|
||||||
@@ -1113,46 +1122,48 @@ static inline bool button(const char* txt, int x, int y, int w, int h,
|
|||||||
/* edit ***********************************************************************/
|
/* edit ***********************************************************************/
|
||||||
|
|
||||||
static void edit_insert(struct edit* e, const char* s) {
|
static void edit_insert(struct edit* e, const char* s) {
|
||||||
int dst_size = ztrlen(e->str);
|
int dst_size = ztrlen(e->s);
|
||||||
int src_size = ztrlen(s);
|
int src_size = ztrlen(s);
|
||||||
if (dst_size + src_size + 1 < (int)sizeof(e->str)) {
|
if (dst_size + src_size < e->capacity) {
|
||||||
int len = utflen(s); // usually 1, except when smashing keys
|
int len = utflen(s); // usually 1, except when smashing keys
|
||||||
int cur = utfpos(e->str, e->cursor);
|
int cur = utfpos(e->s, e->cursor);
|
||||||
memmove(e->str + cur + src_size, e->str + cur, dst_size - cur);
|
memmove(e->s + cur + src_size, e->s + cur, dst_size - cur);
|
||||||
memmove(e->str + cur, s, src_size);
|
memmove(e->s + cur, s, src_size);
|
||||||
e->str[dst_size + src_size + 1] = 0;
|
e->s[dst_size + src_size] = 0;
|
||||||
e->length += len;
|
e->length += len;
|
||||||
e->cursor += len;
|
e->cursor += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void edit_delete(struct edit* e) {
|
static void edit_delete(struct edit* e) {
|
||||||
int size = ztrlen(e->str);
|
int size = ztrlen(e->s);
|
||||||
int cur = utfpos(e->str, e->cursor);
|
int cur = utfpos(e->s, e->cursor);
|
||||||
int len = utfpos(e->str + cur, 1);
|
int len = utfpos(e->s + cur, 1);
|
||||||
if (size - cur > 0) {
|
if (size - cur > 0) {
|
||||||
memmove(e->str + cur, e->str + cur + len, size - cur);
|
memmove(e->s + cur, e->s + cur + len, size - cur);
|
||||||
e->length -= 1;
|
e->length -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool edit_event(struct edit* e, struct rect r) {
|
/// @return key id or 0
|
||||||
|
static int edit_event(struct edit* e, struct rect r) {
|
||||||
if (is_click_over(r)) {
|
if (is_click_over(r)) {
|
||||||
// take focus
|
// take focus
|
||||||
tim.focus = (uintptr_t)e;
|
tim.focus = e;
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tim.focus != (uintptr_t)e || tim.event.type != KEY_EVENT) {
|
if (tim.focus != e || tim.event.type != KEY_EVENT) {
|
||||||
// not focused or no key press
|
// not focused or no key press
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
tim.event.type = VOID_EVENT; // consume event
|
tim.event.type = VOID_EVENT; // consume event
|
||||||
|
|
||||||
switch (tim.event.key) {
|
switch (tim.event.key) {
|
||||||
|
case ESCAPE_KEY:
|
||||||
case ENTER_KEY:
|
case ENTER_KEY:
|
||||||
tim.focus = 0; // release focus
|
tim.focus = 0; // release focus
|
||||||
return true;
|
break;
|
||||||
case DELETE_KEY:
|
case DELETE_KEY:
|
||||||
edit_delete(e);
|
edit_delete(e);
|
||||||
break;
|
break;
|
||||||
@@ -1174,40 +1185,42 @@ static bool edit_event(struct edit* e, struct rect r) {
|
|||||||
case END_KEY:
|
case END_KEY:
|
||||||
e->cursor = e->length;
|
e->cursor = e->length;
|
||||||
break;
|
break;
|
||||||
case ESCAPE_KEY:
|
|
||||||
tim.focus = 0; // release focus
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
if (tim.event.key >= ' ') {
|
if (tim.event.key >= ' ') {
|
||||||
edit_insert(e, tim.event.str);
|
edit_insert(e, tim.event.s);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return tim.event.key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// text edit - value in state
|
static inline void edit_init(struct edit* e, int capacity, const char* initial_content){
|
||||||
// e : persistent edit state
|
e->length = utflen(initial_content);
|
||||||
// color: frame, background, text
|
e->cursor = utflen(initial_content);
|
||||||
static inline bool edit(struct edit* e, int x, int y, int w, uint64_t color) {
|
e->capacity = capacity;
|
||||||
struct rect r = abs_xywh(x, y, w, 3);
|
e->s = malloc(capacity + 1);
|
||||||
|
int byte_len = strlen(initial_content);
|
||||||
|
memcpy(e->s, initial_content, byte_len);
|
||||||
|
e->s[byte_len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// uninitialized edit state
|
/// text edit - value in state
|
||||||
if (e->str[0] && e->cursor == 0 && e->length == 0) {
|
/// @param e persistent edit state, use edit_init() to create new state
|
||||||
e->length = utflen(e->str);
|
/// @param color frame, background, text
|
||||||
e->cursor = e->length;
|
/// @return key id or 0
|
||||||
}
|
static inline int edit(struct edit* e, int x, int y, int w, uint64_t color) {
|
||||||
|
struct rect r = abs_xywh(x, y, w, 3);
|
||||||
|
|
||||||
if (tim.event.type == DRAW_EVENT) {
|
if (tim.event.type == DRAW_EVENT) {
|
||||||
draw_box(r.x, r.y, r.w, r.h, color >> 16, color >> 8);
|
draw_box(r.x, r.y, r.w, r.h, color >> 16, color >> 8);
|
||||||
if (tim.focus == (uintptr_t)e) {
|
if (tim.focus == e) {
|
||||||
char* str = e->str + utfpos(e->str, e->cursor - r.w + 4);
|
char* s = e->s + utfpos(e->s, e->cursor - r.w + 4);
|
||||||
int cur = MIN(r.w - 4, e->cursor);
|
int cur = MIN(r.w - 4, e->cursor);
|
||||||
draw_str(str, r.x + 2, r.y + 1, r.w - 3, color, color >> 8);
|
draw_str(s, r.x + 2, r.y + 1, r.w - 3, color, color >> 8);
|
||||||
draw_invert(r.x + cur + 2, r.y + 1, 1);
|
draw_invert(r.x + cur + 2, r.y + 1, 1);
|
||||||
} else {
|
} else {
|
||||||
draw_str(e->str, r.x + 2, r.y + 1, r.w - 3, color, color >> 8);
|
draw_str(e->s, r.x + 2, r.y + 1, r.w - 3, color, color >> 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user