1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: display.c 1025 2008-04-08 22:59:38Z 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 * ========================================================================
18 * Program: Display functions
23 * The functions in this file handle redisplay. There are two halves, the
24 * ones that update the virtual display screen, and the ones that make the
25 * physical display screen the same as the virtual display screen. These
26 * functions use hints that are left in the windows by the commands.
30 #include "../c-client/mail.h"
31 #include "../c-client/utf8.h"
34 /* wingdi.h uses ERROR (!) and we aren't using the c-client ERROR so... */
39 #include "../pith/charconv/filesys.h"
40 #include "../pith/charconv/utf8.h"
43 void vtmove(int, int);
46 void updateline(int, CELL
*, CELL
*, short *);
48 void mlputi(int, int);
49 void pprints(int, int);
50 void mlputli(long, int);
51 void showCompTitle(void);
53 int dumbroot(int, int);
54 int dumblroot(long, int);
55 unsigned cellwidth_ptr_to_ptr(CELL
*pstart
, CELL
*pend
);
56 unsigned vcellwidth_a_to_b(int row
, int a
, int b
);
57 int window_signature_block(WINDOW
*wp
);
59 void pico_config_menu_items (KEYMENU
*);
60 int update_scroll (void);
65 * Standard pico keymenus...
67 static KEYMENU menu_pico
[] = {
68 {"^G", N_("Get Help"), KS_SCREENHELP
}, {"^O", N_("WriteOut"), KS_SAVEFILE
},
69 {"^R", N_("Read File"), KS_READFILE
}, {"^Y", N_("Prev Pg"), KS_PREVPAGE
},
70 {"^K", N_("Cut Text"), KS_NONE
}, {"^C", N_("Cur Pos"), KS_CURPOSITION
},
71 {"^X", N_("Exit"), KS_EXIT
}, {"^J", N_("Justify"), KS_JUSTIFY
},
72 {"^W", N_("Where is"), KS_WHEREIS
}, {"^V", N_("Next Pg"), KS_NEXTPAGE
},
73 {"^U", NULL
, KS_NONE
},
75 {"^T", N_("To Spell"), KS_SPELLCHK
}
77 {"^D", N_("Del Char"), KS_NONE
}
83 static KEYMENU menu_compose
[] = {
84 {"^G", N_("Get Help"), KS_SCREENHELP
}, {"^X", NULL
, KS_SEND
},
85 {"^R", N_("Read File"), KS_READFILE
}, {"^Y", N_("Prev Pg"), KS_PREVPAGE
},
86 {"^K", N_("Cut Text"), KS_NONE
}, {"^O", N_("Postpone"), KS_POSTPONE
},
87 /* TRANSLATORS: Justify is to reformat a paragraph automatically */
88 {"^C", N_("Cancel"), KS_CANCEL
}, {"^J", N_("Justify"), KS_JUSTIFY
},
89 {NULL
, NULL
, KS_NONE
}, {"^V", N_("Next Pg"), KS_NEXTPAGE
},
90 {"^U", NULL
, KS_NONE
},
92 {"^T", N_("To Spell"), KS_SPELLCHK
}
94 {"^D", N_("Del Char"), KS_NONE
}
103 * Definition's for pico's modeline
105 #define PICO_TITLE " UW PICO %s"
106 #define PICO_MOD_MSG "Modified"
107 #define PICO_NEWBUF_MSG "New Buffer"
109 #define WFDEBUG 0 /* Window flag debug. */
111 #define VFCHG 0x0001 /* Changed flag */
112 #define VFEXT 0x0002 /* extended (beyond column 80) */
113 #define VFREV 0x0004 /* reverse video status */
114 #define VFREQ 0x0008 /* reverse video request */
115 #define VFSIG 0x0010 /* in signature block */
116 #define VFNOR 0x0020 /* in not signature block */
117 #define VFQUO 0x0040 /* in quoted text */
119 int vtrow
= 0; /* Row location of SW cursor */
120 int vtcol
= 0; /* Column location of SW cursor */
121 int vtind
= 0; /* Index into row array of SW cursor */
122 int ttrow
= FARAWAY
; /* Row location of HW cursor */
123 int ttcol
= FARAWAY
; /* Column location of HW cursor */
124 int lbound
= 0; /* leftmost column of current line
127 VIDEO
**vscreen
; /* Virtual screen. */
128 VIDEO
**pscreen
; /* Physical screen. */
132 * Initialize the data structures used by the display code. The edge vectors
133 * used to access the screens are set up. The operating system's terminal I/O
134 * channel is set up. All the other things get initialized at compile time.
135 * The original window has "WFCHG" set, so that it will get completely
136 * redrawn on the first call to "update".
144 PCOLORS
*pcolors
= Pmaster
&& Pmaster
->colors
? Pmaster
->colors
: Pcolors
;
150 vtterminalinfo(gmode
& MDTCAPWINS
);
154 (*term
.t_rev
)(FALSE
);
155 vscreen
= (VIDEO
**) malloc((term
.t_nrow
+1)*sizeof(VIDEO
*));
156 memset(vscreen
, 0, (term
.t_nrow
+1)*sizeof(VIDEO
*));
157 if (vscreen
== NULL
){
158 emlwrite("Allocating memory for virtual display failed.", NULL
);
162 pscreen
= (VIDEO
**) malloc((term
.t_nrow
+1)*sizeof(VIDEO
*));
163 memset(pscreen
, 0, (term
.t_nrow
+1)*sizeof(VIDEO
*));
164 if (pscreen
== NULL
){
165 free((void *)vscreen
);
166 emlwrite("Allocating memory for physical display failed.", NULL
);
171 for (i
= 0; i
<= term
.t_nrow
; ++i
) {
172 vp
= (VIDEO
*) malloc(sizeof(VIDEO
)+(term
.t_ncol
*sizeof(CELL
)));
175 free((void *)vscreen
);
176 free((void *)pscreen
);
177 emlwrite("Allocating memory for virtual display lines failed.",
182 for(j
= 0; j
< term
.t_ncol
; j
++)
188 vp
= (VIDEO
*) malloc(sizeof(VIDEO
)+(term
.t_ncol
*sizeof(CELL
)));
191 free((void *)vscreen
[i
]);
193 free((void *)vscreen
[i
]);
194 free((void *)pscreen
[i
]);
197 free((void *)vscreen
);
198 free((void *)pscreen
);
199 emlwrite("Allocating memory for physical display lines failed.",
204 for(j
= 0; j
< term
.t_ncol
; j
++)
215 vtterminalinfo(int termcap_wins
)
217 return((term
.t_terminalinfo
) ? (*term
.t_terminalinfo
)(termcap_wins
)
218 : (Pmaster
? 0 : TRUE
));
223 * Clean up the virtual terminal system, in anticipation for a return to the
224 * operating system. Move down to the last line and clear it out (the next
225 * system prompt will be written in the line). Shut down the channel to the
231 movecursor(term
.t_nrow
-1, 0);
233 movecursor(term
.t_nrow
, 0);
240 * Set the virtual cursor to the specified row and column on the virtual
241 * screen. There is no checking for nonsense values; this might be a good
242 * idea during the early stages.
245 vtmove(int row
, int col
)
256 * This is unused so don't worry about it.
264 * Write a character to the virtual screen. The virtual row and column are
265 * updated. If the line is too long put a "$" in the last column. This routine
266 * only puts printing characters into the virtual terminal buffers. Only
267 * column overflow is checked.
281 if (vtcol
>= term
.t_ncol
) {
283 * What's this supposed to be doing? This sets vtcol
284 * to the even multiple of 8 >= vtcol. Why are we doing that?
285 * Must make tab work correctly.
293 vtcol
= (vtcol
+ 0x07) & ~0x07;
297 * If we get to here that means that there must be characters
298 * past the right hand edge, so we want to put a $ character
299 * in the last visible character. It would be nice to replace
300 * the last visible character by a double-$ if it is double-width
301 * but we aren't doing that because we'd have to add up the widths
302 * starting at the left hand margin each time through.
304 if(vtind
> 0 && vtind
<= term
.t_ncol
)
305 vp
->v_text
[vtind
-1] = ac
;
307 else if (c
.c
== '\t') {
312 while (((vtcol
+ (vtrow
==currow
? lbound
: 0)) & 0x07) != 0 && vtcol
< term
.t_ncol
);
314 else if (ISCONTROL(c
.c
)){
317 ac
.c
= ((c
.c
& 0x7f) | 0x40);
323 * Have to worry about what happens if we skip over 0
324 * with a double-width character. There may be a better
325 * place to be setting vtind, or maybe we could make do
329 w
= wcellwidth((UCS
) c
.c
);
330 w
= (w
>= 0 ? w
: 1);
332 if(vtcol
== 0 || (vtcol
< 0 && vtcol
+ w
== 1)){
339 * Double-width character overlaps right edge.
340 * Replace it with a $.
342 if(vtcol
+ w
> term
.t_ncol
){
348 if(vtind
>= 0 && vtind
< term
.t_ncol
)
349 vp
->v_text
[vtind
++] = c
;
357 * Erase from the end of the software cursor to the end of the line on which
358 * the software cursor is located.
371 while (vtind
< term
.t_ncol
)
372 vp
->v_text
[vtind
++] = c
;
378 window_signature_block(WINDOW
*wp
)
381 int in_sig
, is_sig_start
;
385 lp
= lforw(wp
->w_bufp
->b_linep
);
388 in_sig
= lback(lp
) == wp
->w_bufp
->b_linep
? 0 : lback(lp
)->l_sig
;
390 if(llength(lp
) == 3){
391 if(lgetc(lp
, 0).c
== '-'
392 && lgetc(lp
, 1).c
== '-'
393 && lgetc(lp
, 2).c
== ' '){
400 if(is_sig_start
== 0) in_sig
= 0;
403 if(lp
->l_sig
!= in_sig
)
407 } while(lp
!= wp
->w_bufp
->b_linep
);
414 * Make sure that the display is right. This is a three part process. First,
415 * scan through all of the windows looking for dirty ones. Check the framing,
416 * and refresh the screen. Second, make sure that "currow" and "curcol" are
417 * correct for the current window. Third, make the virtual and physical
433 PCOLORS
*pcolors
= Pmaster
&& Pmaster
->colors
? Pmaster
->colors
: Pcolors
;
441 /* This tells our MS Windows module to not bother updating the
442 * cursor position while a massive screen update is in progress.
444 mswin_beginupdate ();
448 * BUG: setting and unsetting whole region at a time is dumb. fix this.
458 /* Look at any window with update flags set on. */
461 repaint
= window_signature_block(wp
);
462 if (wp
->w_flag
!= 0){
463 /* If not force reframe, check the framing. */
465 if ((wp
->w_flag
& WFFORCE
) == 0){
468 for (i
= 0; i
< wp
->w_ntrows
; ++i
){
469 if (lp
== wp
->w_dotp
)
472 if (lp
== wp
->w_bufp
->b_linep
)
479 /* Not acceptable, better compute a new value for the line at the
480 * top of the window. Then set the "WFHARD" flag to force full
488 if (i
>= wp
->w_ntrows
)
497 else if(TERM_OPTIMIZE
){
499 * find dotp, if its been moved just above or below the
500 * window, use scrollxxx() to facilitate quick redisplay...
502 lp
= lforw(wp
->w_dotp
);
503 if(lp
!= wp
->w_dotp
){
504 if(lp
== wp
->w_linep
&& lp
!= wp
->w_bufp
->b_linep
){
509 for(j
=0;j
< wp
->w_ntrows
; ++j
){
510 if(lp
!= wp
->w_bufp
->b_linep
)
515 if(lp
== wp
->w_dotp
&& j
== wp
->w_ntrows
)
519 j
= i
= wp
->w_ntrows
/2;
526 while (i
!= 0 && lback(lp
) != wp
->w_bufp
->b_linep
){
532 * this is supposed to speed things up by using tcap sequences
533 * to efficiently scroll the terminal screen. the thinking here
534 * is that its much faster to update pscreen[] than to actually
535 * write the stuff to the screen...
539 case 1: /* scroll text down */
540 j
= j
-i
+1; /* add one for dot line */
542 * do we scroll down the header as well? Well, only
543 * if we're not editing the header, we've backed up
544 * to the top, and the composer is not being
547 if(Pmaster
&& Pmaster
->headents
&& !ComposerEditing
548 && (lback(lp
) == wp
->w_bufp
->b_linep
)
549 && (ComposerTopLine
== COMPOSER_TOP_LINE
))
550 j
+= entry_line(1000, TRUE
); /* Never > 1000 headers */
552 scrolldown(wp
, -1, j
);
554 case 2: /* scroll text up */
555 j
= wp
->w_ntrows
- (j
-i
); /* we chose new top line! */
558 * do we scroll down the header as well? Well, only
559 * if we're not editing the header, we've backed up
560 * to the top, and the composer is not being
564 && (ComposerTopLine
!= COMPOSER_TOP_LINE
))
565 scrollup(wp
, COMPOSER_TOP_LINE
,
566 j
+entry_line(1000, TRUE
));
579 wp
->w_flag
|= WFHARD
; /* Force full. */
582 * if the line at the top of the page is the top line
583 * in the body, show the header...
585 if(Pmaster
&& Pmaster
->headents
&& !ComposerEditing
){
586 if(lback(wp
->w_linep
) == wp
->w_bufp
->b_linep
){
587 if(ComposerTopLine
== COMPOSER_TOP_LINE
){
588 i
= term
.t_nrow
- 2 - term
.t_mrow
- HeaderLen();
589 if(i
> 0 && nlforw() >= i
) { /* room for header ? */
590 if((i
= nlforw()/2) == 0 && term
.t_nrow
&1)
592 while(wp
->w_linep
!= wp
->w_bufp
->b_linep
&& i
--)
593 wp
->w_linep
= lforw(wp
->w_linep
);
601 if(ComposerTopLine
!= COMPOSER_TOP_LINE
)
602 ToggleHeader(0); /* hide it ! */
606 /* Try to use reduced update. Mode line update has its own special
607 * flag. The fast update is used if the only thing to do is within
613 if ((wp
->w_flag
& ~WFMODE
) == WFEDIT
){
614 /* if the signature separator was modified (or created)
615 * do the other side below
617 if(repaint
) goto other
;
618 while (lp
!= wp
->w_dotp
){
623 for (j
= 0, quoted
= -1; j
< llength(lp
); ++j
){
625 if(lgetc(lp
,j
).c
!= '>' && lgetc(lp
, j
).c
!= ' ')
627 else if(lgetc(lp
,j
).c
== '>')
632 vscreen
[i
]->v_flag
&= ~(VFSIG
|VFNOR
|VFQUO
);
633 vscreen
[i
]->v_flag
|= (quoted
> 0 ? VFQUO
: 0)|(lp
->l_sig
? VFSIG
: 0)| VFCHG
;
636 for (j
= 0; j
< llength(lp
); ++j
)
637 vtputc(lgetc(lp
, j
));
640 else if ((wp
->w_flag
& (WFEDIT
| WFHARD
)) != 0){
642 while (i
< wp
->w_toprow
+wp
->w_ntrows
){
644 for (j
= 0, quoted
= -1; j
< llength(lp
) && quoted
< 0; ++j
){
646 if(lgetc(lp
,j
).c
!= '>' && lgetc(lp
, j
).c
!= ' ')
648 else if(lgetc(lp
,j
).c
== '>')
652 if(repaint
&& (vscreen
[i
]->v_flag
& VFSIG
) && lp
->l_sig
== 0)
654 if(quoted
> 0) flag
|= VFQUO
;
655 vscreen
[i
]->v_flag
&= ~(VFSIG
| VFNOR
| VFQUO
);
656 vscreen
[i
]->v_flag
|= flag
| (lp
->l_sig
? VFSIG
: 0 )| VFCHG
;
659 /* if line has been changed */
660 if (lp
!= wp
->w_bufp
->b_linep
){
661 for (j
= 0; j
< llength(lp
); ++j
)
662 vtputc(lgetc(lp
, j
));
672 if ((wp
->w_flag
&WFMODE
) != 0)
685 /* and onward to the next window */
689 /* Always recompute the row and column number of the hardware cursor. This
690 * is the only update for simple moves.
693 currow
= curwp
->w_toprow
;
695 while (lp
!= curwp
->w_dotp
){
703 while (i
< curwp
->w_doto
){
710 else if(ISCONTROL(c
.c
)){
716 w
= wcellwidth((UCS
) c
.c
);
717 curcol
+= (w
>= 0 ? w
: 1);
721 if (curcol
>= term
.t_ncol
) { /* extended line. */
722 /* flag we are extended and changed */
723 vscreen
[currow
]->v_flag
|= VFEXT
| VFCHG
;
724 updext(); /* and output extended line */
726 lbound
= 0; /* not extended line */
728 /* make sure no lines need to be de-extended because the cursor is
738 while (i
< wp
->w_toprow
+ wp
->w_ntrows
) {
739 if (vscreen
[i
]->v_flag
& VFEXT
) {
740 /* always flag extended lines as changed */
741 vscreen
[i
]->v_flag
|= VFCHG
;
742 if ((wp
!= curwp
) || (lp
!= wp
->w_dotp
) ||
743 (curcol
< term
.t_ncol
)) {
745 for (j
= 0; j
< llength(lp
); ++j
)
746 vtputc(lgetc(lp
, j
));
749 /* this line no longer is extended */
750 vscreen
[i
]->v_flag
&= ~VFEXT
;
756 /* and onward to the next window */
760 /* Special hacking if the screen is garbage. Clear the hardware screen,
761 * and update your copy to agree with it. Set all the virtual screen
762 * change bits, to force a full update.
765 if (sgarbf
!= FALSE
){
771 if(ComposerTopLine
!= COMPOSER_TOP_LINE
){
772 UpdateHeader(0); /* arrange things */
773 PaintHeader(COMPOSER_TOP_LINE
, TRUE
);
777 * since we're using only a portion of the screen and only
778 * one buffer, only clear enough screen for the current window
779 * which is to say the *only* window.
781 for(i
=wheadp
->w_toprow
;i
<=term
.t_nrow
; i
++){
784 vscreen
[i
]->v_flag
|= VFCHG
;
786 rv
= (*Pmaster
->showmsg
)('X' & 0x1f); /* ctrl-L */
788 picosigs(); /* restore altered handlers */
789 if(rv
) /* Did showmsg corrupt the display? */
790 PaintBody(0); /* Yes, repaint */
791 movecursor(wheadp
->w_toprow
, 0);
796 for (i
= 0; i
< term
.t_nrow
-term
.t_mrow
; i
++){
797 vscreen
[i
]->v_flag
|= VFCHG
;
799 for (j
= 0; j
< term
.t_ncol
; j
++)
807 movecursor(0, 0); /* Erase the screen. */
812 sgarbf
= FALSE
; /* Erase-page clears */
813 mpresf
= FALSE
; /* the message area. */
818 sgarbk
= TRUE
; /* fix the keyhelp as well...*/
821 /* Make sure that the physical and virtual displays agree. Unlike before,
822 * the "updateline" code is only called with a line that has been updated
830 if (term
.t_nrow
> term
.t_mrow
)
831 c
.c
= term
.t_nrow
- term
.t_mrow
;
835 for (; i
< (int)c
.c
; ++i
){
839 /* for each line that needs to be updated, or that needs its
840 reverse video status changed, call the line updater */
854 updateline(i
, &vp1
->v_text
[0], &vp2
->v_text
[0], &vp1
->v_flag
);
862 movecursor(term
.t_nrow
-1, 0);
864 movecursor(term
.t_nrow
, 0);
869 /* TRANSLATORS: UnJustify means undo the previous
871 menu_pico
[UNCUT_KEY
].label
= N_("UnJustify");
872 if(!(lastflag
&CFFLBF
)){
873 emlwrite(_("Can now UnJustify!"), NULL
);
874 mpresf
= FARAWAY
; /* remove this after next keystroke! */
878 menu_pico
[UNCUT_KEY
].label
= N_("UnCut Text");
886 emlwrite(_("Can now UnJustify!"), NULL
);
887 mpresf
= FARAWAY
; /* remove this after next keystroke! */
890 /* Finally, update the hardware cursor and flush out buffers. */
892 movecursor(currow
, curcol
- lbound
);
897 * Update the scroll bars. This function is where curbp->b_linecnt
898 * is really managed. See update_scroll.
906 /* updext - update the extended line which the cursor is currently
907 * on at a column greater than the terminal width. The line
908 * will be scrolled right or left to let the user see where
914 int rcursor
; /* real cursor location */
915 LINE
*lp
; /* pointer to current line */
916 int j
; /* index into line */
921 * Calculate what column the real cursor will end up in.
922 * The cursor will be in the rcursor'th column. So if we're
923 * counting columns 0 1 2 3 and rcursor is 8, then rcursor
924 * will be over cell 7.
926 * What this effectively does is to scroll the screen as we're
927 * moving to the right when the cursor first passes off the
928 * screen's right edge. It would be nice if it did the same
929 * thing coming back to the left. Instead, in order that the
930 * screen's display depends only on the curcol and not on
931 * how we got there, the screen scrolls when we pass the
932 * t_margin column. It's also kind of funky that you can't
933 * see the character under the $ but you can delete it.
935 rcursor
= ((curcol
- term
.t_ncol
) % (term
.t_ncol
- term
.t_margin
+ 1)) + term
.t_margin
;
936 lbound
= curcol
- rcursor
+ 1;
939 * Make sure lbound is set so that a double-width character does
940 * not straddle the boundary. If it does, move over one cell.
942 lp
= curwp
->w_dotp
; /* line to output */
943 for (j
=0; j
<llength(lp
) && w
< lbound
; ++j
){
944 ww
= wcellwidth((UCS
) lgetc(lp
, j
).c
);
945 w
+= (ww
>= 0 ? ww
: 1);
952 /* scan through the line outputing characters to the virtual screen
953 * once we reach the left edge
955 vtmove(currow
, -lbound
); /* start scanning offscreen */
956 for (j
=0; j
<llength(lp
); ++j
) /* until the end-of-line */
957 vtputc(lgetc(lp
, j
));
959 /* truncate the virtual line */
962 /* and put a '$' in column 1, may have to adjust curcol */
963 w
= wcellwidth((UCS
) vscreen
[currow
]->v_text
[0].c
);
964 vscreen
[currow
]->v_text
[0].c
= '$';
965 vscreen
[currow
]->v_text
[0].a
= 0;
968 * We want to put $ in the first two columns so that it
969 * takes up the right amount of space, but that means we
970 * have to scoot the real characters over one slot.
972 for (j
= term
.t_ncol
-1; j
>= 2; --j
)
973 vscreen
[currow
]->v_text
[j
] = vscreen
[currow
]->v_text
[j
-1];
975 vscreen
[currow
]->v_text
[1].c
= '$';
976 vscreen
[currow
]->v_text
[1].a
= 0;
982 * Update a single line. This does not know how to use insert or delete
983 * character sequences; we are using VT52 functionality. Update the physical
984 * row and column variables.
987 updateline(int row
, /* row on screen */
988 CELL vline
[], /* what we want it to end up as */
989 CELL pline
[], /* what it looks like now */
992 CELL
*cp1
, *cp2
, *cp3
, *cp4
, *cp5
, *cp6
, *cp7
;
994 int nbflag
; /* non-blanks to the right flag? */
996 int in_quote
, quote_found
= 0, level
;
997 PCOLORS
*pcolors
= Pmaster
&& Pmaster
->colors
? Pmaster
->colors
: Pcolors
;
998 COLOR_PAIR
*qcolor
= NULL
, *lastc
= NULL
;
1000 int x
; /* bit to indicate if we should eXecute a block below */
1002 if(row
< 0 || row
> term
.t_nrow
)
1005 /* set up pointers to virtual and physical lines */
1008 cp3
= &vline
[term
.t_ncol
];
1010 /* advance past any common chars at the left */
1011 if(!(*flags
& (VFSIG
|VFNOR
|VFQUO
))
1012 && (pcolors
== NULL
|| vline
[0].c
!= ' '))
1013 while (cp1
!= cp3
&& cp1
[0].c
== cp2
[0].c
&& cp1
[0].a
== cp2
[0].a
) {
1018 /* This can still happen, even though we only call this routine on changed
1019 * lines. A hard update is always done when a line splits, a massive
1020 * change is done, or a buffer is displayed twice. This optimizes out most
1021 * of the excess updating. A lot of computes are used, but these tend to
1022 * be hard operations that do a lot of update, so I don't really care.
1024 /* if both lines are the same, no update needs to be done */
1026 *flags
&= ~VFCHG
; /* mark it clean */
1030 /* find out if there is a match on the right */
1032 cp3
= &vline
[term
.t_ncol
];
1033 cp4
= &pline
[term
.t_ncol
];
1035 if(cellwidth_ptr_to_ptr(cp1
, cp3
) == cellwidth_ptr_to_ptr(cp2
, cp4
))
1036 while (cp3
!= cp1
&& cp3
[-1].c
== cp4
[-1].c
&& cp3
[-1].a
== cp4
[-1].a
) {
1039 if (cp3
[0].c
!= '\0' || cp3
[0].a
!= 0) /* Note if any nonblank */
1040 nbflag
= TRUE
; /* in right match. */
1045 if (nbflag
== FALSE
&& TERM_EOLEXIST
) { /* Erase to EOL ? */
1046 while (cp5
!= cp1
&& cp5
[-1].c
== '\0' && cp5
[-1].a
== 0)
1049 if (cp3
-cp5
<= 3) /* Use only if erase is */
1050 cp5
= cp3
; /* fewer characters. */
1053 /* go to start of differences */
1054 movecursor(row
, cellwidth_ptr_to_ptr(&vline
[0], cp1
));
1056 /* the next code inserts a character or deletes one in the middle
1057 * of a line. However, we do not need this code to work when we
1058 * are using colors that depend on what is inserted/deleted, so
1059 * we defer this work to the code below
1061 x
= pcolors
&& (pcolors
->qlcp
|| pcolors
->qllcp
|| pcolors
->qlllcp
);
1062 if (!nbflag
&& x
== 0) { /* use insert or del char? */
1067 &&(cp7
!=cp2
&& cp6
[0].c
==cp7
[-1].c
&& cp6
[0].a
==cp7
[-1].a
)){
1068 while (cp7
!= cp2
&& cp6
[0].c
==cp7
[-1].c
&& cp6
[0].a
==cp7
[-1].a
){
1073 if (cp7
==cp2
&& cp4
-cp2
> 3){
1076 (*term
.t_rev
)(cp1
->a
); /* set inverse for this char */
1077 o_insert((UCS
) cp1
->c
); /* insert the char */
1078 ww
= wcellwidth((UCS
) cp1
->c
);
1079 ttcol
+= (ww
>= 0 ? ww
: 1);
1080 display
= FALSE
; /* only do it once!! */
1083 else if(TERM_DELCHAR
&& cp3
!= cp1
&& cp7
[0].c
== cp6
[-1].c
1084 && cp7
[0].a
== cp6
[-1].a
){
1085 while (cp6
!= cp1
&& cp7
[0].c
==cp6
[-1].c
&& cp7
[0].a
==cp6
[-1].a
){
1090 if (cp6
==cp1
&& cp5
-cp6
> 3){
1093 w
= wcellwidth((UCS
) cp7
[0].c
);
1094 w
= (w
>= 0 ? w
: 1);
1095 while(w
-- > 0) /* in case double-width char */
1096 o_delete(); /* delete the char */
1097 display
= FALSE
; /* only do it once!! */
1102 if(cp1
== cp5
&& (*flags
& (VFSIG
|VFNOR
|VFQUO
)))
1103 while(cp5
< &vline
[term
.t_ncol
] && cp5
->c
!= '\0')
1106 if(cp1
!= cp5
&& display
){
1110 lastc
= pico_get_cur_color();
1112 pico_set_colorp(pcolors
->tbcp
, PSC_NONE
);
1113 else if(row
< term
.t_nrow
- 2)
1114 pico_set_colorp((*flags
& VFSIG
) ? pcolors
->sbcp
: pcolors
->ntcp
, PSC_NONE
);
1117 * If we need to copy characters from cp1 to cp2 and
1118 * we need to display them, then we have to worry about
1119 * the characters that we are replacing being of a different
1120 * width than the new characters, else the display may be
1123 * If the new width (w1) is less than the old width, that means
1124 * we will leave behind some old remnants if we aren't careful.
1125 * If the new width is larger than the old width, we have to
1126 * make sure we draw the characters all the way to the end
1127 * in order to get it right. Take advantage of clear to end
1128 * of line if we have it.
1130 w1
= cellwidth_ptr_to_ptr(cp1
, cp3
);
1131 w2
= cellwidth_ptr_to_ptr(cp2
, cp2
+ (cp3
-cp1
));
1133 if(w1
< w2
|| (nbflag
&& w1
!= w2
)){
1137 * Draw all of the characters starting with cp1
1138 * until we get to all spaces, then clear to the end of
1139 * line from there. Watch out we don't run over the
1140 * right hand edge, which shouldn't happen.
1142 * Set cp5 to the first of the repeating spaces.
1144 cp5
= &vline
[term
.t_ncol
];
1145 while (cp5
!= cp1
&& cp5
[-1].c
== ' ' && cp5
[-1].a
== 0)
1150 * In the !nbflag case we want spaces from cp5 on.
1151 * Setting cp3 to something different from cp5 triggers
1152 * the clear to end of line below.
1154 if(cellwidth_ptr_to_ptr(&vline
[0], cp5
) < term
.t_ncol
)
1161 * No peeol so draw all the way to the edge whether they
1162 * are spaces or not.
1165 for(w
= 0; w
< term
.t_ncol
; cp3
++){
1168 ww
= wcellwidth((UCS
) cp3
->c
);
1169 w
+= (ww
>= 0 ? ww
: 1);
1179 while (cp1
!= cp5
) { /* Ordinary. */
1184 if(cp1
->c
!= '>' && cp1
->c
!= ' '){
1186 } else if (in_quote
&& cp1
->c
== '>' && pcolors
!= NULL
)
1187 level
= (level
+ 1) % 3;
1189 if(level
== 0) qcolor
= pcolors
->qlcp
;
1190 else if(level
== 1) qcolor
= pcolors
->qllcp
;
1191 else if(level
== 2) qcolor
= pcolors
->qlllcp
;
1192 pico_set_colorp(qcolor
, PSC_NONE
);
1196 /* cp1->c could be null because we set it up that way by default. Initialization
1197 * is made with null characters. We did this because otherwise Pico does not
1198 * color trailing spaces in lines, so this gives a way for pico to distinguish
1199 * trailing spaces in lines from its own old default initialization of cells
1200 * using spaces. So when we get a null character we output the corresponding
1201 * space that would have been output in the past. If you want to see what
1202 * would happen if we output a null character, rewrite the code below.
1204 (*term
.t_rev
)(cp1
->a
); /* set inverse for this char */
1205 (*term
.t_putchar
)(cp1
->c
|| pcolors
== NULL
? cp1
->c
: ' ');
1208 ww
= wcellwidth((UCS
) cp1
->c
);
1209 ttcol
+= (ww
>= 0 ? ww
: 1);
1214 if (pcolors
&& lastc
){
1215 (void)pico_set_colorp(lastc
, PSC_NONE
);
1216 free_color_pair(&lastc
);
1219 (*term
.t_rev
)(0); /* turn off inverse anyway! */
1221 if (cp5
!= cp3
|| cleartoeol
) { /* Erase. */
1229 *flags
&= ~VFCHG
; /* flag this line is changed */
1234 * Redisplay the mode line for the window pointed to by the "wp". This is the
1235 * only routine that has any idea of how the modeline is formatted. You can
1236 * change the modeline format by hacking at this routine. Called by "update"
1237 * any time there is a dirty window.
1240 modeline(WINDOW
*wp
)
1246 menu_compose
[EXIT_KEY
].label
= (Pmaster
->headents
)
1247 ? N_("Send") :N_("Exit");
1248 menu_compose
[PSTPN_KEY
].name
= (Pmaster
->headents
)
1250 menu_compose
[PSTPN_KEY
].label
= (Pmaster
->headents
)
1251 ? N_("Postpone") : NULL
;
1252 menu_compose
[WHERE_KEY
].name
= (Pmaster
->alt_ed
) ? "^_" : "^W";
1253 menu_compose
[WHERE_KEY
].label
= (Pmaster
->alt_ed
) ? N_("Alt Edit")
1255 KS_OSDATASET(&menu_compose
[WHERE_KEY
],
1256 (Pmaster
->alt_ed
) ? KS_ALTEDITOR
: KS_WHEREIS
);
1257 menu_compose
[UNCUT_KEY
].label
= (thisflag
&CFFILL
) ? N_("UnJustify")
1259 wkeyhelp(menu_compose
);
1264 char t1
[NLINE
], t2
[NLINE
], t3
[NLINE
], tline
[NLINE
];
1265 int w1
, w2
, w3
, w1_to_2
, w2_to_3
, w3_to_r
;
1270 vscreen
[0]->v_flag
|= VFCHG
; /* Redraw next time. */
1271 vtmove(0, 0); /* Seek to right line. */
1273 snprintf(t1
, sizeof(t1
), PICO_TITLE
, version
); /* write version */
1276 if(bp
->b_fname
[0]) /* File name? */
1277 snprintf(t2
, sizeof(t2
), "File: %s", bp
->b_fname
);
1279 strncpy(t2
, PICO_NEWBUF_MSG
, sizeof(t2
));
1280 t2
[sizeof(t2
)-1] = '\0';
1283 if(bp
->b_flag
&BFCHG
){ /* "MOD" if changed. */
1284 strncpy(t3
, PICO_MOD_MSG
, sizeof(t3
));
1285 t3
[sizeof(t3
)-1] = '\0';
1290 #define ALLOFTHEM (w1+w1_to_2+w2+w2_to_3+w3+w3_to_r)
1291 #define ALLBUTSPACE (w1+w2+w3+w3_to_r)
1293 w1
= utf8_width(t1
);
1294 w2
= utf8_width(t2
);
1295 w3
= utf8_width(t3
);
1296 w1_to_2
= w2_to_3
= 1; /* min values for separation */
1299 if(ALLOFTHEM
<= term
.t_ncol
){ /* everything fits */
1300 w1_to_2
= (term
.t_ncol
- ALLBUTSPACE
)/2;
1301 w2_to_3
= term
.t_ncol
- (ALLBUTSPACE
+ w1_to_2
);
1306 if(ALLOFTHEM
<= term
.t_ncol
)
1307 w2_to_3
= term
.t_ncol
- (ALLBUTSPACE
+ w1_to_2
);
1309 w1
= w1_to_2
= w3_to_r
= 0;
1310 if(ALLOFTHEM
<= term
.t_ncol
)
1311 w2_to_3
= term
.t_ncol
- (ALLBUTSPACE
+ w1_to_2
);
1314 snprintf(t2
, sizeof(t2
), "%s", bp
->b_fname
);
1315 w2
= utf8_width(t2
);
1318 if(ALLOFTHEM
<= term
.t_ncol
)
1319 w2_to_3
= term
.t_ncol
- (ALLBUTSPACE
+ w1_to_2
);
1322 if(bp
->b_fname
[0] && ALLOFTHEM
<= term
.t_ncol
){
1323 /* reduce size of file */
1324 w2
= term
.t_ncol
- (ALLOFTHEM
- w2
);
1325 t2
[0] = t2
[1] = t2
[2] = '.';
1326 utf8_to_width_rhs(t2
+3, bp
->b_fname
, sizeof(t2
)-3, w2
-3);
1327 w2
= utf8_width(t2
);
1330 w2
= utf8_width(t2
);
1332 if(ALLOFTHEM
<= term
.t_ncol
)
1333 w2_to_3
= term
.t_ncol
- (ALLBUTSPACE
+ w1_to_2
);
1335 w1
= w1_to_2
= w2
= w2_to_3
= w3_to_r
= 0;
1336 if(ALLOFTHEM
<= term
.t_ncol
)
1337 w2_to_3
= term
.t_ncol
- ALLBUTSPACE
;
1346 utf8_snprintf(tline
, sizeof(tline
),
1347 "%*.*w%*.*w%*.*w%*.*w%*.*w%*.*w",
1349 w1_to_2
, w1_to_2
, "",
1351 w2_to_3
, w2_to_3
, "",
1353 w3_to_r
, w3_to_r
, "");
1356 if(utf8_width(tline
) <= term
.t_ncol
)
1357 ucs
= utf8_to_ucs4_cpystr(tline
);
1365 while((c
.c
= CELLMASK
& *ucsp
++))
1368 fs_give((void **) &ucs
);
1376 * Send a command to the terminal to move the hardware cursor to row "row"
1377 * and column "col". The row and column arguments are origin 0. Optimize out
1378 * random calls. Update "ttrow" and "ttcol".
1381 movecursor(int row
, int col
)
1383 if (row
!=ttrow
|| col
!=ttcol
) {
1386 (*term
.t_move
)(MIN(MAX(row
,0),term
.t_nrow
), MIN(MAX(col
,0),term
.t_ncol
-1));
1392 * Erase any sense we have of the cursor's HW location...
1397 ttrow
= ttcol
= FARAWAY
;
1401 get_cursor(int *row
, int *col
)
1411 * Erase the message line. This is a special routine because the message line
1412 * is not considered to be part of the virtual screen. It always works
1413 * immediately; the terminal buffer is flushed via a call to the flusher.
1418 if (term
.t_nrow
< term
.t_mrow
)
1421 movecursor(term
.t_nrow
- term
.t_mrow
, 0);
1423 if (TERM_EOLEXIST
== TRUE
)
1426 if(ttrow
== term
.t_nrow
){
1427 while(ttcol
++ < term
.t_ncol
-1)
1428 (*term
.t_putchar
)(' ');
1431 while(ttcol
++ < term
.t_ncol
) /* track's ttcol */
1432 (*term
.t_putchar
)(' ');
1440 /* returns the chosen dictionary. If one was already chosen
1444 speller_choice(char **sp_list
, int *choice
)
1449 if(sp_list
== NULL
|| sp_list
[0] == NULL
|| sp_list
[0][0] == '\0')
1452 if(choice
&& *choice
>= 0)
1453 return sp_list
[*choice
];
1455 for(cnt
= 0; sp_list
[cnt
] != NULL
&& sp_list
[cnt
][0] != '\0'; cnt
++)
1458 if(cnt
> 10) /* only the first 10 dictionaries */
1461 if(cnt
== 1) /* only one dictionary? choose it! */
1464 if(ch_dict
> cnt
- 1) /* choose again in case something changed */
1467 if(ch_dict
< 0){ /* not a choice yet? do one now! */
1472 EXTRAKEYS menu_dictionary
[] = {
1485 for(i
= 0; i
< cnt
; i
++)
1486 menu_dictionary
[i
].label
= sp_list
[i
];
1489 menu_dictionary
[cnt
].name
= NULL
;
1492 /* write the prompt in utf8, and let internal functions translate it to ucs4 */
1493 ucs4_prompt
= utf8_to_ucs4_cpystr(_("Choose Dictionary: "));
1495 i
= mlchoose(ucs4_prompt
, menu_dictionary
);
1497 if(i
>= '0' && i
<= '9')
1500 if (i
== -2) /* user cancelled */
1504 fs_give((void **)&ucs4_prompt
);
1511 return ch_dict
>= 0 ? sp_list
[ch_dict
] : NULL
;
1514 /* just like mlreplyd, but user cannot fill a prompt */
1516 mlchoose(UCS
*prompt
, EXTRAKEYS
*extras
)
1521 int changed
= FALSE
;
1523 KEYMENU menu_choose
[12];
1524 COLOR_PAIR
*lastc
= NULL
;
1526 for(i
= 0; i
< 12; i
++){
1527 menu_choose
[i
].name
= NULL
;
1528 KS_OSDATASET(&menu_choose
[i
], KS_NONE
);
1531 menu_choose
[0].name
= "^G";
1532 menu_choose
[0].label
= N_("Get Help");
1533 KS_OSDATASET(&menu_choose
[0], KS_SCREENHELP
);
1535 menu_choose
[6].name
= "^C";
1536 menu_choose
[6].label
= N_("Cancel");
1537 KS_OSDATASET(&menu_choose
[6], KS_NONE
);
1539 for(i
= 0; i
< 10; i
++){
1541 menu_choose
[i
/ 2 + 1].name
= extras
[i
].name
;
1542 menu_choose
[i
/ 2 + 1].label
= extras
[i
].label
;
1545 menu_choose
[(i
+ 13) / 2].name
= extras
[i
].name
;
1546 menu_choose
[(i
+ 13) / 2].label
= extras
[i
].label
;
1549 wkeyhelp(menu_choose
); /* paint generic menu */
1550 sgarbk
= TRUE
; /* mark menu dirty */
1551 if(Pmaster
&& curwp
)
1552 curwp
->w_flag
|= WFMODE
;
1554 ucs4_strncpy(buf
, prompt
, NLINE
);
1555 buf
[NLINE
-1] = '\0';
1557 if(Pmaster
&& Pmaster
->colors
&& Pmaster
->colors
->prcp
1558 && pico_is_good_colorpair(Pmaster
->colors
->prcp
)){
1559 lastc
= pico_get_cur_color();
1560 (void) pico_set_colorp(Pmaster
->colors
->prcp
, PSC_NONE
);
1568 for(i
= 0; i
< 10 && extras
[i
].name
!= NULL
&& extras
[i
].key
!= c
; i
++)
1570 if(i
< 10 && extras
[i
].name
)
1573 case (CTRL
|'C') : /* Bail out! */
1575 pputs_utf8(_("Cancel"), 1);
1580 if(term
.t_mrow
== 0 && km_popped
== 0){
1581 movecursor(term
.t_nrow
-2, 0);
1585 (void) pico_set_colorp(lastc
, PSC_NONE
);
1586 free_color_pair(&lastc
);
1591 wkeyhelp(menu_choose
); /* paint generic menu */
1593 if(Pmaster
&& Pmaster
->colors
&& Pmaster
->colors
->prcp
1594 && pico_is_good_colorpair(Pmaster
->colors
->prcp
)){
1595 lastc
= pico_get_cur_color();
1596 (void) pico_set_colorp(Pmaster
->colors
->prcp
, PSC_NONE
);
1601 sgarbk
= TRUE
; /* mark menu dirty */
1605 /* else fall through */
1614 if (return_val
!= -1){ /* abort sets rv = -2, other return values are positive */
1616 (void) pico_set_colorp(lastc
, PSC_NONE
);
1617 free_color_pair(&lastc
);
1624 movecursor(term
.t_nrow
, 0);
1637 mlyesno_utf8(char *utf8prompt
, int dflt
)
1642 prompt
= utf8_to_ucs4_cpystr(utf8prompt
? utf8prompt
: "");
1644 ret
= mlyesno(prompt
, dflt
);
1647 fs_give((void **) &prompt
);
1654 * Ask a yes or no question in the message line. Return either TRUE, FALSE, or
1655 * ABORT. The ABORT status is returned if the user bumps out of the question
1656 * with a ^G. if d >= 0, d is the default answer returned. Otherwise there
1660 mlyesno(UCS
*prompt
, int dflt
)
1663 UCS buf
[NLINE
], lbuf
[10];
1664 KEYMENU menu_yesno
[12];
1665 COLOR_PAIR
*lastc
= NULL
;
1666 PCOLORS
*pcolors
= Pmaster
&& Pmaster
->colors
? Pmaster
->colors
: Pcolors
;
1669 if (mswin_usedialog ())
1670 switch (mswin_yesno (prompt
)) {
1672 case 0: return (ABORT
);
1673 case 1: return (TRUE
);
1674 case 2: return (FALSE
);
1678 for(rv
= 0; rv
< 12; rv
++){
1679 menu_yesno
[rv
].name
= NULL
;
1680 KS_OSDATASET(&menu_yesno
[rv
], KS_NONE
);
1683 menu_yesno
[1].name
= "Y";
1684 menu_yesno
[1].label
= (dflt
== TRUE
) ? "[" N_("Yes") "]" : N_("Yes");
1685 menu_yesno
[6].name
= "^C";
1686 menu_yesno
[6].label
= N_("Cancel");
1687 menu_yesno
[7].name
= "N";
1688 menu_yesno
[7].label
= (dflt
== FALSE
) ? "[" N_("No") "]" : N_("No");
1689 wkeyhelp(menu_yesno
); /* paint generic menu */
1690 sgarbk
= TRUE
; /* mark menu dirty */
1691 if(Pmaster
&& curwp
)
1692 curwp
->w_flag
|= WFMODE
;
1694 ucs4_strncpy(buf
, prompt
, NLINE
);
1695 buf
[NLINE
-1] = '\0';
1696 lbuf
[0] = ' '; lbuf
[1] = '?'; lbuf
[2] = ' '; lbuf
[3] = '\0';
1697 ucs4_strncat(buf
, lbuf
, NLINE
- ucs4_strlen(buf
) - 1);
1698 buf
[NLINE
-1] = '\0';
1700 if(pcolors
&& pcolors
->prcp
1701 && pico_is_good_colorpair(pcolors
->prcp
)){
1702 lastc
= pico_get_cur_color();
1703 (void) pico_set_colorp(pcolors
->prcp
, PSC_NONE
);
1710 case (CTRL
|'M') : /* default */
1712 pputs_utf8((dflt
) ? _("Yes") : _("No"), 1);
1720 case (CTRL
|'C') : /* Bail out! */
1722 pputs_utf8(_("ABORT"), 1);
1729 pputs_utf8(_("Yes"), 1);
1736 pputs_utf8(_("No"), 1);
1741 if(term
.t_mrow
== 0 && km_popped
== 0){
1742 movecursor(term
.t_nrow
-2, 0);
1746 (void) pico_set_colorp(lastc
, PSC_NONE
);
1747 free_color_pair(&lastc
);
1752 wkeyhelp(menu_yesno
); /* paint generic menu */
1754 if(pcolors
&& pcolors
->prcp
1755 && pico_is_good_colorpair(pcolors
->prcp
)){
1756 lastc
= pico_get_cur_color();
1757 (void) pico_set_colorp(pcolors
->prcp
, PSC_NONE
);
1762 sgarbk
= TRUE
; /* mark menu dirty */
1766 /* else fall through */
1777 (void) pico_set_colorp(lastc
, PSC_NONE
);
1778 free_color_pair(&lastc
);
1785 movecursor(term
.t_nrow
, 0);
1798 * Write a prompt into the message line, then read back a response. Keep
1799 * track of the physical position of the cursor. If we are in a keyboard
1800 * macro throw the prompt away, and return the remembered response. This
1801 * lets macros run at full speed. The reply is always terminated by a carriage
1802 * return. Handle erase, kill, and abort keys.
1805 mlreply_utf8(char *utf8prompt
, char *utf8buf
, int nbuf
, int flg
, EXTRAKEYS
*extras
)
1807 return(mlreplyd_utf8(utf8prompt
, utf8buf
, nbuf
, flg
|QDEFLT
, extras
));
1812 mlreply(UCS
*prompt
, UCS
*buf
, int nbuf
, int flg
, EXTRAKEYS
*extras
)
1814 return(mlreplyd(prompt
, buf
, nbuf
, flg
|QDEFLT
, extras
));
1819 * function key mappings
1821 static UCS rfkm
[12][2] = {
1838 mlreplyd_utf8(char *utf8prompt
, char *utf8buf
, int nbuf
, int flg
, EXTRAKEYS
*extras
)
1845 buf
= (UCS
*) fs_get(nbuf
* sizeof(*b
));
1846 b
= utf8_to_ucs4_cpystr(utf8buf
);
1848 ucs4_strncpy(buf
, b
, nbuf
);
1850 fs_give((void **) &b
);
1853 prompt
= utf8_to_ucs4_cpystr(utf8prompt
? utf8prompt
: "");
1855 ret
= mlreplyd(prompt
, buf
, nbuf
, flg
, extras
);
1857 utf8
= ucs4_to_utf8_cpystr(buf
);
1859 strncpy(utf8buf
, utf8
, nbuf
);
1860 utf8buf
[nbuf
-1] = '\0';
1861 fs_give((void **) &utf8
);
1865 fs_give((void **) &buf
);
1868 fs_give((void **) &prompt
);
1882 * mlreplyd - write the prompt to the message line along with a default
1883 * answer already typed in. Carriage return accepts the
1884 * default. answer returned in buf which also holds the initial
1885 * default, nbuf is its length, def set means use default value.
1886 * In order to be able to eliminate keys from a menu, EXTRAKEYS
1887 * always has size 10.
1890 mlreplyd(UCS
*prompt
, UCS
*buf
, int nbuf
, int flg
, EXTRAKEYS
*extras
)
1892 UCS c
; /* current char */
1893 UCS
*b
; /* pointer in buf */
1896 int changed
= FALSE
;
1898 KEYMENU menu_mlreply
[12];
1900 struct display_line dline
;
1901 COLOR_PAIR
*lastc
= NULL
;
1902 PCOLORS
*pcolors
= Pmaster
&& Pmaster
->colors
? Pmaster
->colors
: Pcolors
;
1905 if(mswin_usedialog()){
1906 MDlgButton btn_list
[12];
1907 LPTSTR free_names
[12];
1908 LPTSTR free_labels
[12];
1911 memset(&free_names
, 0, sizeof(LPTSTR
) * 12);
1912 memset(&free_labels
, 0, sizeof(LPTSTR
) * 12);
1913 memset(&btn_list
, 0, sizeof (MDlgButton
) * 12);
1915 for(i
= 0; extras
&& extras
[i
].name
!= NULL
; ++i
) {
1916 if(extras
[i
].label
[0] != '\0') {
1917 if((extras
[i
].key
& CTRL
) == CTRL
)
1918 btn_list
[j
].ch
= (extras
[i
].key
& ~CTRL
) - '@';
1920 btn_list
[j
].ch
= extras
[i
].key
;
1922 btn_list
[j
].rval
= extras
[i
].key
;
1923 free_names
[j
] = utf8_to_lptstr(extras
[i
].name
);
1924 btn_list
[j
].name
= free_names
[j
];
1925 free_labels
[j
] = utf8_to_lptstr(extras
[i
].label
);
1926 btn_list
[j
].label
= free_labels
[j
];
1931 btn_list
[j
].ch
= -1;
1933 return_val
= mswin_dialog(prompt
, buf
, nbuf
, ((flg
&QDEFLT
) > 0),
1934 FALSE
, btn_list
, NULL
, 0);
1937 return_val
= HELPCH
;
1939 for(i
= 0; i
< 12; i
++){
1941 fs_give((void **) &free_names
[i
]);
1943 fs_give((void **) &free_labels
[i
]);
1950 memset(&menu_mlreply
, 0, 12*sizeof(KEYMENU
));
1951 menu_mlreply
[0].name
= "^G";
1952 menu_mlreply
[0].label
= N_("Get Help");
1953 KS_OSDATASET(&menu_mlreply
[0], KS_SCREENHELP
);
1954 for(j
= 0, i
= 1; i
< 6; i
++){ /* insert odd extras */
1955 menu_mlreply
[i
].name
= NULL
;
1956 KS_OSDATASET(&menu_mlreply
[i
], KS_NONE
);
1961 rfkm
[2*i
][1] = extras
[j
].key
;
1962 menu_mlreply
[i
].name
= extras
[j
].name
;
1963 menu_mlreply
[i
].label
= extras
[j
].label
;
1964 KS_OSDATASET(&menu_mlreply
[i
], KS_OSDATAGET(&extras
[j
]));
1969 menu_mlreply
[6].name
= "^C";
1970 menu_mlreply
[6].label
= N_("Cancel");
1971 KS_OSDATASET(&menu_mlreply
[6], KS_NONE
);
1972 for(j
= 0, i
= 7; i
< 12; i
++){ /* insert even extras */
1973 menu_mlreply
[i
].name
= NULL
;
1974 rfkm
[2*(i
-6)+1][1] = 0;
1978 rfkm
[2*(i
-6)+1][1] = extras
[j
].key
;
1979 menu_mlreply
[i
].name
= extras
[j
].name
;
1980 menu_mlreply
[i
].label
= extras
[j
].label
;
1981 KS_OSDATASET(&menu_mlreply
[i
], KS_OSDATAGET(&extras
[j
]));
1986 /* set up what to watch for and return values */
1987 memset(extra_v
, 0, sizeof(extra_v
));
1988 for(i
= 0, j
= 0; i
< 12 && extras
&& extras
[i
].name
; i
++)
1989 extra_v
[j
++] = extras
[i
].key
;
1991 plen
= mlwrite(prompt
, NULL
); /* paint prompt */
1996 dline
.vused
= ucs4_strlen(buf
);
1997 dline
.dwid
= term
.t_ncol
- plen
;
1998 dline
.row
= term
.t_nrow
- term
.t_mrow
;
2001 dline
.dlen
= 2 * dline
.dwid
+ 100;
2003 dline
.dl
= (UCS
*) fs_get(dline
.dlen
* sizeof(UCS
));
2004 dline
.olddl
= (UCS
*) fs_get(dline
.dlen
* sizeof(UCS
));
2005 memset(dline
.dl
, 0, dline
.dlen
* sizeof(UCS
));
2006 memset(dline
.olddl
, 0, dline
.dlen
* sizeof(UCS
));
2008 dline
.movecursor
= movecursor
;
2009 dline
.writechar
= writeachar
;
2012 dline
.vlen
= nbuf
-1;
2015 b
= &buf
[(flg
& QBOBUF
) ? 0 : ucs4_strlen(buf
)];
2017 wkeyhelp(menu_mlreply
); /* paint generic menu */
2019 sgarbk
= 1; /* mark menu dirty */
2021 if(pcolors
&& pcolors
->prcp
2022 && pico_is_good_colorpair(pcolors
->prcp
)){
2023 lastc
= pico_get_cur_color();
2024 (void) pico_set_colorp(pcolors
->prcp
, PSC_NONE
);
2031 line_paint(b
-buf
, &dline
, NULL
);
2035 mouse_in_content(KEY_MOUSE
, -1, -1, 0x5, 0);
2036 register_mfunc(mouse_in_content
,
2037 term
.t_nrow
- term
.t_mrow
, plen
,
2038 term
.t_nrow
- term
.t_mrow
, term
.t_ncol
-1);
2041 mswin_allowpaste(MSWIN_PASTE_LINE
);
2043 while((c
= GetKey()) == NODATA
)
2047 clear_mfunc(mouse_in_content
);
2050 mswin_allowpaste(MSWIN_PASTE_DISABLE
);
2053 switch(c
= normalize_cmd(c
, rfkm
, 1)){
2054 case (CTRL
|'A') : /* CTRL-A beginning */
2059 case (CTRL
|'B') : /* CTRL-B back a char */
2068 case (CTRL
|'C') : /* CTRL-C abort */
2069 pputs_utf8(_("ABORT"), 1);
2074 case (CTRL
|'E') : /* CTRL-E end of line */
2076 b
= &buf
[ucs4_strlen(buf
)];
2079 case (CTRL
|'F') : /* CTRL-F forward a char*/
2088 case (CTRL
|'G') : /* CTRL-G help */
2089 if(term
.t_mrow
== 0 && km_popped
== 0){
2090 movecursor(term
.t_nrow
-2, 0);
2092 sgarbk
= 1; /* mark menu dirty */
2096 (void) pico_set_colorp(lastc
, PSC_NONE
);
2097 free_color_pair(&lastc
);
2102 wkeyhelp(menu_mlreply
); /* paint generic menu */
2103 plen
= mlwrite(prompt
, NULL
); /* paint prompt */
2104 if(pcolors
&& pcolors
->prcp
2105 && pico_is_good_colorpair(pcolors
->prcp
)){
2106 lastc
= pico_get_cur_color();
2107 (void) pico_set_colorp(pcolors
->prcp
, PSC_NONE
);
2116 pputs_utf8(_("HELP"), 1);
2117 return_val
= HELPCH
;
2120 case (CTRL
|'H') : /* CTRL-H backspace */
2121 case 0x7f : /* rubout */
2129 case (CTRL
|'D') : /* CTRL-D delete char */
2139 do /* blat out left char */
2141 while(b
[i
++] != '\0');
2144 case (CTRL
|'L') : /* CTRL-L redraw */
2145 return_val
= (CTRL
|'L');
2148 case (CTRL
|'K') : /* CTRL-K kill line */
2155 case F1
: /* sort of same thing */
2156 return_val
= HELPCH
;
2159 case (CTRL
|'M') : /* newline */
2160 return_val
= changed
;
2168 mouse_get_last (NULL
, &mp
);
2170 /* The clicked line have anything special on it? */
2172 case M_BUTTON_LEFT
: /* position cursor */
2173 mp
.col
-= plen
; /* normalize column */
2174 if(mp
.col
>= 0 && mp
.col
<= ucs4_strlen(buf
))
2179 case M_BUTTON_RIGHT
:
2181 mswin_allowpaste(MSWIN_PASTE_LINE
);
2182 mswin_paste_popup();
2183 mswin_allowpaste(MSWIN_PASTE_DISABLE
);
2187 case M_BUTTON_MIDDLE
: /* NO-OP for now */
2188 default: /* just ignore */
2198 /* look for match in extra_v */
2199 for(i
= 0; i
< 12; i
++)
2200 if(c
&& c
== extra_v
[i
]){
2207 if(c
& (CTRL
| FUNC
)){ /* bag ctrl_special chars */
2212 if(flg
&QNODQT
){ /* reject double quotes? */
2219 if(dline
.vused
>= nbuf
-1){
2224 do /* blat out left char */
2236 (void) pico_set_colorp(lastc
, PSC_NONE
);
2237 free_color_pair(&lastc
);
2246 movecursor(term
.t_nrow
, 0);
2253 fs_give((void **) &dline
.dl
);
2256 fs_give((void **) &dline
.olddl
);
2263 emlwrite(char *utf8message
, EML
*eml
)
2267 message
= utf8_to_ucs4_cpystr(utf8message
? utf8message
: "");
2269 emlwrite_ucs4(message
, eml
);
2272 fs_give((void **) &message
);
2277 * emlwrite() - write the message string to the error half of the screen
2278 * center justified. much like mlwrite (which is still used
2279 * to paint the line for prompts and such), except it center
2283 emlwrite_ucs4(UCS
*message
, EML
*eml
)
2287 COLOR_PAIR
*lastc
= NULL
;
2288 PCOLORS
*pcolors
= Pmaster
&& Pmaster
->colors
? Pmaster
->colors
: Pcolors
;
2292 if(!(message
&& *message
) || term
.t_nrow
< 2)
2293 return; /* nothing to write or no space to write, bag it */
2297 width
= ucs4_str_width(message
);
2300 * next, figure out where the to move the cursor so the message
2301 * comes out centered
2303 if((ap
=ucs4_strchr(message
, '%')) != NULL
){
2308 width
+= (eml
&& eml
->c
) ? wcellwidth(eml
->c
) : 1;
2311 width
+= dumbroot(eml
? eml
->d
: 0, 10);
2314 width
+= dumblroot(eml
? eml
->l
: 0L, 10);
2317 width
+= dumbroot(eml
? eml
->d
: 0, 8);
2320 width
+= dumbroot(eml
? eml
->d
: 0, 16);
2322 case 's': /* string arg is UTF-8 */
2323 width
+= (eml
&& eml
->s
) ? utf8_width(eml
->s
) : 2;
2328 if(width
+4 <= term
.t_ncol
)
2329 movecursor(term
.t_nrow
-term
.t_mrow
, (term
.t_ncol
- (width
+ 4))/2);
2331 movecursor(term
.t_nrow
-term
.t_mrow
, 0);
2333 if(pcolors
&& pcolors
->stcp
2334 && pico_is_good_colorpair(pcolors
->stcp
)){
2335 lastc
= pico_get_cur_color();
2336 (void) pico_set_colorp(pcolors
->stcp
, PSC_NONE
);
2341 pputs_utf8("[ ", 1);
2342 while (*bufp
!= '\0' && ttcol
< term
.t_ncol
-2){
2345 else if(*bufp
== '%'){
2351 pputs_utf8("%c", 0);
2355 mlputi(eml
? eml
->d
: 0, 10);
2358 mlputli(eml
? eml
->l
: 0L, 10);
2361 mlputi(eml
? eml
->d
: 0, 16);
2364 mlputi(eml
? eml
->d
: 0, 8);
2367 pputs_utf8((eml
&& eml
->s
) ? eml
->s
: "%s", 0);
2380 pputs_utf8(" ]", 1);
2383 (void) pico_set_colorp(lastc
, PSC_NONE
);
2384 free_color_pair(&lastc
);
2396 mlwrite_utf8(char *utf8fmt
, void *arg
)
2401 fmt
= utf8_to_ucs4_cpystr(utf8fmt
? utf8fmt
: "");
2402 ret
= mlwrite(fmt
, arg
);
2404 fs_give((void **) &fmt
);
2411 * Write a message into the message line. Keep track of the physical cursor
2412 * position. A small class of printf like format items is handled. Assumes the
2413 * stack grows down; this assumption is made by the "++" in the argument scan
2414 * loop. Set the "message line" flag TRUE.
2417 mlwrite(UCS
*fmt
, void *arg
)
2422 COLOR_PAIR
*lastc
= NULL
;
2423 PCOLORS
*pcolors
= Pmaster
&& Pmaster
->colors
? Pmaster
->colors
: Pcolors
;
2426 * the idea is to only highlight if there is something to show
2429 movecursor(ttrow
, 0);
2431 if(pcolors
&& pcolors
->prcp
2432 && pico_is_good_colorpair(pcolors
->prcp
)){
2433 lastc
= pico_get_cur_color();
2434 (void) pico_set_colorp(pcolors
->prcp
, PSC_NONE
);
2441 while ((c
= *fmt
++) != 0) {
2449 mlputi(*(int *)ap
, 10);
2454 mlputi(*(int *)ap
, 8);
2459 mlputi(*(int *)ap
, 16);
2464 mlputli(*(long *)ap
, 10);
2469 pputs_utf8(*(char **)ap
, 1);
2470 ap
+= sizeof(char *);
2476 ttcol
+= (ww
>= 0 ? ww
: 1);
2482 while(ttcol
< term
.t_ncol
)
2485 movecursor(term
.t_nrow
- term
.t_mrow
, ret
);
2488 (void) pico_set_colorp(lastc
, PSC_NONE
);
2489 free_color_pair(&lastc
);
2502 * Write out an integer, in the specified radix. Update the physical cursor
2503 * position. This will not handle any negative numbers; maybe it should.
2506 mlputi(int i
, int r
)
2509 static char hexdigits
[] = "0123456789ABCDEF";
2521 pputc(hexdigits
[i
%r
], 1);
2526 * do the same except as a long integer.
2529 mlputli(long l
, int r
)
2543 pputc((int)(l
%r
)+'0', 1);
2548 unknown_command(UCS c
)
2550 char buf
[10], ch
, *s
;
2559 else if(c
& CTRL
&& c
>= (CTRL
|'@') && c
<= (CTRL
|'_')){
2560 ch
= c
- (CTRL
|'@') + '@';
2561 snprintf(s
, sizeof(buf
), "^%c", ch
);
2565 case ' ' : s
= "SPACE"; break;
2566 case '\033' : s
= "ESC"; break;
2567 case '\177' : s
= "DEL"; break;
2568 case ctrl('I') : s
= "TAB"; break;
2569 case ctrl('J') : s
= "LINEFEED"; break;
2570 case ctrl('M') : s
= "RETURN"; break;
2571 case ctrl('Q') : s
= "XON"; break;
2572 case ctrl('S') : s
= "XOFF"; break;
2573 case KEY_UP
: s
= "Up Arrow"; break;
2574 case KEY_DOWN
: s
= "Down Arrow"; break;
2575 case KEY_RIGHT
: s
= "Right Arrow"; break;
2576 case KEY_LEFT
: s
= "Left Arrow"; break;
2577 case CTRL
|KEY_UP
: s
= "Ctrl-Up Arrow"; break;
2578 case CTRL
|KEY_DOWN
: s
= "Ctrl-Down Arrow"; break;
2579 case CTRL
|KEY_RIGHT
: s
= "Ctrl-Right Arrow"; break;
2580 case CTRL
|KEY_LEFT
: s
= "Ctrl-Left Arrow"; break;
2581 case KEY_PGUP
: s
= "Prev Page"; break;
2582 case KEY_PGDN
: s
= "Next Page"; break;
2583 case KEY_HOME
: s
= "Home"; break;
2584 case KEY_END
: s
= "End"; break;
2585 case KEY_DEL
: s
= "Delete"; break; /* Not necessary DEL! */
2598 snprintf(s
, sizeof(buf
), "F%ld", (long) (c
- PF1
+ 1));
2603 utf8_put((unsigned char *) s
, (unsigned long) c
);
2609 emlwrite("Unknown Command: %s", &eml
);
2615 * scrolldown - use stuff to efficiently move blocks of text on the
2616 * display, and update the pscreen array to reflect those
2619 * wp is the window to move in
2620 * r is the row at which to begin scrolling
2621 * n is the number of lines to scrol
2624 scrolldown(WINDOW
*wp
, int r
, int n
)
2629 register VIDEO
*vp1
;
2630 register VIDEO
*vp2
;
2640 if(r
> wp
->w_toprow
)
2641 vscreen
[r
-1]->v_flag
|= VFCHG
;
2642 l
= wp
->w_toprow
+wp
->w_ntrows
-r
;
2647 for(i
=l
-n
-1; i
>= 0; i
--){
2649 vp2
= pscreen
[r
+i
+n
];
2650 memcpy(vp2
, vp1
, term
.t_ncol
* sizeof(CELL
));
2655 #endif /* TERMCAP */
2660 * scrollup - use tcap stuff to efficiently move blocks of text on the
2661 * display, and update the pscreen array to reflect those
2665 scrollup(WINDOW
*wp
, int r
, int n
)
2669 register VIDEO
*vp1
;
2670 register VIDEO
*vp2
;
2683 if(!(r
+i
+n
< wp
->w_toprow
+wp
->w_ntrows
))
2687 if(!((i
< wp
->w_ntrows
-n
)&&(r
+i
+n
< wp
->w_toprow
+wp
->w_ntrows
)))
2690 vp1
= pscreen
[r
+i
+n
];
2692 memcpy(vp2
, vp1
, term
.t_ncol
* sizeof(CELL
));
2695 pprints(wp
->w_toprow
+wp
->w_ntrows
-n
, wp
->w_toprow
+wp
->w_ntrows
-1);
2698 #endif /* TERMCAP */
2703 * print spaces in the physical screen starting from row abs(n) working in
2704 * either the positive or negative direction (depending on sign of n).
2707 pprints(int x
, int y
)
2713 for(i
= x
;i
<= y
; ++i
){
2714 for(j
= 0; j
< term
.t_ncol
; j
++){
2715 pscreen
[i
]->v_text
[j
].c
= ' ';
2716 pscreen
[i
]->v_text
[j
].a
= 0;
2721 for(i
= x
;i
>= y
; --i
){
2722 for(j
= 0; j
< term
.t_ncol
; j
++){
2723 pscreen
[i
]->v_text
[j
].c
= ' ';
2724 pscreen
[i
]->v_text
[j
].a
= 0;
2734 * doton - return the physical line number that the dot is on in the
2735 * current window, and by side effect the number of lines remaining
2738 doton(int *r
, unsigned *chs
)
2741 register LINE
*lp
= curwp
->w_linep
;
2744 assert(r
!= NULL
&& chs
!= NULL
);
2747 while(i
++ < curwp
->w_ntrows
){
2748 if(lp
== curwp
->w_dotp
)
2751 if(lp
== curwp
->w_bufp
->b_linep
){
2756 (*chs
) += llength(lp
);
2758 *r
= i
- l
- term
.t_mrow
;
2759 return(l
+curwp
->w_toprow
);
2765 * resize_pico - given new window dimensions, allocate new resources
2768 resize_pico(int row
, int col
)
2770 int old_nrow
, old_ncol
;
2774 old_nrow
= term
.t_nrow
;
2775 old_ncol
= term
.t_ncol
;
2780 if (old_ncol
== term
.t_ncol
&& old_nrow
== term
.t_nrow
)
2784 curwp
->w_toprow
= 2;
2785 curwp
->w_ntrows
= term
.t_nrow
- curwp
->w_toprow
- term
.t_mrow
;
2789 fillcol
= Pmaster
->fillcolumn
;
2790 (*Pmaster
->resize
)();
2792 else if(userfillcol
> 0)
2793 fillcol
= userfillcol
;
2795 fillcol
= term
.t_ncol
- 6; /* we control the fill column */
2798 * free unused screen space ...
2800 for(i
=term
.t_nrow
+1; i
<= old_nrow
; ++i
){
2801 free((char *) vscreen
[i
]);
2802 free((char *) pscreen
[i
]);
2806 * realloc new space for screen ...
2808 if((vscreen
=(VIDEO
**)realloc(vscreen
,(term
.t_nrow
+1)*sizeof(VIDEO
*))) == NULL
){
2815 if((pscreen
=(VIDEO
**)realloc(pscreen
,(term
.t_nrow
+1)*sizeof(VIDEO
*))) == NULL
){
2822 for (i
= 0; i
<= term
.t_nrow
; ++i
) {
2824 vp
= (VIDEO
*) realloc(vscreen
[i
], sizeof(VIDEO
)+(term
.t_ncol
*sizeof(CELL
)));
2826 vp
= (VIDEO
*) malloc(sizeof(VIDEO
)+(term
.t_ncol
*sizeof(CELL
)));
2832 if(old_ncol
< term
.t_ncol
){ /* don't let any garbage in */
2834 vtcol
= (i
< old_nrow
) ? old_ncol
: 0;
2839 vp
= (VIDEO
*) realloc(pscreen
[i
], sizeof(VIDEO
)+(term
.t_ncol
*sizeof(CELL
)));
2841 vp
= (VIDEO
*) malloc(sizeof(VIDEO
)+(term
.t_ncol
*sizeof(CELL
)));
2850 if(!ResizeBrowser()){
2851 if(Pmaster
&& Pmaster
->headents
){
2855 curwp
->w_flag
|= (WFHARD
| WFMODE
);
2856 pico_refresh(0, 1); /* redraw whole enchilada. */
2857 update(); /* do it */
2865 redraw_pico_for_callback(void)
2873 * showCompTitle - display the anchor line passed in from pine
2880 extern UCS
*pico_anchor
;
2881 COLOR_PAIR
*lastc
= NULL
;
2883 if((bufp
= pico_anchor
) == NULL
)
2886 movecursor(COMPOSER_TITLE_LINE
, 0);
2887 if (Pmaster
->colors
&& Pmaster
->colors
->tbcp
&&
2888 pico_is_good_colorpair(Pmaster
->colors
->tbcp
)){
2889 lastc
= pico_get_cur_color();
2890 (void)pico_set_colorp(Pmaster
->colors
->tbcp
, PSC_NONE
);
2895 while (ttcol
< term
.t_ncol
)
2902 (void)pico_set_colorp(lastc
, PSC_NONE
);
2903 free_color_pair(&lastc
);
2908 movecursor(COMPOSER_TITLE_LINE
+ 1, 0);
2916 * zotdisplay - blast malloc'd space created for display maps
2923 for (i
= 0; i
<= term
.t_nrow
; ++i
){ /* free screens */
2924 free((char *) vscreen
[i
]);
2925 free((char *) pscreen
[i
]);
2928 free((char *) vscreen
);
2929 free((char *) pscreen
);
2935 * nlforw() - returns the number of lines from the top to the dot
2941 register LINE
*lp
= curwp
->w_linep
;
2943 while(lp
!= curwp
->w_dotp
){
2953 * pputc - output the given char, keep track of it on the physical screen
2954 * array, and keep track of the cursor
2957 pputc(UCS c
, /* char to write */
2958 int a
) /* and its attribute */
2960 int ind
, width
, printable_ascii
= 0;
2963 * This is necessary but not sufficient to allow us to draw. Note that
2964 * ttrow runs from 0 to t_nrow (so total number of rows is t_nrow+1)
2965 * ttcol runs from 0 to t_ncol-1 (so total number of cols is t_ncol)
2967 if((ttcol
>= 0 && ttcol
< term
.t_ncol
) && (ttrow
>= 0 && ttrow
<= term
.t_nrow
)){
2970 * Width is the number of screen columns a character will occupy.
2972 if(c
< 0x80 && isprint(c
)){
2977 width
= wcellwidth(c
);
2980 width
= 1; /* will be a '?' */
2982 if(ttcol
+ width
<= term
.t_ncol
){ /* it fits */
2984 * Some terminals scroll when you write in the lower right corner
2985 * of the screen, so don't write there.
2987 if(!(ttrow
== term
.t_nrow
&& ttcol
+width
== term
.t_ncol
)){
2988 (*term
.t_putchar
)(c
); /* write it */
2989 ind
= index_from_col(ttrow
, ttcol
);
2990 pscreen
[ttrow
]->v_text
[ind
].c
= c
; /* keep track of it */
2991 pscreen
[ttrow
]->v_text
[ind
].a
= a
; /* keep track of it */
2996 * Character overlaps right edge of screen. Hopefully the higher
2997 * layers will prevent this but we're making sure.
2999 * We may want to do something like writing a space character
3000 * into the cells that are on the screen. We'll see.
3004 ttcol
= MIN(term
.t_ncol
, ttcol
+width
);
3010 * pputs - print a string and keep track of the cursor
3013 pputs(UCS
*s
, /* string to write */
3014 int a
) /* and its attribute */
3022 pputs_utf8(char *s
, int a
)
3027 ucsstr
= utf8_to_ucs4_cpystr(s
);
3030 fs_give((void **) &ucsstr
);
3037 * peeol - physical screen array erase to end of the line. remember to
3043 int i
, width
= 0, ww
;
3046 if(ttrow
< 0 || ttrow
> term
.t_nrow
)
3053 * Don't clear if we think we are sitting past the last column,
3054 * that erases the last column if we just wrote it.
3056 if(ttcol
< term
.t_ncol
)
3060 * Because the characters are variable width it's a little tricky
3061 * to erase the rest of the line. What we do is add up the
3062 * widths of the characters until we reach ttcol
3063 * then set the rest to the space character.
3065 for(i
= 0; i
< term
.t_ncol
&& width
< ttcol
; i
++){
3066 ww
= wcellwidth((UCS
) pscreen
[ttrow
]->v_text
[i
].c
);
3067 width
+= (ww
>= 0 ? ww
: 1);
3070 while(i
< term
.t_ncol
)
3071 pscreen
[ttrow
]->v_text
[i
++] = cl
;
3076 * pscr - return the character cell on the physical screen map on the
3077 * given line, l, and offset, o.
3082 if((l
>= 0 && l
<= term
.t_nrow
) && (o
>= 0 && o
< term
.t_ncol
))
3083 return(&(pscreen
[l
]->v_text
[o
]));
3090 * pclear() - clear the physical screen from row x through row y (inclusive)
3091 * row is zero origin, min row = 0 max row = t_nrow
3092 * Clear whole screen -- pclear(0, term.t_nrow)
3093 * Clear bottom two rows -- pclear(term.t_nrow-1, term.t_nrow)
3094 * Clear bottom three rows -- pclear(term.t_nrow-2, term.t_nrow)
3097 pclear(int x
, int y
)
3101 x
= MIN(MAX(0, x
), term
.t_nrow
);
3102 y
= MIN(MAX(0, y
), term
.t_nrow
);
3104 for(i
=x
; i
<= y
; i
++){
3112 * dumbroot - just get close
3115 dumbroot(int x
, int b
)
3120 return(dumbroot(x
/b
, b
) + 1);
3125 * dumblroot - just get close
3128 dumblroot(long x
, int b
)
3133 return(dumblroot(x
/b
, b
) + 1);
3138 * pinsertc - use optimized insert, fixing physical screen map.
3139 * returns true if char written, false otherwise
3147 if(ttrow
< 0 || ttrow
> term
.t_nrow
)
3150 if(o_insert((UCS
) c
.c
)){ /* if we've got it, use it! */
3151 p
= pscreen
[ttrow
]->v_text
; /* then clean up physical screen */
3153 ind
= index_from_col(ttrow
, ttcol
);
3155 for(i
= term
.t_ncol
-1; i
> ind
; i
--)
3156 p
[i
] = p
[i
-1]; /* shift right */
3158 p
[ind
] = c
; /* insert new char */
3160 ww
= wcellwidth((UCS
) c
.c
);
3161 ttcol
+= (ww
>= 0 ? ww
: 1);
3171 * pdel - use optimized delete to rub out the current char and
3172 * fix the physical screen array.
3173 * returns true if optimized the delete, false otherwise
3181 if(ttrow
< 0 || ttrow
> term
.t_nrow
)
3184 if(TERM_DELCHAR
){ /* if we've got it, use it! */
3185 p
= pscreen
[ttrow
]->v_text
;
3186 ind
= index_from_col(ttrow
, ttcol
);
3190 w
= wcellwidth((UCS
) p
[ind
].c
);
3191 w
= (w
>= 0 ? w
: 1);
3194 for(i
= 0; i
< w
; i
++){
3195 (*term
.t_putchar
)('\b'); /* move left a char */
3196 o_delete(); /* and delete it */
3199 /* then clean up physical screen */
3200 for(i
=ind
; i
< term
.t_ncol
-1; i
++)
3216 * wstripe - write out the given string at the given location, and reverse
3217 * video on flagged characters. Does the same thing as pine's
3220 * I believe this needs to be fixed to work with non-ascii utf8pmt, but maybe
3221 * only if you want to put the tildes before multi-byte chars.
3224 wstripe(int line
, int column
, char *utf8pmt
, int key
)
3230 COLOR_PAIR
*lastc
= NULL
;
3231 COLOR_PAIR
*kncp
= NULL
;
3232 COLOR_PAIR
*klcp
= NULL
;
3234 if(line
< 0 || line
> term
.t_nrow
)
3237 if (Pmaster
&& Pmaster
->colors
){
3238 if(pico_is_good_colorpair(Pmaster
->colors
->klcp
))
3239 klcp
= Pmaster
->colors
->klcp
;
3241 if(klcp
&& pico_is_good_colorpair(Pmaster
->colors
->kncp
))
3242 kncp
= Pmaster
->colors
->kncp
;
3245 klcp
= Pcolors
->klcp
;
3246 kncp
= Pcolors
->kncp
;
3249 lastc
= pico_get_cur_color();
3250 ucs4pmt
= utf8_to_ucs4_cpystr(utf8pmt
);
3251 l
= ucs4_strlen(ucs4pmt
);
3253 if(i
>= term
.t_ncol
|| col
>= term
.t_ncol
|| j
>= l
)
3254 return; /* equal strings */
3256 if(ucs4pmt
[j
] == (UCS
) key
)
3259 if (pscr(line
, i
) == NULL
)
3262 if(pscr(line
, i
)->c
!= ucs4pmt
[j
]){
3263 if(j
>= 1 && ucs4pmt
[j
-1] == (UCS
) key
)
3268 ww
= wcellwidth((UCS
) pscr(line
, i
)->c
);
3269 col
+= (ww
>= 0 ? ww
: 1);
3274 movecursor(line
, column
+col
);
3275 if(klcp
) (void)pico_set_colorp(klcp
, PSC_NONE
);
3278 if(*u
== (UCS
) key
){
3281 (void)pico_set_colorp(kncp
, PSC_NONE
);
3283 (void)(*term
.t_rev
)(1);
3287 (void)pico_set_colorp(klcp
, PSC_NONE
);
3289 (void)(*term
.t_rev
)(0);
3295 while(*++u
!= '\0');
3298 fs_give((void **) &ucs4pmt
);
3302 (void)pico_set_colorp(lastc
, PSC_NONE
);
3303 free_color_pair(&lastc
);
3311 * wkeyhelp - paint list of possible commands on the bottom
3312 * of the display (yet another pine clone)
3313 * NOTE: function key mode is handled here since all the labels
3316 * The KEYMENU definitions have names and labels defined as UTF-8 strings,
3317 * and wstripe expects UTF-8.
3320 wkeyhelp(KEYMENU
*keymenu
)
3322 char *obufp
, *p
, fkey
[4];
3323 char linebuf
[2*NLINE
]; /* "2" is for space for invert tokens */
3324 int row
, slot
, tspace
, adjusted_tspace
, nspace
[6], index
, n
;
3330 pico_config_menu_items (keymenu
);
3333 if(term
.t_mrow
== 0)
3340 * Calculate amount of space for the names column by column...
3342 for(index
= 0; index
< 6; index
++)
3343 if(!(gmode
&MDFKEY
)){
3344 nspace
[index
] = (keymenu
[index
].name
)
3345 ? utf8_width(keymenu
[index
].name
) : 0;
3346 if(keymenu
[index
+6].name
3347 && (n
= utf8_width(keymenu
[index
+6].name
)) > nspace
[index
])
3353 nspace
[index
] = (index
< 4) ? 3 : 4;
3355 tspace
= term
.t_ncol
/6; /* total space for each item */
3358 * Avoid writing in bottom right corner so we won't scroll screens that
3359 * scroll when you do that. The way this is setup, we won't do that
3360 * unless the number of columns is evenly divisible by 6.
3362 adjusted_tspace
= (6 * tspace
== term
.t_ncol
) ? tspace
- 1 : tspace
;
3365 for(row
= 0; row
<= 1; row
++){
3367 obufp
= &linebuf
[0];
3368 for(slot
= 0; slot
< 6; slot
++){
3369 if(keymenu
[index
].name
&& keymenu
[index
].label
){
3371 char this_label
[200], tmp_label
[200];
3373 if(keymenu
[index
].label
[0] == '[' && keymenu
[index
].label
[(l
=strlen(keymenu
[index
].label
))-1] == ']' && l
> 2){
3374 strncpy(tmp_label
, &keymenu
[index
].label
[1], MIN(sizeof(tmp_label
),l
-2));
3375 tmp_label
[MIN(sizeof(tmp_label
)-1,l
-2)] = '\0';
3376 snprintf(this_label
, sizeof(this_label
), "[%s]", _(tmp_label
));
3379 strncpy(this_label
, _(keymenu
[index
].label
), sizeof(this_label
));
3381 this_label
[sizeof(this_label
)-1] = '\0';
3385 snprintf(fkey
, sizeof(fkey
), "F%d", (2 * slot
) + row
+ 1);
3388 p
= keymenu
[index
].name
;
3390 snprintf(nbuf
, sizeof(nbuf
), "%.*s %s", nspace
[slot
], p
, this_label
);
3392 (gmode
&MDFKEY
) ? F1
+ (2 * slot
) + row
:
3393 (keymenu
[index
].name
[0] == '^')
3394 ? (CTRL
| keymenu
[index
].name
[1])
3395 : (keymenu
[index
].name
[0] == 'S'
3396 && !strcmp(keymenu
[index
].name
, "Spc"))
3398 : keymenu
[index
].name
[0],
3400 term
.t_nrow
- 1 + row
, (slot
* tspace
),
3402 (Pmaster
&& Pmaster
->colors
)
3403 ? Pmaster
->colors
->kncp
: NULL
,
3404 (Pmaster
&& Pmaster
->colors
)
3405 ? Pmaster
->colors
->klcp
: NULL
);
3409 while(p
&& *p
&& n
--){
3410 *obufp
++ = '~'; /* insert "invert" token */
3418 n
= ((slot
== 5 && row
== 1) ? adjusted_tspace
3419 : tspace
) - nspace
[slot
];
3420 while(p
&& *p
&& n
-- > 0)
3427 n
= (slot
== 5 && row
== 1) ? adjusted_tspace
: tspace
;
3432 register_key(index
, NODATA
, "", NULL
, 0, 0, 0, NULL
, NULL
);
3440 wstripe(term
.t_nrow
- 1 + row
, 0, linebuf
, '~');
3446 * This returns the screen width between pstart (inclusive) and
3447 * pend (exclusive) where the pointers point into an array of CELLs.
3450 cellwidth_ptr_to_ptr(CELL
*pstart
, CELL
*pend
)
3457 for(p
= pstart
; p
< pend
; p
++){
3458 ww
= wcellwidth((UCS
) p
->c
);
3459 width
+= (ww
>= 0 ? ww
: 1);
3467 * This returns the virtual screen width in row from index a to b (exclusive).
3470 vcellwidth_a_to_b(int row
, int a
, int b
)
3472 CELL
*pstart
, *pend
;
3475 if(row
< 0 || row
> term
.t_nrow
)
3481 a
= MIN(MAX(0, a
), term
.t_ncol
-1);
3482 b
= MIN(MAX(0, a
), term
.t_ncol
); /* b is past where we stop */
3485 pstart
= &vp
->v_text
[a
];
3486 pend
= &vp
->v_text
[b
];
3488 return(cellwidth_ptr_to_ptr(pstart
, pend
));
3493 * This returns the physical screen width in row from index a to b (exclusive).
3496 pcellwidth_a_to_b(int row
, int a
, int b
)
3498 CELL
*pstart
, *pend
;
3501 if(row
< 0 || row
> term
.t_nrow
)
3507 a
= MIN(MAX(0, a
), term
.t_ncol
-1);
3508 b
= MIN(MAX(0, a
), term
.t_ncol
); /* b is past where we stop */
3511 pstart
= &vp
->v_text
[a
];
3512 pend
= &vp
->v_text
[b
];
3514 return(cellwidth_ptr_to_ptr(pstart
, pend
));
3519 index_from_col(int row
, int col
)
3521 CELL
*p_start
, *p_end
, *p_limit
;
3522 int w_consumed
= 0, w
, done
= 0;
3524 if(row
< 0 || row
> term
.t_nrow
)
3527 p_end
= p_start
= pscreen
[row
]->v_text
;
3528 p_limit
= p_start
+ term
.t_ncol
;
3531 while(!done
&& p_end
< p_limit
&& p_end
->c
&& w_consumed
<= col
){
3532 w
= wcellwidth((UCS
) p_end
->c
);
3533 w
= (w
>= 0 ? w
: 1);
3534 if(w_consumed
+ w
<= col
){
3542 /* MIN and MAX just to be sure */
3543 return(MIN(MAX(0, p_end
- p_start
), term
.t_ncol
-1));
3549 pico_config_menu_items (KEYMENU
*keymenu
)
3555 mswin_menuitemclear ();
3557 /* keymenu's seem to be hardcoded at 12 entries. */
3558 for (i
= 0, k
= keymenu
; i
< 12; ++i
, ++k
) {
3559 if (k
->name
!= NULL
&& k
->label
!= NULL
&&
3560 k
->menuitem
!= KS_NONE
) {
3562 if (k
->name
[0] == '^')
3563 key
= CTRL
| k
->name
[1];
3564 else if (strcmp(k
->name
, "Ret") == 0)
3569 mswin_menuitemadd (key
, k
->label
, k
->menuitem
, 0);
3575 * Update the scroll range and position. (exported)
3577 * This is where curbp->b_linecnt is really managed. With out this function
3578 * to count the number of lines when needed curbp->b_linecnt will never
3579 * really be correct. BUT, this function is only compiled into the
3580 * windows version, so b_linecnt will only ever be right in the windows
3581 * version. OK for now because that is the only version that
3582 * looks at b_linecnt.
3585 update_scroll (void)
3590 static LINE
*last_top_line
= NULL
;
3591 static long last_scroll_pos
= -1;
3594 if (ComposerEditing
) {
3595 /* Editing header - don't allow scroll bars. */
3596 mswin_setscrollrange (0, 0);
3602 * Count the number of lines in the current bufer. Done when:
3604 * when told to recount: curbp->b_linecnt == -1
3605 * when the top line changed: curwp->w_linep != last_top_line
3606 * when we don't know the scroll pos: last_scroll_pos == -1
3608 * The first line in the list is a "place holder" line and is not
3609 * counted. The list is circular, when we return the to place
3610 * holder we have reached the end.
3612 if(curbp
->b_linecnt
== -1 || curwp
->w_linep
!= last_top_line
3613 || last_scroll_pos
== -1) {
3616 for (lp
= lforw (curbp
->b_linep
); lp
!= curbp
->b_linep
;
3618 if (lp
== curwp
->w_linep
)
3619 scr_pos
= scr_range
;
3624 curbp
->b_linecnt
= scr_range
;
3625 last_scroll_pos
= scr_pos
;
3626 last_top_line
= curwp
->w_linep
;
3630 * Set new scroll range and position.
3632 mswin_setscrollrange (curwp
->w_ntrows
- 2, curbp
->b_linecnt
- 1);
3633 mswin_setscrollpos (last_scroll_pos
);
3636 #endif /* _WINDOWS */