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(&param);
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