3 * $Id: ui.c,v 1.58 2006/09/06 02:24:33 cduval Exp $
5 * by JH <jheinonen@users.sourceforge.net>
7 * Copyright (C) Jaakko Heinonen
31 #ifdef HAVE_SYS_IOCTL_H
32 # include <sys/ioctl.h>
41 extern char *datafile
;
43 extern bool alternative_datafile
;
49 static bool ui_initialized
= FALSE
;
51 static bool should_resize
= FALSE
;
52 static bool can_resize
= FALSE
;
54 static WINDOW
*top
= NULL
, *bottom
= NULL
;
60 top
= newwin(LIST_TOP
- 1, COLS
, 0, 0);
61 bottom
= newwin(LINES
- LIST_BOTTOM
, COLS
, LIST_BOTTOM
, 0);
79 ioctl(0, TIOCGWINSZ
, &winsz
);
81 if(winsz
.ws_col
>= MIN_COLS
&& winsz
.ws_row
>= MIN_LINES
) {
82 fprintf(stderr
, "Warning: COLS=%d, LINES=%d\n", winsz
.ws_col
, winsz
.ws_row
);
86 if(winsz
.ws_col
>= MIN_COLS
&& winsz
.ws_row
>= MIN_LINES
) {
87 #ifdef HAVE_RESIZETERM
88 resizeterm(winsz
.ws_row
, winsz
.ws_col
);
95 should_resize
= FALSE
;
96 close_list(); /* we need to recreate windows */
102 #endif /* TIOCGWINSZ */
112 should_resize
= TRUE
;
114 #endif /* SIGWINCH */
120 return ui_initialized
;
126 if(!is_ui_initialized())
131 intrflush(stdscr
, FALSE
);
132 keypad(stdscr
, TRUE
);
140 fprintf(stderr
, "init_abook():\n");
141 fprintf(stderr
, " COLS = %d, LINES = %d\n", COLS
, LINES
);
143 if( LINES
< MIN_LINES
|| COLS
< MIN_COLS
) {
144 clear(); refresh(); endwin();
145 fprintf(stderr
, _("Your terminal size is %dx%d\n"), COLS
, LINES
);
146 fprintf(stderr
, _("Terminal is too small. Minimum terminal "
148 "%dx%d\n"), MIN_COLS
, MIN_LINES
);
155 ui_initialized
= TRUE
;
158 signal(SIGWINCH
, win_changed
);
173 ui_initialized
= FALSE
;
178 headerline(const char *str
)
182 mvwhline(top
, 1, 0, UI_HLINE_CHAR
, COLS
);
184 mvwprintw(top
, 0, 0, "%s | %s", PACKAGE
" " VERSION
, str
);
202 refresh_statusline();
203 headerline(gettext(MAIN_HELPLINE
));
211 statusline_msg(const char *msg
)
216 statusline_addstr(msg
);
219 fprintf(stderr
, "statusline_msg(\"%s\")\n", msg
);
227 statusline_addstr(const char *str
)
229 mvwaddstr(bottom
, 1, 0, str
);
234 /* Same as statusline_addstr(), but hilight "<str>" sequences if the terminal
237 statusline_addhlstr(const char *str
)
239 #if defined(A_BOLD) && defined(A_NORMAL) && defined(A_DIM)
240 const char *p
= str
, *start
= str
;
245 if(!*p
|| strchr("<>", *p
)) {
247 wattrset(bottom
, (*p
== '>') ? A_BOLD
: A_NORMAL
);
248 tmp
= xstrndup(start
, p
- start
);
249 mvwaddstr(bottom
, 1, pos
, tmp
);
250 pos
+= strwidth(tmp
);
256 /* show tag markers */
257 wattrset(bottom
, A_DIM
);
258 mvwaddch(bottom
, 1, pos
++, *p
);
263 wattrset(bottom
, A_NORMAL
);
270 mvwaddstr(bottom
, 1, 0, str
);
278 statusline_askchoice(const char *msg
, const char *choices
, short dflt
)
283 assert((dflt
>= 0) && (dflt
<= strlen(choices
)));
286 s
= strdup_printf("%s [%c]", msg
, choices
[dflt
- 1]);
287 statusline_addhlstr(s
);
290 statusline_addhlstr(msg
);
294 ch
= tolower(getch());
296 if(ch
== 7) /* ctrl+G */
299 if(dflt
&& (ch
== '\r')) /* default choice */
302 if((s
= strchr(choices
, ch
)))
303 return (s
- choices
+ 1);
308 ui_readline(const char *prompt
, char *s
, size_t limit
, bool use_completion
)
313 mvwaddstr(bottom
, 1, 0, prompt
);
317 ret
= abook_readline(bottom
, y
, x
, s
, use_completion
);
321 if(strlen(ret
) > limit
&& limit
> 0)
329 statusline_ask_boolean(const char *msg
, int def
)
332 char *msg2
= strconcat(msg
, def
? _(" (Y/n)?") : _(" (y/N)?"), NULL
);
335 statusline_addstr(msg2
);
339 ch
= tolower(getch());
341 if(ch
== *(S_("keybinding for no|n")))
343 else if(ch
== *(S_("keybinding for yes|y")))
358 mvwhline(bottom
, 0, 0, UI_HLINE_CHAR
, COLS
);
365 ask_filename(const char *prompt
)
371 buf
= ui_readline(prompt
, NULL
, -1, 1);
392 display_help(int help
)
408 helpw
= newwin(LINES
- 5, COLS
- 6, 2, 3);
410 headerline(_("help"));
412 for(i
= 0; tbl
[i
] != NULL
; i
++) {
413 waddstr(helpw
, gettext(tbl
[i
]));
414 if( (!((i
+ 1) % (LINES
- 8))) ||
415 (tbl
[i
+ 1] == NULL
) ) {
418 refresh_statusline();
419 if(statusline_msg(_("Press any key to continue..."))
434 extern char *selected
;
442 can_resize
= TRUE
; /* it's safe to resize now */
443 if(!opt_get_bool(BOOL_SHOW_CURSOR
))
448 if(!opt_get_bool(BOOL_SHOW_CURSOR
))
450 can_resize
= FALSE
; /* it's not safe to resize anymore */
453 case 'Q': quit_abook(QUIT_DONTSAVE
); break;
454 case 'P': print_stderr(selected_items() ?
455 -1 : list_get_curitem());
458 display_help(HELP_MAIN
);
461 case 'a': add_item(); break;
462 case '\r': edit_item(-1); break;
465 case 'r': ui_remove_items(); break;
466 case 'D': duplicate_item(); break;
467 case 12: refresh_screen(); break;
470 case KEY_UP
: scroll_up(); break;
472 case KEY_DOWN
: scroll_down(); break;
474 case KEY_PPAGE
: page_up(); break;
476 case KEY_NPAGE
: page_down(); break;
479 case KEY_HOME
: goto_home(); break;
481 case KEY_END
: goto_end(); break;
483 case 'w': save_database();
485 case 'l': ui_read_database(); break;
486 case 'i': import_database(); break;
487 case 'e': export_database(); break;
488 case 'C': ui_clear_database(); break;
490 case 'o': ui_open_datafile(); break;
492 case 's': sort_by_field("name");break;
493 case 'S': sort_surname(); break;
494 case 'F': sort_by_field(NULL
); break;
496 case '/': ui_find(0); break;
497 case '\\': ui_find(1); break;
499 case ' ': if(list_get_curitem() >= 0) {
500 list_invert_curitem_selection();
501 ui_print_number_of_items();
505 case '+': select_all();
508 case '-': select_none();
511 case '*': invert_selection();
514 case 'A': move_curitem(MOVE_ITEM_UP
);
516 case 'Z': move_curitem(MOVE_ITEM_DOWN
);
519 case 'm': launch_mutt(selected_items() ?
520 -1 : list_get_curitem());
524 case 'p': ui_print_database(); break;
526 case 'v': launch_wwwbrowser(list_get_curitem());
539 if(statusline_ask_boolean(_("Remove selected item(s)"), TRUE
))
540 remove_selected_items();
549 if(statusline_ask_boolean(_("Clear WHOLE database"), FALSE
)) {
559 static char findstr
[MAX_FIELD_LEN
];
560 int search_fields
[] = {NAME
, EMAIL
, NICK
, -1};
569 s
= ui_readline("/", findstr
, MAX_FIELD_LEN
- 1, 0);
572 return; /* user cancelled (ctrl-G) */
574 strncpy(findstr
, s
, MAX_FIELD_LEN
);
579 if( (item
= find_item(findstr
, list_get_curitem() + !!next
,
580 search_fields
)) < 0 &&
581 (item
= find_item(findstr
, 0, search_fields
)) >= 0)
582 statusline_addstr(_("Search hit bottom, continuing at top"));
585 list_set_curitem(item
);
591 ui_print_number_of_items()
593 char *str
= strdup_printf(" " "|%3d/%3d",
594 selected_items(), db_n_items());
596 mvaddstr(0, COLS
-strlen(str
), str
);
606 if(!list_is_empty()) {
607 msg
= strdup_printf(_("Your current data will be lost - "
608 "Press '%c' to continue"),
609 *(S_("keybinding for yes|y")));
610 if(!statusline_ask_boolean(msg
, FALSE
)) {
617 load_database(datafile
);
626 char *command
= opt_get_str(STR_PRINT_COMMAND
);
632 switch(statusline_askchoice(_("Print <a>ll, print <s>elected, or <c>ancel?"), S_("keybindings:all/selected/cancel|asc"), 3)) {
637 if( !selected_items() ) {
638 statusline_msg(_("No selected items"));
641 mode
= ENUM_SELECTED
;
650 if( ! *command
|| (handle
= popen(command
, "w")) == NULL
)
653 fexport("text", handle
, mode
);
664 filename
= ask_filename(_("File to open: "));
666 if(!filename
|| ! *filename
) {
672 if(opt_get_bool(BOOL_AUTOSAVE
))
674 else if(statusline_ask_boolean(_("Save current database"), FALSE
))
679 load_database(filename
);
681 if(list_is_empty()) {
682 statusline_msg(_("Sorry, the specified file appears not to be a valid abook addressbook"));
683 load_database(datafile
);
686 datafile
= xstrdup(filename
);
692 alternative_datafile
= TRUE
;