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 */
29typedef struct {
30 int flin;
31 int fcol;
32 int flen;
33 int ff;
34 char fill_char;
35 WINDOW *win;
36 bool cf_erase_remainder;
37} CmField;
38
40
41int cf_accept(WINDOW *win, char *accept_s, int flin, int fcol, int flen);
42
43/** @brief Accepts input for a field in a C-Menu window
44 @param win The window to accept input from
45 @param accept_s The string to accept input into
46 @param flin The line number of the field
47 @param fcol The column number of the field
48 @param flen The length of the field
49 @return The key pressed to exit the field (KEY_ENTER, KEY_F(9), etc.)
50 */
51int cf_accept(WINDOW *win, char *accept_s, int flin, int fcol, int flen) {
52 bool f_insert = FALSE;
53 int in_key = 0;
54 char *s, *d;
55 char *fstart;
56
57 click_x = click_y = -1;
58 char *p = fstart = accept_s;
59 char *fend = fstart + flen;
60 int x = fcol;
61 char *str_end = p + strlen(p);
62 while (1) {
63 if (in_key == 0) {
64 mvwaddstr(win, flin, fcol, accept_s);
65 wclrtoeol(win);
66 wmove(win, flin, x);
67 tcflush(0, TCIFLUSH);
68 in_key = vgetch(win, 0);
69 }
70 curs_set(0);
71 switch (in_key) {
72 case KEY_F(9):
73 in_key = KEY_F(9);
74 return (in_key);
75 case '\t':
76 case KEY_END:
77 case Ctrl('e'):
78 while (*p != '\0')
79 p++;
80 x = fcol + (p - fstart);
81 in_key = 0;
82 continue;
83 /**< Enter accepts the field and moves to the next field if
84 * f_erase_remainder is set, it will clear the remaining
85 * characters above and after the current cursor location */
86 case '\n':
87 case KEY_ENTER:
89 *p = '\0';
90 in_key = KEY_ENTER;
91 return (in_key);
92 /** KEY_IC toggles insert mode */
93 case KEY_IC:
94 f_insert = !f_insert;
95 in_key = 0;
96 continue;
97 /** KEY_DC deletes character at cursor */
98 case KEY_DC:
99 s = p + 1;
100 d = p;
101 while (*s != '\0')
102 *d++ = *s++;
103 *d = '\0';
104 str_end = d;
105 f_insert = FALSE;
106 in_key = 0;
107 continue;
108 /** KEY_HOME moves cursor to start of field */
109 case KEY_HOME:
110 case Ctrl('a'):
111 p = fstart;
112 x = fcol;
113 in_key = 0;
114 continue;
115 /** KEY_BACKSPACE deletes character before cursor */
116 case KEY_BACKSPACE:
117 if (p > fstart) {
118 p--;
119 x--;
120 }
121 s = p + 1;
122 d = p;
123 while (*s != '\0')
124 *d++ = *s++;
125 *d = '\0';
126 str_end = d;
127 in_key = 0;
128 continue;
129 /** KEY_LEFT moves cursor left one character */
130 case KEY_LEFT:
131 if (p > fstart) {
132 p--;
133 x--;
134 }
135 in_key = 0;
136 continue;
137 /** KEY_RIGHT moves cursor right one character */
138 case KEY_RIGHT:
139 if (p < fend && p < str_end) {
140 p++;
141 x++;
142 }
143 in_key = 0;
144 continue;
145 /** Handles mouse events for field editing */
146 case KEY_MOUSE:
147 x = click_x;
148 flin = click_y;
149 fstart = accept_s;
150 fend = fstart + flen;
151 str_end = fstart + strlen(fstart);
152 p = fstart + (x - fcol);
153 if (p > str_end)
154 x -= p - str_end;
155 p = min(p, str_end);
156 in_key = 0;
157 continue;
158 default:
159 if (p >= fend) {
160 in_key = 0;
161 continue;
162 }
163 if (in_key < ' ' || in_key > '~') {
164 in_key = 0;
165 continue;
166 }
167 if (f_insert) {
168 if (str_end < fend) {
169 s = str_end - 1;
170 d = str_end;
171 while (s >= p)
172 *d-- = *s--;
173 *p++ = in_key;
174 str_end++;
175 x++;
176 }
177 } else {
178 if (p < fend) {
179 if (p < str_end) {
180 if (p == accept_s && in_key == ' ') {
181 d = accept_s;
182 s = accept_s + 1;
183 while (*s != '\0')
184 *d++ = *s++;
185 *d = '\0';
186 in_key = 0;
187 continue;
188 }
189 *p++ = in_key;
190 x++;
191 } else if (p == str_end) {
192 *p++ = in_key;
193 *p = '\0';
194 str_end = p;
195 x++;
196 }
197 }
198 }
199 in_key = 0;
200 continue;
201 }
202 }
203}
int click_x
Definition dwin.c:81
int click_y
Definition dwin.c:80
#define min(x, y)
min macro evaluates two expressions, returning least result
Definition cm.h:89
#define Ctrl(c)
Definition cm.h:52
#define FALSE
Definition iloan.c:18
int cf_accept(WINDOW *win, char *accept_s, int flin, int fcol, int flen)
Accepts input for a field in a C-Menu window.
Definition cm_fields.c:51
bool f_erase_remainder
Definition cm_fields.c:39
int vgetch(WINDOW *, int)
Wrapper for wgetch that handles signals and mouse events, and accepts a single character answer.
Definition dwin.c:2258