~ubuntu-branches/ubuntu/trusty/lifelines/trusty

« back to all changes in this revision

Viewing changes to src/liflines/listui.c

  • Committer: Bazaar Package Importer
  • Author(s): Felipe Augusto van de Wiel (faw)
  • Date: 2007-08-14 00:02:04 UTC
  • mfrom: (1.1.4 upstream) (3.1.4 gutsy)
  • Revision ID: james.westby@ubuntu.com-20070814000204-mpv5faygl0dgq3qi
Tags: 3.0.61-1
* New upstream release. (Closes: #387856).
* Fixing documentation build problems also fixes FTBFS if built twice in a
  row. (Closes: #424543).
* Adding lynx as a build dependency. This is necessary to generate txt files
  from html, discovered while fixing #424543.
* Upstream fix: charset for gedcom file in unicode. (Closes: #396206).
* Upstream fim: updating documentation about desc-tex2. (Closes: #405501).
* Bumping Standards-Version to 3.7.2 without package changes.
* Dropping local debian patches added upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Copyright (c) 2006 Perry Rapp
 
3
 
 
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:
 
11
 
 
12
   The above copyright notice and this permission notice shall be
 
13
   included in all copies or substantial portions of the Software.
 
14
 
 
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
 
22
   SOFTWARE.
 
23
*/
 
24
/*=============================================================
 
25
 * listui.c -- display code for popup list and list browse screen
 
26
 * Copyright(c) 2006
 
27
 *===========================================================*/
 
28
 
 
29
#include <time.h>
 
30
#include "llstdlib.h"
 
31
#ifdef HAVE_LOCALE_H
 
32
#include <locale.h>
 
33
#endif
 
34
#include "table.h"
 
35
#include "liflines.h"
 
36
#include "arch.h"
 
37
#include "lloptions.h"
 
38
#include "interp.h"
 
39
#include "llinesi.h"
 
40
#include "menuitem.h"
 
41
#include "screen.h"
 
42
#include "cscurses.h"
 
43
#include "zstr.h"
 
44
#include "cache.h"
 
45
#ifdef WIN32_ICONV_SHIM
 
46
#include "iconvshim.h"
 
47
#endif
 
48
#include "codesets.h"
 
49
#include "charprops.h"
 
50
#include "listui.h"
 
51
 
 
52
 
 
53
 
 
54
static INT LISTWIN_WIDTH=0;
 
55
 
 
56
 /*********************************************
 
57
 * external/imported variables
 
58
 *********************************************/
 
59
 
 
60
extern STRING qSmn_quit;
 
61
 
 
62
/*********************************************
 
63
 * local types
 
64
 *********************************************/
 
65
 
 
66
/*
 
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
 
71
*/
 
72
typedef struct listdisp_s
 
73
{
 
74
        UIWINDOW uiwin;
 
75
        struct tag_llrect rectList;
 
76
        struct tag_llrect rectDetails;
 
77
        struct tag_llrect rectMenu;
 
78
        INT details; /* #rows of detail info */
 
79
        INT details_minhgt;
 
80
        INT details_beginhgt; /* increase from 0 goes to this */
 
81
        INT details_maxhgt;
 
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 */
 
87
} listdisp;
 
88
 
 
89
/*********************************************
 
90
 * local function prototypes
 
91
 *********************************************/
 
92
 
 
93
/* alphabetical */
 
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);
 
104
 
 
105
/*********************************************
 
106
 * local variables
 
107
 *********************************************/
 
108
 
 
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 */
 
112
/* working values */
 
113
static int LIST_LINES=0;
 
114
static int POPUP_LINES=0;
 
115
 
 
116
/*==============================================
 
117
 * listui_init_windows -- Initialize anything dependent on screen size
 
118
 *============================================*/
 
119
void
 
120
listui_init_windows (INT extralines)
 
121
{
 
122
        /* initialize list window heights to default */
 
123
        LIST_LINES = LIST_LINES_DEF;
 
124
        POPUP_LINES = POPUP_LINES_DEF;
 
125
        /* increase for larger screens */
 
126
        if(extralines > 0) {
 
127
                LIST_LINES = LIST_LINES_DEF + extralines;
 
128
                POPUP_LINES = POPUP_LINES_DEF + extralines;
 
129
        }
 
130
 
 
131
        LISTWIN_WIDTH = ll_cols-7;
 
132
}
 
133
/*==============================================
 
134
 * array_interact -- Interact with user over list
 
135
 *  ttl:        [IN]  title
 
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
 *============================================*/
 
143
INT
 
144
array_interact (STRING ttl, INT len, STRING *strings
 
145
        , BOOLEAN selectable, DETAILFNC detfnc, void * param)
 
146
{
 
147
        WINDOW *win=0;
 
148
        INT row, done;
 
149
        char fulltitle[128];
 
150
        STRING responses = len<10 ? "jkiq123456789[]()$^" : "jkiq[]()$^";
 
151
        STRING promptline=0;
 
152
        listdisp ld; /* structure used in resizable list displays */
 
153
 
 
154
        if (selectable)
 
155
                promptline = _("Commands:   j Move down     k Move up    i Select     q Quit");
 
156
        else
 
157
                promptline = _("Commands:   j Move down     k Move up    q Quit");
 
158
 
 
159
        memset(&ld, 0, sizeof(ld));
 
160
        ld.listlen = len;
 
161
        ld.mode = 'n'; /* irrelevant for array list */
 
162
 
 
163
resize_win: /* we come back here if we resize the window */
 
164
        activate_popup_list_uiwin(&ld);
 
165
        win = uiw_win(ld.uiwin);
 
166
        uierase(ld.uiwin);
 
167
        draw_win_box(win);
 
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);
 
171
        done = FALSE;
 
172
        while (!done) {
 
173
                INT code=0, ret=0;
 
174
                print_list_title(fulltitle, sizeof(fulltitle), &ld, _(ttl));
 
175
                mvccwaddstr(win, 1, 1, fulltitle);
 
176
                shw_array_of_strings(strings, &ld, detfnc, param);
 
177
                wrefresh(win);
 
178
                code = interact_popup(ld.uiwin, responses);
 
179
                if (handle_list_cmds(&ld, code))
 
180
                        continue;
 
181
                if (handle_popup_list_resize(&ld, code)) {
 
182
                        deactivate_uiwin_and_touch_all();
 
183
                        /* we're going to repick window & activate */
 
184
                        goto resize_win;
 
185
                }
 
186
                if (ret == 0) { /* not handled yet */
 
187
                        switch(code) {
 
188
                        case 'i': /* select current item */
 
189
                        case CMD_KY_ENTER:
 
190
                                if (selectable) {
 
191
                                        done=TRUE;
 
192
                                }
 
193
                                break;
 
194
                        case '1':
 
195
                        case '2':
 
196
                        case '3':
 
197
                        case '4':
 
198
                        case '5':
 
199
                        case '6':
 
200
                        case '7':
 
201
                        case '8':
 
202
                        case '9':
 
203
                                if (len < 10 && selectable && code - '1' < len) {
 
204
                                        done=TRUE;
 
205
                                        ld.cur = code - '1';
 
206
                                }
 
207
                                break;
 
208
                        case 'q':
 
209
                                done=TRUE;
 
210
                                ld.cur = -1; /* ld.cur == -1 means cancelled */
 
211
                        }
 
212
                }
 
213
        }
 
214
        deactivate_uiwin_and_touch_all();
 
215
        return ld.cur;
 
216
}
 
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
 
226
 * Localizes ttl
 
227
 *===========================================================*/
 
228
INT
 
229
choose_one_or_list_from_indiseq (STRING ttl, INDISEQ seq, BOOLEAN multi)
 
230
{
 
231
        WINDOW *win=0;
 
232
        INT row, done;
 
233
        char fulltitle[128];
 
234
        INT elemwidth;
 
235
        listdisp ld; /* structure used in resizable list displays */
 
236
        STRING menu, choices;
 
237
        BOOLEAN first=TRUE;
 
238
 
 
239
        ASSERT(seq);
 
240
 
 
241
        calc_indiseq_names(seq); /* we certainly need the names */
 
242
        
 
243
        memset(&ld, 0, sizeof(ld));
 
244
        ld.listlen = length_indiseq(seq);
 
245
        ld.mode = 'n';
 
246
 
 
247
        /* TO DO: connect this to menuitem system */
 
248
        if (multi) {
 
249
                menu = _("Commands:  j Move down   k Move up  d Delete   i Select   q Quit");
 
250
                choices = "jkriq123456789()[]$^udUD";
 
251
        } else {
 
252
                menu = _("Commands:   j Move down     k Move up    i Select     q Quit");
 
253
                choices = "jkiq123456789()[]$^udUD";
 
254
        }
 
255
 
 
256
resize_win: /* we come back here if we resize the window */
 
257
        activate_popup_list_uiwin(&ld);
 
258
        win = uiw_win(ld.uiwin);
 
259
        if (first) {
 
260
                elemwidth = ld.rectDetails.right - ld.rectDetails.left + 1;
 
261
                if (length_indiseq(seq)<50)
 
262
                        preprint_indiseq(seq, elemwidth, &disp_shrt_rfmt);
 
263
                first=FALSE;
 
264
        }
 
265
        uierase(ld.uiwin);
 
266
        draw_win_box(win);
 
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);
 
270
        done = FALSE;
 
271
        while (!done) {
 
272
                INT code=0, ret=0;
 
273
                print_list_title(fulltitle, sizeof(fulltitle), &ld, ttl);
 
274
                mvccwaddstr(win, 1, 1, fulltitle);
 
275
                shw_popup_list(seq, &ld);
 
276
                wmove(win, row, 11);
 
277
                wrefresh(win);
 
278
                code = interact_popup(ld.uiwin, choices);
 
279
                if (handle_list_cmds(&ld, code))
 
280
                        continue;
 
281
                if (handle_popup_list_resize(&ld, code)) {
 
282
                        deactivate_uiwin_and_touch_all(); /* kills ld.uiwin */
 
283
                        ld.uiwin = NULL;
 
284
                        /* we're going to repick window & activate */
 
285
                        goto resize_win;
 
286
                }
 
287
                if (ret == 0) { /* not handled yet */
 
288
                        switch (code) {
 
289
                        case 'r':
 
290
                                if (!multi)
 
291
                                        break;
 
292
                                delete_indiseq(seq, NULL, NULL, ld.cur);
 
293
                                if (!(ld.listlen = length_indiseq(seq))) {
 
294
                                        done=TRUE;
 
295
                                        ld.cur = -1;
 
296
                                }
 
297
                                if (ld.cur == ld.listlen) ld.cur--;
 
298
                                if (ld.cur < ld.top) ld.top = ld.cur;
 
299
                                break;
 
300
                        case 'i':
 
301
                        case CMD_KY_ENTER:
 
302
                                done=TRUE;
 
303
                                /* ld.cur points to currently selected */
 
304
                                break;
 
305
                        case '1':
 
306
                        case '2':
 
307
                        case '3':
 
308
                        case '4':
 
309
                        case '5':
 
310
                        case '6':
 
311
                        case '7':
 
312
                        case '8':
 
313
                        case '9':
 
314
                                if (ld.listlen < 10 && code - '1' < ld.listlen) {
 
315
                                        done=TRUE;
 
316
                                        ld.cur = code - '1';
 
317
                                }
 
318
                                break;
 
319
                        case 'q':
 
320
                                done=TRUE;
 
321
                                ld.cur = -1; /* ld.cur == -1 means cancelled */
 
322
                                break;
 
323
                        }
 
324
                }
 
325
        }
 
326
        deactivate_uiwin_and_touch_all(); /* kills ld.uiwin */
 
327
        ld.uiwin = NULL;
 
328
        
 
329
        return ld.cur;
 
330
}
 
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
 *===========================================================*/
 
339
static INT
 
340
handle_list_cmds (listdisp * ld, INT code)
 
341
{
 
342
        INT rows = ld->rectList.bottom - ld->rectList.top + 1;
 
343
        INT tmp;
 
344
        switch(code) {
 
345
        case 'j': /* next item */
 
346
        case CMD_KY_DN:
 
347
                if (ld->cur < ld->listlen - 1) {
 
348
                        ld->cur++;
 
349
                        if (ld->cur >= ld->top + rows)
 
350
                                ld->top = ld->cur + 1 - rows;
 
351
                }
 
352
                return TRUE; /* handled */
 
353
        case 'd':
 
354
        case CMD_KY_PGDN:
 
355
                if (ld->top + rows < ld->listlen) {
 
356
                        ld->top += rows;
 
357
                        ld->cur += rows;
 
358
                        if (ld->cur > ld->listlen - 1)
 
359
                                ld->cur = ld->listlen - 1;
 
360
                }
 
361
                return TRUE; /* handled */
 
362
        case 'D':
 
363
        case CMD_KY_SHPGDN:
 
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;
 
369
                        ld->top += tmp;
 
370
                        ld->cur += tmp;
 
371
                        if (ld->cur > ld->listlen - 1)
 
372
                                ld->cur = ld->listlen - 1;
 
373
                }
 
374
                return TRUE; /* handled */
 
375
        case '$': /* jump to end of list */
 
376
        case CMD_KY_END:
 
377
                ld->top = ld->listlen - rows;
 
378
                if (ld->top < 0)
 
379
                        ld->top = 0;
 
380
                ld->cur = ld->listlen-1;
 
381
                return TRUE; /* handled */
 
382
        case 'k': /* previous item */
 
383
        case CMD_KY_UP:
 
384
                if (ld->cur > 0) {
 
385
                        ld->cur--;
 
386
                        if (ld->cur < ld->top)
 
387
                                ld->top = ld->cur;
 
388
                }
 
389
                return TRUE; /* handled */
 
390
        case 'u':
 
391
        case CMD_KY_PGUP:
 
392
                tmp = rows;
 
393
                if (tmp > ld->top) tmp = ld->top;
 
394
                ld->top -= tmp;
 
395
                ld->cur -= tmp;
 
396
                return TRUE; /* handled */
 
397
        case 'U':
 
398
        case CMD_KY_SHPGUP:
 
399
                tmp = (ld->listlen)/10;
 
400
                if (tmp < rows*2) tmp = rows*2;
 
401
                if (tmp > ld->top) tmp = ld->top;
 
402
                ld->cur -= tmp;
 
403
                ld->top -= tmp;
 
404
                return TRUE; /* handled */
 
405
        case '^': /* jump to top of list */
 
406
        case CMD_KY_HOME:
 
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 */
 
417
        }
 
418
        return FALSE; /* unhandled */
 
419
}
 
