1 /* Public Domain Curses */
2
3 #include <curspriv.h>
4
5 /*man-start**************************************************************
6
7 slk
8 ---
9
10 ### Synopsis
11
12 int slk_init(int fmt);
13 int slk_set(int labnum, const char *label, int justify);
14 int slk_refresh(void);
15 int slk_noutrefresh(void);
16 char *slk_label(int labnum);
17 int slk_clear(void);
18 int slk_restore(void);
19 int slk_touch(void);
20 int slk_attron(const chtype attrs);
21 int slk_attr_on(const attr_t attrs, void *opts);
22 int slk_attrset(const chtype attrs);
23 int slk_attr_set(const attr_t attrs, short color_pair, void *opts);
24 int slk_attroff(const chtype attrs);
25 int slk_attr_off(const attr_t attrs, void *opts);
26 int slk_color(short color_pair);
27
28 int slk_wset(int labnum, const wchar_t *label, int justify);
29
30 int PDC_mouse_in_slk(int y, int x);
31 void PDC_slk_free(void);
32 void PDC_slk_initialize(void);
33
34 wchar_t *slk_wlabel(int labnum)
35
36 ### Description
37
38 These functions manipulate a window that contain Soft Label Keys
39 (SLK). To use the SLK functions, a call to slk_init() must be
40 made BEFORE initscr() or newterm(). slk_init() removes 1 or 2
41 lines from the useable screen, depending on the format selected.
42
43 The line(s) removed from the screen are used as a separate
44 window, in which SLKs are displayed.
45
46 slk_init() requires a single parameter which describes the
47 format of the SLKs as follows:
48
49 0 3-2-3 format
50 1 4-4 format
51 2 4-4-4 format (ncurses extension)
52 3 4-4-4 format with index line (ncurses extension)
53 2 lines used
54 55 5-5 format (pdcurses format)
55
56 In PDCurses, one can alternatively set fmt as a series of hex
57 digits specifying the format. For example, 0x414 would result
58 in 4-1-4 format; 0x21b3 would result in 2-1-11-3 format; and
59 so on. Also, negating fmt results in the index line being added.
60
61 Also, in PDCurses, one can call slk_init() at any time
62 _after_ initscr(), to reset the label format. If you do this,
63 you'll need to reset the label text and call slk_refresh(). And
64 you can't toggle the index line. (Doing so would add/remove a line
65 from the useable screen, which would be hard to handle correctly.)
66
67 slk_refresh(), slk_noutrefresh() and slk_touch() are analogous
68 to refresh(), noutrefresh() and touch().
69
70 ### Return Value
71
72 All functions return OK on success and ERR on error.
73
74 ### Portability
75 X/Open BSD SYS V
76 slk_init Y - Y
77 slk_set Y - Y
78 slk_refresh Y - Y
79 slk_noutrefresh Y - Y
80 slk_label Y - Y
81 slk_clear Y - Y
82 slk_restore Y - Y
83 slk_touch Y - Y
84 slk_attron Y - Y
85 slk_attrset Y - Y
86 slk_attroff Y - Y
87 slk_attr_on Y
88 slk_attr_set Y
89 slk_attr_off Y
90 slk_wset Y
91 PDC_mouse_in_slk - - -
92 PDC_slk_free - - -
93 PDC_slk_initialize - - -
94 slk_wlabel - - -
95
96 **man-end****************************************************************/
97
98 #include <stdlib.h>
99
100 static int label_length = 0;
101 static int n_labels = 0;
102 static int label_fmt = 0;
103 static int label_line = 0;
104 static bool hidden = FALSE;
105
106 #define MAX_LABEL_LENGTH 32
107
108 static struct SLK {
109 chtype label[MAX_LABEL_LENGTH];
110 int len;
111 int format;
112 int start_col;
113 } *slk = (struct SLK *)NULL;
114
115 /* See comments above on this function. */
116
slk_init(int fmt)117 int slk_init(int fmt)
118 {
119 int i;
120
121 PDC_LOG(("slk_init() - called\n"));
122
123 switch (fmt)
124 {
125 case 0: /* 3 - 2 - 3 */
126 label_fmt = 0x323;
127 break;
128
129 case 1: /* 4 - 4 */
130 label_fmt = 0x44;
131 break;
132
133 case 2: /* 4 4 4 */
134 label_fmt = 0x444;
135 break;
136
137 case 3: /* 4 4 4 with index */
138 label_fmt = -0x444;
139 break;
140
141 case 55: /* 5 - 5 */
142 label_fmt = 0x55;
143 break;
144
145 default:
146 label_fmt = fmt;
147 break;
148 }
149
150 traceon( );
151 n_labels = 0;
152 for( i = abs( label_fmt); i; i /= 16)
153 n_labels += i % 16;
154
155 PDC_LOG(("slk_init: fmt %d, %d labels, %p\n",
156 fmt, n_labels, slk));
157 if( slk)
158 free( slk);
159 slk = calloc(n_labels, sizeof(struct SLK));
160 PDC_LOG(( "New slk: %p; SP = %p\n", slk, SP));
161 traceoff( );
162
163 if (!slk)
164 n_labels = 0;
165 if( SP)
166 {
167 if( SP->slk_winptr)
168 wclear( SP->slk_winptr);
169 PDC_slk_initialize( );
170 }
171
172 return slk ? OK : ERR;
173 }
174
175 /* draw a single button */
176
_drawone(int num)177 static void _drawone(int num)
178 {
179 int i, col, slen;
180
181 if (hidden)
182 return;
183
184 slen = slk[num].len;
185
186 switch (slk[num].format)
187 {
188 case 0: /* LEFT */
189 col = 0;
190 break;
191
192 case 1: /* CENTER */
193 col = (label_length - slen) / 2;
194
195 if (col + slen > label_length)
196 --col;
197 break;
198
199 default: /* RIGHT */
200 col = label_length - slen;
201 }
202
203 if( col < 0) /* Ensure start of label is visible */
204 col = 0;
205 wmove(SP->slk_winptr, label_line, slk[num].start_col);
206
207 for (i = 0; i < label_length; ++i)
208 waddch(SP->slk_winptr, (i >= col && i < (col + slen)) ?
209 slk[num].label[i - col] : ' ');
210 }
211
212 /* redraw each button */
213
_redraw(void)214 static void _redraw(void)
215 {
216 int i;
217
218 if( !hidden)
219 {
220 for (i = 0; i < n_labels; ++i)
221 _drawone(i);
222 if (label_fmt < 0)
223 {
224 const chtype save_attr = SP->slk_winptr->_attrs;
225
226 wattrset(SP->slk_winptr, A_NORMAL);
227 wmove(SP->slk_winptr, 0, 0);
228 whline(SP->slk_winptr, 0, COLS);
229
230 for (i = 0; i < n_labels; i++)
231 mvwprintw(SP->slk_winptr, 0, slk[i].start_col, "F%d", i + 1);
232
233 SP->slk_winptr->_attrs = save_attr;
234 }
235 }
236 }
237
238 /* slk_set() Used to set a slk label to a string.
239
240 labnum = 1 - 8 (or 10) (number of the label)
241 label = string (8 or 7 bytes total), or NULL
242 justify = 0 : left, 1 : center, 2 : right */
243
slk_set(int labnum,const char * label,int justify)244 int slk_set(int labnum, const char *label, int justify)
245 {
246 #ifdef PDC_WIDE
247 wchar_t wlabel[MAX_LABEL_LENGTH];
248
249 PDC_mbstowcs(wlabel, label, MAX_LABEL_LENGTH - 1);
250 return slk_wset(labnum, wlabel, justify);
251 #else
252 PDC_LOG(("slk_set() - called\n"));
253
254 if (labnum < 1 || labnum > n_labels || justify < 0 || justify > 2)
255 return ERR;
256
257 labnum--;
258
259 if (!label || !(*label))
260 {
261 /* Clear the label */
262
263 *slk[labnum].label = 0;
264 slk[labnum].format = 0;
265 slk[labnum].len = 0;
266 }
267 else
268 {
269 int i;
270
271 /* Skip leading spaces */
272
273 while( *label == ' ')
274 label++;
275
276 /* Copy it */
277
278 for (i = 0; label[i] && i < MAX_LABEL_LENGTH - 1; i++)
279 slk[labnum].label[i] = label[i];
280
281 /* Drop trailing spaces */
282
283 while( i && label[i - 1] == ' ')
284 i--;
285
286 slk[labnum].label[i] = 0;
287 slk[labnum].format = justify;
288 slk[labnum].len = i;
289 }
290
291 _drawone(labnum);
292
293 return OK;
294 #endif
295 }
296
slk_refresh(void)297 int slk_refresh(void)
298 {
299 PDC_LOG(("slk_refresh() - called\n"));
300
301 return (slk_noutrefresh() == ERR) ? ERR : doupdate();
302 }
303
slk_noutrefresh(void)304 int slk_noutrefresh(void)
305 {
306 PDC_LOG(("slk_noutrefresh() - called\n"));
307
308 return wnoutrefresh(SP->slk_winptr);
309 }
310
slk_label(int labnum)311 char *slk_label(int labnum)
312 {
313 static char temp[MAX_LABEL_LENGTH + 1];
314 #ifdef PDC_WIDE
315 wchar_t *wtemp = slk_wlabel(labnum);
316
317 PDC_wcstombs(temp, wtemp, MAX_LABEL_LENGTH);
318 #else
319 chtype *p;
320 int i;
321
322 PDC_LOG(("slk_label() - called\n"));
323
324 if (labnum < 1 || labnum > n_labels)
325 return (char *)0;
326
327 for (i = 0, p = slk[labnum - 1].label; *p; i++)
328 temp[i] = (char)*p++; /* BJG */
329
330 temp[i] = '\0';
331 #endif
332 return temp;
333 }
334
slk_clear(void)335 int slk_clear(void)
336 {
337 PDC_LOG(("slk_clear() - called\n"));
338
339 hidden = TRUE;
340 werase(SP->slk_winptr);
341 return wrefresh(SP->slk_winptr);
342 }
343
slk_restore(void)344 int slk_restore(void)
345 {
346 PDC_LOG(("slk_restore() - called\n"));
347
348 hidden = FALSE;
349 _redraw();
350 return wrefresh(SP->slk_winptr);
351 }
352
slk_touch(void)353 int slk_touch(void)
354 {
355 PDC_LOG(("slk_touch() - called\n"));
356
357 return touchwin(SP->slk_winptr);
358 }
359
slk_attron(const chtype attrs)360 int slk_attron(const chtype attrs)
361 {
362 int rc;
363
364 PDC_LOG(("slk_attron() - called\n"));
365
366 rc = wattron(SP->slk_winptr, attrs);
367 _redraw();
368
369 return rc;
370 }
371
slk_attr_on(const attr_t attrs,void * opts)372 int slk_attr_on(const attr_t attrs, void *opts)
373 {
374 PDC_LOG(("slk_attr_on() - called\n"));
375
376 return slk_attron(attrs);
377 }
378
slk_attroff(const chtype attrs)379 int slk_attroff(const chtype attrs)
380 {
381 int rc;
382
383 PDC_LOG(("slk_attroff() - called\n"));
384
385 rc = wattroff(SP->slk_winptr, attrs);
386 _redraw();
387
388 return rc;
389 }
390
slk_attr_off(const attr_t attrs,void * opts)391 int slk_attr_off(const attr_t attrs, void *opts)
392 {
393 PDC_LOG(("slk_attr_off() - called\n"));
394
395 return slk_attroff(attrs);
396 }
397
slk_attrset(const chtype attrs)398 int slk_attrset(const chtype attrs)
399 {
400 int rc;
401
402 PDC_LOG(("slk_attrset() - called\n"));
403
404 rc = wattrset(SP->slk_winptr, attrs);
405 _redraw();
406
407 return rc;
408 }
409
slk_color(short color_pair)410 int slk_color(short color_pair)
411 {
412 int rc;
413
414 PDC_LOG(("slk_color() - called\n"));
415
416 rc = wcolor_set(SP->slk_winptr, color_pair, NULL);
417 _redraw();
418
419 return rc;
420 }
421
slk_attr_set(const attr_t attrs,short color_pair,void * opts)422 int slk_attr_set(const attr_t attrs, short color_pair, void *opts)
423 {
424 PDC_LOG(("slk_attr_set() - called\n"));
425
426 return slk_attrset(attrs | COLOR_PAIR(color_pair));
427 }
428
_slk_calc(void)429 static void _slk_calc(void)
430 {
431 int i, j, idx, remaining_space;
432 int n_groups = 0, group_size[10];
433
434 label_length = COLS / n_labels;
435 if (label_length > MAX_LABEL_LENGTH)
436 label_length = MAX_LABEL_LENGTH;
437 remaining_space = COLS - label_length * n_labels + 1;
438 for( i = abs( label_fmt); i; i /= 16)
439 group_size[n_groups++] = i % 16;
440 /* We really want at least two spaces between groups: */
441 while( label_length > 1 && remaining_space < n_groups - 1)
442 {
443 label_length--;
444 remaining_space += n_labels;
445 }
446
447 for( i = idx = 0; i < n_groups; i++)
448 for( j = 0; j < group_size[i]; j++, idx++)
449 slk[idx].start_col = label_length * idx
450 + (i ? (i * remaining_space) / (n_groups - 1) : 0);
451
452 if( label_length)
453 --label_length;
454
455 /* make sure labels are all in window */
456
457 _redraw();
458 }
459
PDC_slk_initialize(void)460 void PDC_slk_initialize(void)
461 {
462 if (slk)
463 {
464 if( label_fmt < 0)
465 {
466 SP->slklines = 2;
467 label_line = 1;
468 }
469 else
470 SP->slklines = 1;
471
472 if (!SP->slk_winptr)
473 {
474 if ( !(SP->slk_winptr = newwin(SP->slklines, COLS,
475 LINES - SP->slklines, 0)) )
476 return;
477
478 wattrset(SP->slk_winptr, A_REVERSE);
479 }
480
481 _slk_calc();
482
483 touchwin(SP->slk_winptr);
484 }
485 }
486
PDC_slk_free(void)487 void PDC_slk_free(void)
488 {
489 if (slk)
490 {
491 if (SP->slk_winptr)
492 {
493 delwin(SP->slk_winptr);
494 SP->slk_winptr = (WINDOW *)NULL;
495 }
496
497 free(slk);
498 slk = (struct SLK *)NULL;
499
500 label_length = 0;
501 n_labels = 0;
502 label_fmt = 0;
503 label_line = 0;
504 hidden = FALSE;
505 }
506 }
507
PDC_mouse_in_slk(int y,int x)508 int PDC_mouse_in_slk(int y, int x)
509 {
510 int i;
511
512 PDC_LOG(("PDC_mouse_in_slk() - called: y->%d x->%d\n", y, x));
513
514 /* If the line on which the mouse was clicked is NOT the last line
515 of the screen, or the SLKs are hidden, we are not interested in it. */
516
517 if (!slk || hidden || !SP->slk_winptr
518 || (y != SP->slk_winptr->_begy + label_line))
519 return 0;
520
521 for (i = 0; i < n_labels; i++)
522 if (x >= slk[i].start_col && x < (slk[i].start_col + label_length))
523 return i + 1;
524
525 return 0;
526 }
527
528 #ifdef PDC_WIDE
slk_wset(int labnum,const wchar_t * label,int justify)529 int slk_wset(int labnum, const wchar_t *label, int justify)
530 {
531 PDC_LOG(("slk_wset() - called\n"));
532
533 if (labnum < 1 || labnum > n_labels || justify < 0 || justify > 2)
534 return ERR;
535
536 labnum--;
537
538 if (!label || !(*label))
539 {
540 /* Clear the label */
541
542 *slk[labnum].label = 0;
543 slk[labnum].format = 0;
544 slk[labnum].len = 0;
545 }
546 else
547 {
548 int i;
549
550 /* Skip leading spaces */
551
552 while( *label == L' ')
553 label++;
554
555 /* Copy it */
556
557 for (i = 0; label[i] && i < MAX_LABEL_LENGTH - 1; i++)
558 slk[labnum].label[i] = label[i];
559
560 /* Drop trailing spaces */
561
562 while( i && label[i - 1] == L' ')
563 i--;
564
565 slk[labnum].label[i] = 0;
566 slk[labnum].format = justify;
567 slk[labnum].len = i;
568 }
569
570 _drawone(labnum);
571
572 return OK;
573 }
574
slk_wlabel(int labnum)575 wchar_t *slk_wlabel(int labnum)
576 {
577 static wchar_t temp[MAX_LABEL_LENGTH + 1];
578 chtype *p;
579 int i;
580
581 PDC_LOG(("slk_wlabel() - called\n"));
582
583 if (labnum < 1 || labnum > n_labels)
584 return (wchar_t *)0;
585
586 for (i = 0, p = slk[labnum - 1].label; *p; i++)
587 temp[i] = (wchar_t)*p++;
588
589 temp[i] = '\0';
590
591 return temp;
592 }
593 #endif
594