1 /****************************************************************************
2 * Copyright 2019,2020 Thomas E. Dickey *
3 * Copyright 2008-2016,2017 Free Software Foundation, Inc. *
4 * *
5 * Permission is hereby granted, free of charge, to any person obtaining a *
6 * copy of this software and associated documentation files (the *
7 * "Software"), to deal in the Software without restriction, including *
8 * without limitation the rights to use, copy, modify, merge, publish, *
9 * distribute, distribute with modifications, sublicense, and/or sell *
10 * copies of the Software, and to permit persons to whom the Software is *
11 * furnished to do so, subject to the following conditions: *
12 * *
13 * The above copyright notice and this permission notice shall be included *
14 * in all copies or substantial portions of the Software. *
15 * *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * *
24 * Except as contained in this notice, the name(s) of the above copyright *
25 * holders shall not be used in advertising or otherwise to promote the *
26 * sale, use or other dealings in this Software without prior written *
27 * authorization. *
28 ****************************************************************************/
29 /*
30 * $Id: clip_printw.c,v 1.19 2020/05/10 00:40:23 tom Exp $
31 *
32 * demonstrate how to use printw without wrapping.
33 */
34
35 #include <test.priv.h>
36 #include <popup_msg.h>
37
38 #ifdef HAVE_VW_PRINTW
39
40 #define SHOW(n) ((n) == ERR ? "ERR" : "OK")
41 #define COLOR_DEFAULT (-1)
42
43 typedef struct {
44 unsigned c;
45 unsigned v;
46 int status;
47 int pair;
48 attr_t attr;
49 int count;
50 int ch;
51 const char *c_msg;
52 const char *v_msg;
53 int y_val;
54 int x_val;
55 int y_beg, x_beg;
56 int y_max, x_max;
57 } STATUS;
58
59 static int
clip_wprintw(WINDOW * win,NCURSES_CONST char * fmt,...)60 clip_wprintw(WINDOW *win, NCURSES_CONST char *fmt, ...)
61 {
62 int y0, x0, y1, x1, width;
63 WINDOW *sub;
64 va_list ap;
65 int rc;
66
67 /*
68 * Allocate a single-line derived window extending from the current
69 * cursor position to the end of the current line in the given window.
70 * Disable scrolling in the derived window.
71 */
72 getyx(win, y0, x0);
73 width = getmaxx(win) - x0;
74 sub = derwin(win, 1, width, y0, x0);
75 scrollok(sub, FALSE);
76
77 /*
78 * Print the text.
79 */
80 va_start(ap, fmt);
81 rc = vw_printw(sub, fmt, ap);
82 va_end(ap);
83
84 getyx(sub, y1, x1);
85 delwin(sub);
86
87 wmove(win, y1 + y0, x1 + x0);
88
89 return rc;
90 }
91
92 static const char *
color_params(unsigned state,int * pair)93 color_params(unsigned state, int *pair)
94 {
95 /* *INDENT-OFF* */
96 static struct {
97 int pair;
98 int fg, bg;
99 const char *msg;
100 } table[] = {
101 { 0, COLOR_DEFAULT, COLOR_DEFAULT, "default" },
102 { 1, COLOR_RED, COLOR_BLACK, "red/black" },
103 { 2, COLOR_WHITE, COLOR_BLUE, "white/blue" },
104 };
105 /* *INDENT-ON* */
106
107 const char *result = 0;
108
109 if (has_colors()) {
110 static bool first = TRUE;
111
112 if (first) {
113 unsigned n;
114
115 start_color();
116 for (n = 0; n < SIZEOF(table); ++n) {
117 init_pair((short) table[n].pair,
118 (short) table[n].fg,
119 (short) table[n].bg);
120 }
121 }
122 if (state < SIZEOF(table)) {
123 *pair = table[state].pair;
124 result = table[state].msg;
125 }
126 }
127 return result;
128 }
129
130 static const char *
video_params(unsigned state,attr_t * attr)131 video_params(unsigned state, attr_t *attr)
132 {
133 /* *INDENT-OFF* */
134 static struct {
135 attr_t attr;
136 const char *msg;
137 } table[] = {
138 { WA_NORMAL, "normal" },
139 { WA_BOLD, "bold" },
140 { WA_REVERSE, "reverse" },
141 { WA_UNDERLINE, "underline" },
142 { WA_BLINK, "blink" },
143 };
144 /* *INDENT-ON* */
145
146 const char *result = 0;
147
148 if (state < SIZEOF(table)) {
149 *attr = table[state].attr;
150 result = table[state].msg;
151 }
152 return result;
153 }
154
155 /* fill the window with a test-pattern */
156 static void
fill_window(WINDOW * win)157 fill_window(WINDOW *win)
158 {
159 int y, x;
160 int y0 = -1, x0 = -1;
161
162 getyx(win, y, x);
163 wmove(win, 0, 0);
164 while (waddstr(win, "0123456789 abcdefghijklmnopqrstuvwxyz ") != ERR) {
165 int y1, x1;
166 getyx(win, y1, x1);
167 if (y1 == y0 && x1 == x0)
168 break;
169 x0 = x1;
170 y0 = y1;
171 }
172 wmove(win, y, x);
173 }
174
175 static void
show_status(WINDOW * win,STATUS * sp)176 show_status(WINDOW *win, STATUS * sp)
177 {
178 int y, x;
179
180 getyx(win, y, x);
181 wmove(win, 0, 0);
182 wprintw(win, "Count %d", sp->count);
183 if (sp->v_msg != 0)
184 wprintw(win, " Video %s", sp->v_msg);
185 if (sp->c_msg != 0)
186 wprintw(win, " Color %s", sp->c_msg);
187 wprintw(win, " (%d)", sp->status);
188 wclrtoeol(win);
189 wmove(win, y, x);
190 }
191
192 static void
do_subwindow(WINDOW * win,STATUS * sp,void func (WINDOW *))193 do_subwindow(WINDOW *win, STATUS * sp, void func(WINDOW *))
194 {
195 WINDOW *win1 = newwin(sp->y_max - 2, sp->x_max - 2,
196 sp->y_beg + 1, sp->x_beg + 1);
197
198 if (win1 != 0 && sp->y_max > 4 && sp->x_max > 4) {
199 WINDOW *win2 = derwin(win1, sp->y_max - 4, sp->x_max - 4, 1, 1);
200
201 if (win2 != 0) {
202 box(win1, 0, 0);
203 wrefresh(win1);
204 func(win2);
205
206 delwin(win2);
207 } else {
208 beep();
209 }
210 delwin(win1);
211 touchwin(win);
212 } else {
213 if (win1)
214 delwin(win1);
215 beep();
216 }
217 }
218
219 static void
init_status(WINDOW * win,STATUS * sp)220 init_status(WINDOW *win, STATUS * sp)
221 {
222 memset(sp, 0, sizeof(*sp));
223 sp->c = 99;
224 sp->v = 99;
225 sp->ch = ' ';
226
227 keypad(win, TRUE);
228 fill_window(win);
229
230 getbegyx(win, sp->y_beg, sp->x_beg);
231 getmaxyx(win, sp->y_max, sp->x_max);
232 }
233
234 static void
show_help(WINDOW * win)235 show_help(WINDOW *win)
236 {
237 static const char *msgs[] =
238 {
239 "Basic commands:"
240 ,"Use h/j/k/l or arrow keys to move the cursor."
241 ,"Set the count parameter for clip_wprintw by entering digits 0-9."
242 ,""
243 ,"Other commands:"
244 ,"space toggles through the set of video attributes and colors."
245 ,"t touches (forces repaint) of the current line."
246 ,". calls vw_printw at the current position with the given count."
247 ,"= resets count to zero."
248 ,"? shows this help-window"
249 ,0
250 };
251
252 popup_msg(win, msgs);
253 }
254
255 static void
update_status(WINDOW * win,STATUS * sp)256 update_status(WINDOW *win, STATUS * sp)
257 {
258 switch (sp->ch) {
259 case ' ': /* next test-iteration */
260 if (has_colors()) {
261 if ((sp->c_msg = color_params(++(sp->c), &(sp->pair))) == 0) {
262 sp->c_msg = color_params(sp->c = 0, &(sp->pair));
263 if ((sp->v_msg = video_params(++(sp->v), &(sp->attr))) == 0) {
264 sp->v_msg = video_params(sp->v = 0, &(sp->attr));
265 }
266 }
267 } else {
268 if ((sp->v_msg = video_params(++(sp->v), &(sp->attr))) == 0) {
269 sp->v_msg = video_params(sp->v = 0, &(sp->attr));
270 }
271 }
272 sp->count = 0;
273 show_status(win, sp);
274 break;
275 case KEY_LEFT:
276 case 'h':
277 if (sp->x_val > 0)
278 wmove(win, sp->y_val, --(sp->x_val));
279 break;
280 case KEY_DOWN:
281 case 'j':
282 if (sp->y_val < sp->y_max)
283 wmove(win, ++(sp->y_val), sp->x_val);
284 break;
285 case KEY_UP:
286 case 'k':
287 if (sp->y_val > 0)
288 wmove(win, --(sp->y_val), sp->x_val);
289 break;
290 case KEY_RIGHT:
291 case 'l':
292 if (sp->x_val < sp->x_max)
293 wmove(win, sp->y_val, ++(sp->x_val));
294 break;
295 case 't':
296 touchline(win, sp->y_val, 1);
297 break;
298 case '=':
299 sp->count = 0;
300 show_status(win, sp);
301 break;
302 case HELP_KEY_1:
303 show_help(win);
304 break;
305 default:
306 if (isdigit(sp->ch)) {
307 sp->count = (sp->count * 10) + (sp->ch - '0');
308 show_status(win, sp);
309 } else {
310 beep();
311 }
312 break;
313 }
314 }
315
316 static void
test_clipping(WINDOW * win)317 test_clipping(WINDOW *win)
318 {
319 STATUS st;
320 char fmt[80];
321 char *buffer;
322 unsigned j, need;
323
324 init_status(win, &st);
325
326 do {
327 switch (st.ch) {
328 case '.': /* change from current position */
329 (void) wattrset(win, AttrArg(COLOR_PAIR(st.pair), st.attr));
330 if (st.count > 0) {
331 need = (unsigned) st.count + 1;
332 _nc_SPRINTF(fmt, _nc_SLIMIT(sizeof(fmt)) "%%c%%%ds%%c", st.count);
333 } else {
334 int want = getmaxx(win);
335 if (want < 10)
336 want = 10;
337 need = (unsigned) want - 1;
338 _nc_STRCPY(fmt, "%c%s%c", sizeof(fmt));
339 }
340 if ((buffer = typeMalloc(char, need + 1)) != 0) {
341 for (j = 0; j < need; ++j) {
342 buffer[j] = (char) ('A' + (j % 26));
343 }
344 buffer[need - 1] = '\0';
345 st.status = clip_wprintw(win, fmt, '[', buffer, ']');
346 free(buffer);
347 }
348 break;
349 case 'w':
350 do_subwindow(win, &st, test_clipping);
351 break;
352 case 'q':
353 return;
354 default:
355 update_status(win, &st);
356 break;
357 }
358 } while ((st.ch = wgetch(win)) != ERR);
359 }
360
361 int
main(int argc GCC_UNUSED,char * argv[]GCC_UNUSED)362 main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
363 {
364 initscr();
365 cbreak();
366 noecho();
367
368 test_clipping(stdscr);
369 endwin();
370
371 ExitProgram(EXIT_SUCCESS);
372 }
373
374 #else
375 int
main(void)376 main(void)
377 {
378 printf("This program requires the curses vw_printw function\n");
379 ExitProgram(EXIT_FAILURE);
380 }
381 #endif
382