420
/*=====================================================
 
421
 * shw_popup_list -- Draw list & details of popup list
 
422
 *===================================================*/
 
423
static void
 
424
shw_popup_list (INDISEQ seq, listdisp * ld)
 
425
{
 
426
        WINDOW *win = uiw_win(ld->uiwin);
 
427
        ASSERT(ld->listlen == length_indiseq(seq));
 
428
        if (ld->details) {
 
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 ---"));
 
435
        }
 
436
        shw_recordlist_list(seq, ld);
 
437
}
 
438
/*=====================================================
 
439
 * shw_recordlist_details -- Draw record details for a list
 
440
 * For either popup list or full-screen list (list browse)
 
441
 *===================================================*/
 
442
static void
 
443
shw_recordlist_details (INDISEQ seq, listdisp * ld)
 
444
{
 
445
        WINDOW *win = uiw_win(ld->uiwin);
 
446
        INT i;
 
447
        STRING key, name;
 
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);
 
451
        }
 
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);
 
457
        }
 
458
}
 
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
 *===========================================================*/
 
464
static BOOLEAN
 
465
handle_popup_list_resize (listdisp * ld, INT code)
 
466
{
 
467
        INT delta;
 
468
        switch(code) {
 
469
        case '[': /* shrink detail area */
 
470
                if (ld->details) {
 
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 */
 
476
                }
 
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 */
 
485
                }
 
486
                return TRUE; /* handled (nothing) */
 
487
        }
 
