Renamed every 'str' fiend and variable to 's'. Implemented edit_init.

This commit is contained in:
2026-01-09 00:46:42 +05:00
parent 11589d4623
commit b725182544
4 changed files with 95 additions and 81 deletions

135
tim.h
View File

@@ -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);
}
}