C-Menu 0.2.9
A User Interface Toolkit
Loading...
Searching...
No Matches
menu_engine.c
Go to the documentation of this file.
1/** @file menu_engine.c
2 @brief The working part of C-Menu Menu
3 @author Bill Waller
4 Copyright (c) 2025
5 MIT License
6 billxwaller@gmail.com
7 @date 2026-02-09
8 */
9
10/** @defgroup menu_engine Menu Engine
11 @brief Main loop and command processor for the C-Menu menu system
12 @details This module contains the core functionality for displaying menus,
13 processing user input, and executing commands associated with menu choices.
14 It handles navigation through menu options, responding to special keys,
15 and managing the display of submenus, pick lists, forms, and views.
16 */
17
18#include <common.h>
19#include <ctype.h>
20#include <stdlib.h>
21#include <string.h>
22#include <termios.h>
23#include <unistd.h>
24
25unsigned int menu_engine(Init *);
26unsigned int menu_cmd_processor(Init *);
27
28/** @brief The main loop of the menu system.
29 @ingroup menu_engine
30 @param init A pointer to an Init structure containing initialization data for
31 the menu system.
32 @returns an integer indicating the action taken by the user, such as
33 returning to the main menu or exiting the menu system.
34 @note displays the menu and processes user input until the user exits the
35 menu or returns to the main menu.
36 */
37unsigned int menu_engine(Init *init) {
38 int action;
39 int i;
40 char tmp_str[MAXLEN];
41 Menu *menu = init->menu;
42 if (menu == nullptr) {
43 Perror("menu_engine: menu is nullptr");
44 return (1);
45 }
46 menu->lines = 0;
47 menu->cols = 0;
48 menu->line_idx = 0;
49 menu->item_count = 0;
50 menu->title[0] = '\0';
51 menu->choice_max_len = 0;
52 menu->text_max_len = 0;
54 if (win_new(menu->lines, menu->cols, menu->begy, menu->begx, menu->title,
55 0)) {
56 ssnprintf(tmp_str, MAXLEN - 1, "win_new(%d, %d, %d, %d, %s, %b) failed",
57 menu->lines, menu->cols, menu->begy, menu->begx, menu->title,
58 0);
59 Perror(tmp_str);
60 return 1;
61 }
62 menu->win = win_win[win_ptr];
63 menu->box = win_box[win_ptr];
64
65 action = MA_DISPLAY_MENU;
66 while (action) {
67 switch (action) {
68 case MA_RETURN:
70 if (win_ptr < 0) {
72 return 0;
73 }
74 menu->win = win_win[win_ptr];
75 menu->box = win_box[win_ptr];
77 return 0;
78 case MA_DISPLAY_MENU:
79 for (menu->line_idx = 0; menu->line_idx < menu->item_count;
80 menu->line_idx++) {
81 mvwaddstr(menu->win, menu->line_idx, 0,
83 }
84 action = MA_RESET_MENU;
85 break;
86 case MA_RESET_MENU:
87 menu->line_idx = 0;
88 for (i = 0; i < menu->item_count; i++) {
89 if (menu->line[i]->type == MT_CHOICE) {
90 menu->line_idx = i;
91 break;
92 }
93 }
94 action = MA_CONTINUE;
95 break;
96 case MA_CONTINUE:
97 while ((action = menu_cmd_processor(init)) == MA_CONTINUE)
98 ;
99 break;
100 default:
101 break;
102 }
103 }
104 destroy_menu(init);
105 return 0;
106}
107/** @brief Processes user input for the menu system.
108 @ingroup menu_engine
109 @param init A pointer to an Init structure containing initialization data
110 for the menu system.
111 @returns an integer indicating the action taken by the user, such as
112 returning to the main menu, displaying a submenu, or executing a command
113 associated with a menu choice.
114 @note handles navigation through the menu options, executing commands
115 associated with menu choices, and responding to special keys such as
116 function keys and mouse clicks.
117 */
118unsigned int menu_cmd_processor(Init *init) {
119 int i, c;
120 char *d;
121 int in_key;
122 char tmp_str[MAXLEN];
123
124 Menu *menu = init->menu;
125 keypad(menu->win, TRUE);
126 mousemask(BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED, nullptr);
127 MEVENT event;
128
129 wattron(menu->win, A_REVERSE);
132 wattroff(menu->win, A_REVERSE);
133
134 event.y = event.x = -1;
135 // tcflush(2, TCIFLUSH);
136 wmove(menu->win, menu->line_idx, 1);
137 in_key = xwgetch(menu->win, nullptr, -1);
138
141 switch (in_key) {
142 /** Move up to the previous menu choice */
143 case KEY_UP:
144 i = menu->line_idx;
145 while (i > 0) {
146 i--;
147 if (menu->line[i]->type == MT_CHOICE) {
148 menu->line_idx = i;
149 break;
150 }
151 }
152 return (MA_CONTINUE);
153 /** Move down to the next menu choice */
154 case KEY_DOWN:
155 i = menu->line_idx;
156 while (i < menu->item_count - 1) {
157 i++;
158 if (menu->line[i]->type == MT_CHOICE) {
159 menu->line_idx = i;
160 break;
161 }
162 }
163 return (MA_CONTINUE);
164 /** Select the current menu choice and execute its associated
165 * command */
166 case '\n':
167 case KEY_ENTER:
168 break;
169 /** @brief Display help information for the menu system */
170 case '?':
171 case KEY_F(1):
172 if (menu->f_help_spec && menu->help_spec[0] != '\0')
173 strnz__cpy(tmp_str, menu->help_spec, MAXLEN - 1);
174 else {
175 strnz__cpy(tmp_str, init->mapp_help, MAXLEN - 1);
176 strnz__cat(tmp_str, "/", MAXLEN - 1);
178 }
179 eargc = 0;
180 eargv[eargc++] = strdup("view");
181 eargv[eargc++] = strdup("-N");
182 eargv[eargc++] = strdup("f");
183 eargv[eargc++] = strdup(tmp_str);
185 init->lines = 30;
186 init->cols = 60;
187 init->begy = menu->begy + 1;
188 init->begx = menu->begx + 1;
189 strnz__cpy(init->title, "Menu Help", MAXLEN - 1);
191 init->begx);
193 return (MA_DISPLAY_MENU);
194 /** Exit the menu and return to the previous menu or exit if at top
195 */
196 case KEY_F(9):
197 case KEY_BREAK:
198 return (MA_RETURN);
199 /** @brief send default printer output file to printer */
200 case KEY_ALTF(9):
201 d = getenv("PRTCMD");
202 if (d == nullptr || *d == '\0')
204 else
207 d = getenv("PRTFILE");
208 if (d == nullptr || *d == '\0') {
209 d = getenv("HOME");
210 if (d == nullptr || *d == '\0')
212 else {
216 }
217 } else
220 return (MA_RESET_MENU);
221 /** @brief open the default editor */
222 case KEY_ALTF(10):
224 return (MA_DISPLAY_MENU);
225 /** @brief process mouse event */
226 case KEY_MOUSE:
227 if (click_y == -1 || click_x == -1)
228 return (MA_CONTINUE);
229 if (click_y < 0 || click_y >= menu->item_count)
230 return (MA_CONTINUE);
231 menu->line_idx = click_y;
232 break;
233 default:
234 /** @brief If the user presses a key that corresponds to a menu
235 * choice's letter, select that menu choice */
236 for (i = 0; i < menu->item_count; i++) {
237 if (menu->line[i]->raw_text[0] == '_') {
238 if (menu->line[i]->choice_letter == (char)in_key) {
239 menu->line_idx = i;
240 break;
241 }
242 } else {
243 if (menu->line[i]->choice_letter == toupper((char)in_key)) {
244 menu->line_idx = i;
245 break;
246 }
247 }
248 }
249 if (i >= menu->item_count)
250 return (MA_CONTINUE);
251 break;
252 }
253 c = (int)menu->line[menu->line_idx]->command_type;
254 switch (c) {
255 /** @brief Execute the command associated with the selected menu
256 * choice
257 */
258 case CT_EXEC:
259 char *s;
260 s = strpbrk(menu->line[menu->line_idx]->command_str, " \t\f\v");
266 return (MA_RESET_MENU);
267 /** @brief Display help information for the menu system */
268 case CT_HELP:
269 if (menu->f_help_spec && menu->help_spec[0] != '\0')
270 strnz__cpy(tmp_str, menu->help_spec, MAXLEN - 1);
271 else {
272 strnz__cpy(tmp_str, init->mapp_help, MAXLEN - 1);
273 strnz__cat(tmp_str, "/", MAXLEN - 1);
275 }
276 eargc = 0;
277 eargv[eargc++] = strdup("view");
278 eargv[eargc++] = strdup("-N");
279 eargv[eargc++] = strdup("f");
280 eargv[eargc++] = strdup(tmp_str);
282 init->lines = 66;
283 init->cols = 80;
284 init->begy = menu->begy + 1;
285 init->begx = menu->begx + 1;
286 strnz__cpy(init->title, "Menu Help", MAXLEN - 1);
288 init->begx);
290 return (MA_DISPLAY_MENU);
291 /** @brief Display a submenu or perform an action associated with
292 * the selected menu choice */
293 case CT_MENU:
295 MAXLEN - 1);
297 if (eargc == 0)
298 return (MA_DISPLAY_MENU);
299 zero_opt_args(init);
301 if (init->begy == 0)
302 init->begy = menu->begy + 1;
303 if (init->begx == 0)
304 init->begx = menu->begx + 1;
305 Menu *save_menu = init->menu;
306 init->menu = nullptr;
307 init->menu = new_menu(init, eargc, eargv, init->begy, init->begx);
308 if (!init->menu)
309 abend(-1, "menu_cmd_processor: new_menu() failed");
310 // menu = init->menu;
312 menu_engine(init);
314 init->menu = destroy_menu(init);
315 init->menu = save_menu;
316 menu = init->menu;
317 return (MA_RESET_MENU);
318 /** @brief Display a pick list or form associated with the selected
319 * menu choice */
320 case CT_PICK:
322 MAXLEN - 1);
324 popup_pick(init, eargc, eargv, menu->begy + 1, menu->begx + 1);
326 return (MA_DISPLAY_MENU);
327 /** @brief Display a form associated with the selected menu choice
328 */
329 case CT_FORM:
331 MAXLEN - 1);
333 popup_form(init, eargc, eargv, menu->begy + 1, menu->begx + 1);
335 return (MA_RESET_MENU);
336 /** @brief Display a view associated with the selected menu choice
337 */
338 case CT_VIEW:
340 MAXLEN - 1);
342 init->lines = 66;
343 init->cols = 80;
344 init->begy = menu->begy + 1;
345 init->begx = menu->begx + 1;
347 MAXLEN - 1);
349 init->begx);
351 return (MA_DISPLAY_MENU);
352 /** @brief open ckeys (test curses keys) */
353 case CT_CKEYS:
355 return (MA_DISPLAY_MENU);
356 /** @brief return to calling program */
357 case CT_RETURN:
358 return (MA_RETURN);
359 /** @brief write the current menu configuration to a file */
360 case CT_WRITE_CONFIG:
361 write_config(init);
362 return (MA_CONTINUE);
363 default:
364 return (MA_CONTINUE);
365 }
366 return 0;
367}
#define PRINTCMD
Definition common.h:46
#define VIEW_PRT_FILE
Definition common.h:40
int popup_form(Init *, int, char **, int, int)
Definition popups.c:34
#define MENU_HELP_FILE
Definition common.h:36
int popup_view(Init *, int, char **, int, int, int, int)
Definition popups.c:47
int parse_opt_args(Init *, int, char **)
Definition init.c:393
int popup_pick(Init *, int, char **, int, int)
Definition popups.c:21
int eargc
Definition futil.c:41
#define MAX_ARGS
Definition cm.h:28
char earg_str[MAXLEN]
Definition futil.c:40
#define nullptr
Definition cm.h:23
char * eargv[MAXARGS]
Definition futil.c:42
#define KEY_ALTF(n)
Definition cm.h:346
@ MT_CHOICE
Definition menu.h:22
@ MA_RETURN
Definition menu.h:25
@ MA_DISPLAY_MENU
Definition menu.h:25
@ MA_RESET_MENU
Definition menu.h:25
@ MA_CONTINUE
Definition menu.h:25
@ CT_PICK
Definition menu.h:37
@ CT_FORM
Definition menu.h:33
@ CT_MENU
Definition menu.h:36
@ CT_RETURN
Definition menu.h:40
@ CT_HELP
Definition menu.h:31
@ CT_WRITE_CONFIG
Definition menu.h:42
@ CT_EXEC
Definition menu.h:30
@ CT_VIEW
Definition menu.h:38
@ CT_CKEYS
Definition menu.h:39
#define TRUE
Definition iloan.c:19
int popup_ckeys()
Display Curses Keys Responds to curses keys and mouse events, displaying the key code and description...
Definition curskeys.c:23
#define MAXLEN
Definition curskeys.c:15
WINDOW * win_win[MAXWIN]
Definition dwin.c:114
int click_x
Definition dwin.c:45
int win_ptr
Definition dwin.c:121
int click_y
Definition dwin.c:44
WINDOW * win_box[MAXWIN]
Definition dwin.c:115
int xwgetch(WINDOW *, Chyron *, int)
Wrapper for wgetch that handles signals, mouse events, checks for clicks on the chyron line,...
Definition dwin.c:1359
void restore_wins()
Restore all windows after a screen resize.
Definition dwin.c:938
int win_new(int, int, int, int, char *, int)
Create a new window with optional box and title.
Definition dwin.c:783
WINDOW * win_del()
Delete the current window and its associated box window.
Definition dwin.c:902
void mvwaddstr_fill(WINDOW *, int, int, char *, int)
For lines shorter than their display area, fill the rest with spaces.
Definition dwin.c:1262
int Perror(char *)
Display a simple error message window or print to stderr.
Definition dwin.c:1110
void abend(int, char *)
Abnormal program termination.
Definition dwin.c:1331
int full_screen_fork_exec(char **)
Execute a command in full screen mode.
Definition exec.c:44
int full_screen_shell(char *)
Execute a shell command in full screen mode.
Definition exec.c:60
void destroy_argv(int argc, char **argv)
Deallocates memory allocated for argument strings in argv.
Definition futil.c:221
size_t strnz__cpy(char *, const char *, size_t)
safer alternative to strncpy
Definition futil.c:269
size_t trim(char *)
Trims leading and trailing spaces from string s in place.
Definition futil.c:118
size_t ssnprintf(char *, size_t, const char *,...)
ssnprintf was designed to be a safer alternative to snprintf.
Definition futil.c:147
size_t strnz__cat(char *, const char *, size_t)
safer alternative to strncat
Definition futil.c:298
int str_to_args(char **, char *, int)
Converts a string into an array of argument strings.
Definition futil.c:167
int write_config(Init *)
Write the current configuration to a file specified in init->minitrc.
Definition init.c:723
void zero_opt_args(Init *)
Initialize optional arguments in the Init struct to default values.
Definition init.c:408
Menu * new_menu(Init *, int, char **, int, int)
Create and initialize Menu structure.
Definition mem.c:148
Menu * destroy_menu(Init *init)
Destroy Menu structure.
Definition mem.c:169
unsigned int menu_engine(Init *)
The main loop of the menu system.
Definition menu_engine.c:37
unsigned int menu_cmd_processor(Init *)
Processes user input for the menu system.
unsigned int parse_menu_description(Init *)
Parse menu description file and create Menu.
char title[MAXLEN]
Definition common.h:123
char mapp_help[MAXLEN]
Definition common.h:140
int begx
Definition common.h:112
int cols
Definition common.h:110
int begy
Definition common.h:111
Menu * menu
Definition common.h:172
int lines
Definition common.h:109
char * choice_text
Definition menu.h:54
char * raw_text
Definition menu.h:51
char * command_str
Definition menu.h:70
unsigned int type
Definition menu.h:49
unsigned int command_type
Definition menu.h:64
char choice_letter
Definition menu.h:57
int cols
Definition menu.h:92
Line * line[MAX_MENU_LINES]
Definition menu.h:194
bool f_help_spec
Definition menu.h:153
WINDOW * win
Definition menu.h:100
WINDOW * box
Definition menu.h:103
int begy
Definition menu.h:94
int text_max_len
Definition menu.h:181
int item_count
Definition menu.h:187
int choice_max_len
Definition menu.h:175
int line_idx
Definition menu.h:190
char help_spec[MAXLEN]
Definition menu.h:121
int lines
Definition menu.h:90
char title[MAXLEN]
Definition menu.h:106
int begx
Definition menu.h:97