488
        return FALSE; /* unhandled */
 
489
}
 
490
/*=====================================================
 
491
 * shw_recordlist_list -- Draw actual list items
 
492
 * For either popup list or full-screen list (list browse)
 
493
 *===================================================*/
 
494
static void
 
495
shw_recordlist_list (INDISEQ seq, listdisp * ld)
 
496
{
 
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;
 
500
        INT i, j, row;
 
501
        INT offset=4;
 
502
        char buffer[160];
 
503
        BOOLEAN scrollable = (rows < ld->listlen);
 
504
        /* for short lists, use leading numbers */
 
505
        if (ld->listlen < 10) {
 
506
                sprintf(buffer, "%ld: ", ld->listlen);
 
507
                i = strlen(buffer);
 
508
                width -= i; /* for "1: " */
 
509
                offset += i;
 
510
        }
 
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 */
 
516
                i = ld->top + j;
 
517
                /* row is row on screen */
 
518
                row = ld->rectList.top + j;
 
519
                clear_hseg(win, row, ld->rectList.left, ld->rectList.right);
 
520
                if (i<ld->listlen) {
 
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) {
 
527
                                char numstr[12];
 
528
                                sprintf(numstr, "%d:", i+1);
 
529
                                mvccwaddstr(win, row, ld->rectList.left+4, numstr);
 
530
                        }
 
531
                        print_indiseq_element(seq, i, buffer, width, &disp_shrt_rfmt);
 
532
                        mvccwaddstr(win, row, ld->rectList.left+offset, buffer);
 
533
                }
 
