2
Copyright (c) 2006 Perry Rapp
4
Permission is hereby granted, free of charge, to any person
5
obtaining a copy of this software and associated documentation
6
files (the "Software"), to deal in the Software without
7
restriction, including without limitation the rights to use, copy,
8
modify, merge, publish, distribute, sublicense, and/or sell copies
9
of the Software, and to permit persons to whom the Software is
10
furnished to do so, subject to the following conditions:
12
The above copyright notice and this permission notice shall be
13
included in all copies or substantial portions of the Software.
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
/*=============================================================
25
* listui.c -- display code for popup list and list browse screen
27
*===========================================================*/
37
#include "lloptions.h"
45
#ifdef WIN32_ICONV_SHIM
46
#include "iconvshim.h"
49
#include "charprops.h"
54
static INT LISTWIN_WIDTH=0;
56
/*********************************************
57
* external/imported variables
58
*********************************************/
60
extern STRING qSmn_quit;
62
/*********************************************
64
*********************************************/
67
Data for lists display
68
Both popup & full-screen lists have 3 rectangles:
69
details, list items, and menu
70
But they are not in the same place
72
typedef struct listdisp_s
75
struct tag_llrect rectList;
76
struct tag_llrect rectDetails;
77
struct tag_llrect rectMenu;
78
INT details; /* #rows of detail info */
80
INT details_beginhgt; /* increase from 0 goes to this */
82
INT details_scroll; /* scroll offset in detail area */
83
INT cur; /* current item selected, 0-based */
84
INT listlen; /* #items total */
85
INT top; /* current item at top of display, 0-based */
86
INT mode; /* record display mode */
89
/*********************************************
90
* local function prototypes
91
*********************************************/
94
static void activate_popup_list_uiwin (listdisp * ld);
95
static void display_string(UIWINDOW uiwin, LLRECT rect, STRING text);
96
static INT handle_list_cmds(listdisp * ld, INT code);
97
static BOOLEAN handle_popup_list_resize(listdisp * ld, INT code);
98
static void print_list_title(char * buffer, INT len, const listdisp * ld, STRING ttl);
99
static void shw_array_of_strings(STRING *strings, listdisp *ld
100
, DETAILFNC detfnc, void * param);
101
static void shw_popup_list(INDISEQ seq, listdisp * ld);
102
static void shw_recordlist_details(INDISEQ seq, listdisp * ld);
103
static void shw_recordlist_list(INDISEQ seq, listdisp * ld);
105
/*********************************************
107
*********************************************/
109
/* the following values are default (larger screens get more) */
110
static int LIST_LINES_DEF = 6; /* number of lines of person info in list */
111
static int POPUP_LINES_DEF = 17; /* max lines in popup list */
113
static int LIST_LINES=0;
114
static int POPUP_LINES=0;
116
/*==============================================
117
* listui_init_windows -- Initialize anything dependent on screen size
118
*============================================*/
120
listui_init_windows (INT extralines)
122
/* initialize list window heights to default */
123
LIST_LINES = LIST_LINES_DEF;
124
POPUP_LINES = POPUP_LINES_DEF;
125
/* increase for larger screens */
127
LIST_LINES = LIST_LINES_DEF + extralines;
128
POPUP_LINES = POPUP_LINES_DEF + extralines;
131
LISTWIN_WIDTH = ll_cols-7;
133
/*==============================================
134
* array_interact -- Interact with user over list
136
* len: [IN] number of choices
137
* strings: [IN] array of choices
138
* selectable: [IN] FALSE for view-only
139
* detfnc: [IN] callback for details about items
140
* param: [IN] opaque type for callback
141
* returns 0-based index chosen, or -1 if cancelled
142
*============================================*/
144
array_interact (STRING ttl, INT len, STRING *strings
145
, BOOLEAN selectable, DETAILFNC detfnc, void * param)
150
STRING responses = len<10 ? "jkiq123456789[]()$^" : "jkiq[]()$^";
152
listdisp ld; /* structure used in resizable list displays */
155
promptline = _("Commands: j Move down k Move up i Select q Quit");
157
promptline = _("Commands: j Move down k Move up q Quit");
159
memset(&ld, 0, sizeof(ld));
161
ld.mode = 'n'; /* irrelevant for array list */
163
resize_win: /* we come back here if we resize the window */
164
activate_popup_list_uiwin(&ld);
165
win = uiw_win(ld.uiwin);
168
row = ld.rectMenu.top-1;
169
show_horz_line(ld.uiwin, row++, 0, uiw_cols(ld.uiwin));
170
mvccwaddstr(win, row, ld.rectMenu.left, promptline);
174
print_list_title(fulltitle, sizeof(fulltitle), &ld, _(ttl));
175
mvccwaddstr(win, 1, 1, fulltitle);
176
shw_array_of_strings(strings, &ld, detfnc, param);
178
code = interact_popup(ld.uiwin, responses);
179
if (handle_list_cmds(&ld, code))
181
if (handle_popup_list_resize(&ld, code)) {
182
deactivate_uiwin_and_touch_all();
183
/* we're going to repick window & activate */
186
if (ret == 0) { /* not handled yet */
188
case 'i': /* select current item */
203
if (len < 10 && selectable && code - '1' < len) {
210
ld.cur = -1; /* ld.cur == -1 means cancelled */
214
deactivate_uiwin_and_touch_all();
217
/*=============================================================
218
* choose_one_or_list_from_indiseq --
219
* Implements the two choose_xxx_from_indiseq
220
* @ttl: [IN] title/caption for choice list
221
* @seq: [IN] list from which to choose
222
* @multi: [IN] if true, selecting a sublist
223
* returns index of selected (or -1 for quit)
224
* Rewritten to allow dynamic resizing (so user can
225
* resize detail area, ie, the [] functions), 2000/12, Perry Rapp
227
*===========================================================*/
229
choose_one_or_list_from_indiseq (STRING ttl, INDISEQ seq, BOOLEAN multi)
235
listdisp ld; /* structure used in resizable list displays */
236
STRING menu, choices;
241
calc_indiseq_names(seq); /* we certainly need the names */
243
memset(&ld, 0, sizeof(ld));
244
ld.listlen = length_indiseq(seq);
247
/* TO DO: connect this to menuitem system */
249
menu = _("Commands: j Move down k Move up d Delete i Select q Quit");
250
choices = "jkriq123456789()[]$^udUD";
252
menu = _("Commands: j Move down k Move up i Select q Quit");
253
choices = "jkiq123456789()[]$^udUD";
256
resize_win: /* we come back here if we resize the window */
257
activate_popup_list_uiwin(&ld);
258
win = uiw_win(ld.uiwin);
260
elemwidth = ld.rectDetails.right - ld.rectDetails.left + 1;
261
if (length_indiseq(seq)<50)
262
preprint_indiseq(seq, elemwidth, &disp_shrt_rfmt);
267
row = ld.rectMenu.top-1;
268
show_horz_line(ld.uiwin, row++, 0, uiw_cols(ld.uiwin));
269
mvccwaddstr(win, row, ld.rectMenu.left, menu);
273
print_list_title(fulltitle, sizeof(fulltitle), &ld, ttl);
274
mvccwaddstr(win, 1, 1, fulltitle);
275
shw_popup_list(seq, &ld);
278
code = interact_popup(ld.uiwin, choices);
279
if (handle_list_cmds(&ld, code))
281
if (handle_popup_list_resize(&ld, code)) {
282
deactivate_uiwin_and_touch_all(); /* kills ld.uiwin */
284
/* we're going to repick window & activate */
287
if (ret == 0) { /* not handled yet */
292
delete_indiseq(seq, NULL, NULL, ld.cur);
293
if (!(ld.listlen = length_indiseq(seq))) {
297
if (ld.cur == ld.listlen) ld.cur--;
298
if (ld.cur < ld.top) ld.top = ld.cur;
303
/* ld.cur points to currently selected */
314
if (ld.listlen < 10 && code - '1' < ld.listlen) {
321
ld.cur = -1; /* ld.cur == -1 means cancelled */
326
deactivate_uiwin_and_touch_all(); /* kills ld.uiwin */
331
/*=============================================================
332
* handle_list_cmds -- Process choices from list display
333
* This handles moving up & down, adjusting size of detail,
334
* and scrolling detail.
335
* @listdisp: [I/O] array of info about list display
336
* @code: [IN] command to process
337
* Returns -1 if resized window, 1 if handled, 0 if unhandled.
338
*===========================================================*/
340
handle_list_cmds (listdisp * ld, INT code)
342
INT rows = ld->rectList.bottom - ld->rectList.top + 1;
345
case 'j': /* next item */
347
if (ld->cur < ld->listlen - 1) {
349
if (ld->cur >= ld->top + rows)
350
ld->top = ld->cur + 1 - rows;
352
return TRUE; /* handled */
355
if (ld->top + rows < ld->listlen) {
358
if (ld->cur > ld->listlen - 1)
359
ld->cur = ld->listlen - 1;
361
return TRUE; /* handled */
364
if (ld->top + rows < ld->listlen) {
365
tmp = (ld->listlen)/10;
366
if (tmp < rows*2) tmp = rows*2;
367
if (tmp > ld->listlen - rows - ld->top)
368
tmp = ld->listlen - rows - ld->top;
371
if (ld->cur > ld->listlen - 1)
372
ld->cur = ld->listlen - 1;
374
return TRUE; /* handled */
375
case '$': /* jump to end of list */
377
ld->top = ld->listlen - rows;
380
ld->cur = ld->listlen-1;
381
return TRUE; /* handled */
382
case 'k': /* previous item */
386
if (ld->cur < ld->top)
389
return TRUE; /* handled */
393
if (tmp > ld->top) tmp = ld->top;
396
return TRUE; /* handled */
399
tmp = (ld->listlen)/10;
400
if (tmp < rows*2) tmp = rows*2;
401
if (tmp > ld->top) tmp = ld->top;
404
return TRUE; /* handled */
405
case '^': /* jump to top of list */
407
ld->top = ld->cur = 0;
408
return TRUE; /* handled */
409
case '(': /* scroll detail area up */
410
if (ld->details_scroll)
411
ld->details_scroll--;
412
return TRUE; /* handled */
413
case ')': /* scroll detail area down */
414
if (ld->details_scroll<2)
415
ld->details_scroll++;
416
return 1; /* handled */
418
return FALSE; /* unhandled */
420
/*=====================================================
421
* shw_popup_list -- Draw list & details of popup list
422
*===================================================*/
424
shw_popup_list (INDISEQ seq, listdisp * ld)
426
WINDOW *win = uiw_win(ld->uiwin);
427
ASSERT(ld->listlen == length_indiseq(seq));
429
INT row = ld->rectDetails.top-1;
430
clear_hseg(win, row, ld->rectDetails.left, ld->rectDetails.right);
431
mvccwaddstr(win, row, 2, _("--- CURRENT SELECTION ---"));
432
shw_recordlist_details(seq, ld);
433
row = ld->rectDetails.bottom+1;
434
mvccwaddstr(win, row, ld->rectDetails.left, _("--- LIST ---"));
436
shw_recordlist_list(seq, ld);
438
/*=====================================================
439
* shw_recordlist_details -- Draw record details for a list
440
* For either popup list or full-screen list (list browse)
441
*===================================================*/
443
shw_recordlist_details (INDISEQ seq, listdisp * ld)
445
WINDOW *win = uiw_win(ld->uiwin);
448
BOOLEAN reuse=FALSE; /* don't reuse display strings in list */
449
for (i=ld->rectDetails.top; i<=ld->rectDetails.bottom; ++i) {
450
clear_hseg(win, i, ld->rectDetails.left, ld->rectDetails.right-10);
452
element_indiseq(seq, ld->cur, &key, &name);
453
if (!show_record(ld->uiwin, key, ld->mode, &ld->rectDetails
454
, &ld->details_scroll, reuse)) {
455
/* if couldn't find record, just display record key */
456
display_string(ld->uiwin, &ld->rectDetails, key);
459
/*=============================================================
460
* handle_popup_list_resize -- Process resizes of popup list
461
* In popup list, details & list compete, & menu is fixed
462
* Returns TRUE if handled, FALSE if not
463
*===========================================================*/
465
handle_popup_list_resize (listdisp * ld, INT code)
469
case '[': /* shrink detail area */
471
delta = (ld->details > ld->details_minhgt) ? 1 : ld->details;
472
ld->details -= delta;
473
ld->rectDetails.bottom -= delta;
474
ld->rectList.top -= delta;
475
return -1; /* handled & needs resize */
477
return 1; /* handled (nothing) */
478
case ']': /* enlarge detail area */
479
if (ld->details < ld->details_maxhgt) {
480
delta = ld->details ? 1 : ld->details_beginhgt;
481
ld->details += delta;
482
ld->rectDetails.bottom += delta;
483
ld->rectList.top += delta;
484
return TRUE; /* handled */
486
return TRUE; /* handled (nothing) */
488
return FALSE; /* unhandled */
490
/*=====================================================
491
* shw_recordlist_list -- Draw actual list items
492
* For either popup list or full-screen list (list browse)
493
*===================================================*/
495
shw_recordlist_list (INDISEQ seq, listdisp * ld)
497
WINDOW *win = uiw_win(ld->uiwin);
498
INT width = (ld->rectList.right - ld->rectList.left + 1) - 4;
499
INT rows = ld->rectList.bottom - ld->rectList.top + 1;
503
BOOLEAN scrollable = (rows < ld->listlen);
504
/* for short lists, use leading numbers */
505
if (ld->listlen < 10) {
506
sprintf(buffer, "%ld: ", ld->listlen);
508
width -= i; /* for "1: " */
511
if (width > (INT)sizeof(buffer)-1)
512
width = sizeof(buffer)-1;
513
for (j=0; j<rows; j++) {
514
/* j is zero-based iterator */
515
/* i is actual offset into indiseq */
517
/* row is row on screen */
518
row = ld->rectList.top + j;
519
clear_hseg(win, row, ld->rectList.left, ld->rectList.right);
521
if (i == 0 && scrollable)
522
mvwaddch(win, row, ld->rectList.left, '^');
523
if (i == ld->listlen-1 && scrollable)
524
mvwaddch(win, row, ld->rectList.left, '$');
525
if (i == ld->cur) mvwaddch(win, row, ld->rectList.left+3, '>');
526
if (ld->listlen < 10) {
528
sprintf(numstr, "%d:", i+1);
529
mvccwaddstr(win, row, ld->rectList.left+4, numstr);
531
print_indiseq_element(seq, i, buffer, width, &disp_shrt_rfmt);
532
mvccwaddstr(win, row, ld->rectList.left+offset, buffer);
536
/*==================================
537
* print_list_title -- Print title line of an array list
538
* Adds suffix such as (5/11)
539
* Truncates title if necessary (leaving room for suffix)
540
* buffer: [OUT] output string
541
* len: [IN] size of buffer
542
* ld: [IN] list display structure
543
* ttl: [IN] title to print (localized)
544
*================================*/
546
print_list_title (char * buffer, INT len, const listdisp * ld, STRING ttl)
550
if (len > uiw_cols(ld->uiwin)-2)
551
len = uiw_cols(ld->uiwin)-2;
552
sprintf(suffix, " (%ld/%ld)", ld->cur+1, ld->listlen);
553
len -= strlen(suffix)+1; /* reserve room for suffix */
555
if ((INT)strlen(ttl)>len-1) {
557
llstrcatn(&ptr, ttl, &len);
559
llstrcatn(&ptr, "...", &len);
561
llstrcatn(&ptr, ttl, &len);
563
len += strlen(suffix)+1; /* we reserved this room above */
564
llstrcatn(&ptr, suffix, &len);
566
/*================================================================
567
* shw_array_of_strings -- Show string list in list interact window
568
* strings: [IN] array (of choices) to be listed
569
* ld: [IN] structure of info for variable-sized list
570
* detfnc: [IN] callback for detail area
571
* param: [IN] opaque data for callback
572
*==============================================================*/
574
shw_array_of_strings (STRING *strings, listdisp * ld, DETAILFNC detfnc
578
STRING empstr120 = " ";
579
WINDOW *win = uiw_win(ld->uiwin);
580
INT i, j, row, lines;
581
INT rows = ld->rectList.bottom - ld->rectList.top + 1;
584
INT width = uiw_cols(ld->uiwin);
585
if (width > (INT)sizeof(buffer)-1)
586
width = sizeof(buffer)-1;
587
/* clear current lines */
588
lines = rows + (ld->details ? ld->details+2 : 0);
589
for (i = 0; i<lines; ++i) {
591
llstrncpy(buffer, empstr120, width-1, uu8);
592
mvccwaddstr(win, row, 1, buffer);
597
mvccwaddstr(win, row++, 2, _("--- LIST ---"));
599
for (j=0; j<rows;++j) {
604
/* for short lists, we show leading numbers */
605
if (ld->listlen<10) {
607
llstrncpyf(numstr, sizeof(numstr), uu8, "%d: ", i+1);
608
if (i == ld->cur) mvwaddch(win, row, 3, '>');
609
mvccwaddstr(win, row, 4, numstr);
610
nlen = strlen(numstr);
612
if (i == ld->cur) mvwaddch(win, row, 3, '>');
615
llstrncpy(buffer, strings[i], temp, uu8);
616
if ((INT)strlen(buffer) > temp-2) {
619
strcpy(&buffer[temp-3], "...");
621
mvccwaddstr(win, row, 4+nlen, buffer);
625
STRING ptr = strings[ld->cur];
628
mvccwaddstr(win, row++, 2, _("-- CURRENT SELECTION --"));
629
for (i=0; i<ld->details; ++i) {
632
llstrncpy(buffer, ptr, width-5, uu8);
633
mvccwaddstr(win, row++, 4, buffer);
634
ptr += strlen(buffer);
636
count = ld->details-1;
637
if (count && detfnc) {
638
/* caller gave us a detail callback, so we set up the
639
data needed & call it */
640
STRING * linestr = (STRING *)stdalloc(count * sizeof(STRING));
641
struct tag_array_details dets;
642
for (j=0; j<count; ++j) {
643
linestr[j] = stdalloc(width);
646
memset(&dets, 0, sizeof(dets));
649
dets.lines = linestr;
652
(*detfnc)(&dets, param);
653
for (j=0 ; j<count; ++j) {
654
mvccwaddstr(win, row++, 4, linestr[j]);
656
for (j=0; j<count; ++j)
662
/*=============================================================
663
* activate_popup_list_uiwin --
664
* Choose list uiwin & activate
665
* @listdisp: [I/O] caller must have filled this in
666
* This routine sets the uiwin, height, rows members
667
*===========================================================*/
669
activate_popup_list_uiwin (listdisp * ld)
671
INT asklen, hgt, rows, waste;
673
How many rows do we want ?
674
One for each item in list
675
+5: top line, title, bottom row, menu, bottom line
676
if details, need also line above & below details
678
asklen = ld->listlen;
680
asklen += ld->details+2;
685
create_newwin2(&ld->uiwin, "list", hgt, LISTWIN_WIDTH);
686
uiw_dynamic(ld->uiwin) = TRUE; /* delete when finished */
687
/* list is below details to nearly bottom */
688
ld->rectList.left = 1;
689
ld->rectList.right = LISTWIN_WIDTH-2;
690
ld->rectList.top = 2;
691
if (ld->details) /* leave room for --DETAILS-- & --LIST-- lines */
692
ld->rectList.top += 2+ld->details;
693
ld->rectList.bottom = hgt-4;
694
/* details is from top down as far as #details */
695
ld->rectDetails.top = 2;
696
if (ld->details) /* leave room for --DETAILS-- line */
697
++ld->rectDetails.top;
698
ld->rectDetails.bottom = ld->rectDetails.top + ld->details-1;
699
ld->rectDetails.left = 1;
700
ld->rectDetails.right = LISTWIN_WIDTH-2;
701
/* menu is at bottom, single-line */
702
ld->rectMenu.top = hgt-2;
703
ld->rectMenu.bottom = hgt-2;
704
ld->rectMenu.left = 1;
705
ld->rectMenu.right = LISTWIN_WIDTH-2;
706
ld->details_beginhgt = 4;
707
ld->details_maxhgt = POPUP_LINES-10;
708
ld->details_minhgt = 3;
710
activate_uiwin(ld->uiwin);
711
/* ensure cur is on-screen */
712
/* (growing detail area can push current off-screen) */
713
rows = ld->rectList.bottom + 1 - ld->rectList.top;
714
if (ld->cur < ld->top)
716
else if (ld->cur >= ld->top + rows)
717
ld->top = ld->cur + 1 - rows;
718
/* don't waste space by scrolling end up */
719
waste = ld->top + rows - ld->listlen;
720
if (waste>0 && ld->top) {
726
/*=====================================================
727
* display_string -- Draw string in rectangle
728
* handle embedded carriage returns
729
*===================================================*/
731
display_string (UIWINDOW uiwin, LLRECT rect, STRING text)
733
INT max = rect->right - rect->left + 2;
734
STRING str = stdalloc(max), p2;
735
WINDOW *win = uiw_win(uiwin);
737
wipe_window_rect(uiwin, rect);
738
for (row = rect->top; row <= rect->bottom; ++row) {
741
while (p2<str+max && text[0] && !islinebreak(text[0]))
744
mvccwaddstr(win, row, rect->left, str);
752
/*==========================================
753
* show_big_list - Show name list in list screen
754
*========================================*/
756
show_big_list (INDISEQ seq,
762
TODO: To be resizable like popup list, need a listdisp structure,
763
and need to repaint that RHS menu, as its height will vary
764
just to be scrollable details doesn't require repainting the RHS menu
765
But in any case the real problem is that
766
show_big_list (screen.c) is called by list_browse (screen.c)
767
which is called by browse_list (lbrowse.c!), and it handles menus
768
and listdisp is local to screen.c right now, so browse_list can't have one
769
A solution would be to pass in what is known from browse_list, and then
770
manufacture a listdisp here
773
static STRING empstr49 = (STRING) " ";
774
UIWINDOW uiwin = main_win;
775
WINDOW *win = uiw_win(uiwin);
776
INT i, j, row, len = length_indiseq(seq);
782
BOOLEAN scrollable = (viewlines < len);
784
calc_indiseq_names(seq); /* we certainly need the names */
786
for (i = LIST_LINES+2; i < LIST_LINES+2+viewlines; i++)
787
mvccwaddstr(win, i, 1, empstr49);
789
for (i = top, j = 0; j < viewlines && i < len; i++, j++) {
790
element_indiseq(seq, i, &key, &name);
791
recnode = key_to_type(key, 0);
792
if (i == 0 && scrollable) mvwaddch(win, row, 1, '^');
793
if (i == len-1 && scrollable) mvwaddch(win, row, 1, '$');
794
if (i == mark) mvwaddch(win, row, 2, 'x');
799
struct tag_llrect rectList;
801
rectList.bottom = drow + LIST_LINES-1;
803
rectList.right = get_main_screen_width()-2;
804
mvwaddch(win, row, 3, '>');
805
show_record(main_win, key, mode, &rectList, &scroll, reuse);
809
SURCAPTYPE surcaptype = DOSURCAP;
810
if (!getlloptint("UppercaseSurnames", 1))
811
surcaptype = NOSURCAP;
812
name = manip_name(name, surcaptype, REGORDER, 40);
813
llstrapps(scratch, sizeof(scratch), uu8, name);
814
llstrapps(scratch, sizeof(scratch), uu8, " ");
816
if(getlloptint("DisplayKeyTags", 0) > 0) {
817
llstrappf(scratch, sizeof(scratch), uu8, "(i%s)", key_of_record(recnode));
819
llstrappf(scratch, sizeof(scratch), uu8, "(%s)", key_of_record(recnode));
821
mvccwaddstr(win, row, 4, scratch);
825
/*==============================================
826
* paint_list_screen -- Paint list browse screen
827
*============================================*/
829
paint_list_screen (void)
831
UIWINDOW uiwin = main_win;
832
WINDOW *win = uiw_win(uiwin);
836
show_horz_line(uiwin, LIST_LINES+1, 0, ll_cols);
837
show_horz_line(uiwin, ll_lines-3, 0, ll_cols);
838
show_vert_line(uiwin, LIST_LINES+1, 52, 15);
839
mvwaddch(win, LIST_LINES+1, 52, get_gr_ttee());
840
mvccwaddstr(win, LIST_LINES+2, 54, _("Choose an operation:"));
841
row = LIST_LINES+3; col = 55;
842
mvccwaddstr(win, row++, col, _("j Move down list"));
843
mvccwaddstr(win, row++, col, _("k Move up list"));
844
mvccwaddstr(win, row++, col, _("e Edit this person"));
845
mvccwaddstr(win, row++, col, _("i Browse this person"));
846
mvccwaddstr(win, row++, col, _("m Mark this person"));
847
mvccwaddstr(win, row++, col, _("r Remove from list"));
848
mvccwaddstr(win, row++, col, _("t Enter tandem mode"));
849
mvccwaddstr(win, row++, col, _("n Name this list"));
850
mvccwaddstr(win, row++, col, _("b Browse new persons"));
851
mvccwaddstr(win, row++, col, _("a Add to this list"));
852
mvccwaddstr(win, row++, col, _("x Swap mark/current"));
853
mvccwaddstr(win, row++, col, _(qSmn_quit));
855
/*==============================================
856
* listui_placecursor_main -- Get location for cursor in the large list browse window
857
*============================================*/
859
listui_placecursor_main (INT * prow, INT * pcol)
861
*prow = LIST_LINES+2;