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-2014 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
);
58 void pico_config_menu_items (KEYMENU
*);
59 int update_scroll (void);
64 * Standard pico keymenus...
66 static KEYMENU menu_pico
[] = {
67 {"^G", N_("Get Help"), KS_SCREENHELP
}, {"^O", N_("WriteOut"), KS_SAVEFILE
},
68 {"^R", N_("Read File"), KS_READFILE
}, {"^Y", N_("Prev Pg"), KS_PREVPAGE
},
69 {"^K", N_("Cut Text"), KS_NONE
}, {"^C", N_("Cur Pos"), KS_CURPOSITION
},
70 {"^X", N_("Exit"), KS_EXIT
}, {"^J", N_("Justify"), KS_JUSTIFY
},
71 {"^W", N_("Where is"), KS_WHEREIS
}, {"^V", N_("Next Pg"), KS_NEXTPAGE
},
72 {"^U", NULL
, KS_NONE
},
74 {"^T", N_("To Spell"), KS_SPELLCHK
}
76 {"^D", N_("Del Char"), KS_NONE
}
82 static KEYMENU menu_compose
[] = {
83 {"^G", N_("Get Help"), KS_SCREENHELP
}, {"^X", NULL
, KS_SEND
},
84 {"^R", N_("Read File"), KS_READFILE
}, {"^Y", N_("Prev Pg"), KS_PREVPAGE
},
85 {"^K", N_("Cut Text"), KS_NONE
}, {"^O", N_("Postpone"), KS_POSTPONE
},
86 /* TRANSLATORS: Justify is to reformat a paragraph automatically */
87 {"^C", N_("Cancel"), KS_CANCEL
}, {"^J", N_("Justify"), KS_JUSTIFY
},
88 {NULL
, NULL
, KS_NONE
}, {"^V", N_("Next Pg"), KS_NEXTPAGE
},
89 {"^U", NULL
, KS_NONE
},
91 {"^T", N_("To Spell"), KS_SPELLCHK
}
93 {"^D", N_("Del Char"), KS_NONE
}
102 * Definition's for pico's modeline
104 #define PICO_TITLE " UW PICO %s"
105 #define PICO_MOD_MSG "Modified"
106 #define PICO_NEWBUF_MSG "New Buffer"
108 #define WFDEBUG 0 /* Window flag debug. */
110 #define VFCHG 0x0001 /* Changed flag */
111 #define VFEXT 0x0002 /* extended (beyond column 80) */
112 #define VFREV 0x0004 /* reverse video status */
113 #define VFREQ 0x0008 /* reverse video request */
115 int vtrow
= 0; /* Row location of SW cursor */
116 int vtcol
= 0; /* Column location of SW cursor */
117 int vtind
= 0; /* Index into row array of SW cursor */
118 int ttrow
= FARAWAY
; /* Row location of HW cursor */
119 int ttcol
= FARAWAY
; /* Column location of HW cursor */
120 int lbound
= 0; /* leftmost column of current line
123 VIDEO
**vscreen
; /* Virtual screen. */
124 VIDEO
**pscreen
; /* Physical screen. */
128 * Initialize the data structures used by the display code. The edge vectors
129 * used to access the screens are set up. The operating system's terminal I/O
130 * channel is set up. All the other things get initialized at compile time.
131 * The original window has "WFCHG" set, so that it will get completely
132 * redrawn on the first call to "update".
145 vtterminalinfo(gmode
& MDTCAPWINS
);
149 (*term
.t_rev
)(FALSE
);
150 vscreen
= (VIDEO
**) malloc((term
.t_nrow
+1)*sizeof(VIDEO
*));
151 memset(vscreen
, 0, (term
.t_nrow
+1)*sizeof(VIDEO
*));
152 if (vscreen
== NULL
){
153 emlwrite("Allocating memory for virtual display failed.", NULL
);
157 pscreen
= (VIDEO
**) malloc((term
.t_nrow
+1)*sizeof(VIDEO
*));
158 memset(pscreen
, 0, (term
.t_nrow
+1)*sizeof(VIDEO
*));
159 if (pscreen
== NULL
){
160 free((void *)vscreen
);
161 emlwrite("Allocating memory for physical display failed.", NULL
);
166 for (i
= 0; i
<= term
.t_nrow
; ++i
) {
167 vp
= (VIDEO
*) malloc(sizeof(VIDEO
)+(term
.t_ncol
*sizeof(CELL
)));
170 free((void *)vscreen
);
171 free((void *)pscreen
);
172 emlwrite("Allocating memory for virtual display lines failed.",
177 for(j
= 0; j
< term
.t_ncol
; j
++)
183 vp
= (VIDEO
*) malloc(sizeof(VIDEO
)+(term
.t_ncol
*sizeof(CELL
)));
186 free((void *)vscreen
[i
]);
188 free((void *)vscreen
[i
]);
189 free((void *)pscreen
[i
]);
192 free((void *)vscreen
);
193 free((void *)pscreen
);
194 emlwrite("Allocating memory for physical display lines failed.",
199 for(j
= 0; j
< term
.t_ncol
; j
++)
210 vtterminalinfo(int termcap_wins
)
212 return((term
.t_terminalinfo
) ? (*term
.t_terminalinfo
)(termcap_wins
)
213 : (Pmaster
? 0 : TRUE
));
218 * Clean up the virtual terminal system, in anticipation for a return to the
219 * operating system. Move down to the last line and clear it out (the next
220 * system prompt will be written in the line). Shut down the channel to the
226 movecursor(term
.t_nrow
-1, 0);
228 movecursor(term
.t_nrow
, 0);
235 * Set the virtual cursor to the specified row and column on the virtual
236 * screen. There is no checking for nonsense values; this might be a good
237 * idea during the early stages.
240 vtmove(int row
, int col
)
251 * This is unused so don't worry about it.
259 * Write a character to the virtual screen. The virtual row and column are
260 * updated. If the line is too long put a "$" in the last column. This routine
261 * only puts printing characters into the virtual terminal buffers. Only
262 * column overflow is checked.
275 if (vtcol
>= term
.t_ncol
) {
277 * What's this supposed to be doing? This sets vtcol
278 * to the even multiple of 8 >= vtcol. Why are we doing that?
279 * Must make tab work correctly.
287 vtcol
= (vtcol
+ 0x07) & ~0x07;
291 * If we get to here that means that there must be characters
292 * past the right hand edge, so we want to put a $ character
293 * in the last visible character. It would be nice to replace
294 * the last visible character by a double-$ if it is double-width
295 * but we aren't doing that because we'd have to add up the widths
296 * starting at the left hand margin each time through.
298 if(vtind
> 0 && vtind
<= term
.t_ncol
)
299 vp
->v_text
[vtind
-1] = ac
;
301 else if (c
.c
== '\t') {
305 while (((vtcol
+ (vtrow
==currow
? lbound
: 0)) & 0x07) != 0 && vtcol
< term
.t_ncol
);
307 else if (ISCONTROL(c
.c
)){
310 ac
.c
= ((c
.c
& 0x7f) | 0x40);
316 * Have to worry about what happens if we skip over 0
317 * with a double-width character. There may be a better
318 * place to be setting vtind, or maybe we could make do
322 w
= wcellwidth((UCS
) c
.c
);
323 w
= (w
>= 0 ? w
: 1);
325 if(vtcol
== 0 || (vtcol
< 0 && vtcol
+ w
== 1)){
332 * Double-width character overlaps right edge.
333 * Replace it with a $.
335 if(vtcol
+ w
> term
.t_ncol
){
341 if(vtind
>= 0 && vtind
< term
.t_ncol
)
342 vp
->v_text
[vtind
++] = c
;
350 * Erase from the end of the software cursor to the end of the line on which
351 * the software cursor is located.
364 while (vtind
< term
.t_ncol
)
365 vp
->v_text
[vtind
++] = c
;
372 * Make sure that the display is right. This is a three part process. First,
373 * scan through all of the windows looking for dirty ones. Check the framing,
374 * and refresh the screen. Second, make sure that "currow" and "curcol" are
375 * correct for the current window. Third, make the virtual and physical
396 /* This tells our MS Windows module to not bother updating the
397 * cursor position while a massive screen update is in progress.
399 mswin_beginupdate ();
403 * BUG: setting and unsetting whole region at a time is dumb. fix this.
413 /* Look at any window with update flags set on. */
415 if (wp
->w_flag
!= 0){
416 /* If not force reframe, check the framing. */
418 if ((wp
->w_flag
& WFFORCE
) == 0){
421 for (i
= 0; i
< wp
->w_ntrows
; ++i
){
422 if (lp
== wp
->w_dotp
)
425 if (lp
== wp
->w_bufp
->b_linep
)
432 /* Not acceptable, better compute a new value for the line at the
433 * top of the window. Then set the "WFHARD" flag to force full
441 if (i
>= wp
->w_ntrows
)
450 else if(TERM_OPTIMIZE
){
452 * find dotp, if its been moved just above or below the
453 * window, use scrollxxx() to facilitate quick redisplay...
455 lp
= lforw(wp
->w_dotp
);
456 if(lp
!= wp
->w_dotp
){
457 if(lp
== wp
->w_linep
&& lp
!= wp
->w_bufp
->b_linep
){
462 for(j
=0;j
< wp
->w_ntrows
; ++j
){
463 if(lp
!= wp
->w_bufp
->b_linep
)
468 if(lp
== wp
->w_dotp
&& j
== wp
->w_ntrows
)
472 j
= i
= wp
->w_ntrows
/2;
479 while (i
!= 0 && lback(lp
) != wp
->w_bufp
->b_linep
){
485 * this is supposed to speed things up by using tcap sequences
486 * to efficiently scroll the terminal screen. the thinking here
487 * is that its much faster to update pscreen[] than to actually
488 * write the stuff to the screen...
492 case 1: /* scroll text down */
493 j
= j
-i
+1; /* add one for dot line */
495 * do we scroll down the header as well? Well, only
496 * if we're not editing the header, we've backed up
497 * to the top, and the composer is not being
500 if(Pmaster
&& Pmaster
->headents
&& !ComposerEditing
501 && (lback(lp
) == wp
->w_bufp
->b_linep
)
502 && (ComposerTopLine
== COMPOSER_TOP_LINE
))
503 j
+= entry_line(1000, TRUE
); /* Never > 1000 headers */
505 scrolldown(wp
, -1, j
);
507 case 2: /* scroll text up */
508 j
= wp
->w_ntrows
- (j
-i
); /* we chose new top line! */
511 * do we scroll down the header as well? Well, only
512 * if we're not editing the header, we've backed up
513 * to the top, and the composer is not being
517 && (ComposerTopLine
!= COMPOSER_TOP_LINE
))
518 scrollup(wp
, COMPOSER_TOP_LINE
,
519 j
+entry_line(1000, TRUE
));
532 wp
->w_flag
|= WFHARD
; /* Force full. */
535 * if the line at the top of the page is the top line
536 * in the body, show the header...
538 if(Pmaster
&& Pmaster
->headents
&& !ComposerEditing
){
539 if(lback(wp
->w_linep
) == wp
->w_bufp
->b_linep
){
540 if(ComposerTopLine
== COMPOSER_TOP_LINE
){
541 i
= term
.t_nrow
- 2 - term
.t_mrow
- HeaderLen();
542 if(i
> 0 && nlforw() >= i
) { /* room for header ? */
543 if((i
= nlforw()/2) == 0 && term
.t_nrow
&1)
545 while(wp
->w_linep
!= wp
->w_bufp
->b_linep
&& i
--)
546 wp
->w_linep
= lforw(wp
->w_linep
);
554 if(ComposerTopLine
!= COMPOSER_TOP_LINE
)
555 ToggleHeader(0); /* hide it ! */
559 /* Try to use reduced update. Mode line update has its own special
560 * flag. The fast update is used if the only thing to do is within
566 if ((wp
->w_flag
& ~WFMODE
) == WFEDIT
){
567 while (lp
!= wp
->w_dotp
){
572 vscreen
[i
]->v_flag
|= VFCHG
;
575 for (j
= 0; j
< llength(lp
); ++j
)
576 vtputc(lgetc(lp
, j
));
580 else if ((wp
->w_flag
& (WFEDIT
| WFHARD
)) != 0){
581 while (i
< wp
->w_toprow
+wp
->w_ntrows
){
582 vscreen
[i
]->v_flag
|= VFCHG
;
585 /* if line has been changed */
586 if (lp
!= wp
->w_bufp
->b_linep
){
587 for (j
= 0; j
< llength(lp
); ++j
)
588 vtputc(lgetc(lp
, j
));
598 if ((wp
->w_flag
&WFMODE
) != 0)
611 /* and onward to the next window */
615 /* Always recompute the row and column number of the hardware cursor. This
616 * is the only update for simple moves.
619 currow
= curwp
->w_toprow
;
621 while (lp
!= curwp
->w_dotp
){
629 while (i
< curwp
->w_doto
){
636 else if(ISCONTROL(c
.c
)){
642 w
= wcellwidth((UCS
) c
.c
);
643 curcol
+= (w
>= 0 ? w
: 1);
647 if (curcol
>= term
.t_ncol
) { /* extended line. */
648 /* flag we are extended and changed */
649 vscreen
[currow
]->v_flag
|= VFEXT
| VFCHG
;
650 updext(); /* and output extended line */
652 lbound
= 0; /* not extended line */
654 /* make sure no lines need to be de-extended because the cursor is
664 while (i
< wp
->w_toprow
+ wp
->w_ntrows
) {
665 if (vscreen
[i
]->v_flag
& VFEXT
) {
666 /* always flag extended lines as changed */
667 vscreen
[i
]->v_flag
|= VFCHG
;
668 if ((wp
!= curwp
) || (lp
!= wp
->w_dotp
) ||
669 (curcol
< term
.t_ncol
)) {
671 for (j
= 0; j
< llength(lp
); ++j
)
672 vtputc(lgetc(lp
, j
));
675 /* this line no longer is extended */
676 vscreen
[i
]->v_flag
&= ~VFEXT
;
682 /* and onward to the next window */
686 /* Special hacking if the screen is garbage. Clear the hardware screen,
687 * and update your copy to agree with it. Set all the virtual screen
688 * change bits, to force a full update.
691 if (sgarbf
!= FALSE
){
697 if(ComposerTopLine
!= COMPOSER_TOP_LINE
){
698 UpdateHeader(0); /* arrange things */
699 PaintHeader(COMPOSER_TOP_LINE
, TRUE
);
703 * since we're using only a portion of the screen and only
704 * one buffer, only clear enough screen for the current window
705 * which is to say the *only* window.
707 for(i
=wheadp
->w_toprow
;i
<=term
.t_nrow
; i
++){
710 vscreen
[i
]->v_flag
|= VFCHG
;
712 rv
= (*Pmaster
->showmsg
)('X' & 0x1f); /* ctrl-L */
714 picosigs(); /* restore altered handlers */
715 if(rv
) /* Did showmsg corrupt the display? */
716 PaintBody(0); /* Yes, repaint */
717 movecursor(wheadp
->w_toprow
, 0);
720 for (i
= 0; i
< term
.t_nrow
-term
.t_mrow
; ++i
){
721 vscreen
[i
]->v_flag
|= VFCHG
;
725 for (j
= 0; j
< term
.t_ncol
; ++j
)
729 movecursor(0, 0); /* Erase the screen. */
734 sgarbf
= FALSE
; /* Erase-page clears */
735 mpresf
= FALSE
; /* the message area. */
740 sgarbk
= TRUE
; /* fix the keyhelp as well...*/
743 /* Make sure that the physical and virtual displays agree. Unlike before,
744 * the "updateline" code is only called with a line that has been updated
752 if (term
.t_nrow
> term
.t_mrow
)
753 c
.c
= term
.t_nrow
- term
.t_mrow
;
757 for (; i
< (int)c
.c
; ++i
){
761 /* for each line that needs to be updated, or that needs its
762 reverse video status changed, call the line updater */
776 updateline(i
, &vp1
->v_text
[0], &vp2
->v_text
[0], &vp1
->v_flag
);
784 movecursor(term
.t_nrow
-1, 0);
786 movecursor(term
.t_nrow
, 0);
791 /* TRANSLATORS: UnJustify means undo the previous
793 menu_pico
[UNCUT_KEY
].label
= N_("UnJustify");
794 if(!(lastflag
&CFFLBF
)){
795 emlwrite(_("Can now UnJustify!"), NULL
);
796 mpresf
= FARAWAY
; /* remove this after next keystroke! */
800 menu_pico
[UNCUT_KEY
].label
= N_("UnCut Text");
808 emlwrite(_("Can now UnJustify!"), NULL
);
809 mpresf
= FARAWAY
; /* remove this after next keystroke! */
812 /* Finally, update the hardware cursor and flush out buffers. */
814 movecursor(currow
, curcol
- lbound
);
819 * Update the scroll bars. This function is where curbp->b_linecnt
820 * is really managed. See update_scroll.
828 /* updext - update the extended line which the cursor is currently
829 * on at a column greater than the terminal width. The line
830 * will be scrolled right or left to let the user see where
836 int rcursor
; /* real cursor location */
837 LINE
*lp
; /* pointer to current line */
838 int j
; /* index into line */
843 * Calculate what column the real cursor will end up in.
844 * The cursor will be in the rcursor'th column. So if we're
845 * counting columns 0 1 2 3 and rcursor is 8, then rcursor
846 * will be over cell 7.
848 * What this effectively does is to scroll the screen as we're
849 * moving to the right when the cursor first passes off the
850 * screen's right edge. It would be nice if it did the same
851 * thing coming back to the left. Instead, in order that the
852 * screen's display depends only on the curcol and not on
853 * how we got there, the screen scrolls when we pass the
854 * t_margin column. It's also kind of funky that you can't
855 * see the character under the $ but you can delete it.
857 rcursor
= ((curcol
- term
.t_ncol
) % (term
.t_ncol
- term
.t_margin
+ 1)) + term
.t_margin
;
858 lbound
= curcol
- rcursor
+ 1;
861 * Make sure lbound is set so that a double-width character does
862 * not straddle the boundary. If it does, move over one cell.
864 lp
= curwp
->w_dotp
; /* line to output */
865 for (j
=0; j
<llength(lp
) && w
< lbound
; ++j
){
866 ww
= wcellwidth((UCS
) lgetc(lp
, j
).c
);
867 w
+= (ww
>= 0 ? ww
: 1);
874 /* scan through the line outputing characters to the virtual screen
875 * once we reach the left edge
877 vtmove(currow
, -lbound
); /* start scanning offscreen */
878 for (j
=0; j
<llength(lp
); ++j
) /* until the end-of-line */
879 vtputc(lgetc(lp
, j
));
881 /* truncate the virtual line */
884 /* and put a '$' in column 1, may have to adjust curcol */
885 w
= wcellwidth((UCS
) vscreen
[currow
]->v_text
[0].c
);
886 vscreen
[currow
]->v_text
[0].c
= '$';
887 vscreen
[currow
]->v_text
[0].a
= 0;
890 * We want to put $ in the first two columns so that it
891 * takes up the right amount of space, but that means we
892 * have to scoot the real characters over one slot.
894 for (j
= term
.t_ncol
-1; j
>= 2; --j
)
895 vscreen
[currow
]->v_text
[j
] = vscreen
[currow
]->v_text
[j
-1];
897 vscreen
[currow
]->v_text
[1].c
= '$';
898 vscreen
[currow
]->v_text
[1].a
= 0;
904 * Update a single line. This does not know how to use insert or delete
905 * character sequences; we are using VT52 functionality. Update the physical
906 * row and column variables.
909 updateline(int row
, /* row on screen */
910 CELL vline
[], /* what we want it to end up as */
911 CELL pline
[], /* what it looks like now */
914 CELL
*cp1
, *cp2
, *cp3
, *cp4
, *cp5
, *cp6
, *cp7
;
916 int nbflag
; /* non-blanks to the right flag? */
919 if(row
< 0 || row
> term
.t_nrow
)
922 /* set up pointers to virtual and physical lines */
925 cp3
= &vline
[term
.t_ncol
];
927 /* advance past any common chars at the left */
928 while (cp1
!= cp3
&& cp1
[0].c
== cp2
[0].c
&& cp1
[0].a
== cp2
[0].a
) {
933 /* This can still happen, even though we only call this routine on changed
934 * lines. A hard update is always done when a line splits, a massive
935 * change is done, or a buffer is displayed twice. This optimizes out most
936 * of the excess updating. A lot of computes are used, but these tend to
937 * be hard operations that do a lot of update, so I don't really care.
939 /* if both lines are the same, no update needs to be done */
941 *flags
&= ~VFCHG
; /* mark it clean */
945 /* find out if there is a match on the right */
947 cp3
= &vline
[term
.t_ncol
];
948 cp4
= &pline
[term
.t_ncol
];
950 if(cellwidth_ptr_to_ptr(cp1
, cp3
) == cellwidth_ptr_to_ptr(cp2
, cp4
))
951 while (cp3
[-1].c
== cp4
[-1].c
&& cp3
[-1].a
== cp4
[-1].a
) {
954 if (cp3
[0].c
!= ' ' || cp3
[0].a
!= 0) /* Note if any nonblank */
955 nbflag
= TRUE
; /* in right match. */
960 if (nbflag
== FALSE
&& TERM_EOLEXIST
) { /* Erase to EOL ? */
961 while (cp5
!= cp1
&& cp5
[-1].c
== ' ' && cp5
[-1].a
== 0)
964 if (cp3
-cp5
<= 3) /* Use only if erase is */
965 cp5
= cp3
; /* fewer characters. */
968 /* go to start of differences */
969 movecursor(row
, cellwidth_ptr_to_ptr(&vline
[0], cp1
));
971 if (!nbflag
) { /* use insert or del char? */
976 &&(cp7
!=cp2
&& cp6
[0].c
==cp7
[-1].c
&& cp6
[0].a
==cp7
[-1].a
)){
977 while (cp7
!= cp2
&& cp6
[0].c
==cp7
[-1].c
&& cp6
[0].a
==cp7
[-1].a
){
982 if (cp7
==cp2
&& cp4
-cp2
> 3){
985 (*term
.t_rev
)(cp1
->a
); /* set inverse for this char */
986 o_insert((UCS
) cp1
->c
); /* insert the char */
987 ww
= wcellwidth((UCS
) cp1
->c
);
988 ttcol
+= (ww
>= 0 ? ww
: 1);
989 display
= FALSE
; /* only do it once!! */
992 else if(TERM_DELCHAR
&& cp3
!= cp1
&& cp7
[0].c
== cp6
[-1].c
993 && cp7
[0].a
== cp6
[-1].a
){
994 while (cp6
!= cp1
&& cp7
[0].c
==cp6
[-1].c
&& cp7
[0].a
==cp6
[-1].a
){
999 if (cp6
==cp1
&& cp5
-cp6
> 3){
1002 w
= wcellwidth((UCS
) cp7
[0].c
);
1003 w
= (w
>= 0 ? w
: 1);
1004 while(w
-- > 0) /* in case double-width char */
1005 o_delete(); /* delete the char */
1006 display
= FALSE
; /* only do it once!! */
1011 if(cp1
!= cp5
&& display
){
1015 * If we need to copy characters from cp1 to cp2 and
1016 * we need to display them, then we have to worry about
1017 * the characters that we are replacing being of a different
1018 * width than the new characters, else the display may be
1021 * If the new width (w1) is less than the old width, that means
1022 * we will leave behind some old remnants if we aren't careful.
1023 * If the new width is larger than the old width, we have to
1024 * make sure we draw the characters all the way to the end
1025 * in order to get it right. Take advantage of clear to end
1026 * of line if we have it.
1028 w1
= cellwidth_ptr_to_ptr(cp1
, cp3
);
1029 w2
= cellwidth_ptr_to_ptr(cp2
, cp2
+ (cp3
-cp1
));
1031 if(w1
< w2
|| (nbflag
&& w1
!= w2
)){
1035 * Draw all of the characters starting with cp1
1036 * until we get to all spaces, then clear to the end of
1037 * line from there. Watch out we don't run over the
1038 * right hand edge, which shouldn't happen.
1040 * Set cp5 to the first of the repeating spaces.
1042 cp5
= &vline
[term
.t_ncol
];
1043 while (cp5
!= cp1
&& cp5
[-1].c
== ' ' && cp5
[-1].a
== 0)
1048 * In the !nbflag case we want spaces from cp5 on.
1049 * Setting cp3 to something different from cp5 triggers
1050 * the clear to end of line below.
1052 if(cellwidth_ptr_to_ptr(&vline
[0], cp5
) < term
.t_ncol
)
1059 * No peeol so draw all the way to the edge whether they
1060 * are spaces or not.
1063 for(w
= 0; w
< term
.t_ncol
; cp3
++){
1066 ww
= wcellwidth((UCS
) cp3
->c
);
1067 w
+= (ww
>= 0 ? ww
: 1);
1075 while (cp1
!= cp5
) { /* Ordinary. */
1079 (*term
.t_rev
)(cp1
->a
); /* set inverse for this char */
1080 (*term
.t_putchar
)(cp1
->c
);
1083 ww
= wcellwidth((UCS
) cp1
->c
);
1084 ttcol
+= (ww
>= 0 ? ww
: 1);
1089 (*term
.t_rev
)(0); /* turn off inverse anyway! */
1091 if (cp5
!= cp3
|| cleartoeol
) { /* Erase. */
1099 *flags
&= ~VFCHG
; /* flag this line is changed */
1104 * Redisplay the mode line for the window pointed to by the "wp". This is the
1105 * only routine that has any idea of how the modeline is formatted. You can
1106 * change the modeline format by hacking at this routine. Called by "update"
1107 * any time there is a dirty window.
1110 modeline(WINDOW
*wp
)
1116 menu_compose
[EXIT_KEY
].label
= (Pmaster
->headents
)
1117 ? N_("Send") :N_("Exit");
1118 menu_compose
[PSTPN_KEY
].name
= (Pmaster
->headents
)
1120 menu_compose
[PSTPN_KEY
].label
= (Pmaster
->headents
)
1121 ? N_("Postpone") : NULL
;
1122 menu_compose
[WHERE_KEY
].name
= (Pmaster
->alt_ed
) ? "^_" : "^W";
1123 menu_compose
[WHERE_KEY
].label
= (Pmaster
->alt_ed
) ? N_("Alt Edit")
1125 KS_OSDATASET(&menu_compose
[WHERE_KEY
],
1126 (Pmaster
->alt_ed
) ? KS_ALTEDITOR
: KS_WHEREIS
);
1127 menu_compose
[UNCUT_KEY
].label
= (thisflag
&CFFILL
) ? N_("UnJustify")
1129 wkeyhelp(menu_compose
);
1134 char t1
[NLINE
], t2
[NLINE
], t3
[NLINE
], tline
[NLINE
];
1135 int w1
, w2
, w3
, w1_to_2
, w2_to_3
, w3_to_r
;
1140 vscreen
[0]->v_flag
|= VFCHG
; /* Redraw next time. */
1141 vtmove(0, 0); /* Seek to right line. */
1143 snprintf(t1
, sizeof(t1
), PICO_TITLE
, version
); /* write version */
1146 if(bp
->b_fname
[0]) /* File name? */
1147 snprintf(t2
, sizeof(t2
), "File: %s", bp
->b_fname
);
1149 strncpy(t2
, PICO_NEWBUF_MSG
, sizeof(t2
));
1150 t2
[sizeof(t2
)-1] = '\0';
1153 if(bp
->b_flag
&BFCHG
){ /* "MOD" if changed. */
1154 strncpy(t3
, PICO_MOD_MSG
, sizeof(t3
));
1155 t3
[sizeof(t3
)-1] = '\0';
1160 #define ALLOFTHEM (w1+w1_to_2+w2+w2_to_3+w3+w3_to_r)
1161 #define ALLBUTSPACE (w1+w2+w3+w3_to_r)
1163 w1
= utf8_width(t1
);
1164 w2
= utf8_width(t2
);
1165 w3
= utf8_width(t3
);
1166 w1_to_2
= w2_to_3
= 1; /* min values for separation */
1169 if(ALLOFTHEM
<= term
.t_ncol
){ /* everything fits */
1170 w1_to_2
= (term
.t_ncol
- ALLBUTSPACE
)/2;
1171 w2_to_3
= term
.t_ncol
- (ALLBUTSPACE
+ w1_to_2
);
1176 if(ALLOFTHEM
<= term
.t_ncol
)
1177 w2_to_3
= term
.t_ncol
- (ALLBUTSPACE
+ w1_to_2
);
1179 w1
= w1_to_2
= w3_to_r
= 0;
1180 if(ALLOFTHEM
<= term
.t_ncol
)
1181 w2_to_3
= term
.t_ncol
- (ALLBUTSPACE
+ w1_to_2
);
1184 snprintf(t2
, sizeof(t2
), "%s", bp
->b_fname
);
1185 w2
= utf8_width(t2
);
1188 if(ALLOFTHEM
<= term
.t_ncol
)
1189 w2_to_3
= term
.t_ncol
- (ALLBUTSPACE
+ w1_to_2
);
1192 if(bp
->b_fname
[0] && ALLOFTHEM
<= term
.t_ncol
){
1193 /* reduce size of file */
1194 w2
= term
.t_ncol
- (ALLOFTHEM
- w2
);
1195 t2
[0] = t2
[1] = t2
[2] = '.';
1196 utf8_to_width_rhs(t2
+3, bp
->b_fname
, sizeof(t2
)-3, w2
-3);
1197 w2
= utf8_width(t2
);
1200 w2
= utf8_width(t2
);
1202 if(ALLOFTHEM
<= term
.t_ncol
)
1203 w2_to_3
= term
.t_ncol
- (ALLBUTSPACE
+ w1_to_2
);
1205 w1
= w1_to_2
= w2
= w2_to_3
= w3_to_r
= 0;
1206 if(ALLOFTHEM
<= term
.t_ncol
)
1207 w2_to_3
= term
.t_ncol
- ALLBUTSPACE
;
1216 utf8_snprintf(tline
, sizeof(tline
),
1217 "%*.*w%*.*w%*.*w%*.*w%*.*w%*.*w",
1219 w1_to_2
, w1_to_2
, "",
1221 w2_to_3
, w2_to_3
, "",
1223 w3_to_r
, w3_to_r
, "");
1226 if(utf8_width(tline
) <= term
.t_ncol
)
1227 ucs
= utf8_to_ucs4_cpystr(tline
);
1235 while((c
.c
= CELLMASK
& *ucsp
++))
1238 fs_give((void **) &ucs
);
1246 * Send a command to the terminal to move the hardware cursor to row "row"
1247 * and column "col". The row and column arguments are origin 0. Optimize out
1248 * random calls. Update "ttrow" and "ttcol".
1251 movecursor(int row
, int col
)
1253 if (row
!=ttrow
|| col
!=ttcol
) {
1256 (*term
.t_move
)(MIN(MAX(row
,0),term
.t_nrow
), MIN(MAX(col
,0),term
.t_ncol
-1));
1262 * Erase any sense we have of the cursor's HW location...
1267 ttrow
= ttcol
= FARAWAY
;
1271 get_cursor(int *row
, int *col
)
1281 * Erase the message line. This is a special routine because the message line
1282 * is not considered to be part of the virtual screen. It always works
1283 * immediately; the terminal buffer is flushed via a call to the flusher.
1288 if (term
.t_nrow
< term
.t_mrow
)
1291 movecursor(term
.t_nrow
- term
.t_mrow
, 0);
1293 if (TERM_EOLEXIST
== TRUE
)
1296 if(ttrow
== term
.t_nrow
){
1297 while(ttcol
++ < term
.t_ncol
-1)
1298 (*term
.t_putchar
)(' ');
1301 while(ttcol
++ < term
.t_ncol
) /* track's ttcol */
1302 (*term
.t_putchar
)(' ');
1312 mlyesno_utf8(char *utf8prompt
, int dflt
)
1317 prompt
= utf8_to_ucs4_cpystr(utf8prompt
? utf8prompt
: "");
1319 ret
= mlyesno(prompt
, dflt
);
1322 fs_give((void **) &prompt
);
1329 * Ask a yes or no question in the message line. Return either TRUE, FALSE, or
1330 * ABORT. The ABORT status is returned if the user bumps out of the question
1331 * with a ^G. if d >= 0, d is the default answer returned. Otherwise there
1335 mlyesno(UCS
*prompt
, int dflt
)
1338 UCS buf
[NLINE
], lbuf
[10];
1339 KEYMENU menu_yesno
[12];
1340 COLOR_PAIR
*lastc
= NULL
;
1343 if (mswin_usedialog ())
1344 switch (mswin_yesno (prompt
)) {
1346 case 0: return (ABORT
);
1347 case 1: return (TRUE
);
1348 case 2: return (FALSE
);
1352 for(rv
= 0; rv
< 12; rv
++){
1353 menu_yesno
[rv
].name
= NULL
;
1354 KS_OSDATASET(&menu_yesno
[rv
], KS_NONE
);
1357 menu_yesno
[1].name
= "Y";
1358 menu_yesno
[1].label
= (dflt
== TRUE
) ? "[" N_("Yes") "]" : N_("Yes");
1359 menu_yesno
[6].name
= "^C";
1360 menu_yesno
[6].label
= N_("Cancel");
1361 menu_yesno
[7].name
= "N";
1362 menu_yesno
[7].label
= (dflt
== FALSE
) ? "[" N_("No") "]" : N_("No");
1363 wkeyhelp(menu_yesno
); /* paint generic menu */
1364 sgarbk
= TRUE
; /* mark menu dirty */
1365 if(Pmaster
&& curwp
)
1366 curwp
->w_flag
|= WFMODE
;
1368 ucs4_strncpy(buf
, prompt
, NLINE
);
1369 buf
[NLINE
-1] = '\0';
1370 lbuf
[0] = ' '; lbuf
[1] = '?'; lbuf
[2] = ' '; lbuf
[3] = '\0';
1371 ucs4_strncat(buf
, lbuf
, NLINE
- ucs4_strlen(buf
) - 1);
1372 buf
[NLINE
-1] = '\0';
1374 if(Pmaster
&& Pmaster
->colors
&& Pmaster
->colors
->prcp
1375 && pico_is_good_colorpair(Pmaster
->colors
->prcp
)){
1376 lastc
= pico_get_cur_color();
1377 (void) pico_set_colorp(Pmaster
->colors
->prcp
, PSC_NONE
);
1385 case (CTRL
|'M') : /* default */
1387 pputs_utf8((dflt
) ? _("Yes") : _("No"), 1);
1395 case (CTRL
|'C') : /* Bail out! */
1397 pputs_utf8(_("ABORT"), 1);
1404 pputs_utf8(_("Yes"), 1);
1411 pputs_utf8(_("No"), 1);
1416 if(term
.t_mrow
== 0 && km_popped
== 0){
1417 movecursor(term
.t_nrow
-2, 0);
1421 (void) pico_set_colorp(lastc
, PSC_NONE
);
1422 free_color_pair(&lastc
);
1427 wkeyhelp(menu_yesno
); /* paint generic menu */
1429 if(Pmaster
&& Pmaster
->colors
&& Pmaster
->colors
->prcp
1430 && pico_is_good_colorpair(Pmaster
->colors
->prcp
)){
1431 lastc
= pico_get_cur_color();
1432 (void) pico_set_colorp(Pmaster
->colors
->prcp
, PSC_NONE
);
1437 sgarbk
= TRUE
; /* mark menu dirty */
1441 /* else fall through */
1452 (void) pico_set_colorp(lastc
, PSC_NONE
);
1453 free_color_pair(&lastc
);
1460 movecursor(term
.t_nrow
, 0);
1473 * Write a prompt into the message line, then read back a response. Keep
1474 * track of the physical position of the cursor. If we are in a keyboard
1475 * macro throw the prompt away, and return the remembered response. This
1476 * lets macros run at full speed. The reply is always terminated by a carriage
1477 * return. Handle erase, kill, and abort keys.
1480 mlreply_utf8(char *utf8prompt
, char *utf8buf
, int nbuf
, int flg
, EXTRAKEYS
*extras
)
1482 return(mlreplyd_utf8(utf8prompt
, utf8buf
, nbuf
, flg
|QDEFLT
, extras
));
1487 mlreply(UCS
*prompt
, UCS
*buf
, int nbuf
, int flg
, EXTRAKEYS
*extras
)
1489 return(mlreplyd(prompt
, buf
, nbuf
, flg
|QDEFLT
, extras
));
1494 * function key mappings
1496 static UCS rfkm
[12][2] = {
1513 mlreplyd_utf8(char *utf8prompt
, char *utf8buf
, int nbuf
, int flg
, EXTRAKEYS
*extras
)
1520 buf
= (UCS
*) fs_get(nbuf
* sizeof(*b
));
1521 b
= utf8_to_ucs4_cpystr(utf8buf
);
1523 ucs4_strncpy(buf
, b
, nbuf
);
1525 fs_give((void **) &b
);
1528 prompt
= utf8_to_ucs4_cpystr(utf8prompt
? utf8prompt
: "");
1530 ret
= mlreplyd(prompt
, buf
, nbuf
, flg
, extras
);
1532 utf8
= ucs4_to_utf8_cpystr(buf
);
1534 strncpy(utf8buf
, utf8
, nbuf
);
1535 utf8buf
[nbuf
-1] = '\0';
1536 fs_give((void **) &utf8
);
1540 fs_give((void **) &buf
);
1543 fs_give((void **) &prompt
);
1557 * mlreplyd - write the prompt to the message line along with a default
1558 * answer already typed in. Carriage return accepts the
1559 * default. answer returned in buf which also holds the initial
1560 * default, nbuf is its length, def set means use default value.
1563 mlreplyd(UCS
*prompt
, UCS
*buf
, int nbuf
, int flg
, EXTRAKEYS
*extras
)
1565 UCS c
; /* current char */
1566 UCS
*b
; /* pointer in buf */
1569 int changed
= FALSE
;
1571 KEYMENU menu_mlreply
[12];
1573 struct display_line dline
;
1574 COLOR_PAIR
*lastc
= NULL
;
1577 if(mswin_usedialog()){
1578 MDlgButton btn_list
[12];
1579 LPTSTR free_names
[12];
1580 LPTSTR free_labels
[12];
1583 memset(&free_names
, 0, sizeof(LPTSTR
) * 12);
1584 memset(&free_labels
, 0, sizeof(LPTSTR
) * 12);
1585 memset(&btn_list
, 0, sizeof (MDlgButton
) * 12);
1587 for(i
= 0; extras
&& extras
[i
].name
!= NULL
; ++i
) {
1588 if(extras
[i
].label
[0] != '\0') {
1589 if((extras
[i
].key
& CTRL
) == CTRL
)
1590 btn_list
[j
].ch
= (extras
[i
].key
& ~CTRL
) - '@';
1592 btn_list
[j
].ch
= extras
[i
].key
;
1594 btn_list
[j
].rval
= extras
[i
].key
;
1595 free_names
[j
] = utf8_to_lptstr(extras
[i
].name
);
1596 btn_list
[j
].name
= free_names
[j
];
1597 free_labels
[j
] = utf8_to_lptstr(extras
[i
].label
);
1598 btn_list
[j
].label
= free_labels
[j
];
1603 btn_list
[j
].ch
= -1;
1605 return_val
= mswin_dialog(prompt
, buf
, nbuf
, ((flg
&QDEFLT
) > 0),
1606 FALSE
, btn_list
, NULL
, 0);
1609 return_val
= HELPCH
;
1611 for(i
= 0; i
< 12; i
++){
1613 fs_give((void **) &free_names
[i
]);
1615 fs_give((void **) &free_labels
[i
]);
1622 menu_mlreply
[0].name
= "^G";
1623 menu_mlreply
[0].label
= N_("Get Help");
1624 KS_OSDATASET(&menu_mlreply
[0], KS_SCREENHELP
);
1625 for(j
= 0, i
= 1; i
< 6; i
++){ /* insert odd extras */
1626 menu_mlreply
[i
].name
= NULL
;
1627 KS_OSDATASET(&menu_mlreply
[i
], KS_NONE
);
1630 for(; extras
[j
].name
&& j
!= 2*(i
-1); j
++)
1634 rfkm
[2*i
][1] = extras
[j
].key
;
1635 menu_mlreply
[i
].name
= extras
[j
].name
;
1636 menu_mlreply
[i
].label
= extras
[j
].label
;
1637 KS_OSDATASET(&menu_mlreply
[i
], KS_OSDATAGET(&extras
[j
]));
1642 menu_mlreply
[6].name
= "^C";
1643 menu_mlreply
[6].label
= N_("Cancel");
1644 KS_OSDATASET(&menu_mlreply
[6], KS_NONE
);
1645 for(j
= 0, i
= 7; i
< 12; i
++){ /* insert even extras */
1646 menu_mlreply
[i
].name
= NULL
;
1647 rfkm
[2*(i
-6)+1][1] = 0;
1649 for(; extras
[j
].name
&& j
!= (2*(i
-6)) - 1; j
++)
1653 rfkm
[2*(i
-6)+1][1] = extras
[j
].key
;
1654 menu_mlreply
[i
].name
= extras
[j
].name
;
1655 menu_mlreply
[i
].label
= extras
[j
].label
;
1656 KS_OSDATASET(&menu_mlreply
[i
], KS_OSDATAGET(&extras
[j
]));
1661 /* set up what to watch for and return values */
1662 memset(extra_v
, 0, sizeof(extra_v
));
1663 for(i
= 0, j
= 0; i
< 12 && extras
&& extras
[i
].name
; i
++)
1664 extra_v
[j
++] = extras
[i
].key
;
1666 plen
= mlwrite(prompt
, NULL
); /* paint prompt */
1671 dline
.vused
= ucs4_strlen(buf
);
1672 dline
.dwid
= term
.t_ncol
- plen
;
1673 dline
.row
= term
.t_nrow
- term
.t_mrow
;
1676 dline
.dlen
= 2 * dline
.dwid
+ 100;
1678 dline
.dl
= (UCS
*) fs_get(dline
.dlen
* sizeof(UCS
));
1679 dline
.olddl
= (UCS
*) fs_get(dline
.dlen
* sizeof(UCS
));
1680 memset(dline
.dl
, 0, dline
.dlen
* sizeof(UCS
));
1681 memset(dline
.olddl
, 0, dline
.dlen
* sizeof(UCS
));
1683 dline
.movecursor
= movecursor
;
1684 dline
.writechar
= writeachar
;
1687 dline
.vlen
= nbuf
-1;
1690 b
= &buf
[(flg
& QBOBUF
) ? 0 : ucs4_strlen(buf
)];
1692 wkeyhelp(menu_mlreply
); /* paint generic menu */
1694 sgarbk
= 1; /* mark menu dirty */
1696 if(Pmaster
&& Pmaster
->colors
&& Pmaster
->colors
->prcp
1697 && pico_is_good_colorpair(Pmaster
->colors
->prcp
)){
1698 lastc
= pico_get_cur_color();
1699 (void) pico_set_colorp(Pmaster
->colors
->prcp
, PSC_NONE
);
1706 line_paint(b
-buf
, &dline
, NULL
);
1710 mouse_in_content(KEY_MOUSE
, -1, -1, 0x5, 0);
1711 register_mfunc(mouse_in_content
,
1712 term
.t_nrow
- term
.t_mrow
, plen
,
1713 term
.t_nrow
- term
.t_mrow
, term
.t_ncol
-1);
1716 mswin_allowpaste(MSWIN_PASTE_LINE
);
1718 while((c
= GetKey()) == NODATA
)
1722 clear_mfunc(mouse_in_content
);
1725 mswin_allowpaste(MSWIN_PASTE_DISABLE
);
1728 switch(c
= normalize_cmd(c
, rfkm
, 1)){
1729 case (CTRL
|'A') : /* CTRL-A beginning */
1734 case (CTRL
|'B') : /* CTRL-B back a char */
1743 case (CTRL
|'C') : /* CTRL-C abort */
1744 pputs_utf8(_("ABORT"), 1);
1749 case (CTRL
|'E') : /* CTRL-E end of line */
1751 b
= &buf
[ucs4_strlen(buf
)];
1754 case (CTRL
|'F') : /* CTRL-F forward a char*/
1763 case (CTRL
|'G') : /* CTRL-G help */
1764 if(term
.t_mrow
== 0 && km_popped
== 0){
1765 movecursor(term
.t_nrow
-2, 0);
1767 sgarbk
= 1; /* mark menu dirty */
1771 (void) pico_set_colorp(lastc
, PSC_NONE
);
1772 free_color_pair(&lastc
);
1777 wkeyhelp(menu_mlreply
); /* paint generic menu */
1778 plen
= mlwrite(prompt
, NULL
); /* paint prompt */
1779 if(Pmaster
&& Pmaster
->colors
&& Pmaster
->colors
->prcp
1780 && pico_is_good_colorpair(Pmaster
->colors
->prcp
)){
1781 lastc
= pico_get_cur_color();
1782 (void) pico_set_colorp(Pmaster
->colors
->prcp
, PSC_NONE
);
1791 pputs_utf8(_("HELP"), 1);
1792 return_val
= HELPCH
;
1795 case (CTRL
|'H') : /* CTRL-H backspace */
1796 case 0x7f : /* rubout */
1804 case (CTRL
|'D') : /* CTRL-D delete char */
1814 do /* blat out left char */
1816 while(b
[i
++] != '\0');
1819 case (CTRL
|'L') : /* CTRL-L redraw */
1820 return_val
= (CTRL
|'L');
1823 case (CTRL
|'K') : /* CTRL-K kill line */
1830 case F1
: /* sort of same thing */
1831 return_val
= HELPCH
;
1834 case (CTRL
|'M') : /* newline */
1835 return_val
= changed
;
1843 mouse_get_last (NULL
, &mp
);
1845 /* The clicked line have anything special on it? */
1847 case M_BUTTON_LEFT
: /* position cursor */
1848 mp
.col
-= plen
; /* normalize column */
1849 if(mp
.col
>= 0 && mp
.col
<= ucs4_strlen(buf
))
1854 case M_BUTTON_RIGHT
:
1856 mswin_allowpaste(MSWIN_PASTE_LINE
);
1857 mswin_paste_popup();
1858 mswin_allowpaste(MSWIN_PASTE_DISABLE
);
1862 case M_BUTTON_MIDDLE
: /* NO-OP for now */
1863 default: /* just ignore */
1873 /* look for match in extra_v */
1874 for(i
= 0; i
< 12; i
++)
1875 if(c
&& c
== extra_v
[i
]){
1882 if(c
& (CTRL
| FUNC
)){ /* bag ctrl_special chars */
1887 if(flg
&QNODQT
){ /* reject double quotes? */
1894 if(dline
.vused
>= nbuf
-1){
1899 do /* blat out left char */
1911 (void) pico_set_colorp(lastc
, PSC_NONE
);
1912 free_color_pair(&lastc
);
1921 movecursor(term
.t_nrow
, 0);
1928 fs_give((void **) &dline
.dl
);
1931 fs_give((void **) &dline
.olddl
);
1938 emlwrite(char *utf8message
, EML
*eml
)
1942 message
= utf8_to_ucs4_cpystr(utf8message
? utf8message
: "");
1944 emlwrite_ucs4(message
, eml
);
1947 fs_give((void **) &message
);
1952 * emlwrite() - write the message string to the error half of the screen
1953 * center justified. much like mlwrite (which is still used
1954 * to paint the line for prompts and such), except it center
1958 emlwrite_ucs4(UCS
*message
, EML
*eml
)
1962 COLOR_PAIR
*lastc
= NULL
;
1966 if(!(message
&& *message
) || term
.t_nrow
< 2)
1967 return; /* nothing to write or no space to write, bag it */
1971 width
= ucs4_str_width(message
);
1974 * next, figure out where the to move the cursor so the message
1975 * comes out centered
1977 if((ap
=ucs4_strchr(message
, '%')) != NULL
){
1982 width
+= (eml
&& eml
->c
) ? wcellwidth(eml
->c
) : 1;
1985 width
+= dumbroot(eml
? eml
->d
: 0, 10);
1988 width
+= dumblroot(eml
? eml
->l
: 0L, 10);
1991 width
+= dumbroot(eml
? eml
->d
: 0, 8);
1994 width
+= dumbroot(eml
? eml
->d
: 0, 16);
1996 case 's': /* string arg is UTF-8 */
1997 width
+= (eml
&& eml
->s
) ? utf8_width(eml
->s
) : 2;
2002 if(width
+4 <= term
.t_ncol
)
2003 movecursor(term
.t_nrow
-term
.t_mrow
, (term
.t_ncol
- (width
+ 4))/2);
2005 movecursor(term
.t_nrow
-term
.t_mrow
, 0);
2007 if(Pmaster
&& Pmaster
->colors
&& Pmaster
->colors
->stcp
2008 && pico_is_good_colorpair(Pmaster
->colors
->stcp
)){
2009 lastc
= pico_get_cur_color();
2010 (void) pico_set_colorp(Pmaster
->colors
->stcp
, PSC_NONE
);
2015 pputs_utf8("[ ", 1);
2016 while (*bufp
!= '\0' && ttcol
< term
.t_ncol
-2){
2019 else if(*bufp
== '%'){
2025 pputs_utf8("%c", 0);
2029 mlputi(eml
? eml
->d
: 0, 10);
2032 mlputli(eml
? eml
->l
: 0L, 10);
2035 mlputi(eml
? eml
->d
: 0, 16);
2038 mlputi(eml
? eml
->d
: 0, 8);
2041 pputs_utf8((eml
&& eml
->s
) ? eml
->s
: "%s", 0);
2054 pputs_utf8(" ]", 1);
2057 (void) pico_set_colorp(lastc
, PSC_NONE
);
2058 free_color_pair(&lastc
);
2070 mlwrite_utf8(char *utf8fmt
, void *arg
)
2075 fmt
= utf8_to_ucs4_cpystr(utf8fmt
? utf8fmt
: "");
2076 ret
= mlwrite(fmt
, arg
);
2078 fs_give((void **) &fmt
);
2085 * Write a message into the message line. Keep track of the physical cursor
2086 * position. A small class of printf like format items is handled. Assumes the
2087 * stack grows down; this assumption is made by the "++" in the argument scan
2088 * loop. Set the "message line" flag TRUE.
2091 mlwrite(UCS
*fmt
, void *arg
)
2096 COLOR_PAIR
*lastc
= NULL
;
2099 * the idea is to only highlight if there is something to show
2102 movecursor(ttrow
, 0);
2104 if(Pmaster
&& Pmaster
->colors
&& Pmaster
->colors
->prcp
2105 && pico_is_good_colorpair(Pmaster
->colors
->prcp
)){
2106 lastc
= pico_get_cur_color();
2107 (void) pico_set_colorp(Pmaster
->colors
->prcp
, PSC_NONE
);
2114 while ((c
= *fmt
++) != 0) {
2122 mlputi(*(int *)ap
, 10);
2127 mlputi(*(int *)ap
, 8);
2132 mlputi(*(int *)ap
, 16);
2137 mlputli(*(long *)ap
, 10);
2142 pputs_utf8(*(char **)ap
, 1);
2143 ap
+= sizeof(char *);
2149 ttcol
+= (ww
>= 0 ? ww
: 1);
2155 while(ttcol
< term
.t_ncol
)
2158 movecursor(term
.t_nrow
- term
.t_mrow
, ret
);
2161 (void) pico_set_colorp(lastc
, PSC_NONE
);
2162 free_color_pair(&lastc
);
2175 * Write out an integer, in the specified radix. Update the physical cursor
2176 * position. This will not handle any negative numbers; maybe it should.
2179 mlputi(int i
, int r
)
2182 static char hexdigits
[] = "0123456789ABCDEF";
2194 pputc(hexdigits
[i
%r
], 1);
2199 * do the same except as a long integer.
2202 mlputli(long l
, int r
)
2216 pputc((int)(l
%r
)+'0', 1);
2221 unknown_command(UCS c
)
2223 char buf
[10], ch
, *s
;
2232 else if(c
& CTRL
&& c
>= (CTRL
|'@') && c
<= (CTRL
|'_')){
2233 ch
= c
- (CTRL
|'@') + '@';
2234 snprintf(s
, sizeof(buf
), "^%c", ch
);
2238 case ' ' : s
= "SPACE"; break;
2239 case '\033' : s
= "ESC"; break;
2240 case '\177' : s
= "DEL"; break;
2241 case ctrl('I') : s
= "TAB"; break;
2242 case ctrl('J') : s
= "LINEFEED"; break;
2243 case ctrl('M') : s
= "RETURN"; break;
2244 case ctrl('Q') : s
= "XON"; break;
2245 case ctrl('S') : s
= "XOFF"; break;
2246 case KEY_UP
: s
= "Up Arrow"; break;
2247 case KEY_DOWN
: s
= "Down Arrow"; break;
2248 case KEY_RIGHT
: s
= "Right Arrow"; break;
2249 case KEY_LEFT
: s
= "Left Arrow"; break;
2250 case CTRL
|KEY_UP
: s
= "Ctrl-Up Arrow"; break;
2251 case CTRL
|KEY_DOWN
: s
= "Ctrl-Down Arrow"; break;
2252 case CTRL
|KEY_RIGHT
: s
= "Ctrl-Right Arrow"; break;
2253 case CTRL
|KEY_LEFT
: s
= "Ctrl-Left Arrow"; break;
2254 case KEY_PGUP
: s
= "Prev Page"; break;
2255 case KEY_PGDN
: s
= "Next Page"; break;
2256 case KEY_HOME
: s
= "Home"; break;
2257 case KEY_END
: s
= "End"; break;
2258 case KEY_DEL
: s
= "Delete"; break; /* Not necessary DEL! */
2271 snprintf(s
, sizeof(buf
), "F%ld", (long) (c
- PF1
+ 1));
2276 utf8_put((unsigned char *) s
, (unsigned long) c
);
2282 emlwrite("Unknown Command: %s", &eml
);
2288 * scrolldown - use stuff to efficiently move blocks of text on the
2289 * display, and update the pscreen array to reflect those
2292 * wp is the window to move in
2293 * r is the row at which to begin scrolling
2294 * n is the number of lines to scrol
2297 scrolldown(WINDOW
*wp
, int r
, int n
)
2302 register VIDEO
*vp1
;
2303 register VIDEO
*vp2
;
2313 if(r
> wp
->w_toprow
)
2314 vscreen
[r
-1]->v_flag
|= VFCHG
;
2315 l
= wp
->w_toprow
+wp
->w_ntrows
-r
;
2320 for(i
=l
-n
-1; i
>= 0; i
--){
2322 vp2
= pscreen
[r
+i
+n
];
2323 memcpy(vp2
, vp1
, term
.t_ncol
* sizeof(CELL
));
2328 #endif /* TERMCAP */
2333 * scrollup - use tcap stuff to efficiently move blocks of text on the
2334 * display, and update the pscreen array to reflect those
2338 scrollup(WINDOW
*wp
, int r
, int n
)
2342 register VIDEO
*vp1
;
2343 register VIDEO
*vp2
;
2356 if(!(r
+i
+n
< wp
->w_toprow
+wp
->w_ntrows
))
2360 if(!((i
< wp
->w_ntrows
-n
)&&(r
+i
+n
< wp
->w_toprow
+wp
->w_ntrows
)))
2363 vp1
= pscreen
[r
+i
+n
];
2365 memcpy(vp2
, vp1
, term
.t_ncol
* sizeof(CELL
));
2368 pprints(wp
->w_toprow
+wp
->w_ntrows
-n
, wp
->w_toprow
+wp
->w_ntrows
-1);
2371 #endif /* TERMCAP */
2376 * print spaces in the physical screen starting from row abs(n) working in
2377 * either the positive or negative direction (depending on sign of n).
2380 pprints(int x
, int y
)
2386 for(i
= x
;i
<= y
; ++i
){
2387 for(j
= 0; j
< term
.t_ncol
; j
++){
2388 pscreen
[i
]->v_text
[j
].c
= ' ';
2389 pscreen
[i
]->v_text
[j
].a
= 0;
2394 for(i
= x
;i
>= y
; --i
){
2395 for(j
= 0; j
< term
.t_ncol
; j
++){
2396 pscreen
[i
]->v_text
[j
].c
= ' ';
2397 pscreen
[i
]->v_text
[j
].a
= 0;
2407 * doton - return the physical line number that the dot is on in the
2408 * current window, and by side effect the number of lines remaining
2411 doton(int *r
, unsigned *chs
)
2414 register LINE
*lp
= curwp
->w_linep
;
2417 assert(r
!= NULL
&& chs
!= NULL
);
2420 while(i
++ < curwp
->w_ntrows
){
2421 if(lp
== curwp
->w_dotp
)
2424 if(lp
== curwp
->w_bufp
->b_linep
){
2429 (*chs
) += llength(lp
);
2431 *r
= i
- l
- term
.t_mrow
;
2432 return(l
+curwp
->w_toprow
);
2438 * resize_pico - given new window dimensions, allocate new resources
2441 resize_pico(int row
, int col
)
2443 int old_nrow
, old_ncol
;
2447 old_nrow
= term
.t_nrow
;
2448 old_ncol
= term
.t_ncol
;
2453 if (old_ncol
== term
.t_ncol
&& old_nrow
== term
.t_nrow
)
2457 curwp
->w_toprow
= 2;
2458 curwp
->w_ntrows
= term
.t_nrow
- curwp
->w_toprow
- term
.t_mrow
;
2462 fillcol
= Pmaster
->fillcolumn
;
2463 (*Pmaster
->resize
)();
2465 else if(userfillcol
> 0)
2466 fillcol
= userfillcol
;
2468 fillcol
= term
.t_ncol
- 6; /* we control the fill column */
2471 * free unused screen space ...
2473 for(i
=term
.t_nrow
+1; i
<= old_nrow
; ++i
){
2474 free((char *) vscreen
[i
]);
2475 free((char *) pscreen
[i
]);
2479 * realloc new space for screen ...
2481 if((vscreen
=(VIDEO
**)realloc(vscreen
,(term
.t_nrow
+1)*sizeof(VIDEO
*))) == NULL
){
2488 if((pscreen
=(VIDEO
**)realloc(pscreen
,(term
.t_nrow
+1)*sizeof(VIDEO
*))) == NULL
){
2495 for (i
= 0; i
<= term
.t_nrow
; ++i
) {
2497 vp
= (VIDEO
*) realloc(vscreen
[i
], sizeof(VIDEO
)+(term
.t_ncol
*sizeof(CELL
)));
2499 vp
= (VIDEO
*) malloc(sizeof(VIDEO
)+(term
.t_ncol
*sizeof(CELL
)));
2505 if(old_ncol
< term
.t_ncol
){ /* don't let any garbage in */
2507 vtcol
= (i
< old_nrow
) ? old_ncol
: 0;
2512 vp
= (VIDEO
*) realloc(pscreen
[i
], sizeof(VIDEO
)+(term
.t_ncol
*sizeof(CELL
)));
2514 vp
= (VIDEO
*) malloc(sizeof(VIDEO
)+(term
.t_ncol
*sizeof(CELL
)));
2523 if(!ResizeBrowser()){
2524 if(Pmaster
&& Pmaster
->headents
){
2528 curwp
->w_flag
|= (WFHARD
| WFMODE
);
2529 pico_refresh(0, 1); /* redraw whole enchilada. */
2530 update(); /* do it */
2538 redraw_pico_for_callback(void)
2546 * showCompTitle - display the anchor line passed in from pine
2553 extern UCS
*pico_anchor
;
2554 COLOR_PAIR
*lastc
= NULL
;
2556 if((bufp
= pico_anchor
) == NULL
)
2559 movecursor(COMPOSER_TITLE_LINE
, 0);
2560 if (Pmaster
->colors
&& Pmaster
->colors
->tbcp
&&
2561 pico_is_good_colorpair(Pmaster
->colors
->tbcp
)){
2562 lastc
= pico_get_cur_color();
2563 (void)pico_set_colorp(Pmaster
->colors
->tbcp
, PSC_NONE
);
2568 while (ttcol
< term
.t_ncol
)
2575 (void)pico_set_colorp(lastc
, PSC_NONE
);
2576 free_color_pair(&lastc
);
2581 movecursor(COMPOSER_TITLE_LINE
+ 1, 0);
2589 * zotdisplay - blast malloc'd space created for display maps
2596 for (i
= 0; i
<= term
.t_nrow
; ++i
){ /* free screens */
2597 free((char *) vscreen
[i
]);
2598 free((char *) pscreen
[i
]);
2601 free((char *) vscreen
);
2602 free((char *) pscreen
);
2608 * nlforw() - returns the number of lines from the top to the dot
2614 register LINE
*lp
= curwp
->w_linep
;
2616 while(lp
!= curwp
->w_dotp
){
2626 * pputc - output the given char, keep track of it on the physical screen
2627 * array, and keep track of the cursor
2630 pputc(UCS c
, /* char to write */
2631 int a
) /* and its attribute */
2633 int ind
, width
, printable_ascii
= 0;
2636 * This is necessary but not sufficient to allow us to draw. Note that
2637 * ttrow runs from 0 to t_nrow (so total number of rows is t_nrow+1)
2638 * ttcol runs from 0 to t_ncol-1 (so total number of cols is t_ncol)
2640 if((ttcol
>= 0 && ttcol
< term
.t_ncol
) && (ttrow
>= 0 && ttrow
<= term
.t_nrow
)){
2643 * Width is the number of screen columns a character will occupy.
2645 if(c
< 0x80 && isprint(c
)){
2650 width
= wcellwidth(c
);
2653 width
= 1; /* will be a '?' */
2655 if(ttcol
+ width
<= term
.t_ncol
){ /* it fits */
2657 * Some terminals scroll when you write in the lower right corner
2658 * of the screen, so don't write there.
2660 if(!(ttrow
== term
.t_nrow
&& ttcol
+width
== term
.t_ncol
)){
2661 (*term
.t_putchar
)(c
); /* write it */
2662 ind
= index_from_col(ttrow
, ttcol
);
2663 pscreen
[ttrow
]->v_text
[ind
].c
= c
; /* keep track of it */
2664 pscreen
[ttrow
]->v_text
[ind
].a
= a
; /* keep track of it */
2669 * Character overlaps right edge of screen. Hopefully the higher
2670 * layers will prevent this but we're making sure.
2672 * We may want to do something like writing a space character
2673 * into the cells that are on the screen. We'll see.
2677 ttcol
= MIN(term
.t_ncol
, ttcol
+width
);
2683 * pputs - print a string and keep track of the cursor
2686 pputs(UCS
*s
, /* string to write */
2687 int a
) /* and its attribute */
2695 pputs_utf8(char *s
, int a
)
2700 ucsstr
= utf8_to_ucs4_cpystr(s
);
2703 fs_give((void **) &ucsstr
);
2710 * peeol - physical screen array erase to end of the line. remember to
2716 int i
, width
= 0, ww
;
2719 if(ttrow
< 0 || ttrow
> term
.t_nrow
)
2726 * Don't clear if we think we are sitting past the last column,
2727 * that erases the last column if we just wrote it.
2729 if(ttcol
< term
.t_ncol
)
2733 * Because the characters are variable width it's a little tricky
2734 * to erase the rest of the line. What we do is add up the
2735 * widths of the characters until we reach ttcol
2736 * then set the rest to the space character.
2738 for(i
= 0; i
< term
.t_ncol
&& width
< ttcol
; i
++){
2739 ww
= wcellwidth((UCS
) pscreen
[ttrow
]->v_text
[i
].c
);
2740 width
+= (ww
>= 0 ? ww
: 1);
2743 while(i
< term
.t_ncol
)
2744 pscreen
[ttrow
]->v_text
[i
++] = cl
;
2749 * pscr - return the character cell on the physical screen map on the
2750 * given line, l, and offset, o.
2755 if((l
>= 0 && l
<= term
.t_nrow
) && (o
>= 0 && o
< term
.t_ncol
))
2756 return(&(pscreen
[l
]->v_text
[o
]));
2763 * pclear() - clear the physical screen from row x through row y (inclusive)
2764 * row is zero origin, min row = 0 max row = t_nrow
2765 * Clear whole screen -- pclear(0, term.t_nrow)
2766 * Clear bottom two rows -- pclear(term.t_nrow-1, term.t_nrow)
2767 * Clear bottom three rows -- pclear(term.t_nrow-2, term.t_nrow)
2770 pclear(int x
, int y
)
2774 x
= MIN(MAX(0, x
), term
.t_nrow
);
2775 y
= MIN(MAX(0, y
), term
.t_nrow
);
2777 for(i
=x
; i
<= y
; i
++){
2785 * dumbroot - just get close
2788 dumbroot(int x
, int b
)
2793 return(dumbroot(x
/b
, b
) + 1);
2798 * dumblroot - just get close
2801 dumblroot(long x
, int b
)
2806 return(dumblroot(x
/b
, b
) + 1);
2811 * pinsertc - use optimized insert, fixing physical screen map.
2812 * returns true if char written, false otherwise
2820 if(ttrow
< 0 || ttrow
> term
.t_nrow
)
2823 if(o_insert((UCS
) c
.c
)){ /* if we've got it, use it! */
2824 p
= pscreen
[ttrow
]->v_text
; /* then clean up physical screen */
2826 ind
= index_from_col(ttrow
, ttcol
);
2828 for(i
= term
.t_ncol
-1; i
> ind
; i
--)
2829 p
[i
] = p
[i
-1]; /* shift right */
2831 p
[ind
] = c
; /* insert new char */
2833 ww
= wcellwidth((UCS
) c
.c
);
2834 ttcol
+= (ww
>= 0 ? ww
: 1);
2844 * pdel - use optimized delete to rub out the current char and
2845 * fix the physical screen array.
2846 * returns true if optimized the delete, false otherwise
2854 if(ttrow
< 0 || ttrow
> term
.t_nrow
)
2857 if(TERM_DELCHAR
){ /* if we've got it, use it! */
2858 p
= pscreen
[ttrow
]->v_text
;
2859 ind
= index_from_col(ttrow
, ttcol
);
2863 w
= wcellwidth((UCS
) p
[ind
].c
);
2864 w
= (w
>= 0 ? w
: 1);
2867 for(i
= 0; i
< w
; i
++){
2868 (*term
.t_putchar
)('\b'); /* move left a char */
2869 o_delete(); /* and delete it */
2872 /* then clean up physical screen */
2873 for(i
=ind
; i
< term
.t_ncol
-1; i
++)
2889 * wstripe - write out the given string at the given location, and reverse
2890 * video on flagged characters. Does the same thing as pine's
2893 * I believe this needs to be fixed to work with non-ascii utf8pmt, but maybe
2894 * only if you want to put the tildes before multi-byte chars.
2897 wstripe(int line
, int column
, char *utf8pmt
, int key
)
2903 COLOR_PAIR
*lastc
= NULL
;
2904 COLOR_PAIR
*kncp
= NULL
;
2905 COLOR_PAIR
*klcp
= NULL
;
2907 if(line
< 0 || line
> term
.t_nrow
)
2910 if (Pmaster
&& Pmaster
->colors
){
2911 if(pico_is_good_colorpair(Pmaster
->colors
->klcp
))
2912 klcp
= Pmaster
->colors
->klcp
;
2914 if(klcp
&& pico_is_good_colorpair(Pmaster
->colors
->kncp
))
2915 kncp
= Pmaster
->colors
->kncp
;
2917 lastc
= pico_get_cur_color();
2920 ucs4pmt
= utf8_to_ucs4_cpystr(utf8pmt
);
2921 l
= ucs4_strlen(ucs4pmt
);
2923 if(i
>= term
.t_ncol
|| col
>= term
.t_ncol
|| j
>= l
)
2924 return; /* equal strings */
2926 if(ucs4pmt
[j
] == (UCS
) key
)
2929 if (pscr(line
, i
) == NULL
)
2932 if(pscr(line
, i
)->c
!= ucs4pmt
[j
]){
2933 if(j
>= 1 && ucs4pmt
[j
-1] == (UCS
) key
)
2938 ww
= wcellwidth((UCS
) pscr(line
, i
)->c
);
2939 col
+= (ww
>= 0 ? ww
: 1);
2944 movecursor(line
, column
+col
);
2945 if(klcp
) (void)pico_set_colorp(klcp
, PSC_NONE
);
2948 if(*u
== (UCS
) key
){
2951 (void)pico_set_colorp(kncp
, PSC_NONE
);
2953 (void)(*term
.t_rev
)(1);
2957 (void)pico_set_colorp(klcp
, PSC_NONE
);
2959 (void)(*term
.t_rev
)(0);
2965 while(*++u
!= '\0');
2968 fs_give((void **) &ucs4pmt
);
2972 (void)pico_set_colorp(lastc
, PSC_NONE
);
2973 free_color_pair(&lastc
);
2981 * wkeyhelp - paint list of possible commands on the bottom
2982 * of the display (yet another pine clone)
2983 * NOTE: function key mode is handled here since all the labels
2986 * The KEYMENU definitions have names and labels defined as UTF-8 strings,
2987 * and wstripe expects UTF-8.
2990 wkeyhelp(KEYMENU
*keymenu
)
2992 char *obufp
, *p
, fkey
[4];
2993 char linebuf
[2*NLINE
]; /* "2" is for space for invert tokens */
2994 int row
, slot
, tspace
, adjusted_tspace
, nspace
[6], index
, n
;
3000 pico_config_menu_items (keymenu
);
3003 if(term
.t_mrow
== 0)
3010 * Calculate amount of space for the names column by column...
3012 for(index
= 0; index
< 6; index
++)
3013 if(!(gmode
&MDFKEY
)){
3014 nspace
[index
] = (keymenu
[index
].name
)
3015 ? utf8_width(keymenu
[index
].name
) : 0;
3016 if(keymenu
[index
+6].name
3017 && (n
= utf8_width(keymenu
[index
+6].name
)) > nspace
[index
])
3023 nspace
[index
] = (index
< 4) ? 3 : 4;
3025 tspace
= term
.t_ncol
/6; /* total space for each item */
3028 * Avoid writing in bottom right corner so we won't scroll screens that
3029 * scroll when you do that. The way this is setup, we won't do that
3030 * unless the number of columns is evenly divisible by 6.
3032 adjusted_tspace
= (6 * tspace
== term
.t_ncol
) ? tspace
- 1 : tspace
;
3035 for(row
= 0; row
<= 1; row
++){
3037 obufp
= &linebuf
[0];
3038 for(slot
= 0; slot
< 6; slot
++){
3039 if(keymenu
[index
].name
&& keymenu
[index
].label
){
3041 char this_label
[200], tmp_label
[200];
3043 if(keymenu
[index
].label
[0] == '[' && keymenu
[index
].label
[(l
=strlen(keymenu
[index
].label
))-1] == ']' && l
> 2){
3044 strncpy(tmp_label
, &keymenu
[index
].label
[1], MIN(sizeof(tmp_label
),l
-2));
3045 tmp_label
[MIN(sizeof(tmp_label
)-1,l
-2)] = '\0';
3046 snprintf(this_label
, sizeof(this_label
), "[%s]", _(tmp_label
));
3049 strncpy(this_label
, _(keymenu
[index
].label
), sizeof(this_label
));
3051 this_label
[sizeof(this_label
)-1] = '\0';
3055 snprintf(fkey
, sizeof(fkey
), "F%d", (2 * slot
) + row
+ 1);
3058 p
= keymenu
[index
].name
;
3060 snprintf(nbuf
, sizeof(nbuf
), "%.*s %s", nspace
[slot
], p
, this_label
);
3062 (gmode
&MDFKEY
) ? F1
+ (2 * slot
) + row
:
3063 (keymenu
[index
].name
[0] == '^')
3064 ? (CTRL
| keymenu
[index
].name
[1])
3065 : (keymenu
[index
].name
[0] == 'S'
3066 && !strcmp(keymenu
[index
].name
, "Spc"))
3068 : keymenu
[index
].name
[0],
3070 term
.t_nrow
- 1 + row
, (slot
* tspace
),
3072 (Pmaster
&& Pmaster
->colors
)
3073 ? Pmaster
->colors
->kncp
: NULL
,
3074 (Pmaster
&& Pmaster
->colors
)
3075 ? Pmaster
->colors
->klcp
: NULL
);
3079 while(p
&& *p
&& n
--){
3080 *obufp
++ = '~'; /* insert "invert" token */
3088 n
= ((slot
== 5 && row
== 1) ? adjusted_tspace
3089 : tspace
) - nspace
[slot
];
3090 while(p
&& *p
&& n
-- > 0)
3097 n
= (slot
== 5 && row
== 1) ? adjusted_tspace
: tspace
;
3102 register_key(index
, NODATA
, "", NULL
, 0, 0, 0, NULL
, NULL
);
3110 wstripe(term
.t_nrow
- 1 + row
, 0, linebuf
, '~');
3116 * This returns the screen width between pstart (inclusive) and
3117 * pend (exclusive) where the pointers point into an array of CELLs.
3120 cellwidth_ptr_to_ptr(CELL
*pstart
, CELL
*pend
)
3127 for(p
= pstart
; p
< pend
; p
++){
3128 ww
= wcellwidth((UCS
) p
->c
);
3129 width
+= (ww
>= 0 ? ww
: 1);
3137 * This returns the virtual screen width in row from index a to b (exclusive).
3140 vcellwidth_a_to_b(int row
, int a
, int b
)
3142 CELL
*pstart
, *pend
;
3145 if(row
< 0 || row
> term
.t_nrow
)
3151 a
= MIN(MAX(0, a
), term
.t_ncol
-1);
3152 b
= MIN(MAX(0, a
), term
.t_ncol
); /* b is past where we stop */
3155 pstart
= &vp
->v_text
[a
];
3156 pend
= &vp
->v_text
[b
];
3158 return(cellwidth_ptr_to_ptr(pstart
, pend
));
3163 * This returns the physical screen width in row from index a to b (exclusive).
3166 pcellwidth_a_to_b(int row
, int a
, int b
)
3168 CELL
*pstart
, *pend
;
3171 if(row
< 0 || row
> term
.t_nrow
)
3177 a
= MIN(MAX(0, a
), term
.t_ncol
-1);
3178 b
= MIN(MAX(0, a
), term
.t_ncol
); /* b is past where we stop */
3181 pstart
= &vp
->v_text
[a
];
3182 pend
= &vp
->v_text
[b
];
3184 return(cellwidth_ptr_to_ptr(pstart
, pend
));
3189 index_from_col(int row
, int col
)
3191 CELL
*p_start
, *p_end
, *p_limit
;
3192 int w_consumed
= 0, w
, done
= 0;
3194 if(row
< 0 || row
> term
.t_nrow
)
3197 p_end
= p_start
= pscreen
[row
]->v_text
;
3198 p_limit
= p_start
+ term
.t_ncol
;
3201 while(!done
&& p_end
< p_limit
&& p_end
->c
&& w_consumed
<= col
){
3202 w
= wcellwidth((UCS
) p_end
->c
);
3203 w
= (w
>= 0 ? w
: 1);
3204 if(w_consumed
+ w
<= col
){
3212 /* MIN and MAX just to be sure */
3213 return(MIN(MAX(0, p_end
- p_start
), term
.t_ncol
-1));
3219 pico_config_menu_items (KEYMENU
*keymenu
)
3225 mswin_menuitemclear ();
3227 /* keymenu's seem to be hardcoded at 12 entries. */
3228 for (i
= 0, k
= keymenu
; i
< 12; ++i
, ++k
) {
3229 if (k
->name
!= NULL
&& k
->label
!= NULL
&&
3230 k
->menuitem
!= KS_NONE
) {
3232 if (k
->name
[0] == '^')
3233 key
= CTRL
| k
->name
[1];
3234 else if (strcmp(k
->name
, "Ret") == 0)
3239 mswin_menuitemadd (key
, k
->label
, k
->menuitem
, 0);
3245 * Update the scroll range and position. (exported)
3247 * This is where curbp->b_linecnt is really managed. With out this function
3248 * to count the number of lines when needed curbp->b_linecnt will never
3249 * really be correct. BUT, this function is only compiled into the
3250 * windows version, so b_linecnt will only ever be right in the windows
3251 * version. OK for now because that is the only version that
3252 * looks at b_linecnt.
3255 update_scroll (void)
3260 static LINE
*last_top_line
= NULL
;
3261 static long last_scroll_pos
= -1;
3264 if (ComposerEditing
) {
3265 /* Editing header - don't allow scroll bars. */
3266 mswin_setscrollrange (0, 0);
3272 * Count the number of lines in the current bufer. Done when:
3274 * when told to recount: curbp->b_linecnt == -1
3275 * when the top line changed: curwp->w_linep != last_top_line
3276 * when we don't know the scroll pos: last_scroll_pos == -1
3278 * The first line in the list is a "place holder" line and is not
3279 * counted. The list is circular, when we return the to place
3280 * holder we have reached the end.
3282 if(curbp
->b_linecnt
== -1 || curwp
->w_linep
!= last_top_line
3283 || last_scroll_pos
== -1) {
3286 for (lp
= lforw (curbp
->b_linep
); lp
!= curbp
->b_linep
;
3288 if (lp
== curwp
->w_linep
)
3289 scr_pos
= scr_range
;
3294 curbp
->b_linecnt
= scr_range
;
3295 last_scroll_pos
= scr_pos
;
3296 last_top_line
= curwp
->w_linep
;
3300 * Set new scroll range and position.
3302 mswin_setscrollrange (curwp
->w_ntrows
- 2, curbp
->b_linecnt
- 1);
3303 mswin_setscrollpos (last_scroll_pos
);
3306 #endif /* _WINDOWS */