534
        }
 
535
}
 
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
 *================================*/
 
545
static void
 
546
print_list_title (char * buffer, INT len, const listdisp * ld, STRING ttl)
 
547
{
 
548
        STRING ptr = buffer;
 
549
        char suffix[30];
 
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 */
 
554
        ptr[0] = 0;
 
555
        if ((INT)strlen(ttl)>len-1) {
 
556
                len -= 4;
 
557
                llstrcatn(&ptr, ttl, &len);
 
558
                len += 4;
 
559
                llstrcatn(&ptr, "...", &len);
 
560
        } else {
 
561
                llstrcatn(&ptr, ttl, &len);
 
562
        }
 
563
        len += strlen(suffix)+1; /* we reserved this room above */
 
564
        llstrcatn(&ptr, suffix, &len);
 
565
}
 
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
 *==============================================================*/
 
573
static void
 
574
shw_array_of_strings (STRING *strings, listdisp * ld, DETAILFNC detfnc
 
575
        , void * param)
 
576
{
 
577
        /* 120 spaces */
 
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;
 
582
        INT overflag=FALSE;
 
583
        char buffer[120];
 
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) {
 
590
                row = i+2;
 
591
                llstrncpy(buffer, empstr120, width-1, uu8);
 
592
                mvccwaddstr(win, row, 1, buffer);
 
593
        }
 
