Renamed every 'str' fiend and variable to 's'. Implemented edit_init.
This commit is contained in:
135
tim.h
135
tim.h
@@ -117,9 +117,10 @@
|
||||
//
|
||||
// edit (state, x, y, w, color) -> bool
|
||||
//
|
||||
// Draw text edit. Output is stored in state.str. Receives input events when
|
||||
// focused by mouse click. Escape or return relinquish focus. Returns true
|
||||
// when return is pressed.
|
||||
// Draw text edit. Output is stored in state.s.
|
||||
// Receives input events when focused by mouse click or by setting focus manually.
|
||||
// Escape or return relinquish focus.
|
||||
// Returns key id if received key input.
|
||||
//
|
||||
// state pointer to persistent edit state struct
|
||||
// x/y/w see layout documentation
|
||||
@@ -357,7 +358,7 @@ struct text {
|
||||
};
|
||||
|
||||
struct line {
|
||||
const char* str; // input and parse state
|
||||
const char* s; // input and parse state
|
||||
const char* line; // line strings, not terminated
|
||||
int size; // line size in bytes
|
||||
int width; // line width in glyph
|
||||
@@ -368,13 +369,14 @@ struct event {
|
||||
int32_t key; // used by KEY_EVENT and MOUSE_EVENT
|
||||
int x; // 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 {
|
||||
int cursor; // cursor position (utf8)
|
||||
int length; // string length (utf8)
|
||||
char str[256]; // zero terminated buffer
|
||||
int capacity; // buffer size
|
||||
char* s; // zero terminated buffer
|
||||
};
|
||||
|
||||
struct state {
|
||||
@@ -382,7 +384,7 @@ struct state {
|
||||
int h; // screen height
|
||||
int frame; // frame counter
|
||||
struct event event; // current event
|
||||
uintptr_t focus; // focused element
|
||||
void* focus; // focused element
|
||||
int loop_stage; // loop stage
|
||||
bool resized; // screen was resized
|
||||
int scope; // current scope
|
||||
@@ -436,8 +438,12 @@ struct state tim = {
|
||||
|
||||
// like strlen, returns 0 on NULL or int overflow
|
||||
static inline int ztrlen(const char* s) {
|
||||
size_t n = s ? strlen(s) : 0;
|
||||
return MAX((int)n, 0);
|
||||
if(s == NULL)
|
||||
return 0;
|
||||
int n = strlen(s);
|
||||
if(n < 0)
|
||||
n = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
// bit scan reverse, count leading zeros
|
||||
@@ -494,8 +500,9 @@ static int utfpos(const char* s, int pos) {
|
||||
}
|
||||
|
||||
// scan string for width and lines
|
||||
static struct text scan_str(const char* str) {
|
||||
const char* s = str ? str : "";
|
||||
static struct text scan_str(const char* s) {
|
||||
if(s == NULL)
|
||||
s = "";
|
||||
struct text t = {
|
||||
.width = 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
|
||||
static bool next_line(struct line* l) {
|
||||
if (!l->str || !l->str[0]) {
|
||||
if (!l->s || !l->s[0]) {
|
||||
return false;
|
||||
}
|
||||
l->line = l->str;
|
||||
l->line = l->s;
|
||||
l->size = 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->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;
|
||||
}
|
||||
|
||||
@@ -563,7 +570,8 @@ static void signal_handler(int signal) {
|
||||
static void update_screen_size(void) {
|
||||
struct winsize 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 h = ws.ws_row;
|
||||
@@ -601,9 +609,9 @@ static void reset_terminal(void) {
|
||||
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) {
|
||||
char* s = e->str;
|
||||
char* s = e->s;
|
||||
|
||||
if (n == 1 || s[0] != 27) {
|
||||
// regular key press
|
||||
@@ -694,7 +702,7 @@ static void read_event(int timeout_ms) {
|
||||
|
||||
if (pfd[1].revents & POLLIN) {
|
||||
// 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)) {
|
||||
return;
|
||||
}
|
||||
@@ -727,7 +735,8 @@ static void update_screen_size(void) {
|
||||
HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
CONSOLE_SCREEN_BUFFER_INFO 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 h = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
|
||||
@@ -839,7 +848,7 @@ static void read_event(int timeout_ms) {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
return;
|
||||
}
|
||||
@@ -1076,16 +1085,16 @@ static inline void frame(int x, int y, int w, int h, uint64_t color) {
|
||||
// text label
|
||||
// str : text - supports multiple lines
|
||||
// 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) {
|
||||
if (tim.event.type == DRAW_EVENT) {
|
||||
struct text s = scan_str(str);
|
||||
w = (w == A) ? s.width : w;
|
||||
h = (h == A) ? s.lines : h;
|
||||
struct text t = scan_str(s);
|
||||
w = (w == A) ? t.width : w;
|
||||
h = (h == A) ? t.lines : h;
|
||||
struct rect r = abs_xywh(x, y, w, h);
|
||||
struct cell c = cell(" ", color, color >> 8);
|
||||
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++) {
|
||||
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 ***********************************************************************/
|
||||
|
||||
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);
|
||||
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 cur = utfpos(e->str, e->cursor);
|
||||
memmove(e->str + cur + src_size, e->str + cur, dst_size - cur);
|
||||
memmove(e->str + cur, s, src_size);
|
||||
e->str[dst_size + src_size + 1] = 0;
|
||||
int cur = utfpos(e->s, e->cursor);
|
||||
memmove(e->s + cur + src_size, e->s + cur, dst_size - cur);
|
||||
memmove(e->s + cur, s, src_size);
|
||||
e->s[dst_size + src_size] = 0;
|
||||
e->length += len;
|
||||
e->cursor += len;
|
||||
}
|
||||
}
|
||||
|
||||
static void edit_delete(struct edit* e) {
|
||||
int size = ztrlen(e->str);
|
||||
int cur = utfpos(e->str, e->cursor);
|
||||
int len = utfpos(e->str + cur, 1);
|
||||
int size = ztrlen(e->s);
|
||||
int cur = utfpos(e->s, e->cursor);
|
||||
int len = utfpos(e->s + cur, 1);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
// take focus
|
||||
tim.focus = (uintptr_t)e;
|
||||
return false;
|
||||
tim.focus = e;
|
||||
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
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
tim.event.type = VOID_EVENT; // consume event
|
||||
|
||||
switch (tim.event.key) {
|
||||
case ESCAPE_KEY:
|
||||
case ENTER_KEY:
|
||||
tim.focus = 0; // release focus
|
||||
return true;
|
||||
break;
|
||||
case DELETE_KEY:
|
||||
edit_delete(e);
|
||||
break;
|
||||
@@ -1174,40 +1185,42 @@ static bool edit_event(struct edit* e, struct rect r) {
|
||||
case END_KEY:
|
||||
e->cursor = e->length;
|
||||
break;
|
||||
case ESCAPE_KEY:
|
||||
tim.focus = 0; // release focus
|
||||
break;
|
||||
default:
|
||||
if (tim.event.key >= ' ') {
|
||||
edit_insert(e, tim.event.str);
|
||||
edit_insert(e, tim.event.s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
return tim.event.key;
|
||||
}
|
||||
|
||||
// text edit - value in state
|
||||
// e : persistent edit state
|
||||
// color: frame, background, text
|
||||
static inline bool edit(struct edit* e, int x, int y, int w, uint64_t color) {
|
||||
struct rect r = abs_xywh(x, y, w, 3);
|
||||
static inline void edit_init(struct edit* e, int capacity, const char* initial_content){
|
||||
e->length = utflen(initial_content);
|
||||
e->cursor = utflen(initial_content);
|
||||
e->capacity = capacity;
|
||||
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
|
||||
if (e->str[0] && e->cursor == 0 && e->length == 0) {
|
||||
e->length = utflen(e->str);
|
||||
e->cursor = e->length;
|
||||
}
|
||||
/// text edit - value in state
|
||||
/// @param e persistent edit state, use edit_init() to create new state
|
||||
/// @param color frame, background, text
|
||||
/// @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) {
|
||||
draw_box(r.x, r.y, r.w, r.h, color >> 16, color >> 8);
|
||||
if (tim.focus == (uintptr_t)e) {
|
||||
char* str = e->str + utfpos(e->str, e->cursor - r.w + 4);
|
||||
if (tim.focus == e) {
|
||||
char* s = e->s + utfpos(e->s, e->cursor - r.w + 4);
|
||||
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);
|
||||
} 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