]>
Commit | Line | Data |
---|---|---|
d5a8d3e8 | 1 | #include "config.h" |
2 | ||
139f06bc | 3 | #include <slang.h> |
6fb96a3f | 4 | #include <stdio.h> |
5 | #include <stdlib.h> | |
6 | #include <string.h> | |
ae1235d0 | 7 | #include <sys/signal.h> |
6fb96a3f | 8 | #include <sys/time.h> |
9 | #include <sys/types.h> | |
91be88a7 | 10 | #include <termios.h> |
ad8aa646 | 11 | #include <time.h> |
6fb96a3f | 12 | #include <unistd.h> |
349586bb | 13 | #include <wchar.h> |
6fb96a3f | 14 | |
d5a8d3e8 | 15 | #ifdef HAVE_ALLOCA_H |
16 | #include <alloca.h> | |
17 | #endif | |
18 | ||
6fb96a3f | 19 | #include "newt.h" |
20 | #include "newt_pr.h" | |
21 | ||
6fb96a3f | 22 | struct Window { |
23 | int height, width, top, left; | |
6a1d8e87 | 24 | SLsmg_Char_Type * buffer; |
aa47774f | 25 | char * title; |
6fb96a3f | 26 | }; |
27 | ||
28 | struct keymap { | |
29 | char * str; | |
30 | int code; | |
31 | char * tc; | |
32 | }; | |
33 | ||
a1f11019 | 34 | static struct Window windowStack[20]; |
35 | static struct Window * currentWindow = NULL; | |
6fb96a3f | 36 | |
a1f11019 | 37 | static char * helplineStack[20]; |
38 | static char ** currentHelpline = NULL; | |
39 | ||
40 | static int cursorRow, cursorCol; | |
5e171db1 | 41 | static int cursorOn = 1; |
9b146a9f | 42 | static int noFlowCtrl = 0; |
7ff5fd71 | 43 | static int trashScreen = 0; |
0593cb33 | 44 | extern int needResize; |
81361f3e | 45 | |
6605d1bf | 46 | static const char * const defaultHelpLine = |
7d4604a9 | 47 | " <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen" |
48 | ; | |
49 | ||
57c466b0 | 50 | const struct newtColors newtDefaultColorPalette = { |
6f481af2 | 51 | "white", "blue", /* root fg, bg */ |
52 | "black", "lightgray", /* border fg, bg */ | |
53 | "black", "lightgray", /* window fg, bg */ | |
54 | "white", "black", /* shadow fg, bg */ | |
55 | "red", "lightgray", /* title fg, bg */ | |
56 | "lightgray", "red", /* button fg, bg */ | |
57 | "red", "lightgray", /* active button fg, bg */ | |
f838d158 | 58 | "lightgray", "blue", /* checkbox fg, bg */ |
59 | "lightgray", "red", /* active checkbox fg, bg */ | |
60 | "lightgray", "blue", /* entry box fg, bg */ | |
6f481af2 | 61 | "blue", "lightgray", /* label fg, bg */ |
62 | "black", "lightgray", /* listbox fg, bg */ | |
f838d158 | 63 | "lightgray", "blue", /* active listbox fg, bg */ |
6f481af2 | 64 | "black", "lightgray", /* textbox fg, bg */ |
f838d158 | 65 | "lightgray", "red", /* active textbox fg, bg */ |
6f481af2 | 66 | "white", "blue", /* help line */ |
f838d158 | 67 | "lightgray", "blue", /* root text */ |
6f481af2 | 68 | "blue", /* scale full */ |
69 | "red", /* scale empty */ | |
70 | "blue", "lightgray", /* disabled entry fg, bg */ | |
feef2cb5 | 71 | "black", "lightgray", /* compact button fg, bg */ |
f838d158 | 72 | "lightgray", "red", /* active & sel listbox */ |
6f481af2 | 73 | "black", "brown" /* selected listbox */ |
6fb96a3f | 74 | }; |
75 | ||
57c466b0 | 76 | static const struct keymap keymap[] = { |
feef2cb5 | 77 | { "\033OA", NEWT_KEY_UP, "ku" }, |
78 | { "\020", NEWT_KEY_UP, NULL }, /* emacs ^P */ | |
6f481af2 | 79 | { "\033OB", NEWT_KEY_DOWN, "kd" }, |
feef2cb5 | 80 | { "\016", NEWT_KEY_DOWN, NULL }, /* emacs ^N */ |
6f481af2 | 81 | { "\033OC", NEWT_KEY_RIGHT, "kr" }, |
feef2cb5 | 82 | { "\006", NEWT_KEY_RIGHT, NULL }, /* emacs ^F */ |
6f481af2 | 83 | { "\033OD", NEWT_KEY_LEFT, "kl" }, |
feef2cb5 | 84 | { "\002", NEWT_KEY_LEFT, NULL }, /* emacs ^B */ |
85 | { "\033OH", NEWT_KEY_HOME, "kh" }, | |
86 | { "\033[1~", NEWT_KEY_HOME, NULL }, | |
87 | { "\001", NEWT_KEY_HOME, NULL }, /* emacs ^A */ | |
6f481af2 | 88 | { "\033Ow", NEWT_KEY_END, "kH" }, |
feef2cb5 | 89 | { "\033[4~", NEWT_KEY_END, "@7" }, |
90 | { "\005", NEWT_KEY_END, NULL }, /* emacs ^E */ | |
6f481af2 | 91 | |
feef2cb5 | 92 | { "\033[3~", NEWT_KEY_DELETE, "kD" }, |
93 | { "\004", NEWT_KEY_DELETE, NULL }, /* emacs ^D */ | |
94 | { "\033[2~", NEWT_KEY_INSERT, "kI" }, | |
6f481af2 | 95 | |
feef2cb5 | 96 | { "\033\t", NEWT_KEY_UNTAB, "kB" }, |
3003455e | 97 | { "\033[Z", NEWT_KEY_UNTAB, NULL }, |
6f481af2 | 98 | |
feef2cb5 | 99 | { "\033[5~", NEWT_KEY_PGUP, "kP" }, |
100 | { "\033[6~", NEWT_KEY_PGDN, "kN" }, | |
101 | { "\033V", NEWT_KEY_PGUP, NULL }, | |
102 | { "\033v", NEWT_KEY_PGUP, NULL }, | |
103 | { "\026", NEWT_KEY_PGDN, NULL }, | |
6f481af2 | 104 | |
105 | { "\033[[A", NEWT_KEY_F1, NULL }, | |
106 | { "\033[[B", NEWT_KEY_F2, NULL }, | |
107 | { "\033[[C", NEWT_KEY_F3, NULL }, | |
108 | { "\033[[D", NEWT_KEY_F4, NULL }, | |
109 | { "\033[[E", NEWT_KEY_F5, NULL }, | |
110 | ||
111 | { "\033OP", NEWT_KEY_F1, NULL }, | |
112 | { "\033OQ", NEWT_KEY_F2, NULL }, | |
113 | { "\033OR", NEWT_KEY_F3, NULL }, | |
114 | { "\033OS", NEWT_KEY_F4, NULL }, | |
115 | ||
feef2cb5 | 116 | { "\033[11~", NEWT_KEY_F1, "k1" }, |
117 | { "\033[12~", NEWT_KEY_F2, "k2" }, | |
118 | { "\033[13~", NEWT_KEY_F3, "k3" }, | |
119 | { "\033[14~", NEWT_KEY_F4, "k4" }, | |
120 | { "\033[15~", NEWT_KEY_F5, "k5" }, | |
121 | { "\033[17~", NEWT_KEY_F6, "k6" }, | |
122 | { "\033[18~", NEWT_KEY_F7, "k7" }, | |
123 | { "\033[19~", NEWT_KEY_F8, "k8" }, | |
124 | { "\033[20~", NEWT_KEY_F9, "k9" }, | |
125 | { "\033[21~", NEWT_KEY_F10, "k;" }, | |
126 | { "\033[23~", NEWT_KEY_F11, "F1" }, | |
127 | { "\033[24~", NEWT_KEY_F12, "F2" }, | |
128 | { "\033", NEWT_KEY_ESCAPE, "@2" }, | |
129 | { "\033", NEWT_KEY_ESCAPE, "@9" }, | |
130 | ||
131 | { "\177", NEWT_KEY_BKSPC, NULL }, | |
132 | { "\010", NEWT_KEY_BKSPC, NULL }, | |
133 | ||
6f481af2 | 134 | { 0 }, /* LEAVE this one */ |
6fb96a3f | 135 | }; |
feef2cb5 | 136 | static void initKeymap(); |
136c3059 | 137 | static void freeKeymap(); |
88d3e0a3 | 138 | |
b7c1b763 | 139 | static newtSuspendCallback suspendCallback = NULL; |
06cf519e | 140 | static void * suspendCallbackData = NULL; |
b7c1b763 | 141 | |
06cf519e | 142 | void newtSetSuspendCallback(newtSuspendCallback cb, void * data) { |
b7c1b763 | 143 | suspendCallback = cb; |
06cf519e | 144 | suspendCallbackData = data; |
b7c1b763 | 145 | } |
146 | ||
ae1235d0 | 147 | static void handleSigwinch(int signum) { |
148 | needResize = 1; | |
149 | } | |
150 | ||
151 | static int getkeyInterruptHook(void) { | |
152 | return -1; | |
153 | } | |
154 | ||
feef2cb5 | 155 | int _newt_wstrlen(const char *str, int len) { |
6f481af2 | 156 | mbstate_t ps; |
157 | wchar_t tmp; | |
158 | int nchars = 0; | |
159 | ||
160 | if (!str) return 0; | |
161 | if (!len) return 0; | |
162 | if (len < 0) len = strlen(str); | |
163 | memset(&ps,0,sizeof(mbstate_t)); | |
164 | while (len > 0) { | |
165 | int x,y; | |
166 | ||
167 | x = mbrtowc(&tmp,str,len,&ps); | |
168 | if (x >0) { | |
169 | str += x; | |
170 | len -= x; | |
171 | y = wcwidth(tmp); | |
172 | if (y>0) | |
173 | nchars+=y; | |
174 | } else break; | |
175 | } | |
176 | return nchars; | |
349586bb | 177 | } |
178 | ||
feef2cb5 | 179 | /** Trim a string to fit |
180 | * @param title - string. NULL will be inserted if necessary | |
181 | * @param chrs - available space. (character cells) | |
182 | */ | |
183 | void trim_string(char *title, int chrs) | |
184 | { | |
185 | char *p = title; | |
b9b1302c | 186 | int ln; |
feef2cb5 | 187 | int x = 0,y = 0; |
188 | wchar_t tmp; | |
189 | mbstate_t ps; | |
190 | ||
191 | memset(&ps, 0, sizeof(ps)); | |
b9b1302c | 192 | ln = strlen(title); |
feef2cb5 | 193 | |
194 | while (*p) { | |
195 | x = mbrtowc(&tmp, p, ln, &ps); | |
196 | if (x < 0) { // error | |
197 | *p = '\0'; | |
198 | return; | |
199 | } | |
200 | y = wcwidth(tmp); | |
b9b1302c | 201 | if (y > chrs) { |
feef2cb5 | 202 | *p = '\0'; |
203 | return; | |
204 | } else { | |
205 | p += x; | |
b9b1302c | 206 | ln -= x; |
207 | chrs -= y; | |
feef2cb5 | 208 | } |
209 | } | |
210 | } | |
211 | ||
16e8af2f | 212 | static int getkey() { |
213 | int c; | |
214 | ||
215 | while ((c = SLang_getkey()) == '\xC') { /* if Ctrl-L redraw whole screen */ | |
5baf7e4b | 216 | SLsmg_touch_lines(0, SLtt_Screen_Rows); |
16e8af2f | 217 | SLsmg_refresh(); |
218 | } | |
219 | return c; | |
220 | ||
221 | } | |
222 | ||
34e56d12 ML |
223 | static void updateColorset(char *fg, char *bg, char **fg_p, char **bg_p) |
224 | { | |
225 | if (*fg && fg_p) | |
226 | *fg_p = fg; | |
227 | if (*bg && bg_p) | |
228 | *bg_p = bg; | |
229 | } | |
230 | ||
231 | /* parse color specifications (e.g. root=,black:border=red,blue) | |
232 | * and update the palette | |
233 | */ | |
234 | static void parseColors(char *s, struct newtColors *palette) | |
235 | { | |
236 | char *name, *str, *fg, *bg; | |
34e56d12 ML |
237 | |
238 | for (str = s; (s = strtok(str, ";:\n\r\t ")); str = NULL) { | |
239 | name = s; | |
240 | if (!(s = strchr(s, '=')) || !*s) | |
241 | continue; | |
242 | *s = '\0'; | |
243 | fg = ++s; | |
244 | if (!(s = strchr(s, ',')) || !*s) | |
245 | continue; | |
246 | *s = '\0'; | |
247 | bg = ++s; | |
248 | ||
249 | if (!strcmp(name, "root")) | |
250 | updateColorset(fg, bg, &palette->rootFg, &palette->rootBg); | |
251 | else if (!strcmp(name, "border")) | |
252 | updateColorset(fg, bg, &palette->borderFg, &palette->borderBg); | |
253 | else if (!strcmp(name, "window")) | |
254 | updateColorset(fg, bg, &palette->windowFg, &palette->windowBg); | |
255 | else if (!strcmp(name, "shadow")) | |
256 | updateColorset(fg, bg, &palette->shadowFg, &palette->shadowBg); | |
257 | else if (!strcmp(name, "title")) | |
258 | updateColorset(fg, bg, &palette->titleFg, &palette->titleBg); | |
259 | else if (!strcmp(name, "button")) | |
260 | updateColorset(fg, bg, &palette->buttonFg, &palette->buttonBg); | |
261 | else if (!strcmp(name, "actbutton")) | |
262 | updateColorset(fg, bg, &palette->actButtonFg, &palette->actButtonBg); | |
263 | else if (!strcmp(name, "checkbox")) | |
264 | updateColorset(fg, bg, &palette->checkboxFg, &palette->checkboxBg); | |
265 | else if (!strcmp(name, "actcheckbox")) | |
266 | updateColorset(fg, bg, &palette->actCheckboxFg, &palette->actCheckboxBg); | |
267 | else if (!strcmp(name, "entry")) | |
268 | updateColorset(fg, bg, &palette->entryFg, &palette->entryBg); | |
269 | else if (!strcmp(name, "label")) | |
270 | updateColorset(fg, bg, &palette->labelFg, &palette->labelBg); | |
271 | else if (!strcmp(name, "listbox")) | |
272 | updateColorset(fg, bg, &palette->listboxFg, &palette->listboxBg); | |
273 | else if (!strcmp(name, "actlistbox")) | |
274 | updateColorset(fg, bg, &palette->actListboxFg, &palette->actListboxBg); | |
275 | else if (!strcmp(name, "textbox")) | |
276 | updateColorset(fg, bg, &palette->textboxFg, &palette->textboxBg); | |
277 | else if (!strcmp(name, "acttextbox")) | |
278 | updateColorset(fg, bg, &palette->actTextboxFg, &palette->actTextboxBg); | |
279 | else if (!strcmp(name, "helpline")) | |
280 | updateColorset(fg, bg, &palette->helpLineFg, &palette->helpLineBg); | |
281 | else if (!strcmp(name, "roottext")) | |
282 | updateColorset(fg, bg, &palette->rootTextFg, &palette->rootTextBg); | |
283 | else if (!strcmp(name, "emptyscale")) | |
284 | updateColorset(fg, bg, NULL, &palette->emptyScale); | |
285 | else if (!strcmp(name, "fullscale")) | |
286 | updateColorset(fg, bg, NULL, &palette->fullScale); | |
287 | else if (!strcmp(name, "disentry")) | |
288 | updateColorset(fg, bg, &palette->disabledEntryFg, &palette->disabledEntryBg); | |
289 | else if (!strcmp(name, "compactbutton")) | |
290 | updateColorset(fg, bg, &palette->compactButtonFg, &palette->compactButtonBg); | |
291 | else if (!strcmp(name, "actsellistbox")) | |
292 | updateColorset(fg, bg, &palette->actSelListboxFg, &palette->actSelListboxBg); | |
293 | else if (!strcmp(name, "sellistbox")) | |
294 | updateColorset(fg, bg, &palette->selListboxFg, &palette->selListboxBg); | |
295 | } | |
296 | } | |
297 | ||
298 | static void initColors(void) | |
299 | { | |
300 | char *colors, *colors_file, buf[16384]; | |
301 | FILE *f; | |
302 | struct newtColors palette; | |
303 | ||
304 | palette = newtDefaultColorPalette; | |
305 | ||
306 | colors_file = getenv("NEWT_COLORS_FILE"); | |
307 | #ifdef NEWT_COLORS_FILE | |
308 | if (colors_file == NULL) | |
309 | colors_file = NEWT_COLORS_FILE; | |
310 | #endif | |
311 | ||
312 | if ((colors = getenv("NEWT_COLORS"))) { | |
313 | strncpy(buf, colors, sizeof (buf)); | |
314 | buf[sizeof (buf) - 1] = '\0'; | |
315 | parseColors(buf, &palette); | |
316 | } else if (colors_file && *colors_file && (f = fopen(colors_file, "r"))) { | |
317 | size_t r; | |
318 | if ((r = fread(buf, 1, sizeof (buf) - 1, f)) > 0) { | |
319 | buf[r] = '\0'; | |
320 | parseColors(buf, &palette); | |
321 | } | |
322 | fclose(f); | |
323 | } | |
324 | ||
325 | newtSetColors(palette); | |
326 | } | |
327 | ||
327436b3 | 328 | void newtFlushInput(void) { |
329 | while (SLang_input_pending(0)) { | |
6f481af2 | 330 | getkey(); |
327436b3 | 331 | } |
332 | } | |
333 | ||
3eec7ce4 | 334 | /** |
335 | * @brief Refresh the screen | |
336 | */ | |
6fb96a3f | 337 | void newtRefresh(void) { |
338 | SLsmg_refresh(); | |
339 | } | |
340 | ||
3cf3e1b9 | 341 | void newtSuspend(void) { |
5e171db1 | 342 | SLtt_set_cursor_visibility (1); |
3cf3e1b9 | 343 | SLsmg_suspend_smg(); |
344 | SLang_reset_tty(); | |
5e171db1 | 345 | SLtt_set_cursor_visibility (cursorOn); |
3cf3e1b9 | 346 | } |
347 | ||
3eec7ce4 | 348 | /** |
349 | * @brief Return after suspension. | |
350 | * @return 0 on success. | |
351 | */ | |
b3ddfdd7 | 352 | int newtResume(void) { |
3cf3e1b9 | 353 | SLsmg_resume_smg (); |
354 | SLsmg_refresh(); | |
9b146a9f | 355 | return SLang_init_tty(0, noFlowCtrl, 0); |
3cf3e1b9 | 356 | } |
357 | ||
6fb96a3f | 358 | void newtCls(void) { |
81361f3e | 359 | SLsmg_set_color(NEWT_COLORSET_ROOT); |
6fb96a3f | 360 | SLsmg_gotorc(0, 0); |
361 | SLsmg_erase_eos(); | |
362 | ||
363 | newtRefresh(); | |
364 | } | |
365 | ||
3eec7ce4 | 366 | /** |
367 | * @brief Resize the screen | |
368 | * @param redraw - boolean - should we redraw the screen? | |
369 | */ | |
ae1235d0 | 370 | void newtResizeScreen(int redraw) { |
0593cb33 | 371 | /* we can't redraw from scratch, just redisplay SLang screen */ |
ae1235d0 | 372 | SLtt_get_screen_size(); |
0593cb33 | 373 | /* SLsmg_reinit_smg(); */ |
16e8af2f | 374 | if (redraw) { |
5baf7e4b | 375 | SLsmg_touch_lines(0, SLtt_Screen_Rows); |
16e8af2f | 376 | newtRefresh(); |
377 | } | |
ae1235d0 | 378 | } |
379 | ||
3eec7ce4 | 380 | /** |
381 | * @brief Initialize the newt library | |
382 | * @return int - 0 for success, else < 0 | |
383 | */ | |
6fb96a3f | 384 | int newtInit(void) { |
16e8af2f | 385 | char * MonoValue, * MonoEnv = "NEWT_MONO"; |
9b146a9f | 386 | char * NoFlowCtrlValue, * NoFlowCtrlEnv = "NEWT_NOFLOWCTRL"; |
16e8af2f | 387 | const char *lang; |
b3ddfdd7 | 388 | int ret; |
16e8af2f | 389 | |
390 | if ((lang = getenv("LC_ALL")) == NULL) | |
391 | if ((lang = getenv("LC_CTYPE")) == NULL) | |
392 | if ((lang = getenv("LANG")) == NULL) | |
393 | lang = ""; | |
3aab8830 | 394 | /* slang doesn't support multibyte encodings except UTF-8, |
395 | avoid character corruption by redrawing the screen */ | |
16e8af2f | 396 | if (strstr (lang, ".euc") != NULL) |
6f481af2 | 397 | trashScreen = 1; |
91be88a7 | 398 | |
33b96ba3 | 399 | SLutf8_enable(-1); |
6fb96a3f | 400 | SLtt_get_terminfo(); |
ae1235d0 | 401 | SLtt_get_screen_size(); |
91be88a7 | 402 | |
7d4604a9 | 403 | MonoValue = getenv(MonoEnv); |
85ee6604 | 404 | if ( MonoValue != NULL ) |
6f481af2 | 405 | SLtt_Use_Ansi_Colors = 0; |
6fb96a3f | 406 | |
9b146a9f RG |
407 | NoFlowCtrlValue = getenv(NoFlowCtrlEnv); |
408 | if ( NoFlowCtrlValue != NULL ) | |
409 | noFlowCtrl = 1; | |
410 | ||
b3ddfdd7 | 411 | if ((ret = SLsmg_init_smg()) < 0) |
6f481af2 | 412 | return ret; |
9b146a9f | 413 | if ((ret = SLang_init_tty(0, noFlowCtrl, 0)) < 0) |
6f481af2 | 414 | return ret; |
45f6c4fd | 415 | |
34e56d12 | 416 | initColors(); |
23efd09b | 417 | newtCursorOff(); |
feef2cb5 | 418 | initKeymap(); |
6fb96a3f | 419 | |
ae1235d0 | 420 | SLsignal_intr(SIGWINCH, handleSigwinch); |
421 | SLang_getkey_intr_hook = getkeyInterruptHook; | |
422 | ||
6fb96a3f | 423 | return 0; |
424 | } | |
425 | ||
3eec7ce4 | 426 | /** |
427 | * @brief Closedown the newt library, tidying screen. | |
428 | * @returns int , 0. (no errors reported) | |
429 | */ | |
6fb96a3f | 430 | int newtFinished(void) { |
a753da93 | 431 | if (currentWindow) { |
432 | for (; currentWindow >= windowStack; currentWindow--) { | |
433 | free(currentWindow->buffer); | |
434 | free(currentWindow->title); | |
435 | } | |
436 | currentWindow = NULL; | |
437 | } | |
438 | ||
439 | if (currentHelpline) { | |
440 | for (; currentHelpline >= helplineStack; currentHelpline--) | |
441 | free(*currentHelpline); | |
442 | currentHelpline = NULL; | |
443 | } | |
444 | ||
136c3059 ML |
445 | freeKeymap(); |
446 | ||
6fb96a3f | 447 | SLsmg_gotorc(SLtt_Screen_Rows - 1, 0); |
23efd09b | 448 | newtCursorOn(); |
6fb96a3f | 449 | SLsmg_refresh(); |
450 | SLsmg_reset_smg(); | |
451 | SLang_reset_tty(); | |
452 | ||
453 | return 0; | |
454 | } | |
455 | ||
3eec7ce4 | 456 | /** |
457 | * @brief Set the colors used. | |
458 | * @param colors - newtColor struct used. | |
459 | */ | |
6fb96a3f | 460 | void newtSetColors(struct newtColors colors) { |
16e8af2f | 461 | if (!SLtt_Use_Ansi_Colors) { |
462 | int i; | |
463 | ||
464 | for (i = 2; i < 25; i++) | |
465 | SLtt_set_mono(i, NULL, 0); | |
466 | ||
467 | SLtt_set_mono(NEWT_COLORSET_SELLISTBOX, NULL, SLTT_BOLD_MASK); | |
468 | ||
469 | SLtt_set_mono(NEWT_COLORSET_ACTBUTTON, NULL, SLTT_REV_MASK); | |
470 | SLtt_set_mono(NEWT_COLORSET_ACTCHECKBOX, NULL, SLTT_REV_MASK); | |
471 | SLtt_set_mono(NEWT_COLORSET_ACTLISTBOX, NULL, SLTT_REV_MASK); | |
472 | SLtt_set_mono(NEWT_COLORSET_ACTTEXTBOX, NULL, SLTT_REV_MASK); | |
473 | ||
474 | SLtt_set_mono(NEWT_COLORSET_ACTSELLISTBOX, NULL, SLTT_REV_MASK | SLTT_BOLD_MASK); | |
475 | ||
476 | SLtt_set_mono(NEWT_COLORSET_DISENTRY, NULL, 0); // FIXME | |
477 | SLtt_set_mono(NEWT_COLORSET_FULLSCALE, NULL, SLTT_ULINE_MASK | SLTT_REV_MASK); | |
478 | SLtt_set_mono(NEWT_COLORSET_EMPTYSCALE, NULL, SLTT_ULINE_MASK); | |
479 | return; | |
480 | } | |
81361f3e | 481 | SLtt_set_color(NEWT_COLORSET_ROOT, "", colors.rootFg, colors.rootBg); |
482 | SLtt_set_color(NEWT_COLORSET_BORDER, "", colors.borderFg, colors.borderBg); | |
483 | SLtt_set_color(NEWT_COLORSET_WINDOW, "", colors.windowFg, colors.windowBg); | |
484 | SLtt_set_color(NEWT_COLORSET_SHADOW, "", colors.shadowFg, colors.shadowBg); | |
485 | SLtt_set_color(NEWT_COLORSET_TITLE, "", colors.titleFg, colors.titleBg); | |
486 | SLtt_set_color(NEWT_COLORSET_BUTTON, "", colors.buttonFg, colors.buttonBg); | |
45f6c4fd | 487 | SLtt_set_color(NEWT_COLORSET_ACTBUTTON, "", colors.actButtonFg, |
6f481af2 | 488 | colors.actButtonBg); |
45f6c4fd | 489 | SLtt_set_color(NEWT_COLORSET_CHECKBOX, "", colors.checkboxFg, |
6f481af2 | 490 | colors.checkboxBg); |
45f6c4fd | 491 | SLtt_set_color(NEWT_COLORSET_ACTCHECKBOX, "", colors.actCheckboxFg, |
6f481af2 | 492 | colors.actCheckboxBg); |
81361f3e | 493 | SLtt_set_color(NEWT_COLORSET_ENTRY, "", colors.entryFg, colors.entryBg); |
494 | SLtt_set_color(NEWT_COLORSET_LABEL, "", colors.labelFg, colors.labelBg); | |
45f6c4fd | 495 | SLtt_set_color(NEWT_COLORSET_LISTBOX, "", colors.listboxFg, |
6f481af2 | 496 | colors.listboxBg); |
45f6c4fd | 497 | SLtt_set_color(NEWT_COLORSET_ACTLISTBOX, "", colors.actListboxFg, |
6f481af2 | 498 | colors.actListboxBg); |
45f6c4fd | 499 | SLtt_set_color(NEWT_COLORSET_TEXTBOX, "", colors.textboxFg, |
6f481af2 | 500 | colors.textboxBg); |
45f6c4fd | 501 | SLtt_set_color(NEWT_COLORSET_ACTTEXTBOX, "", colors.actTextboxFg, |
6f481af2 | 502 | colors.actTextboxBg); |
45f6c4fd | 503 | SLtt_set_color(NEWT_COLORSET_HELPLINE, "", colors.helpLineFg, |
6f481af2 | 504 | colors.helpLineBg); |
45f6c4fd | 505 | SLtt_set_color(NEWT_COLORSET_ROOTTEXT, "", colors.rootTextFg, |
6f481af2 | 506 | colors.rootTextBg); |
3cf3e1b9 | 507 | |
5505c898 | 508 | SLtt_set_color(NEWT_COLORSET_EMPTYSCALE, "", "white", |
6f481af2 | 509 | colors.emptyScale); |
5505c898 | 510 | SLtt_set_color(NEWT_COLORSET_FULLSCALE, "", "white", |
6f481af2 | 511 | colors.fullScale); |
a1f11019 | 512 | SLtt_set_color(NEWT_COLORSET_DISENTRY, "", colors.disabledEntryFg, |
6f481af2 | 513 | colors.disabledEntryBg); |
39dd7d98 | 514 | |
515 | SLtt_set_color(NEWT_COLORSET_COMPACTBUTTON, "", colors.compactButtonFg, | |
6f481af2 | 516 | colors.compactButtonBg); |
45f6c4fd | 517 | |
46263d9e | 518 | SLtt_set_color(NEWT_COLORSET_ACTSELLISTBOX, "", colors.actSelListboxFg, |
6f481af2 | 519 | colors.actSelListboxBg); |
46263d9e | 520 | SLtt_set_color(NEWT_COLORSET_SELLISTBOX, "", colors.selListboxFg, |
6f481af2 | 521 | colors.selListboxBg); |
6fb96a3f | 522 | } |
523 | ||
70728aab | 524 | void newtSetColor(int colorset, char *fg, char *bg) { |
7b6003b0 ML |
525 | if (colorset < NEWT_COLORSET_ROOT || |
526 | (colorset > NEWT_COLORSET_SELLISTBOX && colorset < NEWT_COLORSET_CUSTOM(0)) || | |
70728aab | 527 | !SLtt_Use_Ansi_Colors) |
528 | return; | |
529 | ||
530 | SLtt_set_color(colorset, "", fg, bg); | |
531 | } | |
532 | ||
feef2cb5 | 533 | /* Keymap handling - rewritten by Henning Makholm <henning@makholm.net>, |
534 | * November 2003. | |
535 | */ | |
536 | ||
537 | struct kmap_trie_entry { | |
136c3059 | 538 | char alloced; /* alloced/not first element in array */ |
feef2cb5 | 539 | char c ; /* character got from terminal */ |
540 | int code; /* newt key, or 0 if c does not make a complete sequence */ | |
541 | struct kmap_trie_entry *contseq; /* sub-trie for character following c */ | |
542 | struct kmap_trie_entry *next; /* try this if char received != c */ | |
543 | }; | |
136c3059 ML |
544 | |
545 | static struct kmap_trie_entry *kmap_trie_root = NULL; | |
feef2cb5 | 546 | static int keyreader_buf_len = 10 ; |
547 | static unsigned char default_keyreader_buf[10]; | |
548 | static unsigned char *keyreader_buf = default_keyreader_buf; | |
549 | ||
550 | #if 0 /* for testing of the keymap manipulation code */ | |
551 | static void dumpkeys_recursive(struct kmap_trie_entry *curr, int i, FILE *f) { | |
552 | int j, ps ; | |
553 | char seen[256]={0}; | |
554 | if( curr && i >= keyreader_buf_len ) { | |
555 | fprintf(f,"ARGH! Too long sequence!\n") ; | |
556 | return ; | |
557 | } | |
558 | for(;curr;curr=curr->next) { | |
559 | keyreader_buf[i] = curr->c ; | |
560 | ps = seen[(unsigned char)curr->c]++ ; | |
561 | if( ps || curr->code || (!curr->code && !curr->contseq) ) { | |
562 | for(j=0;j<=i;j++) { | |
563 | if( keyreader_buf[j] > 32 && keyreader_buf[j]<127 && | |
564 | keyreader_buf[j] != '^' && keyreader_buf[j] != '\\' ) | |
565 | fprintf(f,"%c",keyreader_buf[j]); | |
566 | else if( keyreader_buf[j] > 0 && keyreader_buf[j]<=32 ) | |
567 | fprintf(f,"^%c",keyreader_buf[j] + 0x40); | |
568 | else | |
569 | fprintf(f,"\\%03o", | |
570 | (unsigned)(unsigned char)keyreader_buf[j]); | |
571 | } | |
572 | if( curr->code ) | |
573 | fprintf(f,": 0x%X\n",curr->code); | |
574 | else | |
575 | fprintf(f,": (just keymap)\n"); | |
576 | } | |
577 | dumpkeys_recursive(curr->contseq,i+1,f); | |
578 | } | |
579 | } | |
580 | static void dump_keymap(void) { | |
581 | FILE *f = fopen("newt.keydump","wt"); | |
582 | if (f) { | |
136c3059 | 583 | dumpkeys_recursive(kmap_trie_root, 0, f); |
feef2cb5 | 584 | fclose(f); |
585 | } | |
586 | } | |
587 | #endif | |
588 | ||
589 | /* newtBindKey may overwrite a binding that is there already */ | |
590 | static void newtBindKey(char *keyseq, int meaning) { | |
136c3059 | 591 | struct kmap_trie_entry *root = kmap_trie_root ; |
feef2cb5 | 592 | struct kmap_trie_entry **curptr = &root ; |
593 | ||
594 | /* Try to make sure the common matching buffer is long enough. */ | |
595 | if( strlen(keyseq) > keyreader_buf_len ) { | |
596 | int i = strlen(keyseq)+10; | |
597 | unsigned char *newbuf = malloc(i); | |
598 | if (newbuf) { | |
599 | if (keyreader_buf != default_keyreader_buf) | |
600 | free(keyreader_buf); | |
601 | keyreader_buf = newbuf; | |
602 | keyreader_buf_len = i; | |
603 | } | |
604 | } | |
605 | ||
606 | if (*keyseq == 0) return; /* binding the empty sequence is meaningless */ | |
607 | ||
608 | while(1) { | |
609 | while ((*curptr) && (*curptr)->c != *keyseq) | |
610 | curptr = &(*curptr)->next; | |
611 | if ((*curptr)==0) { | |
612 | struct kmap_trie_entry* fresh | |
613 | = calloc(strlen(keyseq),sizeof(struct kmap_trie_entry)); | |
614 | if (fresh == 0) return; /* despair! */ | |
136c3059 | 615 | fresh->alloced = 1; |
feef2cb5 | 616 | *curptr = fresh; |
617 | while (keyseq[1]) { | |
618 | fresh->contseq = fresh+1; | |
619 | (fresh++)->c = *(keyseq++); | |
620 | } | |
621 | fresh->c = *keyseq; | |
622 | fresh->code = meaning; | |
623 | return; | |
624 | } | |
625 | if (keyseq[1]==0) { | |
626 | (*curptr)->code = meaning; | |
627 | return; | |
628 | } else { | |
629 | curptr = &(*curptr)->contseq; | |
630 | keyseq++; | |
631 | } | |
632 | } | |
633 | } | |
634 | ||
635 | /* This function recursively inserts all entries in the "to" trie into | |
636 | corresponding positions in the "from" trie, except positions that | |
637 | are already defined in the "from" trie. */ | |
638 | static void kmap_trie_fallback(struct kmap_trie_entry *to, | |
639 | struct kmap_trie_entry **from) { | |
640 | if (*from == NULL) | |
641 | *from = to ; | |
642 | if (*from == to) | |
643 | return ; | |
644 | for (;to!=NULL;to=to->next) { | |
645 | struct kmap_trie_entry **fromcopy = from ; | |
646 | while ((*fromcopy) && (*fromcopy)->c != to->c) | |
647 | fromcopy = &(*fromcopy)->next ; | |
648 | if (*fromcopy) { | |
649 | if ((*fromcopy)->code == 0) | |
650 | (*fromcopy)->code = to->code; | |
651 | kmap_trie_fallback(to->contseq, &(*fromcopy)->contseq); | |
652 | } else { | |
653 | *fromcopy = malloc(sizeof(struct kmap_trie_entry)); | |
654 | if (*fromcopy) { | |
655 | **fromcopy = *to ; | |
136c3059 | 656 | (*fromcopy)->alloced = 1; |
feef2cb5 | 657 | (*fromcopy)->next = 0 ; |
658 | } | |
659 | } | |
660 | } | |
661 | } | |
662 | ||
6fb96a3f | 663 | int newtGetKey(void) { |
b8b8a86f | 664 | int key, lastcode, errors = 0; |
feef2cb5 | 665 | unsigned char *chptr = keyreader_buf, *lastmatch; |
136c3059 | 666 | struct kmap_trie_entry *curr = kmap_trie_root; |
6fb96a3f | 667 | |
b7c1b763 | 668 | do { |
6f481af2 | 669 | key = getkey(); |
670 | if (key == SLANG_GETKEY_ERROR) { | |
6f481af2 | 671 | if (needResize) { |
16e8af2f | 672 | needResize = 0; |
6f481af2 | 673 | return NEWT_KEY_RESIZE; |
16e8af2f | 674 | } |
ae1235d0 | 675 | |
b8b8a86f ML |
676 | /* Ignore other signals, but assume that stdin disappeared (the |
677 | * parent terminal was proably closed) if the error persists. | |
678 | */ | |
679 | if (errors++ > 10) | |
680 | return NEWT_KEY_ERROR; | |
681 | ||
6f481af2 | 682 | continue; |
683 | } | |
ae1235d0 | 684 | |
6f481af2 | 685 | if (key == NEWT_KEY_SUSPEND && suspendCallback) |
686 | suspendCallback(suspendCallbackData); | |
b8b8a86f | 687 | } while (key == NEWT_KEY_SUSPEND || key == SLANG_GETKEY_ERROR); |
6fb96a3f | 688 | |
feef2cb5 | 689 | /* Read more characters, matching against the trie as we go */ |
690 | lastcode = *chptr = key; | |
691 | lastmatch = chptr ; | |
692 | while(1) { | |
693 | while (curr->c != key) { | |
694 | curr = curr->next ; | |
695 | if (curr==NULL) goto break2levels; | |
696 | } | |
697 | if (curr->code) { | |
698 | lastcode = curr->code; | |
699 | lastmatch = chptr; | |
700 | } | |
701 | curr = curr->contseq; | |
702 | if (curr==NULL) break; | |
703 | ||
704 | if (SLang_input_pending(5) <= 0) | |
705 | break; | |
706 | ||
707 | if (chptr==keyreader_buf+keyreader_buf_len-1) break; | |
708 | *++chptr = key = getkey(); | |
6fb96a3f | 709 | } |
feef2cb5 | 710 | break2levels: |
711 | ||
712 | /* The last time the trie matched was at position lastmatch. Back | |
713 | * up if we have read too many characters. */ | |
714 | while (chptr > lastmatch) | |
715 | SLang_ungetkey(*chptr--); | |
716 | ||
717 | return lastcode; | |
6fb96a3f | 718 | } |
719 | ||
3eec7ce4 | 720 | /** |
721 | * @brief Wait for a keystroke | |
722 | */ | |
6fb96a3f | 723 | void newtWaitForKey(void) { |
724 | newtRefresh(); | |
725 | ||
16e8af2f | 726 | getkey(); |
6fb96a3f | 727 | newtClearKeyBuffer(); |
728 | } | |
729 | ||
3eec7ce4 | 730 | /** |
731 | * @brief Clear the keybuffer | |
732 | */ | |
6fb96a3f | 733 | void newtClearKeyBuffer(void) { |
734 | while (SLang_input_pending(1)) { | |
6f481af2 | 735 | getkey(); |
6fb96a3f | 736 | } |
737 | } | |
738 | ||
3eec7ce4 | 739 | /** |
740 | * Open a new window. | |
edad3d82 | 741 | * @param left. int Size; _not_ including border |
742 | * @param top: int size, _not_ including border | |
3eec7ce4 | 743 | * @param width unsigned int |
744 | * @param height unsigned int | |
745 | * @param title - title string | |
a753da93 | 746 | * @return zero on success |
3eec7ce4 | 747 | */ |
edad3d82 | 748 | int newtOpenWindow(int left, int top, |
feef2cb5 | 749 | unsigned int width, unsigned int height, |
6f481af2 | 750 | const char * title) { |
46263d9e | 751 | int j, row, col; |
d4663248 | 752 | int n; |
44de2c93 | 753 | int i; |
6fb96a3f | 754 | |
327436b3 | 755 | newtFlushInput(); |
756 | ||
a753da93 | 757 | if (currentWindow && currentWindow - windowStack + 1 |
758 | >= sizeof (windowStack) / sizeof (struct Window)) | |
759 | return 1; | |
760 | ||
6fb96a3f | 761 | if (!currentWindow) { |
6f481af2 | 762 | currentWindow = windowStack; |
6fb96a3f | 763 | } else { |
6f481af2 | 764 | currentWindow++; |
6fb96a3f | 765 | } |
766 | ||
767 | currentWindow->left = left; | |
768 | currentWindow->top = top; | |
769 | currentWindow->width = width; | |
770 | currentWindow->height = height; | |
649a0152 | 771 | currentWindow->title = title ? strdup(title) : NULL; |
6fb96a3f | 772 | |
b9b1302c | 773 | currentWindow->buffer = malloc(sizeof(SLsmg_Char_Type) * (width + 5) * (height + 3)); |
6fb96a3f | 774 | |
775 | row = top - 1; | |
b9b1302c | 776 | col = left - 2; |
22cc0d5e | 777 | /* clip to the current screen bounds - msw */ |
778 | if (row < 0) | |
6f481af2 | 779 | row = 0; |
22cc0d5e | 780 | if (col < 0) |
6f481af2 | 781 | col = 0; |
22cc0d5e | 782 | if (left + width > SLtt_Screen_Cols) |
6f481af2 | 783 | width = SLtt_Screen_Cols - left; |
22cc0d5e | 784 | if (top + height > SLtt_Screen_Rows) |
6f481af2 | 785 | height = SLtt_Screen_Rows - top; |
d4663248 | 786 | n = 0; |
6fb96a3f | 787 | for (j = 0; j < height + 3; j++, row++) { |
6f481af2 | 788 | SLsmg_gotorc(row, col); |
789 | SLsmg_read_raw(currentWindow->buffer + n, | |
b9b1302c | 790 | currentWindow->width + 5); |
791 | n += currentWindow->width + 5; | |
6fb96a3f | 792 | } |
793 | ||
7ff5fd71 | 794 | newtTrashScreen(); |
795 | ||
81361f3e | 796 | SLsmg_set_color(NEWT_COLORSET_BORDER); |
feef2cb5 | 797 | SLsmg_set_char_set(1); |
6fb96a3f | 798 | SLsmg_draw_box(top - 1, left - 1, height + 2, width + 2); |
feef2cb5 | 799 | SLsmg_set_char_set(0); |
6fb96a3f | 800 | |
aa47774f | 801 | if (currentWindow->title) { |
feef2cb5 | 802 | trim_string (currentWindow->title, width-4); |
6f481af2 | 803 | i = wstrlen(currentWindow->title,-1) + 4; |
804 | i = ((width - i) / 2) + left; | |
805 | SLsmg_gotorc(top - 1, i); | |
806 | SLsmg_set_char_set(1); | |
807 | SLsmg_write_char(SLSMG_RTEE_CHAR); | |
808 | SLsmg_set_char_set(0); | |
809 | SLsmg_write_char(' '); | |
810 | SLsmg_set_color(NEWT_COLORSET_TITLE); | |
10de8f4a | 811 | SLsmg_write_string((char *)currentWindow->title); |
6f481af2 | 812 | SLsmg_set_color(NEWT_COLORSET_BORDER); |
813 | SLsmg_write_char(' '); | |
814 | SLsmg_set_char_set(1); | |
815 | SLsmg_write_char(SLSMG_LTEE_CHAR); | |
816 | SLsmg_set_char_set(0); | |
6fb96a3f | 817 | } |
818 | ||
81361f3e | 819 | SLsmg_set_color(NEWT_COLORSET_WINDOW); |
6fb96a3f | 820 | SLsmg_fill_region(top, left, height, width, ' '); |
821 | ||
81361f3e | 822 | SLsmg_set_color(NEWT_COLORSET_SHADOW); |
6fb96a3f | 823 | SLsmg_fill_region(top + height + 1, left, 1, width + 2, ' '); |
824 | SLsmg_fill_region(top, left + width + 1, height + 1, 1, ' '); | |
825 | ||
826 | for (i = top; i < (top + height + 1); i++) { | |
6f481af2 | 827 | SLsmg_gotorc(i, left + width + 1); |
828 | SLsmg_write_string(" "); | |
6fb96a3f | 829 | } |
44de2c93 | 830 | |
831 | return 0; | |
6fb96a3f | 832 | } |
833 | ||
3eec7ce4 | 834 | /** |
835 | * @brief Draw a centered window. | |
836 | * @param width - width in char cells | |
837 | * @param height - no. of char cells. | |
838 | * @param title - fixed title | |
a753da93 | 839 | * @returns zero on success |
3eec7ce4 | 840 | */ |
feef2cb5 | 841 | int newtCenteredWindow(unsigned int width,unsigned int height, |
842 | const char * title) { | |
edad3d82 | 843 | int top, left; |
f16e164f | 844 | |
edad3d82 | 845 | top = (int)(SLtt_Screen_Rows - height) / 2; |
f16e164f | 846 | |
45f6c4fd | 847 | /* I don't know why, but this seems to look better */ |
f16e164f | 848 | if ((SLtt_Screen_Rows % 2) && (top % 2)) top--; |
849 | ||
edad3d82 | 850 | left = (int)(SLtt_Screen_Cols - width) / 2; |
f16e164f | 851 | |
a753da93 | 852 | return newtOpenWindow(left, top, width, height, title); |
f16e164f | 853 | } |
854 | ||
3eec7ce4 | 855 | /** |
856 | * @brief Remove the top window | |
857 | */ | |
6fb96a3f | 858 | void newtPopWindow(void) { |
e5df813b | 859 | newtPopWindowNoRefresh(); |
860 | newtRefresh(); | |
861 | } | |
862 | ||
863 | void newtPopWindowNoRefresh(void) { | |
6fb96a3f | 864 | int j, row, col; |
45f6c4fd | 865 | int n = 0; |
6fb96a3f | 866 | |
a753da93 | 867 | if (currentWindow == NULL) |
868 | return; | |
869 | ||
6fb96a3f | 870 | row = currentWindow->top - 1; |
b9b1302c | 871 | col = currentWindow->left - 2; |
22cc0d5e | 872 | if (row < 0) |
6f481af2 | 873 | row = 0; |
22cc0d5e | 874 | if (col < 0) |
6f481af2 | 875 | col = 0; |
6fb96a3f | 876 | for (j = 0; j < currentWindow->height + 3; j++, row++) { |
6f481af2 | 877 | SLsmg_gotorc(row, col); |
878 | SLsmg_write_raw(currentWindow->buffer + n, | |
b9b1302c | 879 | currentWindow->width + 5); |
880 | n += currentWindow->width + 5; | |
6fb96a3f | 881 | } |
882 | ||
883 | free(currentWindow->buffer); | |
aa47774f | 884 | free(currentWindow->title); |
6fb96a3f | 885 | |
45f6c4fd | 886 | if (currentWindow == windowStack) |
6f481af2 | 887 | currentWindow = NULL; |
6fb96a3f | 888 | else |
6f481af2 | 889 | currentWindow--; |
6fb96a3f | 890 | |
891 | SLsmg_set_char_set(0); | |
892 | ||
7ff5fd71 | 893 | newtTrashScreen(); |
6fb96a3f | 894 | } |
895 | ||
45f6c4fd | 896 | void newtGetWindowPos(int * x, int * y) { |
897 | if (currentWindow) { | |
6f481af2 | 898 | *x = currentWindow->left; |
899 | *y = currentWindow->top; | |
45f6c4fd | 900 | } else |
6f481af2 | 901 | *x = *y = 0; |
45f6c4fd | 902 | } |
903 | ||
a1f11019 | 904 | void newtGetrc(int * row, int * col) { |
28de1915 | 905 | *row = cursorRow; |
906 | *col = cursorCol; | |
907 | ||
908 | if (currentWindow) { | |
909 | *row -= currentWindow->top; | |
910 | *col -= currentWindow->left; | |
911 | } | |
a1f11019 | 912 | } |
913 | ||
914 | void newtGotorc(int newRow, int newCol) { | |
915 | if (currentWindow) { | |
6f481af2 | 916 | newRow += currentWindow->top; |
917 | newCol += currentWindow->left; | |
a1f11019 | 918 | } |
919 | ||
920 | cursorRow = newRow; | |
921 | cursorCol = newCol; | |
922 | SLsmg_gotorc(cursorRow, cursorCol); | |
6fb96a3f | 923 | } |
924 | ||
925 | void newtDrawBox(int left, int top, int width, int height, int shadow) { | |
926 | if (currentWindow) { | |
6f481af2 | 927 | top += currentWindow->top; |
928 | left += currentWindow->left; | |
6fb96a3f | 929 | } |
930 | ||
931 | SLsmg_draw_box(top, left, height, width); | |
932 | ||
933 | if (shadow) { | |
6f481af2 | 934 | SLsmg_set_color(NEWT_COLORSET_SHADOW); |
935 | SLsmg_fill_region(top + height, left + 1, 1, width - 1, ' '); | |
936 | SLsmg_fill_region(top + 1, left + width, height, 1, ' '); | |
6fb96a3f | 937 | } |
938 | } | |
939 | ||
940 | void newtClearBox(int left, int top, int width, int height) { | |
941 | if (currentWindow) { | |
6f481af2 | 942 | top += currentWindow->top; |
943 | left += currentWindow->left; | |
6fb96a3f | 944 | } |
945 | ||
946 | SLsmg_fill_region(top, left, height, width, ' '); | |
947 | } | |
948 | ||
6fb96a3f | 949 | static void initKeymap(void) { |
feef2cb5 | 950 | const struct keymap * curr; |
136c3059 ML |
951 | struct kmap_trie_entry *kmap_trie_escBrack, *kmap_trie_escO; |
952 | ||
953 | /* Here are some entries that will help in handling esc O foo and | |
954 | esc [ foo as variants of each other. */ | |
955 | kmap_trie_root = calloc(3, sizeof (struct kmap_trie_entry)); | |
956 | kmap_trie_escBrack = kmap_trie_root + 1; | |
957 | kmap_trie_escO = kmap_trie_root + 2; | |
958 | ||
959 | kmap_trie_root->alloced = 1; | |
960 | kmap_trie_root->c = '\033'; | |
961 | kmap_trie_root->contseq = kmap_trie_escBrack; | |
962 | ||
963 | kmap_trie_escBrack->c = '['; | |
964 | kmap_trie_escBrack->next = kmap_trie_escO; | |
965 | ||
966 | kmap_trie_escO->c = 'O'; | |
6fb96a3f | 967 | |
feef2cb5 | 968 | /* First bind built-in default bindings. They may be shadowed by |
969 | the termcap entries that get bound later. */ | |
6fb96a3f | 970 | for (curr = keymap; curr->code; curr++) { |
feef2cb5 | 971 | if (curr->str) |
972 | newtBindKey(curr->str,curr->code); | |
6fb96a3f | 973 | } |
974 | ||
feef2cb5 | 975 | /* Then bind strings from termcap entries */ |
976 | for (curr = keymap; curr->code; curr++) { | |
977 | if (curr->tc) { | |
978 | char *pc = SLtt_tgetstr(curr->tc); | |
979 | if (pc) { | |
980 | newtBindKey(pc,curr->code); | |
981 | } | |
982 | } | |
983 | } | |
6fb96a3f | 984 | |
feef2cb5 | 985 | /* Finally, invent lowest-priority keybindings that correspond to |
986 | searching for esc-O-foo if esc-[-foo was not found and vice | |
987 | versa. That is needed because of strong confusion among | |
988 | different emulators of VTxxx terminals; some terminfo/termcap | |
989 | descriptions are apparently written by people who were not | |
990 | aware of the differences between "applicataion" and "terminal" | |
991 | keypad modes. Or perhaps they were, but tried to make their | |
992 | description work with a program that puts the keyboard in the | |
993 | wrong emulation mode. In short, one needs this: */ | |
136c3059 ML |
994 | kmap_trie_fallback(kmap_trie_escO->contseq, &kmap_trie_escBrack->contseq); |
995 | kmap_trie_fallback(kmap_trie_escBrack->contseq, &kmap_trie_escO->contseq); | |
996 | } | |
997 | ||
998 | static void free_keys(struct kmap_trie_entry *kmap, struct kmap_trie_entry *parent, int prepare) { | |
999 | if (kmap == NULL) | |
1000 | return; | |
1001 | ||
1002 | free_keys(kmap->contseq, kmap, prepare); | |
1003 | free_keys(kmap->next, kmap, prepare); | |
1004 | ||
1005 | if (!kmap->alloced && kmap - parent == 1) | |
1006 | return; | |
1007 | ||
1008 | /* find first element in array */ | |
1009 | while (!kmap->alloced) | |
1010 | kmap--; | |
1011 | ||
1012 | kmap->alloced += prepare ? 1 : -1; | |
1013 | if (!prepare && kmap->alloced == 1) | |
1014 | free(kmap); | |
1015 | } | |
1016 | ||
1017 | static void freeKeymap() { | |
1018 | free_keys(kmap_trie_root, NULL, 1); | |
1019 | free_keys(kmap_trie_root, NULL, 0); | |
1020 | kmap_trie_root = NULL; | |
6fb96a3f | 1021 | } |
6fb96a3f | 1022 | |
3eec7ce4 | 1023 | /** |
1024 | * @brief Delay for a specified number of usecs | |
1025 | * @param int - number of usecs to wait for. | |
1026 | */ | |
feef2cb5 | 1027 | void newtDelay(unsigned int usecs) { |
ad8aa646 RP |
1028 | struct timespec t = { usecs / 1000000, (usecs % 1000000) * 1000 }; |
1029 | ||
1030 | nanosleep(&t, NULL); | |
6fb96a3f | 1031 | } |
8735cc88 | 1032 | |
45c366b1 | 1033 | struct eventResult newtDefaultEventHandler(newtComponent c, |
6f481af2 | 1034 | struct event ev) { |
8735cc88 | 1035 | struct eventResult er; |
1036 | ||
1037 | er.result = ER_IGNORED; | |
1038 | return er; | |
1039 | } | |
81361f3e | 1040 | |
7d4604a9 | 1041 | void newtRedrawHelpLine(void) { |
81361f3e | 1042 | char * buf; |
1043 | ||
1044 | SLsmg_set_color(NEWT_COLORSET_HELPLINE); | |
45f6c4fd | 1045 | |
22cc0d5e | 1046 | if (currentHelpline) { |
6f481af2 | 1047 | /* buffer size needs to be wide enough to hold all the multibyte |
1048 | currentHelpline + all the single byte ' ' to fill the line */ | |
1049 | int wlen = wstrlen(*currentHelpline, -1); | |
1050 | int len; | |
1051 | ||
1052 | if (wlen > SLtt_Screen_Cols) | |
1053 | wlen = SLtt_Screen_Cols; | |
1054 | len = strlen(*currentHelpline) + (SLtt_Screen_Cols - wlen); | |
1055 | buf = alloca(len + 1); | |
1056 | memset(buf, ' ', len); | |
1057 | memcpy(buf, *currentHelpline, strlen(*currentHelpline)); | |
1058 | buf[len] = '\0'; | |
ce11acc8 | 1059 | } else { |
6f481af2 | 1060 | buf = alloca(SLtt_Screen_Cols + 1); |
1061 | memset(buf, ' ', SLtt_Screen_Cols); | |
1062 | buf[SLtt_Screen_Cols] = '\0'; | |
22cc0d5e | 1063 | } |
81361f3e | 1064 | SLsmg_gotorc(SLtt_Screen_Rows - 1, 0); |
10de8f4a | 1065 | SLsmg_write_string(buf); |
b6c968d2 | 1066 | SLsmg_gotorc(cursorRow, cursorCol); |
81361f3e | 1067 | } |
1068 | ||
d4109c37 | 1069 | void newtPushHelpLine(const char * text) { |
a753da93 | 1070 | if (currentHelpline && currentHelpline - helplineStack + 1 |
1071 | >= sizeof (helplineStack) / sizeof (char *)) | |
1072 | return; | |
1073 | ||
7d4604a9 | 1074 | if (!text) |
6f481af2 | 1075 | text = defaultHelpLine; |
45f6c4fd | 1076 | |
81361f3e | 1077 | if (currentHelpline) |
6f481af2 | 1078 | (*(++currentHelpline)) = strdup(text); |
81361f3e | 1079 | else { |
6f481af2 | 1080 | currentHelpline = helplineStack; |
1081 | *currentHelpline = strdup(text); | |
81361f3e | 1082 | } |
1083 | ||
7d4604a9 | 1084 | newtRedrawHelpLine(); |
81361f3e | 1085 | } |
1086 | ||
1087 | void newtPopHelpLine(void) { | |
1088 | if (!currentHelpline) return; | |
1089 | ||
1090 | free(*currentHelpline); | |
1091 | if (currentHelpline == helplineStack) | |
6f481af2 | 1092 | currentHelpline = NULL; |
81361f3e | 1093 | else |
6f481af2 | 1094 | currentHelpline--; |
81361f3e | 1095 | |
7d4604a9 | 1096 | newtRedrawHelpLine(); |
81361f3e | 1097 | } |
1098 | ||
39280c3a | 1099 | void newtDrawRootText(int col, int row, const char * text) { |
81361f3e | 1100 | SLsmg_set_color(NEWT_COLORSET_ROOTTEXT); |
7d4604a9 | 1101 | |
1102 | if (col < 0) { | |
6f481af2 | 1103 | col = SLtt_Screen_Cols + col; |
7d4604a9 | 1104 | } |
1105 | ||
1106 | if (row < 0) { | |
6f481af2 | 1107 | row = SLtt_Screen_Rows + row; |
7d4604a9 | 1108 | } |
45f6c4fd | 1109 | |
81361f3e | 1110 | SLsmg_gotorc(row, col); |
10de8f4a | 1111 | SLsmg_write_string((char *)text); |
81361f3e | 1112 | } |
a1f11019 | 1113 | |
1114 | int newtSetFlags(int oldFlags, int newFlags, enum newtFlagsSense sense) { | |
1115 | switch (sense) { | |
1116 | case NEWT_FLAGS_SET: | |
6f481af2 | 1117 | return oldFlags | newFlags; |
a1f11019 | 1118 | |
1119 | case NEWT_FLAGS_RESET: | |
6f481af2 | 1120 | return oldFlags & (~newFlags); |
a1f11019 | 1121 | |
69bf2308 | 1122 | case NEWT_FLAGS_TOGGLE: |
6f481af2 | 1123 | return oldFlags ^ newFlags; |
69bf2308 | 1124 | |
a1f11019 | 1125 | default: |
6f481af2 | 1126 | return oldFlags; |
a1f11019 | 1127 | } |
1128 | } | |
69bf2308 | 1129 | |
1130 | void newtBell(void) | |
1131 | { | |
721584c3 | 1132 | SLtt_beep(); |
1133 | } | |
1134 | ||
1135 | void newtGetScreenSize(int * cols, int * rows) { | |
1136 | if (rows) *rows = SLtt_Screen_Rows; | |
1137 | if (cols) *cols = SLtt_Screen_Cols; | |
69bf2308 | 1138 | } |
8f52cd47 | 1139 | |
1140 | void newtDefaultPlaceHandler(newtComponent c, int newLeft, int newTop) { | |
1141 | c->left = newLeft; | |
1142 | c->top = newTop; | |
1143 | } | |
1144 | ||
1145 | void newtDefaultMappedHandler(newtComponent c, int isMapped) { | |
1146 | c->isMapped = isMapped; | |
1147 | } | |
23efd09b | 1148 | |
1149 | void newtCursorOff(void) { | |
5e171db1 | 1150 | cursorOn = 0; |
1151 | SLtt_set_cursor_visibility (cursorOn); | |
23efd09b | 1152 | } |
1153 | ||
1154 | void newtCursorOn(void) { | |
5e171db1 | 1155 | cursorOn = 1; |
1156 | SLtt_set_cursor_visibility (cursorOn); | |
23efd09b | 1157 | } |
7ff5fd71 | 1158 | |
1159 | void newtTrashScreen(void) { | |
1160 | if (trashScreen) | |
5baf7e4b | 1161 | SLsmg_touch_lines(0, SLtt_Screen_Rows); |
7ff5fd71 | 1162 | } |
1163 | ||
c397bfc8 DW |
1164 | void newtComponentGetPosition(newtComponent co, int * left, int * top) { |
1165 | if (left) *left = co->left; | |
1166 | if (top) *top = co->top; | |
1167 | } | |
1168 | ||
1169 | void newtComponentGetSize(newtComponent co, int * width, int * height) { | |
1170 | if (width) *width = co->width; | |
1171 | if (height) *height = co->height; | |
1172 | } |