594
        row = 2;
 
595
        if (ld->details) {
 
596
                row = 3+ld->details;
 
597
                mvccwaddstr(win, row++, 2, _("--- LIST ---"));
 
598
        }
 
599
        for (j=0; j<rows;++j) {
 
600
                INT nlen=0,temp;
 
601
                i = ld->top + j;
 
602
                if (i>=ld->listlen)
 
603
                        break;
 
604
                /* for short lists, we show leading numbers */
 
605
                if (ld->listlen<10) {
 
606
                        char numstr[12]="";
 
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);
 
611
                } else {
 
612
                        if (i == ld->cur) mvwaddch(win, row, 3, '>');
 
613
                }
 
614
                temp = width-6-nlen;
 
615
                llstrncpy(buffer, strings[i], temp, uu8);
 
616
                if ((INT)strlen(buffer) > temp-2) {
 
617
                        if (i==ld->cur)
 
618
                                overflag=TRUE;
 
619
                        strcpy(&buffer[temp-3], "...");
 
620
                }
 
621
                mvccwaddstr(win, row, 4+nlen, buffer);
 
622
                row++;
 
623
        }
 
624
        if (ld->details) {
 
625
                STRING ptr = strings[ld->cur];
 
626
                INT count;
 
627
                row = 2;
 
628
                mvccwaddstr(win, row++, 2, _("-- CURRENT SELECTION --"));
 
629
                for (i=0; i<ld->details; ++i) {
 
630
                        /* TODO: scroll */
 
631
                        if (!ptr[0]) break;
 
632
                        llstrncpy(buffer, ptr, width-5, uu8);
 
633
                        mvccwaddstr(win, row++, 4, buffer);
 
634
                        ptr += strlen(buffer);
 
635
                }
 
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);
 
644
                                linestr[j][0] = 0;
 
645
                        }
 
646
                        memset(&dets, 0, sizeof(dets));
 
647
                        dets.list = strings;
 
648
                        dets.cur = ld->cur;
 
649
                        dets.lines = linestr;
 
650
                        dets.count = count;
 
651
                        dets.maxlen = width;
 
652
                        (*detfnc)(&dets, param);
 
653
                        for (j=0 ; j<count; ++j) {
 
654
                                mvccwaddstr(win, row++, 4, linestr[j]);
 
655
                        }
 
656
                        for (j=0; j<count; ++j)
 
657
                                stdfree(linestr[j]);
 
658
                        stdfree(linestr);
 
659
                }
 
660
        }
 
661
}
 
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
 *===========================================================*/
 
668
static void
 
669
activate_popup_list_uiwin (listdisp * ld)
 
