1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: titlebar.c 1075 2008-06-04 00:19:39Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2016 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
22 #include "../pith/state.h"
23 #include "../pith/bitmap.h"
24 #include "../pith/msgno.h"
25 #include "../pith/thread.h"
26 #include "../pith/conf.h"
27 #include "../pith/init.h"
28 #include "../pith/sort.h"
29 #include "../pith/news.h"
30 #include "../pith/util.h"
31 #include "../pith/folder.h"
36 int digit_count(long);
37 void output_titlebar(TITLE_S
*);
38 char sort_letter(SortOrder
);
39 char *percentage(long, long, int);
43 * some useful macros...
50 #define STATUS_BITS(X) (!(X && (X)->valid) ? 0 \
51 : (X)->deleted ? MS_DEL \
52 : (X)->answered ? MS_ANS \
53 : (as.stream && user_flag_is_set(as.stream, (X)->msgno, FORWARDED_FLAG)) ? MS_FWD \
55 && (ps_global->unseen_in_view \
57 && (!IS_NEWS(as.stream) \
58 || F_ON(F_FAKE_NEW_IN_NEWS, \
62 #define BAR_STATUS(X) (((X) & MS_DEL) ? "DEL" \
63 : ((X) & MS_ANS) ? "ANS" \
64 : ((X) & MS_FWD) ? "FWD" \
66 && (!IS_NEWS(as.stream) \
67 || F_ON(F_FAKE_NEW_IN_NEWS, ps_global)) \
68 && ((X) & MS_NEW)) ? "NEW" : " ")
71 static struct titlebar_state
{
87 enum {Normal
, OnlyRead
, Closed
} stream_status
;
89 TITLE_S titlecontainer
;
93 static int titlebar_is_dirty
= 1;
97 push_titlebar_state(void)
100 as
.folder_name
= NULL
; /* erase knowledge of malloc'd data */
101 as
.context_name
= NULL
;
106 pop_titlebar_state(void)
108 /* guard against case where push pushed no state */
109 if(titlebar_stack
.style
!= TitleBarNone
){
110 fs_give((void **)&(as
.folder_name
)); /* free malloc'd values */
111 fs_give((void **)&(as
.context_name
));
118 digit_count(long int n
)
123 ? (1 + (((i
= digit_count(n
/ 10L)) == 3 || i
== 7) ? i
+1 : i
))
129 mark_titlebar_dirty(void)
131 titlebar_is_dirty
= 1;
135 /*----------------------------------------------------------------------
136 Sets up style and contents of current titlebar line
138 All of the text is assumed to be UTF-8 text, which probably isn't
141 Args: title -- The title that appears in the center of the line
142 This title is in UTF-8 characters.
143 display_on_screen -- flag whether to display on screen or generate
145 style -- The format/style of the titlebar line
146 msgmap -- MSGNO_S * to selected message map
147 current_pl -- The current page or line number
148 total_pl -- The total line or page count
150 Set the contents of the anchor line. It's called an anchor line
151 because it's always present and titlebars the user. This accesses a
152 number of global variables, but doesn't change any. There are several
153 different styles of the titlebar line.
155 It's OK to call this with a bogus current message - it is only used
156 to look up status of current message
158 Formats only change the right section (part3).
159 FolderName: "<folder>" xx Messages
160 MessageNumber: "<folder>" message x,xxx of x,xxx XXX
161 TextPercent: line xxx of xxx xx%
162 MsgTextPercent: "<folder>" message x,xxx of x,xxx xx% XXX
163 FileTextPercent: "<filename>" line xxx of xxx xx%
165 Several strings and column numbers are saved so later updates to the status
166 line for changes in message number or percentage can be done efficiently.
170 set_titlebar(char *title
, MAILSTREAM
*stream
, CONTEXT_S
*cntxt
, char *folder
,
171 MSGNO_S
*msgmap
, int display_on_screen
, TitleBarType style
,
172 long int current_pl
, long int total_pl
, COLOR_PAIR
*color
)
174 struct variable
*vars
= ps_global
->vars
;
175 MESSAGECACHE
*mc
= NULL
;
176 PINETHRD_S
*thrd
= NULL
;
179 dprint((9, "set_titlebar - style: %d current message cnt:%ld",
180 style
, mn_total_cur(msgmap
)));
181 dprint((9, " current_pl: %ld total_pl: %ld\n",
182 current_pl
, total_pl
));
184 as
.current_msg
= (mn_get_total(msgmap
) > 0L)
185 ? MAX(0, mn_get_cur(msgmap
)) : 0L;
190 as
.stream_status
= (!as
.stream
|| (sp_dead_stream(as
.stream
)))
191 ? Closed
: as
.stream
->rdonly
? OnlyRead
: Normal
;
193 if(ps_global
->first_open_was_attempted
194 && as
.stream_status
== Closed
195 && VAR_TITLECLOSED_FORE_COLOR
&& VAR_TITLECLOSED_BACK_COLOR
){
196 memset(&as
.titlecontainer
.color
, 0, sizeof(as
.titlecontainer
.color
));
197 strncpy(as
.titlecontainer
.color
.fg
,
198 VAR_TITLECLOSED_FORE_COLOR
, MAXCOLORLEN
);
199 as
.titlecontainer
.color
.fg
[MAXCOLORLEN
] = '\0';
200 strncpy(as
.titlecontainer
.color
.bg
,
201 VAR_TITLECLOSED_BACK_COLOR
, MAXCOLORLEN
);
202 as
.titlecontainer
.color
.bg
[MAXCOLORLEN
] = '\0';
206 memset(&as
.titlecontainer
.color
, 0, sizeof(as
.titlecontainer
.color
));
208 strncpy(as
.titlecontainer
.color
.fg
, color
->fg
, MAXCOLORLEN
);
209 as
.titlecontainer
.color
.fg
[MAXCOLORLEN
] = '\0';
213 strncpy(as
.titlecontainer
.color
.bg
, color
->bg
, MAXCOLORLEN
);
214 as
.titlecontainer
.color
.bg
[MAXCOLORLEN
] = '\0';
218 memset(&as
.titlecontainer
.color
, 0, sizeof(as
.titlecontainer
.color
));
219 if(VAR_TITLE_FORE_COLOR
){
220 strncpy(as
.titlecontainer
.color
.fg
,
221 VAR_TITLE_FORE_COLOR
, MAXCOLORLEN
);
222 as
.titlecontainer
.color
.fg
[MAXCOLORLEN
] = '\0';
225 if(VAR_TITLE_BACK_COLOR
){
226 strncpy(as
.titlecontainer
.color
.bg
,
227 VAR_TITLE_BACK_COLOR
, MAXCOLORLEN
);
228 as
.titlecontainer
.color
.bg
[MAXCOLORLEN
] = '\0';
234 fs_give((void **)&as
.folder_name
);
237 unsigned char *fname
;
238 fname
= folder_name_decoded((unsigned char *) folder
);
239 if(!strucmp(folder
, ps_global
->inbox_name
) && cntxt
== ps_global
->context_list
)
240 as
.folder_name
= cpystr(pretty_fn(fname
? (char *) fname
: folder
));
242 as
.folder_name
= cpystr(fname
? (char *) fname
: folder
);
243 if(fname
) fs_give((void **)&fname
);
247 as
.folder_name
= cpystr("");
250 fs_give((void **)&as
.context_name
);
253 * Handle setting up the context if appropriate.
255 if(cntxt
&& context_isambig(folder
) && ps_global
->context_list
->next
256 && (strucmp(as
.folder_name
, ps_global
->inbox_name
) || cntxt
!= ps_global
->context_list
)){
258 * if there's more than one context and the current folder
259 * is in it (ambiguous name), set the context name...
261 as
.context_name
= cpystr(cntxt
->nickname
267 as
.context_name
= cpystr("");
269 if(as
.stream
&& style
!= FolderName
270 && style
!= ThrdIndex
&& as
.current_msg
> 0L) {
273 if((rawno
= mn_m2raw(msgmap
, as
.current_msg
)) > 0L
274 && rawno
<= as
.stream
->nmsgs
275 && !((mc
= mail_elt(as
.stream
, rawno
)) && mc
->valid
)){
276 pine_mail_fetch_flags(as
.stream
, long2string(rawno
), NIL
);
277 mc
= mail_elt(as
.stream
, rawno
);
281 if(style
== ThrdIndex
|| style
== ThrdMsgNum
|| style
== ThrdMsgPercent
){
282 if(mn_get_total(msgmap
) > 0L)
283 thrd
= fetch_thread(stream
, mn_m2raw(msgmap
, mn_get_cur(msgmap
)));
285 if(thrd
&& thrd
->top
&& thrd
->top
!= thrd
->rawno
)
286 thrd
= fetch_thread(stream
, thrd
->top
);
289 as
.current_thrd
= thrd
->thrdno
;
294 as
.total_lines
= msgmap
->max_thrdno
;
299 case FileTextPercent
:
301 as
.total_lines
= total_pl
;
302 as
.current_line
= current_pl
;
303 /* fall through to set state */
306 as
.msg_state
= STATUS_BITS(mc
);
308 case FolderName
: /* nothing more to do for this one */
314 tc
= format_titlebar();
315 if(display_on_screen
)
318 return(tc
->titlebar_line
);
323 redraw_titlebar(void)
325 output_titlebar(format_titlebar());
330 output_titlebar(TITLE_S
*tc
)
332 COLOR_PAIR
*lastc
= NULL
, *newcolor
;
335 && (ps_global
->ttyo
->screen_rows
- FOOTER_ROWS(ps_global
)) < 1){
336 titlebar_is_dirty
= 1;
340 newcolor
= tc
? &tc
->color
: NULL
;
343 lastc
= pico_set_colorp(newcolor
, PSC_REV
| PSC_RET
);
345 if(tc
&& tc
->titlebar_line
)
346 PutLine0(0, 0, tc
->titlebar_line
);
349 (void)pico_set_colorp(lastc
, PSC_NONE
);
350 free_color_pair(&lastc
);
358 titlebar_stream_closing(MAILSTREAM
*stream
)
360 if(stream
== as
.stream
)
365 /* caller should free returned color pair */
367 current_titlebar_color(void)
371 COLOR_PAIR
*the_color
= NULL
;
373 tc
= format_titlebar();
374 col
= tc
? &tc
->color
: NULL
;
376 if(col
&& col
->fg
&& col
->fg
[0] && col
->bg
&& col
->bg
[0])
377 the_color
= new_color_pair(col
->fg
, col
->bg
);
383 /*----------------------------------------------------------------------
384 Redraw or draw the top line, the title bar
386 The titlebar has Four fields:
387 1) "Version" of fixed length and is always positioned two spaces
388 in from left display edge.
389 2) "Location" which is fixed for each style of titlebar and
390 is positioned two spaces from the right display edge
391 3) "Title" which is of fixed length, and is centered if
393 4) "Folder" whose existence depends on style and which can
394 have it's length adjusted (within limits) so it will
395 equally share the space between 1) and 2) with the
396 "Title". The rule for existence is that in the
397 space between 1) and 2) there must be one space between
398 3) and 4) AND at least 50% of 4) must be displayed.
399 However, if the folder name can be displayed, then do
400 so, and display as much as possible of the collection name.
402 Returns - Formatted title bar
405 format_titlebar(void)
407 char version
[50], fold_tmp
[6*MAXPATH
+1], *titlebar_line
,
408 loc1
[200], loc_label
[10], *thd_label
, *ss_string
, *q
,
409 *plus
, *loc2
= "", title
[200];
410 int title_len
= 0, ver_len
, loc1_len
= 0, loc2_len
= 0, fold_len
= 0, num_len
,
411 s1
= 0, s2
= 0, s3
= 0, s4
= 0, s5
= 0, s6
= 0, tryloc
= 1,
412 cur_mess_col_offset
= -1, percent_column_offset
= -1, page_column_offset
= -1,
413 ss_len
, thd_len
, is_context
, avail
, extra
;
415 titlebar_is_dirty
= 0;
421 as
.folder_name
= cpystr("");
424 as
.context_name
= cpystr("");
427 * Full blown title looks like:
429 * | LV vers VT title TF folder FL location LR |
431 #define LV 2 /* space between Left edge and Version, must be >= 2 */
432 #define VT 3 /* space between Version and Title */
433 #define TF 1 /* space between Title and Folder */
434 #define FL 2 /* space between Folder and Location */
435 #define LR 2 /* space between Location and Right edge, >= 2 */
436 /* half of n but round up */
437 #define HRU(n) (((n) <= 0) ? 0 : (((n)%2) ? ((n)+1)/2 : (n)/2))
438 /* half of n but round down */
439 #define HRD(n) (((n) <= 0) ? 0 : ((n)/2))
441 titlebar_line
= as
.titlecontainer
.titlebar_line
;
443 avail
= MIN(ps_global
->ttyo
->screen_cols
, MAX_SCREEN_COLS
);
447 as
.cur_mess_col
= -1;
448 as
.percent_column
= -1;
451 is_context
= as
.context_name
? strlen(as
.context_name
) : 0;
453 snprintf(version
, sizeof(version
), "ALPINE %s", ALPINE_VERSION
);
454 version
[sizeof(version
)-1] = '\0';
455 ver_len
= (int) utf8_width(version
); /* fixed version field width */
459 strncpy(title
, as
.title
, sizeof(title
));
460 title
[sizeof(title
)-1] = '\0';
463 /* Add Sort indicator to title */
464 if(F_ON(F_SHOW_SORT
, ps_global
) &&
465 !(as
.style
== FileTextPercent
|| as
.style
== TextPercent
)){
466 SortOrder current_sort
;
470 current_sort
= mn_get_sort(ps_global
->msgmap
);
471 current_rev
= mn_get_revsort(ps_global
->msgmap
);
473 /* turn current_sort into a letter */
474 let
= sort_letter(current_sort
);
475 if(let
== 'A' && current_rev
){
480 snprintf(title
+strlen(title
), sizeof(title
)-strlen(title
),
481 " [%s%c]", current_rev
? "R" : "", let
);
482 title
[sizeof(title
)-1] = '\0';
485 title_len
= (int) utf8_width(title
); /* title field width */
487 s1
= MAX(MIN(LV
, avail
), 0); /* left two spaces */
490 s6
= MAX(MIN(LR
, avail
), 0); /* right two spaces */
493 title_len
= MAX(MIN(title_len
, avail
), 0);
496 if(ver_len
+ VT
> avail
){ /* can only fit title */
499 s2
= MAX(MIN(HRD(avail
), avail
), 0);
505 s2
= MAX(MIN(VT
, avail
), 0);
508 ver_len
= MAX(MIN(ver_len
, avail
), 0);
514 * set location field's length and value based on requested style
516 if(as
.style
== ThrdIndex
)
517 /* TRANSLATORS: In titlebar, Thd is an abbreviation for Thread, Msg for Message.
518 They are used when there isn't enough space so need to be short.
519 The formatting isn't very flexible. These come before the number
520 of the message or thread, as in
522 when reading message number 17. */
523 snprintf(loc_label
, sizeof(loc_label
), "%s ", (is_context
|| tryloc
==2) ? _("Thd") : _("Thread"));
525 snprintf(loc_label
, sizeof(loc_label
), "%s ", (is_context
|| tryloc
==2) ? _("Msg") : _("Message"));
527 if(tryloc
== 3 && as
.style
!= FolderName
&& mn_get_total(as
.msgmap
))
530 loc_label
[sizeof(loc_label
)-1] = '\0';
532 if(as
.style
== ThrdMsgNum
|| as
.style
== ThrdMsgPercent
){
533 thd_label
= is_context
? _("Thd") : _("Thread");
534 thd_len
= (int) utf8_width(thd_label
);
537 loc1_len
= (int) utf8_width(loc_label
); /* initial length */
539 if(!mn_get_total(as
.msgmap
)){
540 loc_label
[strlen(loc_label
)-1] = 's';
541 snprintf(loc1
, sizeof(loc1
), "%s %s", _("No"), loc_label
);
542 loc1
[sizeof(loc1
)-1]= '\0';
546 case FolderName
: /* "x,xxx <loc_label>s" */
548 if(mn_get_total(as
.msgmap
) != 1)
549 loc_label
[strlen(loc_label
)-1] = 's';
551 loc_label
[strlen(loc_label
)-1] = '\0';
554 snprintf(loc1
, sizeof(loc1
), "%s %s", comatose(mn_get_total(as
.msgmap
)), loc_label
);
555 loc1
[sizeof(loc1
)-1]= '\0';
558 case MessageNumber
: /* "<loc_label> xxx of xxx DEL" */
559 num_len
= strlen(comatose(mn_get_total(as
.msgmap
)));
560 cur_mess_col_offset
= loc1_len
;
561 snprintf(loc1
, sizeof(loc1
), "%s%*.*s of %s", loc_label
,
563 comatose(as
.current_msg
),
564 comatose(mn_get_total(as
.msgmap
)));
565 loc1
[sizeof(loc1
)-1]= '\0';
566 loc2
= BAR_STATUS(as
.msg_state
);
570 case ThrdIndex
: /* "<loc_label> xxx of xxx" */
571 num_len
= strlen(comatose(as
.total_lines
));
572 cur_mess_col_offset
= loc1_len
;
573 snprintf(loc1
, sizeof(loc1
), "%s%*.*s of %s", loc_label
,
575 comatose(as
.current_thrd
),
576 comatose(as
.total_lines
));
577 loc1
[sizeof(loc1
)-1]= '\0';
580 case ThrdMsgNum
: /* "<loc_label> xxx in Thd xxx DEL" */
581 num_len
= strlen(comatose(mn_get_total(as
.msgmap
)));
582 cur_mess_col_offset
= loc1_len
;
583 snprintf(loc1
, sizeof(loc1
), "%s%*.*s in %s %s", loc_label
,
585 comatose(as
.current_msg
),
587 comatose(as
.current_thrd
));
588 loc1
[sizeof(loc1
)-1]= '\0';
589 loc2
= BAR_STATUS(as
.msg_state
);
593 case MsgTextPercent
: /* "<loc_label> xxx of xxx xx% DEL" */
594 num_len
= strlen(comatose(mn_get_total(as
.msgmap
)));
595 cur_mess_col_offset
= loc1_len
;
596 percent_column_offset
= 3;
597 snprintf(loc1
, sizeof(loc1
), "%s%*.*s of %s %s", loc_label
,
599 comatose(as
.current_msg
),
600 comatose(mn_get_total(as
.msgmap
)),
601 percentage(as
.current_line
, as
.total_lines
, 1));
602 loc1
[sizeof(loc1
)-1]= '\0';
603 loc2
= BAR_STATUS(as
.msg_state
);
607 case ThrdMsgPercent
: /* "<loc_label> xxx in Thd xxx xx% DEL" */
608 num_len
= strlen(comatose(mn_get_total(as
.msgmap
)));
609 cur_mess_col_offset
= loc1_len
;
610 percent_column_offset
= 3;
611 snprintf(loc1
, sizeof(loc1
), "%s%*.*s in %s %s %s", loc_label
,
613 comatose(as
.current_msg
),
615 comatose(as
.current_thrd
),
616 percentage(as
.current_line
, as
.total_lines
, 1));
617 loc1
[sizeof(loc1
)-1]= '\0';
618 loc2
= BAR_STATUS(as
.msg_state
);
623 /* NOTE: no fold_tmp setup below for TextPercent style */
624 case FileTextPercent
: /* "Line xxx of xxx xx%" */
625 num_len
= strlen(comatose(as
.total_lines
));
626 page_column_offset
= 5;
627 percent_column_offset
= 3;
628 snprintf(loc1
, sizeof(loc1
), "Line %*.*s of %s %s",
630 comatose(as
.current_line
),
631 comatose(as
.total_lines
),
632 percentage(as
.current_line
, as
.total_lines
, 1));
633 loc1
[sizeof(loc1
)-1]= '\0';
640 loc1_len
= utf8_width(loc1
);
642 if(loc1_len
+ loc2_len
+ ((loc2_len
> 0) ? 1 : 0) >= avail
){ /* can't fit location in */
645 goto try_smaller_loc
;
648 loc1_len
= loc2_len
= 0;
650 avail
+= s2
; /* re-allocate s2 to center title */
652 s2
= MAX(MIN(HRD(avail
), avail
), 0);
658 loc1_len
= MAX(MIN(loc1_len
, avail
), 0);
661 loc2_len
= MAX(MIN(loc2_len
, avail
), 0);
665 s5
= MAX(MIN(1, avail
), 0);
671 s3
= MAX(MIN(TF
, avail
), 0);
674 s4
= MAX(MIN(FL
, avail
), 0);
678 /* TRANSLATORS: it might say READONLY or CLOSED in the titlebar, referring to
679 the current folder. */
680 ss_string
= as
.stream_status
== Closed
? _("(CLOSED)") :
681 (as
.stream_status
== OnlyRead
682 && !IS_NEWS(as
.stream
))
683 ? _("(READONLY)") : "";
684 ss_len
= (int) utf8_width(ss_string
);
686 /* figure folder_length and what's to be displayed */
688 if(as
.style
== FileTextPercent
|| as
.style
== TextPercent
){
689 if(as
.style
== FileTextPercent
){
690 extra
= (int) utf8_width("File: ");
691 fold_len
= (int) utf8_width(as
.folder_name
);
692 if(fold_len
+ extra
<= avail
){ /* all of folder fit? */
693 strncpy(fold_tmp
, "File: ", sizeof(fold_tmp
));
694 q
= fold_tmp
+ strlen(fold_tmp
);
695 strncpy(q
, as
.folder_name
, sizeof(fold_tmp
)-(q
-fold_tmp
));
697 else if(HRU(fold_len
) + extra
+3 <= avail
){
699 * fold_tmp = ...partial_folder_name
701 strncpy(fold_tmp
, "File: ...", sizeof(fold_tmp
));
702 q
= fold_tmp
+ strlen(fold_tmp
);
703 (void) utf8_to_width_rhs(q
, as
.folder_name
, sizeof(fold_tmp
)-(q
-fold_tmp
), avail
-(extra
+3));
706 /* else leave folder/file name blank */
711 fold_len
= (int) utf8_width(as
.folder_name
);
714 && as
.stream_status
!= Closed
715 && (ct_len
= (int) utf8_width(as
.context_name
))){
717 extra
= 3; /* length from "<" ">" and SPACE */
719 if(ct_len
+ fold_len
+ ss_len
+ extra
<= avail
){
722 strncpy(q
, as
.context_name
, sizeof(fold_tmp
)-(q
-fold_tmp
));
726 strncpy(q
, as
.folder_name
, sizeof(fold_tmp
)-(q
-fold_tmp
));
728 strncpy(q
, ss_string
, sizeof(fold_tmp
)-(q
-fold_tmp
));
730 else if(ct_len
+ fold_len
+ ss_len
+ extra
<= avail
){
733 strncpy(q
, as
.context_name
, sizeof(fold_tmp
)-(q
-fold_tmp
));
737 strncpy(q
, as
.folder_name
, sizeof(fold_tmp
)-(q
-fold_tmp
));
739 strncpy(q
, ss_string
, sizeof(fold_tmp
)-(q
-fold_tmp
));
741 else if(HRU(ct_len
) + fold_len
+ ss_len
+ extra
<= avail
){
744 q
+= utf8_pad_to_width(q
, as
.context_name
, sizeof(fold_tmp
)-(q
-fold_tmp
), avail
-(fold_len
+ss_len
+extra
), 1);
747 strncpy(q
, as
.folder_name
, sizeof(fold_tmp
)-(q
-fold_tmp
));
749 strncpy(q
, ss_string
, sizeof(fold_tmp
)-(q
-fold_tmp
));
751 else if(HRU(ct_len
) + HRU(fold_len
) + ss_len
+ extra
<= avail
){
754 q
+= utf8_pad_to_width(q
, as
.context_name
, sizeof(fold_tmp
)-(q
-fold_tmp
), HRU(ct_len
), 1);
757 q
+= utf8_to_width_rhs(q
, as
.folder_name
, sizeof(fold_tmp
)-(q
-fold_tmp
), avail
-(HRU(ct_len
)+ss_len
+extra
));
758 strncpy(q
, ss_string
, sizeof(fold_tmp
)-(q
-fold_tmp
));
760 else if(ss_len
> 0 && ss_len
<= avail
){
762 strncpy(q
, ss_string
, sizeof(fold_tmp
)-(q
-fold_tmp
));
763 } else if(fold_len
< avail
){
765 if(fold_len
+ 7 < avail
){
767 q
+= utf8_pad_to_width(q
, as
.context_name
, sizeof(fold_tmp
)-(q
-fold_tmp
), avail
- fold_len
- 3, 1);
771 strncpy(q
, as
.folder_name
, sizeof(fold_tmp
)-(q
-fold_tmp
));
773 /* else leave it out */
776 /* TRANSLATORS: the name of the open folder follows this in the titlebar */
777 extra
= strlen(_("Folder: "));
778 if(fold_len
+ ss_len
+ extra
<= avail
){
780 strncpy(q
, "Folder: ", sizeof(fold_tmp
)-(q
-fold_tmp
));
782 strncpy(q
, as
.folder_name
, sizeof(fold_tmp
)-(q
-fold_tmp
));
784 strncpy(q
, ss_string
, sizeof(fold_tmp
)-(q
-fold_tmp
));
787 if(fold_len
+ ss_len
<= avail
){
789 strncpy(q
, as
.folder_name
, sizeof(fold_tmp
)-(q
-fold_tmp
));
791 strncpy(q
, ss_string
, sizeof(fold_tmp
)-(q
-fold_tmp
));
793 else if(((HRU(fold_len
) + ss_len
<= avail
)
794 || (avail
> ss_len
+3 && avail
> 10)) && fold_len
> 5){
796 strncpy(q
, "...", sizeof(fold_tmp
));
798 q
+= utf8_to_width_rhs(q
, as
.folder_name
, sizeof(fold_tmp
)-(q
-fold_tmp
), avail
-(3+ss_len
));
799 strncpy(q
, ss_string
, sizeof(fold_tmp
)-(q
-fold_tmp
));
801 else if(ss_len
> 0 && ss_len
<= avail
){
803 strncpy(q
, ss_string
, sizeof(fold_tmp
)-(q
-fold_tmp
));
805 /* else leave it out */
810 fold_tmp
[sizeof(fold_tmp
)-1] = '\0';
812 /* write title, location and, optionally, the folder name */
813 fold_len
= (int) utf8_width(fold_tmp
);
816 fold_len
= MAX(MIN(fold_len
, avail
), 0);
819 /* center folder in its space */
835 if(as
.style
!= FileTextPercent
&& as
.style
!= TextPercent
){
839 && as
.stream
->mailbox
840 && mail_valid_net_parse(as
.stream
->mailbox
, &mb
)
841 && (mb
.sslflag
|| mb
.tlsflag
))
846 if(loc1_len
> 0 && cur_mess_col_offset
>= 0)
847 as
.cur_mess_col
= s1
+ver_len
+s2
+title_len
+s3
+fold_len
+s4
+ cur_mess_col_offset
;
849 if(loc1_len
> 0 && page_column_offset
>= 0)
850 as
.page_column
= s1
+ver_len
+s2
+title_len
+s3
+fold_len
+s4
+ page_column_offset
;
853 as
.del_column
= s1
+ver_len
+s2
+title_len
+s3
+fold_len
+s4
+loc1_len
+s5
;
855 if(loc1_len
> 0 && percent_column_offset
> 0)
856 as
.percent_column
= s1
+ver_len
+s2
+title_len
+s3
+fold_len
+s4
+loc1_len
- percent_column_offset
;
859 utf8_snprintf(titlebar_line
, 6*MAX_SCREEN_COLS
, "%*.*s%-*.*w%*.*s%-*.*w%*.*s%-*.*w%*.*s%-*.*w%*.*s%-*.*w%*.*s",
861 ver_len
, ver_len
, version
,
863 title_len
, title_len
, title
,
865 fold_len
, fold_len
, fold_tmp
,
867 loc1_len
, loc1_len
, loc1
,
869 loc2_len
, loc2_len
, loc2
,
872 return(&as
.titlecontainer
);
877 sort_letter(SortOrder sort
)
881 if((p
= sort_name(sort
)) != NULL
&& *p
){
882 while(*(p
+1) && islower((unsigned char) *p
))
894 * Update the titlebar line if the message number changed
896 * Args: None, uses state setup on previous call to set_titlebar.
899 update_titlebar_message(void)
901 long curnum
, maxnum
, oldnum
;
902 PINETHRD_S
*thrd
= NULL
;
903 COLOR_PAIR
*lastc
= NULL
, *titlecolor
;
909 && (ps_global
->ttyo
->screen_rows
- FOOTER_ROWS(ps_global
)) < 1){
910 titlebar_is_dirty
= 1;
914 if(as
.style
== ThrdIndex
){
916 oldnum
= as
.current_thrd
;
918 if(as
.stream
&& (rawno
=mn_m2raw(as
.msgmap
, mn_get_cur(as
.msgmap
))))
919 thrd
= fetch_thread(as
.stream
, rawno
);
921 if(thrd
&& thrd
->top
&& (thrd
=fetch_thread(as
.stream
, thrd
->top
)))
922 curnum
= thrd
->thrdno
;
924 else if(as
.cur_mess_col
>= 0){
925 curnum
= mn_get_cur(as
.msgmap
);
926 oldnum
= as
.current_msg
;
929 if(as
.cur_mess_col
>= 0 && oldnum
!= curnum
){
931 if(as
.style
== ThrdIndex
){
932 as
.current_thrd
= curnum
;
933 maxnum
= as
.msgmap
->max_thrdno
;
936 as
.current_msg
= curnum
;
937 maxnum
= mn_get_total(as
.msgmap
);
940 titlecolor
= &as
.titlecontainer
.color
;
943 lastc
= pico_set_colorp(titlecolor
, PSC_REV
|PSC_RET
);
945 num_len
= strlen(comatose(maxnum
));
947 snprintf(buf
, sizeof(buf
), "%*.*s", num_len
, num_len
, comatose(curnum
));
949 PutLine0(0, as
.cur_mess_col
, buf
);
952 (void)pico_set_colorp(lastc
, PSC_NONE
);
953 free_color_pair(&lastc
);
963 * Update titlebar line's message status field ("DEL", "NEW", etc)
965 * Args: None, operates on state set during most recent set_titlebar call
968 update_titlebar_status(void)
972 COLOR_PAIR
*lastc
= NULL
, *titlecolor
;
975 && (ps_global
->ttyo
->screen_rows
- FOOTER_ROWS(ps_global
)) < 1){
976 titlebar_is_dirty
= 1;
980 if(!as
.stream
|| as
.current_msg
<= 0L || as
.del_column
< 0)
983 if(as
.current_msg
!= mn_get_cur(as
.msgmap
))
984 update_titlebar_message();
986 mc
= ((rawno
= mn_m2raw(as
.msgmap
, as
.current_msg
)) > 0L
987 && rawno
<= as
.stream
->nmsgs
)
988 ? mail_elt(as
.stream
, rawno
) : NULL
;
990 if(!(mc
&& mc
->valid
))
991 return(0); /* indeterminate */
993 if(mc
->deleted
){ /* deleted takes precedence */
994 if(as
.msg_state
& MS_DEL
)
997 else if(mc
->answered
){ /* then answered */
998 if(as
.msg_state
& MS_ANS
)
1000 } /* then forwarded */
1001 else if(user_flag_is_set(as
.stream
, mc
->msgno
, FORWARDED_FLAG
)){
1002 if(as
.msg_state
& MS_FWD
)
1005 else if(!mc
->seen
&& as
.stream
1006 && (!IS_NEWS(as
.stream
)
1007 || F_ON(F_FAKE_NEW_IN_NEWS
, ps_global
))){
1008 if(as
.msg_state
& MS_NEW
) /* then seen */
1012 if(as
.msg_state
== 0) /* nothing to change */
1016 as
.msg_state
= STATUS_BITS(mc
);
1018 titlecolor
= &as
.titlecontainer
.color
;
1021 lastc
= pico_set_colorp(titlecolor
, PSC_REV
|PSC_RET
);
1023 PutLine0(0, as
.del_column
, BAR_STATUS(as
.msg_state
));
1026 (void)pico_set_colorp(lastc
, PSC_NONE
);
1027 free_color_pair(&lastc
);
1036 * Update the percentage shown in the titlebar line
1038 * Args: new_line_number -- line number to calculate new percentage
1041 update_titlebar_percent(long int new_line_number
)
1043 COLOR_PAIR
*lastc
= NULL
, *titlecolor
;
1045 if(as
.percent_column
< 0 || new_line_number
== as
.current_line
)
1049 && (ps_global
->ttyo
->screen_rows
- FOOTER_ROWS(ps_global
)) < 1){
1050 titlebar_is_dirty
= 1;
1054 as
.current_line
= new_line_number
;
1056 titlecolor
= &as
.titlecontainer
.color
;
1059 lastc
= pico_set_colorp(titlecolor
, PSC_REV
|PSC_RET
);
1061 PutLine0(0, as
.percent_column
,
1062 percentage(as
.current_line
, as
.total_lines
, 0));
1065 (void)pico_set_colorp(lastc
, PSC_NONE
);
1066 free_color_pair(&lastc
);
1074 * Update the percentage AND line number shown in the titlebar line
1076 * Args: new_line_number -- line number to calculate new percentage
1079 update_titlebar_lpercent(long int new_line_number
)
1081 COLOR_PAIR
*lastc
= NULL
, *titlecolor
;
1085 if(as
.page_column
< 0 || new_line_number
== as
.current_line
)
1089 && (ps_global
->ttyo
->screen_rows
- FOOTER_ROWS(ps_global
)) < 1){
1090 titlebar_is_dirty
= 1;
1094 as
.current_line
= new_line_number
;
1096 titlecolor
= &as
.titlecontainer
.color
;
1099 lastc
= pico_set_colorp(titlecolor
, PSC_REV
|PSC_RET
);
1101 num_len
= strlen(comatose(as
.total_lines
));
1102 snprintf(buf
, sizeof(buf
), "%*.*s", num_len
, num_len
, comatose(as
.current_line
));
1104 PutLine0(0, as
.page_column
, buf
);
1106 PutLine0(0, as
.percent_column
,
1107 percentage(as
.current_line
, as
.total_lines
, 0));
1110 (void)pico_set_colorp(lastc
, PSC_NONE
);
1111 free_color_pair(&lastc
);
1118 /*----------------------------------------------------------------------
1119 Return static buf containing portion of lines displayed
1121 Args: part -- how much so far
1122 total -- how many total
1126 percentage(long int part
, long int total
, int suppress_top
)
1128 static char percent
[4];
1130 if(total
== 0L || (total
<= ps_global
->ttyo
->screen_rows
1131 - HEADER_ROWS(ps_global
)
1132 - FOOTER_ROWS(ps_global
)))
1133 strncpy(percent
, "ALL", sizeof(percent
));
1134 else if(!suppress_top
&& part
<= ps_global
->ttyo
->screen_rows
1135 - HEADER_ROWS(ps_global
)
1136 - FOOTER_ROWS(ps_global
))
1137 strncpy(percent
, "TOP", sizeof(percent
));
1138 else if(part
>= total
)
1139 strncpy(percent
, "END", sizeof(percent
));
1141 snprintf(percent
, sizeof(percent
), "%2ld%%", (100L * part
)/total
);
1143 percent
[sizeof(percent
)-1] = '\0';
1150 * end_titlebar - free resources associated with titlebar state struct
1156 fs_give((void **)&as
.folder_name
);
1159 fs_give((void **)&as
.context_name
);
1163 /*----------------------------------------------------------------------
1164 Exported method to display status of mail check
1166 Args: putstr -- should be NO LONGER THAN 2 bytes
1168 Result: putstr displayed at upper-left-hand corner of screen
1171 check_cue_display(char *putstr
)
1173 COLOR_PAIR
*lastc
= NULL
, *titlecolor
;
1174 static char check_cue_char
;
1176 if(ps_global
->read_predicted
&&
1177 (check_cue_char
== putstr
[0]
1178 || (putstr
[0] == ' ' && putstr
[1] == '\0')))
1181 if(putstr
[0] == ' ')
1182 check_cue_char
= '\0';
1184 check_cue_char
= putstr
[0];
1187 titlecolor
= &as
.titlecontainer
.color
;
1190 lastc
= pico_set_colorp(titlecolor
, PSC_REV
|PSC_RET
);
1192 PutLine0(0, 0, putstr
); /* show delay cue */
1194 (void)pico_set_colorp(lastc
, PSC_NONE
);
1195 free_color_pair(&lastc
);
1202 /*----------------------------------------------------------------------
1203 Mandatory function of ../pith/newmail.c
1207 Result: newmail cue displayed at upper-left-hand corner of screen
1210 newmail_check_cue(int onoroff
)
1212 if(F_ON(F_SHOW_DELAY_CUE
, ps_global
) && !ps_global
->in_init_seq
){
1213 check_cue_display((onoroff
== TRUE
) ? " *" : " ");
1214 MoveCursor(ps_global
->ttyo
->screen_rows
-FOOTER_ROWS(ps_global
), 0);
1219 mswin_setcursor (MSWIN_CURSOR_BUSY
);
1221 mswin_setcursor (MSWIN_CURSOR_ARROW
);
1226 /*----------------------------------------------------------------------
1227 Mandatory function of ../pith/newmail.c
1231 Result: checkpoint delay cue displayed at upper-left-hand corner of screen
1234 newmail_check_point_cue(int onoroff
)
1236 if(F_ON(F_SHOW_DELAY_CUE
, ps_global
)){
1237 check_cue_display((onoroff
== TRUE
) ? "**" : " ");
1238 MoveCursor(ps_global
->ttyo
->screen_rows
-FOOTER_ROWS(ps_global
), 0);
1243 mswin_setcursor (MSWIN_CURSOR_BUSY
);
1245 mswin_setcursor (MSWIN_CURSOR_ARROW
);