C-Menu 0.2.9
A User Interface Toolkit
Loading...
Searching...
No Matches
cm_fields.c
Go to the documentation of this file.
1/** @file cm_fields.c
2 @brief Stand-alone Field Edit and Entry for C-Menu
3 @details Currently, this modules contains a single function, cf_accept(),
4 a lightweight yet fully functional field editor. For text fields, it is
5 equivalent to the field editor in fields.c. Instead of the built-in
6 formatting and validation in fields.c, this module provides a clean slate
7 for a modular plug-in architecture to accomodate formatting, validation, and
8 high-precision numeric data. It will eventually replace the field editor in
9 fields.c. It is a work in progress.
10 @author Bill Waller
11 Copyright (c) 2025, 2026
12 MIT License
13 billxwaller@gmail.com
14 @date 2026-02-09
15 */
16
17#include <common.h>
18#include <monetary.h>
19#include <stdbool.h>
20#include <stddef.h>
21#include <string.h>
22#include <termios.h>
23#include <unistd.h>
24
25/** @brief Structure to hold field information for C-Menu
26 @note Not currently used in the code, but may be used in
27 future versions of C-Menu
28 */
29
31
32/** @brief Accepts input for a field in a C-Menu window
33 @param UiSurface *sfc The surface to accept input from
34 @param win The window to accept input from
35 @param accept_s The string to accept input into
36 @param flin The line number of the field
37 @param fcol The column number of the field
38 @param flen The length of the field
39 @return The key pressed to exit the field (KEY_ENTER, KEY_F09, etc.)
40 */
41int cf_accept(UiSurface *sfc, uint w, char *accept_s, uint flin, uint fcol, uint flen) {
42 bool f_insert = false;
43 int in_key = 0;
44 char *s, *d;
45 char *fstart;
46 UiEvent event;
47
48 click_x = click_y = -1;
49 char *p = fstart = accept_s;
50 char *fend = fstart + flen;
51 int x = fcol;
52 char *str_end = p + strlen(p);
53 while (1) {
54 if (in_key == 0) {
55 ui_mvwaddstr(sfc, w, flin, fcol, accept_s);
56 ui_wclrtoeol(sfc, w);
57 ui_cursor_move(sfc, w, flin, x);
59 in_key = ui_get_event(sfc, WIN, &event, -1);
60 }
62 switch (in_key) {
63 case KEY_F09:
64 in_key = KEY_F09;
65 return (in_key);
66 case '\t':
67 case KEY_END:
68 case Ctrl('e'):
69 while (*p != '\0')
70 p++;
71 x = fcol + (p - fstart);
72 in_key = 0;
73 continue;
74 /**< Enter accepts the field and moves to the next field if
75 * f_erase_remainder is set, it will clear the remaining
76 * characters above and after the current cursor location */
77 case '\n':
78 case KEY_ENTER:
80 *p = '\0';
81 in_key = KEY_ENTER;
82 return (in_key);
83 /** KEY_IC toggles insert mode */
84 case KEY_IC:
85 f_insert = !f_insert;
86 in_key = 0;
87 continue;
88 /** KEY_DC deletes character at cursor */
89 case KEY_DC:
90 s = p + 1;
91 d = p;
92 while (*s != '\0')
93 *d++ = *s++;
94 *d = '\0';
95 str_end = d;
96 f_insert = false;
97 in_key = 0;
98 continue;
99 /** KEY_HOME moves cursor to start of field */
100 case KEY_HOME:
101 case Ctrl('a'):
102 p = fstart;
103 x = fcol;
104 in_key = 0;
105 continue;
106 /** KEY_BACKSPACE deletes character before cursor */
107 case KEY_BACKSPACE:
108 if (p > fstart) {
109 p--;
110 x--;
111 }
112 s = p + 1;
113 d = p;
114 while (*s != '\0')
115 *d++ = *s++;
116 *d = '\0';
117 str_end = d;
118 in_key = 0;
119 continue;
120 /** KEY_LEFT moves cursor left one character */
121 case KEY_LEFT:
122 if (p > fstart) {
123 p--;
124 x--;
125 }
126 in_key = 0;
127 continue;
128 /** KEY_RIGHT moves cursor right one character */
129 case KEY_RIGHT:
130 if (p < fend && p < str_end) {
131 p++;
132 x++;
133 }
134 in_key = 0;
135 continue;
136 /** Handles mouse events for field editing */
137 case KEY_MOUSE:
138 x = click_x;
139 flin = click_y;
140 fstart = accept_s;
141 fend = fstart + flen;
142 str_end = fstart + strlen(fstart);
143 p = fstart + (x - fcol);
144 if (p > str_end)
145 x -= p - str_end;
146 p = min(p, str_end);
147 in_key = 0;
148 continue;
149 default:
150 if (p >= fend) {
151 in_key = 0;
152 continue;
153 }
154 if (in_key < ' ' || in_key > '~') {
155 in_key = 0;
156 continue;
157 }
158 if (f_insert) {
159 if (str_end < fend) {
160 s = str_end - 1;
161 d = str_end;
162 while (s >= p)
163 *d-- = *s--;
164 *p++ = in_key;
165 str_end++;
166 x++;
167 }
168 } else {
169 if (p < fend) {
170 if (p < str_end) {
171 if (p == accept_s && in_key == ' ') {
172 d = accept_s;
173 s = accept_s + 1;
174 while (*s != '\0')
175 *d++ = *s++;
176 *d = '\0';
177 in_key = 0;
178 continue;
179 }
180 *p++ = in_key;
181 x++;
182 } else if (p == str_end) {
183 *p++ = in_key;
184 *p = '\0';
185 str_end = p;
186 x++;
187 }
188 }
189 }
190 in_key = 0;
191 continue;
192 }
193 }
194}
#define min(x, y)
min macro evaluates two expressions, returning least result
Definition cm.h:91
#define Ctrl(c)
Definition cm.h:54
void ui_render()
Definition ui_ncurses.c:800
int ui_cursor_move(UiSurface *s, uint w, uint y, uint x)
Definition ui_ncurses.c:727
int ui_mvwaddstr(UiSurface *s, uint w, uint y, uint x, const char *text)
int ui_get_event(UiSurface *s, uint w, UiEvent *ev, int timeout_ms)
Wait for an input event on target (or stdscr if NULL).
int ui_wclrtoeol(UiSurface *s, uint w)
int ui_curs_set(int visibility)
Definition ui_ncurses.c:737
#define KEY_F09
#define KEY_RIGHT
#define KEY_DC
#define KEY_BACKSPACE
#define KEY_END
#define KEY_ENTER
#define KEY_MOUSE
#define KEY_IC
#define KEY_LEFT
#define KEY_HOME
int cf_accept(UiSurface *sfc, uint w, char *accept_s, uint flin, uint fcol, uint flen)
Accepts input for a field in a C-Menu window.
Definition cm_fields.c:41
bool f_erase_remainder
Structure to hold field information for C-Menu.
Definition cm_fields.c:30
int click_x
Definition dwin.c:45
int click_y
Definition dwin.c:44