670
{
 
671
        INT asklen, hgt, rows, waste;
 
672
        /* 
 
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
 
677
        */
 
678
        asklen = ld->listlen;
 
679
        if (ld->details)
 
680
                asklen += ld->details+2;
 
681
        hgt = asklen+5;
 
682
 
 
683
        if (hgt>POPUP_LINES)
 
684
                hgt = POPUP_LINES;
 
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;
 
709
 
 
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)
 
715
                ld->top = ld->cur;
 
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) {
 
721
                ld->top -= waste;
 
722
                if (ld->top < 0)
 
723
                        ld->top = 0;
 
724
        }
 
725
}
 
726
/*=====================================================
 
727
 * display_string -- Draw string in rectangle
 
728
 *  handle embedded carriage returns
 
729
 *===================================================*/
 
730
static void
 
731
display_string (UIWINDOW uiwin, LLRECT rect, STRING text)
 
732
{
 
733
        INT max = rect->right - rect->left + 2;
 
734
        STRING str = stdalloc(max), p2;
 
735
        WINDOW *win = uiw_win(uiwin);
 
736
        INT row = rect->top;
 
737
        wipe_window_rect(uiwin, rect);
 
738
        for (row = rect->top; row <= rect->bottom; ++row) {
 
739
                str[0] = 0;
 
740
                p2 = str;
 
741
                while (p2<str+max && text[0] && !islinebreak(text[0]))
 
742
                        *p2++ = *text++;
 
743
                *p2 = 0;
 
744
                mvccwaddstr(win, row, rect->left, str);
 
745
                if (!text[0])
 
746
                        break;
 
747
                else
 
748
                        ++text;
 
749
        }
 
750
        stdfree(str);
 
751
}
 
752
/*==========================================
 
753
 * show_big_list - Show name list in list screen
 
754
 *========================================*/
 
755
void
 
756
show_big_list (INDISEQ seq,
 
757
           INT top,
 
758
           INT cur,
 
759
           INT mark)
 
760
{
 
761
/*
 
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
 
771
- Perry, 2002/01/01
 
772
*/
 
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);
 
777
        STRING key, name;
 
778
        NODE recnode=0;
 
779
        char scratch[200];
 
780
        INT mode = 'n';
 
781
        INT viewlines = 13;
 
782
        BOOLEAN scrollable = (viewlines < len);
 
783
 
 
784
        calc_indiseq_names(seq); /* we certainly need the names */
 
785
        
 
786
        for (i = LIST_LINES+2; i < LIST_LINES+2+viewlines; i++)
 
787
                mvccwaddstr(win, i, 1, empstr49);
 
788
        row = LIST_LINES+2;
 
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');
 
795
                if (i == cur) {
 
796
                        INT drow=1;
 
797
                        INT scroll=0;
 
798
                        BOOLEAN reuse=FALSE;
 
799
                        struct tag_llrect rectList;
 
800
                        rectList.top = drow;
 
801
                        rectList.bottom = drow + LIST_LINES-1;
 
802
                        rectList.left = 1;
 
803
                        rectList.right = get_main_screen_width()-2;
 
804
                        mvwaddch(win, row, 3, '>');
 
805
                        show_record(main_win, key, mode, &rectList, &scroll, reuse);
 
806
                }
 
807
                scratch[0] =0;
 
808
                if (name) {
 
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, " ");
 
815
                }
 
816
                if(getlloptint("DisplayKeyTags", 0) > 0) {
 
817
                        llstrappf(scratch, sizeof(scratch), uu8, "(i%s)", key_of_record(recnode));
 
818
                } else {
 
819
                        llstrappf(scratch, sizeof(scratch), uu8, "(%s)", key_of_record(recnode));
 
820
                }
 
821
                mvccwaddstr(win, row, 4, scratch);
 
822
                row++;
 
823
        }
 
824
}
 
825
/*==============================================
 
826
 * paint_list_screen -- Paint list browse screen
 
827
 *============================================*/
 
828
void
 
829
paint_list_screen (void)
 
830
{
 
831
        UIWINDOW uiwin = main_win;
 
832
        WINDOW *win = uiw_win(uiwin);
 
833
        INT row, col;
 
834
        uierase(uiwin);
 
835
        draw_win_box(win);
 
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));
 
854
}
 
855
/*==============================================
 
856
 * listui_placecursor_main -- Get location for cursor in the large list browse window
 
857
 *============================================*/
 
858
void
 
859
listui_placecursor_main (INT * prow, INT * pcol)
 
860
{
 
861
        *prow = LIST_LINES+2;
 
862
        *pcol = 75;
 
863
}