1 /*
2 Copyright (c) 1991-1999 Thomas T. Wetmore IV
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 * screen.c -- Curses user interface to LifeLines
26 * Copyright(c) 1992-96 by T.T. Wetmore IV; all rights reserved
27 *===========================================================*/
28
29 #include "llstdlib.h"
30 #ifdef HAVE_LOCALE_H
31 #include <locale.h>
32 #endif
33 #include "table.h"
34 #include "liflines.h"
35 #include "arch.h"
36 #include "lloptions.h"
37 #include "interp.h"
38 #include "llinesi.h"
39 #include "menuitem.h"
40 #include "screen.h"
41 #include "screeni.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 #define LINESREQ 24
53 #define COLSREQ 80
54 /*
55 OVERHEAD_MENU:
56 1 line across top of screen
57 1 line above menu
58 1 line below menu
59 1 line of prompt message
60 1 line at very bottom of screen
61 This is how many lines can't be used by person (or whatever)
62 */
63 #define OVERHEAD_MENU 5
64 INT MAINWIN_WIDTH=0;
65
66 /* center windows on real physical screen (LINES x COLS) */
67 #define NEWWIN(r,c) newwin(r,c,(LINES - (r))/2,(COLS - (c))/2)
68 #define SUBWIN(w,r,c) subwin(w,r,c,(LINES - (r))/2,(COLS - (c))/2)
69
70 /*********************************************
71 * global/exported variables
72 *********************************************/
73
74 INT ll_lines = -1; /* update to be number of lines in screen */
75 INT ll_cols = -1; /* number of columns in screen used by LifeLines */
76 BOOLEAN stdout_vis = FALSE;
77 INT cur_screen = 0;
78 UIWINDOW main_win = NULL;
79 UIWINDOW stdout_win=NULL;
80 static UIWINDOW debug_win=NULL, debug_box_win=NULL;
81 static UIWINDOW ask_win=NULL, ask_msg_win=NULL;
82 static UIWINDOW add_menu_win=NULL, del_menu_win=NULL;
83 static UIWINDOW utils_menu_win=NULL, tt_menu_win=NULL;
84 static UIWINDOW extra_menu_win=NULL;
85
86 /*********************************************
87 * external/imported variables
88 *********************************************/
89
90 extern INT alldone;
91 extern BOOLEAN progrunning;
92 extern STRING empstr,empstr71,readpath,readpath_file,qSronlye,qSdataerr;
93 extern STRING qSabverr,qSuoperr,qSbadttnum,qSnosuchtt,qSmouttt,qSmintt;
94 extern STRING qSmtitle,qScright,qSdbname,qSdbimmut,qSdbrdonly,qSplschs;
95 extern STRING qSmn_unkcmd,qSronlya,qSronlyr;
96 extern STRING qSaskynq,qSaskynyn,qSaskyY;
97 extern STRING qSmn_quit, qSmn_changedb, qSmn_ret, qSmn_exit;
98 extern STRING qSmn_mmbrws,qSmn_mmsear,qSmn_mmadd,qSmn_mmdel;
99 extern STRING qSmn_mmprpt,qSmn_mmrpt,qSmn_mmcset;
100 extern STRING qSmn_mmtt,qSmn_mmut,qSmn_mmex;
101 extern STRING qSmn_cstsort,qSmn_cspref,qSmn_cschar,qSmn_cslcas,qSmn_csucas;
102 extern STRING qSmn_csrpt;
103 extern STRING qSmn_csrpttl;
104 extern STRING idsortttl,idloc;
105 extern STRING qSmn_edttttl,qSmn_svttttl;
106 extern STRING qSmn_utsave,qSmn_utread,qSmn_utgdchoo;
107 extern STRING qSmn_utkey,qSmn_utkpers,qSmn_utdbstat,qSmn_utmemsta;
108 extern STRING qSmn_utplaces,qSmn_utusropt;
109 extern STRING qSmn_xxbsour, qSmn_xxbeven, qSmn_xxbothr, qSmn_xxasour, qSmn_xxesour;
110 extern STRING qSmn_xxaeven, qSmn_xxeeven, qSmn_xxaothr, qSmn_xxeothr;
111 extern STRING qSerrlist,qSdefttl,qSiddefpath;
112
113 extern STRING qSmn_uttl;
114 extern STRING qSmn_xttl;
115 extern STRING qSmn_notimpl;
116 extern STRING qShitkey;
117
118 extern STRING qSmn_add_ttl,qSmn_add_indi,qSmn_add_fam,qSmn_add_chil,qSmn_add_spou;
119 extern STRING qSmn_del_ttl,qSmn_del_chil,qSmn_del_spou;
120 extern STRING qSmn_del_indi,qSmn_del_fam,qSmn_del_any;
121 extern STRING qSmn_tt_ttl,qSmn_tt_edit,qSmn_tt_load,qSmn_tt_save,qSmn_tt_exp;
122 extern STRING qSmn_tt_imp,qSmn_tt_dir;
123 extern STRING qSmn_tt_edin,qSmn_tt_ined,qSmn_tt_gdin,qSmn_tt_ingd;
124 extern STRING qSmn_tt_dsin,qSmn_tt_inds,qSmn_tt_inrp;
125
126
127 /*********************************************
128 * local function prototypes
129 *********************************************/
130
131 /* alphabetical */
132 static void add_shims_info(LIST list);
133 static void add_uiwin(UIWINDOW uiwin);
134 static void append_to_msg_list(STRING msg);
135 static BOOLEAN ask_for_filename_impl(STRING ttl, STRING path, STRING prmpt
136 , STRING buffer, INT buflen);
137 static void begin_action(void);
138 static void check_menu(DYNMENU dynmenu);
139 static void check_stdout(void);
140 static INT choose_or_view_array (STRING ttl, INT no, STRING *pstrngs
141 , BOOLEAN selecting, DETAILFNC detfnc, void *param);
142 static INT choose_tt(STRING prompt);
143 static void clear_msgs(void);
144 static void clear_status(void);
145 static void clearw(void);
146 static void color_hseg(WINDOW *win, INT row, INT x1, INT x2, char ch);
147 static void create_boxed_newwin2(UIWINDOW * puiw, CNSTRING name, INT rows, INT cols);
148 static void create_newwin(UIWINDOW * puiw, CNSTRING name, INT rows, INT cols, INT begy, INT begx);
149 static void create_uisubwindow(UIWINDOW * puiw, CNSTRING name, UIWINDOW parent, INT rows, INT cols, INT begy, INT begx);
150 static void create_uiwindow_impl(UIWINDOW * puiw, CNSTRING name, WINDOW * win, INT rows, INT cols);
151 static void create_windows(void);
152 static void deactivate_uiwin(void);
153 static void delete_uiwindow(UIWINDOW * uiw);
154 static void destroy_windows(void);
155 static void disp_trans_table_choice(UIWINDOW uiwin, INT row, INT col, INT indx);
156 static void display_status(STRING text);
157 static BOOLEAN does_match(VPTR param, VPTR el);
158 static void edit_tt_menu(void);
159 static void edit_user_options(void);
160 static void edit_place_table(void);
161 static void end_action(void);
162 BOOLEAN get_answer(UIWINDOW uiwin, INT row, INT col, STRING buffer, INT buflen);
163 static INT get_brwsmenu_size(INT screen);
164 static RECORD invoke_add_menu(void);
165 static void invoke_cset_display(void);
166 static void invoke_del_menu(void);
167 static INT invoke_extra_menu(RECORD *rec);
168 static void invoke_utils_menu(void);
169 static void output_menu(UIWINDOW uiwin, DYNMENU dynmenu);
170 static void place_cursor_main(void);
171 static void place_std_msg(void);
172 static void platform_postcurses_init(void);
173 static void refresh_main(void);
174 static void register_screen_lang_callbacks(BOOLEAN registering);
175 static void remove_uiwin(UIWINDOW uiwin);
176 static void repaint_add_menu(UIWINDOW uiwin);
177 static void repaint_delete_menu(UIWINDOW uiwin);
178 /*static void repaint_tt_menu(UIWINDOW uiwin);*/
179 static void repaint_utils_menu(UIWINDOW uiwin);
180 static void repaint_extra_menu(UIWINDOW uiwin);
181 static void repaint_main_menu(UIWINDOW uiwin);
182 static int resize_screen_impl(char * errmsg, int errsize);
183 static void run_report(BOOLEAN picklist);
184 static void screen_on_lang_change(VPTR uparm);
185 static RECORD search_for_one_record(void);
186 static void show_fam (UIWINDOW uiwin, RECORD frec, INT mode, INT row, INT hgt, INT width, INT * scroll, BOOLEAN reuse);
187 BOOLEAN show_record(UIWINDOW uiwin, STRING key, INT mode, LLRECT
188 , INT * scroll, BOOLEAN reuse);
189 static void show_tandem_line(UIWINDOW uiwin, INT row);
190 static void switch_to_uiwin(UIWINDOW uiwin);
191 static void touch_all(BOOLEAN includeCurrent);
192 static void uicolor(UIWINDOW, LLRECT rect, char ch);
193 static INT update_browse_menu(INT screen);
194 static void update_screen_size(void);
195 static BOOLEAN yes_no_value(INT c);
196
197 /*********************************************
198 * local variables
199 *********************************************/
200
201 /* what is showing now in status bar */
202 static char status_showing[150];
203 /* flag if it is not important to keep */
204 static BOOLEAN status_transitory = FALSE;
205
206
207 /* total screen lines used */
208 static INT LINESTOTAL = LINESREQ;
209 /* number of lines for various menus */
210 static INT EMPTY_MENU = -1; /* save one horizontal line */
211 /* the following values are default (larger screens get more) */
212 static int TANDEM_LINES_DEF = 6; /* number of lines of tandem info */
213 static int AUX_LINES_DEF = 15; /* number of lines in aux window */
214 /* working values */
215 static int TANDEM_LINES=0;
216 static int AUX_LINES=0;
217
218 int winx=0, winy=0; /* user specified window size */
219
220 static LIST msg_list = 0;
221 static BOOLEAN msg_flag = FALSE; /* need to show msg list */
222 static BOOLEAN viewing_msgs = FALSE; /* user is viewing msgs */
223 static BOOLEAN lock_std_msg = FALSE; /* to hold status message */
224 static UIWINDOW active_uiwin = 0;
225 static LIST list_uiwin = 0; /* list of all uiwindows */
226
227 /* we ought to use chtype, but only if it is typedef'd, but there is no
228 test to see if a type is typedef'd */
229 static llchtype gr_btee='+', gr_ltee='+', gr_rtee='+', gr_ttee='+';
230 static llchtype gr_hline='-', gr_vline= '|';
231 static llchtype gr_llx='*', gr_lrx='*', gr_ulx='*', gr_urx='*';
232
233 /*********************************************
234 * local & exported function definitions
235 * body of module
236 *********************************************/
237
238 /*============================
239 * set_screen_graphical -- Specify whether to use ncurses box characters
240 * graphical: [IN] whether to use ncurses graphical box lines
241 *==========================*/
242 void
set_screen_graphical(BOOLEAN graphical)243 set_screen_graphical (BOOLEAN graphical)
244 {
245 if (graphical) {
246 gr_btee = ACS_BTEE;
247 gr_hline = ACS_HLINE;
248 gr_ltee = ACS_LTEE;
249 gr_rtee = ACS_RTEE;
250 gr_ttee = ACS_TTEE;
251 gr_vline = ACS_VLINE;
252 gr_llx = ACS_LLCORNER;
253 gr_lrx = ACS_LRCORNER;
254 gr_ulx = ACS_ULCORNER;
255 gr_urx = ACS_URCORNER;
256 }
257 else {
258 gr_btee = '+';
259 gr_hline = '-';
260 gr_ltee = '+';
261 gr_rtee = '+';
262 gr_ttee = '+';
263 gr_vline = '|';
264 gr_llx = '*';
265 gr_lrx = '*';
266 gr_ulx = '*';
267 gr_urx = '*';
268 }
269
270 }
271 /*============================
272 * init_screen -- Init screens
273 * returns 0 if current terminal is not large enough, or size requested too small
274 * errmsg: [OUT] buffer to hold failure message
275 * errsize: [IN] size of errmsg buffer
276 *==========================*/
277 int
init_screen(char * errmsg,int errsize)278 init_screen (char * errmsg, int errsize)
279 {
280 int rtn = resize_screen_impl(errmsg, errsize);
281 if (rtn) { /* success */
282 register_screen_lang_callbacks(TRUE);
283 }
284 return rtn;
285 }
286 /*============================
287 * update_screen_size -- Recreate windows etc if screen size has changed
288 *==========================*/
289 static void
update_screen_size(void)290 update_screen_size (void)
291 {
292 char errmsg[512];
293 resize_screen_impl(errmsg, sizeof(errmsg)/sizeof(errmsg[0]));
294 }
295 /*============================
296 * resize_screen_impl -- setup windows & things dependent on screen size
297 * returns 0 if current terminal is not large enough, or size requested too small
298 * errmsg: [OUT] buffer to hold failure message
299 * errsize: [IN] size of errmsg buffer
300 * Safe to be called over and over again
301 * Doesn't do anything if screen size is unchanged from previous size, or if unsupported size
302 *==========================*/
303 static int
resize_screen_impl(char * errmsg,int errsize)304 resize_screen_impl (char * errmsg, int errsize)
305 {
306 INT extralines=0;
307 INT newlines=0, newcols=0;
308
309 /* stop & restart ncurses to update LINES & COLS */
310 if (ll_lines > 0) {
311 /* need endwin before initscr below */
312 endwin();
313 }
314 if (1) {
315 WINDOW *win = initscr();
316 if (!win) {
317 snprintf(errmsg, errsize, _("initscr failed"));
318 return 0; /* fail */
319 }
320 noecho();
321 keypad(win, 1);
322 }
323
324 /* by default, use full screen (as many rows & cols as they have */
325 newlines=LINES;
326 newcols = COLS;
327
328 /* if user specified window size, use it, but check its validity */
329 if (winx) {
330 newlines = winy;
331 newcols = winx;
332 if (newcols > COLS || newlines > LINES) {
333 snprintf(errmsg, errsize
334 , _("The requested window size (%ld,%ld) is too large for your terminal (%d,%d).\n")
335 , newcols, newlines, COLS, LINES);
336 return 0; /* fail */
337 }
338 }
339 /* check that terminal meet minimum requirements */
340 if (newcols < COLSREQ || newlines < LINESREQ) {
341 snprintf(errmsg, errsize
342 , _("The requested window size (%ld,%ld) is too small for LifeLines (%d,%d).\n")
343 , newcols, newlines, COLSREQ, LINESREQ);
344 return 0; /* fail */
345 }
346
347 if (ll_lines == newlines && ll_cols == newcols) {
348 /* screen size is already configured & hasn't changed */
349 return 1; /* succeed */
350 }
351
352
353 ll_lines = newlines;
354 ll_cols = newcols;
355
356 extralines = ll_lines - LINESREQ;
357 LINESTOTAL = ll_lines;
358
359 /* initialize browse window heights to default */
360 TANDEM_LINES = TANDEM_LINES_DEF;
361 AUX_LINES = AUX_LINES_DEF;
362 /* increase for larger screens */
363 if(extralines > 0) {
364 TANDEM_LINES = TANDEM_LINES_DEF + (extralines / 2);
365 AUX_LINES = AUX_LINES_DEF + extralines;
366 }
367 listui_init_windows(extralines);
368 create_windows();
369 brwsmenu_initialize(ll_lines, ll_cols);
370
371
372 return 1; /* succeed */
373 }
374 /*============================
375 * term_screen -- Terminate screens
376 * complement of init_screen
377 *==========================*/
378 void
term_screen(void)379 term_screen (void)
380 {
381 register_screen_lang_callbacks(FALSE);
382 menuitem_terminate();
383 active_uiwin = 0;
384 destroy_windows();
385
386 /* must clear window size so resize_screen_impl will
387 start from scratch, in case we're closing and then
388 starting up again (ie, Q option from main menu) */
389 ll_lines = -1;
390 ll_cols = -1;
391 }
392 /*=======================================
393 * draw_win_box -- wrapper for curses box
394 * handles the case that user didn't want
395 * curses graphics
396 *=====================================*/
397 void
draw_win_box(WINDOW * win)398 draw_win_box (WINDOW * win)
399 {
400 wborder(win, gr_vline, gr_vline, gr_hline, gr_hline, gr_ulx, gr_urx, gr_llx, gr_lrx);
401 }
402 /*=======================================
403 * repaint_main_menu -- Display choices for main menu
404 * See function main_menu for actions
405 *=====================================*/
406 static void
repaint_main_menu(UIWINDOW uiwin)407 repaint_main_menu (UIWINDOW uiwin)
408 {
409 WINDOW *win = uiw_win(uiwin);
410 INT row;
411 char title[80];
412 INT width=sizeof(title);
413 STRING str;
414
415 uierase(uiwin);
416 draw_win_box(win);
417 show_horz_line(uiwin, 4, 0, ll_cols);
418 show_horz_line(uiwin, ll_lines-3, 0, ll_cols);
419 if (width > ll_cols-4)
420 width = ll_cols-4;
421 llstrncpyf(title, width, uu8, _(qSmtitle), get_lifelines_version(ll_cols-4));
422 mvccwaddstr(win, 1, 2, title);
423 mvccwaddstr(win, 2, 4, _(qScright));
424 str = getlloptint("FullDbPath", 1) ? readpath : readpath_file;
425 mvccwprintw(win, 3, 4, _(qSdbname), str);
426 if (immutable)
427 wprintw(win, _(qSdbimmut));
428 else if (readonly)
429 wprintw(win, _(qSdbrdonly));
430 row = 5;
431 /* i18n problem: the letters are not being read from the menu strings */
432 mvccwaddstr(win, row++, 2, _(qSplschs));
433 mvccwaddstr(win, row++, 4, _(qSmn_mmbrws));
434 mvccwaddstr(win, row++, 4, _(qSmn_mmsear));
435 mvccwaddstr(win, row++, 4, _(qSmn_mmadd));
436 mvccwaddstr(win, row++, 4, _(qSmn_mmdel));
437 mvccwaddstr(win, row++, 4, _(qSmn_mmprpt));
438 mvccwaddstr(win, row++, 4, _(qSmn_mmrpt));
439 mvccwaddstr(win, row++, 4, _(qSmn_mmtt));
440 mvccwaddstr(win, row++, 4, _(qSmn_mmut));
441 mvccwaddstr(win, row++, 4, _(qSmn_mmex));
442 mvccwaddstr(win, row++, 4, _(qSmn_changedb));
443 mvccwaddstr(win, row++, 4, _(qSmn_exit));
444 }
445 /*==========================================
446 * create_uiwindow_impl -- Create (or update) the WINDOW wrapper
447 * safe to call on existing UIWINDOW
448 *========================================*/
449 static void
create_uiwindow_impl(UIWINDOW * puiw,CNSTRING name,WINDOW * win,INT rows,INT cols)450 create_uiwindow_impl (UIWINDOW * puiw, CNSTRING name, WINDOW * win, INT rows, INT cols)
451 {
452 UIWINDOW uiwin=0;
453 ASSERT(puiw);
454 uiwin = *puiw;
455 if (!uiwin) {
456 *puiw = uiwin = (UIWINDOW)stdalloc(sizeof(*uiwin));
457 memset(uiwin, 0, sizeof(*uiwin));
458 add_uiwin(uiwin);
459 }
460 if (uiwin->name)
461 stdfree((STRING)uiwin->name);
462 uiwin->name = strsave(name);
463 if (uiw_win(uiwin) != win) {
464 if (uiw_win(uiwin))
465 delwin(uiw_win(uiwin));
466 uiw_win(uiwin) = win;
467 }
468 uiw_rows(uiwin) = rows;
469 uiw_cols(uiwin) = cols;
470 }
471 /*==========================================
472 * add_uiwin -- Record new uiwin into master list
473 *========================================*/
474 static void
add_uiwin(UIWINDOW uiwin)475 add_uiwin (UIWINDOW uiwin)
476 {
477 if (!list_uiwin)
478 list_uiwin = create_list2(LISTNOFREE);
479 enqueue_list(list_uiwin, uiwin);
480 }
481 /*==========================================
482 * remove_uiwin -- Remove uiwin from master list
483 *========================================*/
484 static void
remove_uiwin(UIWINDOW uiwin)485 remove_uiwin (UIWINDOW uiwin)
486 {
487 VPTR param = uiwin;
488 BOOLEAN deleteall = FALSE;
489 ASSERT(list_uiwin);
490 find_delete_list_elements(list_uiwin, param, &does_match, deleteall);
491 }
492 /*==========================================
493 * does_match -- Used as callback to remove_uiwin
494 * in finding an element in a list
495 *========================================*/
496 static BOOLEAN
does_match(VPTR param,VPTR el)497 does_match (VPTR param, VPTR el)
498 {
499 return param == el;
500 }
501 /*==========================================
502 * create_boxed_newwin2 -- Create a window with
503 * an auxiliary box window outside it
504 *========================================*/
505 static void
create_boxed_newwin2(UIWINDOW * puiw,CNSTRING name,INT rows,INT cols)506 create_boxed_newwin2 (UIWINDOW * puiw, CNSTRING name, INT rows, INT cols)
507 {
508 INT begy = (LINES - rows)/2;
509 INT begx = (COLS - cols)/2;
510 WINDOW * boxwin = newwin(rows, cols, begy, begx);
511 WINDOW * win=0;
512 ASSERT(puiw);
513 ++begy;
514 ++begx;
515 win = subwin(boxwin, rows-2, cols-2, begy, begx);
516 create_uiwindow_impl(puiw, name, win, rows-2, cols-2);
517 uiw_boxwin(*puiw) = boxwin;
518 }
519 /*==========================================
520 * delete_uiwindow -- Delete WINDOW wrapper & contents
521 * Created: 2002/01/23
522 *========================================*/
523 static void
delete_uiwindow(UIWINDOW * uiw)524 delete_uiwindow (UIWINDOW * uiw)
525 {
526 if (*uiw) {
527 UIWINDOW w = *uiw;
528 remove_uiwin(w);
529 ASSERT(uiw_win(w));
530 delwin(uiw_win(w));
531 ASSERT(w->name);
532 stdfree((STRING)w->name);
533 stdfree(w);
534 *uiw = 0;
535 }
536 }
537 /*==========================================
538 * create_newwin -- Create our WINDOW wrapper
539 * Create ncurses window of specified size & location
540 * and wrap it with a WUIWINDOW wrapper
541 * and return that
542 *========================================*/
543 static void
create_newwin(UIWINDOW * puiw,CNSTRING name,INT rows,INT cols,INT begy,INT begx)544 create_newwin (UIWINDOW * puiw, CNSTRING name, INT rows, INT cols, INT begy, INT begx)
545 {
546 WINDOW * win = newwin(rows, cols, begy, begx);
547 create_uiwindow_impl(puiw, name, win, rows, cols);
548 }
549 /*==========================================
550 * create_newwin2 -- Create our WINDOW wrapper
551 * Create ncurses window of specified size, centered on current physical screen
552 * and wrap it with a WUIWINDOW wrapper
553 * and return that
554 *========================================*/
555 void
create_newwin2(UIWINDOW * puiw,CNSTRING name,INT rows,INT cols)556 create_newwin2 (UIWINDOW * puiw, CNSTRING name, INT rows, INT cols)
557 {
558 /* NEWWIN centers window on current physical screen */
559 WINDOW * win = NEWWIN(rows, cols);
560 create_uiwindow_impl(puiw, name, win,rows,cols);
561 }
562 /*==========================================
563 * create_uisubwindow -- Create our WINDOW wrapper
564 * for a true (& permanent) subwindow
565 *========================================*/
566 static void
create_uisubwindow(UIWINDOW * puiw,CNSTRING name,UIWINDOW parent,INT rows,INT cols,INT begy,INT begx)567 create_uisubwindow (UIWINDOW * puiw, CNSTRING name, UIWINDOW parent
568 , INT rows, INT cols
569 , INT begy, INT begx)
570 {
571 WINDOW * win = subwin(uiw_win(parent), rows, cols, begy, begx);
572 create_uiwindow_impl(puiw, name, win, rows, cols);
573 uiw_parent(*puiw) = parent;
574 uiw_permsub(*puiw) = TRUE;
575 }
576 /*==========================================
577 * destroy_windows -- Undo create_windows
578 *========================================*/
579 static void
destroy_windows(void)580 destroy_windows (void)
581 {
582 delete_uiwindow(&ask_msg_win);
583 delete_uiwindow(&ask_win);
584 delete_uiwindow(&tt_menu_win);
585 delete_uiwindow(&main_win);
586 delete_uiwindow(&debug_win);
587 delete_uiwindow(&debug_box_win);
588 delete_uiwindow(&stdout_win);
589 }
590 /*==========================================
591 * create_windows -- Create and init windows
592 *========================================*/
593 static void
create_windows(void)594 create_windows (void)
595 {
596 INT col;
597
598 create_boxed_newwin2(&stdout_win, "stdout_win", ll_lines-4, ll_cols-4);
599 scrollok(uiw_win(stdout_win), TRUE);
600
601 col = COLS/4;
602 create_newwin(&debug_box_win, "debug_box", 8, ll_cols-col-2, 1, col);
603
604 create_uisubwindow(&debug_win, "debug", debug_box_win, 6, ll_cols-col-4, 2, col+1);
605 scrollok(uiw_win(debug_win), TRUE);
606
607 MAINWIN_WIDTH = ll_cols;
608 create_newwin2(&main_win, "main", ll_lines, MAINWIN_WIDTH);
609
610 create_newwin2(&tt_menu_win, "tt_menu", 12,MAINWIN_WIDTH-7);
611
612 create_newwin2(&ask_win, "ask", 4, 73);
613
614 create_newwin2(&ask_msg_win, "ask_msg", 5, 73);
615
616
617 /* tt_menu_win is drawn dynamically */
618 draw_win_box(uiw_win(ask_win));
619 draw_win_box(uiw_win(ask_msg_win));
620 draw_win_box(uiw_win(debug_box_win));
621 }
622 /*=================================
623 * display_screen --
624 * There are six screens that all use
625 * the main_win. MAIN_SCREEN is the
626 * intro/main menu. The other 6 are all
627 * browse screens.
628 * cur_screen tells which is active.
629 *===============================*/
630 void
display_screen(INT new_screen)631 display_screen (INT new_screen)
632 {
633 UIWINDOW uiwin = main_win;
634 WINDOW * win = uiw_win(uiwin);
635 cur_screen = new_screen;
636 check_stdout();
637 if (!status_showing[0] || status_transitory)
638 place_std_msg();
639 else
640 mvccwaddstr(win, ll_lines-2, 2, status_showing);
641 place_cursor_main();
642 switch_to_uiwin(uiwin);
643 }
644 /*=====================================
645 * do_check_stdout -- Pause for stdout/err display
646 * if it is up
647 *===================================*/
648 static INT
do_prompt_stdout(STRING prompt)649 do_prompt_stdout (STRING prompt)
650 {
651 INT ch=0;
652 llwprintf("\n%s\n", prompt);
653 crmode();
654 ch = wgetch(uiw_win(stdout_win));
655 nocrmode();
656 /* ok the status string was available until they struck a key */
657 clear_status();
658 return ch;
659 }
660 /*=====================================
661 * check_stdout -- If stdout populated,
662 * prompt user to acknowledge, close & deactivate it
663 *===================================*/
664 static void
check_stdout(void)665 check_stdout (void)
666 {
667 if (active_uiwin == stdout_win) {
668 if (stdout_vis) {
669 do_prompt_stdout(_(qShitkey));
670 stdout_vis = FALSE;
671 }
672 deactivate_uiwin_and_touch_all();
673 }
674 }
675 /*=====================================
676 * prompt_stdout -- Prompt user in stdout
677 * This is like check_stdout, except it always
678 * prompts, and it returns the response char,
679 * and it doesn't clear stdout
680 *===================================*/
681 INT
prompt_stdout(STRING prompt)682 prompt_stdout (STRING prompt)
683 {
684 INT i;
685 if (active_uiwin != stdout_win)
686 activate_uiwin(stdout_win);
687 stdout_vis = TRUE;
688 i = do_prompt_stdout(prompt);
689 return i;
690 }
691 /*=====================================
692 * search_for_one_record -- Invoke search menu & trim to one record
693 *===================================*/
694 static RECORD
search_for_one_record(void)695 search_for_one_record (void)
696 {
697 INDISEQ seq = invoke_search_menu();
698 if (!seq) return NULL;
699 if (!length_indiseq(seq)) {
700 remove_indiseq(seq);
701 return NULL;
702 }
703 /* namesort uses canonkeysort for non-persons */
704 namesort_indiseq(seq);
705 return choose_from_indiseq(seq, DOASK1,
706 _("Search results"), _("Search results"));
707 }
708 /*=====================================
709 * main_menu -- Handle main_menu screen
710 *===================================*/
711 void
main_menu(void)712 main_menu (void)
713 {
714 INT c;
715 UIWINDOW uiwin = main_win;
716 WINDOW * win = uiw_win(uiwin);
717 repaint_main_menu(uiwin);
718 display_screen(MAIN_SCREEN);
719 c = interact_choice_string(uiwin, "bsadprtuxqQ");
720 place_std_msg();
721 wrefresh(win);
722 switch (c) {
723 case 'b': main_browse(NULL, BROWSE_INDI); break;
724 case 's':
725 {
726 RECORD rec = search_for_one_record();
727 if (rec)
728 main_browse(rec, BROWSE_UNK);
729 }
730 break;
731 case 'a':
732 {
733 RECORD rec = 0;
734 if (readonly) {
735 msg_error(_(qSronlya));
736 break;
737 }
738 rec = invoke_add_menu();
739 if (rec)
740 main_browse(rec, BROWSE_UNK);
741 }
742 break;
743 case 'd':
744 {
745 if (readonly) {
746 msg_error(_(qSronlyr));
747 break;
748 }
749 invoke_del_menu();
750 }
751 break;
752 case 'p': run_report(TRUE); break;
753 case 'r': run_report(FALSE); break;
754 case 't': edit_tt_menu(); break;
755 case 'u': invoke_utils_menu(); break;
756 case 'x':
757 {
758 RECORD rec=0;
759 c = invoke_extra_menu(&rec);
760 if (c != BROWSE_QUIT)
761 main_browse(rec, c);
762 /* main_browse consumed rec */
763 }
764 break;
765 case 'q': alldone = 1; break;
766 case 'Q':
767 uierase(main_win);
768 alldone = 2;
769 break;
770 }
771 }
772 /*=========================================
773 * run_report -- run a report program
774 * @picklist: [IN] display list of reports to user ?
775 *=======================================*/
776 void
run_report(BOOLEAN picklist)777 run_report (BOOLEAN picklist)
778 {
779 LIST progfiles = NULL; /* will prompt for report */
780 STRING ofile = NULL; /* will prompt for output file */
781 BOOLEAN timing = TRUE;
782 begin_action();
783 interp_main(progfiles, ofile, picklist, timing);
784 end_action(); /* displays any errors that happened */
785 }
786 /*=========================================
787 * update_browse_menu -- redraw menu if needed
788 * This is browse menu using dynamic menu
789 * in rectangle at bottom of screen
790 * Returns number lines used by menu
791 *=======================================*/
792 static INT
update_browse_menu(INT screen)793 update_browse_menu (INT screen)
794 {
795 DYNMENU dynmenu = get_screen_dynmenu(screen);
796 INT lines = LINESTOTAL-OVERHEAD_MENU - get_brwsmenu_size(screen);
797 if (dynmenu->dirty || (cur_screen != screen)) {
798 UIWINDOW uiwin = main_win;
799 WINDOW *win = uiw_win(uiwin);
800 uierase(uiwin);
801 draw_win_box(win);
802 show_horz_line(uiwin, ll_lines-3, 0, ll_cols);
803 if (!dynmenu->hidden) {
804 /* display title */
805 INT width = ll_cols;
806 char prompt[128];
807 check_menu(dynmenu);
808 /* display prompt immediately above menu */
809 llstrncpy(prompt, _(qSplschs), sizeof(prompt), uu8);
810 dynmenu->cur_x = strlen(_(qSplschs))+3;
811 dynmenu->cur_y = dynmenu->top - 1;
812 llstrapps(prompt, sizeof(prompt), uu8, " ");
813 llstrappf(prompt, sizeof(prompt), uu8, _("(pg %d/%d)")
814 , dynmenu->page+1, dynmenu->pages);
815 /* display line across */
816 show_horz_line(uiwin, dynmenu->top-2, 0, width);
817 /* display prompt */
818 mvccwaddstr(win, dynmenu->top-1, dynmenu->left-1, prompt);
819 /* draw menu */
820 output_menu(uiwin, dynmenu);
821 }
822 }
823 dynmenu->dirty = FALSE;
824 return lines;
825 }
826 /*=========================================
827 * show_indi -- Show indi according to mode
828 * @uiwin: [IN] where to display
829 * @indi: [IN] whom to display
830 * @mode: [IN] how to display (eg, traditional, gedcom, ...)
831 * @rect: [IN] rectangular area in which to display
832 * @scroll: [I/O] how far down display is scrolled
833 * @reuse: [IN] flag to save recalculating display strings
834 *=======================================*/
835 void
show_indi(UIWINDOW uiwin,RECORD irec,INT mode,LLRECT rect,INT * scroll,BOOLEAN reuse)836 show_indi (UIWINDOW uiwin, RECORD irec, INT mode, LLRECT rect
837 , INT * scroll, BOOLEAN reuse)
838 {
839 CACHEEL icel;
840 icel = indi_to_cacheel(irec);
841 lock_cache(icel);
842 if (mode=='g')
843 show_gedcom(uiwin, irec, GDVW_NORMAL, rect, scroll, reuse);
844 else if (mode=='x')
845 show_gedcom(uiwin, irec, GDVW_EXPANDED, rect, scroll, reuse);
846 else if (mode=='t')
847 show_gedcom(uiwin, irec, GDVW_TEXT, rect, scroll, reuse);
848 else if (mode=='a')
849 show_ancestors(uiwin, irec, rect, scroll, reuse);
850 else if (mode=='d')
851 show_descendants(uiwin, irec, rect, scroll, reuse);
852 else
853 show_indi_vitals(uiwin, irec, rect, scroll, reuse);
854 unlock_cache(icel);
855 }
856 /*=========================================
857 * show_fam -- Show family
858 * fam: [IN] whom to display
859 * mode: [IN] how to display
860 * row: [IN] starting row to use
861 * hgt: [IN] how many rows allowed
862 * width: [IN] how many columns allowed
863 * reuse: [IN] flag to save recalculating display strings
864 *=======================================*/
865 static void
show_fam(UIWINDOW uiwin,RECORD frec,INT mode,INT row,INT hgt,INT width,INT * scroll,BOOLEAN reuse)866 show_fam (UIWINDOW uiwin, RECORD frec, INT mode, INT row, INT hgt
867 , INT width, INT * scroll, BOOLEAN reuse)
868 {
869 struct tag_llrect rect;
870 CACHEEL fcel;
871 fcel = fam_to_cacheel(frec);
872 lock_cache(fcel);
873 rect.top = row;
874 rect.bottom = row+hgt-1;
875 rect.left = 1;
876 rect.right = width-1;
877 if (mode=='g')
878 show_gedcom(uiwin, frec, GDVW_NORMAL, &rect, scroll, reuse);
879 else if (mode=='x')
880 show_gedcom(uiwin, frec, GDVW_EXPANDED, &rect, scroll, reuse);
881 else if (mode=='t')
882 show_gedcom(uiwin, frec, GDVW_TEXT, &rect, scroll, reuse);
883 else
884 show_fam_vitals(uiwin, frec, row, hgt, width, scroll, reuse);
885 unlock_cache(fcel);
886 }
887 /*=========================================
888 * display_indi -- Paint indi on-screen
889 *=======================================*/
890 void
display_indi(RECORD indi,INT mode,BOOLEAN reuse)891 display_indi (RECORD indi, INT mode, BOOLEAN reuse)
892 {
893 INT screen = ONE_PER_SCREEN;
894 INT lines=0;
895 struct tag_llrect rect;
896 update_screen_size(); /* ensure screen size is current */
897 lines = update_browse_menu(screen);
898 /* leave room for box all around */
899 rect.top = 1;
900 rect.bottom = lines;
901 rect.left = 1;
902 rect.right = MAINWIN_WIDTH-2;
903 show_indi(main_win, indi, mode, &rect, &Scroll1, reuse);
904 display_screen(screen);
905 }
906 /*=========================================
907 * interact_indi -- Get menu choice for indi browse
908 *=======================================*/
909 INT
interact_indi(void)910 interact_indi (void)
911 {
912 return interact_screen_menu(main_win, ONE_PER_SCREEN);
913 }
914 /*=======================================
915 * display_fam -- Paint fam on-screen
916 *=====================================*/
917 void
display_fam(RECORD frec,INT mode,BOOLEAN reuse)918 display_fam (RECORD frec, INT mode, BOOLEAN reuse)
919 {
920 INT width=0;
921 INT screen = ONE_FAM_SCREEN;
922 INT lines=0;
923 update_screen_size(); /* ensure screen size is current */
924 lines = update_browse_menu(screen);
925 width = MAINWIN_WIDTH;
926 show_fam(main_win, frec, mode, 1, lines, width, &Scroll1, reuse);
927 display_screen(screen);
928 }
929 /*=========================================
930 * interact_fam -- Get menu choice for indi browse
931 *=======================================*/
932 INT
interact_fam(void)933 interact_fam (void)
934 {
935 return interact_screen_menu(main_win, ONE_FAM_SCREEN);
936 }
937 /*=============================================
938 * display_2indi -- Paint tandem indi screen
939 *===========================================*/
940 void
display_2indi(RECORD irec1,RECORD irec2,INT mode)941 display_2indi (RECORD irec1, RECORD irec2, INT mode)
942 {
943 INT screen = TWO_PER_SCREEN;
944 INT lines=0;
945 INT lines1=0,lines2=0;
946 BOOLEAN reuse = FALSE; /* can't reuse display strings in tandem */
947 struct tag_llrect rect;
948
949 update_screen_size(); /* ensure screen size is current */
950
951 lines = update_browse_menu(screen);
952 lines--; /* for tandem line */
953 lines2 = lines/2;
954 lines1 = lines - lines2;
955
956 rect.top = 1;
957 rect.bottom = lines1;
958 rect.left = 1;
959 rect.right = MAINWIN_WIDTH-2;
960
961 show_indi(main_win, irec1, mode, &rect, &Scroll1, reuse);
962 show_tandem_line(main_win, lines1+1);
963 switch_scrolls();
964 rect.top = lines1+2;
965 rect.bottom = lines+1;
966 show_indi(main_win, irec2, mode, &rect, &Scroll1, reuse);
967 switch_scrolls();
968
969 display_screen(screen);
970 }
971 /*=========================================
972 * interact_2indi -- Get menu choice for tandem indi
973 *=======================================*/
974 INT
interact_2indi(void)975 interact_2indi (void)
976 {
977 return interact_screen_menu(main_win, TWO_PER_SCREEN);
978 }
979 /*====================================
980 * show_tandem_line -- Display horizontal line between top & bottom
981 * PR 1999/03
982 *==================================*/
983 static void
show_tandem_line(UIWINDOW win,INT row)984 show_tandem_line (UIWINDOW win, INT row)
985 {
986 show_horz_line(win, row, 0, ll_cols);
987 }
988 /*=============================================
989 * display_2fam -- Paint tandem families
990 *===========================================*/
991 void
display_2fam(RECORD frec1,RECORD frec2,INT mode)992 display_2fam (RECORD frec1, RECORD frec2, INT mode)
993 {
994 UIWINDOW uiwin = main_win;
995 INT width=0;
996 INT screen = TWO_FAM_SCREEN;
997 INT lines=0;
998 INT lines1=0,lines2=0;
999 BOOLEAN reuse = FALSE; /* can't reuse display strings in tandem */
1000
1001 update_screen_size(); /* ensure screen size is current */
1002 width=MAINWIN_WIDTH;
1003
1004 lines = update_browse_menu(screen);
1005 lines--; /* for tandem line */
1006 lines2 = lines/2;
1007 lines1 = lines - lines2;
1008
1009 show_fam(uiwin, frec1, mode, 1, lines1, width, &Scroll1, reuse);
1010 show_tandem_line(main_win, lines1+1);
1011 switch_scrolls();
1012 show_fam(uiwin, frec2, mode, lines1+2, lines2, width, &Scroll1, reuse);
1013 switch_scrolls();
1014
1015 display_screen(screen);
1016 }
1017 /*=========================================
1018 * interact_2fam -- Get menu choice for tandem fam
1019 *=======================================*/
1020 INT
interact_2fam(void)1021 interact_2fam (void)
1022 {
1023 return interact_screen_menu(main_win, TWO_FAM_SCREEN);
1024 }
1025 /*=========================================
1026 * interact_popup -- Get menu choice for a popup window
1027 *=======================================*/
1028 INT
interact_popup(UIWINDOW uiwin,STRING str)1029 interact_popup (UIWINDOW uiwin, STRING str)
1030 {
1031 return interact_choice_string(uiwin, str);
1032 }
1033 /*=======================================
1034 * aux_browse -- Handle aux_browse screen
1035 * This is used for browsing S, E, or X records.
1036 *=====================================*/
1037 INT
aux_browse(RECORD rec,INT mode,BOOLEAN reuse)1038 aux_browse (RECORD rec, INT mode, BOOLEAN reuse)
1039 {
1040 UIWINDOW uiwin = main_win;
1041 INT lines = update_browse_menu(AUX_SCREEN);
1042 struct tag_llrect rect;
1043 rect.top = 1;
1044 rect.bottom = lines;
1045 rect.left = 1;
1046 rect.right = MAINWIN_WIDTH-1;
1047 show_aux(uiwin, rec, mode, &rect, &Scroll1, reuse);
1048 display_screen(AUX_SCREEN);
1049 return interact_screen_menu(uiwin, AUX_SCREEN);
1050 }
1051 /*=========================================
1052 * list_browse -- Handle list_browse screen
1053 * cur is passed for GUI doing
1054 * direct navigation in list
1055 * this curses implementation does not use them
1056 *=======================================*/
1057 INT
list_browse(INDISEQ seq,INT top,INT * cur,INT mark)1058 list_browse (INDISEQ seq, INT top, INT * cur, INT mark)
1059 {
1060 if (cur_screen != LIST_SCREEN) paint_list_screen();
1061 show_big_list(seq, top, *cur, mark);
1062 display_screen(LIST_SCREEN);
1063 return interact_choice_string(main_win, "jkeimrtbanx$^udUDq");
1064 }
1065 /*======================================
1066 * ask_for_db_filename -- Ask user for lifelines database directory
1067 * ttl: [IN] title of question (1rst line)
1068 * prmpt: [IN] prompt of question (2nd line)
1069 *====================================*/
1070 BOOLEAN
ask_for_db_filename(CNSTRING ttl,CNSTRING prmpt,CNSTRING basedir,STRING buffer,INT buflen)1071 ask_for_db_filename (CNSTRING ttl, CNSTRING prmpt, CNSTRING basedir, STRING buffer, INT buflen)
1072 {
1073 basedir=basedir; /* unused */
1074 /* This could have a list of existing ones like askprogram.c */
1075 return ask_for_string(ttl, prmpt, buffer, buflen);
1076 }
1077 /*======================================
1078 * ask_for_output_filename -- Ask user for filename to which to write
1079 * returns static buffer
1080 * ttl1: [IN] title of question (1rst line)
1081 * prmpt: [IN] prompt of question (3rd line)
1082 * buffer: [OUT] response
1083 * buflen: [IN] max size of response
1084 *====================================*/
1085 BOOLEAN
ask_for_output_filename(STRING ttl,STRING path,STRING prmpt,STRING buffer,INT buflen)1086 ask_for_output_filename (STRING ttl, STRING path, STRING prmpt, STRING buffer, INT buflen)
1087 {
1088 /* curses version doesn't differentiate input from output prompts */
1089 return ask_for_filename_impl(ttl, path, prmpt, buffer, buflen);
1090 }
1091 /*======================================
1092 * ask_for_input_filename -- Ask user for filename from which to read
1093 * returns static buffer
1094 * ttl1: [IN] title of question (1rst line)
1095 * prmpt: [IN] prompt of question (3rd line)
1096 * buffer: [OUT] response
1097 * buflen: [IN] max size of response
1098 *====================================*/
1099 BOOLEAN
ask_for_input_filename(STRING ttl,STRING path,STRING prmpt,STRING buffer,INT buflen)1100 ask_for_input_filename (STRING ttl, STRING path, STRING prmpt, STRING buffer, INT buflen)
1101 {
1102 /* curses version doesn't differentiate input from output prompts */
1103 return ask_for_filename_impl(ttl, path, prmpt, buffer, buflen);
1104 }
1105 /*======================================
1106 * ask_for_input_filename_impl -- Ask user for a filename
1107 * (in curses version, we don't differentiate input from output prompts)
1108 * ttl1: [IN] title of question (1rst line)
1109 * path: [IN] path prompt (2nd line)
1110 * prmpt: [IN] prompt of question (3rd line)
1111 * buffer: [OUT] response
1112 * buflen: [IN] max size of response
1113 *====================================*/
1114 static BOOLEAN
ask_for_filename_impl(STRING ttl,STRING path,STRING prmpt,STRING buffer,INT buflen)1115 ask_for_filename_impl (STRING ttl, STRING path, STRING prmpt, STRING buffer, INT buflen)
1116 {
1117 /* display current path (truncated to fit) */
1118 char curpath[120];
1119 INT len = sizeof(curpath);
1120 if (len > uiw_cols(ask_msg_win)-2)
1121 len = uiw_cols(ask_msg_win)-2;
1122 curpath[0] = 0;
1123 llstrapps(curpath, len, uu8, _(qSiddefpath));
1124 llstrapps(curpath, len, uu8, compress_path(path, len-strlen(curpath)-1));
1125
1126 return ask_for_string2(ttl, curpath, prmpt, buffer, buflen);
1127 }
1128 /*======================================
1129 * refresh_main -- touch & refresh main or stdout
1130 * as appropriate
1131 *====================================*/
1132 static void
refresh_main(void)1133 refresh_main (void)
1134 {
1135 WINDOW *win = stdout_vis ? uiw_win(stdout_win) : uiw_win(main_win);
1136 wrefresh(win);
1137 }
1138 /*======================================
1139 * ask_for_string -- Ask user for string
1140 * returns static buffer
1141 * ttl: [IN] title of question (1rst line)
1142 * prmpt: [IN] prompt of question (2nd line)
1143 * buffer: [OUT] response
1144 * buflen: [IN] max size of response
1145 *====================================*/
1146 BOOLEAN
ask_for_string(CNSTRING ttl,CNSTRING prmpt,STRING buffer,INT buflen)1147 ask_for_string (CNSTRING ttl, CNSTRING prmpt, STRING buffer, INT buflen)
1148 {
1149 UIWINDOW uiwin = ask_win;
1150 WINDOW *win = uiw_win(uiwin);
1151 BOOLEAN rtn;
1152 uierase(uiwin);
1153 draw_win_box(win);
1154 mvccuwaddstr(uiwin, 1, 1, ttl);
1155 mvccuwaddstr(uiwin, 2, 1, prmpt);
1156 activate_uiwin(uiwin);
1157 rtn = get_answer(uiwin, 2, strlen(prmpt) + 2, buffer, buflen);
1158 deactivate_uiwin_and_touch_all();
1159 return rtn;
1160 }
1161 /*======================================
1162 * ask_for_string2 -- Ask user for string
1163 * Two lines of title
1164 * returns static buffer
1165 * ttl1: [IN] title of question (1rst line)
1166 * ttl2: [IN] 2nd line of title
1167 * prmpt: [IN] prompt of question (3rd line)
1168 * buffer: [OUT] response
1169 * buflen: [IN] max size of response
1170 *====================================*/
1171 BOOLEAN
ask_for_string2(CNSTRING ttl1,CNSTRING ttl2,CNSTRING prmpt,STRING buffer,INT buflen)1172 ask_for_string2 (CNSTRING ttl1, CNSTRING ttl2, CNSTRING prmpt, STRING buffer, INT buflen)
1173 {
1174 UIWINDOW uiwin = ask_msg_win;
1175 WINDOW *win = uiw_win(uiwin);
1176 BOOLEAN rtn;
1177 uierase(uiwin);
1178 draw_win_box(win);
1179 mvccwaddstr(win, 1, 1, ttl1);
1180 mvccwaddstr(win, 2, 1, ttl2);
1181 mvccwaddstr(win, 3, 1, prmpt);
1182 wrefresh(win);
1183 activate_uiwin(uiwin);
1184 rtn = get_answer(uiwin, 3, strlen(prmpt) + 2, buffer, buflen);
1185 deactivate_uiwin_and_touch_all();
1186 return rtn;
1187 }
1188 /*========================================
1189 * yes_no_value -- Convert character to TRUE if y(es)
1190 *======================================*/
1191 static BOOLEAN
yes_no_value(INT c)1192 yes_no_value (INT c)
1193 {
1194 STRING ptr;
1195 for (ptr = _(qSaskyY); *ptr; ptr++) {
1196 if (c == *ptr) return TRUE;
1197 }
1198 return FALSE;
1199 }
1200 /*========================================
1201 * ask_yes_or_no -- Ask yes or no question
1202 * ttl: [IN] title to display
1203 *======================================*/
1204 BOOLEAN
ask_yes_or_no(STRING ttl)1205 ask_yes_or_no (STRING ttl)
1206 {
1207 INT c = ask_for_char(ttl, _(qSaskynq), _(qSaskynyn));
1208 return yes_no_value(c);
1209 }
1210 /*=========================================================
1211 * ask_yes_or_no_msg -- Ask yes or no question with message
1212 * msg: [IN] top line displayed
1213 * ttl: [IN] 2nd line displayed
1214 *=======================================================*/
1215 BOOLEAN
ask_yes_or_no_msg(STRING msg,STRING ttl)1216 ask_yes_or_no_msg (STRING msg, STRING ttl)
1217 {
1218 INT c = ask_for_char_msg(msg, ttl, _(qSaskynq), _(qSaskynyn));
1219 return yes_no_value(c);
1220 }
1221 /*=======================================
1222 * ask_for_char -- Ask user for character
1223 * ttl: [IN] 1nd line displayed
1224 * prmpt: [IN] 2nd line text before cursor
1225 * ptrn: [IN] List of allowable character responses
1226 *=====================================*/
1227 INT
ask_for_char(STRING ttl,STRING prmpt,STRING ptrn)1228 ask_for_char (STRING ttl, STRING prmpt, STRING ptrn)
1229 {
1230 return ask_for_char_msg(NULL, ttl, prmpt, ptrn);
1231 }
1232 /*===========================================
1233 * ask_for_char_msg -- Ask user for character
1234 * msg: [IN] top line displayed (optional)
1235 * ttl: [IN] 2nd line displayed
1236 * prmpt: [IN] 3rd line text before cursor
1237 * ptrn: [IN] List of allowable character responses
1238 *=========================================*/
1239 INT
ask_for_char_msg(STRING msg,STRING ttl,STRING prmpt,STRING ptrn)1240 ask_for_char_msg (STRING msg, STRING ttl, STRING prmpt, STRING ptrn)
1241 {
1242 UIWINDOW uiwin = (msg ? ask_msg_win : ask_win);
1243 WINDOW *win = uiw_win(uiwin);
1244 INT y;
1245 INT rv;
1246 uierase(uiwin);
1247 draw_win_box(win);
1248 y = 1;
1249 if (msg)
1250 mvccwaddstr(win, y++, 2, msg);
1251 mvccwaddstr(win, y++, 2, ttl);
1252 mvccwaddstr(win, y++, 2, prmpt);
1253 wrefresh(win);
1254 rv = interact_choice_string(uiwin, ptrn);
1255 return rv;
1256 }
1257 /*============================================
1258 * choose_from_array -- Choose from string list
1259 * ttl: [IN] title for choice display
1260 * no: [IN] number of choices
1261 * pstrngs: [IN] array of choices
1262 * returns 0-based index chosen, or -1 if cancelled
1263 *==========================================*/
1264 INT
choose_from_array(STRING ttl,INT no,STRING * pstrngs)1265 choose_from_array (STRING ttl, INT no, STRING *pstrngs)
1266 {
1267 BOOLEAN selecting = TRUE;
1268 if (!ttl) ttl=_(qSdefttl);
1269 return choose_or_view_array(ttl, no, pstrngs, selecting, 0, 0);
1270 }
1271 /*============================================
1272 * display_list -- Show user list of information
1273 * ttl: [IN] title for display
1274 * list [IN] list of string entries
1275 * returns 0-based index chosen, or -1 if cancelled
1276 *==========================================*/
1277 INT
display_list(STRING ttl,LIST list)1278 display_list (STRING ttl, LIST list)
1279 {
1280 /* TODO: Need to set some flag to suppress i & <enter> */
1281 return choose_from_list(ttl, list);
1282 }
1283 /*============================================
1284 * choose_from_list -- Choose from string list
1285 * ttl: [IN] title for display
1286 * list [IN] list of string choices
1287 * returns 0-based index chosen, or -1 if cancelled
1288 *==========================================*/
1289 INT
choose_from_list(STRING ttl,LIST list)1290 choose_from_list (STRING ttl, LIST list)
1291 {
1292 STRING * array=0;
1293 STRING choice=0;
1294 INT i=0, rtn=-1;
1295 INT len = length_list(list);
1296
1297 if (len < 1) return -1;
1298 if (!ttl) ttl=_(qSdefttl);
1299
1300 array = (STRING *) stdalloc(len*sizeof(STRING));
1301 i = 0;
1302 FORLIST(list, el)
1303 choice = (STRING)el;
1304 ASSERT(choice);
1305 array[i] = strsave(choice);
1306 ++i;
1307 ENDLIST
1308
1309 rtn = choose_from_array(ttl, len, array);
1310
1311 for (i=0; i<len; ++i)
1312 strfree(&array[i]);
1313 stdfree(array);
1314 return rtn;
1315 }
1316 /*============================================
1317 * choose_from_array_x -- Choose from string list
1318 * ttl: [IN] title for choice display
1319 * no: [IN] number of choices
1320 * pstrngs: [IN] array of choices
1321 * detfnc: [IN] callback for details about items
1322 * param: [IN] opaque type for callback
1323 * returns 0-based index chosen, or -1 if cancelled
1324 *==========================================*/
1325 INT
choose_from_array_x(STRING ttl,INT no,STRING * pstrngs,DETAILFNC detfnc,void * param)1326 choose_from_array_x (STRING ttl, INT no, STRING *pstrngs, DETAILFNC detfnc
1327 , void *param)
1328 {
1329 BOOLEAN selecting = TRUE;
1330 if (!ttl) ttl=_(qSdefttl);
1331 return choose_or_view_array(ttl, no, pstrngs, selecting, detfnc, param);
1332 }
1333 /*============================================
1334 * view_array -- Choose from string list
1335 * ttl: [IN] title for choice display
1336 * no: [IN] number of choices
1337 * pstrngs: [IN] array of choices
1338 * returns 0-based index chosen, or -1 if cancelled
1339 *==========================================*/
1340 void
view_array(STRING ttl,INT no,STRING * pstrngs)1341 view_array (STRING ttl, INT no, STRING *pstrngs)
1342 {
1343 BOOLEAN selecting = FALSE;
1344 choose_or_view_array(ttl, no, pstrngs, selecting, 0, 0);
1345 }
1346 /*============================================
1347 * choose_or_view_array -- Implement choose/view from array
1348 * ttl: [IN] title for choice display
1349 * no: [IN] number of choices
1350 * pstrngs: [IN] array of choices
1351 * selecting: [IN] if FALSE then view-only
1352 * detfnc: [IN] callback for details about items
1353 * param: [IN] opaque type for callback
1354 * returns 0-based index chosen, or -1 if cancelled
1355 *==========================================*/
1356 static INT
choose_or_view_array(STRING ttl,INT no,STRING * pstrngs,BOOLEAN selecting,DETAILFNC detfnc,void * param)1357 choose_or_view_array (STRING ttl, INT no, STRING *pstrngs, BOOLEAN selecting
1358 , DETAILFNC detfnc, void *param)
1359 {
1360 INT rv;
1361 rv = array_interact(ttl, no, pstrngs, selecting, detfnc, param);
1362 refresh_main();
1363 return rv;
1364 }
1365 /*=============================================================
1366 * choose_one_from_indiseq --
1367 * Choose a single person from indiseq
1368 * Returns index of selected item (or -1 if user quit)
1369 * ttl: [IN] title
1370 *===========================================================*/
1371 INT
choose_one_from_indiseq(STRING ttl,INDISEQ seq)1372 choose_one_from_indiseq (STRING ttl, INDISEQ seq)
1373 {
1374 return choose_one_or_list_from_indiseq(ttl, seq, FALSE);
1375 }
1376 /*==========================================================
1377 * choose_list_from_indiseq -- User chooses subsequence from
1378 * person sequence
1379 * returns input sequence, but may have deleted elements
1380 * called by both reports & interactive use
1381 * ttl: [IN] title/caption for choice list
1382 * seq: [I/O] list from which to choose (user may delete items)
1383 * returns index of where user choose select (or -1 if quit)
1384 *========================================================*/
1385 INT
choose_list_from_indiseq(STRING ttl,INDISEQ seq)1386 choose_list_from_indiseq (STRING ttl, INDISEQ seq)
1387 {
1388 return choose_one_or_list_from_indiseq(ttl, seq, TRUE);
1389 }
1390 /*==============================
1391 * draw_tt_win -- Draw menu for edit translations
1392 *============================*/
1393 static void
draw_tt_win(STRING prompt)1394 draw_tt_win (STRING prompt)
1395 {
1396 UIWINDOW uiwin = tt_menu_win;
1397 WINDOW *win = uiw_win(uiwin);
1398 INT row = 0;
1399 uierase(uiwin);
1400 draw_win_box(win);
1401 row = 1;
1402 mvccwaddstr(win, row++, 2, prompt);
1403 disp_trans_table_choice(uiwin, row++, 4, MEDIN);
1404 disp_trans_table_choice(uiwin, row++, 4, MINED);
1405 disp_trans_table_choice(uiwin, row++, 4, MGDIN);
1406 disp_trans_table_choice(uiwin, row++, 4, MINGD);
1407 disp_trans_table_choice(uiwin, row++, 4, MDSIN);
1408 disp_trans_table_choice(uiwin, row++, 4, MINDS);
1409 disp_trans_table_choice(uiwin, row++, 4, MRPIN);
1410 disp_trans_table_choice(uiwin, row++, 4, MINRP);
1411 mvccwaddstr(win, row++, 4, _(qSmn_ret));
1412 }
1413 /*==============================
1414 * disp_trans_table_choice -- Display line in
1415 * translation table menu, & show current info
1416 * Created: 2001/07/20
1417 *============================*/
1418 static void
disp_trans_table_choice(UIWINDOW uiwin,INT row,INT col,INT trnum)1419 disp_trans_table_choice (UIWINDOW uiwin, INT row, INT col, INT trnum)
1420 {
1421 XLAT xlat;
1422 ZSTR zstr, z1;
1423
1424 xlat = transl_get_predefined_xlat(trnum);
1425 zstr = transl_get_predefined_menukey(trnum);
1426 z1 = transl_get_predefined_name(trnum);
1427 zs_apps(zstr, " ");
1428 zs_appz(zstr, z1);
1429 zs_apps(zstr, " : ");
1430 if (xlat) {
1431 zs_appz(zstr, transl_get_description(xlat));
1432 } else {
1433 zs_sets(zstr, _("No conversion"));
1434 }
1435 mvccuwaddstr(uiwin, row, col, zs_str(zstr));
1436 zs_free(&zstr);
1437 }
1438 /*============================
1439 * invoke_add_menu -- Handle add menu
1440 * returns addref'd record
1441 *==========================*/
1442 static RECORD
invoke_add_menu(void)1443 invoke_add_menu (void)
1444 {
1445 UIWINDOW uiwin=0;
1446 WINDOW * win=0;
1447 RECORD rec=0;
1448 INT code;
1449
1450 if (!add_menu_win) {
1451 create_newwin2(&add_menu_win, "add_menu", 8, 66);
1452 add_menu_win->outdated = TRUE; /* needs drawing */
1453 }
1454
1455 if (add_menu_win->outdated) {
1456 repaint_add_menu(add_menu_win);
1457 }
1458 uiwin = add_menu_win;
1459 win = uiw_win(uiwin);
1460
1461 activate_uiwin(uiwin);
1462 wmove(win, 1, 27);
1463 code = interact_choice_string(uiwin, "pfcsq");
1464 deactivate_uiwin_and_touch_all();
1465
1466 switch (code) {
1467 case 'p':
1468 rec = add_indi_by_edit(&disp_long_rfmt);
1469 break;
1470 case 'f': add_family_by_edit(NULL, NULL, NULL, &disp_long_rfmt); break;
1471 case 'c': my_prompt_add_child(NULL, NULL); break;
1472 case 's': prompt_add_spouse(NULL, NULL, TRUE); break;
1473 case 'q': break;
1474 }
1475 return rec;
1476 }
1477 /*===============================
1478 * invoke_del_menu -- Handle delete menu
1479 *=============================*/
1480 void
invoke_del_menu(void)1481 invoke_del_menu (void)
1482 {
1483 INT code;
1484 UIWINDOW uiwin=0;
1485 WINDOW * win=0;
1486 if (!del_menu_win) {
1487 create_newwin2(&del_menu_win, "del_menu", 9, 66);
1488 del_menu_win->outdated = TRUE; /* needs drawing */
1489 }
1490 if (del_menu_win->outdated) {
1491 repaint_delete_menu(del_menu_win);
1492 }
1493 uiwin = del_menu_win;
1494 win = uiw_win(uiwin);
1495
1496 activate_uiwin(uiwin);
1497 wmove(win, 1, 30);
1498 code = interact_choice_string(uiwin, "csifoq");
1499 deactivate_uiwin_and_touch_all();
1500
1501 switch (code) {
1502 case 'c': choose_and_remove_child(NULL, NULL, FALSE); break;
1503 case 's': choose_and_remove_spouse(NULL, NULL, FALSE); break;
1504 case 'i': choose_and_remove_indi(NULL, DOCONFIRM); break;
1505 case 'f': choose_and_remove_family(); break;
1506 case 'o': choose_and_remove_any_record(NULL, DOCONFIRM); break;
1507 case 'q': break;
1508 }
1509 }
1510 /*======================================
1511 * invoke_cset_display -- Handle character set menu
1512 *====================================*/
1513 static void
invoke_cset_display(void)1514 invoke_cset_display (void)
1515 {
1516 LIST list = create_list2(LISTDOFREE);
1517 ZSTR zstr=zs_newn(80);
1518
1519 zs_setf(zstr, "%s: %s", _("Internal codeset"), int_codeset);
1520 enqueue_list(list, strsave(zs_str(zstr)));
1521 if (uu8) {
1522 enqueue_list(list, strsave(_("Internal UTF-8: Yes")));
1523 } else {
1524 enqueue_list(list, strsave(_("Internal UTF-8: No")));
1525 }
1526
1527 if (are_locales_supported())
1528 enqueue_list(list, strsave(_("Locales are enabled.")));
1529 else
1530 enqueue_list(list, strsave(_("Locales are disabled.")));
1531
1532 if (is_nls_supported()) {
1533 enqueue_list(list, strsave(_("NLS (National Language Support) is compiled in.")));
1534 zs_setf(zstr, "LocaleDir (default): %s", LOCALEDIR);
1535 enqueue_list(list, strsave(zs_str(zstr)));
1536 zs_setf(zstr, "LocaleDir (override): %s", getlloptstr("LocaleDir", ""));
1537 enqueue_list(list, strsave(zs_str(zstr)));
1538 } else {
1539 enqueue_list(list, strsave(_("NLS (National Language Support) is not compiled in.")));
1540 }
1541
1542 if (1) {
1543 CNSTRING str = get_gettext_codeset();
1544 str = str ? str : "";
1545 zs_setf(zstr, "bind_textdomain_codeset: %s", str);
1546 enqueue_list(list, strsave(zs_str(zstr)));
1547 }
1548
1549 add_shims_info(list);
1550
1551 if (is_iconv_supported())
1552 enqueue_list(list, strsave(_("iconv (codeset conversion) is compiled in.")));
1553 else
1554 enqueue_list(list, strsave(_("iconv (codeset conversion) is not compiled in.")));
1555
1556 zs_setf(zstr, _("Startup collate locale: %s"), get_original_locale_collate());
1557 enqueue_list(list, strsave(zs_str(zstr)));
1558
1559 zs_setf(zstr, _("Startup messages locale: %s") , get_original_locale_msgs());
1560 enqueue_list(list, strsave(zs_str(zstr)));
1561
1562 zs_setf(zstr, _("Current collate locale: %s"), get_current_locale_collate());
1563 enqueue_list(list, strsave(zs_str(zstr)));
1564
1565 zs_setf(zstr, _("Current messages locale: %s"), get_current_locale_msgs());
1566 enqueue_list(list, strsave(zs_str(zstr)));
1567
1568 zs_setf(zstr, _("Collation routine: %s"), ll_what_collation());
1569 enqueue_list(list, strsave(zs_str(zstr)));
1570
1571 if (eqstr_ex(gui_codeset_in, gui_codeset_out)) {
1572 zs_setf(zstr, _("GUI codeset: %s"), gui_codeset_in);
1573 enqueue_list(list, strsave(zs_str(zstr)));
1574 } else {
1575 zs_setf(zstr, _("GUI output codeset: %s"), gui_codeset_out);
1576 enqueue_list(list, strsave(zs_str(zstr)));
1577 zs_setf(zstr, _("GUI input codeset: %s"), gui_codeset_in);
1578 enqueue_list(list, strsave(zs_str(zstr)));
1579 }
1580
1581 if (eqstr_ex(editor_codeset_in, editor_codeset_out)) {
1582 zs_setf(zstr, _("editor codeset: %s"), editor_codeset_in);
1583 enqueue_list(list, strsave(zs_str(zstr)));
1584 } else {
1585 zs_setf(zstr, _("editor output codeset: %s"), editor_codeset_out);
1586 enqueue_list(list, strsave(zs_str(zstr)));
1587 zs_setf(zstr, _("editor input codeset: %s"), editor_codeset_in);
1588 enqueue_list(list, strsave(zs_str(zstr)));
1589 }
1590
1591 if (eqstr_ex(report_codeset_in, report_codeset_out)) {
1592 zs_setf(zstr, _("report codeset: %s"), report_codeset_in);
1593 enqueue_list(list, strsave(zs_str(zstr)));
1594 } else {
1595 zs_setf(zstr, _("report output codeset: %s"), report_codeset_out);
1596 enqueue_list(list, strsave(zs_str(zstr)));
1597 zs_setf(zstr, _("report input codeset: %s"), report_codeset_in);
1598 enqueue_list(list, strsave(zs_str(zstr)));
1599 }
1600
1601 if (eqstr_ex(gedcom_codeset_in, gedcom_codeset_out)) {
1602 zs_setf(zstr, _("GEDCOM codeset: %s"), gedcom_codeset_in);
1603 enqueue_list(list, strsave(zs_str(zstr)));
1604 } else {
1605 zs_setf(zstr, _("gedcom output codeset: %s"), gedcom_codeset_out);
1606 enqueue_list(list, strsave(zs_str(zstr)));
1607 zs_setf(zstr, _("gedcom input codeset: %s"), gedcom_codeset_in);
1608 enqueue_list(list, strsave(zs_str(zstr)));
1609 }
1610
1611 zs_setf(zstr, "TTPATH: %s", getlloptstr("TTPATH", "."));
1612 enqueue_list(list, strsave(zs_str(zstr)));
1613
1614 if (charprops_is_loaded()) {
1615 enqueue_list(list, strsave(_("UTF-8 charprops loaded" )));
1616 } else {
1617 enqueue_list(list, strsave(_("UTF-8 charprops not loaded" )));
1618 }
1619
1620
1621 display_list(_("Codeset information"), list);
1622 destroy_list(list);
1623 zs_free(&zstr);
1624 }
1625 /*======================================
1626 * add_shims_info -- Add information about gettext and iconv dlls
1627 *====================================*/
1628 static void
add_shims_info(LIST list)1629 add_shims_info (LIST list)
1630 {
1631 ZSTR zstr=zs_newn(80);
1632 list=list; /* only used on MS-Windows */
1633 #ifdef WIN32_INTL_SHIM
1634 {
1635 char value[MAXPATHLEN];
1636 if (intlshim_get_property("dll_path", value, sizeof(value)))
1637 {
1638 zs_setf(zstr, _("gettext dll: %s"), value);
1639 enqueue_list(list, strsave(zs_str(zstr)));
1640 if (intlshim_get_property("dll_version", value, sizeof(value)))
1641 {
1642 zs_setf(zstr, _("gettext dll version: %s"), value);
1643 enqueue_list(list, strsave(zs_str(zstr)));
1644 }
1645 else
1646 {
1647 enqueue_list(list, strsave(_("gettext dll had no version")));
1648 }
1649 }
1650 else
1651 {
1652 enqueue_list(list, strsave(_("no gettext dll found")));
1653 }
1654 }
1655 #endif
1656 #ifdef WIN32_ICONV_SHIM
1657 {
1658 char value[MAXPATHLEN];
1659 if (iconvshim_get_property("dll_path", value, sizeof(value)))
1660 {
1661 zs_setf(zstr, _("iconv dll: %s"), value);
1662 enqueue_list(list, strsave(zs_str(zstr)));
1663 if (iconvshim_get_property("dll_version", value, sizeof(value)))
1664 {
1665 zs_setf(zstr, _("iconv dll version: %s"), value);
1666 enqueue_list(list, strsave(zs_str(zstr)));
1667 }
1668 else
1669 {
1670 enqueue_list(list, strsave(_("iconv dll had no version")));
1671 }
1672 }
1673 else
1674 {
1675 enqueue_list(list, strsave(_("no iconv dll found")));
1676 }
1677 }
1678 #endif
1679 zs_free(&zstr);
1680 }
1681 /*======================================
1682 * invoke_trans_menu -- menu for translation tables
1683 * TODO: decide whether to bring this back or not
1684 *====================================*/
1685 #ifdef UNUSED_CODE
1686 static void
invoke_trans_menu(void)1687 invoke_trans_menu (void)
1688 {
1689 INT code;
1690 UIWINDOW uiwin=0;
1691 BOOLEAN done=FALSE;
1692
1693 if (!trans_menu_win) {
1694 trans_menu_win = create_newwin2("trans_menu", 10,66);
1695 }
1696 uiwin = trans_menu_win;
1697
1698 while (!done) {
1699 stdout_vis=FALSE;
1700 repaint_trans_menu(uiwin);
1701 reactivate_uiwin(uiwin);
1702 wmove(uiw_win(uiwin), 1, strlen(_(qSmn_tt_ttl))+3);
1703 code = interact(uiwin, "elsxiq", -1);
1704
1705 begin_action();
1706 switch (code) {
1707 case 'e': edit_tt_menu(); break;
1708 case 'l': load_tt_action(); break;
1709 case 's': save_tt_action(); break;
1710 case 'x': export_tts(); break;
1711 case 'i': import_tts(); break;
1712 case 'q': done=TRUE; break;
1713 }
1714 end_action(); /* displays any errors that happened */
1715 }
1716 deactivate_uiwin_and_touch_all();
1717 }
1718 #endif
1719 /*======================================
1720 * edit_tt_menu -- menu for "Edit translation table"
1721 *====================================*/
1722 static void
edit_tt_menu(void)1723 edit_tt_menu (void)
1724 {
1725 INT ttnum;
1726 while ((ttnum = choose_tt(_(qSmn_edttttl))) != -1) {
1727 edit_mapping(ttnum);
1728 stdout_vis = FALSE; /* don't need to see errors after done */
1729 }
1730 }
1731 /*======================================
1732 * load_tt_action -- menu for "Load translation table"
1733 *====================================*/
1734 #ifdef UNUSED_CODE
1735 static void
load_tt_action(void)1736 load_tt_action (void)
1737 {
1738 FILE * fp;
1739 STRING fname=0;
1740 INT ttnum;
1741 STRING ttimportdir;
1742
1743 if (readonly) {
1744 msg_error(_(qSronlye));
1745 return;
1746 }
1747
1748 /* Ask which table */
1749 ttnum = choose_tt(_(qSmn_svttttl));
1750 if (ttnum == -1) return;
1751 if (ttnum < 0 || ttnum >= NUM_TT_MAPS) {
1752 msg_error(_(qSbadttnum));
1753 return;
1754 }
1755
1756 /* Ask whence to load it */
1757 ttimportdir = getlloptstr("TTPATH", ".");
1758 fp = ask_for_input_file(LLREADTEXT, _(qSmintt), &fname, ttimportdir, ".tt");
1759 if (fp) {
1760 fclose(fp);
1761 /* Load it */
1762 if (!load_new_tt(fname, ttnum))
1763 msg_error(_(qSdataerr));
1764 }
1765 strfree(&fname);
1766 }
1767 /*======================================
1768 * save_tt_action -- save a translation table
1769 * to a file
1770 *====================================*/
1771 static void
save_tt_action(void)1772 save_tt_action (void)
1773 {
1774 FILE * fp;
1775 STRING fname=0;
1776 INT ttnum;
1777 STRING ttexportdir;
1778
1779 /* Ask which table */
1780 ttnum = choose_tt(_(qSmn_svttttl));
1781 if (ttnum == -1) return;
1782 if (ttnum < 0 || ttnum >= NUM_TT_MAPS) {
1783 msg_error(_(qSbadttnum));
1784 return;
1785 }
1786 if (!transl_get_legacy_tt(ttnum)) {
1787 msg_error(_(qSnosuchtt));
1788 return;
1789 }
1790 /* Ask whither to save it */
1791 ttexportdir = getlloptstr("LLTTEXPORT", ".");
1792 fp = ask_for_output_file(LLWRITETEXT, _(qSmouttt), &fname, ttexportdir, ".tt");
1793 if (fp) {
1794 fclose(fp);
1795 /* Save it */
1796 if (!save_tt_to_file(ttnum, fname)) {
1797 msg_error(_(qSdataerr));
1798 strfree(&fname);
1799 return;
1800 }
1801 }
1802 strfree(&fname);
1803 }
1804 #endif
1805 /*======================================
1806 * choose_tt -- select a translation table (-1 for none)
1807 *====================================*/
1808 static INT
choose_tt(STRING prompt)1809 choose_tt (STRING prompt)
1810 {
1811 INT code;
1812 UIWINDOW uiwin = tt_menu_win;
1813 while (1) {
1814 draw_tt_win(prompt);
1815 activate_uiwin(uiwin);
1816 wmove(uiw_win(uiwin), 1, strlen(prompt)+3);
1817 code = interact_choice_string(uiwin, "emixgdrq");
1818 deactivate_uiwin_and_touch_all();
1819 switch (code) {
1820 case 'e': return MEDIN;
1821 case 'm': return MINED;
1822 case 'i': return MGDIN;
1823 case 'x': return MINGD;
1824 case 'g': return MDSIN;
1825 case 'd': return MINDS;
1826 case 'r': return MINRP;
1827 case 'q': return -1;
1828 }
1829 }
1830 }
1831 /*====================================
1832 * invoke_utils_menu -- Handle utilities menu
1833 *==================================*/
1834 static void
invoke_utils_menu(void)1835 invoke_utils_menu (void)
1836 {
1837 INT code;
1838 UIWINDOW uiwin=0;
1839 WINDOW *win=0;
1840
1841 if (!utils_menu_win) {
1842 create_newwin2(&utils_menu_win, "utils_menu", 14, 66);
1843 utils_menu_win->outdated = TRUE; /* needs drawing */
1844 }
1845 if (utils_menu_win->outdated) {
1846 repaint_utils_menu(utils_menu_win);
1847 }
1848 uiwin = utils_menu_win;
1849 win = uiw_win(uiwin);
1850 activate_uiwin(uiwin);
1851
1852 wmove(win, 1, strlen(_(qSmn_uttl))+3);
1853 code = interact_choice_string(uiwin, "srRkidmeocq");
1854 deactivate_uiwin_and_touch_all();
1855
1856 begin_action();
1857 switch (code) {
1858 case 's': save_gedcom(); break;
1859 case 'r': load_gedcom(FALSE); break;
1860 case 'R': load_gedcom(TRUE); break;
1861 case 'k': key_util(); break;
1862 case 'i': who_is_he_she(); break;
1863 case 'd': show_database_stats(); break;
1864 case 'm': display_cache_stats(); break;
1865 case 'e': edit_place_table(); break;
1866 case 'o': edit_user_options(); break;
1867 case 'c': invoke_cset_display(); break;
1868 /*
1869 we could add edit_global_config pretty easily, but the difficulty is
1870 that we don't know what to do about codeset with it :( [2002.06.18, Perry]
1871 */
1872 case 'q': break;
1873 }
1874 end_action();
1875 }
1876 /*================================
1877 * invoke_extra_menu -- Handle extra menu
1878 *==============================*/
1879 static INT
invoke_extra_menu(RECORD * prec)1880 invoke_extra_menu (RECORD *prec)
1881 {
1882 INT code;
1883 UIWINDOW uiwin=0;
1884 WINDOW *win=0;
1885
1886 if (!extra_menu_win) {
1887 create_newwin2(&extra_menu_win, "extra_menu", 13,66);
1888 extra_menu_win->outdated = TRUE; /* needs drawing */
1889 }
1890 if (extra_menu_win->outdated) {
1891 repaint_extra_menu(extra_menu_win);
1892 }
1893 uiwin = extra_menu_win;
1894 win = uiw_win(uiwin);
1895
1896 while (1) {
1897
1898 activate_uiwin(uiwin);
1899 wmove(win, 1, strlen(_(qSmn_xttl))+3);
1900 code = interact_choice_string(uiwin, "sex123456q");
1901 deactivate_uiwin_and_touch_all();
1902
1903 switch (code) {
1904 case 's': return BROWSE_SOUR;
1905 case 'e': return BROWSE_EVEN;
1906 case 'x': return BROWSE_AUX;
1907 case '1': *prec = edit_add_source(); return BROWSE_SOUR;
1908 case '2': edit_source(NULL, &disp_long_rfmt); return BROWSE_QUIT;
1909 case '3': *prec = edit_add_event(); return BROWSE_EVEN;
1910 case '4': edit_event(NULL, &disp_long_rfmt); return BROWSE_QUIT;
1911 case '5': *prec = edit_add_other(); return BROWSE_AUX;
1912 case '6': edit_other(NULL, &disp_long_rfmt); return BROWSE_QUIT;
1913 case 'q': return BROWSE_QUIT;
1914 }
1915 }
1916 }
1917 /*===============================
1918 * uopt_validate -- Validator when user edits 'user options table'
1919 * returns descriptive string for failure, 0 for pass
1920 *=============================*/
1921 static STRING
uopt_validate(TABLE tab,void * param)1922 uopt_validate (TABLE tab, void * param)
1923 {
1924 STRING codeset = valueof_str(tab, "codeset");
1925 STRING original_codeset = (STRING)param;
1926 /*
1927 our only rule currently is that user may not change codeset
1928 of a populated database
1929 */
1930 if (!eqstr_ex(codeset, original_codeset)
1931 && !eqstr_ex(codeset, int_codeset)) {
1932 if (num_indis()+num_fams()+num_sours()+num_evens()+num_othrs())
1933 return _("Impermissible to change codeset in a populated database");
1934 }
1935 return 0;
1936 }
1937 /*===============================
1938 * edit_place_table -- Allow user to edit the table of place abbreviations
1939 *=============================*/
1940 static void
edit_place_table(void)1941 edit_place_table (void)
1942 {
1943 edit_valtab_from_db("VPLAC", &placabbvs, ':', _(qSabverr), 0, 0);
1944 }
1945 /*===============================
1946 * edit_user_options -- Allow user to edit options embedded in current db
1947 *=============================*/
1948 static void
edit_user_options(void)1949 edit_user_options (void)
1950 {
1951 TABLE uopts = create_table_str();
1952 STRING param=0;
1953 get_db_options(uopts);
1954 param = valueof_str(uopts, "codeset");
1955 param = (param ? strsave(param) : 0);
1956
1957 if (edit_valtab_from_db("VUOPT", &uopts, '=', _(qSuoperr), uopt_validate, (void *)param))
1958 set_db_options(uopts);
1959 strfree(¶m);
1960 release_table(uopts);
1961 }
1962 /*============================================
1963 * get_answer -- Have user respond with string
1964 * uiwin: [IN] which window to use
1965 * row: [IN] prompt location (vert)
1966 * col: [IN] prompt location (horiz)
1967 * buffer: [OUT] response
1968 * buflen: [IN] max size of response
1969 * Has not been codeset-converted to internal yet
1970 *==========================================*/
1971 BOOLEAN
get_answer(UIWINDOW uiwin,INT row,INT col,STRING buffer,INT buflen)1972 get_answer (UIWINDOW uiwin, INT row, INT col, STRING buffer, INT buflen)
1973 {
1974 WINDOW *win = uiw_win(uiwin);
1975 BOOLEAN rtn = FALSE;
1976
1977 /* TODO: Is this necessary ? It prevents entering long paths */
1978 if (buflen > uiw_cols(uiwin)-col-1)
1979 buflen = uiw_cols(uiwin)-col-1;
1980
1981 echo();
1982 wmove(win, row, col);
1983 if (wgetccnstr(win, buffer, buflen) != ERR)
1984 rtn = TRUE;
1985 noecho();
1986 buffer[buflen-1] = 0; /* ensure zero-termination */
1987
1988 return rtn;
1989 }
1990 /*================================================================
1991 * show_record -- Display record (any type) in requested mode
1992 * uiwin: [IN] whither to draw
1993 * key: [IN] key of record to display
1994 * mode: [IN] what display mode (eg, vitals vs GEDCOM vs...)
1995 * rect: [IN] where to draw
1996 * scroll: [I/O] current scroll setting
1997 * reuse: [IN] flag indicating if same record drawn last time
1998 * returns TRUE if record was found, else FALSE (no record, nothing drawn)
1999 *==============================================================*/
2000 BOOLEAN
show_record(UIWINDOW uiwin,STRING key,INT mode,LLRECT rect,INT * scroll,BOOLEAN reuse)2001 show_record (UIWINDOW uiwin, STRING key, INT mode, LLRECT rect
2002 , INT * scroll, BOOLEAN reuse)
2003 {
2004 INT row = rect->top;
2005 INT hgt = rect->bottom - rect->top + 1;
2006 INT width = rect->right - rect->left + 1;
2007 if (key[0]=='I') {
2008 RECORD irec = key_to_irecord(key);
2009 if (irec)
2010 show_indi(uiwin, irec, mode, rect, scroll, reuse);
2011 return irec != NULL;
2012 } else if (key[0]=='F') {
2013 RECORD frec = key_to_frecord(key);
2014 if (frec)
2015 show_fam(uiwin, frec, mode, row, hgt, width, scroll, reuse);
2016 return frec != NULL;
2017
2018 } else {
2019 /* could be S,E,X -- show_aux handles all of these */
2020 RECORD rec = qkey_to_record(key);
2021 if (rec)
2022 show_aux(uiwin, rec, mode, rect, scroll, reuse);
2023 return rec != NULL;
2024 }
2025 }
2026 /*===================================================
2027 * message_string -- Return background message string
2028 *=================================================*/
2029 STRING
message_string(void)2030 message_string (void)
2031 {
2032 if (!cur_screen) return "";
2033 if (cur_screen == MAIN_SCREEN)
2034 return _("LifeLines -- Main Menu");
2035 ASSERT(cur_screen >= 1);
2036 ASSERT(cur_screen <= MAX_SCREEN);
2037 return get_screen_title(cur_screen);
2038 }
2039 /*=================================================
2040 * place_std_msg - Place standard message on screen
2041 *===============================================*/
2042 void
place_std_msg(void)2043 place_std_msg (void)
2044 {
2045 /* msg is placed on main window */
2046 UIWINDOW uiwin = main_win;
2047 WINDOW *win = uiw_win(uiwin);
2048 STRING str = message_string();
2049 INT row = ll_lines-2;
2050 clear_hseg(win, row, 2, ll_cols-2);
2051 mvccwaddstr(win, row, 2, str);
2052 /* now we need to repaint main window, but if there are
2053 subwindows up, instead we call the touch_all routine,
2054 which does them all from ancestor to descendant */
2055 if (active_uiwin)
2056 touch_all(TRUE);
2057 else
2058 wrefresh(win);
2059 place_cursor_main();
2060 }
2061 /*==================================+
2062 * rpt_print -- Implement report language print function
2063 * Created: 2003-02-01 (Perry Rapp)
2064 *=================================*/
2065 void
rpt_print(STRING str)2066 rpt_print (STRING str)
2067 {
2068 llwprintf(str);
2069 }
2070 /*=================================================
2071 * llvwprintf -- Called as wprintf(fmt, argp)
2072 *===============================================*/
2073 void
llvwprintf(STRING fmt,va_list args)2074 llvwprintf (STRING fmt, va_list args)
2075 {
2076 UIWINDOW uiwin = stdout_win;
2077 if (uiwin) {
2078 WINDOW *win = uiw_win(uiwin);
2079 if (!stdout_vis) {
2080 clearw();
2081 activate_uiwin(uiwin);
2082 }
2083 vccwprintw(win, fmt, args);
2084 wrefresh(win);
2085 } else {
2086 vccprintf(fmt, args);
2087 }
2088 /*
2089 TO DO
2090 It would be nice to add this to the msg list
2091 but we need to deal with embedded carriage returns first
2092 so we can't do this yet. Also, if we do put it on the msg list,
2093 it is going to duplicate the stdout display currently being
2094 used (which is nicer looking, but scrolls off-screen).
2095 */
2096 /* msg_outputv(MSG_ERROR, fmt, args);*/ /* also send to msg list */
2097 }
2098 /*=================================================
2099 * llwprintf -- Called as wprintf(fmt, arg, arg, ...)
2100 *===============================================*/
2101 void
llwprintf(STRING fmt,...)2102 llwprintf (STRING fmt, ...)
2103 {
2104 va_list args;
2105 va_start(args, fmt);
2106 llvwprintf(fmt, args);
2107 va_end(args);
2108 }
2109 /*==============================
2110 * clearw -- Clear stdout window
2111 *============================*/
2112 void
clearw(void)2113 clearw (void)
2114 {
2115 UIWINDOW uiwin = stdout_win;
2116 WINDOW *win = uiw_win(uiwin);
2117 WINDOW *boxwin = uiw_boxwin(uiwin);
2118 uierase(uiwin);
2119 draw_win_box(boxwin);
2120 wmove(win, 0, 0);
2121 stdout_vis = TRUE;
2122 wrefresh(boxwin);
2123 }
2124 /*=======================================
2125 * wfield -- Write field in stdout window
2126 *=====================================*/
2127 void
wfield(INT row,INT col,STRING str)2128 wfield (INT row, INT col, STRING str)
2129 {
2130 UIWINDOW uiwin = stdout_win;
2131 WINDOW *win = uiw_win(uiwin);
2132 if (!stdout_vis) clearw();
2133 mvccwaddstr(win, row, col, str);
2134 wrefresh(win);
2135 }
2136 /*===========================================
2137 * wpos -- Position to place in stdout window
2138 *=========================================*/
2139 void
wpos(INT row,INT col)2140 wpos (INT row, INT col)
2141 {
2142 UIWINDOW uiwin = stdout_win;
2143 WINDOW *win = uiw_win(uiwin);
2144 wmove(win, row, col);
2145 }
2146 /*=======================================
2147 * show_horz_line -- Draw horizontal line
2148 *=====================================*/
2149 void
show_horz_line(UIWINDOW uiwin,INT row,INT col,INT len)2150 show_horz_line (UIWINDOW uiwin, INT row, INT col, INT len)
2151 {
2152 WINDOW *win = uiw_win(uiwin);
2153 INT i;
2154 mvwaddch(win, row, col, gr_ltee);
2155 for (i = 0; i < len-2; i++)
2156 waddch(win, gr_hline);
2157 waddch(win, gr_rtee);
2158 }
2159 /*=====================================
2160 * show_vert_line -- Draw vertical line
2161 *===================================*/
2162 void
show_vert_line(UIWINDOW uiwin,INT row,INT col,INT len)2163 show_vert_line (UIWINDOW uiwin, INT row, INT col, INT len)
2164 {
2165 WINDOW *win = uiw_win(uiwin);
2166 INT i;
2167 mvwaddch(win, row++, col, gr_ttee);
2168 for (i = 0; i < len-2; i++)
2169 mvwaddch(win, row++, col, gr_vline);
2170 mvwaddch(win, row, col, gr_btee);
2171 }
2172 /*=============================================
2173 * place_cursor_popup -- Move to cursor input location
2174 * For use with UIWINDOW menus -- popup menus which live
2175 * in their own private UIWINDOW (& curses) window,
2176 * such as the full scan popup
2177 *===========================================*/
2178 void
place_cursor_popup(UIWINDOW uiwin)2179 place_cursor_popup (UIWINDOW uiwin)
2180 {
2181 wmove(uiw_win(uiwin), uiw_cury(uiwin), uiw_curx(uiwin));
2182 }
2183 /*=============================================
2184 * place_cursor_main -- Move to idle cursor location
2185 * for use with main menu screens
2186 *===========================================*/
2187 static void
place_cursor_main(void)2188 place_cursor_main (void)
2189 {
2190 INT row=0, col = 30;
2191 DYNMENU dynmenu = get_screen_dynmenu(cur_screen);
2192
2193 /* Hide/Display Cursor */
2194 if (dynmenu && dynmenu->hidden) {
2195 curs_set(0);
2196 } else {
2197 curs_set(1);
2198 }
2199
2200 /* Position Cursor */
2201 switch (cur_screen) {
2202 case MAIN_SCREEN:
2203 row = 5;
2204 col = strlen(_(qSplschs))+3;
2205 break;
2206 case LIST_SCREEN:
2207 listui_placecursor_main(&row, &col);
2208 break;
2209 case ONE_PER_SCREEN:
2210 case ONE_FAM_SCREEN:
2211 case AUX_SCREEN:
2212 case TWO_PER_SCREEN:
2213 case TWO_FAM_SCREEN:
2214 {
2215 /* These screens, which live on the main screen uiwindow,
2216 all use dynamic menus, and the cursor position in dynamic
2217 menus is controlled by the dynamic menu, because cursor
2218 moves up & down with dynamic menu */
2219 if (dynmenu->hidden) {
2220 /* no need to position cursor */
2221 } else {
2222 row = dynmenu->cur_y;
2223 col = dynmenu->cur_x;
2224 }
2225 }
2226 break;
2227 default:
2228 row = 1;
2229 col = 1;
2230 break;
2231 }
2232 wmove(uiw_win(main_win), row, col);
2233 }
2234 /*=============================================
2235 * dbprintf -- Debug printf(fmt, arg, arg, ...)
2236 *===========================================*/
2237 void
dbprintf(STRING fmt,...)2238 dbprintf (STRING fmt, ...)
2239 {
2240 va_list args;
2241 touchwin(uiw_win(debug_box_win));
2242 va_start(args, fmt);
2243 vccwprintw(uiw_win(debug_win), fmt, args);
2244 va_end(args);
2245 wrefresh(uiw_win(debug_box_win));
2246 sleep(2);
2247 touchwin(uiw_win(main_win));
2248 wrefresh(uiw_win(main_win));
2249 }
2250 /*==================================================
2251 * do_edit -- Shift to user's screen editor and back
2252 *================================================*/
2253 void
do_edit(void)2254 do_edit (void)
2255 {
2256 endwin();
2257 #ifdef WIN32
2258 /* use w32system, because it will wait for the editor to finish */
2259 w32system(editstr);
2260 #else
2261 system(editstr);
2262 #endif
2263 clearok(curscr, 1);
2264 place_cursor_main();
2265 wrefresh(curscr);
2266 noecho();
2267 }
2268 /*================================================
2269 * mvwaddstr_lim -- output a string, like mvwaddstr
2270 * except trim it to no more than maxlen wide
2271 *==============================================*/
2272 static void
mvwaddstr_lim(WINDOW * wp,int x,int y,char * cp,INT maxlen)2273 mvwaddstr_lim (WINDOW *wp, int x, int y, char *cp, INT maxlen)
2274 {
2275 char buffer[60];
2276 if ((INT)strlen(cp)<=maxlen)
2277 mvccwaddstr(wp, x, y, cp);
2278 else {
2279 if (maxlen > (INT)sizeof(buffer)-1)
2280 maxlen = sizeof(buffer)-1;
2281 llstrncpy(buffer, cp, maxlen-1, uu8);
2282 strcat(buffer, "*");
2283 mvccwaddstr(wp, x, y, buffer);
2284 }
2285 }
2286 /*================================================
2287 * check_menu -- update menu layout info
2288 * (in case just resized)
2289 * Created: 2002/10/24 (Perry Rapp)
2290 *==============================================*/
2291 static void
check_menu(DYNMENU dynmenu)2292 check_menu (DYNMENU dynmenu)
2293 {
2294 /* (reserve spots for ? and q on each page) */
2295 dynmenu->pageitems = dynmenu->rows*dynmenu->cols-2;
2296 dynmenu->pages = (dynmenu->size-1)/dynmenu->pageitems+1;
2297 if (dynmenu->size < dynmenu->pageitems + 1) { /* don't need ? if they fit */
2298 dynmenu->pages = 1;
2299 dynmenu->page = 0;
2300 }
2301 }
2302 /*================================================
2303 * output_menu -- print menu array to screen
2304 * Caller specifies bottom row to use, & width
2305 * Menu structure contains all menu items & # of
2306 * columns to use
2307 *==============================================*/
2308 static void
output_menu(UIWINDOW uiwin,DYNMENU dynmenu)2309 output_menu (UIWINDOW uiwin, DYNMENU dynmenu)
2310 {
2311 WINDOW *win = uiw_win(uiwin);
2312 INT row;
2313 INT icol=0;
2314 INT col=3;
2315 /* more legible names */
2316 INT MenuSize = dynmenu->size;
2317 INT MenuCols = dynmenu->cols;
2318 INT MenuPage = dynmenu->page;
2319 INT MenuPages = dynmenu->pages;
2320 INT pageitems = dynmenu->pageitems;
2321 MENUSET menuset = dynmenu_get_menuset(dynmenu);
2322 MenuItem ** items = menuset_get_items(menuset);
2323 INT width = dynmenu->width;
2324 /* reserve 2 spaces at each end, and one space in front of each Col */
2325 INT colwidth = (width-4)/MenuCols-1;
2326 INT Item = 0;
2327 Item = MenuPage * pageitems;
2328 if (Item >= MenuSize)
2329 Item = ((MenuSize-1)/pageitems)*pageitems;
2330 icol = 0;
2331 col = 3;
2332 row = dynmenu->top;
2333 /* now display all the menu items we can fit on this page */
2334 while (1)
2335 {
2336 mvwaddstr_lim(win, row, col, items[Item++]->LocalizedDisplay, colwidth);
2337 if (Item == MenuSize)
2338 break;
2339 row++;
2340 if (icol<MenuCols-1 && row>dynmenu->bottom)
2341 {
2342 icol++;
2343 col += colwidth+1;
2344 row = dynmenu->top;
2345 continue;
2346 }
2347 if (MenuPages == 1) {
2348 /* one slot reserved for "q" */
2349 if (icol==MenuCols-1 && row==dynmenu->bottom)
2350 break;
2351 } else {
2352 /* two slots reserved, "q" & "?" */
2353 if (icol==MenuCols-1 && row==dynmenu->bottom-1)
2354 break;
2355 }
2356 }
2357 /* print the "q" and "?" items */
2358 row = dynmenu->bottom-1;
2359 col = 3+(MenuCols-1)*(colwidth+1);
2360 if (dynmenu->pages > 1)
2361 mvwaddstr_lim(win, row, col, g_MenuItemOther.LocalizedDisplay, colwidth);
2362 mvwaddstr_lim(win, ++row, col, g_MenuItemQuit.LocalizedDisplay, colwidth);
2363 }
2364 /*==================================================================
2365 * toggle_browse_menu - toggle display of menu at bottom of screen
2366 *================================================================*/
2367 void
toggle_browse_menu(void)2368 toggle_browse_menu (void)
2369 {
2370 dynmenu_toggle_menu(get_screen_dynmenu(cur_screen));
2371 }
2372 /*==================================================================
2373 * cycle_browse_menu() - show other menu choices on browse menu
2374 *================================================================*/
2375 void
cycle_browse_menu(void)2376 cycle_browse_menu (void)
2377 {
2378 dynmenu_next_page(get_screen_dynmenu(cur_screen));
2379 }
2380 /*==================================================================
2381 * adjust_browse_menu_height - Change height of current browse screen menu
2382 *================================================================*/
2383 void
adjust_browse_menu_height(INT delta)2384 adjust_browse_menu_height (INT delta)
2385 {
2386 dynmenu_adjust_height(get_screen_dynmenu(cur_screen), delta);
2387 }
2388 /*==================================================================
2389 * adjust_browse_menu_cols - Change # of columns in current menu
2390 *================================================================*/
2391 void
adjust_browse_menu_cols(INT delta)2392 adjust_browse_menu_cols (INT delta)
2393 {
2394 dynmenu_adjust_menu_cols(get_screen_dynmenu(cur_screen), delta);
2395 }
2396 /*=========================================
2397 * get_brwsmenu_size -- How many lines does browse menu take ?
2398 *=======================================*/
2399 static INT
get_brwsmenu_size(INT screen)2400 get_brwsmenu_size (INT screen)
2401 {
2402 DYNMENU dynmenu = get_screen_dynmenu(screen);
2403 return dynmenu->hidden ? EMPTY_MENU : dynmenu->rows+1;
2404 }
2405 /*=====================
2406 * clear_stdout_hseg -- clear a horizontal line segment on stdout win
2407 *====================*/
2408 void
clear_stdout_hseg(INT row,INT x1,INT x2)2409 clear_stdout_hseg (INT row, INT x1, INT x2)
2410 {
2411 UIWINDOW uiwin = stdout_win;
2412 WINDOW *win = uiw_win(uiwin);
2413 clear_hseg(win, row, x1, x2);
2414 }
2415 /*=====================
2416 * clear_hseg -- clear a horizontal line segment
2417 * (used for partial screen clears)
2418 *====================*/
2419 void
clear_hseg(WINDOW * win,INT row,INT x1,INT x2)2420 clear_hseg (WINDOW *win, INT row, INT x1, INT x2)
2421 {
2422 /* workaround for curses bug with spacs */
2423 if (getlloptint("ForceScreenErase", 0) > 0) {
2424 /* fill virtual output with dots */
2425 color_hseg(win, row, x1, x2, '_');
2426 wnoutrefresh(win);
2427 /* now fill it back with spaces */
2428 color_hseg(win, row, x1, x2, ' ');
2429 wrefresh(win);
2430 } else {
2431 color_hseg(win, row, x1, x2, ' ');
2432 }
2433 }
2434 /*=====================
2435 * color_hseg -- fill a horizontal line segment
2436 * (used for clearing)
2437 *====================*/
2438 static void
color_hseg(WINDOW * win,INT row,INT x1,INT x2,char ch)2439 color_hseg (WINDOW *win, INT row, INT x1, INT x2, char ch)
2440 {
2441 INT i;
2442 for (i=x1; i<=x2; ++i)
2443 mvwaddch(win, row, i, ch);
2444 }
2445 /*===============================================
2446 * display_status -- put string in status line
2447 * We don't touch the status_transitory flag
2448 * That is caller's responsibility.
2449 *=============================================*/
2450 static void
display_status(STRING text)2451 display_status (STRING text)
2452 {
2453 UIWINDOW uiwin = main_win;
2454 WINDOW *win = uiw_win(uiwin);
2455 INT row;
2456 /* first store it */
2457 llstrncpy(status_showing, text, sizeof(status_showing), uu8);
2458 if ((INT)strlen(text)>ll_cols-6) {
2459 status_showing[ll_cols-8] = 0;
2460 strcat(status_showing, "...");
2461 }
2462 /* then display it */
2463 row = ll_lines-2;
2464 clear_hseg(win, row, 2, ll_cols-2);
2465 wmove(win, row, 2);
2466 mvccwaddstr(win, row, 2, status_showing);
2467 place_cursor_main();
2468 wrefresh(win);
2469 }
2470 /*=========================================
2471 * msg_error -- handle error message
2472 * delegates to msg_outputv
2473 *=======================================*/
2474 void
msg_error(STRING fmt,...)2475 msg_error (STRING fmt, ...)
2476 {
2477 va_list args;
2478 va_start(args, fmt);
2479 msg_outputv(MSG_ERROR, fmt, args);
2480 va_end(args);
2481 }
2482 /*=========================================
2483 * msg_info -- handle regular messages
2484 * delegates to msg_outputv
2485 *=======================================*/
2486 void
msg_info(STRING fmt,...)2487 msg_info (STRING fmt, ...)
2488 {
2489 va_list args;
2490 va_start(args, fmt);
2491 msg_outputv(MSG_INFO, fmt, args);
2492 va_end(args);
2493 }
2494 /*=========================================
2495 * msg_status -- handle transitory/status messages
2496 * delegates to msg_outputv
2497 *=======================================*/
2498 void
msg_status(STRING fmt,...)2499 msg_status (STRING fmt, ...)
2500 {
2501 va_list args;
2502 va_start(args, fmt);
2503 msg_outputv(MSG_STATUS, fmt, args);
2504 va_end(args);
2505 }
2506 /*=========================================
2507 * msg_output -- handle any message
2508 * delegates to msg_outputv
2509 *=======================================*/
2510 void
msg_output(MSG_LEVEL level,STRING fmt,...)2511 msg_output (MSG_LEVEL level, STRING fmt, ...)
2512 {
2513 va_list args;
2514 va_start(args, fmt);
2515 msg_outputv(level, fmt, args);
2516 va_end(args);
2517 }
2518 /*=====================================
2519 * msg_width -- get max width of msgs
2520 *===================================*/
2521 INT
msg_width(void)2522 msg_width (void)
2523 {
2524 return ll_cols-6;
2525 }
2526 /*=========================================
2527 * msg_outputv -- output message varargs style arguments
2528 * Actually all other msg functions delegate to here.
2529 * @level: -1=error,0=info,1=status
2530 * @fmt: [IN] printf style format string
2531 * @args: [IN] vprintf style varargs
2532 * Puts into message list and/or into status area
2533 *=======================================*/
2534 void
msg_outputv(MSG_LEVEL level,STRING fmt,va_list args)2535 msg_outputv (MSG_LEVEL level, STRING fmt, va_list args)
2536 {
2537 char buffer[250];
2538 STRING ptr;
2539 unsigned int width = MAINWIN_WIDTH-5;
2540 /* prefix errors & infos with * and space respectively */
2541 switch(level) {
2542 case MSG_ERROR:
2543 buffer[0] = '*';
2544 ptr = &buffer[1];
2545 break;
2546 case MSG_INFO:
2547 buffer[0] = ' ';
2548 ptr = &buffer[1];
2549 break;
2550 default:
2551 ptr = buffer;
2552 break;
2553 }
2554 /* now make string to show/put on msg list */
2555 llstrncpyvf(ptr, sizeof(buffer)-1, uu8, fmt, args);
2556 /* first handle transitory/status messages */
2557 if (level==MSG_STATUS) {
2558 if (lock_std_msg)
2559 return; /* can't display it, status bar is locked */
2560 if (status_showing[0] && !status_transitory) {
2561 /* we are overwriting something important
2562 so it is already on the msg list, we just need to make
2563 sure the msg list gets displayed */
2564 if (!viewing_msgs)
2565 msg_flag = TRUE;
2566 }
2567 display_status(buffer);
2568 return;
2569 }
2570 /* everything important goes onto msg list */
2571 append_to_msg_list(buffer);
2572 /* update flag about whether we need to show msg list to user */
2573 /* being careful in case we are currently *in* the msg list
2574 show routine */
2575 if (!viewing_msgs && (length_list(msg_list)>1 || lock_std_msg)) {
2576 msg_flag = TRUE;
2577 }
2578 /* now put it to status area if appropriate */
2579 if (!lock_std_msg) {
2580 if (strlen(buffer)>width) {
2581 buffer[width-4]=0;
2582 strcat(buffer, "...");
2583 /*
2584 TODO: This doesn't make sense until the msg list handles long strings
2585 if (!viewing_msgs)
2586 msg_flag = TRUE;
2587 */
2588 }
2589 display_status(buffer);
2590 }
2591 }
2592 /*=========================================
2593 * msg_impl -- put msg on the msg list
2594 * This is a list that we show the user
2595 * when the current command completes,
2596 * unless it only had one item, and it got
2597 * put on the status bar, and it wasn't too wide.
2598 *=======================================*/
2599 static void
append_to_msg_list(STRING msg)2600 append_to_msg_list (STRING msg)
2601 {
2602 if (!msg_list)
2603 msg_list = create_list2(LISTDOFREE);
2604 enqueue_list(msg_list, strsave(msg));
2605 }
2606 /*=========================================
2607 * begin_action -- prepare to process users choice
2608 *=======================================*/
2609 static
begin_action(void)2610 void begin_action (void)
2611 {
2612 clear_msgs();
2613 }
2614 /*=========================================
2615 * end_action -- finished processing users choice
2616 * show msg list if appropriate
2617 *=======================================*/
2618 static
end_action(void)2619 void end_action (void)
2620 {
2621 /* pause for keypress for finish stdout/err if appropriate */
2622 check_stdout();
2623 /* put up list of errors if appropriate */
2624 if (msg_flag && msg_list) {
2625 STRING * strngs = (STRING *)stdalloc(length_list(msg_list)*sizeof(STRING));
2626 INT i=0;
2627 FORLIST(msg_list, el)
2628 strngs[i++] = el;
2629 ENDLIST
2630 viewing_msgs = TRUE; /* suppress msg generation */
2631 view_array(_(qSerrlist), length_list(msg_list), strngs);
2632 viewing_msgs = FALSE;
2633 stdfree(strngs);
2634 clear_msgs();
2635 }
2636 }
2637 /*=========================================
2638 * clear_msgs -- delete msg list
2639 * The msg list holds messages when several
2640 * occurred during the last operation
2641 *=======================================*/
2642 static void
clear_msgs(void)2643 clear_msgs (void)
2644 {
2645 if (msg_list) {
2646 destroy_list(msg_list);
2647 msg_list = 0;
2648 }
2649 msg_flag = FALSE;
2650 /* also clear status bar */
2651 clear_status();
2652 }
2653 /*=========================================
2654 * clear_status -- clear status string
2655 * The status string is the last message displayed
2656 * and is shown at the very bottom of the main screen
2657 *=======================================*/
2658 static void
clear_status(void)2659 clear_status (void)
2660 {
2661 if (!lock_std_msg)
2662 status_showing[0]=0;
2663 }
2664 /*=========================================
2665 * lock_status_msg -- temporarily hold status message
2666 *=======================================*/
2667 void
lock_status_msg(BOOLEAN lock)2668 lock_status_msg (BOOLEAN lock)
2669 {
2670 lock_std_msg = lock;
2671 }
2672 /*=====================================
2673 * repaint_add_menu -- Draw menu choices for main add item menu
2674 *===================================*/
2675 static void
repaint_add_menu(UIWINDOW uiwin)2676 repaint_add_menu (UIWINDOW uiwin)
2677 {
2678 WINDOW *win = uiw_win(uiwin);
2679 INT row = 1;
2680 uierase(uiwin);
2681 draw_win_box(win);
2682 mvccwaddstr(win, row++, 2, _(qSmn_add_ttl));
2683 mvccwaddstr(win, row++, 4, _(qSmn_add_indi));
2684 mvccwaddstr(win, row++, 4, _(qSmn_add_fam));
2685 mvccwaddstr(win, row++, 4, _(qSmn_add_chil));
2686 mvccwaddstr(win, row++, 4, _(qSmn_add_spou));
2687 mvccwaddstr(win, row++, 4, _(qSmn_ret));
2688 uiwin->outdated = FALSE;
2689 }
2690 /*=====================================
2691 * repaint_delete_menu -- Draw menu choices for main delete item menu
2692 *===================================*/
2693 static void
repaint_delete_menu(UIWINDOW uiwin)2694 repaint_delete_menu (UIWINDOW uiwin)
2695 {
2696 WINDOW *win = uiw_win(uiwin);
2697 INT row = 1;
2698 uierase(uiwin);
2699 draw_win_box(win);
2700 mvccwaddstr(win, row++, 2, _(qSmn_del_ttl));
2701 mvccwaddstr(win, row++, 4, _(qSmn_del_chil));
2702 mvccwaddstr(win, row++, 4, _(qSmn_del_spou));
2703 mvccwaddstr(win, row++, 4, _(qSmn_del_indi));
2704 mvccwaddstr(win, row++, 4, _(qSmn_del_fam));
2705 mvccwaddstr(win, row++, 4, _(qSmn_del_any));
2706 mvccwaddstr(win, row++, 4, _(qSmn_ret));
2707 uiwin->outdated = FALSE;
2708 }
2709 /*=====================================
2710 * repaint_utils_menu --
2711 *===================================*/
2712 static void
repaint_utils_menu(UIWINDOW uiwin)2713 repaint_utils_menu (UIWINDOW uiwin)
2714 {
2715 WINDOW *win = uiw_win(uiwin);
2716 INT row = 1;
2717 uierase(uiwin);
2718 draw_win_box(win);
2719 mvccwaddstr(win, row++, 2, _(qSmn_uttl));
2720 mvccwaddstr(win, row++, 4, _(qSmn_utsave));
2721 mvccwaddstr(win, row++, 4, _(qSmn_utread));
2722 mvccwaddstr(win, row++, 4, _(qSmn_utgdchoo));
2723 mvccwaddstr(win, row++, 4, _(qSmn_utkey));
2724 mvccwaddstr(win, row++, 4, _(qSmn_utkpers));
2725 mvccwaddstr(win, row++, 4, _(qSmn_utdbstat));
2726 mvccwaddstr(win, row++, 4, _(qSmn_utmemsta));
2727 mvccwaddstr(win, row++, 4, _(qSmn_utplaces));
2728 mvccwaddstr(win, row++, 4, _(qSmn_utusropt));
2729 mvccwaddstr(win, row++, 4, _(qSmn_mmcset));
2730 mvccwaddstr(win, row++, 4, _(qSmn_quit));
2731 uiwin->outdated = FALSE;
2732 }
2733 /*=====================================
2734 * repaint_extra_menu --
2735 *===================================*/
2736 static void
repaint_extra_menu(UIWINDOW uiwin)2737 repaint_extra_menu (UIWINDOW uiwin)
2738 {
2739 WINDOW *win = uiw_win(uiwin);
2740 INT row = 1;
2741 uierase(uiwin);
2742 draw_win_box(win);
2743 mvccwaddstr(win, row++, 2, _(qSmn_xttl));
2744 mvccwaddstr(win, row++, 4, _(qSmn_xxbsour));
2745 mvccwaddstr(win, row++, 4, _(qSmn_xxbeven));
2746 mvccwaddstr(win, row++, 4, _(qSmn_xxbothr));
2747 mvccwaddstr(win, row++, 4, _(qSmn_xxasour));
2748 mvccwaddstr(win, row++, 4, _(qSmn_xxesour));
2749 mvccwaddstr(win, row++, 4, _(qSmn_xxaeven));
2750 mvccwaddstr(win, row++, 4, _(qSmn_xxeeven));
2751 mvccwaddstr(win, row++, 4, _(qSmn_xxaothr));
2752 mvccwaddstr(win, row++, 4, _(qSmn_xxeothr));
2753 mvccwaddstr(win, row++, 4, _(qSmn_quit));
2754 uiwin->outdated = FALSE;
2755 }
2756 /*============================
2757 * activate_uiwin --
2758 * push new uiwindow on top of current one
2759 *==========================*/
2760 void
activate_uiwin(UIWINDOW uiwin)2761 activate_uiwin (UIWINDOW uiwin)
2762 {
2763 WINDOW * win = uiw_win(uiwin);
2764 ASSERT(uiwin);
2765 ASSERT(win);
2766 ASSERT(!uiw_parent(uiwin));
2767
2768 /* link into parent/child chain */
2769 uiw_parent(uiwin) = active_uiwin;
2770 if (active_uiwin) {
2771 ASSERT(!uiw_child(active_uiwin));
2772 uiw_child(active_uiwin) = uiwin;
2773 /* refresh current (in case it was obscured by stdout */
2774 wrefresh(uiw_win(active_uiwin));
2775 }
2776
2777 /* switch to new & refresh */
2778 active_uiwin = uiwin;
2779 touchwin(win);
2780 wrefresh(win);
2781 }
2782 /*============================
2783 * reactivate_uiwin --
2784 * push new window on top, if not already on top
2785 * and refresh it in any case
2786 *==========================*/
2787 #ifdef UNUSED_CODE
2788 static void
reactivate_uiwin(UIWINDOW uiwin)2789 reactivate_uiwin (UIWINDOW uiwin)
2790 {
2791 if (active_uiwin != uiwin)
2792 activate_uiwin(uiwin);
2793 else {
2794 WINDOW * win = uiw_win(uiwin);
2795 touchwin(win);
2796 wrefresh(win);
2797 }
2798 }
2799 #endif
2800 /*============================
2801 * deactivate_uiwin -- Remove currently active
2802 * and pop to its parent (if it has one)
2803 *==========================*/
2804 static void
deactivate_uiwin(void)2805 deactivate_uiwin (void)
2806 {
2807 UIWINDOW uiw = active_uiwin;
2808 active_uiwin = uiw_parent(active_uiwin);
2809 if (active_uiwin) {
2810 ASSERT(uiw_child(active_uiwin)==uiw);
2811 }
2812 uiw_parent(uiw)=0;
2813 if (uiw_dynamic(uiw))
2814 delete_uiwindow(&uiw);
2815 if (active_uiwin && uiw_child(active_uiwin)) {
2816 uiw_child(active_uiwin)=0;
2817 }
2818 }
2819 /*=============================================
2820 * deactivate_uiwin_and_touch_all --
2821 * remove current window & repaint ones left
2822 *===========================================*/
2823 void
deactivate_uiwin_and_touch_all(void)2824 deactivate_uiwin_and_touch_all (void)
2825 {
2826 deactivate_uiwin();
2827 if (active_uiwin)
2828 touch_all(TRUE);
2829 }
2830 /*============================
2831 * touch_all -- Repaint all ancestors of current window
2832 * from furthest to nearest
2833 *==========================*/
2834 static void
touch_all(BOOLEAN includeCurrent)2835 touch_all (BOOLEAN includeCurrent)
2836 {
2837 UIWINDOW uiwin=active_uiwin;
2838 ASSERT(uiwin);
2839 /* climb to highest window ancestor */
2840 while (uiw_parent(uiwin)) {
2841 uiwin = uiw_parent(uiwin);
2842 }
2843 /* walk down touching */
2844 while (uiwin && (includeCurrent || uiwin!=active_uiwin)) {
2845 touchwin(uiw_win(uiwin));
2846 wrefresh(uiw_win(uiwin));
2847 uiwin = uiw_child(uiwin);
2848 }
2849 }
2850 /*============================
2851 * switch_to_uiwin --
2852 * switch away from currently active uiwin
2853 * to new uiwin
2854 * currently active uiwin (if any) must be solo
2855 * new uiwin must be solo
2856 *==========================*/
2857 static void
switch_to_uiwin(UIWINDOW uiwin)2858 switch_to_uiwin (UIWINDOW uiwin)
2859 {
2860 WINDOW * win = uiw_win(uiwin);
2861 if (uiwin != active_uiwin)
2862 {
2863 ASSERT(uiwin);
2864 ASSERT(win);
2865 ASSERT(!uiw_parent(uiwin));
2866 ASSERT(!uiw_child(uiwin));
2867
2868 /* link into parent/child chain */
2869 uiw_parent(uiwin) = active_uiwin;
2870 if (active_uiwin)
2871 {
2872 /* current active window must be solo, no parent or child */
2873 ASSERT(!uiw_child(active_uiwin));
2874 ASSERT(!uiw_parent(active_uiwin));
2875 }
2876 /* switch to new & refresh */
2877 active_uiwin = uiwin;
2878 }
2879 touchwin(win);
2880 wrefresh(win);
2881 }
2882 /*============================
2883 * refresh_stdout --
2884 * bring stdout to front
2885 *==========================*/
2886 void
refresh_stdout(void)2887 refresh_stdout (void)
2888 {
2889 wrefresh(uiw_win(stdout_win));
2890 }
2891 /*============================
2892 * call_system_cmd --
2893 * execute a shell command (for report interpreter)
2894 *==========================*/
2895 void
call_system_cmd(STRING cmd)2896 call_system_cmd (STRING cmd)
2897 {
2898 endwin();
2899 #ifndef WIN32
2900 system("clear");
2901 #endif
2902 system(cmd);
2903 touchwin(curscr);
2904 wrefresh(curscr);
2905 }
2906 /*============================
2907 * uierase -- erase window
2908 * handles manual erasing if broken_curses flag set
2909 *==========================*/
2910 void
uierase(UIWINDOW uiwin)2911 uierase (UIWINDOW uiwin)
2912 {
2913 LLRECT rect = 0;
2914 wipe_window_rect(uiwin, rect);
2915 }
2916 /*================================================
2917 * wipe_window_rect -- Clear a rectangle in a window
2918 * handle curses space bug
2919 *==============================================*/
2920 void
wipe_window_rect(UIWINDOW uiwin,LLRECT rect)2921 wipe_window_rect (UIWINDOW uiwin, LLRECT rect)
2922 {
2923 WINDOW * win = uiw_win(uiwin);
2924 /* workaround for curses bug with spaces */
2925 if (getlloptint("ForceScreenErase", 0) > 0) {
2926 /*
2927 To fix the dirty output on a redhat 6 system
2928 (with ncurses-5.2-8), required the call to
2929 redrawwin, instead of using wrefresh.
2930 Perry, 2002.05.27
2931 */
2932 /*
2933 uicolor(uiwin, rect, '=');
2934 wnoutrefresh(win);
2935 */
2936 /* now fill it back with spaces */
2937 uicolor(uiwin, rect, ' ');
2938 redrawwin(win);
2939 } else {
2940 /* fill it back with spaces */
2941 if (rect)
2942 uicolor(uiwin, rect, ' ');
2943 else
2944 werase(win); /* let curses do it */
2945 }
2946 }
2947 /*============================
2948 * uicolor -- fill window with character
2949 * if rect is nonzero, fill that rectangular area
2950 * if rect is zero, fill entire window
2951 *==========================*/
2952 static void
uicolor(UIWINDOW uiwin,LLRECT rect,char ch)2953 uicolor (UIWINDOW uiwin, LLRECT rect, char ch)
2954 {
2955 INT i;
2956 WINDOW *win = uiw_win(uiwin);
2957 struct tag_llrect rects;
2958
2959 if (!rect) {
2960 rects.top = 0;
2961 rects.bottom = uiw_rows(uiwin)-1;
2962 rects.left = 0;
2963 rects.right = uiw_cols(uiwin)-1;
2964 rect = &rects;
2965 }
2966 for (i=rect->top; i <= rect->bottom; ++i) {
2967 color_hseg(win, i, rect->left, rect->right, ch);
2968 }
2969 }
2970 /*==================================================
2971 * platform_postcurses_init -- platform-specific code
2972 * coming after curses initialized
2973 *================================================*/
2974 static void
platform_postcurses_init(void)2975 platform_postcurses_init (void)
2976 {
2977 #ifdef WIN32
2978 char buffer[80];
2979 STRING title = _(qSmtitle);
2980 snprintf(buffer, sizeof(buffer), title, get_lifelines_version(sizeof(buffer)-1-strlen(title)));
2981 wtitle(buffer);
2982 #endif
2983 }
2984 /*==================================================
2985 * get_main_screen_width -- current width of main screen
2986 *================================================*/
2987 INT
get_main_screen_width(void)2988 get_main_screen_width (void)
2989 {
2990 return MAINWIN_WIDTH;
2991 }
2992 /*==================================================
2993 * get_gr_ttee -- current character used for box corners
2994 *================================================*/
2995 llchtype
get_gr_ttee(void)2996 get_gr_ttee (void)
2997 {
2998 return gr_ttee; /* eg, '+' */
2999 }
3000 /*==================================================
3001 * clear_status_display -- clear any lingering status display
3002 * (called by interact code after user has pressed a button)
3003 *================================================*/
3004 void
clear_status_display(void)3005 clear_status_display (void)
3006 {
3007 if (progrunning) return;
3008 if (lock_std_msg) return;
3009 if (status_showing[0]) {
3010 status_showing[0] = 0;
3011 place_std_msg();
3012 }
3013 }
3014 /*============================
3015 * register_screen_lang_callbacks -- (un)register our callbacks
3016 * for language or codeset changes
3017 *==========================*/
3018 static void
register_screen_lang_callbacks(BOOLEAN registering)3019 register_screen_lang_callbacks (BOOLEAN registering)
3020 {
3021 if (registering) {
3022 register_uilang_callback(screen_on_lang_change, 0);
3023 register_uicodeset_callback(screen_on_lang_change, 0);
3024 } else {
3025 unregister_uilang_callback(screen_on_lang_change, 0);
3026 unregister_uicodeset_callback(screen_on_lang_change, 0);
3027 }
3028 }
3029 /*============================
3030 * screen_on_lang_change -- UI language or codeset has changed
3031 *==========================*/
3032 static void
screen_on_lang_change(VPTR uparm)3033 screen_on_lang_change (VPTR uparm)
3034 {
3035 LIST_ITER listit=0;
3036 VPTR ptr=0;
3037 uparm = uparm; /* unused */
3038 listit = begin_list(list_uiwin);
3039 while (next_list_ptr(listit, &ptr)) {
3040 UIWINDOW uiwin = (UIWINDOW)ptr;
3041 uiwin->outdated = TRUE;
3042 }
3043 end_list_iter(&listit);
3044
3045 }
3046