mirror of
https://github.com/clockworkpi/PicoCalc.git
synced 2025-12-12 10:18:54 +01:00
2068 lines
96 KiB
C
2068 lines
96 KiB
C
/***********************************************************************************************************************
|
|
PicoMite MMBasic
|
|
|
|
Editor.c
|
|
|
|
<COPYRIGHT HOLDERS> Geoff Graham, Peter Mather
|
|
Copyright (c) 2021, <COPYRIGHT HOLDERS> All rights reserved.
|
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
|
in the documentation and/or other materials provided with the distribution.
|
|
3. The name MMBasic be used when referring to the interpreter in any documentation and promotional material and the original copyright message be displayed
|
|
on the console at startup (additional copyright messages may be added).
|
|
4. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed
|
|
by the <copyright holder>.
|
|
5. Neither the name of the <copyright holder> nor the names of its contributors may be used to endorse or promote products derived from this software
|
|
without specific prior written permission.
|
|
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDERS> AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDERS> BE LIABLE FOR ANY DIRECT,
|
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
************************************************************************************************************************/
|
|
/**
|
|
* @file Audio.c
|
|
* @author Geoff Graham, Peter Mather
|
|
* @brief Source for Editor MMBasic commands
|
|
*/
|
|
/**
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
|
|
#include "MMBasic_Includes.h"
|
|
#include "Hardware_Includes.h"
|
|
|
|
#define CTRLKEY(a) (a & 0x1f)
|
|
|
|
|
|
#define DISPLAY_CLS 1
|
|
#define REVERSE_VIDEO 3
|
|
#define CLEAR_TO_EOL 4
|
|
#define CLEAR_TO_EOS 5
|
|
#define SCROLL_DOWN 6
|
|
#define DRAW_LINE 7
|
|
|
|
#define GUI_C_NORMAL WHITE
|
|
#define GUI_C_BCOLOUR BLACK
|
|
#define GUI_C_COMMENT YELLOW
|
|
#define GUI_C_KEYWORD CYAN
|
|
#define GUI_C_QUOTE MAGENTA
|
|
#define GUI_C_NUMBER GREEN
|
|
#define GUI_C_LINE MAGENTA
|
|
#define GUI_C_STATUS WHITE
|
|
|
|
//======================================================================================
|
|
// Attribute VT100 Code VT 100 Colour LCD Screen Colour
|
|
//======================================================================================
|
|
#define VT100_C_NORMAL "\033[37m" // White Foreground Colour
|
|
#define VT100_C_COMMENT "\033[33m" // Yellow Yellow
|
|
#define VT100_C_KEYWORD "\033[36m" // Cyan Cyan
|
|
#define VT100_C_QUOTE "\033[35m" // Green Green
|
|
#define VT100_C_NUMBER "\033[32m" // Red Red
|
|
#define VT100_C_LINE "\033[35m" // White Grey
|
|
#define VT100_C_STATUS "\033[37m" // Black Brown
|
|
#define VT100_C_ERROR "\033[31m" // Red Red
|
|
|
|
// these two are the only global variables, the default place for the cursor when the editor opens
|
|
unsigned char *StartEditPoint = NULL;
|
|
int StartEditChar = 0;
|
|
static bool markmode=false;
|
|
extern void routinechecks(void);
|
|
int8_t optioncolourcodesave;
|
|
#if !defined(LITE)
|
|
#ifdef PICOMITEVGA
|
|
int editactive=0;
|
|
static int r_on=0;
|
|
void DisplayPutClever(char c){
|
|
if((DISPLAY_TYPE==SCREENMODE1 && markmode && Option.ColourCode && ytileheight==gui_font_height && gui_font_width % 8 ==0)){
|
|
if(c >= FontTable[gui_font >> 4][2] && c < FontTable[gui_font >> 4][2] + FontTable[gui_font >> 4][3]) {
|
|
if(CurrentX + gui_font_width > HRes) {
|
|
DisplayPutClever('\r');
|
|
DisplayPutClever('\n');
|
|
}
|
|
}
|
|
|
|
// handle the standard control chars
|
|
switch(c) {
|
|
case '\b': CurrentX -= gui_font_width;
|
|
if (CurrentX < 0) CurrentX = 0;
|
|
return;
|
|
case '\r': CurrentX = 0;
|
|
return;
|
|
case '\n': CurrentY += gui_font_height;
|
|
if(CurrentY + gui_font_height >= VRes) {
|
|
ScrollLCD(CurrentY + gui_font_height - VRes);
|
|
CurrentY -= (CurrentY + gui_font_height - VRes);
|
|
}
|
|
return;
|
|
case '\t': do {
|
|
DisplayPutClever(' ');
|
|
} while((CurrentX/gui_font_width) % Option.Tab);
|
|
return;
|
|
}
|
|
#ifdef HDMI
|
|
if(r_on){
|
|
if(FullColour){
|
|
if(r_on)for(int i=0; i< gui_font_width / 8; i++)tilebcols[CurrentY/gui_font_height*X_TILE+CurrentX/8+i]=RGB555(BLUE);
|
|
}
|
|
else {
|
|
if(r_on)for(int i=0; i< gui_font_width / 8; i++)tilebcols_w[CurrentY/gui_font_height*X_TILE+CurrentX/8+i]=RGB332(BLUE);
|
|
}
|
|
}
|
|
#else
|
|
if(r_on)for(int i=0; i< gui_font_width / 8; i++)tilebcols[CurrentY/gui_font_height*X_TILE+CurrentX/8+i]=0x1111;
|
|
#endif
|
|
#ifdef HDMI
|
|
else {
|
|
if(FullColour){
|
|
for(int i=0; i< gui_font_width / 8; i++)tilebcols[CurrentY/gui_font_height*X_TILE+CurrentX/8+i]=RGB555(Option.DefaultBC);
|
|
}
|
|
else {
|
|
for(int i=0; i< gui_font_width / 8; i++)tilebcols_w[CurrentY/gui_font_height*X_TILE+CurrentX/8+i]=RGB332(Option.DefaultBC);
|
|
}
|
|
}
|
|
#else
|
|
else for(int i=0; i< gui_font_width / 8; i++)tilebcols[CurrentY/gui_font_height*X_TILE+CurrentX/8+i]=RGB121pack(Option.DefaultBC);
|
|
#endif
|
|
CurrentX += gui_font_width;
|
|
} else DisplayPutC(c);
|
|
}
|
|
#endif
|
|
|
|
void DisplayPutS(char *s) {
|
|
while(*s) DisplayPutC(*s++);
|
|
}
|
|
|
|
static inline void printnothing(char * dummy){
|
|
|
|
}
|
|
static inline char nothingchar(char dummy,int flush){
|
|
return 0;
|
|
}
|
|
int OriginalFC, OriginalBC; // the original fore/background colours used by MMBasic
|
|
static void (*PrintString)(char *buff)=SSPrintString;
|
|
static char (*SSputchar)(char buff, int flush)=SerialConsolePutC;
|
|
// #define PrintString SSPrintString
|
|
#ifdef PICOMITEVGA
|
|
#define MX470PutC(c) DisplayPutClever(c)
|
|
#else
|
|
#define MX470PutC(c) DisplayPutC(c)
|
|
#endif
|
|
// Only SSD1963 displays support H/W scrolling so for other displays it is much quicker to redraw the screen than scroll it
|
|
// However, we don't want to redraw the serial console so we dummy out the serial writes whiole re-drawing the physical screen
|
|
#ifdef PICOMITEVGA
|
|
#define MX470Scroll(n) ScrollLCD(n);
|
|
#else
|
|
#define MX470Scroll(n) if(Option.DISPLAY_CONSOLE){if(!((SPIREAD && ScrollLCD != ScrollLCDSPISCR) || Option.NoScroll))ScrollLCD(n);\
|
|
else {PrintString=printnothing;SSputchar=nothingchar;printScreen();PrintString=SSPrintString;SSputchar=SerialConsolePutC;}}
|
|
#endif
|
|
|
|
// #define dx(...) {char s[140];sprintf(s, __VA_ARGS__); SerUSBPutS(s); SerUSBPutS("\r\n");}
|
|
|
|
static inline void MX470PutS(char *s, int fc, int bc) {
|
|
if(!Option.DISPLAY_CONSOLE) return;
|
|
int tfc, tbc;
|
|
tfc = gui_fcolour; tbc = gui_bcolour;
|
|
gui_fcolour = fc; gui_bcolour = bc;
|
|
DisplayPutS(s);
|
|
gui_fcolour = tfc; gui_bcolour = tbc;
|
|
}
|
|
|
|
|
|
static inline void MX470Cursor(int x, int y) {
|
|
if(!Option.DISPLAY_CONSOLE) return;
|
|
CurrentX = x;
|
|
CurrentY = y;
|
|
}
|
|
|
|
void MX470Display(int fn) {
|
|
if(!Option.DISPLAY_CONSOLE) return;
|
|
int t;
|
|
switch(fn) {
|
|
case DISPLAY_CLS: ClearScreen(gui_bcolour);
|
|
break;
|
|
#ifdef PICOMITEVGA
|
|
case CLEAR_TO_EOS: MX470Display(CLEAR_TO_EOL);
|
|
DrawRectangle(0, CurrentY + gui_font_height, HRes-1, VRes-1, DISPLAY_TYPE==SCREENMODE1 ? 0 : gui_bcolour);
|
|
#ifdef HDMI
|
|
if(FullColour){
|
|
if(DISPLAY_TYPE==SCREENMODE1 && Option.ColourCode && ytileheight==gui_font_height){
|
|
for(int y=(CurrentY + gui_font_height)/ytileheight;y<Y_TILE;y++)
|
|
for(int x=0;x<X_TILE;x++){
|
|
tilefcols[y*X_TILE+x]=RGB555(gui_fcolour);
|
|
tilebcols[y*X_TILE+x]=RGB555(gui_bcolour);
|
|
}
|
|
}
|
|
} else {
|
|
if(DISPLAY_TYPE==SCREENMODE1 && Option.ColourCode && ytileheight==gui_font_height){
|
|
for(int y=(CurrentY + gui_font_height)/ytileheight;y<Y_TILE;y++)
|
|
for(int x=0;x<X_TILE;x++){
|
|
tilefcols_w[CurrentY/ytileheight*X_TILE+x]=RGB332(gui_fcolour);
|
|
tilebcols_w[CurrentY/ytileheight*X_TILE+x]=RGB332(gui_bcolour);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
if(DISPLAY_TYPE==SCREENMODE1 && Option.ColourCode && ytileheight==gui_font_height){
|
|
for(int y=(CurrentY + gui_font_height)/ytileheight;y<Y_TILE;y++)
|
|
for(int x=0;x<X_TILE;x++){
|
|
tilefcols[CurrentY/ytileheight*X_TILE+x]=RGB121pack(gui_fcolour);
|
|
tilebcols[CurrentY/ytileheight*X_TILE+x]=RGB121pack(gui_bcolour);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
break;
|
|
case REVERSE_VIDEO:
|
|
if((DISPLAY_TYPE==SCREENMODE1 && Option.ColourCode && ytileheight==gui_font_height)){
|
|
r_on^=1;
|
|
} else {
|
|
t = gui_fcolour;
|
|
gui_fcolour = gui_bcolour;
|
|
gui_bcolour = t;
|
|
}
|
|
break;
|
|
case CLEAR_TO_EOL: DrawBox(CurrentX, CurrentY, HRes-1, CurrentY + gui_font_height-1, 0, 0, DISPLAY_TYPE==SCREENMODE1 ? 0 : gui_bcolour);
|
|
#ifdef HDMI
|
|
if(FullColour){
|
|
if(DISPLAY_TYPE==SCREENMODE1 && Option.ColourCode && ytileheight==gui_font_height){
|
|
for(int x=CurrentX/8;x<X_TILE;x++){
|
|
tilefcols[CurrentY/ytileheight*X_TILE+x]=RGB555(gui_fcolour);
|
|
tilebcols[CurrentY/ytileheight*X_TILE+x]=RGB555(gui_bcolour);
|
|
}
|
|
}
|
|
} else {
|
|
if(DISPLAY_TYPE==SCREENMODE1 && Option.ColourCode && ytileheight==gui_font_height){
|
|
for(int x=CurrentX/8;x<X_TILE;x++){
|
|
tilefcols_w[CurrentY/ytileheight*X_TILE+x]=RGB332(gui_fcolour);
|
|
tilebcols_w[CurrentY/ytileheight*X_TILE+x]=RGB332(gui_bcolour);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
if(DISPLAY_TYPE==SCREENMODE1 && Option.ColourCode && ytileheight==gui_font_height){
|
|
for(int x=CurrentX/8;x<X_TILE;x++){
|
|
tilefcols[CurrentY/ytileheight*X_TILE+x]=RGB121pack(gui_fcolour);
|
|
tilebcols[CurrentY/ytileheight*X_TILE+x]=RGB121pack(gui_bcolour);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
break;
|
|
#else
|
|
case REVERSE_VIDEO: t = gui_fcolour;
|
|
gui_fcolour = gui_bcolour;
|
|
gui_bcolour = t;
|
|
break;
|
|
case CLEAR_TO_EOL: DrawBox(CurrentX, CurrentY, HRes-1, CurrentY + gui_font_height-1, 0, 0, gui_bcolour);
|
|
break;
|
|
case CLEAR_TO_EOS: DrawBox(CurrentX, CurrentY, HRes-1, CurrentY + gui_font_height-1, 0, 0, gui_bcolour);
|
|
DrawRectangle(0, CurrentY + gui_font_height, HRes-1, VRes-1, gui_bcolour);
|
|
break;
|
|
#endif
|
|
case SCROLL_DOWN:
|
|
break;
|
|
case DRAW_LINE: DrawBox(0, gui_font_height * (Option.Height - 2), HRes - 1, VRes - 1, 0, 0, (DISPLAY_TYPE==SCREENMODE1 ? 0 :gui_bcolour));
|
|
DrawLine(0, (VRes/gui_font_height)*gui_font_height - gui_font_height - 6, HRes - 1, (VRes/gui_font_height)*gui_font_height - gui_font_height - 6, 1, GUI_C_LINE);
|
|
#ifdef PICOMITEVGA
|
|
#ifdef HDMI
|
|
if(FullColour){
|
|
if(DISPLAY_TYPE==SCREENMODE1 && Option.ColourCode && ytileheight==gui_font_height)for(int i=0; i<HRes/8; i++)tilefcols[(Option.Height - 2)*X_TILE+i]=RGB555(MAGENTA);
|
|
} else {
|
|
if(DISPLAY_TYPE==SCREENMODE1 && Option.ColourCode && ytileheight==gui_font_height)for(int i=0; i<HRes/8; i++)tilefcols_w[(Option.Height - 2)*X_TILE+i]=RGB332(MAGENTA);
|
|
}
|
|
#else
|
|
if(DISPLAY_TYPE==SCREENMODE1 && Option.ColourCode && ytileheight==gui_font_height)for(int i=0; i<HRes/8; i++)tilefcols[(Option.Height - 2)*X_TILE+i]=0x9999;
|
|
#endif
|
|
#endif
|
|
CurrentX = 0; CurrentY = (VRes/gui_font_height)*gui_font_height - gui_font_height;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************************************************************************
|
|
THE EDIT COMMAND
|
|
********************************************************************************************************************************************/
|
|
|
|
unsigned char *EdBuff=NULL; // the buffer used for editing the text
|
|
int nbrlines; // size of the text held in the buffer (in lines)
|
|
int VWidth, VHeight; // editing screen width and height in characters
|
|
int edx, edy; // column and row at the top left hand corner of the editing screen (in characters)
|
|
int curx, cury; // column and row of the current cursor (in characters) relative to the top left hand corner of the editing screen
|
|
unsigned char *txtp; // position of the current cursor in the text being edited
|
|
int drawstatusline; // true if the status line needs to be redrawn on the next keystroke
|
|
int insert; // true if the editor is in insert text mode
|
|
int tempx; // used to track the prefered x position when up/down arrowing
|
|
int TextChanged; // true if the program has been modified and therefor a save might be required
|
|
|
|
#define EDIT 1 // used to select the status line string
|
|
#define MARK 2
|
|
|
|
void FullScreenEditor(int x, int y, char *fname, int edit_buff_size, bool cmdfile);
|
|
char *findLine(int ln, int *inmulti);
|
|
void printLine(int ln);
|
|
void printScreen(void);
|
|
void SCursor(int x, int y);
|
|
int editInsertChar(unsigned char c, char *multi, int edit_buff_size);
|
|
void PrintFunctKeys(int);
|
|
void PrintStatus(void);
|
|
void SaveToProgMemory(void);
|
|
void editDisplayMsg(unsigned char *msg);
|
|
void GetInputString(unsigned char *prompt);
|
|
void Scroll(void);
|
|
void ScrollDown(void);
|
|
void MarkMode(unsigned char *cb, unsigned char *buf);
|
|
void PositionCursor(unsigned char *curp);
|
|
extern void setterminal();
|
|
static int multilinecomment = false;
|
|
bool modmode=false;
|
|
int oldfont;
|
|
int oldmode;
|
|
#define MAXCLIP 1024
|
|
// edit command:
|
|
// EDIT Will run the full screen editor on the current program memory, if run after an error will place the cursor on the error line
|
|
void edit(unsigned char *cmdline, bool cmdfile) {
|
|
unsigned char *fromp, *p=NULL;
|
|
int y, x, edit_buff_size ;
|
|
optioncolourcodesave=Option.ColourCode;
|
|
char name[STRINGSIZE], *filename=NULL;
|
|
getargs(&cmdline,1,(unsigned char *)",");
|
|
if(argc){
|
|
strcpy(name,(char *)getFstring(argv[0]));
|
|
filename=name;
|
|
}
|
|
if(CurrentLinePtr && cmdfile) error("Invalid in a program");
|
|
if(argc==0 && !cmdfile)error("Syntax");
|
|
if(!cmdfile){
|
|
SaveContext();
|
|
ClearVars(0,FALSE);
|
|
}
|
|
#ifdef PICOMITEVGA
|
|
modmode=false;
|
|
editactive=1;
|
|
oldmode = DISPLAY_TYPE;
|
|
oldfont=PromptFont;
|
|
if(HRes<512){
|
|
DISPLAY_TYPE=SCREENMODE1;
|
|
modmode=true;
|
|
ResetDisplay();
|
|
}
|
|
//
|
|
memset((void *)WriteBuf, 0, ScreenSize);
|
|
|
|
#ifdef PICOMITEVGA
|
|
#ifdef rp2350
|
|
#ifdef HDMI
|
|
if(DISPLAY_TYPE==SCREENMODE3)for(int i=0;i<16;i++)map16[i]=remap[i]=RGB555(MAP16DEF[i]);
|
|
#else
|
|
if(DISPLAY_TYPE==SCREENMODE3)for(int i=0;i<16;i++)map16[i]=remap[i]=i;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#endif
|
|
#ifndef USBKEYBOARD
|
|
if(mouse0==false && Option.MOUSE_CLOCK)initMouse0(0); //see if there is a mouse to initialise
|
|
#endif
|
|
if(Option.ColourCode) {
|
|
gui_fcolour = WHITE;
|
|
gui_bcolour = BLACK;
|
|
}
|
|
if(Option.DISPLAY_CONSOLE == true && gui_font_width > 16*HRes/640) error("Font is too large");
|
|
if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf)FreeMemorySafe((void **)&WriteBuf);
|
|
if(cmdfile){
|
|
ClearVars(0,true);
|
|
ClearRuntime(true);
|
|
}
|
|
if(HRes==640 || HRes==512 || HRes==848 || HRes==720){
|
|
SetFont(1);
|
|
PromptFont=1;
|
|
}
|
|
if(modmode){
|
|
#ifdef HDMI
|
|
if(FullColour || MediumRes ){
|
|
#endif
|
|
SetFont(1);
|
|
PromptFont=1;
|
|
#ifdef HDMI
|
|
} else {
|
|
SetFont(2<<4 | 1);
|
|
PromptFont=2<<4 | 1;
|
|
}
|
|
#endif
|
|
}
|
|
#ifdef PICOMITEWEB
|
|
cleanserver();
|
|
#endif
|
|
multilinecomment = false;
|
|
EdBuff = GetTempMemory(EDIT_BUFFER_SIZE);
|
|
edit_buff_size=EDIT_BUFFER_SIZE;
|
|
char buff[STRINGSIZE*2]={0};
|
|
*EdBuff = 0;
|
|
|
|
VHeight = Option.Height - 2;
|
|
VWidth = Option.Width;
|
|
edx = edy = curx = cury = y = x = tempx = 0;
|
|
txtp = EdBuff;
|
|
*tknbuf = 0;
|
|
if(filename==NULL){
|
|
fromp = ProgMemory;
|
|
p = EdBuff;
|
|
nbrlines = 0;
|
|
while(*fromp != 0xff) {
|
|
if(*fromp == T_NEWLINE) {
|
|
if(StartEditPoint >= ProgMemory) {
|
|
if(StartEditPoint == fromp) {
|
|
y = nbrlines; // we will start editing at this line
|
|
tempx = x = StartEditChar;
|
|
txtp = p + StartEditChar;
|
|
}
|
|
} else {
|
|
if(StartEditPoint == (unsigned char *)nbrlines) {
|
|
y = nbrlines;
|
|
tempx = x = StartEditChar;
|
|
txtp = p + StartEditChar;
|
|
}
|
|
}
|
|
nbrlines++;
|
|
if(Option.continuation){
|
|
fromp = llist((unsigned char *)buff, fromp); // otherwise expand the line
|
|
if(!(nbrlines==1 && buff[0]=='\'' && buff[1]=='#'))
|
|
{
|
|
nbrlines+=format_string(&buff[0],Option.Width);
|
|
strcat((char *)p,buff);
|
|
p += strlen((char *)buff);
|
|
*p++ = '\n'; *p = 0;
|
|
} else nbrlines=0;
|
|
} else {
|
|
fromp = llist(p, fromp);
|
|
if(!(nbrlines==1 && p[0]=='\'' && p[1]=='#')){
|
|
p += strlen((char *)p);
|
|
*p++ = '\n'; *p = 0;
|
|
} else nbrlines=0;
|
|
}
|
|
}
|
|
// finally, is it the end of the program?
|
|
if(fromp[0] == 0 || fromp[0] == 0xff) break;
|
|
}
|
|
} else {
|
|
// char *fname = (char *)filename;
|
|
char c;
|
|
int fsize;
|
|
// strcpy(name,fname);
|
|
if(!ExistsFile(filename)){
|
|
if (strchr(filename, '.') == NULL) strcat(filename, ".bas");
|
|
}
|
|
if(!fstrstr(filename,".bas"))Option.ColourCode=0;
|
|
if(ExistsFile(filename)){
|
|
int fnbr1;
|
|
fnbr1 = FindFreeFileNbr();
|
|
BasicFileOpen(filename, fnbr1, FA_READ);
|
|
if(filesource[fnbr1]!=FLASHFILE) fsize = f_size(FileTable[fnbr1].fptr);
|
|
else fsize = lfs_file_size(&lfs,FileTable[fnbr1].lfsptr);
|
|
if(fsize > edit_buff_size - 10) error("Out of memory");
|
|
p=EdBuff;
|
|
char *q=(char *)EdBuff;
|
|
do
|
|
{ // while waiting for the end of file
|
|
c = FileGetChar(fnbr1);
|
|
if(c=='\n'){
|
|
nbrlines++;
|
|
if(Option.continuation){
|
|
strcpy(buff,q);
|
|
nbrlines+=format_string(&buff[0],Option.Width);
|
|
strcpy(q,buff);
|
|
p=(unsigned char *)q+strlen(q);
|
|
q=(char *)p;
|
|
}
|
|
}
|
|
if(c=='\r')continue;
|
|
*p++=c;
|
|
} while (!FileEOF(fnbr1));
|
|
p++;
|
|
FileClose(fnbr1);
|
|
}
|
|
txtp=EdBuff;
|
|
tempx=x=0;
|
|
}
|
|
if(nbrlines == 0) nbrlines++;
|
|
if(p > EdBuff) --p;
|
|
*p = 0; // erase the last line terminator
|
|
//Only setterminal if editor requires is bigger than 80*24
|
|
if (Option.Width > SCREENWIDTH || Option.Height > SCREENHEIGHT){
|
|
setterminal((Option.Height > SCREENHEIGHT)?Option.Height:SCREENHEIGHT,(Option.Width > SCREENWIDTH)?Option.Width:SCREENWIDTH); // or height is > 24
|
|
}
|
|
PrintString("\033[?1000h"); // Tera Term turn on mouse click report in VT200 mode
|
|
PrintString("\0337\033[2J\033[H"); // vt100 clear screen and home cursor
|
|
MX470Display(DISPLAY_CLS); // clear screen on the MX470 display only
|
|
SCursor(0, 0);
|
|
PrintFunctKeys(EDIT);
|
|
|
|
if(nbrlines > VHeight) {
|
|
edy = y - VHeight/2; // edy is the line displayed at the top
|
|
if(edy < 0) edy = 0; // compensate if we are near the start
|
|
y = y - edy; // y is the line on the screen
|
|
}
|
|
if(cmdfile)m_alloc(M_VAR); //clean up clipboard usage
|
|
FullScreenEditor(x,y, filename, edit_buff_size, cmdfile);
|
|
if(cmdfile)memset(tknbuf, 0, STRINGSIZE); // zero this so that nextstmt is pointing to the end of program
|
|
MMCharPos = 0;
|
|
}
|
|
|
|
/* @endcond */
|
|
void cmd_edit(void){
|
|
edit(cmdline, true);
|
|
}
|
|
void cmd_editfile(void){
|
|
edit(cmdline, FALSE);
|
|
}
|
|
int find_longest_line_length(const char *text ,int *linein) {
|
|
int current_length = 0;
|
|
int max_length = 0;
|
|
const char *ptr = text;
|
|
int line=0;
|
|
while (*ptr) {
|
|
if (*ptr == '\n') {
|
|
line++;
|
|
if (ptr > text && *(ptr - 1) == '_' && *(ptr - 2)==' ' && Option.continuation) {
|
|
// Line continuation, do not reset length
|
|
} else {
|
|
// If this line exceeds the max, update
|
|
if (current_length > max_length) {
|
|
max_length = current_length;
|
|
*linein=line;
|
|
}
|
|
current_length = 0; // Reset for a new line
|
|
}
|
|
} else {
|
|
// Increase length for this segment of the line
|
|
current_length++;
|
|
}
|
|
|
|
ptr++;
|
|
}
|
|
|
|
// Final check in case the last line was the longest
|
|
if (current_length > max_length) {
|
|
max_length = current_length;
|
|
}
|
|
|
|
return max_length;
|
|
}
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
#ifndef PICOMITE
|
|
#ifndef PICOMITEWEB
|
|
static short lastx1=9999, lasty1=9999;
|
|
static uint16_t lastfc, lastbc;
|
|
static bool leftpushed=false, rightpushed=false, middlepushed=false;
|
|
#endif
|
|
#endif
|
|
void FullScreenEditor(int xx, int yy, char *fname, int edit_buff_size, bool cmdfile) {
|
|
int c=-1, i;
|
|
unsigned char buf[MAXCLIP+2], clipboard[MAXCLIP+2];
|
|
unsigned char *p, *tp, BreakKeySave;
|
|
char currdel=0, nextdel=0, lastdel=0;
|
|
char multi=false;
|
|
#ifdef PICOMITEVGA
|
|
int fontinc=gui_font_width / 8; //use to decide where to position mouse cursor
|
|
int OptionY_TILESave;
|
|
int ytileheightsave;
|
|
ytileheightsave=ytileheight;
|
|
OptionY_TILESave=Y_TILE;
|
|
if(!Option.ColourCode)ytileheight=16;
|
|
else {
|
|
ytileheight=gui_font_height;
|
|
Y_TILE=VRes/ytileheight;
|
|
if(VRes % ytileheight)Y_TILE++;
|
|
}
|
|
#else
|
|
char RefreshSave=Option.Refresh;
|
|
Option.Refresh=0;
|
|
#endif
|
|
printScreen(); // draw the screen
|
|
SCursor(xx, yy);
|
|
drawstatusline = true;
|
|
unsigned char lastkey = 0;
|
|
int y, statuscount;
|
|
clipboard[0] = 0;
|
|
buf[0]=0;
|
|
insert = true;
|
|
TextChanged = false;
|
|
BreakKeySave = BreakKey;
|
|
BreakKey = 0;
|
|
while(1) {
|
|
statuscount = 0;
|
|
do {
|
|
#ifndef PICOMITE
|
|
#ifndef PICOMITEWEB
|
|
c=-1;
|
|
#ifdef USBKEYBOARD
|
|
if(HID[1].Device_type==2 && DISPLAY_TYPE==SCREENMODE1){
|
|
#else
|
|
if(mouse0 && DISPLAY_TYPE==SCREENMODE1){
|
|
#endif
|
|
if(!nunstruct[2].L)leftpushed=false;
|
|
if(!nunstruct[2].R)rightpushed=false;
|
|
if(!nunstruct[2].C)middlepushed=false;
|
|
if(nunstruct[2].y1!=lasty1 || nunstruct[2].x1!=lastx1){
|
|
if(lastx1!=9999){
|
|
#ifdef HDMI
|
|
if(FullColour){
|
|
#endif
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilefcols[lasty1*X_TILE+i]=lastfc;
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilebcols[lasty1*X_TILE+i]=lastbc;
|
|
#ifdef HDMI
|
|
} else {
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilefcols_w[lasty1*X_TILE+i]=lastfc;
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilebcols_w[lasty1*X_TILE+i]=lastbc;
|
|
}
|
|
#endif
|
|
}
|
|
lastx1=nunstruct[2].x1;
|
|
lasty1=nunstruct[2].y1;
|
|
if(lasty1>=VHeight)lasty1=VHeight-1;
|
|
#ifdef HDMI
|
|
if(FullColour){
|
|
#endif
|
|
lastfc=tilefcols[lasty1*X_TILE+lastx1*fontinc];
|
|
lastbc=tilebcols[lasty1*X_TILE+lastx1*fontinc];
|
|
#ifdef HDMI
|
|
} else {
|
|
lastfc=tilefcols_w[lasty1*X_TILE+lastx1*fontinc];
|
|
lastbc=tilebcols_w[lasty1*X_TILE+lastx1*fontinc];
|
|
}
|
|
if(FullColour){
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilefcols[lasty1*X_TILE+i]=RGB555(RED);
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilebcols[lasty1*X_TILE+i]=RGB555(WHITE);
|
|
} else {
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilefcols_w[lasty1*X_TILE+i]=RGB332(RED);
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilebcols_w[lasty1*X_TILE+i]=RGB332(WHITE);
|
|
}
|
|
#else
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilefcols[lasty1*X_TILE+i]=RGB121pack(RED);
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilebcols[lasty1*X_TILE+i]=RGB121pack(WHITE);
|
|
#endif
|
|
}
|
|
if((nunstruct[2].L && leftpushed==false && rightpushed==false && middlepushed==false) ||
|
|
(nunstruct[2].R && leftpushed==false && rightpushed==false && middlepushed==false) ||
|
|
(nunstruct[2].C && leftpushed==false && rightpushed==false && middlepushed==false)){
|
|
if(nunstruct[2].L)leftpushed=true;
|
|
else if(nunstruct[2].R)rightpushed=true;
|
|
else middlepushed=true;
|
|
if(lastx1 >= 0 && lastx1 < VWidth && lasty1 >= 0 && lasty1 < VHeight) { // c == ' ' means mouse down and no shift, ctrl, etc
|
|
ShowCursor(false);
|
|
// first position on the y axis
|
|
while(*txtp != 0 && lasty1 > cury) // assume we have to move down the screen
|
|
if(*txtp++ == '\n') cury++;
|
|
while(txtp != EdBuff && lasty1 < cury) // assume we have to move up the screen
|
|
if(*--txtp == '\n') cury--;
|
|
while(txtp != EdBuff && *(txtp - 1) != '\n') txtp--; // move to the beginning of the line
|
|
for(curx = 0; curx < lastx1 && *txtp && *txtp != '\n'; curx++) txtp++; // now position on the x axis
|
|
PositionCursor(txtp);
|
|
PrintStatus();
|
|
ShowCursor(true);
|
|
#ifdef HDMI
|
|
if(FullColour){
|
|
#endif
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilefcols[lasty1*X_TILE+i]=lastfc;
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilebcols[lasty1*X_TILE+i]=lastbc;
|
|
#ifdef HDMI
|
|
} else {
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilefcols_w[lasty1*X_TILE+i]=lastfc;
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilebcols_w[lasty1*X_TILE+i]=lastbc;
|
|
}
|
|
#endif
|
|
}
|
|
if(rightpushed==true){
|
|
c=F4;
|
|
}
|
|
else if(middlepushed==true){
|
|
c=F5;
|
|
}
|
|
}
|
|
}
|
|
ShowCursor(true);
|
|
if(!((rightpushed==true && c==F4) || (middlepushed==true && c==F5)))
|
|
#else
|
|
ShowCursor(true);
|
|
#endif
|
|
#else
|
|
ShowCursor(true);
|
|
#endif
|
|
|
|
c = MMInkey();
|
|
|
|
if(statuscount++ == 5000) PrintStatus();
|
|
} while(c == -1);
|
|
ShowCursor(false);
|
|
|
|
if(drawstatusline) PrintFunctKeys(EDIT);
|
|
drawstatusline = false;
|
|
if(c == TAB) {
|
|
strcpy((char *)buf, " ");
|
|
buf[Option.Tab - ((edx + curx) % Option.Tab)] = 0;
|
|
} else {
|
|
buf[0] = c;
|
|
buf[1] = 0;
|
|
}
|
|
do {
|
|
if(buf[0] == BreakKeySave) buf[0] = ESC; // if the user tried to break turn it into an escape
|
|
switch(buf[0]) {
|
|
|
|
case '\r':
|
|
case '\n': // first count the spaces at the beginning of the line
|
|
if(txtp != EdBuff && (*txtp == '\n' || *txtp == 0)) { // we only do this if we are at the end of the line
|
|
for(tp = txtp - 1, i = 0; *tp != '\n' && tp >= EdBuff; tp--)
|
|
if(*tp != ' ')
|
|
i = 0; // not a space
|
|
else
|
|
i++; // potential space at the start
|
|
if(tp == EdBuff && *tp == ' ') i++; // correct for a counting error at the start of the buffer
|
|
if(buf[1] != 0)
|
|
i = 0; // do not insert spaces if buffer too small or has something in it
|
|
else
|
|
buf[i + 1] = 0; // make sure that the end of the buffer is zeroed
|
|
while(i) buf[i--] = ' '; // now, place our spaces in the typeahead buffer
|
|
}
|
|
if(!editInsertChar('\n',&multi, edit_buff_size)) break; // insert the newline
|
|
TextChanged = true;
|
|
nbrlines++;
|
|
if(!(cury < VHeight - 1)) // if we are NOT at the bottom
|
|
edy++; // otherwise scroll
|
|
printScreen(); // redraw everything
|
|
PositionCursor(txtp);
|
|
break;
|
|
|
|
case CTRLKEY('E'):
|
|
case UP: if(cury == 0 && edy == 0) break;
|
|
if(*txtp == '\n') txtp--; // step back over the terminator if we are right at the end of the line
|
|
while(txtp != EdBuff && *txtp != '\n') txtp--; // move to the beginning of the line
|
|
if(txtp != EdBuff) {
|
|
txtp--; // step over the terminator to the end of the previous line
|
|
while(txtp != EdBuff && *txtp != '\n') txtp--; // move to the beginning of that line
|
|
if(*txtp == '\n') txtp++; // and position at the start
|
|
}
|
|
for(i = 0; i < edx + tempx && *txtp != 0 && *txtp != '\n'; i++, txtp++); // move the cursor to the column
|
|
|
|
if(cury > 2 || edy == 0) { // if we are more that two lines from the top
|
|
if(cury > 0) SCursor(i, cury - 1); // just move the cursor up
|
|
}
|
|
else if(edy > 0) { // if we are two lines or less from the top
|
|
curx = i;
|
|
ScrollDown();
|
|
}
|
|
PositionCursor(txtp);
|
|
break;
|
|
|
|
case CTRLKEY('X'):
|
|
case DOWN: p = txtp;
|
|
while(*p != 0 && *p != '\n') p++; // move to the end of this line
|
|
if(*p == 0) break; // skip if it is at the end of the file
|
|
p++; // step over the line terminator to the start of the next line
|
|
for(i = 0; i < edx + tempx && *p != 0 && *p != '\n'; i++, p++); // move the cursor to the column
|
|
txtp = p;
|
|
|
|
if(cury < VHeight - 3 || edy + VHeight == nbrlines) {
|
|
if(cury < VHeight - 1) SCursor(i, cury + 1);
|
|
}
|
|
else if(edy + VHeight < nbrlines) {
|
|
curx = i;
|
|
Scroll();
|
|
}
|
|
PositionCursor(txtp);
|
|
break;
|
|
|
|
case CTRLKEY('S'):
|
|
case LEFT: if(txtp == EdBuff) break;
|
|
if(*(txtp - 1) == '\n') { // if at the beginning of the line wrap around
|
|
buf[1] = UP;
|
|
buf[2] = END;
|
|
buf[3] = 1;
|
|
buf[4] = 0;
|
|
} else {
|
|
txtp--;
|
|
PositionCursor(txtp);
|
|
}
|
|
break;
|
|
|
|
case CTRLKEY('D'):
|
|
case RIGHT: if(*txtp == '\n') { // if at the end of the line wrap around
|
|
buf[1] = HOME;
|
|
buf[2] = DOWN;
|
|
buf[3] = 0;
|
|
break;
|
|
}
|
|
if(curx >= VWidth) {
|
|
editDisplayMsg((unsigned char *)" LINE IS TOO LONG ");
|
|
break;
|
|
}
|
|
|
|
if(*txtp != 0) txtp++; // now we can move the cursor
|
|
PositionCursor(txtp);
|
|
break;
|
|
|
|
// backspace
|
|
case BKSP: if(txtp == EdBuff) break;
|
|
if(*(txtp - 1) == '\n') { // if at the beginning of the line wrap around
|
|
buf[1] = UP;
|
|
buf[2] = END;
|
|
buf[3] = DEL;
|
|
buf[4] = 0;
|
|
break;
|
|
}
|
|
// find how many spaces are between the cursor and the start of the line
|
|
for(p = txtp - 1; *p == ' ' && p != EdBuff; p--);
|
|
if((p == EdBuff || *p == '\n') && txtp - p > 1) {
|
|
i = txtp - p - 1;
|
|
// we have have the number of continuous spaces between the cursor and the start of the line
|
|
// now figure out the number of backspaces to the nearest tab stop
|
|
|
|
i = (i % Option.Tab); if(i == 0) i = Option.Tab;
|
|
// load the corresponding number of deletes in the type ahead buffer
|
|
buf[i + 1] = 0;
|
|
while(i--) {
|
|
buf[i + 1] = DEL;
|
|
txtp--;
|
|
}
|
|
// and let the delete case take care of deleting the characters
|
|
PositionCursor(txtp);
|
|
break;
|
|
}
|
|
// this is just a normal backspace (not a tabbed backspace)
|
|
txtp--;
|
|
PositionCursor(txtp);
|
|
// fall through to delete the char
|
|
|
|
case CTRLKEY(']'):
|
|
case DEL: if(*txtp == 0) break;
|
|
p = txtp;
|
|
c = *p;
|
|
currdel=*p;
|
|
if(p!=EdBuff+edit_buff_size-1)nextdel=p[1];
|
|
else nextdel=0;
|
|
if(p!=EdBuff){
|
|
lastdel=*(--p);
|
|
p++;
|
|
} else lastdel=0;
|
|
while(*p) {
|
|
p[0] = p[1];
|
|
p++;
|
|
}
|
|
if(c == '\n') {
|
|
printScreen();
|
|
nbrlines--;
|
|
}
|
|
else
|
|
printLine(edy + cury);
|
|
TextChanged = true;
|
|
PositionCursor(txtp);
|
|
if(currdel=='/' && nextdel=='*' && Option.ColourCode)printScreen();
|
|
if(currdel=='*' && nextdel=='/' && Option.ColourCode)printScreen();
|
|
if(currdel=='/' && lastdel=='*' && Option.ColourCode)printScreen();
|
|
if(currdel=='*' && lastdel=='/' && Option.ColourCode)printScreen();
|
|
break;
|
|
|
|
case CTRLKEY('N'):
|
|
case INSERT:insert = !insert;
|
|
break;
|
|
|
|
case CTRLKEY('U'):
|
|
case HOME: if(txtp == EdBuff) break;
|
|
if(lastkey == HOME || lastkey == CTRLKEY('U')) {
|
|
edx = edy = curx = cury = 0;
|
|
txtp = EdBuff;
|
|
PrintString("\033[2J\033[H"); // vt100 clear screen and home cursor
|
|
MX470Display(DISPLAY_CLS); // clear screen on the MX470 display only
|
|
printScreen();
|
|
PrintFunctKeys(EDIT);
|
|
PositionCursor(txtp);
|
|
break;
|
|
}
|
|
if(*txtp == '\n') txtp--; // step back over the terminator if we are right at the end of the line
|
|
while(txtp != EdBuff && *txtp != '\n') txtp--; // move to the beginning of the line
|
|
if(*txtp == '\n') txtp++; // skip if no more lines above this one
|
|
PositionCursor(txtp);
|
|
break;
|
|
|
|
case CTRLKEY('K'):
|
|
case END: if(*txtp == 0) break; // already at the end
|
|
if(lastkey == END || lastkey == CTRLKEY('K')) { // jump to the end of the file
|
|
i = 0; p = txtp = EdBuff;
|
|
while(*txtp != 0) {
|
|
if(*txtp == '\n') { p = txtp + 1; i++; }
|
|
txtp++;
|
|
}
|
|
|
|
if(i >= VHeight) {
|
|
edy = i - VHeight + 1;
|
|
printScreen();
|
|
cury = VHeight - 1;
|
|
} else {
|
|
cury = i;
|
|
}
|
|
txtp = p;
|
|
curx = 0;
|
|
}
|
|
|
|
while(curx < VWidth && *txtp != 0 && *txtp != '\n') {
|
|
txtp++;
|
|
PositionCursor(txtp);
|
|
}
|
|
if(curx > VWidth) editDisplayMsg((unsigned char *)" LINE IS TOO LONG ");
|
|
break;
|
|
|
|
case CTRLKEY('P'):
|
|
case PUP: if(edy == 0) { // if we are already showing the top of the text
|
|
buf[1] = HOME; // force the editing point to the start of the text
|
|
buf[2] = HOME;
|
|
buf[3] = 0;
|
|
break;
|
|
} else if(edy >= VHeight - 1) { // if we can scroll a full screenfull
|
|
i = VHeight + 1;
|
|
edy -= VHeight;
|
|
} else { // if it is less than a full screenfull
|
|
i = edy + 1;
|
|
edy = 0;
|
|
}
|
|
while(i--) {
|
|
if(*txtp == '\n') txtp--; // step back over the terminator if we are right at the end of the line
|
|
while(txtp != EdBuff && *txtp != '\n') txtp--; // move to the beginning of the line
|
|
if(txtp == EdBuff) break; // skip if no more lines above this one
|
|
}
|
|
if(txtp != EdBuff) txtp++; // and position at the start of the line
|
|
for(i = 0; i < edx + curx && *txtp != 0 && *txtp != '\n'; i++, txtp++); // move the cursor to the column
|
|
printScreen();
|
|
PositionCursor(txtp);
|
|
break;
|
|
|
|
case CTRLKEY('L'):
|
|
case PDOWN: if(nbrlines <= edy + VHeight + 1) { // if we are already showing the end of the text
|
|
buf[1] = END; // force the editing point to the end of the text
|
|
buf[2] = END;
|
|
buf[3] = 0;
|
|
break; // cursor to the top line
|
|
} else if(nbrlines - edy - VHeight >= VHeight) { // if we can scroll a full screenfull
|
|
edy += VHeight;
|
|
i = VHeight;
|
|
} else { // if it is less than a full screenfull
|
|
i = nbrlines - VHeight - edy;
|
|
edy = nbrlines - VHeight;
|
|
}
|
|
if(*txtp == '\n') i--; // compensate if we are right at the end of a line
|
|
while(i--) {
|
|
if(*txtp == '\n') txtp++; // step over the terminator if we are right at the start of the line
|
|
while(*txtp != 0 && *txtp != '\n') txtp++; // move to the end of the line
|
|
if(*txtp == 0) break; // skip if no more lines after this one
|
|
}
|
|
if(txtp != EdBuff) txtp++; // and position at the start of the line
|
|
for(i = 0; i < edx + curx && *txtp != 0 && *txtp != '\n'; i++, txtp++); // move the cursor to the column
|
|
//y = cury;
|
|
printScreen();
|
|
PositionCursor(txtp);
|
|
break;
|
|
|
|
// Abort without saving
|
|
case ESC: uSec(50000); // wait 50ms to see if anything more is coming
|
|
routinechecks();
|
|
if(MMInkey() == '[' && MMInkey() == 'M') {
|
|
// received escape code for Tera Term reporting a mouse click or scroll wheel movement
|
|
int c, x, y;
|
|
c = MMInkey(); x = MMInkey() - '!'; y = MMInkey() - '!';
|
|
if(c == 'e' || c == 'a') { // Tera Term - SHIFT + mouse-wheel-rotate-down
|
|
buf[1] = UP;
|
|
buf[2] = 0;
|
|
} else if(c == 'd' || c == '`') { // Tera Term - SHIFT + mouse-wheel-rotate-up
|
|
buf[1] = DOWN;
|
|
buf[2] = 0;
|
|
} else if(c == ' ' && x >= 0 && x < VWidth && y >= 0 && y < VHeight) { // c == ' ' means mouse down and no shift, ctrl, etc
|
|
// first position on the y axis
|
|
while(*txtp != 0 && y > cury) // assume we have to move down the screen
|
|
if(*txtp++ == '\n') cury++;
|
|
while(txtp != EdBuff && y < cury) // assume we have to move up the screen
|
|
if(*--txtp == '\n') cury--;
|
|
while(txtp != EdBuff && *(txtp - 1) != '\n') txtp--; // move to the beginning of the line
|
|
for(curx = 0; curx < x && *txtp && *txtp != '\n'; curx++) txtp++; // now position on the x axis
|
|
PositionCursor(txtp);
|
|
}
|
|
break;
|
|
}
|
|
// this must be an ordinary escape (not part of an escape code)
|
|
if(TextChanged) {
|
|
GetInputString((unsigned char *)"Exit and discard all changes (Y/N): ");
|
|
if(toupper(*inpbuf) != 'Y') break;
|
|
}
|
|
// fall through to the normal exit
|
|
|
|
case CTRLKEY('Q'): // Save and exit
|
|
case F1: // Save and exit
|
|
case CTRLKEY('W'): // Save, exit and run
|
|
case F2: // Save, exit and run
|
|
// if(Option.continuation){
|
|
int line=0;
|
|
int i=find_longest_line_length((char *)EdBuff, &line);
|
|
if(i>255){
|
|
char buff[20]={};
|
|
sprintf(buff," LINE %d TOO LONG",line);
|
|
editDisplayMsg((unsigned char *)buff);
|
|
break;
|
|
}
|
|
// }
|
|
c=buf[0];
|
|
PrintString("\033[?1000l"); // Tera Term turn off mouse click report in vt200 mode
|
|
PrintString("\0338\033[2J\033[H"); // vt100 clear screen and home cursor
|
|
gui_fcolour = GUI_C_NORMAL;
|
|
PrintString(VT100_C_NORMAL);
|
|
gui_fcolour = PromptFC;
|
|
gui_bcolour = PromptBC;
|
|
MX470Cursor(0, 0); // home the cursor
|
|
MX470Display(DISPLAY_CLS); // clear screen on the MX470 display only
|
|
PrintString("\033[0m");
|
|
BreakKey = BreakKeySave;
|
|
Option.ColourCode=optioncolourcodesave;
|
|
#ifdef PICOMITEVGA
|
|
editactive=0;
|
|
Y_TILE=OptionY_TILESave;
|
|
ytileheight=ytileheightsave;
|
|
if(modmode){
|
|
DISPLAY_TYPE=oldmode;
|
|
ResetDisplay();
|
|
SetFont(oldfont);
|
|
PromptFont=oldfont;
|
|
MX470Display(DISPLAY_CLS); // clear screen on the MX470 display only
|
|
}
|
|
#ifdef HDMI
|
|
while(v_scanline!=0){}
|
|
if(DISPLAY_TYPE==SCREENMODE5)for(int i=0;i<256;i++)map256[i]=remap[i]=RGB555(MAP256DEF[i]);
|
|
else if(FullColour)for(int i=0;i<16;i++){
|
|
map16[i]=remap[i]=RGB555(MAP16DEF[i]);
|
|
map16pairs[i]=map16[i] | (map16[i]<<16);
|
|
}
|
|
else if(DISPLAY_TYPE==SCREENMODE3)for(int i=0;i<16;i++) {map16s[i]=RGB332(MAP16DEF[i]); map16d[i]=remap[i]=RGB332(MAP16DEF[i]) | (RGB332(MAP16DEF[i])<<8);}
|
|
else if(DISPLAY_TYPE==SCREENMODE2)for(int i=0;i<16;i++) map16q[i]=remap[i]=RGB332(MAP16DEF[i]) | (RGB332(MAP16DEF[i])<<8) | (RGB332(MAP16DEF[i])<<16) | (RGB332(MAP16DEF[i])<<24);
|
|
if(DISPLAY_TYPE==SCREENMODE1) {
|
|
if(FullColour){
|
|
tilefcols=(uint16_t *)((uint32_t)FRAMEBUFFER+(MODE1SIZE*3));
|
|
tilebcols=(uint16_t *)((uint32_t)FRAMEBUFFER+(MODE1SIZE*3)+(MODE1SIZE>>1));
|
|
X_TILE=MODE_H_ACTIVE_PIXELS/8;Y_TILE=MODE_V_ACTIVE_LINES/8;
|
|
for(int x=0;x<X_TILE;x++){
|
|
for(int y=0;y<Y_TILE;y++){
|
|
tilefcols[y*X_TILE+x]=RGB555(Option.DefaultFC);
|
|
tilebcols[y*X_TILE+x]=RGB555(Option.DefaultBC);
|
|
}
|
|
}
|
|
} else {
|
|
tilefcols_w=(uint8_t *)DisplayBuf+MODE1SIZE;
|
|
tilebcols_w=tilefcols_w+(MODE_H_ACTIVE_PIXELS/8)*(MODE_V_ACTIVE_LINES/8); //minimum tilesize is 8x8
|
|
memset(tilefcols_w,RGB332(Option.DefaultFC),(MODE_H_ACTIVE_PIXELS/8)*(MODE_V_ACTIVE_LINES/8)*sizeof(uint8_t));
|
|
memset(tilebcols_w,RGB332(Option.DefaultBC),(MODE_H_ACTIVE_PIXELS/8)*(MODE_V_ACTIVE_LINES/8)*sizeof(uint8_t));
|
|
X_TILE=MODE_H_ACTIVE_PIXELS/8;Y_TILE=MODE_V_ACTIVE_LINES/ytileheight;
|
|
}
|
|
}
|
|
#endif
|
|
#else
|
|
Option.Refresh=RefreshSave;
|
|
#endif
|
|
if(c != ESC && TextChanged && fname==NULL) SaveToProgMemory();
|
|
if(c != ESC && TextChanged && fname) {
|
|
int fnbr1;
|
|
if(ExistsFile(fname)){
|
|
char backup[FF_MAX_LFN];
|
|
strcpy(backup,fname);
|
|
strcat(backup,".bak");
|
|
fnbr1 = FindFreeFileNbr();
|
|
BasicFileOpen(fname, fnbr1, FA_READ);
|
|
int fnbr2 = FindFreeFileNbr();
|
|
BasicFileOpen(backup, fnbr2, FA_WRITE | FA_CREATE_ALWAYS);
|
|
while (!FileEOF(fnbr1))
|
|
{ // while waiting for the end of file
|
|
FilePutChar(FileGetChar(fnbr1),fnbr2);
|
|
}
|
|
FileClose(fnbr1);
|
|
FileClose(fnbr2);
|
|
}
|
|
fnbr1=FindFreeFileNbr();
|
|
BasicFileOpen(fname, fnbr1, FA_WRITE | FA_CREATE_ALWAYS);
|
|
p=EdBuff;
|
|
if(Option.continuation){
|
|
unsigned char *q=p;
|
|
while(*p){
|
|
if(*p==Option.continuation && p[1]=='\n')p+=2; //step over the continuation characters
|
|
else *q++=*p++;
|
|
}
|
|
*q=0;
|
|
p=EdBuff;
|
|
}
|
|
do
|
|
{ // while waiting for the end of file
|
|
c = *p++;
|
|
if(c=='\n')FilePutChar('\r',fnbr1);
|
|
FilePutChar(c,fnbr1);
|
|
} while (*p);
|
|
FileClose(fnbr1);
|
|
}
|
|
if(cmdfile==false){
|
|
RestoreContext(false);
|
|
return;
|
|
}
|
|
if(c == ESC || c == CTRLKEY('Q') || c == F1 || fname) {
|
|
cmdline=NULL;
|
|
do_end(false);
|
|
longjmp(mark, 1); // jump back to the input prompt
|
|
}
|
|
// this must be save, exit and run. We have done the first two, now do the run part.
|
|
ClearRuntime(true);
|
|
// WatchdogSet = false;
|
|
PrepareProgram(true);
|
|
// Create a global constant MM.CMDLINE$ containing the empty string.
|
|
// (void) findvar((unsigned char *)"MM.CMDLINE$", V_FIND | V_DIM_VAR | T_CONST);
|
|
if(Option.LIBRARY_FLASH_SIZE == MAX_PROG_SIZE) ExecuteProgram(LibMemory ); // run anything that might be in the library
|
|
if(*ProgMemory != T_NEWLINE) return; // no program to run
|
|
#ifdef PICOMITEWEB
|
|
cleanserver();
|
|
#endif
|
|
nextstmt = ProgMemory;
|
|
#ifdef USBKEYBOARD
|
|
clearrepeat();
|
|
#endif
|
|
return;
|
|
|
|
// Search
|
|
case CTRLKEY('R'):
|
|
case F3: GetInputString((unsigned char *)"Find (Use SHIFT-F3 to repeat): ");
|
|
if(*inpbuf == 0 || *inpbuf == ESC) break;
|
|
if(!(*inpbuf == 0xb3 || *inpbuf == F3)) strcpy((char *)tknbuf, (char *)inpbuf);
|
|
// fall through
|
|
|
|
case CTRLKEY('G'):
|
|
case 0xB3: // SHIFT-F3
|
|
p = txtp;
|
|
if(*p == 0) p = EdBuff - 1;
|
|
i = strlen((char *)tknbuf);
|
|
while(1) {
|
|
p++;
|
|
if(p == txtp) break;
|
|
if(*p == 0) p = EdBuff;
|
|
if(p == txtp) break;
|
|
if(mem_equal(p, tknbuf, i)) break;
|
|
}
|
|
if(p == txtp) {
|
|
editDisplayMsg((unsigned char *)" NOT FOUND ");
|
|
break;
|
|
}
|
|
for(y = 0, txtp = EdBuff; txtp != p; txtp++) { // find the line and column of the string
|
|
if(*txtp == '\n') {
|
|
y++; // y is the line
|
|
}
|
|
}
|
|
edy = y - VHeight/2; // edy is the line displayed at the top
|
|
if(edy < 0) edy = 0; // compensate if we are near the start
|
|
printScreen();
|
|
PositionCursor(txtp);
|
|
// SCursor(x, y);
|
|
break;
|
|
|
|
// Mark
|
|
case CTRLKEY('T'):
|
|
case F4: MarkMode(clipboard, &buf[1]);
|
|
printScreen();
|
|
PrintFunctKeys(EDIT);
|
|
PositionCursor(txtp);
|
|
break;
|
|
|
|
case CTRLKEY('Y'):
|
|
case CTRLKEY('V'):
|
|
case F5: if(*clipboard == 0) {
|
|
editDisplayMsg((unsigned char *)" CLIPBOARD IS EMPTY ");
|
|
break;
|
|
}
|
|
for(i = 0; clipboard[i]; i++) buf[i + 1] = clipboard[i];
|
|
buf[i + 1] = 0;
|
|
break;
|
|
|
|
// F6 to F12 - Normal function keys
|
|
case F6:
|
|
case F7:
|
|
case F8:
|
|
case F9:
|
|
case F10:
|
|
case F11:
|
|
case F12:
|
|
break;
|
|
|
|
// a normal character
|
|
default: c = buf[0];
|
|
if(c < ' ' || c > '~') break; // make sure that this is valid
|
|
if(curx >= VWidth) {
|
|
editDisplayMsg((unsigned char *)" LINE IS TOO LONG ");
|
|
break;
|
|
}
|
|
TextChanged = true;
|
|
if(insert || *txtp == '\n' || *txtp == 0) {
|
|
if(!editInsertChar(c, &multi, edit_buff_size)) break; // insert it
|
|
} else
|
|
*txtp++ = c; // or just overtype
|
|
printLine(edy + cury); // redraw the whole line so that colour coding will occur
|
|
PositionCursor(txtp);
|
|
// SCursor(x, cury);
|
|
tempx = cury; // used to track the preferred cursor position
|
|
if(multi && Option.ColourCode)printScreen();
|
|
break;
|
|
|
|
}
|
|
lastkey = buf[0];
|
|
if(buf[0] != UP && buf[0] != DOWN && buf[0] != CTRLKEY('E') && buf[0] != CTRLKEY('X')) tempx = curx;
|
|
buf[MAXCLIP + 1] = 0;
|
|
for(i = 0; i < MAXCLIP + 1; i++) buf[i] = buf[i + 1]; // suffle down the buffer to get the next char
|
|
} while(*buf);
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************************************************
|
|
UTILITY FUNCTIONS USED BY THE FULL SCREEN EDITOR
|
|
*******************************************************************************************************************/
|
|
|
|
|
|
void PositionCursor(unsigned char *curp) {
|
|
int ln, col;
|
|
unsigned char *p;
|
|
|
|
for(p = EdBuff, ln = col = 0; p < curp; p++) {
|
|
if(*p == '\n') {
|
|
ln++;
|
|
col = 0;
|
|
} else
|
|
col++;
|
|
}
|
|
if(ln < edy || ln >= edy + VHeight) return;
|
|
SCursor(col, ln - edy);
|
|
}
|
|
|
|
|
|
|
|
// mark mode
|
|
// implement the mark mode (when the user presses F4)
|
|
void MarkMode(unsigned char *cb, unsigned char *buf) {
|
|
unsigned char *p, *mark, *oldmark;
|
|
int c=-1, x, y, i, oldx, oldy, txtpx, txtpy, errmsg = false;
|
|
#ifdef PICOMITEVGA
|
|
int fontinc=gui_font_width/8;
|
|
#endif
|
|
PrintFunctKeys(MARK);
|
|
oldmark = mark = txtp;
|
|
txtpx = oldx = curx; txtpy = oldy = cury;
|
|
while(1) {
|
|
c=-1;
|
|
#ifndef PICOMITE
|
|
#ifndef PICOMITEWEB
|
|
#ifdef USBKEYBOARD
|
|
if(HID[1].Device_type==2 && DISPLAY_TYPE==SCREENMODE1){
|
|
#else
|
|
if(mouse0 && DISPLAY_TYPE==SCREENMODE1){
|
|
#endif
|
|
if(!nunstruct[2].L)leftpushed=false;
|
|
if(!nunstruct[2].R)rightpushed=false;
|
|
if(!nunstruct[2].C)middlepushed=false;
|
|
if(nunstruct[2].y1!=lasty1 || nunstruct[2].x1!=lastx1){
|
|
if(lastx1!=9999){
|
|
#ifdef HDMI
|
|
if(FullColour){
|
|
#endif
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilefcols[lasty1*X_TILE+i]=lastfc;
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilebcols[lasty1*X_TILE+i]=lastbc;
|
|
#ifdef HDMI
|
|
} else {
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilefcols_w[lasty1*X_TILE+i]=lastfc;
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilebcols_w[lasty1*X_TILE+i]=lastbc;
|
|
}
|
|
#endif
|
|
}
|
|
lastx1=nunstruct[2].x1;
|
|
lasty1=nunstruct[2].y1;
|
|
if(lasty1>=VHeight)lasty1=VHeight-1;
|
|
#ifdef HDMI
|
|
if(FullColour){
|
|
#endif
|
|
lastfc=tilefcols[lasty1*X_TILE+lastx1*fontinc];
|
|
lastbc=tilebcols[lasty1*X_TILE+lastx1*fontinc];
|
|
#ifdef HDMI
|
|
} else {
|
|
lastfc=tilefcols_w[lasty1*X_TILE+lastx1*fontinc];
|
|
lastbc=tilebcols_w[lasty1*X_TILE+lastx1*fontinc];
|
|
}
|
|
if(FullColour){
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilefcols[lasty1*X_TILE+i]=RGB555(RED);
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilebcols[lasty1*X_TILE+i]=RGB555(WHITE);
|
|
} else {
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilefcols_w[lasty1*X_TILE+i]=RGB332(RED);
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilebcols_w[lasty1*X_TILE+i]=RGB332(WHITE);
|
|
}
|
|
#else
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilefcols[lasty1*X_TILE+i]=RGB121pack(RED);
|
|
for(int i=lastx1*fontinc;i<(lastx1+1)*fontinc;i++)tilebcols[lasty1*X_TILE+i]=RGB121pack(WHITE);
|
|
#endif
|
|
}
|
|
if((nunstruct[2].L && leftpushed==false && rightpushed==false && middlepushed==false) ||
|
|
(nunstruct[2].R && leftpushed==false && rightpushed==false && middlepushed==false) ||
|
|
(nunstruct[2].C && leftpushed==false && rightpushed==false && middlepushed==false)){
|
|
if(nunstruct[2].L)leftpushed=true;
|
|
else if(nunstruct[2].R)rightpushed=true;
|
|
else middlepushed=true;
|
|
if(lastx1 >= 0 && lastx1 < VWidth && lasty1 >= 0 && lasty1 < VHeight) { // c == ' ' means mouse down and no shift, ctrl, etc
|
|
// unsigned char * mtxtp=txtp;
|
|
p=txtp;
|
|
// first position on the y axis
|
|
while(*p != 0 && lasty1 > cury) // assume we have to move down the screen
|
|
if(*p++ == '\n') cury++;
|
|
while(p != EdBuff && lasty1 < cury) // assume we have to move up the screen
|
|
if(*--p == '\n') cury--;
|
|
while(p != EdBuff && *(p - 1) != '\n') p--; // move to the beginning of the line
|
|
for(curx = 0; curx < lastx1 && *p && *p != '\n'; curx++) p++; // now position on the x axis
|
|
PositionCursor(p);
|
|
mark=p;
|
|
}
|
|
if(rightpushed==true){
|
|
c=F4;
|
|
}
|
|
if(middlepushed==true){
|
|
c=F5;
|
|
}
|
|
if(leftpushed==true ){
|
|
c=9999;
|
|
}
|
|
}
|
|
}
|
|
if(!((rightpushed==true && c==F4) || (middlepushed==true && c==F5) || (leftpushed==true && c==9999)))
|
|
#endif
|
|
#endif
|
|
c = MMInkey();
|
|
if(c != -1 && errmsg) {
|
|
PrintFunctKeys(MARK);
|
|
errmsg = false;
|
|
}
|
|
switch(c) {
|
|
case ESC: uSec(50000); // wait 50ms to see if anything more is coming
|
|
if(MMInkey() == '[' && MMInkey() == 'M') {
|
|
// received escape code for Tera Term reporting a mouse click. in mark mode we ignore it
|
|
MMInkey(); MMInkey(); MMInkey();
|
|
break;
|
|
}
|
|
curx = txtpx; cury = txtpy; // just an escape key
|
|
return;
|
|
|
|
case CTRLKEY('E'):
|
|
case UP: if(cury <= 0) continue;
|
|
p = mark;
|
|
if(*p == '\n') p--; // step back over the terminator if we are right at the end of the line
|
|
while(p != EdBuff && *p != '\n') p--; // move to the beginning of the line
|
|
if(p != EdBuff) {
|
|
p--; // step over the terminator to the end of the previous line
|
|
for(i = 0; p != EdBuff && *p != '\n'; p--, i++); // move to the beginning of that line
|
|
if(*p == '\n') p++; // and position at the start
|
|
//if(i >= VWidth) {
|
|
if(i > VWidth) {
|
|
editDisplayMsg((unsigned char *)" LINE IS TOO LONG ");
|
|
errmsg = true;
|
|
continue;
|
|
}
|
|
}
|
|
mark = p;
|
|
for(i = 0; i < edx + curx && *mark != 0 && *mark != '\n'; i++, mark++); // move the cursor to the column
|
|
curx = i; cury--;
|
|
break;
|
|
|
|
case CTRLKEY('X'):
|
|
case DOWN:if(cury == VHeight -1) continue;
|
|
for(p = mark, i = curx; *p != 0 && *p != '\n'; p++, i++);// move to the end of this line
|
|
if(*p == 0) continue; // skip if it is at the end of the file
|
|
// if(i >= VWidth) {
|
|
if(i > VWidth) {
|
|
editDisplayMsg((unsigned char *)" LINE IS TOO LONG ");
|
|
errmsg = true;
|
|
continue;
|
|
}
|
|
mark = p + 1; // step over the line terminator to the start of the next line
|
|
for(i = 0; i < edx + curx && *mark != 0 && *mark != '\n'; i++, mark++); // move the cursor to the column
|
|
curx = i; cury++;
|
|
break;
|
|
|
|
case CTRLKEY('S'):
|
|
case LEFT:if(curx == edx) continue;
|
|
mark--;
|
|
curx--;
|
|
break;
|
|
|
|
case CTRLKEY('D'):
|
|
case RIGHT:if(curx >= VWidth || *mark == 0 || *mark == '\n') continue;
|
|
mark++;
|
|
curx++;
|
|
break;
|
|
|
|
case CTRLKEY('U'):
|
|
case HOME:if(mark == EdBuff) break;
|
|
if(*mark == '\n') mark--; // step back over the terminator if we are right at the end of the line
|
|
while(mark != EdBuff && *mark != '\n') mark--;// move to the beginning of the line
|
|
if(*mark == '\n') mark++; // skip if no more lines above this one
|
|
break;
|
|
|
|
case CTRLKEY('K'):
|
|
case END: if(*mark == 0) break;
|
|
for(p = mark, i = curx; *p != 0 && *p != '\n'; p++, i++);// move to the end of this line
|
|
//if(i >= VWidth) {
|
|
if(i > VWidth) {
|
|
editDisplayMsg((unsigned char *)" LINE IS TOO LONG ");
|
|
errmsg = true;
|
|
continue;
|
|
}
|
|
mark = p;
|
|
break;
|
|
|
|
case CTRLKEY('Y'):
|
|
case CTRLKEY('T'):
|
|
case F5:
|
|
case F4: if(txtp - mark > MAXCLIP || mark - txtp > MAXCLIP) {
|
|
editDisplayMsg((unsigned char *)" MARKED TEXT EXCEEDS CLIPBOARD BUFFER SIZE");
|
|
errmsg = true;
|
|
break;
|
|
}
|
|
if(mark <= txtp) {
|
|
p = mark;
|
|
while(p < txtp) *cb++ = *p++;
|
|
} else {
|
|
p = txtp;
|
|
while(p <= mark - 1) *cb++ = *p++;
|
|
}
|
|
*cb = 0;
|
|
if(c == F5 || c == CTRLKEY('Y')) {
|
|
PositionCursor(txtp);
|
|
#ifndef PICOMITE
|
|
#ifndef PICOMITEWEB
|
|
#ifdef USBKEYBOARD
|
|
if(HID[1].Device_type==2 && DISPLAY_TYPE==SCREENMODE1){
|
|
#else
|
|
if(mouse0 && DISPLAY_TYPE==SCREENMODE1){
|
|
#endif
|
|
nunstruct[2].ax =curx*FontTable[gui_font >> 4][0] * (gui_font & 0b1111);
|
|
nunstruct[2].ay =cury*FontTable[gui_font >> 4][1] * (gui_font & 0b1111);
|
|
lastx1=9999;lasty1=9999;
|
|
}
|
|
#endif
|
|
#endif
|
|
return;
|
|
}
|
|
// fall through
|
|
|
|
case CTRLKEY(']'):
|
|
case DEL: if(mark < txtp) {
|
|
p = txtp; txtp = mark; mark = p; // swap txtp and mark
|
|
}
|
|
for(p = txtp; p < mark; p++) if(*p == '\n') nbrlines--;
|
|
for(p = txtp; *mark; ) *p++ = *mark++;
|
|
*p++ = 0; *p++ = 0;
|
|
TextChanged = true;
|
|
PositionCursor(txtp);
|
|
#ifndef PICOMITE
|
|
#ifndef PICOMITEWEB
|
|
#ifdef USBKEYBOARD
|
|
if(HID[1].Device_type==2 && DISPLAY_TYPE==SCREENMODE1){
|
|
#else
|
|
if(mouse0 && DISPLAY_TYPE==SCREENMODE1){
|
|
#endif
|
|
nunstruct[2].ax =curx*FontTable[gui_font >> 4][0] * (gui_font & 0b1111);
|
|
nunstruct[2].ay =cury*FontTable[gui_font >> 4][1] * (gui_font & 0b1111);
|
|
lastx1=9999;lasty1=9999;
|
|
}
|
|
#endif
|
|
#endif
|
|
return;
|
|
case 9999: break;
|
|
default: continue;
|
|
}
|
|
|
|
x = curx; y = cury;
|
|
markmode=true;
|
|
// first unmark the area not marked as a result of the keystroke
|
|
if(oldmark < mark) {
|
|
PositionCursor(oldmark);
|
|
p = oldmark;
|
|
while(p < mark) {
|
|
if(*p == '\n') { SSputchar('\r',0); MX470PutC('\r'); }// also print on the MX470 display
|
|
MX470PutC(*p); // print on the MX470 display
|
|
SSputchar(*p++,0);
|
|
}
|
|
} else if(oldmark > mark) {
|
|
PositionCursor(mark);
|
|
p = mark;
|
|
while(oldmark > p) {
|
|
if(*p == '\n') { SSputchar('\r',0); MX470PutC('\r'); }// also print on the MX470 display
|
|
MX470PutC(*p); // print on the MX470 display
|
|
SSputchar(*p++,0);
|
|
}
|
|
}
|
|
fflush(stdout);
|
|
oldmark = mark; oldx = x; oldy = y;
|
|
|
|
// now draw the marked area
|
|
if(mark < txtp) {
|
|
PositionCursor(mark);
|
|
PrintString("\033[7m");
|
|
MX470Display(REVERSE_VIDEO); // reverse video on the MX470 display only
|
|
p = mark;
|
|
while(p < txtp) {
|
|
if(*p == '\n') {
|
|
SSputchar('\r',0); MX470PutC('\r'); // also print on the MX470 display
|
|
}
|
|
MX470PutC(*p); // print on the MX470 display
|
|
SSputchar(*p++,0);
|
|
}
|
|
MX470Display(REVERSE_VIDEO); // reverse video back to normal on the MX470 display only
|
|
} else if(mark > txtp) {
|
|
PositionCursor(txtp);
|
|
PrintString("\033[7m");
|
|
MX470Display(REVERSE_VIDEO); // reverse video on the MX470 display only
|
|
p = txtp;
|
|
while(p < mark) {
|
|
if(*p == '\n') {
|
|
SSputchar('\r',0); MX470PutC('\r'); // also print on the MX470 display
|
|
}
|
|
MX470PutC(*p); // print on the MX470 display
|
|
SSputchar(*p++,0);
|
|
}
|
|
MX470Display(REVERSE_VIDEO); // reverse video back to normal on the MX470 display only
|
|
}
|
|
markmode=false;
|
|
PrintString("\033[0m"); // normal video
|
|
|
|
oldx = x; oldy = y; oldmark = mark;
|
|
PositionCursor(mark);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// search through the text in the editing buffer looking for a specific line
|
|
// enters with ln = the line required
|
|
// exits pointing to the start of the line or pointing to a zero char if not that many lines in the buffer
|
|
char *findLine(int ln, int *inmulti) {
|
|
unsigned char *p, *q;
|
|
*inmulti=false;
|
|
p = q = EdBuff;
|
|
skipspace(q);
|
|
if(q[0]=='/' && q[1]=='*') *inmulti=true;
|
|
if(q[0]=='*' && q[1]=='/') *inmulti=false;
|
|
while(ln && *p) {
|
|
if(*p == '\n') {
|
|
if(*inmulti==2)*inmulti=false;
|
|
ln--;
|
|
q=&p[1];
|
|
skipspace(q);
|
|
if(q[0]=='/' && q[1]=='*') *inmulti=true;
|
|
if(q[0]=='*' && q[1]=='/') *inmulti=2;
|
|
}
|
|
p++;
|
|
}
|
|
return (char *)p;
|
|
}
|
|
|
|
|
|
int EditCompStr(char *p, char *tkn) {
|
|
while(*tkn && (toupper(*tkn) == toupper(*p))) {
|
|
if(*tkn == '(' && *p == '(') return true;
|
|
if(*tkn == '$' && *p == '$') return true;
|
|
tkn++; p++;
|
|
}
|
|
if(*tkn == 0 && !isnamechar(*p)) return true; // return the string if successful
|
|
|
|
return false; // or NULL if not
|
|
}
|
|
|
|
|
|
// this function does the syntax colour coding
|
|
// p = pointer to the current character to be printed
|
|
// or NULL if the colour coding is to be cmdfile to normal
|
|
//
|
|
// it keeps track of where it is in the line using static variables
|
|
// so it must be fed all chars from the start of the line
|
|
void SetColour(unsigned char *p, int DoVT100) {
|
|
int i;
|
|
unsigned char **pp;
|
|
static int intext = false;
|
|
static int incomment = false;
|
|
static int inkeyword = false;
|
|
static unsigned char *twokeyword = NULL;
|
|
static int inquote = false;
|
|
static int innumber = false;
|
|
|
|
if(!Option.ColourCode) return;
|
|
|
|
// this is a list of keywords that can come after the OPTION and GUI commands
|
|
// the list must be terminated with a NULL
|
|
char *twokeywordtbl[] = {
|
|
"BASE", "EXPLICIT", "DEFAULT", "BREAK", "AUTORUN", "BAUDRATE", "DISPLAY",
|
|
#if defined(GUICONTROLS)
|
|
"BUTTON", "SWITCH", "CHECKBOX", "RADIO", "LED", "FRAME", "NUMBERBOX", "SPINBOX", "TEXTBOX", "DISPLAYBOX", "CAPTION", "DELETE",
|
|
"DISABLE", "HIDE", "ENABLE", "SHOW", "FCOLOUR", "BCOLOUR", "REDRAW", "BEEP", "INTERRUPT",
|
|
#endif
|
|
NULL
|
|
};
|
|
|
|
// this is a list of common keywords that should be highlighted as such
|
|
// the list must be terminated with a NULL
|
|
char *specialkeywords[] = {
|
|
"SELECT", "INTEGER", "FLOAT", "STRING", "DISPLAY", "SDCARD", "OUTPUT", "APPEND", "WRITE", "SLAVE","TARGET","PROGRAM",
|
|
// ".PROGRAM", ".END PROGRAM", ".SIDE", ".LABEL" , ".LINE",".WRAP", ".WRAP TARGET",
|
|
NULL
|
|
};
|
|
|
|
|
|
// cmdfile everything back to normal
|
|
if(p == NULL) {
|
|
innumber = inquote = inkeyword = incomment = intext = false;
|
|
twokeyword = NULL;
|
|
if(!multilinecomment){
|
|
gui_fcolour = GUI_C_NORMAL;
|
|
if(DoVT100) PrintString(VT100_C_NORMAL);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if(*p == '*' && p[1]=='/' && !inquote) {
|
|
multilinecomment = 2;
|
|
return;
|
|
}
|
|
|
|
if(*p == '/' && !inquote && multilinecomment==2) {
|
|
multilinecomment = false;
|
|
return;
|
|
}
|
|
|
|
// check for a comment char
|
|
if(*p == '\'' && !inquote) {
|
|
gui_fcolour = GUI_C_COMMENT;
|
|
if(DoVT100) PrintString(VT100_C_COMMENT);
|
|
incomment = true;
|
|
return;
|
|
}
|
|
if(*p == '/' && p[1]=='*' && !inquote) {
|
|
unsigned char *q=p;
|
|
if(*(--q)==(unsigned char)'\n'){
|
|
gui_fcolour = GUI_C_COMMENT;
|
|
if(DoVT100) PrintString(VT100_C_COMMENT);
|
|
multilinecomment = true;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// once in a comment all following chars must be comments also
|
|
if(incomment || multilinecomment) return;
|
|
|
|
// check for a quoted string
|
|
if(*p == '\"') {
|
|
if(!inquote) {
|
|
inquote = true;
|
|
gui_fcolour = GUI_C_QUOTE;
|
|
if(DoVT100) PrintString(VT100_C_QUOTE);
|
|
return;
|
|
} else {
|
|
inquote = false;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(inquote) return;
|
|
|
|
// if we are displaying a keyword check that it is still actually in the keyword and cmdfile if not
|
|
if(inkeyword) {
|
|
if(isnamechar(*p) || *p == '$') return;
|
|
gui_fcolour = GUI_C_NORMAL;
|
|
if(DoVT100) PrintString(VT100_C_NORMAL);
|
|
inkeyword = false;
|
|
return;
|
|
}
|
|
|
|
// if we are displaying a number check that we are still actually in it and cmdfile if not
|
|
// this is complicated because numbers can be in hex or scientific notation
|
|
if(innumber) {
|
|
if(!isdigit(*p) && !(toupper(*p) >= 'A' && toupper(*p) <= 'F') && toupper(*p) != 'O' && toupper(*p) != 'H' && *p != '.') {
|
|
gui_fcolour = GUI_C_NORMAL;
|
|
if(DoVT100) PrintString(VT100_C_NORMAL);
|
|
innumber = false;
|
|
return;
|
|
} else {
|
|
return;
|
|
}
|
|
// check if we are starting a number
|
|
} else if(!intext){
|
|
if(isdigit(*p) || *p == '&' || ((*p == '-' || *p == '+' || *p == '.') && isdigit(p[1]))) {
|
|
gui_fcolour = GUI_C_NUMBER;
|
|
if(DoVT100) PrintString(VT100_C_NUMBER);
|
|
innumber = true;
|
|
return;
|
|
}
|
|
// check if this is an 8 digit hex number as used in CFunctions
|
|
for(i = 0; i < 8; i++) if(!isxdigit(p[i])) break;
|
|
if(i == 8 && (p[8] == ' ' || p[8] == '\'' || p[8] == 0)) {
|
|
gui_fcolour = GUI_C_NUMBER;
|
|
if(DoVT100) PrintString(VT100_C_NUMBER);
|
|
innumber = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// check if this is the start of a keyword
|
|
if(isnamechar(*p) && !intext) {
|
|
for(i = 0; i < CommandTableSize - 1; i++) { // check the command table for a match
|
|
if(EditCompStr((char *)p, (char *)commandtbl[i].name) != 0 ||
|
|
((EditCompStr((char *)&p[1], (char *)&commandtbl[i].name[1]) != 0) && *p=='.' && *commandtbl[i].name=='_')){
|
|
if(EditCompStr((char *)p, "REM") != 0) { // special case, REM is a comment
|
|
gui_fcolour = GUI_C_COMMENT;
|
|
if(DoVT100) PrintString(VT100_C_COMMENT);
|
|
incomment = true;
|
|
} else {
|
|
gui_fcolour = GUI_C_KEYWORD;
|
|
if(DoVT100) PrintString(VT100_C_KEYWORD);
|
|
inkeyword = true;
|
|
if(EditCompStr((char *)p, "GUI") ||
|
|
EditCompStr((char *)p, "OPTION")
|
|
) {
|
|
twokeyword = p;
|
|
while(isalnum(*twokeyword)) twokeyword++;
|
|
while(*twokeyword == ' ') twokeyword++;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
for(i = 0; i < TokenTableSize - 1; i++) { // check the token table for a match
|
|
if(EditCompStr((char *)p, (char *)tokentbl[i].name) != 0){
|
|
gui_fcolour = GUI_C_KEYWORD;
|
|
if(DoVT100) PrintString(VT100_C_KEYWORD);
|
|
inkeyword = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// check for the second keyword in two keyword commands
|
|
if(p == twokeyword) {
|
|
for(pp = (unsigned char **)twokeywordtbl; *pp; pp++)
|
|
if(EditCompStr((char *)p, (char *)*pp)) break;
|
|
if(*pp) {
|
|
gui_fcolour = GUI_C_KEYWORD;
|
|
if(DoVT100) PrintString(VT100_C_KEYWORD);
|
|
inkeyword = true;
|
|
return;
|
|
}
|
|
}
|
|
if(p >= twokeyword) twokeyword = NULL;
|
|
|
|
// check for a range of common keywords
|
|
for(pp = (unsigned char **)specialkeywords; *pp; pp++)
|
|
if(EditCompStr((char *)p, (char *)*pp)) break;
|
|
if(*pp) {
|
|
gui_fcolour = GUI_C_KEYWORD;
|
|
if(DoVT100) PrintString(VT100_C_KEYWORD);
|
|
inkeyword = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// try to keep track of if we are in general text or not
|
|
// this is to avoid recognising keywords or numbers inside variables
|
|
if(isnamechar(*p)) {
|
|
intext = true;
|
|
} else {
|
|
intext = false;
|
|
gui_fcolour = GUI_C_NORMAL;
|
|
if(DoVT100) PrintString(VT100_C_NORMAL);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// print a line starting at the current column (edx) at the current cursor.
|
|
// if the line is beyond the end of the text then just clear to the end of line
|
|
// enters with the line number to be printed
|
|
void printLine(int ln) {
|
|
char *p;
|
|
int i;
|
|
int inmulti=false;
|
|
// we always colour code the output to the LCD panel on the MX470 (when used as the console)
|
|
if(Option.DISPLAY_CONSOLE) {
|
|
MX470PutC('\r'); // print on the MX470 display
|
|
p = findLine(ln, &inmulti);
|
|
// i = VWidth - 1; // I think this is wrong. Does not show last character in line G.A.
|
|
i = VWidth ;
|
|
while(i && *p && *p != '\n') {
|
|
if(!inmulti)SetColour((unsigned char *)p, false); // set the colour for the LCD display only
|
|
else gui_fcolour = GUI_C_COMMENT;
|
|
MX470PutC(*p++); // print on the MX470 display
|
|
i--;
|
|
}
|
|
MX470Display(CLEAR_TO_EOL); // clear to the end of line on the MX470 display only
|
|
}
|
|
SetColour(NULL, false);
|
|
|
|
p = findLine(ln, &inmulti);
|
|
if(Option.ColourCode) {
|
|
// if we are colour coding we need to redraw the whole line
|
|
SSputchar('\r',0); // display the chars after the editing point
|
|
//i = VWidth - 1; // I think this is wrong. Does not show last character in line G.A.
|
|
i = VWidth;
|
|
} else {
|
|
// if we are NOT colour coding we can start drawing at the current cursor position
|
|
i = curx;
|
|
while(i-- && *p && *p != '\n') p++; // find the editing point in the buffer
|
|
i = VWidth - curx;
|
|
}
|
|
|
|
while(i && *p && *p != '\n') {
|
|
if(Option.ColourCode) {
|
|
if(!inmulti)SetColour((unsigned char *)p, true); // if colour coding is used set the colour for the VT100 emulator
|
|
else {
|
|
gui_fcolour = GUI_C_COMMENT;
|
|
PrintString(VT100_C_COMMENT);
|
|
}
|
|
}
|
|
SSputchar(*p++,0); // display the chars after the editing point
|
|
i--;
|
|
}
|
|
|
|
PrintString("\033[K"); // all done, clear to the end of the line on a vt100 emulator
|
|
if(Option.ColourCode) SetColour(NULL, true);
|
|
curx = VWidth - 1;
|
|
}
|
|
|
|
|
|
|
|
// print a full screen starting with the top left corner specified by edx, edy
|
|
// this draws the full screen including blank areas so there is no need to clear the screen first
|
|
// it then returns the cursor to its original position
|
|
void printScreen(void) {
|
|
int i;
|
|
|
|
SCursor(0, 0);
|
|
for(i = 0; i <VHeight; i++) {
|
|
printLine(i + edy);
|
|
PrintString("\r\n");
|
|
MX470PutS("\r\n", gui_fcolour, gui_bcolour);
|
|
curx = 0;
|
|
cury = i + 1;
|
|
}
|
|
while(getConsole() != -1); // consume any keystrokes accumulated while redrawing the screen
|
|
}
|
|
|
|
|
|
// position the cursor on the screen
|
|
void SCursor(int x, int y) {
|
|
char s[12];
|
|
|
|
PrintString("\033[");
|
|
IntToStr(s, y + 1, 10); PrintString(s); PrintString(";");
|
|
IntToStr(s, x + 1, 10); PrintString(s); PrintString("H");
|
|
MX470Cursor(x * gui_font_width, y * gui_font_height); // position the cursor on the MX470 display only
|
|
curx = x; cury = y;
|
|
}
|
|
|
|
|
|
|
|
// move the text down by one char starting at the current position in the text
|
|
// and insert a character
|
|
int editInsertChar(unsigned char c, char *multi, int edit_buff_size) {
|
|
unsigned char *p;
|
|
|
|
for(p = EdBuff; *p; p++); // find the end of the text in memory
|
|
if(p >= EdBuff + edit_buff_size - 10) { // and check that we have the space (allow 10 bytes for slack)
|
|
editDisplayMsg((unsigned char *)" OUT OF MEMORY ");
|
|
return false;
|
|
}
|
|
for(; p >= txtp; p--) *(p + 1) = *p; // shift everything down
|
|
*multi=0;
|
|
p=txtp-1;
|
|
if((c=='/' && *p=='*') || (c=='*' && *p=='/') )*multi=1;
|
|
p+=2;
|
|
if((c=='/' && *p=='*') || (c=='*' && *p=='/') )*multi=1;
|
|
*txtp++ = c; // and insert our char
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
// print the function keys at the bottom of the screen
|
|
void PrintFunctKeys(int typ) {
|
|
int i, x, y;
|
|
char *p;
|
|
|
|
if(typ == EDIT) {
|
|
if(VWidth >= 78)
|
|
p = "ESC:Exit F1:Save F2:Run F3:Find F4:Mark F5:Paste";
|
|
else if(VWidth >= 62)
|
|
p = "F1:Save F2:Run F3:Find F4:Mark F5:Paste";
|
|
else
|
|
p = "EDIT MODE";
|
|
} else {
|
|
if(VWidth >= 49)
|
|
p = "MARK MODE ESC=Exit DEL:Delete F4:Cut F5:Copy";
|
|
else
|
|
p = "MARK MODE";
|
|
}
|
|
|
|
MX470Display(DRAW_LINE); // on the MX470 display draw the line
|
|
MX470PutS(p, GUI_C_STATUS, gui_bcolour); // display the string on the display attached to the MX470
|
|
MX470Display(CLEAR_TO_EOL); // clear to the end of line on the MX470 display only
|
|
|
|
x = curx; y = cury;
|
|
SCursor(0, VHeight);
|
|
if(Option.ColourCode) PrintString(VT100_C_LINE);
|
|
PrintString("\033[4m"); // underline on
|
|
for(i = 0; i < VWidth; i++) SSputchar(' ',0);
|
|
PrintString("\033[0m\r\n"); // underline off
|
|
if(Option.ColourCode) PrintString(VT100_C_STATUS);
|
|
PrintString(p);
|
|
if(Option.ColourCode) PrintString(VT100_C_NORMAL);
|
|
PrintString("\033[K"); // clear to the end of the line on a vt100 emulator
|
|
SCursor(x, y);
|
|
}
|
|
|
|
|
|
|
|
// print the current status
|
|
void PrintStatus(void) {
|
|
int tx;
|
|
char s[MAXSTRLEN];
|
|
|
|
tx = edx + curx + 1;
|
|
strcpy(s, "Ln: ");
|
|
IntToStr(s + strlen(s), edy + cury + 1, 10);
|
|
strcat(s + strlen(s), " Col: ");
|
|
IntToStr(s + strlen(s), tx, 10);
|
|
strcat(s, " ");
|
|
strcpy(s + 19, insert?"INS":"OVR");
|
|
|
|
MX470Cursor((VWidth - strlen(s)) * gui_font_width, (VRes/gui_font_height)*gui_font_height - gui_font_height);
|
|
MX470PutS(s, GUI_C_STATUS, gui_bcolour); // display the string on the display attached to the MX470
|
|
|
|
SCursor(VWidth - 25, VHeight + 1);
|
|
if(Option.ColourCode) PrintString(VT100_C_STATUS);
|
|
PrintString(s);
|
|
if(Option.ColourCode) PrintString(VT100_C_NORMAL);
|
|
|
|
PositionCursor(txtp);
|
|
}
|
|
|
|
|
|
|
|
// display a message in the status line
|
|
void editDisplayMsg(unsigned char *msg) {
|
|
SCursor(0, VHeight + 1);
|
|
if(Option.ColourCode) PrintString(VT100_C_ERROR);
|
|
PrintString("\033[7m");
|
|
MX470Cursor(0, (VRes/gui_font_height)*gui_font_height - gui_font_height);
|
|
PrintString((char *)msg);
|
|
MX470PutS((char *)msg, BLACK, RED);
|
|
if(Option.ColourCode) PrintString(VT100_C_NORMAL);
|
|
PrintString("\033[0m");
|
|
PrintString("\033[K"); // clear to the end of the line on a vt100 emulator
|
|
MX470Display(CLEAR_TO_EOL); // clear to the end of line on the MX470 display only
|
|
PositionCursor(txtp);
|
|
drawstatusline = true;
|
|
}
|
|
|
|
|
|
|
|
// save the program in the editing buffer into the program memory
|
|
void SaveToProgMemory(void) {
|
|
SaveProgramToFlash(EdBuff, true);
|
|
ClearProgram(true);
|
|
StartEditPoint = (unsigned char *)(edy + cury); // record out position in case the editor is invoked again
|
|
StartEditChar = edx + curx;
|
|
// bugfix for when the edit point is a space
|
|
// the space could be at the end of a line which will be trimmed in SaveProgramToFlash() leaving StartEditChar referring to something not there
|
|
// this is not a serious issue so fix the bug in the MX470 only because it has plenty of flash
|
|
while(StartEditChar > 0 && txtp > EdBuff && *(--txtp) == ' ') {
|
|
StartEditChar--;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// get an input string from the user and save into inpbuf
|
|
void GetInputString(unsigned char *prompt) {
|
|
int i;
|
|
unsigned char *p;
|
|
|
|
SCursor(0, VHeight + 1);
|
|
PrintString((char *)prompt);
|
|
MX470Cursor(0, (VRes/gui_font_height)*gui_font_height - gui_font_height);
|
|
MX470PutS((char *)prompt, gui_fcolour, gui_bcolour);
|
|
for(i = 0; i < VWidth - strlen((char *)prompt); i++) {
|
|
SSputchar(' ',1);
|
|
MX470PutC(' ');
|
|
}
|
|
SCursor(strlen((char *)prompt), VHeight + 1);
|
|
MX470Cursor(strlen((char *)prompt) * gui_font_width, (VRes/gui_font_height)*gui_font_height - gui_font_height);
|
|
for(p = inpbuf; (*p = MMgetchar()) != '\r'; p++) { // get the input
|
|
if(*p == 0xb3 || *p == F3 || *p == ESC) { p++; break; } // return if it is SHIFT-F3, F3 or ESC
|
|
if(isprint(*p)) {
|
|
SSputchar(*p,1); // echo the char
|
|
MX470PutC(*p); // echo the char on the MX470 display
|
|
}
|
|
if(*p == '\b') {
|
|
p--; // backspace over a backspace
|
|
if(p >= inpbuf){
|
|
p--; // and the char before
|
|
PrintString("\b \b"); // erase on the screen
|
|
MX470PutS("\b \b", gui_fcolour, gui_bcolour); // erase on the MX470 display
|
|
}
|
|
}
|
|
}
|
|
*p = 0; // terminate the input string
|
|
PrintFunctKeys(EDIT);
|
|
PositionCursor(txtp);
|
|
}
|
|
|
|
|
|
// scroll up the video screen
|
|
void Scroll(void) {
|
|
edy++;
|
|
SCursor(0, VHeight);
|
|
PrintString("\033[J\033[99B\n"); // clear to end of screen, move to the end of the screen and force a scroll of one line
|
|
MX470Cursor(0, VHeight * gui_font_height);
|
|
MX470Scroll(gui_font_height);
|
|
SCursor(0, VHeight);
|
|
curx = 0;
|
|
cury = VHeight - 1;
|
|
PrintFunctKeys(EDIT);
|
|
printLine(VHeight - 1 + edy);
|
|
PositionCursor(txtp);
|
|
while(getConsole() != -1); // consume any keystrokes accumulated while redrawing the screen
|
|
}
|
|
|
|
|
|
// scroll down the video screen
|
|
void ScrollDown(void) {
|
|
SCursor(0, VHeight); // go to the end of the editing area
|
|
PrintString("\033[J"); // clear to end of screen
|
|
edy--;
|
|
SCursor(0, 0);
|
|
PrintString("\033M"); // scroll window down one line
|
|
MX470Scroll(-gui_font_height);
|
|
printLine(edy);
|
|
PrintFunctKeys(EDIT);
|
|
PositionCursor(txtp);
|
|
|
|
while(getConsole() != -1)routinechecks();; // consume any keystrokes accumulated while redrawing the screen
|
|
}
|
|
|
|
#endif
|
|
/* @endcond */
|