REM#const MAX_PROG_SIZE = &FFFF HIMEM = (LOMEM + INT(MAX_PROG_SIZE / 1000) * 1000000) AND -4 REM BBCEdit REM Copyright (c) 2016 Andy Parkes REM This software is supplied as is without any express or implied REM warranty. In no event will the authors be held liable for any damages REM arising from the use of this software. REM REM Permission is granted for anyone to use this software for any purpose REM including commercial applications, and to alter it and redistribute it REM freely subject to the following restrictions: REM REM The origin of this software must not be misrepresented; you must not REM claim that you wrote the original software. If you use this software REM in a product, an acknowledgement in the product documentation would be REM appreciated but is not required. REM REM Altered source versions must be plainly marked as such, and must not be REM misrepresented as being the original software. REM REM This notice may not be removed or altered from any source distribution. (BBCEdit) DIM Prog{name$, version$} Prog.name$ = "BBCEdit" Prog.version$ = "0.40.0" ResDir$ = @dir$ + Prog.name$ + RIGHT$(@dir$) INSTALL @lib$ + "stringlib" INSTALL @lib$ + "sortlib" INSTALL @lib$ + "utf8lib" INSTALL ResDir$ + "menumod" INSTALL ResDir$ + "msgmod" INSTALL ResDir$ + "filedlgmod" INSTALL ResDir$ + "bgroupmod" INSTALL ResDir$ + "dlgmod" REM Keywords REM ---------------------------------------------------------------------- DIM K$(255), K&(255) K$() = "", "CIRCLE", "ELLIPSE", "FILL", "MOUSE", "ORIGIN", "QUIT", "RECTANGLE", \ \ "SWAP", "SYS", "TINT", "WAIT", "INSTALL", "", "PRIVATE", "BY", "EXIT", \ \ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", \ \ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", \ \ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", \ \ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", \ \ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", \ \ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", \ \ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "AND", \ \ "DIV", "EOR", "MOD", "OR", "ERROR", "LINE", "OFF", "STEP", "SPC", "TAB(", "ELSE", "THEN", "", "OPENIN", "PTR", "PAGE", \ \ "TIME", "LOMEM", "HIMEM", "ABS", "ACS", "ADVAL", "ASC", "ASN", "ATN", "BGET", "COS", "COUNT", "DEG", "ERL", "ERR", "EVAL", \ \ "EXP", "EXT", "FALSE", "FN", "GET", "INKEY", "INSTR(", "INT", "LEN", "LN", "LOG", "NOT", "OPENUP", "OPENOUT", "PI", "POINT(", \ \ "POS", "RAD", "RND", "SGN", "SIN", "SQR", "TAN", "TO", "TRUE", "USR", "VAL", "VPOS", "CHR$", "GET$", "INKEY$", "LEFT$(", \ \ "MID$(", "RIGHT$(", "STR$", "STRING$(", "EOF", "SUM", "WHILE", "CASE", "WHEN", "OF", "ENDCASE", "OTHERWISE", "ENDIF", "ENDWHILE", "PTR", "PAGE", \ \ "TIME", "LOMEM", "HIMEM", "SOUND", "BPUT", "CALL", "CHAIN", "CLEAR", "CLOSE", "CLG", "CLS", "DATA", "DEF", "DIM", "DRAW", "END", \ \ "ENDPROC", "ENVELOPE", "FOR", "GOSUB", "GOTO", "GCOL", "IF", "INPUT", "LET", "LOCAL", "MODE", "MOVE", "NEXT", "ON", "VDU", "PLOT", \ \ "PRINT", "PROC", "READ", "REM", "REPEAT", "REPORT", "RESTORE", "RETURN", "RUN", "STOP", "COLOUR", "TRACE", "UNTIL", "WIDTH", "OSCLI" ON ERROR ON ERROR OFF : PRINT REPORT$'FNerrorLine : END FOR I% = 0 TO 255 IF I% > &1F IF I% < &7F K&(I%) = 1 ELSE K&(I%) = LEN K$(I%) NEXT REM#const{ REM keywords for indentation KEYWORD_THEN = &8C KEYWORD_ELSE = &8B KEYWORD_ENDIF = &CD KEYWORD_CASE = &C8 KEYWORD_WHEN = &C9 REM KEYWORD_OF = &CA KEYWORD_OTHERWISE = &CC KEYWORD_ENDCASE = &CB KEYWORD_FOR = &E3 KEYWORD_NEXT = &ED KEYWORD_WHILE = &C7 KEYWORD_ENDWHILE = &CE KEYWORD_REPEAT = &F5 KEYWORD_UNTIL = &FD KEYWORD_EXIT = &10 REM keywords for syntax colour KEYWORD_LOCAL = &EA KEYWORD_ENDPROC = &E1 KEYWORD_DEF = &DD KEYWORD_REM = &F4 KEYWORD_FN = &A4 KEYWORD_PROC = &F2 KEYWORD_USR = &BA KEYWORD_CALL = &D6 KEYWORD_NOT = &AC KEYWORD_AND = &80 KEYWORD_OR = &84 KEYWORD_EOR = &82 KEYWORD_TO = &B8 REM keywords for function list KEYWORD_ON = &EE KEYWORD_CLOSE = &D9 KEYWORD_ERROR = &85 KEYWORD_MOUSE = &04 KEYWORD_MOVE = &EC KEYWORD_SYS = &09 KEYWORD_TIME = &91 REM#} REM Initialisation REM ---------------------------------------------------------------------- (Init) TempDir$ = @tmp$ + Prog.name$ + RIGHT$("0"+STR$VALMID$(TIME$,5,2),2) + MID$(TIME$,17,2) + MID$(TIME$,20,2) S% = VALMID$(TIME$,23,2) - 1 REPEAT S% += 1 : IF S% == 60 S% = 0 UNTIL FNmkdir(TempDir$ + RIGHT$("0"+STR$S%,2)) TempDir$ += RIGHT$("0"+STR$S%,2) + RIGHT$(@tmp$) REM BBC BASIC for Windows <= 095a (NOT SUPPORTED) REM - INKEY(-256) returns 87 (ASCII W) REM REM BBC BASIC for Windows >= 600a REM - INKEY(-256) returns 87 (ASCII W) REM REM BBCSDL <= 012a (NOT SUPPORTED) REM - INKEY(-256) returns 249 REM REM BBCSDL >= 013a REM - INKEY(-256) returns 83 (ASCII S) REM REM BBCSDL >= ? REM - INKEY(-256) returns 115 (ASCII s) REM REM - @platform% has SDL version number in three MS bytes, and platform ID in LS byte: REM REM (@platform% >> 24) AND &FF --> SDL major version REM (@platform% >> 16) AND &FF --> SDL minor version REM (@platform% >> 8) AND &FF --> SDL patch version REM REM @platform% AND &F == 0 --> Win32 REM @platform% AND &F == 1 --> Linux REM @platform% AND &F == 2 --> MacOS REM @platform% AND &F == 3 --> Android REM @platform% AND &F == 4 --> iOS REM @platform% AND &F == 5 --> In-Browser REM REM bit 6 of LS byte is set if platform is 64-bit DIM RTE{pathname$, version$} RTE.version$ = FNversion IF INKEY(-256) == 87 THEN REM BBC BASIC for Windows IF FNbb4w6 THEN SDL% = 0 MemMove$ = "RtlMoveMemory" RTE.pathname$ = FNdirname(@lib$, 1) + "bbcwrun6" ELSE REM not supported VDU 26 : IF POS : VDU 20 : CLS PRINT Prog.name$ + " " + Prog.version$ + " requires BBCSDL >= 014a or BBC BASIC for Windows >= 600a" : END ENDIF ELSE REM BBCSDL SDL% = @platform% MemMove$ = "memmove" CASE @platform% AND &F OF WHEN 0 REPEAT I% = INSTR(@dir$, "/") IF I% MID$(@dir$, I%, 1) = "\" UNTIL I% == 0 WHEN 1, 2 OTHERWISE REM not supported VDU 26 : IF POS : VDU 20 : CLS PRINT Prog.name$ + " " + Prog.version$ + " requires BBC BASIC for Windows, or BBCSDL for Win32, Linux or MaxOS" : END ENDCASE RTE.pathname$ = FNdirname(@lib$, 1) + "bbcsdl" ENDIF IF (SDL% AND &F) THEN REM safe filename for Linux, MacOS FOR I% = 32 TO 126 IF INSTR("/*?!", CHR$I%) ELSE ValidFileName$ += CHR$I% NEXT ELSE REM safe filename for windows FOR I% = 32 TO 126 IF INSTR("\/:*?""<>|", CHR$I%) ELSE ValidFileName$ += CHR$I% NEXT ENDIF IF SDL% AND 64 THEN Accs%% = ]332 *HEX 64 ELSE Accs%% = !332 *HEX 32 ENDIF IFFNrealpath(ResDir$, ResDir$) ResDir$ += RIGHT$(@dir$) IconDir$ = ResDir$ + "icons" + RIGHT$(@dir$) REM Program Storage and Editing REM ---------------------------------------------------------------------- DIM lineBuff%% &FFFF DIM Line$(MAX_PROG_SIZE) DIM lineColour$(MAX_PROG_SIZE) DIM lineIndent&(MAX_PROG_SIZE) DIM lineIndentSelf&(MAX_PROG_SIZE) DIM lineIndentNext%(MAX_PROG_SIZE) DIM lineSelected&(MAX_PROG_SIZE) DIM lineNumberL&(MAX_PROG_SIZE) DIM lineNumberH&(MAX_PROG_SIZE) Line$() = STRING$(&FF, " ") lineColour$() = STRING$(&FF, " ") DIM lineSelect{ \ \ anc%, \ index of the program line (1 - lastLine%) about which the line selection is anchored \ ext%, \ index of the program line (1 - lastLine%) marking the extent of the line selection \ size% \ number of lines selected \ } DIM stringSelect{ \ \ carrotAnc%, \ the edit line carrot index (0 to LEN Edit.text$) about which the string selection is anchored \ carrotExt%, \ the edit line carrot index (0 to LEN Edit.text$) marking the extent of the string selection \ index%, \ the index of the first character of the selection string within the edit line \ text$ \ a copy of the selected string copied from the edit line \ } DIM Edit{ \ \ text$, \ edit line text \ line%, \ edit line program line \ carrot%, \ edit line carrot index \ modified%, \ set to TRUE when the edit line text has been modified relative to Line$(Edit.line%) \ changedIndent%, \ set to TRUE when a modified edit line text results in a different indent effect from Line$(Edit.line%) \ changedLineNumber% \ set to TRUE when a modified edit line text starts with a line number \ } REM Flags REM ---------------------------------------------------------------------- REM#const{ EVENT_INPUT_MOUSE_MOVE = 1 EVENT_INPUT_MOUSE_CLICK = 2 EVENT_INPUT_UP = 4 EVENT_INPUT_DOWN = 8 EVENT_INPUT_ESCAPE = 16 EVENT_INPUT_RETURN = 32 EVENT_INPUT_TAB = 64 EVENT_INPUT_RESIZE = 128 EVENT_INPUT_ALL = 255 : REM SDL_WINDOW_FULLSCREEN = &00000001 : REM /**< fullscreen window */ REM SDL_WINDOW_OPENGL = &00000002 : REM /**< window usable with OpenGL context */ REM SDL_WINDOW_SHOWN = &00000004 : REM /**< window is visible */ REM SDL_WINDOW_HIDDEN = &00000008 : REM /**< window is not visible */ REM SDL_WINDOW_BORDERLESS = &00000010 : REM /**< no window decoration */ REM SDL_WINDOW_RESIZABLE = &00000020 : REM /**< window can be resized */ REM SDL_WINDOW_MINIMIZED = &00000040 : REM /**< window is minimized */ REM SDL_WINDOW_MAXIMIZED = &00000080 : REM /**< window is maximized */ REM SDL_WINDOW_INPUT_GRABBED = &00000100 : REM /**< window has grabbed input focus */ SDL_WINDOW_INPUT_FOCUS = &00000200 : REM /**< window has input focus */ REM SDL_WINDOW_MOUSE_FOCUS = &00000400 : REM /**< window has mouse focus */ REM SDL_WINDOW_FULLSCREEN_DESKTOP = ( SDL_WINDOW_FULLSCREEN OR &00001000 ) REM SDL_WINDOW_FOREIGN = &00000800 : REM /**< window not created by SDL */ REM SDL_WINDOW_ALLOW_HIGHDPI = &00002000 : REM /**< window should be created in high-DPI mode if supported */ REM SDL_WINDOW_MOUSE_CAPTURE = &00004000 : REM /**< window has mouse captured (unrelated to INPUT_GRABBED) */ REM#} REM Colours REM ---------------------------------------------------------------------- REM#const{ PALETTE_DARK = 0 PALETTE_LIGHT = 2 PALETTE_DLG = 1 REM window furniture PAL_BORDER = 1 PAL_HIGHLIGHT = 2 PAL_BACKGROUND = 3 PAL_FOREGROUND = 4 PAL_MARGIN = 5 PAL_EDITLINE = 6 REM syntax highlighting PAL_DIR = 7 PAL_DEF = 8 PAL_KEY = 9 PAL_STR = 10 PAL_REM = 11 PAL_SUB = 12 PAL_VAR = 13 PAL_AND = 14 PAL_NUM = 15 REM#} DIM C&(255) FOR I% = 0 TO 255 IF I% > 31 IF I% < 127 THEN IF I% > 47 IF I% < 58 THEN C&(I%) = PAL_NUM ELSE IF (I% > 63 AND I% < 91) OR (I% > 94 AND I% < 123) THEN C&(I%) = PAL_VAR ELSE C&(I%) = PAL_FOREGROUND ENDIF ENDIF ELSE CASE I% OF WHEN KEYWORD_DEF, KEYWORD_ENDPROC C&(I%) = PAL_DEF WHEN KEYWORD_REM C&(I%) = PAL_REM WHEN KEYWORD_FN, KEYWORD_PROC, KEYWORD_USR, KEYWORD_CALL C&(I%) = PAL_SUB WHEN KEYWORD_NOT, KEYWORD_AND, KEYWORD_OR, KEYWORD_EOR C&(I%) = PAL_AND OTHERWISE C&(I%) = PAL_KEY ENDCASE ENDIF NEXT C&(&22) = PAL_STR C&(&28) = PAL_KEY C&(&29) = PAL_KEY C&(&8D) = PAL_SUB FnDefEnd$ = CHR$KEYWORD_THEN + CHR$KEYWORD_ELSE + ":" + CHR$KEYWORD_OTHERWISE + CHR$KEYWORD_LOCAL REM ANSI and MODE 7 descriptions for ISO-8859-1 control characters 128-159 DIM ANSI$(31), M7$(31) : ANSI$() = "€ Euro", "", \ \ "‚ Low single quote", \ \ "ƒ Latin small f with hook", \ \ "„ Low double quote", \ \ "… horizontal ellipsis", \ \ "† single dagger", \ \ "‡ double dagger", \ \ "ˆ circumflex accent", \ \ "‰ per mille", \ \ "Š Latin capital S with caron", \ \ "‹ single left-point angle quote", \ \ "Œ Latin capital ligature OE", "", \ \ "Latin capital Z with caron", "", "", \ \ "‘ left single quote", \ \ "’ right single quote", \ \ "“ left double quote", \ \ "” right double quote", \ \ "• bullet", \ \ "– en dash", \ \ "— em dash", \ \ "˜ small tilde", \ \ "™ trade mark sign", \ \ "š Latin small s with caron", \ \ "› single right-point angle quote", \ \ "œ Latin small ligature oe", "", \ \ "Latin small z with caron", \ \ "Ÿ Latin capital Y with diaeresis" : M7$() = "", "alphanum red", "alphanum green", "alphanum yellow", \ \ "alphanum blue", "alphanum magenta", "alphanum cyan", \ \ "alphanum white", "flash", "steady", "", "", \ \ "normal height", "double height", "", "", "", \ \ "graphic red", "graphic green", "graphic yellow", "graphic blue", \ \ "graphic magenta", "graphic cyan", "graphic white", "conceal", \ \ "contiguous graphics", "separated graphics", "", \ \ "black background", "new background", "hold graphics", "release graphics" REM Message Window REM ---------------------------------------------------------------------- (MsgWin) REM#const{ MSGWIN_INFO = 1 MSGWIN_QUESTION = 2 MSGWIN_WARNING = 3 MSGWIN_STOP = 4 MSGWIN_ABOUT = 5 MSGWIN_OK = 16 MSGWIN_YESNO = 32 MSGWIN_YESNOCANCEL = 48 REM#} DIM MsgWin{icon{info%%, question%%, warning%%, stop%%, about%%}} MsgWin.icon.about%% = FNloadBMP(IconDir$ + "msg" + RIGHT$(@dir$) + "beeb") MsgWin.icon.info%% = FNloadBMP(IconDir$ + "msg" + RIGHT$(@dir$) + "info") MsgWin.icon.question%% = FNloadBMP(IconDir$ + "msg" + RIGHT$(@dir$) + "question") MsgWin.icon.warning%% = FNloadBMP(IconDir$ + "msg" + RIGHT$(@dir$) + "warning") MsgWin.icon.stop%% = FNloadBMP(IconDir$ + "msg" + RIGHT$(@dir$) + "no") REM Margin REM ---------------------------------------------------------------------- (Margin) DIM Margin{ \ \ show%, \ enable/disable the margin \ w%, \ width of margin in graphic units \ cw%, \ width of margin in characters \ r%, \ right edge of margin as defined for the purpose of detecting mouse clicks \ basic%, \ display BASIC line numbers instead of logical line numbers \ digits% \ number of characters reserved for digits (a component of cw%) \ } Margin.digits% = 5 : REM LEN(STR$ MAX_PROG_SIZE) REM Menu bar REM ---------------------------------------------------------------------- (MenuBar) DIM menuBar{ \ \ show%, \ enable/disable menu bar \ h%, \ height of menu bar in graphic units \ text$, \ string of all menu names to be printed on the menu bar \ menus%, \ number of menus on the menu bar \ selectedMenu%, \ currently highlighted menu bar option \ keepOpen%, \ TRUE if the user is 'surfing' menu bar menus using the mouse \ l%, \ the left edge of the first menu bar item in graphic units \ r%, \ the right edge of the last menu bar item in graphic units \ b%, \ the bottom edge of the menu bar in graphic units \ longestNameLen%, \ the character length of the longest menu bar menu full name \ hfg& \ highlighted text foreground colour (palette index) \ } menuBar.menus% = 6 DIM menuBarMenu{(menuBar.menus%) \ \ fullName$, \ menu name \ name$, \ menu name as shown on the menu bar \ ptr%%, \ pointer to data block of structure defining the menu \ pSetFlags%%, \ pointer to procedure to set menu flags \ cx%, \ a position of menu name in characters \ l%, \ left edge of menu name in graphic units \ r% \ right edge of menu name in graphic units \ } REM maximum items in a menu bar menu REM#const MBM_MAX = 22 DIM Menu{ \ \ l%, b%, r%, t%, \ left, bottom, right, top positions of menu in graphic units relative to graphics origin \ w%, h%, \ width and height of menu in graphic units \ cl%, cb%, cr%, ct%, \ left, bottom, right, top characters bounding the menu rows \\ \ bg&, \ menu background colour \ hbg&, \ menu item highlight background colour \ hfg&, \ menu item highlight foreground colour \\ \ items%, \ number of items in menu \ rows%, \ number of items that can be shown on the menu at any one time without scrolling \ first%, \ index of menu item currently showing at the top of the menu \ last%, \ index of menu item currently showing at the bottom of the menu \ selected%, \ the menu item currently selected (I e highlighted / hovered over) \ longestLHS%, \ the length in characters of the longest lhs menu item string \ longestRHS%, \ the length in characters of the longest rhs menu item string \\ \ tx%, \ x position of menu item text in graphic units relative to graphics origin \ tyOffset%, \ offset of menu item text in graphic units relative to bottom of menu item \ hx%, \ x position of menu item highlight rectangle in graphic units relative to graphic origin \ hw%, \ width of menu item highlight rectangle in graphic units relative to graphic origin \\ \ textWidth%, \ maximum number of characters of menu item text that can be displayed \ rowChrHeight%, \ height of menu item row in characters \ rh%, \ height of menu item row in graphic units \ sbg&, sfg&, \ scroll button background and foreground colour \ ofg&, \ foreground colour of menu items that are 'switched off' \\ \ over%%, \ callback to procedure when menu item has focus E.g. m.over%% = ^PROCsomthing(m{},I%) \\ \ item$(MBM_MAX), \ dynamically constructed text for each menu item \ lhs$(MBM_MAX), \ lhs menu item string \ rhs$(MBM_MAX), \ rhs menu item string \ flag&(MBM_MAX), \ menu item flags (1 == MENU_ITEM_TICK, 2 == MENU_ITEM_OFF) \ fg&(MBM_MAX), \ foreground colour of each menu item \ ico%%(MBM_MAX), \ pointer to icon data block [0:pNormal][4:pHightlight][8:size of square icon graphic units] \ info$(MBM_MAX), \ info/help/data string associated with the menu item \\ \ call%%(MBM_MAX), \ pointer to procedure to be called when menu item is selected \\ \ button&(MBM_MAX), \ mouse button filter to allow button combinations other than just the left button \ button& \ returns the mouse button combination used to select an item \ } REM ********************************************************************** REM Here is a physically compact version of the above structure for use REM in parts of the program where Menu{} can't be used as a prototype. REM DIM m{l%,b%,r%,t%,w%,h%,cl%,cb%,cr%,ct%,bg&,hbg&,hfg&,\ REM \ items%,rows%,first%,last%,selected%,longestLHS%,longestRHS%, \ REM \ tx%,tyOffset%,hx%,hw%,textWidth%,rowChrHeight%,rh%,sbg&,sfg&,ofg&, \ REM \ over%%,item$(),lhs$(),rhs$(),flag&(),fg&(),ico%%(),info$(), \ REM \ call%%(),button&(),button&} REM ********************************************************************** REM#const{ MENU_ITEM_TICK = 1 MENU_ITEM_OFF = 2 REM The OPTIONS_MENU_ constants are defined here because those appertaining REM to the font options are also used by _setFont before any calls to mbm_build OPTIONS_MENU_SHOW_MENU = 1 OPTIONS_MENU_SHOW_TOOLBAR = 2 OPTIONS_MENU_SHOW_MARGIN = 3 OPTIONS_MENU_SHOW_STATUS_BAR = 4 OPTIONS_MENU_SHOW_VSCROLL = 5 OPTIONS_MENU_SHOW_HSCROLL = 6 OPTIONS_MENU_FONT_BITMAP = 8 OPTIONS_MENU_FONT_FREEMONO = 9 OPTIONS_MENU_FONT_DEJAVU = 10 OPTIONS_MENU_FONT_SMALL = 12 OPTIONS_MENU_FONT_MEDIUM = 13 OPTIONS_MENU_FONT_LARGE = 14 OPTIONS_MENU_FONT_XLARGE = 15 OPTIONS_MENU_COLOUR_SCHEME = 17 OPTIONS_MENU_COMPACT_MENUS = 18 OPTIONS_MENU_LOWERCASE_KEYWORDS = 20 OPTIONS_MENU_SYNTAX_COLOURING = 21 OPTIONS_MENU_BRACKET_MATCHING = 22 REM#} *KEY 1 |_ *KEY 2 |^ *KEY 3 |] *KEY 4 |\ *KEY 9 |U REM Toolbar REM ---------------------------------------------------------------------- (Toolbar) DIM Toolbar{ \ \ show%, \ TRUE when toolbar is displayed \ h%, \ height (in graphic units) of screen area reserved for toolbar \ b%, \ y coordinate / bottom (in graphic units) of screen area reserved for toolbar \ buttons%, \ the number of buttons (of all types - including seperators) \ sx%, \ x position (scroll offset) \ bw%, \ combined width of all buttons (graphic units) \ bh%, \ height of buttons (graphic units) \ bl%, \ left edge of left most button assuming .sx% == 0 (graphic units) \ bb%, \ bottom edge of buttons (graphic units) \ br%, \ right edge of right most button assuming .sx% == 0 (graphic units) \ bt%, \ top edge of top buttons (graphic units) \ over% \ index of selected / hovered button \ } Toolbar.buttons% = 29 Toolbar.bh% = 72 : REM height of square toolbar buttons in graphic units REM#const{ BUTTON_STATE_OUT = 1 BUTTON_STATE_IN = 2 BUTTON_STATE_ON = 4 BUTTON_STATE_OFF = 8 BUTTON_STATE_OUTON = 5 BUTTON_STATE_OUTOFF = 9 BUTTON_STATE_INON = 6 BUTTON_STATE_INOFF = 10 BUTTON_STATE_NOBMP = 16 BUTTON_TT_ON = 1 REM#} DIM tbButton{(Toolbar.buttons%) \ \ outOn%%, \ bitmap for normal and spacer button state \ outOff%%, \ bitmap for greyed / inactive button state \ outOver%%, \ mouse hover bitmap for normal button state \ inOn%%, \ bitmap for button pushed state \ inOver%%, \ mouse hover bitmap for button pushed state \ state&, \ button state flags \ l%, \ left position of button in graphic units relative to the graphics origin \ r%, \ right position of button in graphic units relative to the graphics origin \ call%%, \ pointer to procedure to call when the button is clicked \ tip$ \ text to display in the status bar when mouse rolls over button \ } REM Other Metrics REM ---------------------------------------------------------------------- (Metrics) DIM Win{w%, h%, cw%, ch%, resized%} DIM Body{w%, h%, cw%, ch%} DIM textArea{cw%, cl%, cb%, cr%, ct%, ssh%, drag%} DIM vScroll{show%, x%, y%, w%, h%, c%, sx%, sy%, sh%, sr%} DIM hScroll{show%, x%, y%, w%, h%, c%, sx%, sy%, sw%} DIM statusBar{show%, h%} REM Undo REM ---------------------------------------------------------------------- (Undo) REM maximum number of states that can be saved at any given time UndoMax% = 20 N% = UndoMax% DIM Undo{ \ \ ptr%, \ undo stack pointer (its value can wrap around UndoMax%) \ count%, \ the total number of 'states' on the undo stack \ line%(N%), \ line number from which the program has been saved \ t$(N%, 3), \ array to store: Edit.text$, stringSelect.text$, Line$(Edit.line%), lineColour$(Edit.line%) \ i&(N%, 3), \ array to store: lineIndent&(Edit.line%), lineIndentSelf&(), lineNumberL&(), lineNumberH&() \ i%(N%) \ array to store: lineIndentNext%() \ } DIM Redo{ \ \ ptr%, \ redo stack pointer \ t$(N%, 2) \ array to store: Edit.text$, stringSelect.text$ \ } REM#const{ UNDO_STATE_DELETE_BLANK_LINE_ABOVE = -1 UNDO_STATE_INSERT_BLANK_LINE_ABOVE = -2 UNDO_STATE_INSERT_BLANK_LINE_BELOW = -3 REM#} REM FindReplace REM ---------------------------------------------------------------------- (FindReplace) DIM FR{ \ \ find$, \ stores the string to be searched for \ replace$, \ stores the string with which to replace .find$ \ matchWord%, \ TRUE == match whole words only \ matchCase%, \ TRUE == match case \ replaceAll% \ TRUE == replaceAll in progress \ } REM Dialogues REM ---------------------------------------------------------------------- (Dialogue) dlgCheckboxIcons%% = FNdlg_loadBitmapSet(IconDir$ + "dlg" + RIGHT$(@dir$) + "cb") REM#const{ DLG_ITEM_TEXT_ALIGN_CENTRE = 1 DLG_ITEM_TEXT_ALIGN_RIGHT = 2 DLG_ITEM_BORDER_SHOW = 4 DLG_ITEM_DISABLED = 8 DLG_ITEM_CHECKED = 16 DLG_ITEM_DEFAULT = 32 DLG_ITEM_ES_NUMBER = 64 DLG_ITEM_ES_SELECT_ON_FOCUS = 128 DLG_PAL_WHITE = 1 DLG_PAL_GREY1 = 2 DLG_PAL_GREY2 = 3 DLG_PAL_GREY3 = 4 DLG_PAL_TEXT_HIGHLIGHT = 5 DLG_PAL_ITEM_HIGHLIGHT = 6 DLG_FULLSCREEN = 1 DLG_CENTRE = 2 REM#} REM FunctionList REM ---------------------------------------------------------------------- (FunctionList) DIM fnList{rowChrHeight%, includeOn%, includeLabels%, sort%, stripKeywords%} PROCbgroup_build(fnListBtns{()}, 72, 72, \ \ "ion,ilab,strip,sort,,back,next,,close", \ \ IconDir$ + "fnlist" + RIGHT$(@dir$)) REM#const{ FLIST_BUTTON_ION = 1 FLIST_BUTTON_ILAB = 2 FLIST_BUTTON_STRIP = 3 FLIST_BUTTON_SORT = 4 FLIST_BUTTON_BACK = 6 FLIST_BUTTON_NEXT = 7 FLIST_BUTTON_CLOSE = 9 REM#} FOR I% = FLIST_BUTTON_ION TO FLIST_BUTTON_NEXT fnListBtns{(I%)}.tt.flags& OR= BUTTON_TT_ON NEXT fnListBtns{(FLIST_BUTTON_ION)}.a$ = "Show/Hide ON event handlers (ON CLOSE/ERROR/MOUSE/MOVE/SYS/TIME)" fnListBtns{(FLIST_BUTTON_ILAB)}.a$ = "Show/Hide line labels" fnListBtns{(FLIST_BUTTON_STRIP)}.a$ = "Show/Hide FN & PROC keywords at beginning of function/procedure names" fnListBtns{(FLIST_BUTTON_SORT)}.a$ = "Select to sort alpabetically, deselect to sort chronologically" fnListBtns{(FLIST_BUTTON_BACK)}.a$ = "Previous page" fnListBtns{(FLIST_BUTTON_NEXT)}.a$ = "Next page" REM Other Globals REM ---------------------------------------------------------------------- backMax% = 100 DIM Back{(backMax%)topline%, editline%, startchr%, carrot%} backTotal% = 0 backPtr% = 0 Overwrite% = FALSE : REM is set when Insert key is pressed clipboardHasText% = FALSE REM#const RECENT_MAX = 18 DIM Recent$(RECENT_MAX), Recent{total%, showPathname%} REM#const PLACE_MAX = 9 DIM Place$(PLACE_MAX), Place{total%, current$} REM File Dialogue REM#const{ FILEDLG_SAVE = 0 FILEDLG_LOAD = 1 FILEDLG_LAUNCH = 2 : FILEDLG_BUTTON_TMP = 1 FILEDLG_BUTTON_DIR = 2 FILEDLG_BUTTON_LIB = 3 FILEDLG_BUTTON_USR = 4 FILEDLG_BUTTON_PLACE1 = 5 : FILEDLG_BUTTON_EXT = FILEDLG_BUTTON_PLACE1 + PLACE_MAX FILEDLG_BUTTON_COMPACT = FILEDLG_BUTTON_PLACE1 + PLACE_MAX + 1 FILEDLG_BUTTON_DETAILS = FILEDLG_BUTTON_PLACE1 + PLACE_MAX + 2 FILEDLG_BUTTON_CLOSE = FILEDLG_BUTTON_PLACE1 + PLACE_MAX + 4 FILEDLG_BUTTON_SAVE = FILEDLG_BUTTON_PLACE1 + PLACE_MAX + 5 REM#} DIM ReadDir{files$, nfiles%, dirs$, ndirs%, flags%, path$} REM#const{ RD_METHOD_BB4W = 1 RD_METHOD_SDL_WIN = 2 RD_METHOD_SDL_LINUX = 3 RD_METHOD_ALL_ROBUST = 4 RD_METHOD_ALL_NAIVE = 5 : RD_ROOT = 1 RD_HOURGLASS = 2 REM#} Sort%% = FN_sortinit(0, 2) ANSI_BUTTON_BACK = 1 ANSI_BUTTON_NEXT = 2 ANSI_BUTTON_CLOSE = 4 PROCbgroup_build(AnsiBtns{()}, 72, 72, \ \ "back,next,,close", IconDir$ + "fnlist" + RIGHT$(@dir$)) REM Main Program REM ---------------------------------------------------------------------- (Main) REM window size F% = 0 IF INKEY(-1) == 0 THEN F% = OPENIN(@usr$ + "." + Prog.name$ + "_init.dat") IF F% THEN INPUT#F%,W%,H%,X%,Y% CLOSE#F% VDU 23,22,W%;H%;X%,Y%,16,0 ENDIF ENDIF IF F% == 0 VDU 23,22,960;600;8,20,16,0 VDU 26 : IF POS Win.w% = @vdu%!208 * 2 Win.h% = @vdu%!212 * 2 PROCbgroup_build(Fdb{()}, 72, 72, \ \ "tmp,dir,lib,usr,place1,place2,place3,place4,place5,place6,place7,place8,place9,ext,compact,details,,close,save", \ \ IconDir$ + "file" + RIGHT$(@dir$)) Fdb{(FILEDLG_BUTTON_TMP)}.a$ = @tmp$ Fdb{(FILEDLG_BUTTON_DIR)}.a$ = @dir$ Fdb{(FILEDLG_BUTTON_LIB)}.a$ = @lib$ Fdb{(FILEDLG_BUTTON_USR)}.a$ = @usr$ FOR I% = 1 TO 16 Fdb{(I%)}.tt.flags& OR= BUTTON_TT_ON Fdb{(I%)}.tt.bg& = PAL_HIGHLIGHT NEXT PROCoptions_load PROC_setFont(FontFace%, FontSize%) Win.cw% = Win.w% / chrWidth% Win.ch% = Win.h% / chrHeight% PROCfileDlg_loadIcons PROCmenu_loadScrollIcons PROCmbm_build L% = 0 FOR I% = 1 TO menuBar.menus% A% = LEN menuBarMenu{(I%)}.fullName$ IF A% > L% L% = A% NEXT menuBar.longestNameLen% = L% PROCmenuBar_build PROC_setColourScheme(ColourScheme%) PROCrecent_updateMenu PROCplace_updateMenu PROCtoolbar_build PROCfile_new nStateVars% = 15 DIM pStateVars%%(nStateVars%), undoStateVars{(UndoMax%)i%(nStateVars%)}, redoStateVars{(UndoMax%)i%(nStateVars%)} pStateVars%%() = 0, ^longestLineLen%, ^lastLine%, ^topLine%, ^botLine%, ^Start%, \ \ ^Edit.line%, ^Edit.carrot%, ^Edit.modified%, \ \ ^restoreTopLine%, ^lineSelect.anc%, ^lineSelect.ext%, ^lineSelect.size%, \ \ ^stringSelect.carrotAnc%, ^stringSelect.carrotExt%, ^stringSelect.index% PROCsetWindowTitle PROC_drawAll *REFRESH ON IF SDL% ELSE *REFRESH PROCfile_recover ON ERROR PROC_error : END ON CLOSE PROC_exit : PROC_drawAll : RETURN ON MOUSE PROC_click(@wparam%,@lparam%) : RETURN DIM Move%(2) ON MOVE Move%()=@msg%,@wparam%,@lparam% : PROC_move : RETURN *ESC OFF *SYS 4 P% = 0 REPEAT IF lineSelect.anc% == 0 ON *REFRESH ON IF SDL% ELSE *REFRESH REPEAT REM check for input focus IF SDL% THEN SYS "SDL_GetWindowFlags", @hwnd% TO I% IF (I% AND SDL_WINDOW_INPUT_FOCUS) == 0 THEN REPEAT WAIT 10 : SYS "SDL_GetWindowFlags", @hwnd% TO I% : UNTIL I% AND SDL_WINDOW_INPUT_FOCUS ENDIF ELSE SYS "GetForegroundWindow" TO I% IF I% <> @hwnd% THEN REPEAT WAIT 10 : SYS "GetForegroundWindow" TO I% : UNTIL I% == @hwnd% ENDIF ENDIF IF Win.resized% PROC_drawAll : Win.resized% = FALSE K% = INKEY(1) IF K% == -1 IF INKEY(-6) PROCmenuBar_alt : EXIT REPEAT MOUSE X%, Y%, Z% IF Toolbar.show% THEN IF SDL% SYS "SDL_HasClipboardText" TO R% ELSE SYS "IsClipboardFormatAvailable", 1 TO R% IF R% <> clipboardHasText% THEN clipboardHasText% = R% *REFRESH OFF PROCtoolbar_draw *REFRESH ON IF SDL% ELSE *REFRESH ENDIF ENDIF IF Y% > menuBar.b% IF Y% < Win.h% IF X% > menuBar.l% IF X% < menuBar.r% THEN REM mouse over menu bar IF P% MOUSE ON 0 : P% = 0 IF menuBar.show% IF menuBar.keepOpen% THEN FOR I% = 1 TO menuBar.menus% IF X% > menuBarMenu{(I%)}.l% IF X% < menuBarMenu{(I%)}.r% THEN IF menuBar.selectedMenu% <> I% menuBar.selectedMenu% = I% : PROCmbm_open EXIT FOR ENDIF NEXT ENDIF ELSE IF menuBar.selectedMenu% PROCmenuBar_selectMenu(0) : IF lineSelect.anc% == 0 PROCeditLine_draw IF Y% > Toolbar.b% IF Y% < Win.h% IF Y% > Toolbar.bb% IF Y% < Toolbar.bt% IF X% > Toolbar.bl% IF X% < Toolbar.br% THEN REM mouse over tool bar IF P% MOUSE ON 0 : P% = 0 IF K% == 140 PROCtoolbar_scroll(-72) : K% = -1 IF K% == 141 PROCtoolbar_scroll(72) : K% = -1 FOR I% = 1 TO Toolbar.buttons% IF X% > tbButton{(I%)}.l% + Toolbar.sx% IF X% < tbButton{(I%)}.r% + Toolbar.sx% THEN IF I% <> Toolbar.over% : PROCtoolbar_rollOver(I%) : PROCstatusBar_draw(tbButton{(I%)}.tip$) EXIT FOR ENDIF NEXT IF I% > Toolbar.buttons% IF Toolbar.over% PROCtoolbar_rollOver(0) : PROCstatusBar_draw(" ") ELSE IF Toolbar.over% PROCtoolbar_rollOver(0) : PROCstatusBar_draw IF Y% > bottomBorderTop% IF Y% < topBorderBottom% THEN IF X% < Margin.r% THEN REM mouse over margin IF P% <> 137 MOUSE ON 137 : P% = 137 ELSE IF X% < Body.w% THEN REM mouse over text area IF P% <> 1 MOUSE ON 1 : P% = 1 ELSE REM mouse right IF P% MOUSE ON 0 : P% = 0 ENDIF ENDIF ELSE REM mouse high or low IF P% MOUSE ON 0 : P% = 0 ENDIF ENDIF ENDIF UNTIL K% <> -1 OFF *REFRESH OFF IF K% <> -1 menuBar.keepOpen% = FALSE REM respond to key press IF K% > 31 OR K% == &D OR INKEY(-3) THEN IF K% == 27 PROCcontxMenu_select ELSE PROCkey_editLine ELSE CASE K% OF WHEN 1 REM ctrl-A : select all PROClineSelect_range(1, lastLine%) : PROCtextArea_draw(topLine%, 0) : PROCstatusBar_draw WHEN 2 REM ctrl-B : go back PROCback_go : PROC_drawAll WHEN 3 REM ctrl-C : copy PROC_copy : PROCtoolbar_draw WHEN 6 REM ctrl-F : find PROCfr_open : PROC_drawAll WHEN 7 REM ctrl-G : go to PROCgoto_open : PROC_drawAll WHEN 12 REM ctrl-L : load PROCeditLine_save : PROC_load : PROC_drawAll WHEN 14 REM ctrl-N : new PROCeditLine_save : PROC_new : PROC_drawAll WHEN 19 REM ctrl-S : save PROCeditLine_save : PROC_save : PROC_drawAll WHEN 20 REM ctrl-T : toggle toolbar Toolbar.show% = NOT Toolbar.show% : PROCoptions_save : PROC_drawAll WHEN 21 REM F9, ctrl-U : run PROC_run : PROC_drawAll WHEN 22 REM ctrl-V : paste PROC_paste : PROC_refreshAll WHEN 23 REM ctrl-W : toggle menu bar menuBar.show% = NOT menuBar.show% : PROCoptions_save : PROC_drawAll WHEN 24 REM ctrl-X : cut PROC_cut : PROC_refreshAll WHEN 26 REM ctrl-Z : undo PROCundo_restore : PROC_drawAll WHEN 27 REM escape PROCcontxMenu_select WHEN 28 REM F4, ctrl-\ : function list PROCeditLine_save : PROCfnList_buildList : PROC_drawAll WHEN 29 REM F3, ctrl-] : find next PROCfr_findNext WHEN 31 REM F1, ctrl-_ quick help PROCeditLine_save : PROChelp_quick : PROC_drawAll OTHERWISE PROCkey_editLine ENDCASE ENDIF UNTIL 0 END (_) DEF PROC_error ON MOVE OFF ON MOUSE OFF ON CLOSE OFF ON ERROR OFF CLOSE#0 LOCAL F%, errorline$, logfile$ IF fileModified% THEN F% = OPENOUT(@tmp$ + Prog.name$ + "_recoverPath.dat") PRINT#F%, Dirname$, Basename$, Place.current$ CLOSE#F% PROCfile_writeTokenised(@tmp$ + Prog.name$ + "_recoverProg.bbc") ENDIF ON *REFRESH ON *LOWERCASE OFF errorline$ = FNerrorLine logfile$ = @usr$ + Prog.name$ + "_errlog.txt" F% = OPENUP(logfile$) IF F% THEN PTR#F% = EXT#F% ELSE F% = OPENOUT(logfile$) ENDIF BPUT#F%, TIME$ + " : " + REPORT$ + " : " + errorline$ CLOSE#F% IF SDL% THEN VDU 26 : IF POS VDU 20 : CLS PRINT "Fatal Error"'REPORT$'errorline$ ELSE SYS "MessageBox", @hwnd%, REPORT$ + CHR$&A + errorline$, "Fatal Error", 16 ENDIF ENDPROC DEF PROC_move ON MOVE LOCAL Move%()=@msg%,@wparam%,@lparam% : RETURN ON MOUSE LOCAL : RETURN REM wait for user to let go of the mouse LOCAL P%, W%, H% IF SDL% THEN REPEAT WAIT 1 IF Move%(0) == 5 W% = TRUE SYS "SDL_GetGlobalMouseState", 0, 0 TO P% UNTIL P% == 0 ELSE REPEAT WAIT 1 IF Move%(0) == 5 W% = TRUE UNTIL NOT(INKEY(-10) OR INKEY(-11) OR INKEY(-12)) ENDIF IF NOT W% THEN W% = POS H% = VPOS VDU 26 : IF POS IF Win.w% == 2 * @vdu%!208 IF Win.h% == 2 * @vdu%!212 VDU 31, W%, H% : ENDPROC ENDIF W% = Margin.w% + rightBorderWidth% + chrWidth% : REM minimum window width (graphic units) H% = menuBar.h% + Toolbar.h% + bottomBorderTop% + chrHeight% : REM minimum window height (graphic units) REPEAT REPEAT P% = Move%(2) : WAIT 10 : UNTIL P% == Move%(2) : REM try to get last on move interrupt VDU 26 : IF POS Win.w% = 2 * @vdu%!208 Win.h% = 2 * @vdu%!212 IF Win.w% > W% IF Win.h% > H% THEN IF pRedraw%% PROC(pRedraw%%) Win.resized% = TRUE EXIT REPEAT ELSE PROC_windowTooSmall(W%, H%) ENDIF UNTIL 0 menuBar.keepOpen% = FALSE IF FNwindowmaximised Start% = 1 IF SDL% ELSE *REFRESH ENDPROC REM If the output window gets too small, REM pass control to this procedure, which will wait for the user to increase REM the size of the window again. REM REM Parameter Summary REM ~~~~~~~~~~~~~~~~~ REM REM W% : Minimum accepted window width (pixels) REM H% : Minimum accepted window height (pixels) DEF PROC_windowTooSmall(W%, H%) ON MOVE LOCAL : RETURN ON MOUSE LOCAL : RETURN *REFRESH ON LOCAL X%, Y% REPEAT IF Win.w% <> X% OR Win.h% <> Y% THEN COLOR 128 + PAL_BORDER : CLS OSCLI "MDISPLAY " + STR$~MsgWin.icon.stop%% + " " + STR$(Win.w% / 2 - 64) + "," + STR$(Win.h% / 2 - 64) + ",128,128" X% = Win.w% : Y% = Win.h% ENDIF WAIT 1 : VDU 26 : IF POS Win.w% = 2 * @vdu%!208 Win.h% = 2 * @vdu%!212 UNTIL Win.w% > W% AND Win.h% > H% REPEAT : UNTIL INKEY(0) == -1 : REM flush keyboard buffer Win.resized% = TRUE ENDPROC REM Button/key Value REM Left button 1 REM Right button 2 REM SHIFT key 4 REM CTRL key 8 REM Middle button 16 DEF PROC_click(W%, L%) ON MOUSE LOCAL : RETURN IF W% > 7 ENDPROC LOCAL X%, Y% OFF *REFRESH OFF menuBar.keepOpen% = FALSE X% = (L% AND &FFFF) * 2 - @vdu.o.x% Y% = (@vdu%!212 - 1 - (L% >>> 16)) * 2 - @vdu.o.y% REM respond to mouse click IF Y% > topBorderBottom% THEN REM menu bar / toolbar IF Y% < Win.h% THEN IF Y% > menuBar.b% THEN IF X% > menuBar.l% IF X% < menuBar.r% PROCmenuBar_click(X%) ELSE IF Y% > Toolbar.b% THEN IF Y% > Toolbar.bb% IF Y% < Toolbar.bt% IF X% > Toolbar.bl% IF X% < Toolbar.br% PROCtoolbar_click(X%) ENDIF ENDIF ENDIF ELSE IF Y% > bottomBorderTop% THEN IF X% < Margin.r% THEN REM margin PROCmargin_click(Y%, W%) ELSE IF X% < Body.w% THEN REM text area PROCtextArea_click(X%, Y%, W%) WAIT 10 IF INKEY(-10) THEN REM left mouse button down IF textArea.drag% PROCtextArea_drag(X%, Y%) ELSE PROCtextArea_dragSelect(X%, Y%) ENDIF ELSE REM vscroll PROCvscroll_click(X%, Y%, W%) ENDIF ENDIF ELSE REM hscroll IF Y% > hScroll.y% IF X% > hScroll.x% IF X% < Body.w% PROChscroll_click(X%, Y%, W%) ENDIF ENDIF REM empty clicks REPEAT WAIT 1 : MOUSE X%, Y%, W% : UNTIL W% == 0 IF lineSelect.anc% == 0 ON *REFRESH ON *REFRESH ENDPROC DEF PROCkey_lineSelect CASE K% OF WHEN 9 REM tab, Ctrl+I% IF FNrem_invert PROC_refreshAll WHEN 8, 135 REM backspace and forward delete * PROC_delete PROC_refreshAll WHEN 138 IF INKEY(-1) THEN REM shift-down : move line selection down * PROClineSelect_down ELSE REM down : put cursor at end of selected block & deselect (version 0.37.3 onwards) L% = lineSelect.ext% IF L% < lineSelect.anc% L% = lineSelect.anc% PROClineSelect_clear PROCeditLine_set(L%, TRUE) IF Edit.carrot% < Start% Start% = Edit.carrot% IF L% >= topLine% IF L% <= botLine% THEN PROCtextArea_draw(topLine%, 0) ELSE I% = L% - Body.ch% + 1 IF I% < 1 I% = 1 PROCtextArea_draw(I%, 0) PROCvscroll_draw ENDIF PROCeditLine_draw PROCstatusBar_draw PROChscroll_draw ENDIF WHEN 139 IF INKEY(-1) THEN REM shift-up : move line selection up PROClineSelect_up ELSE REM up : put cursor at start of selected block & deselect (version 0.37.3 onwards) L% = lineSelect.anc% IF L% > lineSelect.ext% L% = lineSelect.ext% PROClineSelect_clear PROCeditLine_set(L%, 0) Start% = 1 IF L% >= topLine% IF L% <= botLine% THEN PROCtextArea_draw(topLine%, 0) ELSE IF L% + Body.ch% - 1 > lastLine% L% = lastLine% - Body.ch% + 1 : IF L% < 1 L% = 1 PROCtextArea_draw(L%, 0) PROCvscroll_draw ENDIF PROCeditLine_draw PROCstatusBar_draw PROChscroll_draw ENDIF WHEN 132 REM page up * L% = topLine% - Body.ch% : IF L% < 1 L% = 1 PROCtextArea_draw(L%, 0) PROCvscroll_draw WHEN 133 REM page down * L% = topLine% + Body.ch% : IF L% > lastLine% L% = lastLine% PROCtextArea_draw(L%, 0) PROCvscroll_draw WHEN 140 REM scroll wheel backward (move text up) * IF botLine% >= lastLine% ENDPROC REM J% == number of lines to scroll up REPEAT J% = 0 : REPEAT : J% += 1 : UNTIL INKEY(1) <> 140 IF botLine% + J% > lastLine% J% = lastLine% - botLine% IF J% > 1 PROCtextArea_draw(topLine% + J%, 0) ELSE PROCtextArea_up WAIT 1 UNTIL INKEY(1) <> 140 OR botLine% >= lastLine% PROCvscroll_draw WHEN 141 REM scroll wheel forward (move text down) IF topLine% == 1 ENDPROC REM J% == number of lines to scroll down REM T% == new top line REPEAT J% = 0 : REPEAT : J% += 1 : UNTIL INKEY(1) <> 141 T% = topLine% - J% IF T% < 1 T% = 1 : J% = topLine% - 1 IF J% > 1 PROCtextArea_draw(T%, 0) ELSE PROCtextArea_down WAIT 1 UNTIL INKEY(1) <> 141 OR topLine% == 1 PROCvscroll_draw WHEN 156 REM home - to first line PROCtextArea_draw(1, 0) PROCvscroll_draw WHEN 157 REM end - to last line L% = lastLine% - Body.ch% + 1 : IF L% < 1 L% = 1 PROCtextArea_draw(L%, 0) PROCvscroll_draw OTHERWISE PROClineSelect_clear PROCtextArea_draw(restoreTopLine%, 0) IF Edit.carrot% - Start% > textArea.cw% - 2 Edit.carrot% = Start% + textArea.cw% - 2 IF Edit.line% > botLine% L% = botLine% ELSE L% = Edit.line% PROCeditLine_set(L%, Edit.carrot%) PROCeditLine_draw PROCstatusBar_draw PROCvscroll_draw ENDCASE ENDPROC DEF FNkey_stringSelect IF L% PROC_delete :=FALSE IF INKEY(-3) :=TRUE CASE K% OF WHEN 8, 135 REM backspace and forward delete * PROC_delete PROCeditLine_draw:PROCtoolbar_draw:PROCstatusBar_draw:PROChscroll_draw:=TRUE WHEN 136 REM shift-left * IF INKEY(-1) THEN REM do nothing if carrot is at start of edit text IF Edit.carrot% == 0 :=TRUE REPEAT REM decrement (move left) the string select carrot extent stringSelect.carrotExt% -= 1 X% = stringSelect.carrotAnc% Y% = stringSelect.carrotExt% IF X% == Y% THEN REM if the string select carrot extent overlaps the string select carrot anchor, nothing is selected! stringSelect.index% = 0 stringSelect.text$ = "" Edit.carrot% -= 1 IF POS == textArea.cl% IF Start% > 1 PROCtextArea_right PROCeditLine_draw ELSE REM make sure X% points to the lowest carrot position of .carrotAnc% and .carrotExt% REM if .carrotAnc% > .carrotExt% then by DECREMENTING .carrotExt% we are INCREASING the size of the string selection (I% = 1) REM if .carrotAnc% < .carrotExt% then by DECREMENTING .carrotExt% we are DECREASING the size of the string selection (I% = -1) IF X% > Y% SWAP X%, Y% : I% = 1 ELSE I% = -1 REM update the selected text stringSelect.index% = X% + 1 stringSelect.text$ = MID$(Edit.text$, stringSelect.index%, Y% - X%) REM move cursor IF POS == textArea.cl% Y% = VPOS : PROCtextArea_right : VDU 31, textArea.cl%, Y% ELSE VDU 8 REM choose colour depending upon whether we are increasing or decreasing string selection IF I% < 0 COLOR 128 + PAL_EDITLINE : COLOR PAL_FOREGROUND ELSE COLOR 128 + PAL_HIGHLIGHT : COLOR PAL_BACKGROUND PRINT MID$(Edit.text$, Edit.carrot%, 1); VDU 8 Edit.carrot% -= 1 ENDIF PROCstatusBar_draw *REFRESH TIME = 0 REPEAT I% = INKEY(0) UNTIL I% <> -1 OR INKEY(-1) == 0 OR TIME > 50 UNTIL I% <> 136 OR Edit.carrot% == 0 IF stringSelect.index% PROCtextArea_draw(topLine%, 0) : PROCeditLine_draw ELSE PROCstringSelect_clear =TRUE ENDIF WHEN 137 REM shift-right * IF INKEY(-1) THEN REM do nothing if carrot is at end of edit text IF Edit.carrot% == LEN Edit.text$ :=TRUE REPEAT REM increment (move right) the string select carrot extent stringSelect.carrotExt% += 1 X% = stringSelect.carrotAnc% Y% = stringSelect.carrotExt% Edit.carrot% += 1 IF X% == Y% THEN REM if the string select carrot extent overlaps the the string select carrot anchor, nothing is selected! REM PROCstringSelect_clear stringSelect.index% = 0 stringSelect.text$ = "" IF POS == textArea.cr% PROCtextArea_left PROCeditLine_draw ELSE REM make sure X% points to the lowest carrot position of .carrotAnc% and .carrotExt% REM if .carrotAnc% > .carrotExt% then by INCREMENTING .carrotExt% we are DECREASING the size of the string selection (I% = -1) REM if .carrotAnc% < .carrotExt% then by INCREMENTING .carrotExt% we are INCREASING the size of the string selection (I% = 1) IF X% > Y% SWAP X%, Y% : I% = -1 ELSE I% = 1 REM update the selected text stringSelect.index% = X% + 1 stringSelect.text$ = MID$(Edit.text$, stringSelect.index%, Y% - X%) IF POS == textArea.cr% THEN REM carrot IS at end of text area Y% = VPOS PROCtextArea_left REM choose colour depending upon whether we are increasing or decreasing string selection IF I% < 0 COLOR 128 + PAL_HIGHLIGHT : COLOR PAL_BACKGROUND ELSE COLOR 128 + PAL_EDITLINE : COLOR PAL_FOREGROUND PRINT TAB(textArea.cr%, Y%) LEFT$(MID$(Edit.text$, Edit.carrot% + 1, 1) + " ", 1); VDU 31, textArea.cr% - 1, Y% ENDIF REM choose colour depending upon whether we are increasing or decreasing string selection IF I% < 0 COLOR 128 + PAL_EDITLINE : COLOR PAL_FOREGROUND ELSE COLOR 128 + PAL_HIGHLIGHT : COLOR PAL_BACKGROUND PRINT MID$(Edit.text$, Edit.carrot%, 1); ENDIF PROCstatusBar_draw *REFRESH TIME = 0 REPEAT I% = INKEY(0) UNTIL I% <> -1 OR INKEY(-1) == 0 OR TIME > 50 UNTIL I% <> 137 OR Edit.carrot% == LEN Edit.text$ IF stringSelect.index% PROCtextArea_draw(topLine%, 0) : PROCeditLine_draw ELSE PROCstringSelect_clear =TRUE ENDIF WHEN 128 REM ctrl-left IF LEN stringSelect.text$ == 1 IF stringSelect.index% > 1 THEN stringSelect.index% -= 1 : stringSelect.carrotAnc% -= 1 : stringSelect.carrotExt% -= 1 stringSelect.text$ = MID$(Edit.text$, stringSelect.index%, 1) IF stringSelect.index% < Start% PROCtextArea_right : PROChscroll_draw Edit.carrot% -= 1 PROCeditLine_draw PROCstatusBar_draw ENDIF =TRUE WHEN 129 REM ctrl-right IF LEN stringSelect.text$ == 1 IF stringSelect.index% < LEN Edit.text$ THEN stringSelect.index% += 1 : stringSelect.carrotAnc% += 1 : stringSelect.carrotExt% += 1 : stringSelect.text$ = MID$(Edit.text$, stringSelect.index%, 1) IF stringSelect.index% > Start% + textArea.cw% - 1 PROCtextArea_left : PROChscroll_draw Edit.carrot% += 1 PROCeditLine_draw PROCstatusBar_draw ENDIF =TRUE WHEN 158 REM ctrl-pageup IF LEN stringSelect.text$ == 1 THEN IF NOT FNinQuotes(Edit.text$, stringSelect.index%) IF NOT FNinComment(Edit.text$, stringSelect.index%) THEN ELSE IF NOT Edit.modified% PROCundo_save(0) : Edit.modified% = TRUE IF NOT fileModified% fileModified% = TRUE : PROCtoolbar_draw I% = ASC stringSelect.text$ IF I% >= 255 THEN I% = 32 ELSE IF I% == 126 I% += 2 ELSE I% += 1 ENDIF stringSelect.text$ = CHR$I% MID$(Edit.text$, stringSelect.index%, 1) = CHR$I% PROCeditLine_draw PROCstatusBar_draw ENDIF ENDIF =TRUE WHEN 159 REM ctrl-pagedown IF LEN stringSelect.text$ == 1 THEN IF NOT FNinQuotes(Edit.text$, stringSelect.index%) IF NOT FNinComment(Edit.text$, stringSelect.index%) THEN ELSE IF NOT Edit.modified% PROCundo_save(0) : Edit.modified% = TRUE IF NOT fileModified% fileModified% = TRUE : PROCtoolbar_draw I% = ASC stringSelect.text$ IF I% <= 32 THEN I% = 255 ELSE IF I% == 128 I% -= 2 ELSE I% -= 1 ENDIF stringSelect.text$ = CHR$I% MID$(Edit.text$, stringSelect.index%, 1) = CHR$I% PROCeditLine_draw PROCstatusBar_draw ENDIF ENDIF =TRUE ENDCASE PROCstringSelect_clear PROCeditLine_draw =FALSE DEF PROCkey_editLine IF lineSelect.size% PROCkey_lineSelect : ENDPROC L% = FNpac IF stringSelect.index% IF FNkey_stringSelect : ENDPROC IF L% == 2 IF NOT FNinQuotes(Edit.text$ + " ", Edit.carrot% + 1) IF NOT FNinComment(Edit.text$ + " ", Edit.carrot% + 1) ENDPROC IF L% PROCeditLine_insertChr:PROCeditLine_draw:PROCtoolbar_draw:PROCstatusBar_draw:PROChscroll_draw:ENDPROC IF INKEY(-3) ENDPROC CASE K% OF WHEN 8 REM backspace delete I% = Edit.carrot% IF I% THEN IF NOT Edit.modified% PROCundo_save(0) Edit.text$ = LEFT$(Edit.text$, I% - 1) + MID$(Edit.text$, I% + 1) Edit.carrot% -= 1 IF POS == Margin.cw% IF Start% > 1 PROCtextArea_right PROCeditLine_draw Edit.modified% = TRUE ELSE IF Edit.line% == 1 ENDPROC REM backspace delete has been pressed with the editLine carrot in position 0 REM the current editLine will be concatenated with the previous line REM REM previous line : L% REM ^ REM ____________| REM | REM edit line : Edit.line% REM next line L% = Edit.line% - 1 : REM index of line before edit line (this will become the new edit line) I% = lineIndent&(L%) : REM current indent of previous line J% = LEN Line$(L%) + I% : REM current (length + indent) of previous line REM if the previous line is blank, there is a faster undo option available IF Line$(L%) == "" PROCundo_save(UNDO_STATE_DELETE_BLANK_LINE_ABOVE) ELSE PROCundo_save(L%) REM add current edit line text to previous line Line$(L%) = FNtnt(Line$(L%) + Edit.text$, M%, N%) IF M% lineNumberL&(L%) = N% MOD 256 : lineNumberH&(L%) = N% DIV 256 PROCline_setColour(L%) PROCline_setIndentEffect(L%) PROCline_setIndent(L%) REM we need to know if the indent of the previous OR next line has changed REM remember that the current edit line will become part of the previous line (see diagram above) REM Formula for calculating the indent of a line is: REM previous_line_indent + previous_line_indent_next - self_indent_effect I% = I% <> lineIndent&(L%) IF I% == FALSE IF Edit.line% < lastLine% THEN A% = lineIndent&(L%) + lineIndentNext%(L%) - lineIndentSelf&(Edit.line% + 1) IF A% < 0 A% = 0 I% = lineIndent&(Edit.line% + 1) <> A% ENDIF REM delete the current edit line PROClines_deleteFrom(Edit.line%, 1) REM re-calculate all indents from the edit line if required IF I% IF L% < lastLine% PROClines_setIndentFrom(Edit.line%) REM redraw the text area as required IF J% - Start% > textArea.cw% THEN REM the carrot index will be outside (to the right) of the text area, REM so we need to move the text right (I.e. increase Start%) Start% = J% - textArea.cw% + 2 REM if the current edit line is the top line of the text area, REM then redraw the text area from the previous line REM else redraw the text area from the current top line IF Edit.line% == topLine% I% = L% ELSE I% = topLine% PROCtextArea_draw(I%, 0) ELSE IF I% THEN REM we need to redraw the text area to account for changed indent IF L% < topLine% I% = 0 ELSE I% = FNlineRow(L%, 0) PROCtextArea_draw(L%, I%) ELSE REM we only need to nudge the text area IF Edit.line% == topLine% PROCtextArea_down PROCtextArea_deleteRow(FNlineRow(Edit.line%, 0)) IF botLine% <= lastLine% PROC(PrintLine%%)(botLine%, textArea.cl%, textArea.cb%) ENDIF ENDIF REM draw new edit line etc... IF Margin.basic% PROCmargin_draw PROCeditLine_set(L%, J%) PROCeditLine_draw PROCvscroll_draw PROClines_setLongestLen ENDIF fileModified% = TRUE PROCtoolbar_draw PROCstatusBar_draw PROChscroll_draw ENDPROC WHEN 140 REM scroll wheel backward (move text up) IF botLine% >= lastLine% ENDPROC J% = FALSE REPEAT IF INKEY(0) T% = lastLine% - botLine% : IF T% > 4 T% = 4 IF Edit.line% < topLine% + T% IF NOT J% PROCeditLine_save : J% = TRUE FOR I% = 1 TO T% : PROCtextArea_up : NEXT UNTIL INKEY(0) <> 140 OR botLine% >= lastLine% IF J% THEN PROCeditLine_set(topLine%, Edit.carrot%) PROCeditLine_draw ELSE I% = textArea.cl% + Edit.carrot% - Start% + 1 J% = textArea.ct% + Edit.line% - topLine% IF I% > 127 IF SDL% AND &F THEN VDU 31, 127, J% : WHILE POS < J% : VDU 9 : ENDWHILE ELSE VDU 31, I%, J% ENDIF ENDIF PROCstatusBar_draw PROCvscroll_draw PROChscroll_draw ENDPROC WHEN 141 REM scroll wheel forward (move text down) IF topLine% == 1 ENDPROC J% = FALSE REPEAT IF INKEY(0) T% = topLine% - 1 : IF T% > 4 T% = 4 IF Edit.line% > botLine% - T% IF NOT J% PROCeditLine_save : J% = TRUE FOR I% = 1 TO T% : PROCtextArea_down : NEXT UNTIL INKEY(0) <> 140 OR topLine% == 1 IF J% THEN PROCeditLine_set(botLine%, Edit.carrot%) PROCeditLine_draw ELSE I% = textArea.cl% + Edit.carrot% - Start% + 1 J% = textArea.ct% + Edit.line% - topLine% IF I% > 127 IF SDL% AND &F THEN VDU 31, 127, J% : WHILE POS < J% : VDU 9 : ENDWHILE ELSE VDU 31, I%, J% ENDIF ENDIF PROCstatusBar_draw PROCvscroll_draw PROChscroll_draw ENDPROC WHEN 135 REM forward delete I% = Edit.carrot% IF I% == LEN Edit.text$ ENDPROC IF NOT Edit.modified% PROCundo_save(0) Edit.text$ = LEFT$(Edit.text$, I%) + MID$(Edit.text$, I% + 2) PROCeditLine_draw Edit.modified% = TRUE fileModified% = TRUE PROCtoolbar_draw PROCstatusBar_draw PROChscroll_draw ENDPROC WHEN 136 REM left / shift-left IF Edit.carrot% == 0 ENDPROC Edit.carrot% -= 1 IF INKEY(-1) THEN I% = Edit.carrot% + 1 stringSelect.carrotAnc% = I% : REM high stringSelect.carrotExt% = Edit.carrot% : REM low stringSelect.index% = I% stringSelect.text$ = MID$(Edit.text$, I%, 1) IF POS == textArea.cl% Start% -= 1 : REM PROCtextArea_right PROCtextArea_draw(topLine%, 0) PROCeditLine_draw PROCtoolbar_draw ELSE IF POS == textArea.cl% PROCtextArea_right PROCeditLine_draw ENDIF PROCstatusBar_draw PROChscroll_draw ENDPROC WHEN 137 REM right / shift-right IF INKEY(-1) THEN IF Edit.carrot% == LEN Edit.text$ ENDPROC I% = Edit.carrot% Edit.carrot% += 1 stringSelect.carrotAnc% = I% : REM low stringSelect.carrotExt% = Edit.carrot% : REM high stringSelect.index% = Edit.carrot% stringSelect.text$ = MID$(Edit.text$, stringSelect.index%, 1) IF POS == textArea.cr% Start% += 1 : REM PROCtextArea_left PROCtextArea_draw(topLine%, 0) PROCeditLine_draw PROCtoolbar_draw ELSE IF POS == textArea.cr% PROCtextArea_left IF Edit.carrot% == LEN Edit.text$ Edit.text$ += " " Edit.carrot% += 1 PROCeditLine_draw ENDIF PROCstatusBar_draw PROChscroll_draw ENDPROC WHEN 138 REM down / shift-down L% = Edit.line% J% = Edit.modified% IF INKEY(-1) THEN PROClineSelect_range(L%, L%) IF Edit.changedLineNumber% PROCmargin_draw PROCtextArea_draw(L%, FNlineRow(L%, 0)) PROCtoolbar_draw PROCstatusBar_draw ELSE IF L% == lastLine% ENDPROC PROCeditLine_save IF L% == botLine% THEN PROCline_draw(botLine%) REPEAT PROCtextArea_up PROCvscroll_draw PROCstatusBar_draw IF INKEY(0) UNTIL INKEY(1) <> 138 REM L% = 1 REM REPEAT REM IF botLine% + L% > lastLine% L% = lastLine% - botLine% REM PROCtextArea_draw(topLine% + L%, 0) REM PROCvscroll_draw REM Edit.line% = botLine% REM PROCstatusBar_draw REM *REFRESH REM L% = 0 : FOR I% = 1 TO 5 : L% += INKEY(1) == 138 : NEXT : L% = ABS(L%) REM UNTIL L% == 0 OR botLine% == lastLine% PROCeditLine_set(botLine%, Edit.carrot%) ELSE IF J% THEN PROClines_setIndentFrom(1) PROCtextArea_draw(L%, FNlineRow(L%, 0)) IF Edit.changedLineNumber% PROCmargin_draw ELSE PROCline_draw(L%) ENDIF PROCeditLine_set(L% + 1, Edit.carrot%) PROCstatusBar_draw ENDIF PROCeditLine_draw ENDIF IF J% PROChscroll_draw ENDPROC WHEN 139 REM up / shift-up L% = Edit.line% J% = Edit.modified% IF INKEY(-1) THEN PROClineSelect_range(L%, L%) IF Edit.changedLineNumber% PROCmargin_draw PROCtextArea_draw(L%, FNlineRow(L%, 0)) PROCtoolbar_draw PROCstatusBar_draw ELSE IF L% == 1 ENDPROC PROCeditLine_save IF L% == topLine% THEN PROCline_draw(topLine%) REPEAT PROCtextArea_down PROCvscroll_draw PROCstatusBar_draw IF INKEY(0) UNTIL INKEY(1) <> 138 REM L% = -1 REM REPEAT REM IF topLine% + L% < 1 L% = 1 - topLine% REM PROCtextArea_draw(topLine% + L%, 0) REM PROCvscroll_draw REM Edit.line% = topLine% REM PROCstatusBar_draw REM *REFRESH REM L% = 0 : FOR I% = 1 TO 5 : L% += INKEY(1) == 139 : NEXT REM UNTIL L% == 0 OR topLine% == 1 PROCeditLine_set(topLine%, Edit.carrot%) ELSE IF J% THEN PROClines_setIndentFrom(1) PROCtextArea_draw(L%, FNlineRow(L%, 0)) IF Edit.changedLineNumber% PROCmargin_draw ELSE PROCline_draw(L%) ENDIF PROCeditLine_set(L% - 1, Edit.carrot%) PROCstatusBar_draw ENDIF PROCeditLine_draw ENDIF IF J% PROChscroll_draw ENDPROC WHEN 13 IF lastLine% == MAX_PROG_SIZE PROC_noRoom : ENDPROC REM return / shift-return IF INKEY(-1) THEN REM insert a blank line above the edit line PROCundo_save(UNDO_STATE_INSERT_BLANK_LINE_ABOVE) L% = Edit.line% : REM copy Edit.line% to L% for convenience PROCeditLine_save : REM save the current edit line IF Edit.changedIndent% THEN PROCtextArea_draw(L%, FNlineRow(L%, 0)) : REM indentation was changed, so redraw text area from edit line ELSE PROCline_draw(L%) : REM indentation was not changed, so 'plain' draw edit line ENDIF PROCtextArea_insertRowBefore(FNlineRow(L%, 0)) : REM insert a row into the text area before the current edit line row PROClines_insertBefore(L%, 1) : REM logically insert a line into the program before the current edit line REM now Edit.line% == L% == index of new line REM lets set properties of the new line: Line$(L%) = "" lineColour$(L%) = "" lineIndent&(L%) = lineIndent&(L% - 1) lineIndentSelf&(L%) = 0 lineIndentNext%(L%) = 0 lineNumberL&(L%) = 0 lineNumberH&(L%) = 0 PROCeditLine_set(L%, Edit.carrot%) ELSE REM edit line : Edit.line% REM ___| REM | REM v REM new line : L% REM line AFTER new line IF INKEY(-2) Edit.carrot% = LEN Edit.text$ IF Edit.carrot% == LEN Edit.text$ PROCundo_save(UNDO_STATE_INSERT_BLANK_LINE_BELOW) ELSE PROCundo_save(Edit.line%) L% = Edit.line% + 1 : REM index of new line I% = lineIndent&(Edit.line%) : REM current indent of edit line REM insert new line PROClines_insertBefore(L%, 1) A% = Edit.line% Line$(A%) = FNtnt(LEFT$(Edit.text$, Edit.carrot%), M%, N%) IF M% lineNumberL&(A%) = N% MOD 256 : lineNumberH&(A%) = N% DIV 256 : Margin.basic% = TRUE PROCline_setColour(A%) PROCline_setIndentEffect(A%) PROCline_setIndent(A%) Line$(L%) = FNtnt(MID$(Edit.text$, Edit.carrot% + 1), M%, N%) lineNumberL&(L%) = N% MOD 256 : lineNumberH&(L%) = N% DIV 256 IF M% Margin.basic% = TRUE PROCline_setColour(L%) PROCline_setIndentEffect(L%) PROCline_setIndent(L%) REM we need to know if the indent of the edit line or the line AFTER the new line has changed I% = I% <> lineIndent&(Edit.line%) IF I% == FALSE IF L% < lastLine% THEN A% = lineIndent&(L%) + lineIndentNext%(L%) - lineIndentSelf&(L% + 1) IF A% < 0 A% = 0 I% = lineIndent&(L% + 1) <> A% ENDIF REM re-calculate all indents from the line after the new line if required REM (actually from the new line to save checking for last line and avoid inelegance of passing L% + 1) IF I% PROClines_setIndentFrom(L%) REM redraw the text are as required IF lineIndent&(L%) < Start% - 1 OR lineIndent&(L%) > textArea.cw% - 1 THEN REM the carrot index will be outside of the text area, REM so we need to redraw all the text, setting the editLineStartChr according to the line indent Start% = lineIndent&(L%) + 1 I% = topLine% IF Edit.line% == botLine% I% += 1 PROCtextArea_draw(I%, 0) ELSE IF Edit.line% == botLine% THEN PROCline_draw(Edit.line%) PROCtextArea_up ELSE IF I% THEN PROCtextArea_draw(Edit.line%, FNlineRow(Edit.line%, 0)) ELSE PROCline_draw(Edit.line%) PROCtextArea_insertRowBefore(FNlineRow(L%, 0)) ENDIF ENDIF ENDIF PROCeditLine_set(L%, lineIndent&(L%)) PROClines_setLongestLen ENDIF REM draw new edit line etc... fileModified% = TRUE IF Margin.basic% PROCmargin_draw PROCeditLine_draw PROCtoolbar_draw PROCstatusBar_draw PROCvscroll_draw PROChscroll_draw ENDPROC WHEN 128 REM ctrl-left I% = Edit.carrot% IF I% == 0 ENDPROC REPEAT I% -= 1 UNTIL MID$(Edit.text$, I%, 1) <> " " AND MID$(Edit.text$, I% + 1, 1) == " " OR I% == 0 IF I% < Start% THEN Start% = I% + 1 PROCtextArea_draw(topLine%, 0) REPEAT UNTIL INKEY(0) == -1 ENDIF Edit.carrot% = I% PROCeditLine_draw PROCstatusBar_draw PROChscroll_draw ENDPROC WHEN 129 REM ctrl-right I% = Edit.carrot% IF I% == LEN Edit.text$ ENDPROC REPEAT I% += 1 UNTIL MID$(Edit.text$, I%, 1) <> " " AND MID$(Edit.text$, I% + 1, 1) == " " OR I% == LEN Edit.text$ IF I% - Start% + 2 > textArea.cw% THEN Start% = I% - textArea.cw% + 2 PROCtextArea_draw(topLine%, 0) REPEAT UNTIL INKEY(0) == -1 ENDIF Edit.carrot% = I% PROCeditLine_draw PROCstatusBar_draw PROChscroll_draw ENDPROC WHEN 4 IF lastLine% == MAX_PROG_SIZE PROC_noRoom : ENDPROC A% = Edit.line% PROCundo_save(A%) REM ctrl-D : duplicate line I% = lineIndentNext%(A%) - lineIndentSelf&(A%) IF Edit.modified% THEN Line$(A%) = FNtnt(Edit.text$, M%, N%) IF M% lineNumberL&(A%) = N% MOD 256 : lineNumberH&(A%) = N% DIV 256 PROCline_setColour(A%) PROCline_setIndentEffect(A%) PROClines_setLongestLen Edit.modified% = FALSE J% = lineIndentNext%(A%) - lineIndentSelf&(A%) ELSE J% = I% ENDIF L% = A% + 1 PROClines_insertBefore(L%, 1) Line$(L%) = Line$(A%) lineColour$(L%) = lineColour$(A%) lineIndentSelf&(L%) = lineIndentSelf&(A%) lineIndentNext%(L%) = lineIndentNext%(A%) lineNumberL&(L%) = 0 lineNumberH&(L%) = 0 IF I% == 0 IF J% == 0 lineIndent&(L%) = lineIndent&(A%) ELSE I% = TRUE : PROClines_setIndentFrom(A%) IF A% == botLine% THEN PROCline_draw(A%) PROCtextArea_up ELSE IF I% THEN PROCtextArea_draw(A%, FNlineRow(A%, 0)) ELSE PROCline_draw(A%) PROCtextArea_insertRowBefore(FNlineRow(L%, 0)) ENDIF ENDIF IF Margin.basic% PROCmargin_draw PROCeditLine_set(L%, Edit.carrot%) PROCeditLine_draw fileModified% = TRUE PROCtoolbar_draw PROCstatusBar_draw PROCvscroll_draw PROChscroll_draw ENDPROC WHEN 9 REM tab K% = 32 : PROCeditLine_insertChr : PROCeditLine_insertChr : PROCeditLine_draw : PROCtoolbar_draw : PROCstatusBar_draw : PROChscroll_draw ENDPROC WHEN 10 IF lastLine% == MAX_PROG_SIZE PROC_noRoom : ENDPROC REM ctrl-return : insert blank line below PROCundo_save(UNDO_STATE_INSERT_BLANK_LINE_BELOW) PROCeditLine_save L% = Edit.line% + 1 PROClines_insertBefore(L%, 1) Line$(L%) = "" lineColour$(L%) = "" lineIndent&(L%) = lineIndent&(Edit.line%) lineIndentSelf&(L%) = 0 lineIndentNext%(L%) = 0 lineNumberL&(L%) = 0 lineNumberH&(L%) = 0 IF Edit.line% == botLine% THEN PROCline_draw(Edit.line%) PROCtextArea_up ELSE IF Edit.changedIndent% THEN PROCtextArea_draw(Edit.line%, FNlineRow(Edit.line%, 0)) ELSE PROCline_draw(Edit.line%) PROCtextArea_insertRowBefore(FNlineRow(L%, 0)) ENDIF ENDIF fileModified% = TRUE IF Margin.basic% PROCmargin_draw PROCeditLine_set(L%, Edit.carrot%) PROCeditLine_draw PROCtoolbar_draw PROCstatusBar_draw PROCvscroll_draw PROChscroll_draw ENDPROC WHEN 130 REM home - to first char IF Start% > 1 THEN Start% = 1 PROCtextArea_draw(topLine%, 0) PROChscroll_draw ENDIF Edit.carrot% = 0 PROCeditLine_draw PROCstatusBar_draw ENDPROC WHEN 131 REM end - to last char WHILE ASCRIGHT$(Edit.text$) == &20 Edit.text$ = LEFT$(Edit.text$) : ENDWHILE I% = LEN Edit.text$ IF I% > textArea.cw% + Start% - 1 THEN REM if carrot is outside of field width to right, increment start character Start% = I% - textArea.cw% + 2 Edit.text$ += " " PROCtextArea_draw(topLine%, 0) PROChscroll_draw ENDIF Edit.carrot% = I% PROCeditLine_draw PROCstatusBar_draw ENDPROC WHEN 132 : PROC_pageUp : ENDPROC WHEN 133 : PROC_pageDown : ENDPROC WHEN 134 : Overwrite% = NOT Overwrite% : PROCstatusBar_draw : ENDPROC WHEN 156 REM home - to first line PROCeditLine_save Start% = 1 PROCtextArea_draw(1, 0) PROCeditLine_set(1, 0) PROCeditLine_draw PROCstatusBar_draw PROCvscroll_draw PROChscroll_draw ENDPROC WHEN 157 REM end - to last last PROCeditLine_save I% = LEN Line$(lastLine%) PROCeditLine_set(lastLine%, I%) Start% = 1 REM if carrot is outside of field width to right increment start character IF I% > textArea.cw% + Start% - 1 Start% = I% - textArea.cw% + 2 : Edit.text$ += " " L% = lastLine% - Body.ch% + 1 : IF L% < 1 L% = 1 PROCtextArea_draw(L%, 0) PROCeditLine_draw PROCstatusBar_draw PROCvscroll_draw PROChscroll_draw ENDPROC ENDCASE ENDPROC (_) REM Sets up the data needed to display the menu bar REM Call after font size change or window resize DEF PROCmenuBar_build LOCAL a$, I%, L% L% = menuBar.longestNameLen% REPEAT a$ = " " FOR I% = 1 TO menuBar.menus% menuBarMenu{(I%)}.cx% = LEN a$ menuBarMenu{(I%)}.l% = LEN a$ * chrWidth% IF LEN menuBarMenu{(I%)}.fullName$ <= L% THEN menuBarMenu{(I%)}.name$ = menuBarMenu{(I%)}.fullName$ ELSE menuBarMenu{(I%)}.name$ = LEFT$(menuBarMenu{(I%)}.fullName$, L% - 1) + "." ENDIF a$ += menuBarMenu{(I%)}.name$ menuBarMenu{(I%)}.r% = LEN a$ * chrWidth% IF I% < menuBar.menus% a$ += " " NEXT menuBar.l% = menuBarMenu{(1)}.l% menuBar.r% = menuBarMenu{(menuBar.menus%)}.r% L% -= 1 UNTIL LEN a$ < Win.cw% OR L% < 2 menuBar.text$ = a$ ENDPROC DEF PROCmenuBar_selectMenu(I%) IF NOT menuBar.show% menuBar.selectedMenu% = 0 : ENDPROC LOCAL J%, X%, W%, A%, B% A% = POS : B% = VPOS : OFF W% = Win.cw% - 1 J% = menuBar.selectedMenu% IF J% THEN X% = menuBarMenu{(J%)}.cx% IF X% < W% THEN COLOR 128 + PAL_BORDER : COLOR 0 PRINT TAB(X%, 0) LEFT$(menuBarMenu{(J%)}.name$, W% - X%); ENDIF ENDIF menuBar.selectedMenu% = 0 IF I% THEN X% = menuBarMenu{(I%)}.cx% IF X% < W% THEN COLOR 128 + PAL_STR : COLOR menuBar.hfg& PRINT TAB(X%, 0) LEFT$(menuBarMenu{(I%)}.name$, W% - X%); ENDIF menuBar.selectedMenu% = I% ENDIF VDU 31, A%, B% : ON ENDPROC DEF PROCmenuBar_draw IFNOTmenuBar.show%ENDPROC GCOLPAL_BORDER:IFSDL%RECTANGLEFILL0,menuBar.b%,Win.w%,chrHeight%ELSERECTANGLEFILL0,menuBar.b%-2,Win.w%,chrHeight% COLOR 0:COLOR128+PAL_BORDER:PRINTTAB(0,0)LEFT$(menuBar.text$,Win.cw%-1); ENDPROC DEF PROCmenuBar_click(X%) LOCAL I% FOR I% = 1 TO menuBar.menus% IF X% > menuBarMenu{(I%)}.l% IF X% < menuBarMenu{(I%)}.r% PROCmenuBar_selectMenu(I%) : PROCmbm_open : ENDPROC NEXT ENDPROC DEF PROCmenuBar_alt LOCAL K%, X%, Y%, Z%, I% ON MOUSE LOCAL RETURN PROCeditLine_save REM make sure the menu bar is displayed IF NOT menuBar.show% THEN menuBar.show% = TRUE PROCoptions_save PROC_drawAll ENDIF OFF *REFRESH OFF REM highlight first letter of menu titles Z% = Win.cw% - 1 COLOR 128 + PAL_BORDER COLOR PAL_VAR GCOL PAL_VAR FOR I% = 1 TO menuBar.menus% X% = menuBarMenu{(I%)}.cx% IF X% < Z% THEN PRINT TAB(X%, 0) LEFT$(menuBarMenu{(I%)}.name$, 1); LINE menuBarMenu{(I%)}.l%, menuBar.b%, menuBarMenu{(I%)}.l% + chrWidth%, menuBar.b% ELSE EXIT FOR ENDIF NEXT *REFRESH REM make sure the mouse is not hovering over any menu bar items MOUSE X%, Y%, Z% IF Y% > menuBar.b% IF Y% < Win.h% IF X% < menuBar.r% MOUSE TO X%, menuBar.b% - 1 REM make sure mouse pointer is showing arrow MOUSE ON 0 REM wait until key press or release of alt REPEAT K% = INKEY(1) UNTIL K% <> -1 OR INKEY(-3) == 0 OFF I% = FALSE CASE K% OF WHEN 136 : I% = menuBar.menus% WHEN 137 : I% = 2 WHEN 138 : I% = 1 OTHERWISE IF K% > &40 IF K% < &7B THEN Y% = FALSE FOR I% = 1 TO menuBar.menus% X% = ASC menuBarMenu{(I%)}.name$ IF K% == X% OR K% == X% + 32 Y% = TRUE : EXIT FOR NEXT I% AND= Y% ENDIF ENDCASE REM redraw menu bar to remove highlights PROCmenuBar_draw IF I% THEN menuBar.selectedMenu% = I% PROCmbm_open ELSE REM redraw edit line if applicable IF lineSelect.anc% == 0 PROCeditLine_draw REM restore mouse pointer PROC_setMousePointer ENDIF REPEAT UNTIL INKEY(0) == -1 ENDPROC (_) DEF PROCmbm_build LOCAL item$(), call%%(), info$(), I% DIM item$(MBM_MAX), call%%(MBM_MAX), info$(MBM_MAX) REM File REM ==== REM#const{ FILE_MENU = 1 FILE_MENU_SAVE = 3 FILE_MENU_LAUNCH = 5 FILE_MENU_PLACE1 = 7 FILE_MENU_OPENDIR = 19 REM#} : item$() = "New#Ctrl+N", \ 1 \ "Load#Ctrl+L", \ 2 \ "Save#Ctrl+S", \ 3 \ "Save As", \ 4 \ "Launch...", \ 5 \ "", \ \ "...", "...", "...", "...", "...", "...", "...", "...", "...", "Edit Places", \ 7-16 \ "", \ \ "Export HTML", \ 18 \ "Open Directory", \ 19 \ "", \ \ "Exit" call%%() = ^PROC_new, ^PROC_load, ^PROC_save, ^PROC_saveAs, ^PROC_launchBBC, \ \ 0, \ \ 0, 0, 0, 0, 0, 0, 0, 0, 0, ^PROCplace_edit, \ \ 0, \ \ ^PROCexport_html_open, 0, \ \ 0, \ \ ^PROC_exit info$() = "Start a new BBC BASIC Program", \ \ "Open 'Load' at: ", \ \ "Save the current BBC BASIC Program", \ \ "Open 'Save As' at: ", \ \ "Open 'Launch' at: ", \ \ "", \ \ "","","","","","","","","","Open 'Edit Places' dialogue", \ \ "", \ \ "Open HTML export dialogue", "Open current program directory with OS file manager", \ \ "", \ \ "Exit " + Prog.name$ PROCmbm_dim(fileMenu{}, 21, item$(), call%%(), info$()) : menuBarMenu{(FILE_MENU)}.fullName$ = "File" menuBarMenu{(FILE_MENU)}.ptr%% = fileMenu{} menuBarMenu{(FILE_MENU)}.pSetFlags%% = ^PROCmbm_setFlags_fileMenu : FOR I% = FILE_MENU_PLACE1 TO FILE_MENU_PLACE1 + PLACE_MAX - 1 fileMenu.button&(I%) = 2 NEXT REM Recent REM ====== REM#const{ RECENT_MENU = 2 RECENT_MENU_SHOW_PATHNAME = RECENT_MAX + 2 REM#} : item$() = "..." : call%%() = 0 : info$() = "" : item$(RECENT_MAX) = "" item$(RECENT_MAX + 1) = "Show Full Pathname" item$(RECENT_MAX + 2) = "Clear Missing Files" item$(RECENT_MAX + 3) = "Clear List" call%%(RECENT_MAX + 1) = ^PROCrecent_toggleShowPathname call%%(RECENT_MAX + 2) = ^PROCrecent_clearMissing call%%(RECENT_MAX + 3) = ^PROCrecent_clearAll info$(RECENT_MAX + 1) = "Show/Hide full pathname of files" info$(RECENT_MAX + 2) = "Remove references to programs that no longer exist" info$(RECENT_MAX + 3) = "Empty list of all recently used programs" PROCmbm_dim(recentMenu{}, RECENT_MAX + 4, item$(), call%%(), info$()) : menuBarMenu{(RECENT_MENU)}.fullName$ = "Recent" menuBarMenu{(RECENT_MENU)}.ptr%% = recentMenu{} menuBarMenu{(RECENT_MENU)}.pSetFlags%% = ^PROCmbm_setFlags_recentMenu : FOR I% = 1 TO RECENT_MAX recentMenu.button&(I%) = 2 NEXT REM Edit REM ==== REM#const{ EDIT_MENU = 3 EDIT_MENU_UNDO = 1 EDIT_MENU_REDO = 2 EDIT_MENU_CUT = 4 EDIT_MENU_COPY = 5 EDIT_MENU_PASTE = 6 EDIT_MENU_SELECT_ALL = 8 EDIT_MENU_FIND_NEXT = 11 EDIT_MENU_REPLACE_NEXT = 12 EDIT_MENU_REPLACE_ALL = 13 EDIT_MENU_ADD_REM = 15 EDIT_MENU_REMOVE_REM = 16 EDIT_MENU_INVERT_REM = 17 EDIT_MENU_INDENT_REM = 18 EDIT_MENU_GOTO = 20 EDIT_MENU_BACK = 21 REM#} : item$() = "" : call%%() = 0 : info$() = "" : item$() = "Undo#Ctrl+Z", \ 1 \ "Redo", \ 2 \ "", \ \ "Cut#Ctrl+X", \ 4 \ "Copy#Ctrl+C", \ 5 \ "Paste#Ctrl+V", \ 6 \ "", \ \ "Select All#Ctrl+A", \ 8 \ "", \ \ "Find...#Ctrl+F", \ 10 \ "Find Next#F3", \ 11 \ "Replace Next#Ctrl+R", \ 12 \ "Replace All", \ 13 \ "", \ \ "Add REMs", \ 15 \ "Remove REMs", \ 16 \ "Invert REMs#Ctrl+I", \ 17 \ "Indent REMs", \ 18 \ "", \ \ "Go To...#Ctrl+G", \ 20 \ "Go Back#Ctrl+B" call%%() = ^PROCundo_restore, ^PROCredo_restore, \ \ 0, \ \ ^PROC_cut, ^PROC_copy, ^PROC_paste, \ \ 0, \ \ 0, \ select all \ 0, \ \ ^PROCfr_open, ^PROCfr_findNext, ^PROCfr_replaceNext, ^PROCfr_replaceAll, \ \ 0, \ \ 0, 0, 0, 0, \ \ 0, \ \ ^PROCgoto_open, ^PROCback_go info$() = "Undo the last edit", \ \ "Reverse the last undo", \ \ "", \ \ "Cut selected string/lines to clipboard (ANSI converted to UTF8 - Shift to bypass)", \ \ "Copy selected string/lines to clipboard (ANSI converted to UTF8 - Shift to bypass)", \ \ "Paste text from clipboard (UTF8 converted to ANSI - Shift to bypass)", \ \ "", \ \ "Select the entire program", \ \ "", \ \ "Open a dialogue to set 'Find' & 'Replace' strings", \ \ "Find next occurance of 'Find' string", \ \ "Find next occurance of 'Find' string & replace it with 'Replace' string", \ \ "Find & replace all occurances of 'Find' string up to end of program", \ \ "", \ \ "Add REM to start of selected lines", \ \ "Remove REM from start of selected lines", \ \ "Add REM to selected lines without REM & remove REM from selected lines with REM", \ \ "Use white space to preserve the indendation of lines to which REM is added", \ \ "", \ \ "Move cursor to the given line number (1 to ", \ \ "Return cursor to position before 'Go To' or 'Function List' jump" PROCmbm_dim(editMenu{}, 21, item$(), call%%(), info$()) : menuBarMenu{(EDIT_MENU)}.fullName$ = "Edit" menuBarMenu{(EDIT_MENU)}.ptr%% = editMenu{} menuBarMenu{(EDIT_MENU)}.pSetFlags%% = ^PROCmbm_setFlags_editMenu REM Utils REM ===== REM#const{ UTILS_MENU = 4 UTILS_MENU_FNLIST_COMPACT = 5 UTILS_MENU_FNLIST_INCLUDE_ON = 6 UTILS_MENU_FNLIST_INCLUDE_LABELS = 7 UTILS_MENU_FNLIST_STRIP_KEYWORDS = 8 UTILS_MENU_FNLIST_SORT = 9 UTILS_MENU_SHOW_BASIC_NUMBERS = 13 REM#} : item$() = "" : call%%() = 0 : info$() = "" : item$() = "Run Program#F9", \ 1 \ "Launch Runtime Engine", \ 2 \ "", \ \ "Open Function List#F4", \ 4 \ "FN List: Compact Menus", \ 5 \ "FN List: Include ON", \ 6 \ "FN List: Include Labels", \ 7 \ "FN List: Strip Keywords", \ 8 \ "FN List: Sort", \ 9 \ "", \ \ "Renumber (10, 20...)" , \ 11 \ "Strip Unused Line Numbers", \ 12 \ "Show BASIC Line Numbers" call%%() = ^PROC_run, ^PROC_launchRTE, \ \ 0, \ \ ^PROCfnList_buildList, 0, 0, 0, 0, 0, \ \ 0, \ \ ^PROClineNumbers_add, ^PROClineNumbers_strip, 0 info$() = "Run the current program", \ \ "Open BBC BASIC window with command prompt", \ \ "", \ \ "Open the full function list menu", \ \ "Increase/Decrease function menu row spacing", \ \ "Show/Hide ON statements in function menu", \ \ "Show/Hide labels (...) in functin menu", \ \ "Show/Hide keyword FN or PROC in function menu names", \ \ "Sort function list alphabetically", \ \ "", \ \ "Add BASIC line numbers in increments of 10", \ \ "Remove any unused BASIC line numbers", \ \ "Toggle margin between actual and BASIC line numbers" PROCmbm_dim(utilsMenu{}, 13, item$(), call%%(), info$()) : menuBarMenu{(UTILS_MENU)}.fullName$ = "Utils" menuBarMenu{(UTILS_MENU)}.ptr%% = utilsMenu{} menuBarMenu{(UTILS_MENU)}.pSetFlags%% = ^PROCmbm_setFlags_utilsMenu REM Options REM ======= REM#const{ OPTIONS_MENU = 5 REM#} : item$() = "" : call%%() = 0 : info$() = "" : item$() = "Menu Bar#Ctrl+W", \ 1 \ "Toolbar#Ctrl+T", \ 2 \ "Margin", \ 3 \ "Status Bar", \ 4 \ "V-Scroll", \ 5 \ "H-Scroll", \ 6 \ "", \ \ "Font: Bitmap", \ 8 \ "Font: Free Mono", \ 9 \ "Font: DejaVu Mono", \ 10 \ "", \ \ "Font Size: Small ", \ 12 \ "Font Size: Medium", \ 13 \ "Font Size: Large", \ 14 \ "Font Size: X-Large", \ 15 \ "", \ \ "Light Colour Scheme", \ 17 \ "Compact Menus", \ 18 \ "", \ \ "Lowercase Keywords", \ 20 \ "Syntax Colouring", \ 21 \ "Line Bracket Match" call%%() = 0, 0, 0, 0, 0, 0, \ \ 0, \ \ 0, 0, 0, \ \ 0, \ \ 0, 0, 0, 0, \ \ 0, \ \ 0, 0, \ \ 0, \ \ ^PROC_changeCase, ^PROC_syntaxColouring, 0 info$() = "Show/Hide menu bar", "Show/Hide toolbar", "Show/Hide margin", "Show/Hide status-bar", \ \ "Show/Hide vertical scroll-bar", "Show/Hide horizontal scroll-bar", \ \ "", \ \ "Bitmap font style", "Free Mono font style", "DejaVu Sans Mono font style", \ \ "", \ \ "SMALL font size", "MEDIUM font size", "LARGE font size", "Extra LARGE font size", \ \ "", \ \ "Toggle Light/Dark Colour Scheme", \ \ "Increase/Decrease menu row spacing", \ \ "", \ \ "Display and accept keywords in lowercase", \ \ "Enable/Disable syntax colouring", \ \ "Highlight matching brackets (limited to a single line)" PROCmbm_dim(optionsMenu{}, 22, item$(), call%%(), info$()) : menuBarMenu{(OPTIONS_MENU)}.fullName$ = "Options" menuBarMenu{(OPTIONS_MENU)}.ptr%% = optionsMenu{} menuBarMenu{(OPTIONS_MENU)}.pSetFlags%% = ^PROCmbm_setFlags_optionsMenu REM Help REM ==== REM#const HELP_MENU = 6 HELP_MENU_OPENUSR = 10 HELP_MENU_OPENTMP = 11 HELP_MENU_OPENDIR = 12 : item$() = "" : call%%() = 0 : info$() = "" : item$() = Prog.name$ + " Quick Help#F1", \ 1 \ "", \ \ "BBC BASIC Manual", \ 3 \ "BBC BASIC Wiki" , \ 4 \ "SDL Wiki", \ 5 \ "", \ \ "Table of ASCII Codes", \ 7 \ "", \ \ Prog.name$ + " debug messages", \ 9 \ "Open @usr$", \ 10 \ "Open @tmp$", \ 11 \ "Open @dir$", \ 12 \ "", \ \ "About " + Prog.name$ call%%() = ^PROChelp_quick, \ \ 0, \ \ ^PROChelp_manual, ^PROChelp_basicWiki, ^PROChelp_sdlWiki, \ \ 0, \ \ ^PROChelp_ascii, \ \ 0, \ \ ^PROChelp_debug, 0, 0, 0, \ \ 0, \ \ ^PROChelp_about info$() = "List keyboard shortcuts and other basic help for " + Prog.name$, \ \ "", \ \ "Open online BBC BASIC Manual in the default web browser", \ \ "Open online BBC BASIC Wiki in the default web browser", \ \ "Open online SDL Wiki in the deafult web browser", \ \ "", \ \ "A reference table of ASCII character codes", \ \ "", \ \ "Information about the current state of " + Prog.name$, \ \ "Open @usr$ folder where " + Prog.name$ + " stores config files", \ \ "Open @tmp$ folder where " + Prog.name$ + " stores temporary files", \ \ "Open @dir$ folder containing " + Prog.name$ + " program files", \ \ "", \ \ "About this program" PROCmbm_dim(helpMenu{}, 14, item$(), call%%(), info$()) : menuBarMenu{(HELP_MENU)}.fullName$ = "Help" menuBarMenu{(HELP_MENU)}.ptr%% = helpMenu{} REM Context Menu REM ============ REM#const{ CONTX_MENU_CUT = 1 CONTX_MENU_COPY = 2 CONTX_MENU_PASTE = 3 CONTX_MENU_ADD_REM = 4 CONTX_MENU_REMOVE_REM = 5 CONTX_MENU_INVERT_REM = 6 REM#} : item$() = "" : call%%() = 0 : info$() = "" : item$() = "Cut", "Copy", "Paste", "Add REMs", "Remove REMs", "Invert REMs", \ \ "", \ \ "Function List", "Character Menu" call%%() = ^PROC_cut, ^PROC_copy, ^PROC_paste, 0, 0, 0, \ \ 0, \ \ ^PROCfnList_buildList, ^PROCchrMenu_open PROCmbm_dim(contxMenu{}, 9, item$(), call%%(), info$()) contxMenu.fg&(8) = PAL_DEF : REM set function list menu item colour contxMenu.over%% = 0 ENDPROC DEF PROCmbm_dim(RETURN m{}, N%, item$(), call%%(), info$()) LOCAL I%, J%, A%, L%, R% DIM m{} = Menu{} REM check for RHS? R% = FALSE FOR I% = 0 TO N% - 1 IF INSTR(item$(I%), "#") R% = TRUE : EXIT FOR NEXT IF R% THEN REM menu with RHS (will be built dynamically from lhs and rhs) R% = 0 FOR I% = 1 TO N% J% = I% - 1 A% = INSTR(item$(J%), "#") IF A% THEN m.lhs$(I%) = LEFT$(item$(J%), A% - 1) m.rhs$(I%) = MID$(item$(J%), A% + 1) ELSE m.lhs$(I%) = item$(J%) m.rhs$(I%) = "" ENDIF m.info$(I%) = info$(J%) m.call%%(I%) = call%%(J%) A% = LEN m.lhs$(I%) : IF A% > L% L% = A% A% = LEN m.rhs$(I%) : IF A% > R% R% = A% NEXT ELSE REM menu without RHS FOR I% = 1 TO N% J% = I% - 1 m.item$(I%) = item$(J%) m.rhs$(I%) = "" m.info$(I%) = info$(J%) m.call%%(I%) = call%%(J%) A% = LEN m.item$(I%) : IF A% > L% L% = A% NEXT ENDIF m.items% = N% m.longestLHS% = L% m.longestRHS% = R% REM m.bg& = PAL_BORDER REM m.hbg& = PAL_HIGHLIGHT m.bg& = PAL_BORDER m.hfg& = PAL_VAR m.hbg& = PAL_STR m.sbg& = PAL_MARGIN m.sfg& = PAL_BORDER m.ofg& = PAL_REM m.over%% = ^PROCmbm_updateStatbar() ENDPROC DEF PROCmbm_setFlags_fileMenu fileMenu.flag&(FILE_MENU_SAVE) = NOT(fileModified%) AND MENU_ITEM_OFF fileMenu.flag&(FILE_MENU_OPENDIR) = (LEN Dirname$ == 0) AND MENU_ITEM_OFF ENDPROC DEF PROCmbm_setFlags_recentMenu recentMenu.flag&(RECENT_MENU_SHOW_PATHNAME) = Recent.showPathname% AND MENU_ITEM_TICK ENDPROC DEF PROCmbm_setFlags_editMenu LOCAL I% editMenu.flag&(EDIT_MENU_UNDO) = (Undo.count% == 0) AND MENU_ITEM_OFF editMenu.flag&(EDIT_MENU_REDO) = (Redo.ptr% == 0) AND MENU_ITEM_OFF I% = (lineSelect.anc% == 0) AND (stringSelect.index% == 0) AND MENU_ITEM_OFF editMenu.flag&(EDIT_MENU_CUT) = I% editMenu.flag&(EDIT_MENU_COPY) = I% editMenu.flag&(EDIT_MENU_PASTE) = (FNclipboard_hasText == 0) AND MENU_ITEM_OFF I% = (LEN FR.find$ == 0) AND MENU_ITEM_OFF editMenu.flag&(EDIT_MENU_FIND_NEXT) = I% editMenu.flag&(EDIT_MENU_REPLACE_NEXT) = I% editMenu.flag&(EDIT_MENU_REPLACE_ALL) = I% I% = (lineSelect.anc% == 0) AND MENU_ITEM_OFF editMenu.flag&(EDIT_MENU_ADD_REM) = I% editMenu.flag&(EDIT_MENU_REMOVE_REM) = I% editMenu.flag&(EDIT_MENU_INVERT_REM) = I% editMenu.flag&(EDIT_MENU_INDENT_REM) = IndentRem% AND MENU_ITEM_TICK editMenu.flag&(EDIT_MENU_BACK) = (backTotal% == 0) AND MENU_ITEM_OFF ENDPROC DEF PROCmbm_setFlags_utilsMenu utilsMenu.flag&(UTILS_MENU_FNLIST_COMPACT) = (fnList.rowChrHeight% == 1) AND MENU_ITEM_TICK utilsMenu.flag&(UTILS_MENU_FNLIST_INCLUDE_ON) = fnList.includeOn% AND MENU_ITEM_TICK utilsMenu.flag&(UTILS_MENU_FNLIST_INCLUDE_LABELS) = fnList.includeLabels% AND MENU_ITEM_TICK utilsMenu.flag&(UTILS_MENU_FNLIST_SORT) = fnList.sort% AND MENU_ITEM_TICK utilsMenu.flag&(UTILS_MENU_FNLIST_STRIP_KEYWORDS) = fnList.stripKeywords% AND MENU_ITEM_TICK utilsMenu.flag&(UTILS_MENU_SHOW_BASIC_NUMBERS) = Margin.basic% AND MENU_ITEM_TICK ENDPROC DEF PROCmbm_setFlags_optionsMenu LOCAL I%, J% optionsMenu.flag&(OPTIONS_MENU_SHOW_MENU) = menuBar.show% AND MENU_ITEM_TICK optionsMenu.flag&(OPTIONS_MENU_SHOW_TOOLBAR) = Toolbar.show% AND MENU_ITEM_TICK optionsMenu.flag&(OPTIONS_MENU_SHOW_MARGIN) = Margin.show% AND MENU_ITEM_TICK optionsMenu.flag&(OPTIONS_MENU_SHOW_STATUS_BAR) = statusBar.show% AND MENU_ITEM_TICK optionsMenu.flag&(OPTIONS_MENU_SHOW_VSCROLL) = vScroll.show% AND MENU_ITEM_TICK optionsMenu.flag&(OPTIONS_MENU_SHOW_HSCROLL) = hScroll.show% AND MENU_ITEM_TICK J% = OPTIONS_MENU_FONT_BITMAP + FontFace% FOR I% = OPTIONS_MENU_FONT_BITMAP TO OPTIONS_MENU_FONT_DEJAVU optionsMenu.flag&(I%) = (J% == I%) AND MENU_ITEM_TICK NEXT J% = OPTIONS_MENU_FONT_SMALL + FontSize% FOR I% = OPTIONS_MENU_FONT_SMALL TO OPTIONS_MENU_FONT_XLARGE optionsMenu.flag&(I%) = (J% == I%) AND MENU_ITEM_TICK optionsMenu.flag&(I%) OR= (FontFace% == 0) AND MENU_ITEM_OFF NEXT optionsMenu.flag&(OPTIONS_MENU_COLOUR_SCHEME) = (ColourScheme% == PALETTE_LIGHT) AND MENU_ITEM_TICK optionsMenu.flag&(OPTIONS_MENU_COMPACT_MENUS) = (menuRowChrHeight% == 1) AND MENU_ITEM_TICK optionsMenu.flag&(OPTIONS_MENU_LOWERCASE_KEYWORDS) = Lowercase% AND MENU_ITEM_TICK optionsMenu.flag&(OPTIONS_MENU_SYNTAX_COLOURING) = SyntaxColour% AND MENU_ITEM_TICK optionsMenu.flag&(OPTIONS_MENU_BRACKET_MATCHING) = BracketMatch% AND MENU_ITEM_TICK ENDPROC DEF PROCmbm_setFlags_helpMenu helpMenu.flag&(HELP_MENU_OPENUSR) = ((SDL% AND &F) > 1) AND MENU_ITEM_OFF helpMenu.flag&(HELP_MENU_OPENTMP) = ((SDL% AND &F) > 1) AND MENU_ITEM_OFF helpMenu.flag&(HELP_MENU_OPENDIR) = ((SDL% AND &F) > 1) AND MENU_ITEM_OFF ENDPROC DEF PROCmbm_open LOCAL m{}, I%, X%, W%, pn$ IF SDL% AND 64 ]^m{} = ]^Menu{} ELSE !^m{} = !^Menu{} Win.resized% = FALSE menuBar.keepOpen% = TRUE pn$ = TempDir$ + "s" I% = menuBar.selectedMenu% PROCmenuBar_selectMenu(0) OSCLI "SCREENSAVE """ + pn$ + """ 0,0" PROCmenuBar_selectMenu(I%) REPEAT I% = 0 PROC_setptr(m{}, menuBarMenu{(menuBar.selectedMenu%)}.ptr%%) REM set menu flags IF menuBarMenu{(menuBar.selectedMenu%)}.pSetFlags%% PROC(menuBarMenu{(menuBar.selectedMenu%)}.pSetFlags%%) REM compute left character position of menu X% = menuBarMenu{(menuBar.selectedMenu%)}.cx% W% = FNmenu_charwidth(m{}) WHILE X% + W% > Win.cw% AND X% > 1 X% -= 1 : ENDWHILE IF FNmenu_open(m{}, X%, 1, 0, 0, menuRowChrHeight%) THEN I% = FNmbm_poll(m{}) IF I% THEN IF I% < 0 THEN *REFRESH OFF OSCLI "DISPLAY """ + pn$ + """" IF I% == -2 THEN REM pointer rolled over menu bar IF lineSelect.anc% == 0 ON : PROCeditLine_draw *REFRESH ON ENDPROC ELSE REM arrow keys used to change menu I% += menuBar.selectedMenu% + 2 IF I% < 1 I% = menuBar.menus% ELSE IF I% > menuBar.menus% I% = 1 PROCmenuBar_selectMenu(I%) ENDIF *REFRESH ON ELSE REM menu item selected IF m.call%%(I%) THEN PROC(m.call%%(I%)) ELSE CASE menuBar.selectedMenu% OF WHEN FILE_MENU CASE I% OF WHEN FILE_MENU_OPENDIR IFFNfileropen(Dirname$) OTHERWISE IF I% >= FILE_MENU_PLACE1 IF I% < FILE_MENU_PLACE1 + PLACE_MAX PROCplace_open(I% - FILE_MENU_PLACE1 + 1, m.button& == 2) ENDCASE WHEN RECENT_MENU IF I% <= Recent.total% THEN IF m.button& == 2 PROCrecent_runProgram(I%) ELSE PROCrecent_loadProgram(I%) ENDIF WHEN EDIT_MENU CASE I% OF WHEN EDIT_MENU_SELECT_ALL : PROClineSelect_range(1, lastLine%) WHEN EDIT_MENU_ADD_REM : IF FNrem_add topLine% = restoreTopLine% WHEN EDIT_MENU_REMOVE_REM : PROCrem_remove : topLine% = restoreTopLine% WHEN EDIT_MENU_INVERT_REM : IF FNrem_invert topLine% = restoreTopLine% WHEN EDIT_MENU_INDENT_REM : IndentRem% EOR= TRUE : PROCoptions_save ENDCASE WHEN UTILS_MENU CASE I% OF WHEN UTILS_MENU_FNLIST_COMPACT IF fnList.rowChrHeight% == 2 fnList.rowChrHeight% = 1 ELSE fnList.rowChrHeight% = 2 PROCoptions_save WHEN UTILS_MENU_FNLIST_INCLUDE_ON fnList.includeOn% EOR= TRUE IF fnList.includeOn% fnList.sort% = FALSE PROCoptions_save WHEN UTILS_MENU_FNLIST_INCLUDE_LABELS fnList.includeLabels% EOR= TRUE PROCoptions_save WHEN UTILS_MENU_FNLIST_SORT fnList.sort% EOR= TRUE IF fnList.sort% fnList.includeOn% = FALSE PROCoptions_save WHEN UTILS_MENU_FNLIST_STRIP_KEYWORDS fnList.stripKeywords% EOR= TRUE PROCoptions_save WHEN UTILS_MENU_SHOW_BASIC_NUMBERS Margin.basic% EOR= TRUE PROCoptions_save ENDCASE WHEN OPTIONS_MENU CASE I% OF WHEN OPTIONS_MENU_SHOW_MENU : menuBar.show% EOR= TRUE : PROCoptions_save WHEN OPTIONS_MENU_SHOW_TOOLBAR : Toolbar.show% EOR= TRUE : PROCoptions_save WHEN OPTIONS_MENU_SHOW_MARGIN : Margin.show% EOR= TRUE : PROCoptions_save WHEN OPTIONS_MENU_SHOW_STATUS_BAR : statusBar.show% EOR= TRUE : PROCoptions_save WHEN OPTIONS_MENU_SHOW_VSCROLL : vScroll.show% EOR= TRUE : PROCoptions_save WHEN OPTIONS_MENU_SHOW_HSCROLL : hScroll.show% EOR= TRUE : PROCoptions_save WHEN OPTIONS_MENU_FONT_BITMAP, OPTIONS_MENU_FONT_FREEMONO, OPTIONS_MENU_FONT_DEJAVU PROC_setFont(I%-OPTIONS_MENU_FONT_BITMAP, FontSize%) PROCtoolbar_textAlign PROCoptions_save WHEN OPTIONS_MENU_FONT_SMALL, OPTIONS_MENU_FONT_MEDIUM, OPTIONS_MENU_FONT_LARGE, OPTIONS_MENU_FONT_XLARGE PROC_setFont(FontFace%, I%-OPTIONS_MENU_FONT_SMALL) PROCtoolbar_textAlign PROCoptions_save WHEN OPTIONS_MENU_COLOUR_SCHEME IF ColourScheme% == PALETTE_DARK PROC_setColourScheme(PALETTE_LIGHT) ELSE PROC_setColourScheme(PALETTE_DARK) PROCoptions_save WHEN OPTIONS_MENU_COMPACT_MENUS IF menuRowChrHeight% == 2 menuRowChrHeight% = 1 ELSE menuRowChrHeight% = 2 PROCoptions_save WHEN OPTIONS_MENU_BRACKET_MATCHING : BracketMatch% EOR= TRUE : PROCoptions_save ENDCASE WHEN HELP_MENU CASE I% OF WHEN HELP_MENU_OPENUSR : IFFNfileropen(@usr$) WHEN HELP_MENU_OPENTMP : IFFNfileropen(@tmp$) WHEN HELP_MENU_OPENDIR : IFFNfileropen(@dir$) ENDCASE ENDCASE ENDIF REM prevent mbm_poll() responding to a window resize that occured while processing a menu option Win.resized% = FALSE menuBar.keepOpen% = FALSE PROC_drawAll ENDPROC ENDIF ELSE REM unconditional close caused by clicking off menu / ESC / window resize IF NOT Win.resized% PROC_drawAll Win.resized% = FALSE menuBar.keepOpen% = FALSE ENDIF ENDIF UNTIL I% == 0 ENDPROC REM Returns -3 if we need to open a menu to the left REM Returns -2 if we need to close the menu but keep the menu bar 'open' REM Returns -1 if we need to open a menu to the right REM Returns 0 if we need to close the menu unconditionally REM Otherwise returns the index of the selected menu item DEF FNmbm_poll(m{}) LOCAL I%, K%, X%, Y%, M%, L%, R%, A%, B%, click% ON MOUSE LOCAL click% = FNmbm_click(@wparam%, @lparam%, m{}) : RETURN M% = menuBar.selectedMenu% L% = menuBarMenu{(M%)}.l% R% = menuBarMenu{(M%)}.r% MOUSE ON 0 OFF *REFRESH ON REPEAT REPEAT IF click% THEN IF click% > 0 THEN =click% ELSE =0 ENDIF K% = INKEY(1) MOUSE X%, Y%, I% IF A% == X% IF B% == Y% THEN ELSE A% = X% : B% = Y% IF Y% > menuBar.b% THEN IF X% > L% IF X% < R% ELSE =-2 ELSE IF X% > m.l% IF X% < m.r% IF Y% > m.b% IF Y% < m.t% THEN I% = FNmenu_itemFromMouseY(m{}, Y%) IF m.selected% <> I% PROCmenu_selectItem(m{}, I%) ENDIF ENDIF ENDIF UNTIL K% <> -1 OR Win.resized% == TRUE CASE K% OF WHEN 13 : IF m.selected% IF (m.flag&(m.selected%) AND MENU_ITEM_OFF) == 0 :=m.selected% WHEN 27 : =0 WHEN 136 :=-3 WHEN 137 :=-1 WHEN 140 : PROCmenu_scrollDown(m{}) WHEN 141 : PROCmenu_scrollUp(m{}) WHEN 138 : PROCmenu_cursorDown(m{}) WHEN 139 : PROCmenu_cursorUp(m{}) ENDCASE UNTIL Win.resized% =0 REM Returns 0 if a click should be ignored REM Returns -1 if click results in closing the menu REM Otherwise it returns the index of the selected menu item DEF FNmbm_click(W%, L%, m{}) REM IF W% <> 1 :=0 LOCAL X%, Y%, I%, Z% X% = (L% AND &FFFF) * 2 - @vdu.o.x% Y% = (@vdu%!212 - 1 - (L% >>> 16)) * 2 - @vdu.o.y% IF X% > m.l% IF X% < m.r% IF Y% > m.b% IF Y% < m.t% THEN I% = FNmenu_itemFromMouseY(m{}, Y%) IF I% THEN IF W% <> 1 IF (W% AND m.button&(I%)) == 0 :=0 IF (m.flag&(I%) AND MENU_ITEM_OFF) == 0 IF m.item$(I%) <> "" THEN m.button& = W% :=I% ELSE =0 ENDIF IF W% <> 1 :=0 I% = FNmenu_scrollButtonFromMouseY(m{}, Y%) IF I% THEN MOUSE X%, Y%, Z% WHILE Z% IF I% < 0 PROCmenu_scrollUp(m{}) ELSE PROCmenu_scrollDown(m{}) WAIT 10 MOUSE X%, Y%, Z% ENDWHILE ENDIF ELSE =-1 ENDIF =0 REM M% == status bar modified DEF PROCmbm_updateStatbar(m{}) IF NOT statusBar.show% ENDPROC IF statusBar.h% > m.b% ENDPROC PRIVATE M% LOCAL a$ IF m.selected% IF LEN m.info$(m.selected%) THEN CASE m{} OF WHEN fileMenu{} CASE m.selected% OF WHEN 2,4,FILE_MENU_LAUNCH : a$ = Place.current$ ENDCASE WHEN editMenu{} IF m.selected% == EDIT_MENU_GOTO a$ = STR$lastLine% + ")" ENDCASE PROCstatusBar_draw(m.info$(m.selected%)+a$) M% = TRUE ENDPROC ENDIF IF M% PROCstatusBar_draw(" ") : M% = FALSE ENDPROC (_) DEF PROCcontxMenu_select LOCAL X%, Y%, Z% MOUSE X%, Y%, Z% IF X% > Margin.r% IF X% < Body.w% IF Y% > bottomBorderTop% IF Y% < topBorderBottom% THEN PROCtextArea_click(X%, Y%, 4) ENDIF ENDPROC REM Note that contxMenu{} is dimensioned in PROCmbm_build DEF PROCcontxMenu_open(X%, Y%) LOCAL I% Win.resized% = FALSE REM set contx menu flags I% = (lineSelect.size% OR stringSelect.index%) == 0 I% AND= MENU_ITEM_OFF contxMenu.flag&(CONTX_MENU_CUT) = I% contxMenu.flag&(CONTX_MENU_COPY) = I% contxMenu.flag&(CONTX_MENU_PASTE) = (FNclipboard_hasText == 0) AND MENU_ITEM_OFF I% = (lineSelect.anc% == 0) AND MENU_ITEM_OFF contxMenu.flag&(CONTX_MENU_ADD_REM) = I% contxMenu.flag&(CONTX_MENU_REMOVE_REM) = I% contxMenu.flag&(CONTX_MENU_INVERT_REM) = I% REM find the character x and y position of the mouse X% /= chrWidth% Y% = (Win.h% - Y%) / chrHeight% X% -= 1 IF X% < 0 X% = 0 Y% -= 1 IF Y% < 0 Y% = 0 WHILE X% > 0 AND Win.cw% - X% < contxMenu.longestLHS% + 6 X% -= 1 ENDWHILE WHILE Y% > 0 AND (Win.ch% - Y%) DIV menuRowChrHeight% < contxMenu.items% + 2 Y% -= 1 ENDWHILE IF FNmenu_open(contxMenu{}, X%, Y%, 0, 0, menuRowChrHeight%) THEN I% = FNcontxMenu_poll(contxMenu{}) IF I% THEN IF contxMenu.call%%(I%) THEN PROC(contxMenu.call%%(I%)) ELSE CASE I% OF WHEN CONTX_MENU_ADD_REM : IF FNrem_add topLine% = restoreTopLine% WHEN CONTX_MENU_REMOVE_REM : PROCrem_remove : topLine% = restoreTopLine% WHEN CONTX_MENU_INVERT_REM : IF FNrem_invert topLine% = restoreTopLine% ENDCASE ENDIF ENDIF ENDIF ENDPROC REM Returns 0 if we need to close the menu unconditionally REM Otherwise returns the index of the selected menu item DEF FNcontxMenu_poll(m{}) LOCAL I%, K%, A%, B%, X%, Y%, click% ON MOUSE LOCAL click% = FNmbm_click(@wparam%, @lparam%, m{}) : RETURN MOUSE ON 0 OFF *REFRESH ON *REFRESH REPEAT REPEAT IF click% THEN REPEAT : MOUSE X%, Y%, I% : UNTIL I% == 0 IF click% > 0 :=click% ELSE :=0 ENDIF K% = INKEY(1) MOUSE X%, Y%, I% IF A% == X% IF B% == Y% THEN ELSE REM mouse has moved A% = X% : B% = Y% IF X% > m.l% IF X% < m.r% IF Y% > m.b% IF Y% < m.t% THEN REM mouse is over menu I% = FNmenu_itemFromMouseY(m{}, Y%) IF m.selected% <> I% PROCmenu_selectItem(m{}, I%) ENDIF ENDIF UNTIL K% <> -1 OR Win.resized% == TRUE CASE K% OF WHEN 13 : IF m.selected% IF (m.flag&(m.selected%) AND MENU_ITEM_OFF) == 0 :=m.selected% WHEN 27 : =0 WHEN 140 : PROCmenu_scrollDown(m{}) WHEN 141 : PROCmenu_scrollUp(m{}) WHEN 138 : PROCmenu_cursorDown(m{}) WHEN 139 : PROCmenu_cursorUp(m{}) ENDCASE UNTIL Win.resized% =0 (_) DEF PROCoptions_load LOCAL F%, k$, v$, I%, S% REM intialise defaults Margin.show% = TRUE Margin.basic% = FALSE menuBar.show% = TRUE Toolbar.show% = TRUE statusBar.show% = TRUE vScroll.show% = TRUE hScroll.show% = TRUE textArea.drag% = FALSE FontFace% = 1 FontSize% = 1 ColourScheme% = PALETTE_DARK menuRowChrHeight% = 1 fileDlg_rowChrHeight% = 2 fileDlg_viewDetails% = FALSE fnList.rowChrHeight% = 1 fnList.includeOn% = FALSE fnList.includeLabels% = TRUE fnList.sort% = FALSE fnList.stripKeywords% = TRUE : Lowercase% = FALSE SyntaxColour% = TRUE BracketMatch% = FALSE IndentRem% = TRUE PNGIcons% = TRUE : Recent.total% = 0 Recent.showPathname% = FALSE Recent$() = "" : Place.total% = 0 Place.current$ = FNdirname(@dir$, 1) IF Place.current$ = "" Place.current$ = @dir$ Place$() = "" REM load core options F% = OPENIN(@usr$ + "." + Prog.name$ + "_options.dat") IF F% THEN REM load from .dat INPUT#F%, I% CASE I% OF WHEN 1 INPUT#F%, \ \ menuBar.show%, \ \ Margin.show%, \ \ Margin.basic%, \ \ statusBar.show%, \ \ Toolbar.show%, \ \ vScroll.show%, \ \ hScroll.show%, \ \ textArea.drag%, \ \ I%, \ fontOption% \ menuRowChrHeight%, \ \ fileDlg_rowChrHeight%, \ \ fnList.rowChrHeight%, \ \ fnList.includeOn%, \ \ fnList.includeLabels%, \ \ Lowercase% WHEN TRUE, FALSE PTR#F% = 0 INPUT#F%, \ \ Margin.show%, \ \ Margin.basic%, \ \ statusBar.show%, \ \ Toolbar.show%, \ \ vScroll.show%, \ \ hScroll.show%, \ \ I%, \ fontOption% \ menuRowChrHeight%, \ \ fnList.includeOn%, \ \ menuBar.show%, \ \ textArea.drag% ENDCASE CLOSE#F% S% OR= 1 ELSE REM load from .ini F% = OPENIN(@usr$ + "." + Prog.name$ + "_options.ini") IF F% THEN S% OR= 2 ELSE F% = OPENIN(@usr$ + Prog.name$ + "_options.ini") ENDIF IF F% THEN WHILE FNini_next(F%, k$, v$) CASE k$ OF WHEN "margin-show" : Margin.show% = VALv$ <> 0 WHEN "margin-basic" : Margin.basic% = VALv$ <> 0 WHEN "menubar-show" : menuBar.show% = VALv$ <> 0 WHEN "toolbar-show" : Toolbar.show% = VALv$ <> 0 WHEN "statusbar-show" : statusBar.show% = VALv$ <> 0 WHEN "vscroll-show" : vScroll.show% = VALv$ <> 0 WHEN "hscroll-show" : hScroll.show% = VALv$ <> 0 WHEN "textarea-drag" : textArea.drag% = VALv$ <> 0 WHEN "font-face" : FontFace% = VALv$ WHEN "font-size" : FontSize% = VALv$ WHEN "colour-scheme" : ColourScheme% = VALv$ WHEN "menu-row-size" : menuRowChrHeight% = VALv$ WHEN "filedlg-row-size" : fileDlg_rowChrHeight% = VALv$ WHEN "filedlg-view-details" : fileDlg_viewDetails% = VALv$ <> 0 WHEN "fnlist-row-size" : fnList.rowChrHeight% = VALv$ WHEN "fnlist-include-on" : fnList.includeOn% = VALv$ <> 0 WHEN "fnlist-include-labels" : fnList.includeLabels% = VALv$ <> 0 WHEN "fnlist-sort" : fnList.sort% = VALv$ <> 0 WHEN "fnlist-strip-keywords" : fnList.stripKeywords% = VALv$ <> 0 WHEN "lowercase-keywords" : Lowercase% = VALv$ <> 0 WHEN "syntax-colouring" : SyntaxColour% = VALv$ <> 0 WHEN "bracket-matching" : BracketMatch% = VALv$ <> 0 WHEN "indent-rem" : IndentRem% = VALv$ <> 0 WHEN "png-icons" : PNGIcons% = VALv$ <> 0 WHEN "recent-show-pathname" : Recent.showPathname% = VALv$ <> 0 WHEN "place" : IF Place.total% < PLACE_MAX Place.total% += 1 : Place$(Place.total%) = v$ WHEN "last-visted" : Place.current$ = v$ ENDCASE ENDWHILE CLOSE#F% ENDIF ENDIF REM load recent file list F% = OPENIN(@usr$ + "." + Prog.name$ + "_recent.dat") IF F% THEN REM load from .dat INPUT#F%, Recent.total% IF Recent.total% THEN LOCAL path$, name$ FOR I% = 1 TO Recent.total% INPUT#F%, path$, name$ Recent$(I%) = path$ + name$ NEXT ENDIF CLOSE#F% S% OR= 3 ELSE REM load from .ini F% = OPENIN(@usr$ + Prog.name$ + "_options.ini") IF F% THEN WHILE FNini_next(F%, k$, v$) IF k$ == "recent" IF Recent.total% < RECENT_MAX Recent.total% += 1 : Recent$(Recent.total%) = v$ ENDWHILE CLOSE#F% ENDIF ENDIF IF FontFace% >= 0 IF FontFace% <= 2 ELSE FontFace% = 1 IF FontSize% >= 0 IF FontSize% <= 3 ELSE FontSize% = 1 IF Lowercase% THEN FOR I% = 1 TO 255 : K$(I%) = FN_lower(K$(I%)) : NEXT *LOWERCASE ON ELSE *LOWERCASE OFF ENDIF IF SyntaxColour% PrintLine%% = ^PROCline_printColour() ELSE PrintLine%% = ^PROCline_printMono() CASE ColourScheme% OF WHEN PALETTE_DARK, PALETTE_LIGHT OTHERWISE : ColourScheme% = PALETTE_DARK ENDCASE IF SDL% ELSE PNGIcons% = FALSE IF Place.total% == 0 THEN IF SDL% AND &F THEN IF (SDL% AND &F) == 1 THEN Place.total% = 1 : Place$(1) = "/" I% = INSTR(@usr$, "/", 2) IF I% I% = INSTR(@usr$, "/", I% + 1) IF I% IF I% < LEN@usr$ Place.total% = 2 : Place$(2) = LEFT$(@usr$, I%) ENDIF ELSE Place.total% = 1 : Place$(1) = "C:\" ENDIF ENDIF IF S% == 0 ENDPROC PROCoptions_save IF S% AND 1 IFFNunlink(@usr$ + "." + Prog.name$ + "_options.dat") IF S% AND 2 IFFNunlink(@usr$ + "." + Prog.name$ + "_options.ini") IF S% AND 3 IFFNunlink(@usr$ + "." + Prog.name$ + "_recent.dat") ENDPROC DEF PROCoptions_save LOCAL F%, I% F% = OPENOUT(@usr$ + Prog.name$ + "_options.ini") BPUT#F%, "margin-show:" + STR$ABSMargin.show% BPUT#F%, "margin-basic:" + STR$ABSMargin.basic% BPUT#F%, "menubar-show:" + STR$ABSmenuBar.show% BPUT#F%, "toolbar-show:" + STR$ABSToolbar.show% BPUT#F%, "statusbar-show:" + STR$ABSstatusBar.show% BPUT#F%, "vscroll-show:" + STR$ABSvScroll.show% BPUT#F%, "hscroll-show:" + STR$ABShScroll.show% BPUT#F%, "textarea-drag:" + STR$ABStextArea.drag% BPUT#F%, "font-face:" + STR$FontFace% BPUT#F%, "font-size:" + STR$FontSize% BPUT#F%, "colour-scheme:" + STR$ColourScheme% BPUT#F%, "menu-row-size:" + STR$menuRowChrHeight% BPUT#F%, "filedlg-row-size:" + STR$fileDlg_rowChrHeight% BPUT#F%, "filedlg-view-details:" + STR$ABSfileDlg_viewDetails% BPUT#F%, "fnlist-row-size:" + STR$fnList.rowChrHeight% BPUT#F%, "fnlist-include-on:" + STR$ABSfnList.includeOn% BPUT#F%, "fnlist-include-labels:" + STR$ABS fnList.includeLabels% BPUT#F%, "fnlist-sort:" + STR$ABSfnList.sort% BPUT#F%, "fnlist-strip-keywords:" + STR$ABSfnList.stripKeywords% BPUT#F%, "lowercase-keywords:" + STR$ABSLowercase% BPUT#F%, "syntax-colouring:" + STR$ABSSyntaxColour% BPUT#F%, "bracket-matching:" + STR$ABSBracketMatch% BPUT#F%, "indent-rem:" + STR$ABSIndentRem% BPUT#F%, "png-icons:" + STR$ABSPNGIcons% BPUT#F%, "recent-show-pathname:" + STR$ABSRecent.showPathname% BPUT#F%, "last-visted:" + Place.current$ IF Recent.total% FOR I% = 1 TO Recent.total% : BPUT#F%, "recent:" + Recent$(I%) : NEXT IF Place.total% FOR I% = 1 TO Place.total% : BPUT#F%, "place:" + Place$(I%) : NEXT CLOSE#F% ENDPROC (_) DEF PROC_new IF FN_unsavedWorkOK PROCfile_new : ENDPROC ENDPROC DEF PROC_load(path$) DEF PROC_load : LOCAL path$ IF NOT FN_unsavedWorkOK ENDPROC LOCAL name$, ext$, t$ ext$ = "bbc" IF LEN path$ ELSE path$ = Place.current$ IF FNchdir(path$) ELSE path$ = @usr$ REPEAT REPEAT UNTIL FNfileDlg_open(FILEDLG_LOAD, path$, name$, ext$) IF path$ == "" ENDPROC IF FNis_readable(path$ + name$) PROCfile_load(path$ + name$) : ENDPROC t$ = "" PROCmsgline_title(t$, "Can't Load File!") PROCmsgline_add(t$, CHR$0 + """" + path$ + name$ + """", "C") IFFNmsgwin(t$, MSGWIN_STOP) UNTIL 0 ENDPROC DEF PROC_save IF LEN Dirname$ ELSE PROC_saveAs : ENDPROC PROCfile_save(Dirname$ + Basename$) ENDPROC DEF PROC_saveAs(path$) DEF PROC_saveAs : LOCAL path$ LOCAL name$, ext$, I%, t$ IF LEN path$ ELSE path$ = Place.current$ IF FNchdir(path$) ELSE path$ = @usr$ name$ = Basename$ ext$ = FNextension(name$) IF ext$ == "" ext$ = "bbc" REPEAT REPEAT UNTIL FNfileDlg_open(FILEDLG_SAVE, path$, name$, ext$) IF path$ == "" ENDPROC I% = TRUE IF FNis_readable(path$ + name$) THEN t$ = "" PROCmsgline_title(t$, "File Exists!") PROCmsgline_add(t$, CHR$0 + """" + path$ + name$ + """", "C") PROCmsgline_add(t$, CHR$0 + "Overwrite?", "C") I% = FNmsgwin(t$, MSGWIN_WARNING + MSGWIN_YESNO) - 2 ENDIF IF I% PROCfile_save(path$ + name$) : ENDPROC UNTIL 0 ENDPROC DEF PROC_exit IF NOT FN_unsavedWorkOK ENDPROC ON CLOSE OFF ON MOVE OFF ON MOUSE OFF CLOSE#0 LOCAL I%, W%, H% REM get normal window size IF SDL% THEN REM#const SDL_WINDOW_MAXIMIZED = &80 SYS "SDL_GetWindowFlags", @hwnd% TO I% IF I% AND SDL_WINDOW_MAXIMIZED SYS "SDL_RestoreWindow", @hwnd% : VDU 20 : CLS : PRINT "Restoring window size..." : WAIT 50 VDU 26 : IF POS W% = @vdu%!208 H% = @vdu%!212 ELSE REM#const SW_SHOWMAXIMIZED = 3 LOCAL wp{} DIM wp{length%, flags%, showcmd%, minpos{x%,y%}, maxpos{x%,y%}, normal{l%,t%,r%,b%}} wp.length% = DIM(wp{}) SYS "GetWindowPlacement", @hwnd%, wp{} IF wp.showcmd% == SW_SHOWMAXIMIZED THEN W% = wp.normal.r% - wp.normal.l% H% = wp.normal.b% - wp.normal.t% ELSE W% = Win.w% / 2 H% = Win.h% / 2 ENDIF ENDIF REM save window size I% = OPENOUT(@usr$ + "." + Prog.name$ + "_init.dat") PRINT#I%, W%, H%, chrWidth% / 2, chrHeight% / 2 CLOSE#I% REM remove temp folder IF FNrmdir_r(TempDir$) ELSE PROCalert("Can't delete session temp folder " + TempDir$) REPEAT : UNTIL INKEY(1) == -1 QUIT ENDPROC DEF PROC_run LOCAL name$, dir$, a$, a$(), A%, F% REM if the program is unaltered, then run the program from its source file IF LEN Dirname$ IF NOT fileModified% PROCfile_run(Dirname$, Basename$) : ENDPROC REM ON ERROR LOCAL RESTORE ERROR : ENDPROC PROCeditLine_save REM save the program using the current filename to the temp folder name$ = Basename$ a$ = FN_lower(RIGHT$(name$, 4)) IF a$ <> ".bbc" THEN IF a$ == ".bas" RIGHT$(name$, 4) = ".bbc" ELSE name$ += ".bbc" ENDIF PROCfile_writeTokenised(TempDir$ + name$) REM create a program launcher IF LEN Dirname$ dir$ = Dirname$ ELSE dir$ = TempDir$ IF SDL% a$ = "SDL_SetWindowTitle" ELSE a$ = "SetWindowText" DIM a$(5) a$() = "*CD """ + dir$ + """", \ \ "$PTR(@dir$)=""" + dir$ + """", \ \ "!(^@dir$+4)=" + STR$ LEN dir$, \ \ "!(^@cmd$+4)=0", \ \ "SYS""" + a$ + """,@hwnd%,""" + name$ + """", \ \ "CHAIN""" + TempDir$ + name$ + """" name$ = "_" + name$ F% = OPENOUT(TempDir$ + name$) FOR A% = 0 TO DIM(a$(), 1) a$(A%) = FNtok(a$(A%)) BPUT#F%, LEN a$(A%) + 4 BPUT#F%, 0 BPUT#F%, 0 BPUT#F%, a$(A%); BPUT#F%, &D NEXT BPUT#F%, 0 BPUT#F%, &FF BPUT#F%, &FF CLOSE#F% REM run program launcher PROCfile_run(TempDir$, name$) ENDPROC DEF PROC_launchRTE ON ERROR LOCAL RESTORE ERROR : ENDPROC LOCAL F%, a$ a$ = RTE.version$ + ".bbc" F% = OPENOUT(TempDir$ + a$) BPUT#F%, 0 BPUT#F%, &FF BPUT#F%, &FF CLOSE#F% PROCfile_run(TempDir$, a$) ENDPROC DEF PROC_launchBBC LOCAL path$, name$, ext$, t$ ext$ = "bbc" path$ = Place.current$ IF FNchdir(path$) ELSE path$ = @usr$ REPEAT REPEAT UNTIL FNfileDlg_open(FILEDLG_LAUNCH, path$, name$, ext$) IF path$ == "" ENDPROC IF FNis_readable(path$ + name$) PROCfile_run(path$, name$) : ENDPROC t$ = "" PROCmsgline_title(t$, "Can't Launch Program!") PROCmsgline_add(t$, CHR$0 + """" + path$ + """", "C") IFFNmsgwin(t$, MSGWIN_STOP) UNTIL 0 ENDPROC DEF PROC_changeCase LOCAL A%, line$() REM save edit line PROCeditLine_save REM tokenise program DIM line$(lastLine%) FOR A% = 1 TO lastLine% line$(A%) = FNtok(Line$(A%)) NEXT REM change case IF Lowercase% THEN FOR A% = 1 TO 255 : K$(A%) = FN_upper(K$(A%)) : NEXT *LOWERCASE OFF ELSE FOR A% = 1 TO 255 : K$(A%) = FN_lower(K$(A%)) : NEXT *LOWERCASE ON ENDIF Lowercase% EOR= TRUE PROCoptions_save REM detokenise program FOR A% = 1 TO lastLine% IF LEN line$(A%) THEN $lineBuff%% = line$(A%) Line$(A%) = FNdetok(lineBuff%%) PROCline_setColour(A%) PROCline_setIndentEffect(A%) ENDIF NEXT PROClines_setIndentFrom(1) PROCeditLine_set(Edit.line%, Edit.carrot%) PROCundo_reset IF lastLine% == 1 IF Line$(1) == "" ELSE fileModified% = TRUE ENDPROC DEF PROC_syntaxColouring LOCAL L% SyntaxColour% EOR= TRUE PROCoptions_save IF SyntaxColour% THEN FOR L% = 1 TO lastLine% : $lineBuff%% = FNtok(Line$(L%)) : PROCline_setColour(L%) : NEXT PrintLine%% = ^PROCline_printColour() ELSE PrintLine%% = ^PROCline_printMono() ENDIF PROC_drawAll ENDPROC (_) DEF PROCexport_html_open PRIVATE dlg%% LOCAL lom%(), lo$(), lo%() LOCAL W%, E%, I%, J%, pn$, a$, t$ W% = @vdu%!216 : REM character width E% = 7 : REM number of dialogue items DIM lom%(11), lo$(E%, 4), lo%(E%, 3) lom%() = 0,0, 4,4,4,4, 8*W%,2*@vdu%!220, 8,8, 1,E% lo$() = "","","","","", \ \ "psb","","",STR$FNmin((Win.cw% - 2) * W%, 48 * W%),"", \ \ "peb","#","#below","#","", \ \ "mcb","#","#below","#","", \ \ "icb","#","#below","#","", \ \ "ccb","#","#below","#","", \ \ "ok","@right","#below","","", \ \ "cancel","#left","#","","" FORI%=1TOE%:FORJ%=0TO3:SWAPlo$(I%,J%),lo$(I%,J%+1):NEXT:NEXT PROCdlg_lo_resolve(lom%(), lo$(), lo%(), TRUE) IF dlg%% THEN REM init dialogue size dlg%%!8 = lom%(0) * 2 dlg%%!12 = lom%(1) * 2 FORI%=1TOE%:PROCdlg_setItemPos_(dlg%%,I%,lo%()):NEXT ELSE dlg%% = FNdlg_new(lom%(0), lom%(1), DLG_CENTRE, "Export HTML") PROCstaticbox_new_(dlg%%, 1, lo%(), 0, "Output Pathname:") PROCeditbox_new_(dlg%%, 2, lo%(), 0) PROCcheckbox_new_(dlg%%, 3, lo%(), 0, dlgCheckboxIcons%%, "Include Margin") PROCcheckbox_new_(dlg%%, 4, lo%(), 0, dlgCheckboxIcons%%, "Hard Indent") PROCcheckbox_new_(dlg%%, 5, lo%(), 0, dlgCheckboxIcons%%, "Standard Syntax Colours") PROCpushbutton_new_(dlg%%, 7, lo%(), 0, "Cancel") PROCpushbutton_new_(dlg%%, 6, lo%(), DLG_ITEM_DEFAULT, "OK") ENDIF REM init dialogue contents PROCsetPalette(PALETTE_DLG) PROCdlg_draw(dlg%%,0,0) IF Dirname$ = "" pn$ = @usr$ ELSE pn$ = Dirname$ pn$ += Basename$ + ".html" PROCdlg_setItemText(dlg%%, 2, pn$) PROCdlg_checkItem(dlg%%, 3, FALSE) PROCdlg_checkItem(dlg%%, 4, FALSE) PROCdlg_checkItem(dlg%%, 5, FALSE) PROCdlg_setFocus(dlg%%, 2) REPEAT I% = FNdlg_poll(dlg%%) CASE I% OF WHEN -1, 6 pn$ = FN_trim(FNdlg_getItemText(dlg%%, 2)) IF LEN pn$ THEN IF FN_lower(RIGHT$(pn$, 5)) <> ".html" pn$ += ".html" ELSE RIGHT$(pn$, 4) = "html" PROCdlg_setItemText(dlg%%, 2, pn$) IF FNchdir(pn$) == FALSE a$ = FNdirname(pn$, 1) IF LENa$ IF FNchdir(a$) THEN IF FNis_readable(pn$) THEN t$ = "" PROCmsgline_title(t$, "File Exists!") PROCmsgline_add(t$, CHR$0 + """" + pn$ + """", "C") PROCmsgline_add(t$, CHR$0 + "Overwrite?", "C") IF FNmsgwin(t$, MSGWIN_WARNING + MSGWIN_YESNO) == 2 EXIT REPEAT ENDIF PROCexport_html(pn$, \ \ FNdlg_isItemChecked(dlg%%, 3), \ \ FNdlg_isItemChecked(dlg%%, 4), \ \ FNdlg_isItemChecked(dlg%%, 5)) EXIT REPEAT ENDIF ENDIF PROCalert("Invalid pathname: " + pn$) : I% = 0 WHEN -2, 7 REM close / cancel WHEN -3 REM window resized PROC_move OTHERWISE I% = 0 ENDCASE UNTIL I% PROCdlg_close(dlg%%) PROCsetPalette(ColourScheme%) REM the callee must _drawAll ENDPROC DEF PROCexport_html(pn$, M%, H%, S%) LOCAL a$, F%, L%,I%,J%, C%,D%,c$(),c$ DIM c$(15) c$(PAL_DIR) = "dir" c$(PAL_DEF) = "def" c$(PAL_KEY) = "key" c$(PAL_STR) = "str" c$(PAL_REM) = "rem" c$(PAL_SUB) = "sub" c$(PAL_VAR) = "var" c$(PAL_AND) = "and" c$(PAL_NUM) = "num" : F% = OPENOUT(pn$) BPUT#F%, "" + Basename$ + "" : BPUT#F%, "
" + Dirname$ + Basename$ + "
Exported from " + Prog.name$ + " | " + TIME$ + "
" : BPUT#F%, "" FOR L% = 1 TO lastLine% BPUT#F%, ""; IF M% THEN BPUT#F%, ""; ENDIF IF LEN Line$(L%) IF lineIndent&(L%) IF NOT H% a$ = " style=""padding-left:" + STR$(lineIndent&(L%)/2) + "em;""" ELSE a$ = "" BPUT#F%, "" NEXT BPUT#F%, "
"; IF Margin.basic% THEN IF lineNumberL&(L%) OR lineNumberH&(L%) BPUT#F%, STR$(lineNumberL&(L%)+(lineNumberH&(L%)<<8)); ELSE BPUT#F%, STR$L%; ENDIF BPUT#F%, ""; IF H% IF lineIndent&(L%) BPUT#F%, STRING$(lineIndent&(L%), " "); C% = -1 c$ = lineColour$(L%) FOR I% = 1 TO LEN Line$(L%) D% = ASCMID$(c$, I% , 1) IF S% IF D% == PAL_KEY IF INSTR("()",MID$(Line$(L%),I%,1)) D% = PAL_VAR IF C% <> D% THEN IF S% IF D% == PAL_SUB THEN J% = 0 : a$ = MID$(Line$(L%), I%, 1) IF INSTR("Pp", a$) J% = 4 ELSE IF INSTR("Ff", a$) J% = 2 IF J% THEN BPUT#F%, "" + MID$(Line$(L%), I%, J%) + ""; I% += J% : J% = I% : D% = PAL_VAR WHILE J% < LEN Line$(L%) AND ASCMID$(c$, J% , 1) == PAL_SUB MID$(c$, J%, 1) = CHR$D% J% += 1 ENDWHILE IF I% > LEN Line$(L%) EXIT FOR ENDIF ENDIF C% = D% IF I% > 1 BPUT#F%, ""; BPUT#F%, ""; ENDIF BPUT#F%, MID$(Line$(L%), I%, 1); NEXT BPUT#F%, "
" : CLOSE#F% a$ = "" PROCmsgline_title(a$, "HTML Exported!") PROCmsgline_add(a$, CHR$0 + """" + pn$ + """", "C") PROCmsgline_add(a$, CHR$0 + "Open Directory?", "C") IF FNmsgwin(a$, MSGWIN_QUESTION + MSGWIN_YESNO) IFFNfileropen(FNdirname(pn$, 1)) ENDPROC (_) DEF PROChelp_quick LOCAL t$ : PROCmsgline_title(t$, "Keyboard Shortcuts") t$+=CHR$0 PROCmsgline_add(t$, "f1 : Quick Help!", "") PROCmsgline_add(t$, "f3 : Find next", "") PROCmsgline_add(t$, "f4 : Function List", "") PROCmsgline_add(t$, "f9, Ctrl-U : Run Program", "") PROCmsgline_add(t$, "Ctrl+G : Go to line number", "") PROCmsgline_add(t$, "Ctrl+B : Go back (after line number or function list jump)", "") PROCmsgline_add(t$, "Ctrl+W : Toggle Menu Bar", "") PROCmsgline_add(t$, "Ctrl+T : Toggle Toolbar", "") PROCmsgline_add(t$, "Ctrl+I, Tab : Invert commenting (REMs) for selected lines", "") PROCmsgline_add(t$, "Ctrl+D : Duplicate current line", "") PROCmsgline_add(t$, "Ctrl+F : Open find dialogue", "") PROCmsgline_add(t$, "Ctrl+R : Replace next", "") PROCmsgline_add(t$, "Ctrl+Left-Arrow : Move cursor to end of previous word / Move selected charcter left", "") PROCmsgline_add(t$, "Ctrl+Right-Arrow : Move cursor to end of word / Move selected character right", "") PROCmsgline_add(t$, "Ctrl+Page Up : Increment selected character (comments and string literals)", "") PROCmsgline_add(t$, "Ctrl+Page Down : Decrement selected character (comments and string literals)", "") PROCmsgline_add(t$, "Shift+Return : Insert blank line above", "") PROCmsgline_add(t$, "Ctrl+Return : Insert blank line below", "") : PROCmsgline_title(t$, "Toolbar") PROCmsgline_add(t$, CHR$0\ \+"Scroll the toolbar by dragging, or using mouse scroll-wheel while the mouse pointer is over buttons.", "") : PROCmsgline_title(t$, "Find and Replace") PROCmsgline_add(t$, CHR$0\ \+"Use the 'Find' dialogue to enter the 'Find' and 'Replace with' strings. "\ \+"The process of actually searching (and replacing) is not controlled from the dialogue. "\ \+"Instead use the keyboard shortcuts or the buttons on the toolbar.", "") : PROCmsgline_title(t$, "Context Menu") PROCmsgline_add(t$, CHR$0\ \+"Right-Click on the text area to open a context menu. When no lines/text are selected the "\ \+"'Function List Menu' is opened by default. "\ \+"When lines/text are selected the 'Editor Context Menu' is opened by default. "\ \+"Press Shift + Right-Click to open 'Editor Context Menu' instead of 'Function List Menu'. "\ \+"Press Alt Gr + Right-Click to open the 'Character Menu'. "\ \+"For keyboard control use Esc key instead or Right-Click.", "") : PROCmsgline_title(t$, "Function List") PROCmsgline_add(t$, CHR$0\ \+"If there are no functions, the list will not open. "\ \+"If there are more functions than can be listed in a context menu (determined by the window height), "\ \+"then the list will open into a dialogue with a toolbar. "\ \+"Note that when the list is sorted alphabetically, empty (spacer) labels are automatically removed "\ \+"and the inclusion of ON statements is disabled for clarity.", "") : PROCmsgline_title(t$, "Margin") PROCmsgline_add(t$, CHR$0\ \+"The margin is on the LHS of the text area. "\ \+"Left-click the margin to select a single program line, "\ \+"then right-click the margin elsewhere in the program to select a block of lines. "\ \+"The margin can be set to show 'line index numbers' or 'BASIC line numbers'. "\ \+"When a program is loaded, the margin is set to show one or the other depending upon the "\ \+"presence of 'BASIC line numbers' in the loaded program.", "") : PROCmsgline_title(t$, "Program Reset") PROCmsgline_add(t$, CHR$0\ \+"Starting the program with the SHIFT key pressed will reset the window to its default size. "\ \+"To reset the program options to their defaults, delete the _options.ini file in the user folder.", "") : PROCmsgline_title(t$, "Encoding") PROCmsgline_add(t$, CHR$0\ \+"UTF-8 is currently not supported. Programs with UTF-8 encoded characters within strings and comments can still be loaded, "\ \+"but each octet will be shown as a separate character. This is the same as ANSI mode in other editors such as SDLIDE. "\ \+"If you select a single character, information about the character is shown in the status bar. "\ \+"If the selected character is the first character of a potential UTF-8 encoding (when taken together with the "\ \+"characters that follow it), then the number of octets for the UTF-8 character is displayed.", "") : IFFNmsgwin(t$, MSGWIN_INFO) ENDPROC DEF PROChelp_manual PROCopenurl("http://www.bbcbasic.co.uk/bbcwin/manual/index.html") ENDPROC DEF PROChelp_basicWiki PROCopenurl("http://www.bbcbasic.co.uk/wiki/") ENDPROC DEF PROChelp_sdlWiki PROCopenurl("http://wiki.libsdl.org/FrontPage/") ENDPROC DEF PROChelp_ascii LOCAL t$, A%, a$, b$ LOCAL DATA RESTORE+1 DATA "^@ NUL" DATA "^A SOH Start of Heading" DATA "^B STX Start of Text" DATA "^C ETX End of Text" DATA "^D EOT End of Transmit" DATA "^E ENQ Enquiry" DATA "^F ACK Acknowledge" DATA "^G BEL Bell - Audible Signal" DATA "^H BS Back Space" DATA "^I HT Horizontal Tab" DATA "^J LF Line Feed" DATA "^K VT Vertical Tab" DATA "^L FF Form Feed" DATA "^M CR Carriage Return" DATA "^N SO Shift Out" DATA "^O SI Shift In" DATA "^P DLE Data Link Escape" DATA "^Q DC1 X On" DATA "^R DC2 Aux On" DATA "^S DC3 X Off" DATA "^T DC4 Aux Off" DATA "^U NAK Negative Acknowledge" DATA "^V SYN Synchronous Idle" DATA "^W ETB End of Transmitted Block" DATA "^X CAN Cancel" DATA "^Y EM End of Medium" DATA "^Z SUB Substitute" DATA "^[ ESC Escape" DATA "^\ FS File Separator" DATA "^] GS Group Separator" DATA "^^ RS Record Separator" DATA "^_ US Unit Separator" PROCmsgline_title(t$, "Table of ASCII Codes") t$ += CHR$0 FOR A% = 0 TO 31 READ a$ PROCmsgline_add(t$, \ \ RIGHT$("0000000"+FN_binary(A%),8) + \ \ " &" + RIGHT$("0"+STR$~A%,2) + \ \ RIGHT$(" "+STR$A%,4) + \ \ " " + a$ + STRING$(31-LENa$," "), "C") NEXT PROCmsgline_add(t$, CHR$0 + \ \ RIGHT$("0000000"+FN_binary(32),8) + \ \ " &" + RIGHT$("0"+STR$~32,2) + \ \ " 32" + \ \ " Space" + STRING$(26," "), "C") FOR A% = 33 TO 63 PROCmsgline_add(t$, \ \ RIGHT$("0000000"+FN_binary(A%),8) + \ \ " &" + RIGHT$("0"+STR$~A%,2) + \ \ RIGHT$(" "+STR$A%,4) + \ \ " " + CHR$A% + STRING$(30," "), "C") NEXT t$ += CHR$0 FOR A% = 64 TO 95 PROCmsgline_add(t$, \ \ RIGHT$("0000000"+FN_binary(A%),8) + \ \ " &" + RIGHT$("0"+STR$~A%,2) + \ \ RIGHT$(" "+STR$A%,4) + \ \ " " + CHR$A% + STRING$(30," "), "C") NEXT t$ += CHR$0 FOR A% = 96 TO 126 PROCmsgline_add(t$, \ \ RIGHT$("0000000"+FN_binary(A%),8) + \ \ " &" + RIGHT$("0"+STR$~A%,2) + \ \ RIGHT$(" "+STR$A%,4) + \ \ " " + CHR$A% + STRING$(30," "), "C") NEXT PROCmsgline_add(t$, \ \ RIGHT$("0000000"+FN_binary(127),8) + \ \ " &" + RIGHT$("0"+STR$~127,2) + \ \ " 127" + \ \ " DEL Delete" + STRING$(21," "), "C") IFFNmsgwin(t$, MSGWIN_INFO) ENDPROC DEF PROChelp_debug LOCAL A%, p%%, S%, a$, t$ DIM p%% LOCAL -1 : S% = HIMEM - p%% : REM stack size : PROCmsgline_add(t$, "Platform:", "C") a$ = "BBC BASIC for " IF SDL% a$ += "SDL 2.0" ELSE a$ += "Windows" a$ += " - Version " + RIGHT$(RTE.version$, LEN RTE.version$ - FN_instrr(RTE.version$, " ",0)) PROCmsgline_add(t$, a$, "C") IF SDL% THEN CASE SDL% AND &F OF WHEN 0 : a$ = "Windows" WHEN 1 : a$ = "Linux" WHEN 2 : a$ = "MacOS" WHEN 3 : a$ = "Android" WHEN 4 : a$ = "iOS" WHEN 5 : a$ = "In-Browser" ENDCASE a$ += " Edition (" + FNcpuarc + " " IF SDL% AND 64 a$ += "64" ELSE a$ += "32" PROCmsgline_add(t$, a$ + "-bit)", "C") PROCmsgline_add(t$, "Using SDL Library " + \ \ STR$((SDL%>>24)AND&FF) + "." + STR$((SDL%>>16)AND&FF) + "." + STR$((SDL%>>8)AND&FF), "C") ENDIF : PROCmsgline_add(t$, CHR$0 + "@dir$:", "C") PROCmsgline_add(t$, @dir$, "C") : PROCmsgline_add(t$, CHR$0 + "@tmp$:", "C") PROCmsgline_add(t$, @tmp$, "C") : PROCmsgline_add(t$, CHR$0 + "@usr$:", "C") PROCmsgline_add(t$, @usr$, "C") : PROCmsgline_add(t$, CHR$0 + "@lib$:", "C") PROCmsgline_add(t$, @lib$, "C") : PROCmsgline_add(t$, CHR$0 + Prog.name$ + " Temp Dir:", "C") PROCmsgline_add(t$, TempDir$, "C") : PROCmsgline_add(t$, CHR$0 + Prog.name$ + " Resources Dir:", "C") PROCmsgline_add(t$, ResDir$, "C") : PROCmsgline_add(t$, CHR$0 + "Current Directory:", "C") PROCmsgline_add(t$, FNcurrentdir, "C") : PROCmsgline_add(t$, CHR$0 + "Current Place:", "C") PROCmsgline_add(t$, Place.current$, "C") : PROCmsgline_add(t$, CHR$0 + "@size.x%: @size.y%: @char.x%: @char.y%:", "C") PROCmsgline_add(t$, \ \ LEFT$(STR$@vdu%!208+STRING$(10," "),10) + \ \ LEFT$(STR$@vdu%!212+STRING$(10," "),10) + \ \ LEFT$(STR$@vdu%!216+STRING$(10," "),10) + \ \ LEFT$(STR$@vdu%!220+STRING$(9," "),9), "C") : PROCmsgline_add(t$, CHR$0 + "Stack Size: Heap Size: Free Space:", "C") PROCmsgline_add(t$, \ \ LEFT$(STR$S%+STRING$(13," "),13) + \ \ LEFT$(STR$(END-LOMEM)+STRING$(12," "),12) + \ \ LEFT$(STR$(HIMEM-END-S%)+STRING$(11," "),11), "C") : IFFNmsgwin(t$, MSGWIN_INFO) ENDPROC DEF PROChelp_about LOCAL t$ : PROCmsgline_title(t$, Prog.name$ + " " + Prog.version$) PROCmsgline_add(t$, CHR$0\ \+"A simple BBC BASIC program editor written in BBC BASIC "\ \+"for the purpose of providing a cross-platform editor "\ \+"suitable for use with BBC BASIC for SDL 2.0 and BBC BASIC for Windows", "") : PROCmsgline_add(t$, CHR$0\ \+"This program is free software. You can redistribute it and/or modify it under the terms of the 'zlib' licence. "\ \+"This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, "\ \+"without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.", "") : PROCmsgline_add(t$, CHR$0 + "Editor by Andy Parkes", "C") PROCmsgline_add(t$, "dredandy@yahoo.co.uk", "C") : PROCmsgline_add(t$, CHR$0 + "Including ideas from:", "C") PROCmsgline_add(t$, "Richard Russell", "C") PROCmsgline_add(t$, "J.G. Harston", "C") : PROCmsgline_add(t$, CHR$0 + "With special thanks to Richard Russell for creating and supporting", "Cblue") PROCmsgline_add(t$, "BBC BASIC for Windows and BBC BASIC for SDL 2.0", "Cblue") : IFFNmsgwin(t$, MSGWIN_ABOUT) ENDPROC (_) REM Cuts (deletes) selected lines or a selected edit line string. REM Sets Edit.line%, Edit.text$, Edit.carrot%, Start%, topLine%, botLine%, longestLineLen% accordingly. REM Does not redraw anything! REM Most of the time you will need to preceed PROC_cut with a call to PROC_copy DEF PROC_delete IF lineSelect.anc% THEN REM delete lines LOCAL A%, B% A% = lineSelect.anc% B% = lineSelect.ext% REM make sure A% holds the lower of the two values IF A% > B% SWAP A%, B% PROCundo_save(A%) REM delete lineSelect.size% lines beginning from line A% PROClines_deleteFrom(A%, lineSelect.size%) REM logically clear the line selection PROClineSelect_clear IF lastLine% == 0 THEN REM if all lines were deleted then lastLine% will point to 0, so reset lastLine% to point to line 1 E.g: REM REM 1 A% REM 2 ... REM 3 ... REM 4 B% --> lastLine% REM REM lineSelect.size% = 4 REM REM lastLine% - lineSelect.size% = 0 lastLine% = 1 : Line$(1) = "" : lineIndent&(1) = 0 : lineIndentSelf&(1) = 0 : lineIndentNext%(1) = 0 ELSE REM A% will now point to the line after lastLine%, REM if the deleted block of lines was at the end of the program, REM A% will not be pointing to a valid line E.g: REM REM 1 REM 2 REM 3 A% REM 4 B% -- > lastLine% REM REM lineSelect.size% = 2 REM REM lastLine% - lineSelect.size% = 2 REM REM make sure A% is pointing to a valid line, REM if it already is then make sure the line indents for all lines from A% onwards are correct IF A% > lastLine% A% = lastLine% ELSE PROClines_setIndentFrom(A%) ENDIF REM set edit line PROCeditLine_set(A%, 0) REM adjust text area top and bottom to ensure edit line is inside text area IF A% >= topLine% IF A% <= botLine% ELSE topLine% = A% : botLine% = A% + Body.ch% - 1 REM update longest program line PROClines_setLongestLen fileModified% = TRUE ELSE IF stringSelect.index% THEN REM delete string REM REM textArea.cl% textArea.cr% REM | | REM Edit.carrot% : 0 1 2 3 4 5 6 7 8 9 10 REM edit line characters : 1 2|3 4 5 6 7 8|9 10 REM | | REM Start% == 3 REM stringSelect.text$ : 2 3 4 5 6 7 REM stringSelect.index% == 2 PROCundo_save(0) Edit.text$ = LEFT$(Edit.text$, stringSelect.index% - 1) + MID$(Edit.text$, stringSelect.index% + LEN stringSelect.text$) Edit.modified% = TRUE Edit.carrot% = stringSelect.index% - 1 IF Edit.carrot% < Start% - 1 Start% = Edit.carrot% + 1 PROCstringSelect_clear fileModified% = TRUE ENDIF ENDIF ENDPROC REM Combines copy and delete to perform a cut DEF PROC_cut : PROC_copy : PROC_delete : ENDPROC REM Copies selected lines or a selected edit line string to clipboard DEF PROC_copy LOCAL a$, A%, B%, I%, N%, S% S% = INKEY(-1) IF lineSelect.anc% THEN A% = lineSelect.anc% B% = lineSelect.ext% IF A% > B% SWAP A%, B% a$ = "" FOR I% = A% TO B% N% = lineNumberL&(I%) + lineNumberH&(I%) * 256 IF N% a$ += STR$ N% IF S% a$ += Line$(I%) ELSE a$ += FN_ansi_to_utf8(Line$(I%)) a$ += CHR$&D + CHR$&A NEXT ELSE IF stringSelect.index% THEN IF S% a$ = stringSelect.text$ ELSE a$ = FN_ansi_to_utf8(stringSelect.text$) ENDIF ENDIF IF LENa$ PROCclipboard_putText(a$) ENDPROC REM Pastes text from the clipboard REM Sets Edit.line%, Edit.text$, Edit.carrot%, Start%, topLine%, botLine%, longestLineLen% accordingly. REM Does not redraw anything! DEF PROC_pasteUTF8 : LOCAL U% : U% = TRUE DEF PROC_paste : LOCAL U% : U% = INKEY(-1) IF FNclipboard_hasText == 0 ENDPROC LOCAL I%, S%, copy$, eol$ copy$ = FNclipboard_getText IF INSTR(copy$, CHR$&D + CHR$&A) eol$ = CHR$&D + CHR$&A : REM windows IF LEN eol$ ELSE IF INSTR(copy$, CHR$&A) eol$ = CHR$&A : REM unix/mac IF LEN eol$ ELSE IF INSTR(copy$, CHR$&D) eol$ = CHR$&D : REM old mac IF LEN eol$ THEN IF eol$ <> CHR$&D I% = FN_findreplace(copy$, eol$, CHR$&D, 0) IF RIGHT$(copy$) <> CHR$&D copy$ += CHR$&D ENDIF REM count the number of cr-terminated lines in copy$ I% = INSTR(copy$, CHR$&D) : WHILE I% S% += 1 : I% = INSTR(copy$, CHR$&D, I% + 1) : ENDWHILE REM make sure there is room to add S% lines to the program IF S% IF lastLine% - lineSelect.size% + S% > MAX_PROG_SIZE PROC_noRoom : ENDPROC REM cut without copying (I.e. delete) any lines or string that might be selected I% = Undo.ptr% : REM we need to know if cut has saved a restore point PROC_delete IF S% THEN REM paste lines LOCAL A%, J%, M%, N%, a$ REM A% points to Edit.line% A% = Edit.line% REM save a restore point if cut has not already done so IF Undo.ptr% == I% PROCundo_save(A%) REM add RHS of Edit.text$ to the list of lines to be pasted copy$ += MID$(Edit.text$, Edit.carrot% + 1) + CHR$ &D REM Line$(Edit.line%) is rebuilt using the LHS of Edit.text$ and the first line in copy$ I% = INSTR(copy$, CHR$ &D) a$ = LEFT$(copy$, I% - 1) REM if the first line in copy$ is joining a line that is not empty, REM then make sure the the first line in copy$ does not begin with a line number IF FN_trim(LEFT$(Edit.text$, Edit.carrot%)) <> "" WHILE ASC a$ >= &30 AND ASC a$ <= &39 a$ = MID$(a$, 2) : ENDWHILE Line$(A%) = FNtnt(LEFT$(Edit.text$, Edit.carrot%) + a$, M%, N%) IF M% lineNumberL&(A%) = N% MOD 256 : lineNumberH&(A%) = N% DIV 256 PROCline_setColour(A%) PROCline_setIndentEffect(A%) REM A% points to line after Edit.line% A% += 1 REM insert space for new lines IF A% <= lastLine% THEN PROClines_insertBefore(A%, S%) ELSE lastLine% += S% ENDIF REM populate the new lines using the rest of the lines in copy$ I% += 1 J% = INSTR(copy$, CHR$ &D, I%) WHILE J% Line$(A%) = FNtnt(MID$(copy$, I%, J% - I%), M%, N%) IF NOT U% Line$(A%) = FN_utf8_to_ansi(Line$(A%)) lineNumberL&(A%) = N% MOD 256 : lineNumberH&(A%) = N% DIV 256 PROCline_setColour(A%) PROCline_setIndentEffect(A%) A% += 1 I% = J% + 1 J% = INSTR(copy$, CHR$ &D, I%) ENDWHILE REM update line indents from Edit.line% PROClines_setIndentFrom(Edit.line%) REM the new edit line will be the last line that was added A% -= 1 REM set edit line PROCeditLine_set(A%, 0) REM adjust text area top and bottom to ensure edit line is inside text area IF A% < topLine% OR A% > botLine% THEN I% = A% - Body.ch% / 2 IF I% < 1 I% = 1 botLine% = I% + Body.ch% - 1 WHILE botLine% > lastLine% AND A% < botLine% AND I% > 1 : I% -= 1 : botLine% = I% + Body.ch% - 1 : ENDWHILE topLine% = I% ENDIF REM update longest program line PROClines_setLongestLen ELSE REM paste string LOCAL p%%, P%, A% IF NOT U% copy$ = FN_utf8_to_ansi(copy$) p%% = PTR(copy$) A% = FALSE FOR P% = 0 TO LEN copy$ - 1 IF p%%?P% < 32 p%%?P% += 64 IF p%%?P% == 127 p%%?P% = 32 IF p%%?P% > 127 A% = TRUE NEXT IF A% IF NOT FNinQuotes(Edit.text$ + " ", Edit.carrot% + 1) IF NOT FNinComment(Edit.text$ + " ", Edit.carrot% + 1) ENDPROC REM save restore point if cut has not already done so IF Undo.ptr% == I% PROCundo_save(0) Edit.text$ = LEFT$(Edit.text$, Edit.carrot%) + copy$ + MID$(Edit.text$, Edit.carrot% + 1) Edit.carrot% += LEN copy$ Edit.modified% = TRUE REM formula to determine if Edit.carrot% is too far to the right: IF Edit.carrot% > Start% + textArea.cw% - 2 Start% = Edit.carrot% - textArea.cw% + 2 ENDIF fileModified% = TRUE ENDPROC (_) DEF PROCchrMenu_open IF lineSelect.size% ENDPROC LOCAL K% K% = FNchrMenu_context_open IF K% THEN IF stringSelect.index% THEN *REFRESH OFF PROC_delete ENDIF IF NOT FNinQuotes(Edit.text$ + " ", Edit.carrot% + 1) IF NOT FNinComment(Edit.text$ + " ", Edit.carrot% + 1) ENDPROC PROCeditLine_insertChr ENDIF ENDPROC DEF FNchrMenu_context_open LOCAL m{}, N%, X%, Y%, I% Win.resized% = FALSE N% = 128 DIM m{ \ \ l%,b%,r%,t%,w%,h%,cl%,cb%,cr%,ct%,bg&,hbg&,hfg&,\ \ items%,rows%,first%,last%,selected%,longestLHS%,longestRHS%, \ \ tx%,tyOffset%,hx%,hw%,textWidth%,rowChrHeight%,rh%,sbg&,sfg&,ofg&,over%%, \ \ item$(N%),lhs$(N%),rhs$(N%),flag&(N%),fg&(N%),ico%%(N%),button&(N%),button&} Y% = 0 FOR I% = 1 TO N% X% = 256 - I% IF WIDTH(CHR$X%) THEN Y% += 1 m.item$(Y%) = CHR$X% + " (Dec: " + STR$X% + " Hex: " + STR$~X% + " Bin: " + \ \ STR$SGN(X%AND128)+STR$SGN(X%AND64)+STR$SGN(X%AND32)+STR$SGN(X%AND16) + \ \ STR$SGN(X%AND8)+STR$SGN(X%AND4)+STR$SGN(X%AND2)+STR$SGN(X%AND1) + ")" ENDIF NEXT m.items% = Y% m.bg& = PAL_MARGIN m.hbg& = PAL_STR m.longestLHS% = LENm.item$(1) m.rowChrHeight% = 1 m.rh% = m.rowChrHeight% * chrHeight% m.tyOffset% = (m.rh% + chrHeight%) / 2 m.bg& = PAL_BORDER m.hfg& = PAL_VAR m.hbg& = PAL_STR m.sbg& = PAL_MARGIN m.sfg& = PAL_BORDER m.ofg& = PAL_REM MOUSE X%, Y%, I% X% /= chrWidth% Y% = (Win.h% - Y%) / chrHeight% X% -= 1 IF X% < 0 X% = 0 Y% -= 1 IF Y% < 0 Y% = 0 WHILE X% > 0 AND Win.cw% - X% < m.longestLHS% + 6 X% -= 1 ENDWHILE WHILE Y% > 0 AND (Win.ch% - Y%) < N% + 2 Y% -= 1 ENDWHILE IF FNmenu_open(m{}, X%, Y%, 0, 0, m.rowChrHeight%) I% = FNcontxMenu_poll(m{}) : IF I% :=ASCm.item$(I%) =0 DEF PROCchrMenu_grid_open PROCeditLine_save LOCAL tb{}, grid{}, cell{}, font{}, focus{} LOCAL X%, Y%, I% DIM focus{l%, b%, r%, t%, a%} DIM font{face%, size%} DIM tb{b%, ys%} DIM cell{w%, h%, xo%, yo%, xs%, ys%} DIM grid{l%, b%, r%, t%, w%, h%, xs%, ys%, rows%, cols%, start%, end%} font.face% = FontFace% font.size% = FontSize% tb.ys% = 64 grid.rows% = 8 grid.cols% = 12 grid.start% = 160 : grid.end% = 255 REM grid.start% = 64 : grid.end% = 159 REPEAT pRedraw%% = 0 Win.resized% = FALSE cell.xs% = @size.x% / grid.cols% cell.ys% = (@size.y% - tb.ys%) / grid.rows% cell.w% = cell.xs% * 2 cell.h% = cell.ys% * 2 grid.xs% = cell.xs% * grid.cols% grid.ys% = cell.ys% * grid.rows% grid.w% = grid.xs% * 2 grid.h% = grid.ys% * 2 grid.l% = @size.x% - grid.xs% grid.b% = (@size.y% - tb.ys%) - grid.ys% grid.r% = grid.l% + grid.w% - 2 grid.t% = grid.b% + grid.h% - 2 *REFRESH OFF OFF PROC_setFont(2, 3) WHILE FontSize% > 0 AND WIDTH("@") >= FNmin(cell.xs%, cell.ys%) FontSize% -= 1 PROC_setFont(2, FontSize%) ENDWHILE COLOR 128 + PAL_BACKGROUND CLS VDU 5 MOUSE X%, Y%, I% PROCchrMenu_grid_getFocus(grid{}, cell{}, focus{}, X%,Y%) PROCchrMenu_grid_draw(grid{}, cell{}, focus{}) *REFRESH ON REPEAT I% = FNchrMenu_poll(grid{}, cell{}, focus{}) UNTIL I% OR Win.resized% UNTIL NOT Win.resized% PROC_setFont(font.face%, font.size%) VDU 4 ENDPROC DEF FNchrMenu_grid_poll(grid{}, cell{}, focus{}) LOCAL K%, X%, Y%, I%, A%, B%, click% ON MOUSE LOCAL click% = FNchrMenu_grid_click(@wparam%, @lparam%) : RETURN REPEAT REPEAT IF click% :=0 K% = INKEY(1) MOUSE X%, Y%, I% IF A% == X% IF B% == Y% THEN ELSE A% = X% : B% = Y% IF focus.a% IF X% > focus.l% IF X% < focus.r% IF Y% > focus.b% IF Y% < focus.t% THEN ELSE PROCchrMenu_grid_getFocus(grid{}, cell{}, focus{}, X%,Y%) PROCchrMenu_grid_draw(grid{}, cell{}, focus{}) *REFRESH ON ENDIF ENDIF UNTIL K% <> -1 OR Win.resized% == TRUE CASE K% OF WHEN 13 :=focus.a% WHEN 136 REM cursor left focus.a% -= 1 IF focus.a% < grid.start% focus.a% = grid.end% PROCchrMenu_grid_draw(grid{}, cell{}, focus{}) *REFRESH ON WHEN 137 REM cursor right focus.a% += 1 IF focus.a% > grid.end% focus.a% = grid.start% PROCchrMenu_grid_draw(grid{}, cell{}, focus{}) *REFRESH ON WHEN 138 REM cursor down IF focus.a% THEN focus.a% += grid.cols% IF focus.a% > grid.end% focus.a% = focus.a% - grid.end% + grid.start% - 1 ELSE focus.a% = grid.start% ENDIF PROCchrMenu_grid_draw(grid{}, cell{}, focus{}) *REFRESH ON WHEN 139 REM cursor up IF focus.a% THEN focus.a% -= grid.cols% IF focus.a% < grid.start% focus.a% = focus.a% + grid.end% - grid.start% + 1 ELSE focus.a% = grid.end% ENDIF PROCchrMenu_grid_draw(grid{}, cell{}, focus{}) *REFRESH ON ENDCASE UNTIL Win.resized% =0 DEF FNchrMenu_grid_click(X%, Y%) =0 DEF PROCchrMenu_grid_draw(grid{}, cell{}, focus{}) *REFRESH OFF LOCAL R%,C%, L%,B%, A%,W% GCOL PAL_BACKGROUND IF SDL% THEN RECTANGLE FILL grid.l%, grid.b%, grid.w%-2, grid.h%-2 ELSE RECTANGLE FILL grid.l%, grid.b%-2, grid.w%, grid.h% ENDIF A% = grid.start% - 1 FOR R% = 1 TO grid.rows% FOR C% = 0 TO grid.cols% - 1 A% += 1 L% = grid.l% + cell.w% * C% B% = grid.t% - cell.h% * R% GCOL PAL_HIGHLIGHT IF A% == focus.a% THEN IF SDL% THEN RECTANGLE FILL L%, B%, cell.w%-2, cell.h% ELSE RECTANGLE FILL L%, B%-2, cell.w%, cell.h% ENDIF GCOL PAL_BACKGROUND ELSE RECTANGLE L%, B%, cell.w%, cell.h% ENDIF W% = WIDTH(CHR$A%) MOVE L% + cell.xs% - W%/2, B% + cell.ys% + W% PRINT CHR$A%; NEXT NEXT ENDPROC DEF PROCchrMenu_grid_getFocus(grid{}, cell{}, focus{}, X%,Y%) LOCAL R%,C%, L%,B%, A% A% = grid.start% - 1 FOR R% = 1 TO grid.rows% FOR C% = 0 TO grid.cols% - 1 A% += 1 L% = grid.l% + cell.w% * C% B% = grid.t% - cell.h% * R% IF X% > L% IF X% < L% + cell.w% IF Y% > B% IF Y% < B% + cell.h% THEN focus.l% = L% focus.b% = B% focus.r% = L% + cell.w% - 2 focus.t% = B% + cell.h% - 2 focus.a% = A% ENDPROC ENDIF NEXT NEXT ENDPROC (_) DEF PROCrecent_updateList LOCAL I% REM check for current file in recent list IF Recent.total% THEN FOR I% = 1 TO Recent.total% IF Recent$(I%) == Dirname$ + Basename$ THEN REM float to top of list WHILE I% > 1 SWAP Recent$(I%), Recent$(I% - 1) : I% -= 1 : ENDWHILE PROCrecent_updateMenu PROCoptions_save ENDPROC ENDIF NEXT ENDIF REM current file not in recent list I% = RECENT_MAX Recent$(I%) = Dirname$ + Basename$ REM float to top of list WHILE I% > 1 SWAP Recent$(I%), Recent$(I% - 1) : I% -= 1 : ENDWHILE IF Recent.total% < RECENT_MAX Recent.total% += 1 PROCrecent_updateMenu PROCoptions_save ENDPROC DEF PROCrecent_updateMenu LOCAL I% FOR I% = 1 TO RECENT_MAX IF I% > Recent.total% THEN recentMenu.item$(I%) = "..." recentMenu.flag&(I%) = MENU_ITEM_OFF recentMenu.info$(I%) = "" ELSE IF Recent.showPathname% recentMenu.item$(I%) = Recent$(I%) ELSE recentMenu.item$(I%) = FNbasename(Recent$(I%)) recentMenu.flag&(I%) = 0 recentMenu.info$(I%) = "Left click to load | Right click to run" ENDIF NEXT PROCmenu_setLongestText(recentMenu{}, FALSE) ENDPROC DEF PROCrecent_loadProgram(I%) IF I% > Recent.total% ENDPROC IF NOT FNis_readable(Recent$(I%)) PROCrecent_fileNotFound(I%) : ENDPROC IF NOT FN_unsavedWorkOK ENDPROC PROCfile_load(Recent$(I%)) ENDPROC DEF PROCrecent_runProgram(I%) IF I% > Recent.total% ENDPROC IF NOT FNis_readable(Recent$(I%)) PROCrecent_fileNotFound(I%) : ENDPROC PROCfile_run(FNdirname(Recent$(I%), 1), FNbasename(Recent$(I%))) ENDPROC DEF PROCrecent_fileNotFound(I%) LOCAL t$ PROCmsgline_title(t$, "File Not Found!") PROCmsgline_add(t$, CHR$0 + """" + Recent$(I%) + """", "C") IFFNmsgwin(t$, MSGWIN_STOP) PROCrecent_removeProgram(I%) ENDPROC DEF PROCrecent_removeProgram(I%) IF I% > Recent.total% ENDPROC Recent$(I%) = "" WHILE I% < Recent.total% SWAP Recent$(I%), Recent$(I% + 1) : I% += 1 : ENDWHILE Recent.total% -= 1 PROCrecent_updateMenu PROCoptions_save ENDPROC DEF PROCrecent_toggleShowPathname Recent.showPathname% EOR= TRUE PROCmbm_setFlags_recentMenu PROCrecent_updateMenu PROCoptions_save ENDPROC DEF PROCrecent_clearAll Recent.total% = 0 Recent$() = "" PROCrecent_updateMenu PROCoptions_save ENDPROC DEF PROCrecent_clearMissing LOCAL I%, J%, T% T% = Recent.total% WHILE I% < Recent.total% I% += 1 J% = OPENIN(Recent$(I%)) IF J% THEN CLOSE#J% ELSE Recent$(I%) = "" J% = I% WHILE J% < Recent.total% SWAP Recent$(J%), Recent$(J% + 1) : J% += 1 : ENDWHILE Recent.total% -= 1 I% -= 1 ENDIF ENDWHILE IF Recent.total% < T% PROCrecent_updateMenu : PROCoptions_save ENDPROC (_) DEF PROCplace_updateMenu LOCAL I%, B%, M% B% = FILEDLG_BUTTON_PLACE1 - 1 M% = FILE_MENU_PLACE1 - 1 FOR I% = 1 TO PLACE_MAX B% += 1 : M% += 1 IF I% > Place.total% THEN fileMenu.lhs$(M%) = "..." fileMenu.info$(M%) = "Add place..." Fdb{(B%)}.a$ = "" ELSE fileMenu.lhs$(M%) = Place$(I%) fileMenu.info$(M%) = "Left click to open 'Load' | Right click to open 'Save As'" Fdb{(B%)}.a$ = Place$(I%) ENDIF NEXT PROCmenu_setLongestText(fileMenu{}, TRUE) ENDPROC DEF PROCplace_open(F%, I%) IF F% <= Place.total% THEN IF I% PROC_saveAs(Place$(F%)) ELSE PROC_load(Place$(F%)) ENDPROC ENDIF : DEF PROCplace_edit : LOCAL F%, I% : F% = Place.total% + 1 : IF F% > PLACE_MAX F% = 1 PRIVATE dlg%% LOCAL lom%(), lo$(), lo%() LOCAL W%, E%, J%, a$ W% = @vdu%!216 : REM character width E% = PLACE_MAX + 1 : REM number of dialogue items DIM lom%(11), lo$(E%, 4), lo%(E%, 3) lom%() = 0,0, 4,4,4,4, 8*W%,2*@vdu%!220, 8,8, 1,E% lo$() = "","","","","", \ \ "p1","","",STR$FNmin((Win.cw% - 2) * W%, 32 * W%),"", \ \ "p2","#","#below","#","", \ \ "p3","#","#below","#","", \ \ "p4","#","#below","#","", \ \ "p5","#","#below","#","", \ \ "p6","#","#below","#","", \ \ "p7","#","#below","#","", \ \ "p8","#","#below","#","", \ \ "p9","#","#below","#","", \ \ "OK","@centre","#below","","" FORI%=1TOE%:FORJ%=0TO3:SWAPlo$(I%,J%),lo$(I%,J%+1):NEXT:NEXT PROCdlg_lo_resolve(lom%(), lo$(), lo%(), TRUE) IF dlg%% THEN REM init dialogue size dlg%%!8 = lom%(0) * 2 dlg%%!12 = lom%(1) * 2 FORI%=1TOE%:PROCdlg_setItemPos_(dlg%%,I%,lo%()):NEXT ELSE dlg%% = FNdlg_new(lom%(0), lom%(1), DLG_CENTRE, "Edit Places") FOR I% = 1 TO PLACE_MAX PROCeditbox_new_(dlg%%, I%, lo%(), 0) NEXT PROCpushbutton_new_(dlg%%, I%, lo%(), DLG_ITEM_DEFAULT, "OK") ENDIF REM init dialogue contents PROCsetPalette(PALETTE_DLG) PROCdlg_draw(dlg%%,0,0) FOR I% = 1 TO PLACE_MAX : PROCdlg_setItemText(dlg%%, I%, Place$(I%)) : NEXT PROCdlg_setFocus(dlg%%, F%) REPEAT I% = FNdlg_poll(dlg%%) CASE I% OF WHEN -1, PLACE_MAX + 1 REM gather place strings Place$() = "" : J% = 0 FOR I% = 1 TO PLACE_MAX a$ = FN_trim(FNdlg_getItemText(dlg%%, I%)) IF LEN a$ J% += 1 : Place$(J%) = a$ NEXT Place.total% = J% PROCoptions_save PROCplace_updateMenu REM the callee must _drawAll WHEN -2 REM close / cancel WHEN -3 REM window resized PROC_move OTHERWISE I% = 0 ENDCASE UNTIL I% PROCdlg_close(dlg%%) PROCsetPalette(ColourScheme%) ENDPROC (_) REM Keeps track of previous program lines visited REM It will be modified before/after: REM - selecting a function from the function list REM - vertical scrolling by dragging the scroll bar DEF PROCback_set backPtr% += 1 : IF backPtr% > backMax% backPtr% = 0 Back{(backPtr%)}.topline% = topLine% Back{(backPtr%)}.editline% = Edit.line% Back{(backPtr%)}.carrot% = Edit.carrot% Back{(backPtr%)}.startchr% = Start% IF backTotal% < backMax% backTotal% += 1 ENDPROC DEF PROCback_unset IF backTotal% ELSE ENDPROC backPtr% -= 1 : IF backPtr% < 0 backPtr% = backMax% backTotal% -= 1 ENDPROC DEF PROCback_go IF backTotal% ELSE ENDPROC LOCAL T%, E% T% = Back{(backPtr%)}.topline% E% = Back{(backPtr%)}.editline% IF E% > lastLine% THEN E% = lastLine% T% = E% - Body.ch% + 1 IF T% < 1 T% = 1 ENDIF PROCeditLine_save topLine% = T% Start% = Back{(backPtr%)}.startchr% IF lineSelect.anc% PROClineSelect_clear PROCeditLine_set(E%, Back{(backPtr%)}.carrot%) backPtr% -= 1 : IF backPtr% < 0 backPtr% = backMax% backTotal% -= 1 REM callee must call _drawAll ENDPROC (_) DEF PROCgoto_open IF lineSelect.anc% THEN PROClineSelect_clear IF Edit.line% >= topLine% IF Edit.line% <= botLine% ELSE PROCeditLine_set(topLine%, 0) PROC_drawAll ELSE PROCeditLine_save ENDIF : PRIVATE dlg%% LOCAL lom%(), lo$(), lo%() LOCAL W%, E%, I%, J% W% = @vdu%!216 E% = 4 : REM number of dialogue items DIM lom%(11), lo$(E%, 4), lo%(E%, 3) lom%() = 0,0, 4,4,4,4, 8*W%,2*@vdu%!220, 8,8, 1,E% lo$() = "","","","","", \ \ "label","","",STR$(14 * W%),"", \ \ "field","#right","#","","", \ \ "goto","@right","#below","","", \ \ "cancel","#left","#","","" FORI%=1TOE%:FORJ%=0TO3:SWAPlo$(I%,J%),lo$(I%,J%+1):NEXT:NEXT PROCdlg_lo_resolve(lom%(), lo$(), lo%(), TRUE) IF dlg%% THEN REM init dialogue size dlg%%!8 = lom%(0) * 2 dlg%%!12 = lom%(1) * 2 FORI%=1TOE%:PROCdlg_setItemPos_(dlg%%,I%,lo%()):NEXT ELSE dlg%% = FNdlg_new(lom%(0), lom%(1), DLG_CENTRE, "Go To Line") PROCstaticbox_new_(dlg%%, 1, lo%(), DLG_ITEM_TEXT_ALIGN_RIGHT, "Line Number:") PROCeditbox_new_(dlg%%, 2, lo%(), DLG_ITEM_ES_NUMBER OR DLG_ITEM_ES_SELECT_ON_FOCUS) PROCpushbutton_new_(dlg%%, 3, lo%(), DLG_ITEM_DEFAULT, "Go To") PROCpushbutton_new_(dlg%%, 4, lo%(), 0, "Cancel") ENDIF REM init dialogue contents PROCsetPalette(PALETTE_DLG) PROCdlg_draw(dlg%%,0,0) PROCdlg_setItemText(dlg%%, 2, STR$ Edit.line%) PROCdlg_setItemRange(dlg%%, 2, 1, lastLine%) PROCdlg_setFocus(dlg%%, 2) REPEAT I% = FNdlg_poll(dlg%%) CASE I% OF WHEN -1, 3 REM E% editline REM J% topline E% = VAL FNdlg_getItemText(dlg%%, 2) IF E% == 0 E% = 1 IF E% > lastLine% E% = lastLine% IF E% + Body.ch% - 1 > lastLine% THEN J% = lastLine% - Body.ch% + 1 IF J% < 1 J% = 1 ELSE J% = FNtextArea_topLineToShow(E%) ENDIF IF ABS(topLine% - J%) > Body.ch% PROCback_set topLine% = J% Start% = 1 PROCeditLine_set(E%, 0) REM the callee must _drawAll WHEN -2, 4 REM close / cancel WHEN -3 REM window resized PROC_move OTHERWISE I% = 0 ENDCASE UNTIL I% PROCdlg_close(dlg%%) PROCsetPalette(ColourScheme%) ENDPROC (_) DEF PROC_pageUp LOCAL I%, J% I% = topLine% - Body.ch% : IF I% < 1 I% = 1 IF I% == topLine% ENDPROC PROCeditLine_save J% = Edit.line% - topLine% : REM edit line offset PROCtextArea_draw(I%, 0) IF lineSelect.anc% == 0 PROCeditLine_set(I% + J%, Edit.carrot%) : PROCeditLine_draw : PROCstatusBar_draw PROCvscroll_draw REPEAT UNTIL INKEY(0) == -1 ENDPROC DEF PROC_pageDown LOCAL I%, J% I% = topLine% + Body.ch% IF I% + Body.ch% - 1 > lastLine% I% = lastLine% - Body.ch% + 1 IF I% < 1 I% = 1 IF I% == topLine% ENDPROC PROCeditLine_save J% = Edit.line% - topLine% : REM edit line offset PROCtextArea_draw(I%, 0) IF lineSelect.anc% == 0 PROCeditLine_set(I% + J%, Edit.carrot%) : PROCeditLine_draw : PROCstatusBar_draw PROCvscroll_draw REPEAT UNTIL INKEY(0) == -1 ENDPROC (_) REM Returns TRUE if it was possible to prefix the selected line with REM REM Returns FALSE if if it was not possible because one of the selected lines was too long REM in which case you will need to use _drawAll DEF FNrem_add IF lineSelect.anc% == 0 ENDPROC LOCAL A%, S%, E%, I%, a$ S% = lineSelect.anc% E% = lineSelect.ext% IF S% > E% SWAP S%, E% REM if any of the lines will be too long (I.e. longer than 251 characters when tokenised) REM after having been prefixed with a 'REM' keyboard space character(s), then abort. FOR A% = S% TO E% I% = LEN Line$(A%) + 2 IF IndentRem% I% += lineIndent&(A%) IF I% > 251 THEN a$ = "" PROCmsgline_title(a$, "Can't Add REMs!") PROCmsgline_add(a$, CHR$0 + "Line " + STR$A% + " is too long.", "C") IFFNmsgwin(a$, MSGWIN_STOP) =FALSE ENDIF NEXT REM all is OK, so proceed with prefix PROCundo_save(S%) IF Lowercase% a$ = "rem " ELSE a$ = "REM " FOR A% = S% TO E% IF IndentRem% Line$(A%) = a$ + STRING$(lineIndent&(A%) + 1, " ") + Line$(A%) ELSE Line$(A%) = a$ + " " + Line$(A%) lineIndentSelf&(A%) = 0 lineIndentNext%(A%) = 0 lineColour$(A%) = STRING$(LEN Line$(A%), CHR$ PAL_REM) NEXT PROClines_setIndentFrom(S%) PROClineSelect_clear PROCeditLine_set(Edit.line%, Edit.carrot% + 3) PROClines_setLongestLen fileModified% = TRUE =TRUE DEF PROCrem_remove IF lineSelect.anc% == 0 ENDPROC LOCAL A%, S%, E%, U%, M%, N%, a$ IF Lowercase% a$ = "rem" ELSE a$ = "REM" S% = lineSelect.anc% E% = lineSelect.ext% IF S% > E% SWAP S%, E% FOR A% = S% TO E% IF LEFT$(Line$(A%), 3) == a$ THEN IF NOT U% PROCundo_save(A%) : U% = TRUE Line$(A%) = FNtnt(MID$(Line$(A%), 4), M%, N%) IF M% lineNumberL&(A%) = N% MOD 256 : lineNumberH&(A%) = N% DIV 256 PROCline_setColour(A%) PROCline_setIndentEffect(A%) ENDIF NEXT PROClines_setIndentFrom(S%) PROClineSelect_clear A% = Edit.carrot% - 3 IF A% < 0 A% = 0 PROCeditLine_set(Edit.line%, A%) PROClines_setLongestLen fileModified% = TRUE ENDPROC DEF FNrem_invert IF lineSelect.anc% == 0 ENDPROC LOCAL A%, S%, E%, M%, N%, a$ IF Lowercase% a$ = "rem" ELSE a$ = "REM" S% = lineSelect.anc% E% = lineSelect.ext% IF S% > E% SWAP S%, E% REM if any of the lines will be too long (I.e. longer than 251 characters when tokenised) REM after having been prefixed with a 'REM' keyboard and space character, then abort. FOR A% = S% TO E% IF LEFT$(Line$(A%), 3) <> a$ IF LEN Line$(A%) + 2 > 251 THEN a$ = "" PROCmsgline_title(a$, "Can't Invert REMs!") PROCmsgline_add(a$, CHR$0 + "Line " + STR$A% + " is too long.", "C") IFFNmsgwin(a$, MSGWIN_STOP) =FALSE ENDIF NEXT REM all is OK, so proceed with invert PROCundo_save(S%) FOR A% = S% TO E% IF LEN Line$(A%) THEN IF LEFT$(Line$(A%), 3) == a$ THEN Line$(A%) = FNtnt(MID$(Line$(A%), 4), M%, N%) IF M% lineNumberL&(A%) = N% MOD 256 : lineNumberH&(A%) = N% DIV 256 PROCline_setColour(A%) PROCline_setIndentEffect(A%) ELSE IF IndentRem% Line$(A%) = a$ + STRING$(lineIndent&(A%) + 1, " ") + Line$(A%) ELSE Line$(A%) = a$ + " " + Line$(A%) lineIndentSelf&(A%) = 0 lineIndentNext%(A%) = 0 lineColour$(A%) = STRING$(LEN Line$(A%), CHR$ PAL_REM) ENDIF ENDIF NEXT PROClines_setIndentFrom(S%) PROClineSelect_clear PROCeditLine_set(Edit.line%, Edit.carrot%) PROClines_setLongestLen fileModified% = TRUE =TRUE (_) DEF PROCtoolbar_build LOCAL a$, b$, p$, I%, L%, R%, pspacer%%, S%, call%%() REM#const{ TB_BUTTON_NEW = 1 TB_BUTTON_OPEN = 2 TB_BUTTON_SAVE = 3 REM = 4 TB_BUTTON_UNDO = 5 TB_BUTTON_REDO = 6 REM = 7 TB_BUTTON_CUT = 8 TB_BUTTON_COPY = 9 TB_BUTTON_PASTE = 10 REM = 11 TB_BUTTON_FIND_DLG = 12 TB_BUTTON_FIND_NEXT = 13 TB_BUTTON_REPLACE_NEXT = 14 TB_BUTTON_REPLACE_ALL = 15 REM = 16 TB_BUTTON_REMOVE_REM = 17 TB_BUTTON_ADD_REM = 18 TB_BUTTON_INVERT_REM = 19 REM = 20 TB_BUTTON_RUN = 21 TB_BUTTON_RTE = 22 REM = 23 TB_BUTTON_FN_LIST = 24 REM = 25 TB_BUTTON_HIDE_MENU = 26 TB_BUTTON_DRAG = 27 REM = 28 TB_BUTTON_CLOSE = 29 REM#} DIM call%%(Toolbar.buttons%) call%%() = \ \ ^PROC_new, ^PROC_load, 0, \ new, open, save \ 0, \ \ 0, 0, \ undo, redo \ 0, \ \ 0, 0, 0, \ cut, copy, paste \ 0, \ \ ^PROCfr_open, 0, 0, ^PROCfr_replaceAll, \ find_dlg, find_next, replace_next, replace_all \ 0, \ \ 0, 0, 0, \ remove_rem, add_rem, invert_rem \ 0, \ \ ^PROC_run, ^PROC_launchRTE, \ run \ 0, \ \ ^PROCfnList_buildList, \ fn_list, \ 0, \ \ 0, 0, \ hide_menu, drag \ 0, \ \ ^PROC_exit p$ = IconDir$ + "tbar" + RIGHT$(@dir$) pspacer%% = FNloadBMP(p$ + "spacer") S% = 2 : REM gap between buttons L% = chrWidth% Toolbar.bl% = L% LOCAL DATA RESTORE +1 DATA "new", "Start a new BBC BASIC program" DATA "open", "Load an existing BBC BASIC program" DATA "save", "Save the current BBC BASIC program" DATA "|", " " DATA "undo", "Undo the effect of the last editing operation" DATA "redo", "Reverse the effect of the last undo" DATA "|", " " DATA "cut", "Cut the selection and store it in memory" DATA "copy", "Copy the selection and store it in memory" DATA "paste", "Insert previously cut/copied selection at current point" DATA "|", " " DATA "findDlg", "Open find dialogue to edit search and replace strings" DATA "findNext", "Search for the next occurrence" DATA "replaceNext", "Search for and replace the next occurrence" DATA "replaceAll", "Search for and replace all occurrences up to the end of the program" DATA "|", " " DATA "rem-", "Remove REM keyword from beginning of selected program lines" DATA "rem+", "Add REM keyword to beginning of selected program lines" DATA "remi", "Add REM to lines without REM, and remove REM from lines with REM" DATA "|", " " DATA "run", "Run the current program in a separate process" DATA "rte", "Enter commands for immediate execution" DATA "|", " " DATA "fnList", "Open function list if program contains FN/PROC definitions" DATA "|", " " DATA "hideMenu", "Hide/Show menu bar" DATA "drag", "Enable/Disable text area dragging" DATA "|", " " DATA "close", "Exit " DATA "", "" REPEAT READ a$, b$ IF LEN a$ THEN I% += 1 IF a$ <> "|" THEN a$ = p$ + a$ tbButton{(I%)}.outOn%% = FNloadBMP(a$ + "_outOn") tbButton{(I%)}.outOff%% = FNloadBMP(a$ + "_outOff") tbButton{(I%)}.outOver%% = FNloadBMP(a$ + "_outOver") tbButton{(I%)}.inOn%% = FNloadBMP(a$ + "_inOn") tbButton{(I%)}.inOver%% = FNloadBMP(a$ + "_inOver") tbButton{(I%)}.call%% = call%%(I% - 1) tbButton{(I%)}.state& = BUTTON_STATE_OUTON R% = Toolbar.bh% ELSE tbButton{(I%)}.outOff%% = pspacer%% tbButton{(I%)}.state& = BUTTON_STATE_OUTOFF R% = Toolbar.bh% / 2 ENDIF tbButton{(I%)}.l% = L% L% += R% tbButton{(I%)}.r% = L% L% += S% tbButton{(I%)}.tip$ = b$ ENDIF UNTIL a$ == "" tbButton{(Toolbar.buttons%)}.tip$ += Prog.name$ Toolbar.br% = L% - S% Toolbar.bw% = Toolbar.br% - Toolbar.bl% ENDPROC REM PROCtoolbar_textAlign REM ===================== REM REM Aligns the left edge of the left most button with the left edge of the first character of the menu bar. REM This procedure should be called after the font size has changed. DEF PROCtoolbar_textAlign LOCAL O%, I% O% = chrWidth% - Toolbar.bl% FOR I% = 1 TO Toolbar.buttons% tbButton{(I%)}.l% += O% tbButton{(I%)}.r% += O% NEXT Toolbar.bl% = chrWidth% Toolbar.br% += O% ENDPROC DEF PROCtoolbar_rollOver(I%) LOCAL J%, p%% J% = Toolbar.over% IF J% THEN IF tbButton{(J%)}.state& AND BUTTON_STATE_ON THEN IF tbButton{(J%)}.state& AND BUTTON_STATE_OUT p%% = tbButton{(J%)}.outOn%% ELSE p%% = tbButton{(J%)}.inOn%% OSCLI "MDISPLAY " + STR$~p%% + " " + STR$(tbButton{(J%)}.l% + Toolbar.sx%) + "," + STR$ Toolbar.bb% ENDIF ENDIF IF I% THEN IF tbButton{(I%)}.state& AND BUTTON_STATE_ON THEN IF tbButton{(I%)}.state& AND BUTTON_STATE_OUT p%% = tbButton{(I%)}.outOver%% ELSE p%% = tbButton{(I%)}.inOver%% OSCLI "MDISPLAY " + STR$~p%% + " " + STR$(tbButton{(I%)}.l% + Toolbar.sx%) + "," + STR$ Toolbar.bb% ENDIF ENDIF Toolbar.over% = I% ENDPROC DEF PROCtoolbar_draw IFNOTToolbar.show%ENDPROC LOCAL I%, P%, pbmp%%, X% GCOLPAL_BORDER:IFSDL%RECTANGLEFILL0,Toolbar.b%,Win.w%,Toolbar.h%ELSERECTANGLEFILL0,Toolbar.b%-2,Win.w%,Toolbar.h% FOR I% = 1 TO Toolbar.buttons% X% = tbButton{(I%)}.l% + Toolbar.sx% IF X% < Win.w% IF tbButton{(I%)}.r% + Toolbar.sx% > Toolbar.bl% THEN REM set button state CASE I% OF WHEN TB_BUTTON_SAVE IF fileModified% P% = BUTTON_STATE_OUTON ELSE P% = BUTTON_STATE_OUTOFF tbButton{(I%)}.state& = P% WHEN TB_BUTTON_UNDO IF Undo.count% P% = BUTTON_STATE_OUTON ELSE P% = BUTTON_STATE_OUTOFF tbButton{(I%)}.state& = P% WHEN TB_BUTTON_REDO IF Redo.ptr% P% = BUTTON_STATE_OUTON ELSE P% = BUTTON_STATE_OUTOFF tbButton{(I%)}.state& = P% WHEN TB_BUTTON_CUT, TB_BUTTON_COPY IF stringSelect.index% == 0 IF lineSelect.anc% == 0 P% = BUTTON_STATE_OUTOFF ELSE P% = BUTTON_STATE_OUTON tbButton{(I%)}.state& = P% WHEN TB_BUTTON_PASTE IF FNclipboard_hasText P% = BUTTON_STATE_OUTON ELSE P% = BUTTON_STATE_OUTOFF tbButton{(I%)}.state& = P% WHEN TB_BUTTON_FIND_NEXT, TB_BUTTON_REPLACE_NEXT, TB_BUTTON_REPLACE_ALL IF LEN FR.find$ P% = BUTTON_STATE_OUTON ELSE P% = BUTTON_STATE_OUTOFF tbButton{(I%)}.state& = P% WHEN TB_BUTTON_HIDE_MENU IF menuBar.show% P% = BUTTON_STATE_OUTON ELSE P% = BUTTON_STATE_INON tbButton{(I%)}.state& = P% WHEN TB_BUTTON_DRAG IF textArea.drag% P% = BUTTON_STATE_INON ELSE P% = BUTTON_STATE_OUTON tbButton{(I%)}.state& = P% WHEN TB_BUTTON_REMOVE_REM, TB_BUTTON_ADD_REM, TB_BUTTON_INVERT_REM IF lineSelect.anc% P% = BUTTON_STATE_OUTON ELSE P% = BUTTON_STATE_OUTOFF tbButton{(I%)}.state& = P% OTHERWISE P% = tbButton{(I%)}.state& ENDCASE REM choose button image based upon button state IF P% AND BUTTON_STATE_ON THEN IF I% == Toolbar.over% THEN IF P% AND BUTTON_STATE_OUT pbmp%% = tbButton{(I%)}.outOver%% ELSE pbmp%% = tbButton{(I%)}.inOver%% ELSE IF P% AND BUTTON_STATE_OUT pbmp%% = tbButton{(I%)}.outOn%% ELSE pbmp%% = tbButton{(I%)}.inOn%% ENDIF ELSE pbmp%% = tbButton{(I%)}.outOff%% ENDIF REM display button OSCLI "MDISPLAY " + STR$~pbmp%% + " " + STR$ X% + "," + STR$ Toolbar.bb% ENDIF NEXT ENDPROC DEF PROCtoolbar_click(X%) REM is the user trying to drag the toolbar? LOCAL N%, O%, P%, Q%, I% REPEAT MOUSE P%, Q%, I% WAIT 1 IF P% <> X% PROCtoolbar_drag(X%, P%) : ENDPROC UNTIL I% == 0 Q% = Toolbar.sx% FOR I% = 1 TO Toolbar.buttons% IF X% > tbButton{(I%)}.l% + Q% IF X% < tbButton{(I%)}.r% + Q% IF tbButton{(I%)}.state& AND BUTTON_STATE_ON THEN REM simulate button push IF tbButton{(I%)}.state& AND BUTTON_STATE_OUT IF tbButton{(I%)}.inOn%% == 0 THEN IF Toolbar.bb% - Toolbar.b% < 4 N% = 2 ELSE N% = 4 IF SDL% ELSE O% = 2 P% = Toolbar.bh% - 2 + O% *REFRESH OFF GCOL PAL_BORDER RECTANGLE FILL tbButton{(I%)}.l%, Toolbar.bb%-O%, P%, P% OSCLI "mdisplay " + STR$~tbButton{(I%)}.outOn%% + " " + STR$(tbButton{(I%)}.l%+N%) + "," + STR$(Toolbar.bb%-N%) *REFRESH IF POS WAIT 10 RECTANGLE FILL tbButton{(I%)}.l%+N%, Toolbar.bb%-N%-O%, P%, P% OSCLI "mdisplay " + STR$~tbButton{(I%)}.outOn%% + " " + STR$tbButton{(I%)}.l% + "," + STR$Toolbar.bb% *REFRESH IF POS WAIT 10 OSCLI "mdisplay " + STR$~tbButton{(I%)}.outOver%% + " " + STR$tbButton{(I%)}.l% + "," + STR$Toolbar.bb% *REFRESH ON IF POS ENDIF IF tbButton{(I%)}.call%% THEN PROC(tbButton{(I%)}.call%%) PROC_drawAll ELSE CASE I% OF WHEN TB_BUTTON_SAVE PROCeditLine_save IF LEN Dirname$ PROCfile_save(Dirname$ + Basename$) ELSE PROC_saveAs PROC_drawAll WHEN TB_BUTTON_UNDO PROCundo_restore PROC_drawAll WHEN TB_BUTTON_REDO PROCredo_restore PROC_drawAll WHEN TB_BUTTON_CUT PROC_cut PROC_refreshAll WHEN TB_BUTTON_COPY PROC_copy PROCtoolbar_draw WHEN TB_BUTTON_PASTE PROC_paste PROC_refreshAll WHEN TB_BUTTON_FIND_NEXT PROCfr_findNext WHEN TB_BUTTON_REPLACE_NEXT PROCfr_replaceNext WHEN TB_BUTTON_REMOVE_REM PROCrem_remove PROCtextArea_draw(restoreTopLine%, 0) IF Margin.basic% PROCmargin_draw PROCstatusBar_draw PROChscroll_draw PROCeditLine_draw WHEN TB_BUTTON_ADD_REM, TB_BUTTON_INVERT_REM IF I% == TB_BUTTON_ADD_REM I% = FNrem_add ELSE I% = FNrem_invert IF I% THEN PROCtextArea_draw(restoreTopLine%, 0) PROCtoolbar_draw PROCstatusBar_draw PROChscroll_draw PROCeditLine_draw ELSE PROC_drawAll ENDIF WHEN TB_BUTTON_HIDE_MENU menuBar.show% EOR= TRUE PROCoptions_save PROC_drawAll WHEN TB_BUTTON_DRAG textArea.drag% EOR= TRUE PROCoptions_save PROCtoolbar_draw ENDCASE ENDIF ENDPROC ENDIF NEXT ENDPROC DEF PROCtoolbar_drag(P%, X%) LOCAL Y%, Z% REPEAT PROCtoolbar_scroll(X% - P%) : REM new position - previous position P% = X% WAIT 1 MOUSE X%, Y%, Z% UNTIL Z% == 0 ENDPROC DEF PROCtoolbar_scroll(I%) IF I% > 0 THEN REM scroll right IF Toolbar.sx% < 0 THEN Toolbar.sx% += I% IF Toolbar.sx% > 0 Toolbar.sx% = 0 PROCtoolbar_draw *REFRESH ENDIF ELSE REM scroll left IF I% == 0 ENDPROC LOCAL R% R% = Win.w% - Toolbar.bl% : REM if a button is beyond this point, the toolbar can scroll to the left IF Toolbar.br% + Toolbar.sx% > R% THEN Toolbar.sx% += I% IF Toolbar.br% + Toolbar.sx% < R% Toolbar.sx% = R% - Toolbar.bw% - Toolbar.bl% PROCtoolbar_draw *REFRESH ENDIF ENDIF ENDPROC (_) DEF PROCmargin_draw IFNOTMargin.show%ENDPROC COLOR 128+PAL_MARGIN LOCAL I%,L%,N% L%=topLine%:N%=Body.ch%+textArea.ct%-1 IFNOTMargin.basic%COLORPAL_HIGHLIGHT:FORI%=textArea.ct%TON%:PRINTTAB(0,I%)" ";RIGHT$(" "+STR$L%,Margin.digits%);" ";:L%+=1:NEXT:ENDPROC COLOR PAL_SUB FOR I% = textArea.ct% TO N% N% = lineNumberL&(L%) + lineNumberH&(L%) * 256 IF N% THEN PRINTTAB(0,I%)" ";RIGHT$(" "+STR$N%,Margin.digits%);" "; ELSE PRINTTAB(0,I%)STRING$(Margin.cw%-1," "); ENDIF L% += 1 NEXT ENDPROC REM PROCmargin_click() REM ================== REM REM Responds to a mouse click on the margin REM REM Parameter Summary REM ~~~~~~~~~~~~~~~~~ REM REM Y% : y-coordinate of mouse pointer in graphic units REM W% : value of @wparam% DEF PROCmargin_click(Y%, W%) LOCAL R%, L% R% = (Win.h% - Y%) / chrHeight% : REM row selection L% = topLine% + R% - textArea.ct% : REM line selection IF L% > lastLine% ENDPROC IF W% AND 1 THEN REM left click W% = W% AND 4 OR INKEY(-1) ELSE REM right click W% = TRUE ENDIF IF W% IF lineSelect.anc% THEN PROClineSelect_range(lineSelect.anc%, L%) ELSE REM it is an initial line selection if left-clicking or if no lines are selected PROClineSelect_range(L%, L%) ENDIF PROCtextArea_draw(topLine%, 0) PROCtoolbar_draw PROCstatusBar_draw ENDPROC (_) DEF PROCstatusBar_draw(a$) DEF PROCstatusBar_draw : LOCAL a$ IF NOT statusBar.show% ENDPROC GCOL PAL_BORDER RECTANGLE FILL 0, -1, Win.w%, statusBar.h% MOVE chrWidth%, chrHeight% * 1.5 VDU 18,0,0,5 IF LEN a$ PRINT LEFT$(a$, Win.cw% - 2) : VDU 4 : ENDPROC IF stringSelect.index% IF LEN stringSelect.text$ = 1 THEN LOCAL a&, I% a& = ASC stringSelect.text$ a$ = "[Dec: "+RIGHT$(" "+STR$a&,3)+" Hex: "+RIGHT$("0"+STR$~a&,2)+" Bin: "+\ \STR$SGN(a& AND128)+STR$SGN(a& AND64)+STR$SGN(a& AND32)+STR$SGN(a& AND16)+STR$SGN(a& AND8)+STR$SGN(a& AND4)+STR$SGN(a& AND2)+STR$SGN(a& AND1)+"]" IF a& >= &C0 IF a& <= &F7 IF stringSelect.index% < LEN Edit.text$ THEN a& = a& << 1 : I% = 1 WHILE a& AND &80 AND (ASCMID$(Edit.text$, stringSelect.index% + I%, 1) AND &C0 EOR &40) a& = a& << 1 : I% += 1 : ENDWHILE IF (a& AND &80) == 0 a$ += " [UTF-8: "+STR$I%+"]" ELSE IF a& > 127 IF a& < 160 THEN I% = a& - 128 IF LEN M7$(I%) a$+= " [MODE 7: "+M7$(I%)+"]" IF LEN ANSI$(I%) a$ += " [ANSI: "+ANSI$(I%)+"]" ENDIF ENDIF ELSE IF fileModified% a$ = " *" a$ = "["+Basename$+a$+"] [Lines: "+STR$lastLine%+"] [Ln: "+STR$Edit.line%+" Pos: "+ \ \ STR$Edit.carrot%+" Sel: "+STR$LENstringSelect.text$+" | "+STR$lineSelect.size%+"] [" IF Overwrite% a$ += "OVR]" ELSE a$ += "INS]" ENDIF PRINT LEFT$(a$, Win.cw% - 2) : VDU 4 ENDPROC (_) DEF PROCvscroll_draw IF NOT vScroll.show% ENDPROC GCOL PAL_BORDER IF SDL% THEN RECTANGLE FILL vScroll.x%, vScroll.y%, vScroll.w%, vScroll.h% ELSE RECTANGLE FILL vScroll.x%, vScroll.y%-2, vScroll.w%, vScroll.h% ENDIF IF lastLine% > Body.ch% THEN LOCAL r vScroll.sh% = vScroll.h% * (Body.ch% / lastLine%) IF vScroll.sh% < chrWidth% vScroll.sh% = chrWidth% : REM prevent scroll bar from getting too small to see r = (topLine% - 1) / (lastLine% - Body.ch%) IF r > 1 r = 1 vScroll.sy% = (topBorderBottom% - vScroll.sh%) - (vScroll.h% - vScroll.sh%) * r REM IF vScroll.sy% + vScroll.sh% >= topBorderBottom% vScroll.sy% = topBorderBottom% - vScroll.sh% - 1 ELSE vScroll.sh% = vScroll.h% vScroll.sy% = vScroll.y% ENDIF GCOL PAL_MARGIN RECTANGLE FILL vScroll.sx%, vScroll.sy%, chrWidth%, vScroll.sh% - 1 ENDPROC DEF PROCvscroll_put(Y%) GCOL PAL_BORDER IF SDL% THEN RECTANGLE FILL vScroll.x%, vScroll.y%, vScroll.w%, vScroll.h% ELSE RECTANGLE FILL vScroll.x%, vScroll.y%-2, vScroll.w%, vScroll.h% ENDIF IF Y% < vScroll.y% THEN Y% = vScroll.y% ELSE LOCAL I% I% = vScroll.y% + vScroll.h% - vScroll.sh% IF Y% > I% Y% = I% ENDIF vScroll.sy% = Y% GCOL PAL_MARGIN RECTANGLE FILL vScroll.sx%, vScroll.sy%, chrWidth%, vScroll.sh% - 1 ENDPROC DEF FNvscroll_topLine LOCAL A% IF vScroll.sy% == vScroll.y% THEN A% = lastLine% - Body.ch% + 1 ELSE A% = vScroll.h% - vScroll.sh% IF A% == 0 =1 A% = ((vScroll.y% + A% - vScroll.sy%) / A%) * (lastLine% - Body.ch%) ENDIF IF A% < 1 =1 =A% DEF PROCvscroll_click(X%, Y%, Z%) IF (Z% AND 1) == 0 ENDPROC IF Y% > vScroll.sy% + vScroll.sh% THEN IF stringSelect.index% PROCstringSelect_clear PROC_pageUp ELSE IF Y% < vScroll.sy% THEN IF stringSelect.index% PROCstringSelect_clear PROC_pageDown ELSE REM click-drag vertical scroll bar textArea.drag% OR= 1 PROCeditLine_save PROCback_set LOCAL I%, R% R% = Edit.line% - topLine% : REM current edit line row I% = Y% - vScroll.sy% : REM difference between mouse pointer and bottom edge of scroll bar MOUSE X%, Y%, Z% WHILE Z% PROCvscroll_put(Y% - I%) PROCtextArea_draw(FNvscroll_topLine, 0) IF lineSelect.anc% == 0 IF Edit.line% >= topLine% IF Edit.line% <= botLine% PROCeditLine_draw *REFRESH WAIT 1 MOUSE X%, Y%, Z% ENDWHILE IF lineSelect.anc% == 0 THEN IF Edit.line% >= topLine% IF Edit.line% <= botLine% THEN PROCeditLine_draw PROCback_unset ELSE : IF stringSelect.index% THEN REM set as the edit line, the first line of the current page that contains the selected string LOCAL L% FOR L% = topLine% TO botLine% I% = INSTR(Line$(L%), stringSelect.text$) IF I% THEN R% = L% - topLine% I% += lineIndent&(L%) stringSelect.index% = I% stringSelect.carrotAnc% = I% - 1 stringSelect.carrotExt% = I% + LEN stringSelect.text$ - 1 Edit.carrot% = stringSelect.carrotExt% I% = FALSE IF Edit.carrot% > textArea.cw% + Start% - 2 Start% = Edit.carrot% - textArea.cw% + 2 : Edit.text$ += " " : I% = TRUE IF I% ELSE IF stringSelect.index% < Start% Start% = stringSelect.index% : I% = TRUE IF I% PROCtextArea_draw(topLine%, 0) : PROChscroll_draw EXIT FOR ENDIF NEXT IF L% > botLine% THEN REM no line on the current page contains the selected string stringSelect.carrotAnc% = -1 stringSelect.carrotExt% = -1 stringSelect.index% = 0 stringSelect.text$ = "" PROCtoolbar_draw ENDIF ENDIF : PROCeditLine_set(topLine% + R%, Edit.carrot%) PROCeditLine_draw PROCstatusBar_draw ENDIF ELSE IF Edit.line% >= topLine% IF Edit.line% <= botLine% PROCback_unset ENDIF textArea.drag% = textArea.drag% == TRUE ENDIF ENDIF ENDPROC (_) DEF PROChscroll_draw IF NOT hScroll.show% ENDPROC LOCAL L%, r L% = LEN Edit.text$ IF longestLineLen% > L% L% = longestLineLen% GCOL PAL_BORDER RECTANGLE FILL hScroll.x%, hScroll.y%, hScroll.w%, hScroll.h% IF L% > textArea.cw% THEN hScroll.sw% = hScroll.w% * (textArea.cw% / L%) IF hScroll.sw% < chrWidth% hScroll.sw% = chrWidth% : REM prevent scroll bar from getting too small to see r = (Start% - 1) / (L% - textArea.cw%) IF r > 1 r = 1 hScroll.sx% = hScroll.x% + (hScroll.w% - hScroll.sw%) * r ELSE hScroll.sw% = hScroll.w% hScroll.sx% = hScroll.x% ENDIF GCOL PAL_MARGIN RECTANGLE FILL hScroll.sx%, hScroll.sy%, hScroll.sw%, chrWidth% ENDPROC DEF PROChscroll_put(X%) GCOL PAL_BORDER RECTANGLE FILL hScroll.x%, hScroll.y%, hScroll.w%, hScroll.h% IF X% < hScroll.x% THEN X% = hScroll.x% ELSE LOCAL I% I% = hScroll.x% + hScroll.w% - hScroll.sw% IF X% > I% X% = I% ENDIF hScroll.sx% = X% GCOL PAL_MARGIN RECTANGLE FILL hScroll.sx%, hScroll.sy%, hScroll.sw%, chrWidth% ENDPROC DEF PROChscroll_click(X%, Y%, Z%) IF (Z% AND 1) == 0 ENDPROC LOCAL I%, L%, A%, S% IF X% < hScroll.sx% THEN IF (Z% AND 4) THEN Start% = 1 ELSE Start% -= 8 IF Start% < 1 Start% = 1 ENDIF PROCtextArea_draw(topLine%, 0) IF lineSelect.anc% == 0 THEN IF Edit.carrot% - Start% > textArea.cw% - 2 Edit.carrot% = Start% + textArea.cw% - 2 PROCeditLine_draw ENDIF PROChscroll_draw ELSE IF X% > hScroll.sx% + hScroll.sw% THEN IF (Z% AND 4) THEN REM set start character to RHS of longest line I% = longestLineLen% - textArea.cw% + 1 IF I% < 1 I% = 1 Start% = I% ELSE L% = LEN Edit.text$ IF longestLineLen% > L% L% = longestLineLen% REM I% = number of characters of the longest line to the right of the text area I% = (L% - textArea.cw%) - (Start% - 1) IF I% > 8 Start% += 8 ELSE Start% += I% ENDIF PROCtextArea_draw(topLine%, 0) IF lineSelect.anc% == 0 THEN IF Edit.carrot% < Start% - 1 Edit.carrot% = Start% - 1 PROCeditLine_draw ENDIF PROChscroll_draw ELSE REM click-drag horizontal scroll bar textArea.drag% OR= 1 L% = LEN Edit.text$ IF longestLineLen% > L% L% = longestLineLen% L% -= textArea.cw% REM I% = number of graphic units you have to slide the scroll bar to move 1 character I% = (hScroll.w% - hScroll.sw%) / L% IF I% == 0 REPEAT WAIT 1 : MOUSE X%, Y%, Z% : UNTIL Z% == 0 : ENDPROC L% += 1 : REM L% = the largest legal value of Start% A% = X% : REM A% = previous mouse pointer x position MOUSE X%, Y%, Z% WHILE Z% S% = X% - A% : REM S% = horizontal distance moved by mouse pointer IF ABS(S%) > I% THEN PROChscroll_put(hScroll.sx% + S%) S% = 1 + (hScroll.sx% - hScroll.x%) / I% : REM Start% from hScroll.sx% IF X% > A% THEN REM scroll bar moved right IF Start% < L% THEN IF S% > L% S% = L% Start% = S% : PROCtextArea_draw(topLine%, 0) IF lineSelect.anc% == 0 THEN IF Edit.carrot% < Start% - 1 Edit.carrot% = Start% - 1 PROCeditLine_draw ENDIF ENDIF ELSE REM scroll bar moved left IF Start% > 1 THEN Start% = S% : PROCtextArea_draw(topLine%, 0) IF lineSelect.anc% == 0 THEN IF Edit.carrot% - Start% > textArea.cw% - 2 Edit.carrot% = Start% + textArea.cw% - 2 PROCeditLine_draw ENDIF ENDIF ENDIF A% = X% *REFRESH ENDIF WAIT 1 MOUSE X%, Y%, Z% ENDWHILE textArea.drag% = textArea.drag% == TRUE ENDIF ENDIF ENDPROC (_) REM PROCtextArea_draw() REM =================== REM REM Redraws the text in the text area according to REM the given program line number and text area row number. REM I.e. its puts program line L% at text area row R%, REM and continues sequentially to the last row in the text area. REM REM Parameter Summary REM ~~~~~~~~~~~~~~~~~ REM REM L% : line number REM R% : text area row number (from 0 to Body.ch% - 1) REM from which redraw will begin with given program line number DEF PROCtextArea_draw(L%, R%) IF R% == 0 IF L% <> topLine% topLine% = L% : botLine% = L% + Body.ch% - 1 : PROCmargin_draw LOCAL B%, C% C% = textArea.cl% R% += textArea.ct% VDU 28, C%, textArea.cb%, textArea.cr%, R% COLOR 128 + PAL_BACKGROUND CLS VDU 26 B% = botLine% : IF B% > lastLine% B% = lastLine% R% -= L% IF lineSelect.size% THEN FOR L% = L% TO B% IF lineSelected&(L%) THEN PROCline_printSelected(L%, C%, R% + L%) : COLOR 128 + PAL_BACKGROUND ELSE PROC(PrintLine%%)(L%, C%, R% + L%) ENDIF NEXT ELSE FORL%=L%TOB%:PROC(PrintLine%%)(L%,C%,R%+L%):NEXT IF LEN stringSelect.text$ > 1 PROCtextArea_strSelHilight ENDIF ENDPROC DEF PROCtextArea_strSelHilight LOCAL W%, E%, L%, I%, A%, B%, X%, Y%, a$ W% = LEN stringSelect.text$ E% = Start% + textArea.cw% - 1 Y% = textArea.ct% I% = textArea.ssh% COLOR 0,I%>>16,I%>>8,I% : COLOR 128 : COLOR PAL_FOREGROUND FOR L% = topLine% TO botLine% IF L% <> Edit.line% THEN I% = 1 - W% REPEAT I% = INSTR(Line$(L%), stringSelect.text$, I% + W%) IF I% ELSE EXIT REPEAT A% = I% + lineIndent&(L%) REM index of first character of substring in line (including indent) B% = A% + LEN stringSelect.text$ - 1 REM index of last character of substring in line (including indent) a$ = "" IF A% >= Start% IF A% <= E% THEN X% = A% - Start% REM whole substring visible ELSE start of substring visible IF B% <= E% a$ = stringSelect.text$ ELSE a$ = LEFT$(stringSelect.text$, textArea.cw% - X%) X% += textArea.cl% ELSE IF B% >= Start% IF B% <= E% THEN REM end of string visible a$ = RIGHT$(stringSelect.text$, B% - Start% + 1) X% = textArea.cl% ENDIF ENDIF IF LEN a$ THEN IF X% > 127 IF SDL% AND &F THEN VDU 31, 127, Y% : WHILE POS < X% : VDU 9 : ENDWHILE : PRINT a$; ELSE PRINT TAB(X%, Y%) a$; ENDIF ENDIF UNTIL 0 ENDIF Y% += 1 NEXT COLOR 0,0,0,0 ENDPROC DEF PROCtextArea_left LOCAL L%, I%, J%, R% COLOR 128 + PAL_BACKGROUND VDU 28,textArea.cl%,textArea.cb%,textArea.cr%,textArea.ct% VDU 23,7,0,1,0;0;0; I% = Start% + textArea.cw% Start% += 1 VDU 28,textArea.cr%,textArea.cb%,textArea.cr%,textArea.ct% FOR L% = topLine% TO botLine% IF L% > lastLine% ENDPROC J% = I% - lineIndent&(L%) IF J% <= LENLine$(L%) IF J%>0 COLOR?(PTR(lineColour$(L%)) + J% - 1) : PRINTTAB(0, R%)MID$(Line$(L%), J%, 1); R% += 1 NEXT VDU 26 ENDPROC DEF PROCtextArea_right LOCAL L%, I%, C%, R% VDU 28, textArea.cl%, textArea.cb%, textArea.cr%, textArea.ct% COLOR 128 + PAL_BACKGROUND VDU 23,7,0,0,0;0;0; VDU 26 Start% -= 1 C% = textArea.cl% R% = textArea.ct% FOR L% = topLine% TO botLine% IF L% > lastLine% ENDPROC I% = Start% - lineIndent&(L%) IF I% > 0 IF I% <= LEN Line$(L%) COLOR?(PTR(lineColour$(L%)) + I% - 1) : PRINTTAB(C%, R%)MID$(Line$(L%), I%, 1); R% += 1 NEXT ENDPROC DEF PROCtextArea_down VDU 28, 0, textArea.cb%, textArea.cr%, textArea.ct% COLOR 128 + PAL_BACKGROUND VDU 23,7,0,2,0;0;0; VDU 26 topLine% -= 1 botLine% -= 1 IF lineSelected&(topLine%) THEN PROCline_printSelected(topLine%, textArea.cl%, textArea.ct%) ELSE PROC(PrintLine%%)(topLine%, textArea.cl%, textArea.ct%) ENDIF IF Margin.show% THEN COLOR 128 + PAL_MARGIN VDU 31, 0, textArea.ct% IF Margin.basic% THEN COLOR PAL_SUB LOCAL N% N% = lineNumberL&(topLine%) + lineNumberH&(topLine%) * 256 IF N% THEN PRINT " ";RIGHT$(" " + STR$ N%, Margin.digits%);" "; ELSE PRINT STRING$(Margin.cw% - 1, " "); ENDIF ELSE COLOR PAL_HIGHLIGHT PRINT " ";RIGHT$(" " + STR$ topLine%, Margin.digits%);" "; ENDIF ENDIF IF SDL% ELSE *REFRESH ENDPROC DEF PROCtextArea_up VDU 28, 0, textArea.cb%, textArea.cr%, textArea.ct% COLOR 128 + PAL_BACKGROUND VDU 23,7,0,3,0;0;0; VDU 26 topLine% += 1 botLine% += 1 IF lineSelected&(botLine%) THEN PROCline_printSelected(botLine%, textArea.cl%, textArea.cb%) ELSE PROC(PrintLine%%)(botLine%, textArea.cl%, textArea.cb%) ENDIF IF Margin.show% THEN COLOR 128 + PAL_MARGIN VDU 31, 0, textArea.cb% IF Margin.basic% THEN COLOR PAL_SUB LOCAL N% N% = lineNumberL&(botLine%) + lineNumberH&(botLine%) * 256 IF N% THEN PRINT " ";RIGHT$(" " + STR$ N%, Margin.digits%);" "; ELSE PRINT STRING$(Margin.cw% - 1, " "); ENDIF ELSE COLOR PAL_HIGHLIGHT PRINT " ";RIGHT$(" " + STR$ botLine%, Margin.digits%);" "; ENDIF ENDIF IF SDL% ELSE *REFRESH ENDPROC REM Parameter Summary REM ~~~~~~~~~~~~~~~~~ REM REM R% : text area row number (from 0 to Body.ch% - 1) DEF PROCtextArea_insertRowBefore(R%) VDU 28, textArea.cl%, textArea.cb%, textArea.cr%, R% + textArea.ct% COLOR 128 + PAL_BACKGROUND VDU 23,7,0,2,0;0;0; VDU 26 ENDPROC REM Parameter Summary REM ~~~~~~~~~~~~~~~~~ REM REM R% : text area row number (from 0 to Body.ch% - 1) DEF PROCtextArea_deleteRow(R%) VDU 28, textArea.cl%, textArea.cb%, textArea.cr%, R% + textArea.ct% COLOR 128 + PAL_BACKGROUND VDU 23,7,0,3,0;0;0; VDU 26 ENDPROC REM PROCtextArea_click() REM ==================== REM REM Responds to a mouse click on the text area REM REM Parameter Summary REM ~~~~~~~~~~~~~~~~~ REM REM X% : x-coordinate of mouse pointer in graphic units REM Y% : y-coordinate of mouse pointer in graphic units REM W% : value of @wparam% DEF PROCtextArea_click(X%, Y%, W%) IF (W% AND 1) == 0 THEN IF INKEY(-3) PROCchrMenu_open : PROC_drawAll : ENDPROC IF INKEY(-1) PROCcontxMenu_open(X%, Y%) : PROC_drawAll : ENDPROC IF lineSelect.anc% == 0 IF stringSelect.index% == 0 PROCfnList_buildList(TRUE) : PROC_drawAll : ENDPROC PROCcontxMenu_open(X%, Y%) : PROC_drawAll : ENDPROC ENDIF LOCAL R%, C%, L% R% = (Win.h% - Y%) / chrHeight% : REM row selection L% = topLine% + R% - textArea.ct% : REM line selection IF L% > lastLine% ENDPROC : REM check that selected line is a program line C% = X% / chrWidth% + 0.5 : REM column selection --> (X% + chrWidth% / 2) / chrWidth% IF INKEY(-1) THEN REM shift + left-click IF lineSelect.anc% == 0 IF L% == Edit.line% THEN REM don't allow the user to select the very last visible carrot position in the text area IF C% >= textArea.cr% + 1 C% = textArea.cr% REM index of first character of selection string in Edit.text$: IF stringSelect.index% X% = stringSelect.carrotAnc% ELSE X% = Edit.carrot% REM edit line carrot index under the mouse pointer Y% = C% - Margin.cw% + Start% - 1 IF Y% > LEN Edit.text$ Y% = LEN Edit.text$ stringSelect.carrotAnc% = X% stringSelect.carrotExt% = Y% Edit.carrot% = Y% IF Y% < X% SWAP X%, Y% stringSelect.index% = X% + 1 stringSelect.text$ = MID$(Edit.text$, stringSelect.index%, Y% - X%) PROCtextArea_draw(topLine%, 0) PROCeditLine_draw PROCstatusBar_draw ELSE REM if there are not already lines selected, or this shift-left-click is not on the current edit line, REM then treat this like a shift-left-click on the margin IF lineSelect.anc% == 0 PROClineSelect_range(Edit.line%, Edit.line%) PROCmargin_click(Y%, W%) ENDIF ELSE REM left-click REM don't allow the user to select the very last visible carrot position in the text area IF C% >= textArea.cr% + 1 C% = textArea.cr% IF lineSelect.anc% THEN REM logically deselect the lines PROClineSelect_clear REM redraw the text area to visually clear selected lines PROCtextArea_draw(topLine%, 0) REM set and draw the selected edit line PROCeditLine_set(L%, Start% + C% - Margin.cw% - 1) ELSE REM if a string is currently selected, then logically and visually deselect the string IF stringSelect.index% PROCstringSelect_clear REM compute the new carrot index Edit.carrot% += C% - POS IF L% == Edit.line% THEN REM pad the edit line if necessary IF Edit.carrot% > LEN Edit.text$ Edit.text$ += STRING$(Edit.carrot% - LEN Edit.text$, " ") ELSE REM a new line has been selected so save the edit line and redraw text area or edit line as required PROCeditLine_save IF Edit.changedLineNumber% PROCmargin_draw IF Edit.changedIndent% THEN PROCtextArea_draw(Edit.line%, FNlineRow(Edit.line%, 0)) ELSE PROCline_draw(Edit.line%) ENDIF REM set and draw the selected edit line PROCeditLine_set(L%, Edit.carrot%) ENDIF ENDIF PROCeditLine_draw PROCstatusBar_draw PROChscroll_draw REM double-click TIME = 0 REPEAT IF NOT INKEY(-10) THEN TIME = 0 REPEAT IF INKEY(-10) THEN C% = X% DIV chrWidth% : REM column (0 to Win.cw%-1) C% = C% - textArea.cl% + Start% : REM character index IF NOT FNstringSelect_auto(Edit.text$, C%) ENDPROC C% = stringSelect.carrotExt% IF C% > textArea.cw% + Start% - 2 THEN REM if carrot is outside of field width to right, increment start character WHILE ASCRIGHT$(Edit.text$) == &20 Edit.text$ = LEFT$(Edit.text$) : ENDWHILE Edit.text$ += " " Start% = C% - textArea.cw% + 2 ENDIF PROCtextArea_draw(topLine%, 0) Edit.carrot% = C% REPEAT UNTIL NOT INKEY(-10) PROCeditLine_draw PROCstatusBar_draw PROChscroll_draw PROCtoolbar_draw ENDPROC ENDIF UNTIL TIME > 10 EXIT REPEAT ENDIF UNTIL TIME > 10 ENDIF ENDPROC DEF PROCtextArea_dragSelect(X%, Y%) LOCAL Z%, R%, C%, L%, line%, carrot% REM check that selected line is a program line R% = (Win.h% - Y%) / chrHeight% : REM row selection L% = topLine% + R% - textArea.ct% : REM line selection IF L% > lastLine% ENDPROC REM line% and carrot% are used to test whether the user has paused their drag-select REM operation, in which case the loop does not need to keep re-drawing the selected area. carrot% = -1 Z% = 1 WHILE Z% C% = X% / chrWidth% + 0.5 : REM column selection --> (X% + chrWidth% / 2) / chrWidth% R% = (Win.h% - Y%) / chrHeight% : REM row selection L% = topLine% + R% - textArea.ct% : REM line selection IF lineSelect.anc% THEN REM do click-drag line selection IF L% < 1 L% = 1 ELSE IF L% > lastLine% L% = lastLine% IF L% <> line% THEN REPEAT IF L% < line% PROClineSelect_up ELSE PROClineSelect_down UNTIL lineSelect.ext% == L% line% = L% *REFRESH ENDIF ELSE IF L% == Edit.line% THEN REM do click-drag string selection Y% = C% - Margin.cw% + Start% - 1 : REM the edit line carrot index under the mouse pointer IF Y% < Start% - 1 THEN IF Start% > 1 PROCtextArea_right : PROChscroll_draw Y% = Start% - 1 ELSE IF Y% > LEN Edit.text$ Y% = LEN Edit.text$ IF C% > textArea.cr% - 1 IF Start% + textArea.cw% - 1 < LEN Edit.text$ THEN PROCtextArea_left : PROChscroll_draw Y% = Start% + textArea.cw% - 2 ENDIF ENDIF IF Y% <> carrot% THEN X% = Edit.carrot% IF X% == Y% THEN PROCstringSelect_clear ELSE stringSelect.carrotAnc% = X% IF Y% < X% SWAP X%, Y% stringSelect.index% = X% + 1 stringSelect.text$ = MID$(Edit.text$, stringSelect.index%, Y% - X%) ENDIF PROCeditLine_draw PROCstatusBar_draw *REFRESH carrot% = Y% ENDIF ELSE REM make initial line selection IF stringSelect.index% PROCstringSelect_clear PROClineSelect_range(Edit.line%, L%) PROCtextArea_draw(topLine%, 0) PROCstatusBar_draw line% = L% *REFRESH ENDIF ENDIF WAIT 1 MOUSE X%, Y%, Z% ENDWHILE IF stringSelect.index% THEN IF stringSelect.carrotAnc% < stringSelect.index% THEN stringSelect.carrotExt% = stringSelect.carrotAnc% + LEN stringSelect.text$ ELSE stringSelect.carrotExt% = stringSelect.carrotAnc% - LEN stringSelect.text$ ENDIF Edit.carrot% = stringSelect.carrotExt% IF Edit.carrot% - Start% + 1 == textArea.cw% Start% += 1 : IF Edit.carrot% == LEN Edit.text$ Edit.text$ += " " PROCtextArea_draw(topLine%, 0) : PROCeditLine_draw : PROCstatusBar_draw ENDIF PROCtoolbar_draw ENDPROC REM A% : old X% pos REM B% : old Y% pos DEF PROCtextArea_drag(A%, B%) MOUSE ON 134 LOCAL X%, Y%, Z%, H%,V%, T%,S% MOUSE X%, Y%, Z% WHILE Z% H% = (A% - X%) / chrWidth% : REM horizontal travel (characters) V% = (Y% - B%) / chrHeight% : REM vertical travel (lines) IF H% OR V% THEN T% = topLine% + V% IF V% THEN IF V% < 0 THEN IF T% < 1 T% = 1 ELSE IF T% + Body.ch% - 1 > lastLine% THEN T% = lastLine% - Body.ch% + 1 IF T% < 1 T% = 1 ENDIF ENDIF ENDIF S% = Start% + H% IF H% THEN IF H% < 0 THEN IF S% < 1 S% = 1 ELSE IF longestLineLen% <= textArea.cw% THEN S% = 1 ELSE IF S% + textArea.cw% - 1 > longestLineLen% S% = longestLineLen% - textArea.cw% + 1 ENDIF ENDIF ENDIF V% = T% <> topLine% H% = S% <> Start% IF H% OR V% THEN Start% = S% PROCtextArea_draw(T%, 0) IF H% PROChscroll_draw IF V% PROCvscroll_draw *REFRESH ENDIF A% = X% : B% = Y% ELSE WAIT 1 ENDIF MOUSE X%, Y%, Z% ENDWHILE Y% = Edit.line% IF Y% < topLine% Y% = topLine% IF Y% > botLine% Y% = botLine% X% = Edit.carrot% IF X% < Start% - 1 X% = Start% - 1 IF X% > Start% + textArea.cw% - 2 X% = Start% + textArea.cw% - 2 PROCeditLine_set(Y%, X%) PROCeditLine_draw PROCstatusBar_draw PROC_setMousePointer *REFRESH ENDPROC REM This function returns a value for the text area top line REM ensuring that the given line will be visible in the text area REM If the given line is already visible, then the current topLine value is returned REM If the given line is NOT visible, the value returned will result in the given REM line being approximately in the middle of the text area DEF FNtextArea_topLineToShow(L%) IF L% >= topLine% IF L% <= botLine% :=topLine% L% -= (textArea.cb% - textArea.ct% + 1) / 2 IF L% < 1 L% = 1 =L% (_) DEF PROCline_printMono(L%, C%, R%) LOCAL I%, J% J% = LEN Line$(L%) I% = lineIndent&(L%) COLOR PAL_VAR IF I% THEN IF J% IF Start% <= I% + J% ELSE PRINT TAB(C%, R%) " "; : ENDPROC I% -= Start% - 1 : REM number of characters of indentation that are visible IF I% > 0 THEN PRINT TAB(C%, R%) " "; VDU 31, C% + I%, R% R% = textArea.cw% - I% : REM number of characters after indentation IF R% < 1 ENDPROC IF R% > J% R% = J% PRINTMID$(Line$(L%),1,R%);:ENDPROC ELSE VDU 31, C%, R% R% = -I% + textArea.cw% I% = -I% + 1 : REM index of first visible character of line IF R% > J% R% = J% PRINTMID$(Line$(L%),I%,R%);:ENDPROC ENDIF ELSE IF Start% > J% PRINT TAB(C%, R%) " "; : ENDPROC VDU 31, C%, R% R% = Start% + textArea.cw% - 1 IF R% > J% R% = J% PRINTMID$(Line$(L%),Start%,R%); ENDIF ENDPROC DEF PROCline_printColour(L%, C%, R%) LOCAL I%, J%, p%% J% = LEN Line$(L%) I% = lineIndent&(L%) IF I% THEN IF J% IF Start% <= I% + J% ELSE PRINT TAB(C%, R%) " "; : ENDPROC I% -= Start% - 1 : REM number of characters of indentation that are visible IF I% > 0 THEN PRINT TAB(C%, R%) " "; VDU 31, C% + I%, R% R% = textArea.cw% - I% : REM number of characters after indentation IF R% < 1 ENDPROC IF R% > J% R% = J% p%%=PTR(lineColour$(L%))-1:FORI%=1TOR%:COLORp%%?I%:PRINTMID$(Line$(L%),I%,1);:NEXT:ENDPROC ELSE VDU 31, C%, R% R% = -I% + textArea.cw% I% = -I% + 1 : REM index of first visible character of line IF R% > J% R% = J% p%%=PTR(lineColour$(L%))-1:FORI%=I%TOR%:COLORp%%?I%:PRINTMID$(Line$(L%),I%,1);:NEXT:ENDPROC ENDIF ELSE IF Start% > J% PRINT TAB(C%, R%) " "; : ENDPROC VDU 31, C%, R% R% = Start% + textArea.cw% - 1 IF R% > J% R% = J% p%%=PTR(lineColour$(L%))-1:FORI%=Start%TOR%:COLORp%%?I%:PRINTMID$(Line$(L%),I%,1);:NEXT ENDIF ENDPROC DEF PROCline_printSelected(L%, C%, R%) COLOR 128 + PAL_HIGHLIGHT COLOR PAL_BACKGROUND VDU 31, C%, R% IF LEN Line$(L%) THEN PRINT LEFT$(MID$(STRING$(lineIndent&(L%), " ") + Line$(L%), Start%), textArea.cw%); ELSE IF Start% == 1 PRINT " "; ENDIF ENDPROC DEF PROCline_printUnselected(L%, C%, R%) COLOR 128 + PAL_BACKGROUND IF LEN Line$(L%) THEN PRINT TAB(C%, R%) SPC(textArea.cw%); PROC(PrintLine%%)(L%, C%, R%) ELSE IF Start% == 1 PRINT TAB(C%, R%) " "; ENDIF ENDPROC DEF PROCline_draw(L%) LOCAL R% R% = L% - topLine% + textArea.ct% : REM lineRow REM adding 1 to textArea.cr% grabs an area larger than the text area, REM this is done to compensate for fonts which are not pixel perfect in respect of the text area VDU 28, textArea.cl%, R%, textArea.cr%, R% COLOR 128 + PAL_BACKGROUND CLS PROC(PrintLine%%)(L%, 0, 0) VDU 26 ENDPROC DEF PROCline_setIndentEffect(L%) LOCAL p%%, Q%, b%%, S%, N% b%% = lineBuff%% p%% = b%% WHILE ?p%% <> &D IF ?p%% > &7F OR ?p%% < &11 THEN REM check keywords IF ?p%% > &C6 THEN CASE ?p%% OF WHEN &F4 : EXIT WHILE : REM KEYWORD_REM WHEN &CD : IF p%% == b%% S% += 2 : REM KEYWORD_ENDIF WHEN &C8 : N% += 4 : REM KEYWORD_CASE WHEN &C9, &CC : S% += 2 : N% += 2 : REM KEYWORD_WHEN, KEYWORD_OTHERWISE WHEN &CB : S% += 4 : REM KEYWORD_ENDCASE WHEN &E3, &C7, &F5 : IF Q% <> &10 N% += 2 : REM KEYWORD_FOR, KEYWORD_WHILE, KEYWORD_REPEAT, KEYWORD_EXIT WHEN &ED, &CE, &FD : IF p%% == b%% S% += 2 ELSE N% -= 2 : REM KEYWORD_NEXT, KEYWORD_ENDWHILE, KEYWORD_UNTIL ENDCASE ELSE IF ?p%% == &8B IF p%% == b%% S% += 2 : N% += 2 : REM KEYWORD_ELSE IF ?p%% == &8C IF p%%?1 == &D N% += 2 : REM KEYWORD_THEN ENDIF Q% = ?p%% ELSE IF ?p%% == &22 THEN REM skip string REPEAT:p%%+=1:UNTIL?p%%=&22OR?p%%=&D IF ?p%% == &D EXIT WHILE ELSE REM skip line continuation comment IF ?p%% == &5C AND p%% > b%% EXIT WHILE ENDIF ENDIF p%% += 1 ENDWHILE lineIndentSelf&(L%) = S% lineIndentNext%(L%) = N% ENDPROC DEF PROCline_setIndent(L%) LOCAL I% I% = lineIndent&(L% - 1) + lineIndentNext%(L% - 1) - lineIndentSelf&(L%) IF I% < 0 I% = 0 lineIndent&(L%) = I% ENDPROC DEF PROCline_setColour(L%) IF NOT SyntaxColour% ENDPROC lineColour$(L%) = "" IF ?lineBuff%% == &D ENDPROC LOCAL C%, a%%, V%, b%% a%% = lineBuff%% IF ?a%% == &28 THEN C% = PAL_DEF WHILE ?a%% <> &29 AND ?a%% <> &D lineColour$(L%) += CHR$C% : a%% += 1 ENDWHILE IF ?a%% == &29 lineColour$(L%) += CHR$C% : a%% += 1 ELSE IF ?a%% == &3D lineColour$(L%) += CHR$PAL_DEF : a%% += 1 ENDIF WHILE ?a%% <> &D IF ?a%% < &7F IF ?a%% > &1F THEN IF V% IF ?a%% > &2F IF ?a%% < &40 THEN C% = PAL_VAR ELSE C% = C&(?a%%) IF ?a%% == &22 THEN V% = FALSE REPEAT lineColour$(L%) += CHR$C% : a%% += 1 IF ?a%% == &D ENDPROC UNTIL ?a%% == &22 ELSE IF ?a%% == &5C IF a%% > lineBuff%% THEN lineColour$(L%) += CHR$C% + STRING$(LEN $(a%% + 1), CHR$PAL_REM) : ENDPROC ELSE IF ?a%% == &3D THEN b%% = a%% - 1 : WHILE ?b%% == &20 b%% -= 1 ENDWHILE IF INSTR(FnDefEnd$, CHR$?b%%) C% = PAL_DEF ELSE IF ?a%% > &3F AND ?a%% < &5B OR ?a%% > &5E AND ?a%% < &7E OR ?a%% == &26 V% = TRUE ELSE V% = FALSE ENDIF ENDIF ENDIF ENDIF lineColour$(L%) += CHR$C% : a%% += 1 ELSE C% = C&(?a%%) V% = FALSE IF ?a%% == &8D THEN lineColour$(L%) += STRING$(LENSTR$( (((a%%?1 << 2) AND &C0) EOR a%%?2) + 256 * (((a%%?1 << 4) AND &C0) EOR a%%?3) ), CHR$C%) a%% += 4 ELSE lineColour$(L%) += STRING$(K&(?a%%), CHR$C%) IF ?a%% == KEYWORD_REM THEN a%%+=1 : IF ?a%% <> &21 IF ?a%% <> &23 ELSE C% = PAL_DIR lineColour$(L%) += STRING$(LEN$a%%, CHR$C%) ENDPROC ENDIF IF ?a%% <> KEYWORD_PROC IF ?a%% <> KEYWORD_FN THEN IF ?a%% == KEYWORD_TO IF a%%?1 == &50 lineColour$(L%) += CHR$C% : a%% += 1 a%% += 1 ELSE REPEAT a%% += 1 IF ?a%% < &30 EXIT REPEAT IF ?a%% > &7A EXIT REPEAT IF ?a%% > &39 IF ?a%% < &40 EXIT REPEAT IF ?a%% > &5A IF ?a%% < &5F EXIT REPEAT lineColour$(L%) += CHR$C% UNTIL 0 ENDIF ENDIF ENDIF ENDWHILE ENDPROC REM Converts a line number to a text row number (in the text area) REM REM Parameter Summary REM ~~~~~~~~~~~~~~~~~ REM REM L% : line number REM O% : offset REM E.g. absolute value of top row of text area REM I.e. the row number returned is O% based - it counts from O% DEF FNlineRow(L%, O%):=L%-topLine%+O% (_) DEF PROClineNumbers_add : LOCAL I% : I% = 10 DEF PROClineNumbers_add(I%) PROCundo_save(1) LOCAL L%, O%, N% LOCAL P%, a%() LOCAL A%, B%, C%, M%, a$, t$ DIM a%(lastLine%, 1) REM clear line and string selections, save the edit line IF lineSelect.anc% PROClineSelect_clear IF stringSelect.index% PROCstringSelect_clear PROCeditLine_save REM renumber each line of the program FOR L% = 1 TO lastLine% REM compute new line number N% += I% REM read old line number O% = lineNumberL&(L%) + lineNumberH&(L%) * 256 REM keep a record of changed line numbers IF N% <> O% P% += 1 : a%(P%, 0) = O% : a%(P%, 1) = N% : fileModified% = TRUE lineNumberL&(L%) = N% MOD 256 lineNumberH&(L%) = N% DIV 256 NEXT REM update line number references in the program FOR L% = 1 TO lastLine% M% = FALSE : REM line modified flag REM tokenise line a$ = FNtok(Line$(L%)) REM look for encoded line number I% = INSTR(a$, CHR$ &8D) WHILE I% REM decode line number A% = ASC MID$(a$, I% + 1, 1) B% = ((A% << 2) AND &C0) EOR ASC MID$(a$, I% + 2, 1) C% = ((A% << 4) AND &C0) EOR ASC MID$(a$, I% + 3, 1) N% = VAL STR$(B% + C% * 256) REM linear search for line number in record A% = FALSE : REM valid line number flag FOR O% = 1 TO P% IF a%(O%, 0) == N% THEN REM recode line number A% = EVAL("0:GOTO" + STR$ a%(O%, 1)) MID$(a$, I%, 4) = $(!332 + 3) M% = TRUE A% = TRUE EXIT FOR ENDIF NEXT REM warn user about missing line number IF A% == FALSE THEN t$ = "" PROCmsgline_title(t$, "No Such Line Number!") PROCmsgline_add(t$, CHR$0 + "Line " + STR$ N% + ", referenced in (new) line " \ \ + STR$(lineNumberL&(L%) + lineNumberH&(L%) * 256) + ", does not exist.", "C") IFFNmsgwin(t$, MSGWIN_WARNING) ENDIF REM look for next encoded line number I% = INSTR(a$, CHR$ &8D, I% + 4) ENDWHILE IF M% THEN $lineBuff%% = a$ Line$(L%) = FNdetok(lineBuff%%) PROCline_setColour(L%) fileModified% = TRUE ENDIF NEXT PROClines_setLongestLen PROCeditLine_set(Edit.line%, Edit.carrot%) IF NOT Margin.basic% Margin.basic% = TRUE : PROCoptions_save ENDPROC DEF PROClineNumbers_strip LOCAL L%,a$, I%,J%, a%(),C%, N%,S% REM C% : count line number references (encoded line numbers) REM N% : count program lines with a basic line number REM S% : count program lines stripped of a basic line number REM clear line and string selections, save the edit line IF lineSelect.anc% PROClineSelect_clear IF stringSelect.index% PROCstringSelect_clear PROCeditLine_save : REM gather line number references DIM a%(lastLine% * 2) FOR L% = 1 TO lastLine% IF lineNumberL&(L%) OR lineNumberH&(L%) N% += 1 a$ = FNtok(Line$(L%)) REM look for encoded line numbers and add to a%() I% = INSTR(a$, CHR$&8D) WHILE I% C% += 1 : J% = ASCMID$(a$, I% + 1, 1) a%(C%) = ( ((J%<<2) AND &C0) EOR ASCMID$(a$,I%+2,1) ) + ( ((J%<<4) AND &C0) EOR ASCMID$(a$,I%+3,1) ) * 256 I% = INSTR(a$, CHR$&8D, I% + 4) ENDWHILE NEXT : IF N% THEN PROCundo_save(1) IF C% THEN IF C% > 1 THEN CALL Sort%%, a%(1) REM make set J% = 1 FOR I% = 2 TO C% IF a%(I%) <> a%(J%) J% += 1 : a%(J%) = a%(I%) NEXT C% = J% ENDIF REM remove all line numbers not referenced FOR L% = 1 TO lastLine% IF lineNumberL&(L%) OR lineNumberH&(L%) THEN J% = lineNumberL&(L%) + lineNumberH&(L%) * 256 FOR I% = 1 TO C% IF a%(I%) == J% EXIT FOR NEXT IF I% > C% lineNumberL&(L%) = 0 : lineNumberH&(L%) = 0 : S% += 1 ENDIF NEXT ELSE REM remove all line numbers FOR L% = 1 TO lastLine% IF lineNumberL&(L%) OR lineNumberH&(L%) lineNumberL&(L%) = 0 : lineNumberH&(L%) = 0 : S% += 1 NEXT ENDIF ENDIF : IF S% THEN fileModified% = TRUE IF S% == N% THEN IF Margin.basic% Margin.basic% = FALSE : PROCoptions_save ELSE IF NOT Margin.basic% Margin.basic% = TRUE : PROCoptions_save ENDIF ENDIF ENDPROC (_) REM PROClines_deleteFrom() REM ====================== REM REM Deletes N% lines starting at line I% REM REM Notes: REM REM C% = number of lines to move (I.e. the number of lines after the block to be deleted) REM D% = index of the line after the new last line DEF PROClines_deleteFrom(I%, N%) LOCAL p%%, C%, D% FOR p%% = I% TO I% + N% - 1 : Line$(p%%) = "" : lineColour$(p%%) = "" : NEXT IF I% > lastLine% - N% lastLine% -= N% : ENDPROC C% = lastLine% - (I% + N%) + 1 D% = lastLine% - N% + 1 p%% = ^Line$(I%) : SYS MemMove$, p%%, p%% + N% * 8, C% * 8 IF SDL% SYS "memset", ^Line$(D%), 0, N% * 8 ELSE SYS "RtlZeroMemory", ^Line$(D%), N% * 8 p%% = ^lineColour$(I%) : SYS MemMove$, p%%, p%% + N% * 8, C% * 8 IF SDL% SYS "memset", ^lineColour$(D%), 0, N% * 8 ELSE SYS "RtlZeroMemory", ^lineColour$(D%), N% * 8 p%% = ^lineIndent&(I%) : SYS MemMove$, p%%, p%% + N%, C% p%% = ^lineIndentSelf&(I%) : SYS MemMove$, p%%, p%% + N%, C% p%% = ^lineIndentNext%(I%) : SYS MemMove$, p%%, p%% + N% * 4, C% * 4 p%% = ^lineNumberL&(I%) : SYS MemMove$, p%%, p%% + N%, C% p%% = ^lineNumberH&(I%) : SYS MemMove$, p%%, p%% + N%, C% lastLine% -= N% ENDPROC REM PROClines_insertBefore() REM ======================== REM REM Inserts N% lines before line I% DEF PROClines_insertBefore(I%, N%) LOCAL p%%, C% p%% = lastLine% lastLine% += N% IF I% > p%% ENDPROC C% = p%% - I% + 1 p%% = ^Line$(I%) : SYS MemMove$, p%% + N% * 8, p%%, C% * 8 IF SDL% SYS "memset", p%%, 0, N% * 8 ELSE SYS "RtlZeroMemory", p%%, N% * 8 p%% = ^lineColour$(I%) : SYS MemMove$, p%% + N% * 8, p%%, C% * 8 IF SDL% SYS "memset", p%%, 0, N% * 8 ELSE SYS "RtlZeroMemory", p%%, N% * 8 p%% = ^lineIndent&(I%) : SYS MemMove$, p%% + N%, p%%, C% p%% = ^lineIndentSelf&(I%) : SYS MemMove$, p%% + N%, p%%, C% p%% = ^lineIndentNext%(I%) : SYS MemMove$, p%% + N% * 4, p%%, C% * 4 p%% = ^lineNumberL&(I%) : SYS MemMove$, p%% + N%, p%%, C% p%% = ^lineNumberH&(I%) : SYS MemMove$, p%% + N%, p%%, C% ENDPROC DEF PROClines_setIndentFrom(S%) LOCAL L%, I% I% = lineIndent&(S% - 1) FOR L% = S% TO lastLine% I% += lineIndentNext%(L% - 1) - lineIndentSelf&(L%) IF I% < 0 I% = 0 lineIndent&(L%) = I% NEXT ENDPROC DEF PROClines_setLongestLen LOCAL L%, I%, J% FOR I% = 1 TO lastLine% J% = lineIndent&(I%) + LEN Line$(I%) IF J% > L% L% = J% NEXT longestLineLen% = L% ENDPROC (_) DEF PROCeditLine_draw LOCAL X%, Y% Y% = Edit.line% - topLine% + textArea.ct% VDU 28, textArea.cl%, Y%, textArea.cr%, Y% COLOR 128 + PAL_EDITLINE : COLOR PAL_FOREGROUND CLS IF stringSelect.index% THEN IF stringSelect.carrotAnc% < 128 IF INKEY(-10) IF textArea.drag% == FALSE THEN PRINT LEFT$(MID$(Edit.text$, Start%), textArea.cw%); COLOR 128 + PAL_HIGHLIGHT : COLOR PAL_BACKGROUND X% = Start% - stringSelect.index% IF X% > 0 THEN PRINT TAB(0, 0) LEFT$(MID$(stringSelect.text$, 1 + X%), textArea.cw%); ELSE IF X% < 0 THEN X% = ABS X% IF X% < textArea.cw% PRINT TAB(X%, 0) LEFT$(stringSelect.text$, textArea.cw% - X%); ELSE PRINT TAB(0, 0) LEFT$(stringSelect.text$, textArea.cw%); ENDIF ENDIF ELSE LOCAL P%, Q%, R%, S% P% = textArea.ssh% COLOR 0,P%>>16,P%>>8,P% X% = Start% R% = Start% + textArea.cw% - 1 REPEAT P% = INSTR(Edit.text$, stringSelect.text$, Q% + 1) IF P% THEN Q% = P% + LEN stringSelect.text$ - 1 IF P% >= X% IF P% <= R% EXIT REPEAT IF Q% >= X% IF Q% <= R% EXIT REPEAT ENDIF UNTIL P% == 0 S% = LEN Edit.text$ + 1 IF R% < S% S% = R% R% -= 1 WHILE X% < S% IF P% THEN IF X% > Q% P% = INSTR(Edit.text$, stringSelect.text$, Q% + 1) : IF P% Q% = P% + LEN stringSelect.text$ - 1 IF P% IF X% >= P% IF X% <= Q% THEN IF P% == stringSelect.index% COLOR 128 + PAL_HIGHLIGHT : COLOR PAL_BACKGROUND ELSE COLOR 128 : COLOR PAL_FOREGROUND ELSE COLOR 128 + PAL_EDITLINE : COLOR PAL_FOREGROUND ENDIF ENDIF IF X% == R% VDU 23,16,32| PRINT MID$(Edit.text$, X%, 1); X% += 1 ENDWHILE VDU 23,16,0| COLOR 0,0,0,0 ENDIF ELSE PRINT LEFT$(MID$(Edit.text$, Start%), textArea.cw%); ENDIF VDU 26 X% = textArea.cl% + Edit.carrot% - Start% + 1 IF X% > 127 IF SDL% AND &F THEN VDU 31, 127, Y% : WHILE POS < X% : VDU 9 : ENDWHILE ELSE VDU 31, X%, Y% ENDIF IF stringSelect.index% ENDPROC LOCAL A%, B% A% = ASCMID$(Edit.text$, Edit.carrot%, 1) B% = INSTR("(){}", CHR$A%) IF B% IF NOT FNinQuotes(Edit.text$, Edit.carrot%) ELSE ENDPROC LOCAL C%, Q%, O% IF B% < 3 B% = &28 : C% = &29 ELSE B% = &7B : C% = &7D O% = 1 IF A% == C% THEN REM carrot to right of close bracket FOR X% = Edit.carrot% - 1 TO Start% STEP -1 A% = ASCMID$(Edit.text$, X%, 1) IF A% == &22 THEN Q% EOR= TRUE ELSE IF NOT Q% THEN IF A% == B% THEN O% -= 1 IF O% == 0 THEN A% = textArea.cl% - Start% IF A%+Edit.carrot%>127 IF SDL%AND&F THEN COLOR 128+PAL_EDITLINE : COLOR PAL_FOREGROUND PRINTTAB(textArea.cl%,VPOS);MID$(Edit.text$,Start%,X%-Start%); COLOR 128+PAL_MARGIN : COLOR PAL_DEF PRINTCHR$B%; COLOR 128+PAL_EDITLINE : COLOR PAL_FOREGROUND PRINTMID$(Edit.text$,X%+1,Edit.carrot%-X%-1); COLOR 128+PAL_MARGIN : COLOR PAL_DEF PRINTCHR$C%; ELSE COLOR 128+PAL_MARGIN : COLOR PAL_DEF PRINTTAB(A%+X%,VPOS)CHR$B%;TAB(A%+Edit.carrot%,VPOS)CHR$C%; ENDIF ENDPROC ENDIF ELSE IF A% == C% O% += 1 ENDIF ENDIF ENDIF NEXT ELSE REM carrot to right of open bracket A% = LEN Edit.text$ - (Start%-1) - textArea.cw% REM number of Edit.text$ characters to right of text area IF A% < 1 A% = LEN Edit.text$ ELSE A% = LEN Edit.text$ - A% FOR X% = Edit.carrot% + 1 TO A% A% = ASCMID$(Edit.text$, X%, 1) IF A% == &22 THEN Q% EOR= TRUE ELSE IF NOT Q% THEN IF A% == C% THEN O% -= 1 IF O% == 0 THEN A% = textArea.cl% - Start% IF A%+X%>127 IF SDL%AND&F THEN COLOR 128+PAL_EDITLINE : COLOR PAL_FOREGROUND PRINTTAB(textArea.cl%,VPOS);MID$(Edit.text$,Start%,X%-Start%); COLOR 128+PAL_MARGIN : COLOR PAL_DEF PRINTCHR$C%; COLOR 128+PAL_EDITLINE : COLOR PAL_FOREGROUND PRINTTAB(textArea.cl%,VPOS);MID$(Edit.text$,Start%,Edit.carrot%-Start%); COLOR 128+PAL_MARGIN : COLOR PAL_DEF PRINTCHR$B%; ELSE COLOR 128+PAL_MARGIN : COLOR PAL_DEF PRINTTAB(A%+X%,VPOS)CHR$C%;TAB(A%+Edit.carrot%,VPOS)CHR$B%; ENDIF ENDPROC ENDIF ELSE IF A% == B% O% += 1 ENDIF ENDIF ENDIF NEXT ENDIF ENDPROC REM - edit line number REM - edit line carrot index REM the indent is included in the length of the Edit.text$ REM send TRUE to set carrot to the end of the Edit.text$ DEF PROCeditLine_set(L%, I%) Edit.line% = L% Edit.text$ = STRING$(lineIndent&(L%), " ") + Line$(L%) IF I% < 0 THEN I% = LEN Edit.text$ ELSE IF I% > LEN Edit.text$ Edit.text$ += STRING$(I% - LEN Edit.text$, " ") ENDIF Edit.carrot% = I% Edit.modified% = FALSE ENDPROC DEF PROCeditLine_save IF NOT Edit.modified% Edit.changedIndent% = FALSE : Edit.changedLineNumber% = FALSE : ENDPROC LOCAL A%, I%, J% A% = Edit.line% Line$(A%) = FNtnt(Edit.text$, I%, J%) Edit.modified% = FALSE IF I% THEN Edit.changedLineNumber% = I% lineNumberL&(A%) = J% MOD 256 : lineNumberH&(A%) = J% DIV 256 Margin.basic% = TRUE ENDIF PROClines_setLongestLen PROCline_setColour(A%) I% = lineIndentNext%(A%) - lineIndentSelf&(A%) PROCline_setIndentEffect(A%) IF lineIndentNext%(A%) - lineIndentSelf&(A%) == I% Edit.changedIndent% = FALSE : ENDPROC PROClines_setIndentFrom(A%) Edit.changedIndent% = TRUE ENDPROC REM Inserts a character into Edit.text$ REM The character is read from the value of the global variable K% REM The Edit.carrot% and Start% are incremented as required DEF PROCeditLine_insertChr LOCAL C% IF NOT Edit.modified% PROCundo_save(0) C% = Edit.carrot% IF C% == LEN Edit.text$ THEN Edit.text$ += CHR$K% + " " ELSE IF Overwrite% THEN MID$(Edit.text$, C% + 1, 1) = CHR$K% ELSE Edit.text$ = LEFT$(Edit.text$, C%) + CHR$K% + MID$(Edit.text$, C% + 1) ENDIF ENDIF IF POS >= Body.cw% - 2 PROCtextArea_left Edit.carrot% += 1 Edit.modified% = TRUE fileModified% = TRUE ENDPROC (_) REM PROClineSelect_range() REM ====================== REM REM Logically selects (but does not draw) lines in the range F% to L% inclusive REM Sets the global variables: lineSelect.anc%, lineSelect.ext%, lineSelect.size%, lineSelected&() REM REM Parameter Summary REM ~~~~~~~~~~~~~~~~~ REM REM F% : line selection anchor REM L% : line selection extent REM REM Notes REM ~~~~~ REM REM If a line selection is not currently defined, then the current Edit.text$ is saved REM and the line number of the text area top line is saved in restoreTopLine% DEF PROClineSelect_range(F%, L%) LOCAL I% IF lineSelect.anc% THEN lineSelected&() = 0 ELSE IF stringSelect.index% PROCstringSelect_clear restoreTopLine% = topLine% PROCeditLine_save ENDIF lineSelect.anc% = F% lineSelect.ext% = L% IF L% < F% SWAP F%, L% FOR I% = F% TO L% lineSelected&(I%) = 1 NEXT lineSelect.size% = L% - F% + 1 ENDPROC DEF PROClineSelect_up LOCAL L%, I% L% = lineSelect.ext% IF L% > lineSelect.anc% THEN lineSelected&(L%) = 0 : I% = -1 ELSE IF L% == 1 ENDPROC lineSelected&(L% - 1) = 1 : I% = 1 ENDIF lineSelect.size% += I% lineSelect.ext% -= 1 IF L% >= topLine% IF L% <= botLine% THEN IF I% < 0 THEN REM deselect old extent IF L% == topLine% PROCtextArea_down : PROCvscroll_draw PROCline_printUnselected(L%, textArea.cl%, FNlineRow(L%, textArea.ct%)) ELSE REM select new extent IF L% == topLine% THEN PROCtextArea_down : PROCvscroll_draw ELSE PROCline_printSelected(lineSelect.ext%, textArea.cl%, FNlineRow(lineSelect.ext%, textArea.ct%)) ENDIF ENDIF ELSE L% -= Body.ch% / 2 IF L% < 1 L% = 1 PROCtextArea_draw(L%, 0) PROCvscroll_draw ENDIF PROCstatusBar_draw ENDPROC DEF PROClineSelect_down LOCAL L%, I% L% = lineSelect.ext% IF L% < lineSelect.anc% THEN lineSelected&(L%) = 0 : I% = -1 ELSE IF L% == lastLine% ENDPROC lineSelected&(L% + 1) = 1 : I% = 1 ENDIF lineSelect.size% += I% lineSelect.ext% += 1 IF L% >= topLine% IF L% <= botLine% THEN IF I% < 0 THEN REM deselect old extent IF L% == botLine% PROCtextArea_up : PROCvscroll_draw PROCline_printUnselected(L%, textArea.cl%, FNlineRow(L%, textArea.ct%)) ELSE REM select new extent IF L% == botLine% THEN PROCtextArea_up : PROCvscroll_draw ELSE PROCline_printSelected(lineSelect.ext%, textArea.cl%, FNlineRow(lineSelect.ext%, textArea.ct%)) ENDIF ENDIF ELSE L% -= Body.ch% / 2 IF L% < 1 L% = 1 PROCtextArea_draw(L%, 0) PROCvscroll_draw ENDIF PROCstatusBar_draw ENDPROC REM PROClineSelect_clear REM ======================= REM REM Logically deselects (but does not draw) selected lines (if any) DEF PROClineSelect_clear lineSelected&() = 0 lineSelect.anc% = 0 lineSelect.ext% = 0 lineSelect.size% = 0 PROCtoolbar_draw ENDPROC (_) REM PROCstringSelect_range() REM ======================== REM REM logically selects text within the current edit line REM REM Parameter Summary REM ~~~~~~~~~~~~~~~~~ REM REM I% : index of first character to select REM L% : length of string to select DEF PROCstringSelect_range(I%, L%) stringSelect.index% = I% stringSelect.carrotAnc% = I% - 1 stringSelect.carrotExt% = I% + L% - 1 stringSelect.text$ = MID$(Edit.text$, I%, L%) ENDPROC DEF PROCstringSelect_clear stringSelect.carrotAnc% = -1 stringSelect.carrotExt% = -1 stringSelect.index% = 0 stringSelect.text$ = "" PROCtextArea_draw(topLine%, 0) PROCeditLine_draw PROCtoolbar_draw ENDPROC DEF FNstringSelect_auto(a$, I%) IF I% > LEN a$ :=FALSE LOCAL P%, Q%, b$ b$ = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%&$@_" IF INSTR(b$, MID$(a$, I%, 1)) ELSE =FALSE P% = I% : REPEAT P% -= 1 UNTIL P% < 1 OR INSTR(b$, MID$(a$, P%, 1)) == 0 : P% += 1 Q% = I% : REPEAT Q% += 1 UNTIL Q% > LEN a$ OR INSTR(b$, MID$(a$, Q%, 1)) == 0 : Q% -= 1 stringSelect.index% = P% stringSelect.text$ = MID$(a$, P%, Q% - P% + 1) stringSelect.carrotAnc% = P% - 1 stringSelect.carrotExt% = Q% =TRUE (_) REM Sets the global font and therefore the chrWidth% and chrHeight% REM Most of the editor components have metrics that are based on the font size, REM therefore after changing the font size, it is necessary to reset all REM font dependant metrics. REM F% : a number indicating the font face where 0 is _FONT_BITMAP REM S% : a number indicating the font size where 0 is _FONT_SMALL DEF PROC_setFont(F%, S%) LOCAL a$ FontFace% = F% FontSize% = S% IF F% THEN CASE S% OF WHEN 1 : S% = 12 WHEN 2 : S% = 16 WHEN 3 : S% = 20 OTHERWISE : S% = 10 ENDCASE IF SDL% THEN CASE F% OF WHEN 1 : a$ = "FreeMono" WHEN 2 : a$ = "DejaVuSansMono" ENDCASE F% = OPENIN(@lib$ + a$ + ".ttf") IF F% THEN CLOSE#F% OSCLI "FONT """ + @lib$ + a$ + ".ttf"", " + STR$S% ELSE *FONT ENDIF ELSE LOCAL P% DIM P% LOCAL 31 CASE F% OF WHEN 1 : a$ = "Free Mono" WHEN 2 : a$ = "DejaVu Sans Mono" ENDCASE OSCLI "FONT " + a$ + ", " + STR$ S% SYS "GetTextFace", @memhdc%, 32, P% IF $$P% <> a$ OSCLI "FONT Courier New, " + STR$S% ENDIF ELSE *FONT ENDIF chrWidth% = @vdu%!216 * 2 chrHeight% = @vdu%!220 * 2 REM change cursor to vertical line VDU 23,0,18,2,0;0;0;23,0,10;0;0;0; ENDPROC REM PROC_setMetrics REM =============== REM REM Sets the metrics of editor components whos values depend upon the window size and font size DEF PROC_setMetrics LOCAL H%, C% Win.cw% = Win.w% / chrWidth% Win.ch% = Win.h% / chrHeight% Win.resized% = FALSE IF menuBar.show% THEN C% = 1 menuBar.h% = chrHeight% menuBar.b% = Win.h% - chrHeight% PROCmenuBar_build ELSE menuBar.h% = 0 menuBar.b% = Win.h% ENDIF H% = 0 IF Toolbar.show% THEN REPEAT C% += 1 : H% += chrHeight% : UNTIL H% >= Toolbar.bh% Toolbar.h% = H% Toolbar.b% = menuBar.b% - H% Toolbar.bb% = Toolbar.b% + H% / 2 - Toolbar.bh% / 2 Toolbar.bt% = Toolbar.bb% + Toolbar.bh% ELSE Toolbar.h% = 0 Toolbar.b% = Win.h% ENDIF REM C% == height of top border in characters (I.e. combined chr height of menu bar and toolbar) H% += menuBar.h% : REM height of top border in graphic units topBorderBottom% = Win.h% - H% Body.ch% = Win.ch% - C% - ABS(statusBar.show%) * 2 - ABS(hScroll.show%) Body.h% = Body.ch% * chrHeight% Body.cw% = Win.cw% IF vScroll.show% Body.cw% -= 2 Body.w% = Body.cw% * chrWidth% IF Margin.show% THEN Margin.cw% = Margin.digits% + 2 Margin.w% = Margin.cw% * chrWidth% Margin.r% = Margin.w% - chrWidth% / 2 ELSE Margin.cw% = 0 Margin.w% = 0 Margin.r% = 0 ENDIF textArea.cw% = Body.cw% - Margin.cw% REM IF vScroll.show% textArea.cw% -= 1 textArea.cl% = Margin.cw% textArea.cb% = Body.ch% + C% - 1 textArea.cr% = textArea.cl% + textArea.cw% - 1 textArea.ct% = C% bottomBorderTop% = Win.h% - Body.h% - H% IF hScroll.show% THEN hScroll.h% = chrHeight% hScroll.x% = textArea.cl% * chrWidth% hScroll.y% = bottomBorderTop% - chrHeight% - 1 hScroll.w% = textArea.cw% * chrWidth% hScroll.c% = hScroll.y% + chrHeight% / 2 hScroll.sy% = hScroll.c% - chrWidth% / 2 ELSE hScroll.h% = 0 ENDIF IF statusBar.show% statusBar.h% = bottomBorderTop% - hScroll.h% - 1 IF vScroll.show% THEN rightBorderWidth% = Win.w% - Body.w% vScroll.x% = Body.w% vScroll.y% = bottomBorderTop% vScroll.w% = rightBorderWidth% vScroll.h% = Body.h% vScroll.c% = vScroll.x% + vScroll.w% / 2 vScroll.sx% = vScroll.c% - chrWidth% / 2 vScroll.sr% = vScroll.sx% + chrWidth% ELSE rightBorderWidth% = 0 ENDIF ENDPROC DEF PROC_setMousePointer LOCAL X%, Y%, Z% MOUSE X%, Y%, Z% Z% = 0 IF Y% > bottomBorderTop% IF Y% < topBorderBottom% THEN IF X% < Margin.r% THEN Z% = 137 ELSE IF X% < Body.w% Z% = 1 ENDIF ENDIF MOUSE ON Z% ENDPROC DEF PROC_setColourScheme(I%) LOCAL R%,G%,B% ColourScheme% = I% PROCsetPalette(I%) CASE I% OF WHEN PALETTE_LIGHT I% = PAL_BACKGROUND R% = ((46 + 251) / 3) << 1 G% = ((82 + 250) / 3) << 1 B% = ((219 + 249) / 3) << 1 WHEN PALETTE_DARK I% = PAL_VAR R% = (255 + 42) / 3 G% = (255 + 33) / 3 B% = (0 + 28) / 3 ENDCASE textArea.ssh% = R%<<16ORG%<<8ORB% menuBar.hfg& = I% fileMenu.hfg& = I% recentMenu.hfg& = I% editMenu.hfg& = I% utilsMenu.hfg& = I% optionsMenu.hfg& = I% helpMenu.hfg& = I% contxMenu.hfg& = I% ENDPROC DEF PROCsetPalette(I%) CASE I% OF WHEN PALETTE_DARK COLOR PAL_BORDER, 164, 164, 164 COLOR PAL_HIGHLIGHT, 229, 193, 56 COLOR PAL_BACKGROUND, 42, 33, 28 COLOR PAL_FOREGROUND, 189, 174, 157 COLOR PAL_MARGIN, 76, 74, 65 COLOR PAL_EDITLINE, 75, 60, 52 COLOR PAL_DIR, 128, 200, 128 COLOR PAL_DEF, 255, 0, 0 COLOR PAL_KEY, 248, 177, 71 COLOR PAL_STR, 0, 128, 196 COLOR PAL_REM, 128, 128, 128 COLOR PAL_SUB, 255, 128, 0 COLOR PAL_VAR, 255, 255, 255 COLOR PAL_AND, 255, 255, 0 COLOR PAL_NUM, 255, 128, 128 WHEN PALETTE_LIGHT COLOR PAL_BORDER, 164, 164, 164 COLOR PAL_HIGHLIGHT, 46, 82, 219 COLOR PAL_BACKGROUND, 251, 250, 249 COLOR PAL_FOREGROUND, 66, 81, 98 COLOR PAL_MARGIN, 209, 211, 220 COLOR PAL_EDITLINE, 220, 235, 243 COLOR PAL_DIR, 0, 200, 0 COLOR PAL_DEF, 255, 0, 0 COLOR PAL_KEY, 164, 148, 8 COLOR PAL_STR, 0, 128, 196 COLOR PAL_REM, 128, 128, 128 COLOR PAL_SUB, 228, 100, 0 COLOR PAL_VAR, 0, 0, 0 COLOR PAL_AND, 255, 0, 255 COLOR PAL_NUM, 196, 64, 64 REM COLOUR PAL_BORDER, 164, 164, 164 REM COLOUR PAL_HIGHLIGHT, 26, 62, 199 REM COLOUR PAL_BACKGROUND, 213, 222, 227 REM COLOUR PAL_FOREGROUND, 66, 81, 98 REM COLOUR PAL_MARGIN, 179, 181, 190 REM COLOUR PAL_EDITLINE, 180, 195, 203 REM COLOUR PAL_DIR, 60, 128, 60 REM COLOUR PAL_DEF, 255, 0, 0 REM COLOUR PAL_KEY, 208, 137, 31 REM COLOUR PAL_STR, 0, 128, 196 REM COLOUR PAL_REM, 128, 128, 128 REM COLOUR PAL_SUB, 255, 64, 0 REM COLOUR PAL_VAR, 0, 0, 0 REM COLOUR PAL_AND, 255, 64 ,128 REM COLOUR PAL_NUM, 0, 127, 127 WHEN PALETTE_DLG COLOR DLG_PAL_WHITE, &FF, &FF, &FF COLOR DLG_PAL_GREY1, 164, 164, 164 COLOR DLG_PAL_GREY2, 128,128,128 COLOR DLG_PAL_GREY3, 76, 74, 65 COLOR DLG_PAL_TEXT_HIGHLIGHT, 0, 128, 196 COLOR DLG_PAL_ITEM_HIGHLIGHT, 192, 192, 192 ENDCASE ENDPROC REM PROC_drawAll REM ============ REM REM Completely redraws the editor view DEF PROC_drawAll pRedraw%% = ^PROC_drawAll PROC_setMetrics OFF *REFRESH OFF COLOR 128 + PAL_BACKGROUND VDU 4 : VDU 26 : IF POS CLS GCOL PAL_BORDER RECTANGLE FILL Body.w%, 0, rightBorderWidth%, Win.h% RECTANGLE FILL 0, -1, Win.w%, bottomBorderTop% PROCmenuBar_draw PROCtoolbar_draw PROCmargin_draw REM * recalculate the text area bottom line botLine% = topLine% + Body.ch% - 1 IF lineSelect.anc% THEN PROCtextArea_draw(topLine%, 0) ELSE REM * clear string selection IF stringSelect.index% PROCstringSelect_clear REM * make sure the carrot is within the text area IF Edit.carrot% > Start% + textArea.cw% - 2 Edit.carrot% = Start% + textArea.cw% - 2 REM * make sure the edit line is within the text area by moving the text area rather than the edit line IF Edit.line% > botLine% THEN PROCtextArea_draw(Edit.line% - Body.ch% + 1, 0) ELSE PROCtextArea_draw(topLine%, 0) ENDIF REM * render the edit line PROCeditLine_draw ENDIF PROCstatusBar_draw PROCvscroll_draw PROChscroll_draw IF lineSelect.anc% == 0 ON *REFRESH ON PROC_setMousePointer ENDPROC REM Syntactic sugar for calling all the draw functions DEF PROC_refreshAll PROCtextArea_draw(topLine%, 0) PROCmargin_draw PROChscroll_draw PROCvscroll_draw PROCstatusBar_draw PROCtoolbar_draw IF lineSelect.anc% == 0 PROCeditLine_draw ENDPROC (_) DEF PROCfnList_drawToolbar(I%, first_menu%, last_menu%, nmenus%) LOCAL tb{}, N%, P% DIM tb{b%, h%, ch%, bb%, lb%, sx%} REM .b% toolbar bottom (gfx units) REM .h% toolbar height (gfx units) REM .ch% toolbar height (chrs) REM .bb% button bottom (gfx units) REM .lb% left most button (gfx units) REM .sx% x spacing between buttons (gfx units) N% = 9 tb.ch% = I% tb.h% = tb.ch% * chrHeight% tb.b% = Win.h% - tb.h% + 2 I% = tb.b% MOD 2 tb.b% -= I% tb.h% += I% tb.bb% = Win.h% - (tb.h% / 2) - (Toolbar.bh% / 2) tb.bb% += tb.bb% MOD 2 tb.sx% = chrWidth% tb.lb% = Win.w% - ( N% * (Toolbar.bh% + tb.sx%) ) CASE ColourScheme% OF WHEN PALETTE_DARK : P% = PAL_HIGHLIGHT WHEN PALETTE_LIGHT : P% = PAL_EDITLINE ENDCASE FOR I% = 1 TO N% fnListBtns{(I%)}.l% = tb.lb% + ( (I% - 1) * (Toolbar.bh% + tb.sx%) ) fnListBtns{(I%)}.b% = tb.bb% fnListBtns{(I%)}.r% = fnListBtns{(I%)}.l% + Toolbar.bh% fnListBtns{(I%)}.t% = fnListBtns{(I%)}.b% + Toolbar.bh% fnListBtns{(I%)}.tt.bg& = P% NEXT REM set button states IF fnList.includeOn% I% = BUTTON_STATE_INON ELSE I% = BUTTON_STATE_OUTON fnListBtns{(FLIST_BUTTON_ION)}.state& = I% IF fnList.includeLabels% I% = BUTTON_STATE_INON ELSE I% = BUTTON_STATE_OUTON fnListBtns{(FLIST_BUTTON_ILAB)}.state& = I% IF fnList.stripKeywords% I% = BUTTON_STATE_INON ELSE I% = BUTTON_STATE_OUTON fnListBtns{(FLIST_BUTTON_STRIP)}.state& = I% IF fnList.sort% I% = BUTTON_STATE_INON ELSE I% = BUTTON_STATE_OUTON fnListBtns{(FLIST_BUTTON_SORT)}.state& = I% IF first_menu% == 1 I% = BUTTON_STATE_OUTOFF ELSE I% = BUTTON_STATE_OUTON fnListBtns{(FLIST_BUTTON_BACK)}.state& = I% IF last_menu% == nmenus% I% = BUTTON_STATE_OUTOFF ELSE I% = BUTTON_STATE_OUTON fnListBtns{(FLIST_BUTTON_NEXT)}.state& = I% *REFRESH OFF GCOL PAL_BORDER IF SDL% AND &F P% = 0 ELSE P% = 2 RECTANGLE FILL 0, tb.b% - P%, Win.w%, tb.h% + P% PROCbgroup_tt_reset PROCbgroup_draw(fnListBtns{()}) ENDPROC DEF PROCfnList_addLine(L%, l{()}, RETURN I%) LOCAL line$, J% IF Lowercase% THEN IF LEFT$(Line$(L%), 3) == "def" J% = TRUE ELSE IF LEFT$(Line$(L%), 3) == "DEF" J% = TRUE ENDIF IF J% THEN line$ = FNtok(Line$(L%)) + CHR$&D I% += 1 l{(I%)}.line% = L% l{(I%)}.name$ = FNdefName(PTR(line$)) IF LENl{(I%)}.name$ THEN IF fnList.stripKeywords% THEN IF INSTR( "FN:fn", LEFT$(l{(I%)}.name$, 2) ) THEN l{(I%)}.name$ = MID$(l{(I%)}.name$, 3) ELSE IF INSTR( "PROC:fn", LEFT$(l{(I%)}.name$, 4) ) l{(I%)}.name$ = MID$(l{(I%)}.name$, 5) ENDIF ENDIF l{(I%)}.fg& = PAL_SUB ELSE l{(I%)}.fg& = PAL_VAR ENDIF ENDPROC ENDIF IF fnList.includeLabels% IF LEFT$(Line$(L%), 1) == "(" THEN line$ = MID$( LEFT$( Line$(L%), INSTR(Line$(L%), ")") - 1 ), 2 ) IF line$ == "" ENDPROC IF fnList.sort% THEN REM don't include spacer labels FOR J% = 1 TO LEN line$ IF INSTR("_-", MID$(line$, J%, 1)) == 0 EXIT FOR NEXT IF J% > LEN line$ ENDPROC ENDIF I% += 1 l{(I%)}.name$ = line$ l{(I%)}.line% = L% l{(I%)}.fg& = PAL_DEF ENDPROC ENDIF LOCAL J% IF fnList.includeOn% THEN line$ = FNtok(Line$(L%)) + CHR$ &D J% = FNonEventStatement(line$, INSTR(line$, CHR$ KEYWORD_ON)) IF J% THEN I% += 1 l{(I%)}.line% = L% l{(I%)}.name$ = "ON " + K$(J%) l{(I%)}.fg& = PAL_KEY ENDIF ENDIF ENDPROC REM insertion sort the slow way DEF PROCfnList_sort(l{()}, lsize%) IF lsize% < 2 ENDPROC LOCAL I%, J%, K% FOR I% = 1 TO lsize% - 1 FOR J% = I% + 1 TO 2 STEP -1 K% = J% - 1 IF l{(K%)}.name$ > l{(J%)}.name$ SWAP l{(K%)}, l{(J%)} ELSE EXIT FOR NEXT NEXT ENDPROC REM C% = TRUE to enable context menu fnlist DEF PROCfnList_buildList(C%) DEF PROCfnList_buildList : LOCAL C% PROCeditLine_save LOCAL I%, L%, l{()}, lsize% DIM l{(lastLine%)name$, line%, fg&} REM build list FOR L% = 1 TO lastLine% PROCfnList_addLine(L%, l{()}, lsize%) NEXT IF fnList.sort% PROCfnList_sort(l{()}, lsize%) FOR L% = 1 TO lsize% IF LENl{(L%)}.name$ I% += 1 NEXT REM can we fit the full list on the screen IF C% IF Win.ch% DIV fnList.rowChrHeight% > I% + 5 THEN IF I% < lsize% THEN I% = 0 FOR L% = 1 TO lsize% IF LENl{(L%)}.name$ THEN I% += 1 l{(I%)}.name$ = l{(L%)}.name$ l{(I%)}.line% = l{(L%)}.line% l{(I%)}.fg& = l{(L%)}.fg& ENDIF NEXT lsize% = I% ENDIF REM show function list as a context menu PROCfnList_openContx(l{()}, lsize%) ELSE REM show function list as multiple menus REPEAT IF lsize% == 0 ENDPROC I% = FNfnList_buildMenus(l{()}, lsize%) IF I% THEN REM rebuild list lsize% = 0 FOR L% = 1 TO lastLine% : PROCfnList_addLine(L%, l{()}, lsize%) : NEXT IF fnList.sort% PROCfnList_sort(l{()}, lsize%) ENDIF UNTIL Win.resized% == FALSE AND I% == 0 ENDIF ENDPROC REM Returns non-zero to indicate that the fnlist needs rebuilding REM Returns 0 to indicate fnlist should close because a menu item was selected or the close button was clicked or a menu can't be displayed REM Returns 0 if the window was resized DEF FNfnList_buildMenus(l{()}, lsize%) LOCAL tb_ch% LOCAL m{()}, nmenus%, max_menu_size%, first_menu%, last_menu% LOCAL L%, M%, I% PROC_setMetrics REM find toolbar chr height REPEAT tb_ch% += 1 : I% += chrHeight% : UNTIL I% >= Toolbar.bh% REM how many items can each menu contain max_menu_size% = (Win.ch% - tb_ch% - (2 * fnList.rowChrHeight%)) / fnList.rowChrHeight% REM how many menus are needed nmenus% = lsize% DIV max_menu_size% IF lsize% MOD max_menu_size% nmenus% += 1 REM build menus DIM m{(nmenus%) \ \ l%,b%,r%,t%,w%,h%,cl%,cb%,cr%,ct%,bg&,hbg&,hfg&,\ \ items%,rows%,first%,last%,selected%,longestLHS%,longestRHS%, \ \ tx%,tyOffset%,hx%,hw%,textWidth%,rowChrHeight%,rh%,sbg&,sfg&,ofg&,over%%, \ \ item$(max_menu_size%),lhs$(max_menu_size%),rhs$(max_menu_size%),flag&(max_menu_size%),fg&(max_menu_size%),ico%%(max_menu_size%), \ \ line%(max_menu_size%),cw%} REM find the longest name for each menu I% = 0 M% = 1 FOR L% = 1 TO lsize% I% += 1 IF I% > max_menu_size% M% += 1 : I% = 1 m{(M%)}.longestLHS% = FNmax( LEN l{(L%)}.name$, m{(M%)}.longestLHS% ) NEXT REM populate menu structures I% = max_menu_size% : REM menu item M% = 0 : REM menu pointer FOR L% = 1 TO lsize% I% += 1 IF I% > max_menu_size% THEN IF M% m{(M%)}.items% = I% - 1 M% += 1 : m{(M%)}.bg& = PAL_MARGIN m{(M%)}.hbg& = PAL_STR IF ColourScheme% == PALETTE_LIGHT m{(M%)}.hfg& = PAL_BACKGROUND ELSE m{(M%)}.hfg& = PAL_VAR : m{(M%)}.rowChrHeight% = fnList.rowChrHeight% m{(M%)}.rh% = m{(M%)}.rowChrHeight% * chrHeight% m{(M%)}.tyOffset% = (m{(M%)}.rh% + chrHeight%) / 2 m{(M%)}.sbg& = PAL_BORDER m{(M%)}.sfg& = PAL_MARGIN : I% = 1 ENDIF m{(M%)}.item$(I%) = l{(L%)}.name$ m{(M%)}.line%(I%) = l{(L%)}.line% m{(M%)}.fg&(I%) = l{(L%)}.fg& NEXT m{(M%)}.items% = I% REM compute chr width of each menu FOR M% = 1 TO nmenus% : m{(M%)}.cw% = m{(M%)}.longestLHS% + 6 : NEXT I% = 1 REPEAT CASE I% OF WHEN 1 first_menu% = last_menu% + 1 I% = 0 : REM count number of menus that can be displayed L% = 0 : REM count combined chr width of menus to display FOR M% = first_menu% TO nmenus% L% += m{(M%)}.cw% IF Win.cw% - L% >= 2 I% += 1 ELSE EXIT FOR NEXT last_menu% = first_menu% + I% - 1 WHEN -1 last_menu% = first_menu% - 1 I% = 0 : REM count number of menus that can be displayed L% = 0 : REM count combined chr width of menus to display M% = last_menu% WHILE M% L% += m{(M%)}.cw% IF Win.cw% - L% >= 2 I% += 1 ELSE EXIT WHILE M% -= 1 ENDWHILE first_menu% = last_menu% - I% + 1 WHEN 2 :=TRUE : REM rebuild list ENDCASE I% = FNfnList_openMenus(m{()}, nmenus%, first_menu%, last_menu%, tb_ch%) PROCsetPalette(ColourScheme%) UNTIL I% == 0 =0 REM Returns -1 to indicate back/previous menu set REM Returns 1 to indicate next menu set REM Returns 2 to indicate that the fnlist needs rebuilding REM Returns 0 to indicate fnlist should close because a menu item was selected or the close button was clicked or a menu can't be displayed REM Returns 0 if the window was resized DEF FNfnList_openMenus(m{()}, nmenus%, first_menu%, last_menu%, tb_ch%) LOCAL selected{} LOCAL I%, J%, N%, M%, A%, B% REM draw background OFF *REFRESH OFF VDU 26 : IF POS COLOR 128 + PAL_MARGIN CLS REM draw toolbar PROCfnList_drawToolbar(tb_ch%, first_menu%, last_menu%, nmenus%) REM open the menus A% = 1 FOR M% = first_menu% TO last_menu% IF M% > first_menu% A% += m{(M% - 1)}.cw% IF NOT FNmenu_open(m{(M%)}, A%, tb_ch%, m{(M%)}.cw%, 0, fnList.rowChrHeight%) :=0 NEXT MOUSE ON 0 DIM selected{menu%, item%, button%} pRedraw%% = 0 Win.resized% = FALSE *REFRESH ON *REFRESH M% = first_menu% REPEAT I% = FNfnList_pollMenus(m{(M%)}, m{()}, selected{}, A%, B%, first_menu%, last_menu%, M%) IF I% THEN REM change menu N% = M% IF ABS(I%) == 2 THEN REM using mouse I% = SGN(I%) MOUSE A%, B%, J% WHILE (A% < m{(N%)}.l% OR A% > m{(N%)}.r%) AND N% + I% >= first_menu% AND N% + I% <= last_menu% N% += I% MOUSE A%, B%, J% ENDWHILE ELSE REM using keyboard CASE I% OF WHEN -1 IF M% == first_menu% IF first_menu% > 1 :=-1 IF M% > first_menu% N% = M% - 1 WHEN 1 IF M% == last_menu% IF last_menu% < nmenus% :=1 IF M% < last_menu% N% = M% + 1 ENDCASE ENDIF IF N% <> M% THEN J% = m{(M%)}.selected% REM reset previous menu m{(M%)}.selected% = 0 PROCmenu_draw(m{(M%)}) REM set focus on new menu M% = N% IF J% > m{(M%)}.items% J% = m{(M%)}.items% PROCmenu_selectItem(m{(M%)}, J%) ENDIF ELSE REM was a button selected? IF selected.button% THEN CASE selected.button% OF WHEN FLIST_BUTTON_CLOSE WHEN FLIST_BUTTON_NEXT :=1 WHEN FLIST_BUTTON_BACK :=-1 WHEN FLIST_BUTTON_ION fnList.includeOn% EOR= TRUE IF fnList.includeOn% fnList.sort% = FALSE PROCoptions_save :=2 WHEN FLIST_BUTTON_ILAB fnList.includeLabels% EOR= TRUE PROCoptions_save :=2 WHEN FLIST_BUTTON_STRIP fnList.stripKeywords% EOR= TRUE PROCoptions_save :=2 WHEN FLIST_BUTTON_SORT fnList.sort% EOR= TRUE IF fnList.sort% fnList.includeOn% = FALSE PROCoptions_save :=2 ENDCASE ELSE REM was a menu item selected? IF selected.item% THEN PROCback_set M% = selected.menu% PROCmenu_flashSelection(m{(M%)}, selected.item%) REM make sure no lines or strings are selected REM this might happen if the function list was opened from the contxMenu *REFRESH OFF IF lineSelect.anc% PROClineSelect_clear IF stringSelect.index% PROCstringSelect_clear REM set new top line and edit line N% = m{(M%)}.line%(selected.item%) topLine% = N% WHILE topLine% + Body.ch% - 1 > lastLine% AND topLine% > 1 : topLine% -= 1 : ENDWHILE Start% = 1 PROCeditLine_set(N%, 0) ENDIF ENDIF ENDIF UNTIL I% == 0 =0 REM Returns -1 to indicate change to previous menu by cursor keys REM Returns 1 to indicate change to next menu by cursor keys REM Returns 0 to indicate fnlist should close because a menu item was selected or the close button was clicked REM Returns 0 if the window was resized DEF FNfnList_pollMenus(m{}, m{()}, RETURN selected{}, RETURN A%, RETURN B%, first_menu%, last_menu%, this_menu%) LOCAL I%, K%, X%, Y%, O%, click% ON MOUSE LOCAL click% = FNfnList_click(@wparam%, @lparam%, m{()}, selected{}, first_menu%, last_menu%) : RETURN REPEAT REPEAT IF click% :=0 K% = INKEY(1) MOUSE X%, Y%, I% IF A% == X% IF B% == Y% THEN ELSE A% = X% : B% = Y% IF Y% < m.t% THEN IF O% PROCbgroup_rollOver(fnListBtns{()}, O%, 0) IF X% > m.l% IF X% < m.r% THEN I% = FNmenu_itemFromMouseY(m{}, Y%) IF m.selected% <> I% PROCmenu_selectItem(m{}, I%) ELSE IF X% > m.r% THEN IF this_menu% < last_menu% :=2 ELSE IF m.selected% PROCmenu_selectItem(m{}, 0) ENDIF IF X% < m.l% THEN IF this_menu% > first_menu% :=-2 ELSE IF m.selected% PROCmenu_selectItem(m{}, 0) ENDIF ENDIF ELSE I% = FNbgroup_buttonAt(fnListBtns{()}, X%, Y%) IF I% <> O% PROCbgroup_rollOver(fnListBtns{()}, O%, I%) ENDIF ENDIF UNTIL K% <> -1 OR Win.resized% == TRUE CASE K% OF WHEN 13 : IF m.selected% selected.item% = m.selected% : selected.menu% = this_menu% :=0 WHEN 27 : =0 WHEN 136 : PROCbgroup_tt_clear : =-1 WHEN 137 : PROCbgroup_tt_clear : =1 WHEN 140 : PROCmenu_scrollDown(m{}) WHEN 141 : PROCmenu_scrollUp(m{}) WHEN 138 : PROCbgroup_tt_clear : PROCmenu_cursorDown(m{}) WHEN 139 : PROCbgroup_tt_clear : PROCmenu_cursorUp(m{}) ENDCASE UNTIL Win.resized% =0 DEF FNfnList_click(W%, L%, m{()}, RETURN selected{}, first_menu%, last_menu%) REM make sure left button was used IF W% <> 1 :=FALSE REM coords of mouse click in graphic units LOCAL X%, Y% X% = (L% AND &FFFF) * 2 - @vdu.o.x% Y% = (@vdu%!212 - 1 - (L% >>> 16)) * 2 - @vdu.o.y% REM has one of the buttons been clicked on? L% = FNbgroup_buttonAt(fnListBtns{()}, X%, Y%) IF L% selected.menu% = 0 : selected.item% = 0 : selected.button% = L% :=TRUE REM has one of the menus been clicked on? IF Y% < m{(first_menu%)}.t% THEN FOR W% = first_menu% TO last_menu% IF X% > m{(W%)}.l% IF X% < m{(W%)}.r% THEN REM which item has been clicked on? L% = FNmenu_itemFromMouseY(m{(W%)}, Y%) IF L% selected.menu% = W% : selected.item% = L% : selected.button% = 0 :=TRUE ENDIF NEXT ENDIF =FALSE DEF PROCfnList_openContx(l{()}, lsize%) LOCAL I%, J%, X%, Y%, m{}, N%, A% Win.resized% = FALSE A% = 3 : REM the number of menu items before the fn/proc list, including: 'Paste', 'Go Back' and the seperator N% = lsize% + A% DIM m{ \ \ l%,b%,r%,t%,w%,h%,cl%,cb%,cr%,ct%,bg&,hbg&,hfg&,\ \ items%,rows%,first%,last%,selected%,longestLHS%,longestRHS%, \ \ tx%,tyOffset%,hx%,hw%,textWidth%,rowChrHeight%,rh%,sbg&,sfg&,ofg&,over%%, \ \ item$(N%),lhs$(N%),rhs$(N%),flag&(N%),fg&(N%),ico%%(N%), \ \ line%(N%),button&(N%),button&} REM find the longest name (make sure it is no shorter than "Go Back") J% = 7 : FOR I% = 1 TO lsize% : J% = FNmax(J%, LEN l{(I%)}.name$) : NEXT m.items% = N% m.bg& = PAL_MARGIN m.hbg& = PAL_STR m.longestLHS% = J% m.rowChrHeight% = fnList.rowChrHeight% m.rh% = m.rowChrHeight% * chrHeight% m.tyOffset% = (m.rh% + chrHeight%) / 2 m.sbg& = PAL_MARGIN m.sfg& = PAL_BORDER m.ofg& = PAL_REM IF ColourScheme% == PALETTE_LIGHT THEN m.hfg& = PAL_BACKGROUND m.fg&(1) = 0 m.fg&(2) = 0 ELSE m.hfg& = PAL_VAR m.fg&(1) = PAL_BORDER m.fg&(2) = PAL_BORDER ENDIF m.item$(1) = "Paste" m.flag&(1) = (FNclipboard_hasText == 0) AND MENU_ITEM_OFF m.item$(2) = "Go Back" m.flag&(2) = (backTotal% == 0) AND MENU_ITEM_OFF m.fg&(3) = PAL_BORDER IF N% > A% THEN FOR I% = A% + 1 TO N% J% = I% - A% m.item$(I%) = l{(J%)}.name$ m.line%(I%) = l{(J%)}.line% m.fg&(I%) = l{(J%)}.fg& NEXT ENDIF REM find the character x and y position of the mouse MOUSE X%, Y%, I% X% /= chrWidth% Y% = (Win.h% - Y%) / chrHeight% X% -= 1 IF X% < 0 X% = 0 Y% -= 1 IF Y% < 0 Y% = 0 WHILE X% > 0 AND Win.cw% - X% < m.longestLHS% + 6 X% -= 1 ENDWHILE WHILE Y% > 0 AND (Win.ch% - Y%) DIV fnList.rowChrHeight% < N% + 2 Y% -= 1 ENDWHILE IF FNmenu_open(m{}, X%, Y%, 0, 0, fnList.rowChrHeight%) THEN I% = FNcontxMenu_poll(m{}) CASE I% OF WHEN 0 WHEN 1 : PROC_paste WHEN 2 : PROCback_go OTHERWISE REM set new top line and edit line PROCback_set topLine% = m.line%(I%) WHILE topLine% + Body.ch% - 1 > lastLine% AND topLine% > 1 : topLine% -= 1 : ENDWHILE Start% = 1 PROCeditLine_set(m.line%(I%), 0) ENDCASE ENDIF ENDPROC (_) DEF PROCfr_open IF lineSelect.anc% ENDPROC PRIVATE dlg%% LOCAL lom%(), lo$(), lo%() LOCAL W%, E%, I%, J% W% = @vdu%!216 E% = 8 : REM number of dialogue items DIM lom%(11), lo$(E%, 4), lo%(E%, 3) lom%() = 0,0, 4,4,4,4, 8*W%,2*@vdu%!220, 8,8, 1,E% lo$() = "","","","","", \ \ "fsb","","",STR$(14 * W%),"", \ \ "feb","#right","#",STR$(30 * W%),"", \ \ "rsb","","#below+","=[fsb]","", \ \ "reb","#right","#","=[feb]","", \ \ "ccb","","#below",STR$(17 * W%),"", \ \ "wcb","#right","#","#","", \ \ "opb","@right","#below","","", \ \ "cpb","#left","#","","" FORI%=1TOE%:FORJ%=0TO3:SWAPlo$(I%,J%),lo$(I%,J%+1):NEXT:NEXT PROCdlg_lo_resolve(lom%(), lo$(), lo%(), TRUE) IF dlg%% THEN REM init dialogue size dlg%%!8 = lom%(0) * 2 dlg%%!12 = lom%(1) * 2 FORI%=1TOE%:PROCdlg_setItemPos_(dlg%%,I%,lo%()):NEXT ELSE dlg%% = FNdlg_new(lom%(0), lom%(1), DLG_CENTRE, "Edit Find/Replace Strings") PROCstaticbox_new_(dlg%%, 1, lo%(), DLG_ITEM_TEXT_ALIGN_RIGHT, "Find what:") PROCeditbox_new_(dlg%%, 2, lo%(), 0) PROCstaticbox_new_(dlg%%, 3, lo%(), DLG_ITEM_TEXT_ALIGN_RIGHT, "Replace with:") PROCeditbox_new_(dlg%%, 4, lo%(), 0) PROCcheckbox_new_(dlg%%, 5, lo%(), DLG_ITEM_TEXT_ALIGN_CENTRE, dlgCheckboxIcons%%, "Match case") PROCcheckbox_new_(dlg%%, 6, lo%(), DLG_ITEM_TEXT_ALIGN_CENTRE, dlgCheckboxIcons%%, "Match word") PROCpushbutton_new_(dlg%%, 8, lo%(), 0, "Cancel") PROCpushbutton_new_(dlg%%, 7, lo%(), DLG_ITEM_DEFAULT, "OK") ENDIF REM init dialogue contents PROCsetPalette(PALETTE_DLG) PROCdlg_draw(dlg%%,0,0) IF stringSelect.index% FR.find$ = stringSelect.text$ PROCdlg_setItemText(dlg%%, 2, FR.find$) PROCdlg_setItemText(dlg%%, 4, FR.replace$) PROCdlg_checkItem(dlg%%, 5, FR.matchCase%) PROCdlg_checkItem(dlg%%, 6, FR.matchWord%) PROCdlg_setFocus(dlg%%, 2) REPEAT I% = FNdlg_poll(dlg%%) CASE I% OF WHEN -1, 7 FR.find$ = FNdlg_getItemText(dlg%%, 2) FR.replace$ = FNdlg_getItemText(dlg%%, 4) FR.matchCase% = FNdlg_isItemChecked(dlg%%, 5) FR.matchWord% = FNdlg_isItemChecked(dlg%%, 6) WHEN -2, 8 REM close / cancel WHEN -3 REM window resized PROC_move OTHERWISE I% = 0 ENDCASE UNTIL I% PROCdlg_close(dlg%%) PROCsetPalette(ColourScheme%) ENDPROC REM PROCfr_findNext REM REM Searches program from current edit line and carrot index REM If a string is selected it is cleared (unselected) REM The current edit line is saved if flagged as modified REM Everything is redrawn as required DEF PROCfr_findNext IF lineSelect.anc% ENDPROC IF stringSelect.index% FR.find$ = stringSelect.text$ IF FR.find$ == "" ENDPROC PRIVATE last_search{} DIM last_search{ \ \ find$, \ string searched for in previous find operation \ startLine%, \ line from which previous started \ chrIndex%, \ character index from which previous find operation started \ failed% \ TRUE if previous find operation failed \ } LOCAL L%, S%, I% REM clear currently selected string IF stringSelect.index% PROCstringSelect_clear REM save changes to edit line PROCeditLine_save REM new search from edit line S% = Edit.line% I% = Edit.carrot% + 1 - lineIndent&(Edit.line%) : REM search first line from this character IF last_search.failed% IF last_search.find$ == FR.find$ IF last_search.startLine% == S% IF last_search.chrIndex% == I% THEN REM repeat search from start of program S% = 1 I% = 0 ENDIF last_search.find$ = FR.find$ last_search.startLine% = S% last_search.chrIndex% = I% L% = FNfr_search(S%, I%) IF L% THEN REM set the edit line to the line on which the find string has been found PROCeditLine_set(L%, 0) REM logically select the string PROCstringSelect_range(I% + lineIndent&(L%), LEN FR.find$) REM place the edit line carrot at the end of the found/selected string Edit.carrot% = stringSelect.carrotExt% REM make sure the end of the selected text will be visible by moving the text area left if required IF Edit.carrot% > Start% + textArea.cw% - 2 Start% = Edit.carrot% - textArea.cw% + 2 REM make sure the found string is not off to the left of the text area S% = Start% - stringSelect.index% : REM S% = number of characters of selected string that are off to the left of the text area IF S% > 0 THEN REM the start of the found string is off to the left of the text area REM but is their room to scroll the selected text right? I% = stringSelect.index% + LEN stringSelect.text$ - 1 : REM I% = index of selected text final character I% -= Start% : REM I% = index of final character within text area (0 to textArea.cw% - 1) I% = (textArea.cw% - 2) - I% : REM I% = number of characters the text can move to the right IF I% > 0 THEN IF I% > S% I% = S% : REM don't move to the right more than the number of characters overhanging to the left Start% -= I% ENDIF ENDIF REM redraw PROCtextArea_draw(FNtextArea_topLineToShow(Edit.line%), 0) PROCmargin_draw PROChscroll_draw PROCvscroll_draw PROCstatusBar_draw PROCtoolbar_draw PROCeditLine_draw last_search.failed% = FALSE ELSE REM nothing found IF NOT FR.replaceAll% THEN LOCAL t$ PROCmsgline_title(t$, "Not Found!") PROCmsgline_add(t$, CHR$0 + "Can't find...", "C") PROCmsgline_add(t$, CHR$0 + """" + FR.find$ + """", "Cblue") PROCmsgline_add(t$, CHR$0 + "when searching from line " + STR$ S%, "C") IFFNmsgwin(t$, MSGWIN_INFO) PROC_drawAll ENDIF last_search.failed% = TRUE ENDIF ENDPROC DEF PROCfr_replaceNext IF FR.find$ == "" ENDPROC IF lineSelect.anc% : ENDPROC REM nothing is selected so perform a find IF stringSelect.index% == 0 PROCfr_findNext : ENDPROC REM save undo state IF NOT FR.replaceAll% PROCundo_save(Edit.line%) REM text is selected so perform the replace Edit.text$ = LEFT$(Edit.text$, stringSelect.index% - 1) + \ \ FR.replace$ + \ \ MID$(Edit.text$, stringSelect.index% + LEN stringSelect.text$) REM mark edit line as modified Edit.modified% = TRUE fileModified% = TRUE REM position the carrot at the end of the replaced string Edit.carrot% = stringSelect.index% + LEN FR.replace$ - 1 REM make sure the end of the replaced string will be visible by moving the text area left if required IF Edit.carrot% > Start% + textArea.cw% - 2 Start% = Edit.carrot% - textArea.cw% + 2 REM calling _findNext will also have the desired effect of: REM logically clearing the string selection REM redrawing the text area PROCfr_findNext ENDPROC DEF PROCfr_replaceAll IF FR.find$ == "" ENDPROC IF lineSelect.anc% ENDPROC LOCAL R%, S%, t$ REM save undo state PROCundo_save(Edit.line%) FR.replaceAll% = TRUE S% = Edit.line% REPEAT IF stringSelect.index% R% += 1 PROCfr_replaceNext UNTIL stringSelect.index% == 0 VDU 7 IF R% THEN PROCmsgline_title(t$, "Replace All") PROCmsgline_add(t$, CHR$0 + "Replaced " + STR$ R% + " occurances of", "C") PROCmsgline_add(t$, CHR$0 + """" + FR.find$ + """", "Cblue") PROCmsgline_add(t$, CHR$0 + "with", "C") PROCmsgline_add(t$, CHR$0 + """" + FR.replace$ + """", "Cblue") IFFNmsgwin(t$, MSGWIN_INFO) ELSE PROCmsgline_title(t$, "Not Found!") PROCmsgline_add(t$, CHR$0 + "Can't find...", "C") PROCmsgline_add(t$, CHR$0 + """" + FR.find$ + """", "Cblue") PROCmsgline_add(t$, CHR$0 + "when searching from line " + STR$ S%, "C") IFFNmsgwin(t$, MSGWIN_INFO) ENDIF FR.replaceAll% = FALSE ENDPROC REM Searches the program for FR.find$, REM Searches from the given line and character index to the end of the program. REM Returns the line number and character index of the found string (if any) REM Returns 0 if nothing found REM I.e: foundAtLineNumber = FNfr_search(searchFromLineNumber, searchFromChrIndex --> RETURN foundAtChrIndex) DEF FNfr_search(L%, RETURN I%) FOR L% = L% TO lastLine% IF FR.matchCase% THEN I% = INSTR(Line$(L%), FR.find$, I%) ELSE I% = FN_instri(Line$(L%), FR.find$, I%) ENDIF IF I% THEN IF FR.matchWord% THEN IF I% == 1 OR FNisAlphabetic(ASC MID$(Line$(L%), I% - 1, 1)) == FALSE THEN IF NOT FNisAlphabetic(ASC MID$(Line$(L%), I% + LEN FR.find$, 1)) :=L% ENDIF ELSE =L% ENDIF ENDIF I% = 0 : REM search next line from this character NEXT =0 (_) DEF FN_unsavedWorkOK IF NOT fileModified% :=TRUE LOCAL t$ PROCmsgline_title(t$, "Unsaved Work!") PROCmsgline_add(t$, CHR$0 + "Save current changes in """ + Basename$ + """ ?", "C") CASE FNmsgwin(t$, MSGWIN_WARNING + MSGWIN_YESNOCANCEL) OF WHEN 1 : PROC_save :=(Dirname$ <> "") WHEN 2 :=TRUE ENDCASE =FALSE DEF PROC_noRoom LOCAL t$ PROCmsgline_title(t$, "No Room!") PROCmsgline_add(t$, CHR$0 + "There is not enough room to insert the program line(s).", "C") PROCmsgline_add(t$, Prog.name$ + " starts with space for " + STR$ MAX_PROG_SIZE + " lines.", "C") IFFNmsgwin(t$, MSGWIN_STOP) PROC_drawAll ENDPROC (_) REM PROCundo_save() REM =============== REM REM Saves the state of the program REM REM Parameter Summary REM ~~~~~~~~~~~~~~~~~ REM REM A% : save the state of all lines from the given line number. REM a value of 0 will result in just the edit line, text area and selection data being saved. DEF PROCundo_redo : LOCAL A% : A% = 1 DEF PROCundo_save(A%) : Redo.ptr% = 0 LOCAL P% Undo.ptr% += 1 IF Undo.ptr% > UndoMax% Undo.ptr% = 1 IF Undo.count% < UndoMax% Undo.count% += 1 P% = Undo.ptr% Undo.line%(P%) = A% IF A% > 0 PROCstate_saveLinesFrom(A%, "u" + STR$ P%) PROCstate_saveVars(undoStateVars{(P%)}) A% = Edit.line% Undo.t$(P%, 0) = Edit.text$ Undo.t$(P%, 1) = stringSelect.text$ Undo.t$(P%, 2) = Line$(A%) Undo.t$(P%, 3) = lineColour$(A%) Undo.i&(P%, 0) = lineIndent&(A%) Undo.i&(P%, 1) = lineIndentSelf&(A%) Undo.i&(P%, 2) = lineNumberL&(A%) Undo.i&(P%, 3) = lineNumberH&(A%) Undo.i%(P%) = lineIndentNext%(A%) ENDPROC REM PROCundo_restore REM ================ REM REM Restores the program to the last state saved with PROCundo_save() REM It first sets up a redo restore point. DEF PROCundo_restore IF Undo.count% == 0 ENDPROC LOCAL A%, P%, L% REM save the current state for redo Redo.ptr% += 1 P% = Redo.ptr% PROCstate_saveVars(redoStateVars{(P%)}) Redo.t$(P%, 0) = Edit.text$ Redo.t$(P%, 1) = stringSelect.text$ PROCstate_saveLinesFrom(1, "r" + STR$ P%) REM restore saved state L% = lastLine% : REM make a note of the current lastLine value as it might be needed later P% = Undo.ptr% PROCstate_restoreVars(undoStateVars{(P%)}) A% = Edit.line% Edit.text$ = Undo.t$(P%, 0) stringSelect.text$ = Undo.t$(P%, 1) Line$(A%) = Undo.t$(P%, 2) lineColour$(A%) = Undo.t$(P%, 3) lineIndent&(A%) = Undo.i&(P%, 0) lineIndentSelf&(A%) = Undo.i&(P%, 1) lineNumberL&(A%) = Undo.i&(P%, 2) lineNumberH&(A%) = Undo.i&(P%, 3) lineIndentNext%(A%) = Undo.i%(P%) A% = Undo.line%(P%) IF A% > 0 THEN PROCstate_restoreLinesTo(A%, "u" + STR$ P%) ELSE IF A% < 0 THEN SWAP lastLine%, L% : REM set lastLine% to the value it was before state variables were restored CASE A% OF WHEN UNDO_STATE_DELETE_BLANK_LINE_ABOVE P% = Edit.line% - 1 PROClines_insertBefore(P%, 1) Line$(P%) = "" lineColour$(P%) = "" lineIndent&(P%) = lineIndent&(P% - 1) + lineIndentNext%(P% - 1) lineIndentNext%(P%) = 0 lineIndentSelf&(P%) = 0 lineNumberL&(P%) = 0 lineNumberH&(P%) = 0 WHEN UNDO_STATE_INSERT_BLANK_LINE_ABOVE PROClines_deleteFrom(Edit.line%, 1) WHEN UNDO_STATE_INSERT_BLANK_LINE_BELOW PROClines_deleteFrom(Edit.line% + 1, 1) OTHERWISE ERROR 100, "Invalid undo code" ENDCASE REM#assert IF lastLine% <> L% ERROR 100, "Undo error" ELSE PROClines_setIndentFrom(Edit.line%) ENDIF ENDIF Undo.count% -= 1 IF Undo.count% THEN Undo.ptr% -= 1 : IF Undo.ptr% < 1 Undo.ptr% = UndoMax% ELSE Undo.ptr% = 0 ENDIF fileModified% = TRUE ENDPROC REM PROCredo_restore REM ================ REM REM Restores the program from the last state saved when PROCundo_restore was called. DEF PROCredo_restore IF Redo.ptr% == 0 ENDPROC LOCAL P% PROCundo_redo P% = Redo.ptr% PROCstate_restoreVars(redoStateVars{(P%)}) Edit.text$ = Redo.t$(P%, 0) stringSelect.text$ = Redo.t$(P%, 1) PROCstate_restoreLinesTo(1, "r" + STR$ P%) Redo.ptr% -= 1 ENDPROC REM PROCstate_saveLineFrom() REM ======================== REM REM Quickly saves all program lines from the given line number REM to the end of the program, to a temp file with the given name. DEF PROCstate_saveLinesFrom(I%, name$) LOCAL F%, L% F% = OPENOUT(TempDir$ + name$ + ".dat") PRINT#F%, lastLine% - I% + 1 : REM number of lines to save FOR L% = I% TO lastLine% PRINT#F%, lineIndentNext%(L%), Line$(L%), LEN lineColour$(L%), lineColour$(L%) BPUT#F%, lineSelected&(L%) BPUT#F%, lineIndent&(L%) BPUT#F%, lineIndentSelf&(L%) BPUT#F%, lineNumberL&(L%) BPUT#F%, lineNumberH&(L%) NEXT CLOSE#F% ENDPROC REM PROCstate_restoreLinesTo() REM ========================== REM REM Quickly loads all lines from the temp file with the given name, REM to the lines beginning with the given line number. DEF PROCstate_restoreLinesTo(I%, name$) LOCAL F%, L%, N%, S% F% = OPENIN(TempDir$ + name$ + ".dat") INPUT#F%, N% : REM number of lines to restore FOR L% = I% TO I% + N% - 1 INPUT#F%, lineIndentNext%(L%), Line$(L%), S% lineColour$(L%) = GET$#F% BY S% PTR#F% = PTR#F% + 1 : REM skip terminator written by PRINT# lineSelected&(L%) = BGET#F% lineIndent&(L%) = BGET#F% lineIndentSelf&(L%) = BGET#F% lineNumberL&(L%) = BGET#F% lineNumberH&(L%) = BGET#F% NEXT CLOSE#F% ENDPROC DEF PROCstate_saveVars(i{}):LOCALI%:FORI%=1TOnStateVars%:i.i%(I%)=!pStateVars%%(I%):NEXT:ENDPROC DEF PROCstate_restoreVars(i{}):LOCALI%:FORI%=1TOnStateVars%:!pStateVars%%(I%)=i.i%(I%):NEXT:ENDPROC DEF PROCundo_reset Undo.ptr%=0:Undo.count%=0:Redo.ptr%=0 LOCAL I%, J% FOR I% = 1 TO UndoMax% FORJ%=1TOnStateVars%:undoStateVars{(I%)}.i%(J%)=0:redoStateVars{(I%)}.i%(J%)=0:NEXT FORJ%=0TO3:Undo.t$(I%,J%)="":Undo.i&(I%,J%)=0:NEXT FORJ%=0TO2:Redo.t$(I%,J%)="":NEXT Undo.line%(I%)=0 Undo.i%(I%)=0 NEXT ENDPROC (_) DEF PROCfile_new Line$() = "" lineColour$() = "" lineSelected&() = 0 lineIndent&() = 0 lineIndentSelf&() = 0 lineIndentNext%() = 0 lineNumberL&() = 0 lineNumberH&() = 0 longestLineLen% = 0 lastLine% = 1 topLine% = 1 botLine% = 0 Start% = 1 Edit.text$ = "" Edit.line% = 1 Edit.carrot% = 0 Edit.modified% = FALSE Edit.changedIndent% = FALSE restoreTopLine% = 0 lineSelect.anc% = 0 lineSelect.ext% = 0 lineSelect.size% = 0 stringSelect.carrotAnc% = 0 stringSelect.carrotExt% = 0 stringSelect.index% = 0 stringSelect.text$ = "" Basename$ = "New File" : REM current program basename, this is always set to something. Dirname$ = "" : REM current program dirname (with trailing path delimiter), this is only set when a program is loaded or saved. fileModified% = FALSE Margin.basic% = FALSE backTotal% = 0 PROCsetWindowTitle ENDPROC REM recover program after fatal error DEF PROCfile_recover LOCAL pn$, F% pn$ = @tmp$ + Prog.name$ + "_recoverProg.bbc" F% = OPENIN(pn$) IF F% THEN CLOSE#F% PROCfile_load(pn$) PROCrecent_removeProgram(1) IFFNunlink(pn$) pn$ = @tmp$ + Prog.name$ + "_recoverPath.dat" F% = OPENIN(pn$) IF F% THEN INPUT#F%, Dirname$, Basename$ CLOSE#F% IFFNunlink(pn$) IF LEN Dirname$ IF FNis_readable(Dirname$ + Basename$) ELSE Dirname$ = "" : Basename$ = "New File" ENDIF fileModified% = TRUE PROCsetWindowTitle PROC_drawAll ENDIF ENDPROC REM a$ : used for reading line from file REM b$ : used for building a list of truncated program lines REM c$ : used for building a list of lines with control characters that will be invisible to the user REM A% : line number counter REM F% : file handle REM E% : length of file REM I% : line length REM J% : reads line number returned from tnt() REM N% : TRUE if line numbers found in file REM B% : TRUE if loading .bbc file (otherwise text/.bas with Windows EOL) is assumed REM T% : TRUE if line truncated DEF PROCfile_load(pn$) LOCAL a$, b$, c$, A%, F%, I%, J%, N%, B%, T% pRedraw%% = 0 PROCfile_new PROCundo_reset F% = OPENIN(pn$) B% = (FN_lower(RIGHT$(pn$, 4)) == ".bbc") IF B% THEN I% = BGET#F% : REM line length (includes: ELSE I% = NOT EOF#F% ENDIF MOUSE ON 2 WHILE I% A% += 1 IF A% > MAX_PROG_SIZE THEN a$ = "" PROCmsgline_title(a$, "Program Too Big!") PROCmsgline_add(a$, CHR$0 + "There is not enough room to load the entire program.", "C") PROCmsgline_add(a$, CHR$0 + Prog.name$ + " starts with space for " + STR$ MAX_PROG_SIZE + " lines.", "C") PROCmsgline_add($, CHR$0 + "Do you want to partially load the program ?", "C") IF FNmsgwin(a$, MSGWIN_STOP + MSGWIN_YESNO) == 1 fileModified% = TRUE : EXIT WHILE CLOSE#F% PROCfile_new ENDPROC ENDIF IF B% THEN REM .bbc lineNumberL&(A%) = BGET#F% : REM line number low byte lineNumberH&(A%) = BGET#F% : REM line number high byte IF lineNumberL&(A%) + lineNumberH&(A%) N% = TRUE : REM has line numbers INPUT#F%, a$ IF I% > 4 $lineBuff%% = a$ : Line$(A%) = FNdetok(lineBuff%%) : PROCline_setColour(A%) : PROCline_setIndentEffect(A%) I% = BGET#F% ELSE REM .bas a$ = GET$#F% TO &A T% = TRUE : REM silent truncate Line$(A%) = FNtnt_(LEFT$(a$), I%, J%, T%) IF T% b$ += STR$ A% + ", " : fileModified% = TRUE IF I% lineNumberL&(A%) = J% MOD 256 : lineNumberH&(A%) = J% DIV 256 : N% = TRUE IF LEN Line$(A%) PROCline_setColour(A%) : PROCline_setIndentEffect(A%) I% = NOT EOF#F% ENDIF REM ANSI mode under BB4W, renders some characters invisible to the user IF SDL% ELSE IF LENLine$(A%) IF INSTR(Line$(A%),CHR$129)ORINSTR(Line$(A%),CHR$141)ORINSTR(Line$(A%),CHR$141) \ \ ORINSTR(Line$(A%),CHR$143)ORINSTR(Line$(A%),CHR$144)ORINSTR(Line$(A%),CHR$157) c$+=STR$A%+", " ENDWHILE CLOSE#F% IF A% == 0 THEN A% = 1 ELSE IF A% > MAX_PROG_SIZE A% = MAX_PROG_SIZE ENDIF lastLine% = A% IF NOT fileModified% THEN Place.current$ = FNdirname(pn$, 1) Dirname$ = Place.current$ Basename$ = MID$(pn$, LEN Dirname$ + 1) PROCrecent_updateList ENDIF PROClines_setIndentFrom(1) PROClines_setLongestLen Edit.text$ = Line$(1) IF N% <> Margin.basic% Margin.basic% = N% : PROCoptions_save PROCsetWindowTitle PROC_setMousePointer IF c$ <> "" THEN c$ = LEFT$(c$, LEN c$ - 2) a$ = "" PROCmsgline_title(a$, "Invisible Characters!") PROCmsgline_add(a$, CHR$0 \ \+"The following program lines contain control characters that will not display correctly. "\ \+"They may appear to be invisible, but they can still be editied, or inspected by selecting "\ \+"each character one at a time. Change the selected character using Ctrl+Left/Right Arrow:", "C") PROCmsgline_add(a$, CHR$0 + "At Line" + LEFT$("s",SGNINSTR(c$,", ")) + ": " + c$, "C") IFFNmsgwin(a$, MSGWIN_WARNING) ENDIF IF b$ <> "" THEN b$ = LEFT$(b$, LEN b$ - 2) a$ = "" PROCmsgline_title(a$, "Line(s) Truncated!") PROCmsgline_add(a$, CHR$0\ \+"The following program lines were truncated because they contained more than 251 characters when tokenised:", "C") PROCmsgline_add(a$, CHR$0 + "At Line" + LEFT$("s",SGNINSTR(b$,", ")) + ": " + b$, "C") IFFNmsgwin(a$, MSGWIN_WARNING) ENDIF ENDPROC DEF PROCfile_save(pn$) IF FN_lower(RIGHT$(pn$, 4)) == ".bbc" PROCfile_writeTokenised(pn$) ELSE PROCfile_writeText(pn$) Place.current$ = FNdirname(pn$, 1) Dirname$ = Place.current$ Basename$ = MID$(pn$, LEN Dirname$ + 1) PROCrecent_updateList PROCsetWindowTitle fileModified% = FALSE ENDPROC DEF PROCfile_writeTokenised(pn$) LOCAL L%, F%, a$ F% = OPENOUT(pn$) FOR L% = 1 TO lastLine% a$ = FNtok(Line$(L%)) BPUT#F%, LEN a$ + 4 : REM line length BPUT#F%, lineNumberL&(L%) : BPUT#F%, lineNumberH&(L%) : REM line number BPUT#F%, a$; : BPUT#F%, &D : REM tokenised line and carriage return NEXT BPUT#F%, 0 BPUT#F%, &FF BPUT#F%, &FF CLOSE#F% ENDPROC DEF PROCfile_writeText(pn$) LOCAL L%, F% F% = OPENOUT(pn$) FOR L% = 1 TO lastLine% BPUT#F%, STRING$(lineIndent&(L%), " ") + Line$(L%) + CHR$13 NEXT CLOSE#F% ENDPROC DEF PROCfile_run(path$, name$) IF FNchdir(path$) THEN IF SDL% IF (@platform% AND &F) == 0 THEN REM BBCSDL for Win32 SYS "WinExec", """" + RTE.pathname$ + """ """ + name$ + """", 1 ELSE REM All other platforms OSCLI "RUN """ + RTE.pathname$ + """ """ + name$ + """;" ENDIF ELSE PROCalert("Can't chdir? " + path$) ENDIF ENDPROC (_) DEF FNreaddir(pn$, ext$, H%, RETURN d{}) : LOCAL U% DEF FN_readdir(pn$, ext$, M%, H%, T%, RETURN d{}) : LOCAL U% : U% = TRUE REM normalise the path to the directory and make sure the directory exists IF FNrealpath(pn$, pn$) IF FNchdir(pn$) pn$ += RIGHT$(@dir$) : d.path$=pn$ ELSE :=FALSE REM set d.root% flag LOCAL I%, J%, tmp$ d.flags% AND= NOT RD_ROOT REPEAT I% = INSTR(pn$, RIGHT$(@dir$), I% + 1) IF I% J% += 1 UNTIL I% == 0 d.flags% OR= (J%==1 AND RD_ROOT) REM regularise the extension string IF LEN ext$ THEN WHILE INSTR(ext$, ".") MID$(ext$, INSTR(ext$, "."), 1) = ";" : ENDWHILE ext$ = FN_lower(ext$) IF LEFT$(ext$, 1) <> ";" ext$ = ";" + ext$ IF RIGHT$(ext$) <> ";" ext$ += ";" ENDIF REM build pathname for temp file tmp$ = TempDir$ + "readdir.tmp" : IF U% :=FN`readdir(pn$, ext$, M%, H%, 0, d{}, tmp$) IF SDL% THEN CASE SDL% AND &F OF WHEN 0 REM BBCSDL for Win32 IF LEN ext$ THEN IF FN`readdir(pn$, ext$, RD_METHOD_ALL_NAIVE, H%, 200, d{}, tmp$) :=TRUE ELSE IF FN`readdir(pn$, ext$, RD_METHOD_ALL_ROBUST, H%, 200, d{}, tmp$) :=TRUE ENDIF =FN`readdir(pn$, ext$, RD_METHOD_SDL_WIN, H%, 0, d{}, tmp$) WHEN 1 REM BBCSDL for Linux IF FN`readdir(pn$, ext$, RD_METHOD_SDL_LINUX, H%, 0, d{}, tmp$) :=TRUE IF FN`readdir(pn$, ext$, RD_METHOD_ALL_ROBUST, H%, 200, d{}, tmp$) :=TRUE =FN`readdir(pn$, ext$, RD_METHOD_ALL_NAIVE, H%, 0, d{}, tmp$) WHEN 2 REM BBCSDL for MacOS IF FN`readdir(pn$, ext$, RD_METHOD_ALL_ROBUST, H%, 200, d{}, tmp$) :=TRUE =FN`readdir(pn$, ext$, RD_METHOD_ALL_NAIVE, H%, 0, d{}, tmp$) ENDCASE ENDIF REM BB4W =FN`readdir(pn$, ext$, RD_METHOD_BB4W, H%, 0, d{}, "") DEF FN`readdir(pn$, ext$, M%, H%, T%, RETURN d{}, tmp$) d.files$="" : d.nfiles%=0 : d.dirs$="" : d.ndirs%=0 CASE M% OF WHEN RD_METHOD_BB4W REM Optimised code for Windows (BBC BASIC for Windows) : NO TIMEOUT LOCAL a$, I%, J%, F% DIM I% LOCAL 317 SYS "FindFirstFile", pn$ + "*", I% TO J% IF J% == -1 :=FALSE REPEAT a$ = $$(I% + 44) REM !I% is the file attribute flags, if !I% AND 2 equals 2 the object is hidden IF a$ <> "." IF a$ <> ".." F% = !I% AND 2 IF (F% == 2 AND H%) OR (F% == 0) THEN IF !I% AND 16 THEN d.dirs$ += a$ + CHR$0 : d.ndirs% += 1 ELSE IF FNreaddir`extfilter(a$, ext$) d.files$ += a$ + CHR$0 : d.nfiles% += 1 ENDIF ENDIF SYS "FindNextFile", J%, I% TO F% UNTIL F% == 0 SYS "FindClose", J% WHEN RD_METHOD_SDL_WIN REM Optimised code for Windows (BB4W and BBCSDL for Win32) : NO TIMEOUT LOCAL a$, b$, F% IF NOT H% b$ = "-h" ON ERROR LOCAL :=FALSE OSCLI "run cmd /c dir /ad-s-l" + b$ + " /b > """ + tmp$ + """" RESTORE ERROR F% = OPENIN(tmp$) WHILE NOT EOF#F% a$ = GET$#F% IF LEN a$ d.dirs$ += a$ + CHR$0 : d.ndirs% += 1 ENDWHILE CLOSE#F% ON ERROR LOCAL :=FALSE OSCLI "run cmd /c dir /a-d-s-l" + b$ + " /b > """ + tmp$ + """" RESTORE ERROR F% = OPENIN(tmp$) WHILE NOT EOF#F% a$ = GET$#F% IF LEN a$ IF FNreaddir`extfilter(a$, ext$) d.files$ += a$ + CHR$0 : d.nfiles% += 1 ENDWHILE CLOSE#F% WHEN RD_METHOD_SDL_LINUX REM Optimised code for Linux (BBCSDL for Linux) : NO TIMEOUT LOCAL a$, F% IF H% a$ = " -A" ON ERROR LOCAL :=FALSE OSCLI "ls" + a$ + " -F --file-type """ + pn$ + """ > """ + tmp$ + """" RESTORE ERROR F% = OPENIN(tmp$) IF F% == 0 :=FALSE WHILE NOT EOF#F% a$ = GET$#F% IF LEN a$ THEN IF RIGHT$(a$) == "/" THEN d.dirs$ += LEFT$(a$) + CHR$0 : d.ndirs% += 1 ELSE IF FNreaddir`extfilter(a$, ext$) d.files$ += a$ + CHR$0 : d.nfiles% += 1 ENDIF ENDIF ENDWHILE CLOSE#F% OTHERWISE REM RD_METHOD_ALL_ROBUST, RD_METHOD_ALL_NAIVE (all platforms) LOCAL a$, b$, c$, I%, D%, p%% VDU 21 : REM disable screen output ON ERROR LOCAL OSCLI"spool" : VDU 6 :=FALSE OSCLI "spool """ + tmp$ + """" OSCLI "cd """ + pn$ + """" OSCLI "dir *.*" RESTORE ERROR *spool VDU 6 : REM enable screen output : REM load catalogue I% = OPENIN(tmp$) IF I% == 0 :=FALSE a$ = GET$#I% BY EXT#I% CLOSE#I% IF d.flags% AND RD_HOURGLASS IF LEN a$ > 10000 MOUSE ON 2 : IF M% == RD_METHOD_ALL_ROBUST THEN I% = INSTR(a$, CHR$10) p%% = ^FNreaddir`r() ELSE REM I have assumed that the lines of spooled files are always terminated with , REM as this is the case on BB4W and BBCSDL for Linux I% = -1 : b$ = CHR$13+CHR$10 REPEAT I% = INSTR(a$, b$, I% + 2) IF I% MID$(a$, I%, 2) = " " UNTIL I% = 0 I% = INSTR(a$, " ") p%% = ^FNreaddir`n() ENDIF : H% EOR= TRUE IF H% IF (SDL% AND &F) == 0 c$ = CHR$0\ \+"system volume information"+CHR$0\ \+"$recycle.bin"+CHR$0\ \+"recycler"+CHR$0\ \+"desktop.ini"+CHR$0\ \+"thumbs.db"+CHR$0 : TIME = 0 REPEAT : b$ = FN(p%%)(a$, I%, pn$, D%, ext$) IF LEN b$ THEN : REM If NOT include hidden files, then filter specific names: IF H% THEN IF SDL% AND &F THEN REM Linux and MacOS IF ASC b$ == &2E b$ = "" ELSE REM Windows IF INSTR(c$, CHR$0+FN_lower(b$)+CHR$0) b$ = "" ENDIF ENDIF : IF LEN b$ THEN IF D% d.dirs$ += b$ + CHR$0 : d.ndirs% += 1 ELSE d.files$ += b$ + CHR$0 : d.nfiles% += 1 ENDIF : ENDIF : IF T% IF TIME > T% T% = 0 : IF I% < 0.66 * LENa$ :=FALSE UNTIL I% > LEN a$ ENDCASE =TRUE REM Read the next directory object using the (n)aive algorithm DEF FNreaddir`n(a$, RETURN I%, pn$, RETURN D%, ext$) LOCAL c$, J% REM Find start of next object name (skip: space, *, , ) I% += 2 IF I% > LEN a$ :="" REPEAT J% = ASCMID$(a$, I%, 1) IF J% <> &20 IF J% <> &2A EXIT REPEAT I% += 1 UNTIL 0 IF I% > LEN a$ :="" J% = INSTR(a$, " ", I%) REM We have an object name candidate c$ = MID$(a$, I%, J% - I%) I% = J% REM Ignore implied folders IF c$ <> "." IF c$ <> ".." ELSE ="" REM Return object name if it looks like a file IF LEN ext$ THEN IF FNreaddir`extfilter(c$, ext$) D% = FALSE :=c$ IF INSTR(c$, ".") :="" ELSE IF INSTR(c$, ".") D% = FALSE :=c$ ENDIF REM Return object name if it is confirmed as a directory IF FNchdir(pn$ + c$) D% = TRUE :=c$ REM Object name is not recognised as a file or directory ="" REM Read the next directory object name using the (r)obust algorithm DEF FNreaddir`r(a$, RETURN I%, pn$, RETURN D%, ext$) LOCAL b$, c$, P%, J%, F% : REM Find start of next object name (skip: space, *, , ) b$ = " *"+CHR$10+CHR$13 WHILE INSTR(b$, MID$(a$, I%, 1)) I% += 1 : ENDWHILE IF I% > LEN a$ :="" : REM Read name: I% points to first character of name J% = I% REPEAT : P% = J% REPEAT REPEAT J% += 1 : UNTIL INSTR(b$, MID$(a$, J%, 1)) REM J% points to character after last character of name REM If this character is a space and the next character is not REM a character to ignore, then continue to increment J%. IF ASCMID$(a$, J%, 1) == &20 IF INSTR(b$, MID$(a$, J% + 1, 1)) == 0 ELSE EXIT REPEAT UNTIL 0 : REM We have an object name candidate REM If P% > I% then there is a short name candidate, and an extended name candidate REM c$ = extended name candidate REM (This is the only candidate on first pass as P% == I%) c$ = MID$(a$, I%, J% - I%) REM Ignore implied folders IF c$ <> "." IF c$ <> ".." ELSE I% = J% :="" : REM Return object name if it is confirmed as a directory IF FNchdir(pn$ + c$) I% = J% : D% = TRUE :=c$ REM Return object name if it is confirmed as a file F% = OPENIN(pn$ + c$ + ".") IF F% THEN CLOSE#F% : I% = J% : IF FNreaddir`extfilter(c$, ext$) D% = FALSE :=c$ ELSE ="" ENDIF : REM Before trying to extend the name, test the short name candidate REM (No short name candidate on first pass) IF P% > I% THEN c$ = MID$(a$, P%, J% - P%) REM Return object name if it is confirmed as a directory IF FNchdir(pn$ + c$) I% = J% : D% = TRUE :=c$ REM Return object name if it is confirmed as a file F% = OPENIN(pn$ + c$ + ".") IF F% THEN CLOSE#F% : I% = J% : IF FNreaddir`extfilter(c$, ext$) D% = FALSE :=c$ ELSE ="" ENDIF ENDIF : REM Object name is not recognised as a file or directory, so try to extend the name WHILE ASCMID$(a$, J%, 1) == &20 J% += 1 : ENDWHILE : UNTIL INSTR(b$, MID$(a$, J%, 1)) REM The name could not be extended I% = J% ="" REM Returns non-zero if the given object name (a$) has an extension listed in ext$. REM Always returns TRUE if ext$ is empty. DEF FNreaddir`extfilter(a$, ext$) IF LENext$ ELSE =TRUE LOCAL I%, J% I% = INSTR(a$, ".") IF I% ELSE =FALSE REPEAT J% = I% : I% = INSTR(a$, ".", I% + 1) : UNTIL I% == 0 =INSTR(ext$,";"+FN_lower(MID$(a$,J%+1))+";") DEF FNfilectime(pn$) : LOCAL A% : A% = 4 DEF FNfileatime(pn$) : LOCAL A% : A% = 12 DEF FNfilemtime(pn$) : LOCAL A% : A% = 20 IF SDL% THEN LOCAL a$, b$ b$ = TempDir$ + "filetime.tmp" CASE SDL% AND &F OF WHEN 0 REM WINDOWS CASE A% OF WHEN 20 : a$ = "w" WHEN 12 : a$ = "a" WHEN 4 : a$ = "c" ENDCASE OSCLI "run cmd /c dir """ + pn$ + """ /t:" + a$ + " > """ + b$ + """" A% = OPENIN(b$) IF A% == 0 :="" a$ = GET$#A% BY EXT#A% CLOSE#A% A% = 0 REPEAT A% = INSTR(a$, "/", A%+1) IF A% == 0 :="" UNTIL ASCMID$(a$, A%-3, 1) == 10 LOCAL B% B% = INSTR(a$, ":", A%) IF B% == 0 :="" =MID$(a$,A%+4,4)+"-"+MID$(a$,A%+1,2)+"-"+MID$(a$,A%-2,2)+" "+MID$(a$,B%-2,5)+":--" WHEN 1 REM LINUX CASE A% OF WHEN 20 : a$ = "y" WHEN 12 : a$ = "x" WHEN 4 : a$ = "w" ENDCASE OSCLI "stat -c '%" + a$ + "' """ + pn$ + """ > """ + b$ + """" A% = OPENIN(b$) IF A% == 0 :="" a$ = GET$#A% CLOSE#A% IF ASC a$ > 47 IF ASC a$ < 58 ELSE ="" REM assume ISO format "YYYY-MM-DD hh:mm:ss" =LEFT$(a$,19) ENDCASE ELSE REM BB4W LOCAL D%, S%, T% DIM D% LOCAL 317 DIM T% LOCAL 15 SYS "FindFirstFile", pn$, D% TO S% IF S% == -1 ERROR 100, "No such file " + pn$ SYS "FileTimeToSystemTime", D% + A%, T% =STR$(!T% AND &FFFF)+"-"+\ \RIGHT$("0"+STR$(T%?2),2)+"-"+\ \RIGHT$("0"+STR$(T%?6),2)+" "+\ \RIGHT$("0"+STR$(T%?8),2)+":"+\ \RIGHT$("0"+STR$(T%?10),2)+":"+\ \RIGHT$("0"+STR$(T%?12),2) ENDIF ="" DEF FNrealpath(pn$, RETURN c$) c$ = "" IF LEN pn$ ELSE =FALSE LOCAL I%, a$, d$ IF SDL% AND &F THEN d$ = "/" ELSE d$ = "\" REPEAT I% = INSTR(pn$, "/", I% + 1) IF I% MID$(pn$, I%, 1) = "\" UNTIL I% == 0 ENDIF REPEAT I% = INSTR(pn$, d$+d$) IF I% pn$ = LEFT$(pn$, I%) + MID$(pn$, I% + 2) UNTIL I% == 0 IF RIGHT$(pn$) <> d$ pn$ += d$ IF LEFT$(pn$, 2) == "." + d$ OR LEFT$(pn$, 3) == ".." + d$ THEN a$ = FNcurrentdir : IF LEN a$ ELSE =FALSE IF LEFT$(pn$, 2) == ".." pn$ = FNcurrentdir + pn$ ELSE pn$ = FNcurrentdir + MID$(pn$, 3) ENDIF IF d$ == "/" WHILE LEFT$(pn$, 3) == "/./" pn$ = MID$(pn$, 3) ENDWHILE REPEAT I% = INSTR(pn$, d$ + "." + d$) IF I% pn$ = LEFT$(pn$, I%) + MID$(pn$, I% + 3) UNTIL I% == 0 REPEAT I% = INSTR(pn$, d$ + ".." + d$) IF I% THEN a$ = FNdirname(LEFT$(pn$, I%), 1) IF a$ == "" :=FALSE pn$ = a$ + MID$(pn$, I% + 4) ENDIF UNTIL I% == 0 IF RIGHT$(pn$) == d$ c$ = LEFT$(pn$) ELSE c$ = pn$ =TRUE DEF FNcurrentdir LOCAL a$, P% IF SDL% THEN a$ = TempDir$ + "cd.tmp" VDU 21 ON ERROR LOCAL OSCLI"spool" : VDU 6 :="" OSCLI "spool """ + a$ + """" *cd *spool RESTORE ERROR VDU 6 P% = OPENIN(a$) IF P% ELSE :="" a$ = GET$#P% CLOSE#P% ELSE DIM P% LOCAL 255 : SYS "GetCurrentDirectory", 256, P% a$ = $$P% ENDIF IF LEN a$ IF RIGHT$(a$) <> RIGHT$(@dir$) a$ += RIGHT$(@dir$) =a$ DEF FNdirname(pn$, N%) REM#throw IF N% < 1 ERROR 100, "Number of levels less than 1" IF LEN pn$ ELSE ="" LOCAL p%%, I%, J%, D% : IF SDL% AND &F THEN D% = &2F ELSE D% = &5C REPEAT I% = INSTR(pn$, "/", I% + 1) IF I% MID$(pn$, I%, 1) = "\" UNTIL I% == 0 ENDIF REPEAT I% = INSTR(pn$, CHR$D%+CHR$D%) IF I% pn$ = LEFT$(pn$, I%) + MID$(pn$, I% + 2) UNTIL I% == 0 : IF ASCRIGHT$(pn$) == D% pn$ = LEFT$(pn$) IF INSTR(pn$, CHR$D%) THEN p%% = PTR(pn$) FOR I% = LEN pn$ - 1 TO 0 STEP -1 IF p%%?I% == D% J% += 1 : IF J% == N% :=LEFT$(pn$, I% + 1) NEXT ENDIF ="" DEF FNbasename(pn$) LOCAL p%%, I%, D% : IF SDL% AND &F THEN D% = &2F ELSE D% = &5C REPEAT I% = INSTR(pn$, "/", I% + 1) IF I% MID$(pn$, I%, 1) = "\" UNTIL I% == 0 ENDIF : IF ASCRIGHT$(pn$) == D% pn$ = LEFT$(pn$) IF INSTR(pn$, CHR$D%) THEN p%% = PTR(pn$) FOR I% = LEN pn$ - 1 TO 0 STEP -1 IF p%%?I% == D% :=MID$(pn$, I% + 2) NEXT ENDIF =pn$ DEF FNextension(pn$) LOCAL p%%, I% p%% = PTR(pn$) FOR I% = LEN pn$ - 1 TO 0 STEP -1 IF p%%?I% == &2E :=MID$(pn$, I% + 2) IF p%%?I% <> &2F IF p%%?I% <> &5C ELSE ="" NEXT ="" DEF FNrmdir_r(pn$) LOCAL d{}, I%, p%%, a$ DIM d{} = ReadDir{} IF SDL% IF (@platform% AND &F) == 0 I% = TRUE IF FNreaddir(pn$, "", TRUE, d{}) THEN IF RIGHT$(pn$) <> RIGHT$(@dir$) pn$ += RIGHT$(@dir$) IF d.nfiles% THEN p%% = PTR(d.files$) FOR I% = 1 TO d.nfiles% a$ = $$p%% : p%% += LEN a$ + 1 IFFNunlink(pn$ + a$) ELSE PROCalert(pn$ + a$) NEXT ENDIF IF d.ndirs% THEN p%% = PTR(d.dirs$) FOR I% = 1 TO d.ndirs% a$ = $$p%% : p%% += LEN a$ + 1 IFFNrmdir_r(pn$ + a$ + RIGHT$(@dir$)) NEXT ENDIF ENDIF =FNrmdir(pn$) DEF FNrmdir(pn$) ON ERROR LOCAL :=FALSE OSCLI "cd """ + @usr$ + """" OSCLI "rd """ + pn$ + """" =TRUE DEF FNmkdir(pn$) ON ERROR LOCAL :=FALSE OSCLI "md """ + pn$ + """" =TRUE DEF FNchdir(pn$) ON ERROR LOCAL :=FALSE OSCLI "cd """ + pn$ + """" =TRUE DEF FNis_readable(pn$) : IF FNchdir(pn$) :=FALSE DEF FNfile_exists(pn$) : IF FNchdir(pn$) :=TRUE LOCAL F% F% = OPENIN(pn$ + ".") IF F% == 0 :=FALSE CLOSE#F% =TRUE DEF FNunlink(pn$) ON ERROR LOCAL :=FALSE LOCAL F% F% = OPENIN(pn$ + ".") IF F% CLOSE#F% : OSCLI "del """ + pn$ + """" :=TRUE =FALSE DEF FNfileropen(pn$) ON ERROR LOCAL :=FALSE IF pn$ == "" pn$ = FNcurrentdir : IF pn$ == "" :=FALSE IF SDL% THEN CASE @platform% AND &F OF WHEN 0 IF FNchdir(pn$) THEN OSCLI "explorer """ + pn$ + """" ELSE IF INSTR(pn$, " ") OSCLI "start "" """ + pn$ + """" ELSE OSCLI "start " + pn$ ENDIF WHEN 1 : OSCLI "xdg-open """ + pn$ + """" WHEN 2 : OSCLI "open """ + pn$ + """" OTHERWISE:=FALSE ENDCASE ELSE IF FNchdir(pn$) THEN OSCLI "explorer """ + pn$ + """" ELSE SYS "ShellExecute", @hwnd%, "open", pn$, 0, 0, 1 ENDIF ENDIF =TRUE (_) DEF FNini_next(F%, RETURN k$, RETURN v$) k$ = "" : v$ = "" WHILE NOT EOF#F% IF FNini_parseLine(GET$#F%, k$, v$) :=TRUE ENDWHILE =FALSE DEF FNini_parseLine(a$, RETURN k$, RETURN v$) k$ = "" : v$ = "" IF LEN a$ ELSE =FALSE LOCAL A%, B% WHILE ASC a$ == 32 a$ = MID$(a$, 2) : ENDWHILE A% = ASC a$ IF A% <> -1 IF A% <> &23 IF A% <> &3B THEN IF A% == &5B WHILE INSTR(" ]", RIGHT$(a$)) : a$ = LEFT$(a$) : ENDWHILE : k$ = "[" : v$ = MID$(a$, 2) :=TRUE A% = INSTR(a$, ":") : B% = INSTR(a$, "=") IF A% THEN IF B% IF B% < A% A% = B% ELSE A% = B% ENDIF IF A% k$ = FN_lower(FN_trim(LEFT$(a$, A% - 1))) : v$ = FN_trim(MID$(a$, A% + 1)) :=TRUE ENDIF =FALSE (_) REM Takes a text-only program line and performs the following operations: REM - trims the line REM - extracts the line number (if any) REM - truncates the line if it is too long, REM - fills lineBuff%% with the resulting tokenised code REM - returns the resulting text-only program line REM REM a$ : text-only program line to process REM M% : returns TRUE if a line number is included (I.e. line number has been modified) REM N% : returns the line number (if any) REM T% : as input: TRUE == silent truncate (I.e. don't show warning message) REM : as output: returns TRUE if line was truncated, else returns FALSE DEF FNtnt_(a$, RETURN M%, RETURN N%, RETURN T%) DEF FNtnt(a$, RETURN M%, RETURN N%) : LOCAL T% REM (t)rim WHILE ASC a$ == &20 a$ = MID$(a$, 2) ENDWHILE WHILE RIGHT$(a$) == " " a$ = LEFT$(a$) ENDWHILE REM strip line (n)umber N% = VALa$ IF ASC a$ > &2F IF ASC a$ < &3A THEN M% = TRUE WHILE ASC a$ == &20 OR ASC a$ > &2F AND ASC a$ < &3A a$ = MID$(a$, 2) ENDWHILE ELSE M% = FALSE ENDIF REM (t)okenise / (t)runcate $lineBuff%% = FNtok(a$) IF LEN $lineBuff%% <= 251 THEN T% = 0 IF Lowercase% :=FNdetok(lineBuff%%) =a$ ENDIF IF NOT T% THEN a$ = "" PROCmsgline_title(a$, "Line Truncated!") PROCmsgline_add(a$, CHR$0 + "Program lines can't be more than 251 characters long when tokenised.", "C") T% = -FNmsgwin(a$, MSGWIN_WARNING) PROC_drawAll ENDIF lineBuff%%?251 = &D =FNdetok(lineBuff%%) REM Takes a text-only program line and returns a tokenised program line. REM It should only be used on text-only lines that have already been REM pre-processed to remove leading/trailing white space. REM Resulting line length needs to be checked. DEF FNtok(a$) LOCAL I%, J%, Q%, b$ IF ASC a$ == &5C LEFT$(a$, 1) = CHR$18 REPEAT I% = INSTR(a$, "\", I% + 1) IF I% THEN J% = INSTR(a$, """") : Q% = FALSE WHILE J% > 0 AND J% < I% : Q% EOR= TRUE : J% = INSTR(a$, """", J% + 1) : ENDWHILE IF Q% I% = J% ELSE b$ = MID$(a$, I%) : a$ = LEFT$(a$, I% - 1) : EXIT REPEAT ENDIF UNTIL I% == 0 REPEAT I% = INSTR(a$, ".") IF I% MID$(a$,I%,1) = CHR$17 UNTIL I% == 0 REM EVAL will always tokenise uppcase keywords even in lowercase mode IF EVAL("1RECTANGLERECTANGLE:"+a$) a$ = $(Accs%%+4) IF ASC a$ == 18 LEFT$(a$, 1) = "\" REPEAT I% = INSTR(a$, CHR$17) IF I% MID$(a$,I%,1) = "." UNTIL I% == 0 =a$+b$ REM p%% : pointer to cr-terminated tokenised line DEF FNdetok(p%%) LOCAL Q%, a$, a%% a%% = p%% WHILE ?p%% <> &D IF Q% THEN WHILE ?p%% <> &D AND ?p%% <> &22 : a$ += CHR$?p%% : p%% += 1 : ENDWHILE IF ?p%% == &D :=a$ a$ += CHR$&22 : Q% = FALSE ELSE IF ?p%% < &7F IF ?p%% > &1F THEN IF ?p%% == &5C IF p%% > a%% :=a$+$p%% a$ += CHR$?p%% IF ?p%% == &22 Q% = TRUE ELSE IF ?p%% == &8D THEN p%% += 1 a$ += STR$((((?p%% << 2) AND &C0) EOR p%%?1) + (((?p%% << 4) AND &C0) EOR p%%?2) * 256) p%% += 2 ELSE a$ += K$(?p%%) IF ?p%% == &F4 :=a$+$(p%%+1) ENDIF ENDIF ENDIF p%% += 1 ENDWHILE =a$ REM p%% : pointer to cr-terminated tokenised line DEF FNdefName(p%%) LOCAL q%%, a$ REPEAT p%% += 1 : UNTIL ?p%% <> &20 IF ?p%% == &E REPEAT p%% += 1 : UNTIL ?p%% <> &20 q%% = p%% IF ?q%% <> &F2 IF ?q%% <> &A4 THEN REPEAT REPEAT q%% += 1 : UNTIL ?q%% < &30 OR ?q%% > &7A OR ?q%% > &39 AND ?q%% < &40 UNTIL ?q%% <> &2E =LEFT$($p%%, q%% - p%%) ENDIF IF ?q%% == &F2 THEN IF Lowercase% a$ = "proc" ELSE a$ = "PROC" ELSE IF Lowercase% a$ = "fn" ELSE a$ = "FN" ENDIF REPEAT q%% += 1 : UNTIL ?q%% < &30 OR ?q%% > &7A OR ?q%% > &39 AND ?q%% < &40 IF ?q%% == &24 q%% += 1 a$ += LEFT$($(p%% + 1), q%% - p%% - 1) IF ?q%% == &28 a$ += "()" =a$ REM p%% : pointer to cr-terminated tokenised line DEF FNlabelName(p%%) LOCAL q%% q%% = p%% REPEAT q%% += 1 : UNTIL ?q%% < &30 OR ?q%% > &7A OR ?q%% > &39 AND ?q%% < &40 =MID$(LEFT$($p%%, q%% - p%%), 2) DEF FNonEventStatement(a$, I%) IF I% == 0 =0 LOCAL A% REPEAT I% += 1 : A% = ASCMID$(a$, I%, 1) : UNTIL A% <> &20 CASE A% OF WHEN KEYWORD_CLOSE, KEYWORD_ERROR, KEYWORD_MOUSE, KEYWORD_MOVE, KEYWORD_SYS, KEYWORD_TIME :=A% ENDCASE =0 (_) DEF PROCalert(msg$) IF SDL% THEN SYS "SDL_ShowSimpleMessageBox", &40, Prog.name$, msg$, @hwnd%, @memhdc% ELSE SYS "MessageBox", @hwnd%, msg$, Prog.name$, 0 ENDIF ENDPROC DEF FNpac IFK%<32:=0 IFK%<128:=1 LOCAL L% IF K% > 159 THEN IF SDL% THEN REM this should be a utf8 encoding REM if it is a two-octet encoding, we can convert it to ANSI ISO-8859-1 REM does octet have format 1100001x IF (K% AND 254) <> 194 :=0 REM yes, so read second octet L% = INKEY(1) REM does octect have format 10yyyyyy IF (L% AND 192) <> 128 :=0 REM yes, so decode character K% = ((K% AND 3) << 6) OR (L% AND 63) IF K% < 160 :=0 ENDIF =2 ENDIF =0 REM FNinput() REM ========= REM REM General purpose text field input function that REM returns control to the callee depending upon different events, REM specified as follows: REM REM EVENT_INPUT_MOUSE_MOVE REM mouse moves outside of input bounding rectangle REM EVENT_INPUT_MOUSE_CLICK REM mouse is clicked outside of bounding rectangle REM EVENT_INPUT_UP REM up arrow key is pressed REM EVENT_INPUT_DOWN REM down arrow key is pressed REM EVENT_INPUT_ESCAPE REM escape key is pressed (your program must have disabled escape with *ESC) REM EVENT_INPUT_RETURN REM return key is pressed REM EVENT_INPUT_TAB REM tab key is pressed REM EVENT_INPUT_RESIZE REM the main window is resized REM REM Parameter List REM ~~~~~~~~~~~~~~ REM REM a$ : initial value of text field REM v$ : list of valid characters (can be empty) REM C% : initial position of carrot within initial value (I.e. carrot index 0 to LEN a$) REM E% : event code (control is returned to callee if event code is specified) REM R% : returned event code (gives the reason why the function returned) REM i{} : DIM i{l%, b%, r%, t%, \ specifies the input field bounding rectangle (graphic units) only needed if you require EVENT_INPUT_MOUSE_... REM \ cx%, cy%, \ character x, y position of text field (relative to textview top-left of 0, 0) REM \ cw% \ \ character width of text field REM \ } DEF FNinput(a$, v$, C%, E%, RETURN R%, i{}) LOCAL S%, K% LOCAL P%, Q%, A%, B%, Z%, click% : REM mouse move/click LOCAL G%, H% : REM window resize ON MOUSE LOCAL click% = TRUE : RETURN REM i.cw% == 5 REM i.cx% == 3 REM 0 1 2 3 4 5 : carrot position relative to i.cx% REM | | REM C%: 0 1 2 3 4 5 6 7 8 9 : carrot position REM S%: 1 2 3 4 5 6 7 8 9 : start character REM | | REM REM if C% == S% - 1 then C% is at left of input field REM if C% == S% + i.cw% - 1 then C% is at the right of input field REM make sure the carrot position is valid IF C% > LEN a$ OR C% < 0 C% == LEN a$ REM set up the start character IF C% > i.cw% S% = C% - i.cw% + 1 ELSE S% = 1 REM make a note of the window size and mouse coords G% = Win.w% H% = Win.h% MOUSE A%, B%, Z% R% = 0 REPEAT REM redraw input field OFF REM PRINT TAB(0, 0) "x: ";i.cx%;" y:";i.cy%;" w:";i.cw%;" "; REM PRINT TAB(0, 1) "start: ";S%;" carrot: ";C%;" lineLen: ";LEN a$;" " PRINT TAB(i.cx%, i.cy%) LEFT$(MID$(a$, S%) + STRING$(i.cw%, " "), i.cw%); VDU 31, i.cx% + (C% - S% + 1), i.cy% ON REM poll loop REPEAT K% = INKEY(1) MOUSE P%, Q%, Z% IF (E% AND EVENT_INPUT_RESIZE) THEN REM exit if window resized IF G% == Win.w% IF H% == Win.h% ELSE R% = EVENT_INPUT_RESIZE :=a$ ENDIF IF click% THEN REM was the click somewhere in the input field? IF Q% > i.b% IF Q% < i.t% IF P% > i.l% IF P% < i.r% THEN REM make sure click was between top and bottom of input text IF Q% >= Win.h% - (i.cy% + 1) * chrHeight% IF Q% <= Win.h% - i.cy% * chrHeight% THEN REM make sure click was between left edge and right edge of input text IF P% >= i.cx% * chrWidth% IF P% <= i.cx% * chrWidth% + i.cw% * chrWidth% THEN REM compute new carrot position C% = S% - 1 + (P% - i.cx% * chrWidth% + chrWidth% / 2) / chrWidth% IF C% > LEN a$ C% = LEN a$ REM respond to horizontal drag A% = P% : B% = Q% MOUSE P%, Q%, Z% OFF WHILE Z% IF ABS(A% - P%) > chrWidth% THEN IF P% < A% THEN REM drag left IF S% + i.cw% - 1 < LEN a$ THEN S% += 1 PRINT TAB(i.cx%, i.cy%) LEFT$(MID$(a$, S%) + STRING$(i.cw%, " "), i.cw%); ENDIF ELSE REM drag right IF S% > 1 THEN S% -= 1 PRINT TAB(i.cx%, i.cy%) LEFT$(MID$(a$, S%) + STRING$(i.cw%, " "), i.cw%); ENDIF ENDIF A% = P% : B% = Q% ENDIF MOUSE P%, Q%, Z% ENDWHILE IF C% < S% - 1 C% = S% - 1 IF C% > S% + i.cw% - 1 C% = S% + i.cw% - 1 A% = P% : B% = Q% K% = 0 : REM force redraw ENDIF ENDIF click% = 0 ELSE REM exit if mouse click outside of input bounding rectangle IF (E% AND EVENT_INPUT_MOUSE_CLICK) R% = EVENT_INPUT_MOUSE_CLICK :=a$ ENDIF ENDIF IF (E% AND EVENT_INPUT_MOUSE_MOVE) THEN REM exit if there is mouse movement AND that mouse movement is outside of the input bounding rectangle IF P% == A% IF Q% == B% THEN ELSE IF Q% > i.b% IF Q% < i.t% IF P% > i.l% IF P% < i.r% THEN A% = P% : B% = Q% ELSE R% = EVENT_INPUT_MOUSE_MOVE :=a$ ENDIF ENDIF ENDIF UNTIL K% <> -1 CASE K% OF WHEN 27 : IF (E% AND EVENT_INPUT_ESCAPE) R% = EVENT_INPUT_ESCAPE WHEN 8, 127 REM backspace delete IF C% THEN IF C% == S% - 1 S% -= 1 a$ = LEFT$(a$, C% - 1) + MID$(a$, C% + 1) : C% -= 1 ENDIF WHEN 10 REM Ctrl-RETURN : delete after carrot a$ = LEFT$(a$, C%) WHEN 13 : IF (E% AND EVENT_INPUT_RETURN) R% = EVENT_INPUT_RETURN WHEN 9 : IF (E% AND EVENT_INPUT_TAB) R% = EVENT_INPUT_TAB WHEN 21 REM Ctrl-U : delete before carrot a$ = MID$(a$, C% + 1) C% = 0 : S% = 1 WHEN 130 REM home C% = 0 : S% = 1 WHEN 131 REM end C% = LEN(a$) IF C% > i.cw% S% = C% - i.cw% + 1 ELSE S% == 1 WHEN 135 REM forward delete IF C% < LEN(a$) a$ = LEFT$(a$, C%) + MID$(a$, C% + 2) WHEN 136 REM left arrow key IF C% THEN IF C% == S% - 1 S% -= 1 C% -= 1 ENDIF WHEN 137 REM right arrow key IF C% < LEN(a$) THEN IF C% == S% + i.cw% - 1 S% += 1 C% += 1 ENDIF WHEN 138 : IF (E% AND EVENT_INPUT_DOWN) R% = EVENT_INPUT_DOWN WHEN 139 : IF (E% AND EVENT_INPUT_UP) R% = EVENT_INPUT_UP OTHERWISE IF FNpac IF v$ == "" OR INSTR(v$, CHR$K%) THEN IF C% == S% + i.cw% - 1 S% += 1 a$ = LEFT$(a$, C%) + CHR$K% + MID$(a$, C% + 1) C% += 1 ENDIF ENDCASE UNTIL R% =a$ DEF PROC_setptr(RETURN i{},p%%) IF SDL% AND 64 ](^i{}+8)=p%% ENDPROC !(^i{}+4)=!^p%% ENDPROC DEF PROCopenurl(url$) IF SDL% THEN CASE @platform% AND 3 OF WHEN 0 : SYS "system", "start " + url$ + "&" WHEN 1 : SYS "system", "xdg-open " + url$ + "&" WHEN 2 : SYS "system", "open " + url$ + "&" ENDCASE ELSE SYS "ShellExecute", @hwnd%, "open", url$, 0, 0, 1 ENDIF ENDPROC DEF FNheapptr(P%) : LOCAL a$ : !^a$ = P% :=PTR(a$) DEF FNerrorLine LOCAL i%%, p%%, a$ REM i%% = address at which the most recent error was detected i%% = FNheapptr(!408) REM p%% = start of tokenised library code or main program code IF !360 THEN p%% = FNheapptr(!360) IF i%% < p%% p%% = PAGE ELSE p%% = PAGE ENDIF REM ?p%% is the length of the program line REM p%% + ?p%% is the address of the next line REM REM while (length of program line AND address of next line) < address at which the most recent error was detected WHILE ?p%% AND p%% + ?p%% < i%% p%% += ?p%% : ENDWHILE IF ?p%% == 0 :="" REM read and de-tokenise line p%% += 3 WHILE ?p%% <> &D IF ?p%% < &7F IF ?p%% > &1F a$ += CHR$ ?p%% ELSE a$ += K$(?p%%) p%% += 1 ENDWHILE REM find FN/PROC/method name owning error line a$ += " in " WHILE ?p%% <> &DD AND p%% > PAGE p%% -= 1 : ENDWHILE IF ?p%% <> &DD =a$ + "Main Program" REPEAT p%% += 1 : UNTIL ?p%% <> &20 IF ?p%% == &E REPEAT p%% += 1 : UNTIL ?p%% <> &20 IF ?p%% == &A4 a$ += "FN" : p%% += 1 IF ?p%% == &F2 a$ += "PROC" : p%% += 1 i%% = p%% REPEAT REPEAT i%% += 1 : UNTIL ?i%% < &30 OR ?i%% > &7A OR ?i%% > &39 AND ?i%% < &40 UNTIL ?i%% <> &2E IF ?i%% == &24 i%% += 1 IF ?i%% == &28 THEN =a$ + LEFT$($p%%, i%% + 1 - p%%) + ")" =a$ + LEFT$($p%%, i%% - p%%) DEF PROCsetWindowTitle LOCAL a$ a$ = Dirname$ + Basename$ + " - " + Prog.name$ + " " + Prog.version$ IF SDL% SYS "SDL_SetWindowTitle", @hwnd%, a$ ELSE SYS "SetWindowText", @hwnd%, a$ ENDPROC DEF FNwindowmaximised IF SDL% THEN REM#const SDL_WINDOW_MAXIMIZED = &80 LOCAL R% : SYS "SDL_GetWindowFlags", @hwnd% TO R% IF R% AND SDL_WINDOW_MAXIMIZED THEN =TRUE ELSE REM#const SW_SHOWMAXIMIZED = 3 LOCAL wp{} DIM wp{length%, flags%, showcmd%, minpos{x%,y%}, maxpos{x%,y%}, normal{l%,t%,r%,b%}} wp.length% = DIM(wp{}) SYS "GetWindowPlacement", @hwnd%, wp{} IF wp.showcmd% == SW_SHOWMAXIMIZED THEN =TRUE ENDIF =FALSE DEF FNloadBMP(pn$) LOCAL F%, p%% IF FN_lower(RIGHT$(pn$, 4)) <> ".bmp" pn$ += ".bmp" F% = OPENIN(pn$) IF F% == 0 :=0 DIM p%% EXT#F% CLOSE#F% OSCLI "LOAD """ + pn$ + """ " + STR$~p%% =p%% DEF FNinQuotes(a$, I%) LOCAL P%, Q% P% = INSTR(a$, CHR$&22) WHILE P% > 0 AND P% < I% Q% EOR= TRUE : P% = INSTR(a$, CHR$&22, P% + 1) : ENDWHILE =Q% DEF FNinComment(a$, I%) LOCAL J%, P%, Q%, b$ REM trim leading white space WHILE LEFT$(a$, 1) == " " a$ = MID$(a$, 2) : I% -= 1 : ENDWHILE IF I% < 2 :=FALSE REM line continuation comments J% = INSTR(a$, "\", 2) WHILE J% > 0 AND J% < I% REM is \ in quotes? P% = INSTR(a$, CHR$&22) WHILE P% > 0 AND P% < J% : Q% EOR= TRUE : P% = INSTR(a$, CHR$&22, P% + 1) : ENDWHILE IF NOT Q% :=TRUE J% = INSTR(a$, "\", J% + 1) ENDWHILE REM rem comments IF Lowercase% b$ = "rem" ELSE b$ = "REM" J% = INSTR(a$, b$) IF J% == 0 :=FALSE IF J% == 1 THEN IF J% < I% - 2 :=TRUE ELSE =FALSE ENDIF WHILE J% > 1 AND J% < I% - 2 REM is rem in quotes? P% = INSTR(a$, CHR$&22) : Q% = FALSE WHILE P% > 0 AND P% < J% : Q% EOR= TRUE : P% = INSTR(a$, CHR$&22, P% + 1) : ENDWHILE IF NOT Q% THEN REM is rem part of variable? P% = ASCMID$(a$, J% - 1, 1) IF P% < 48 :=TRUE IF P% < 64 IF P% > 57 :=TRUE IF P% < 97 IF P% > 90 :=TRUE IF P% > 122 :=TRUE ENDIF J% = INSTR(a$, b$, J% + 3) ENDWHILE =FALSE DEF FNdl_size(l$, d$) IF LEN l$ ELSE =0 LOCAL P%, I% P% = INSTR(l$, d$) WHILE P% : I% += 1 : P% = INSTR(l$, d$, P% + LEN d$) : ENDWHILE =I%+1 DEF FNdl_next(l$, d$, RETURN L%) LOCAL R%, a$ R% = INSTR(l$, d$, L%) IF R% a$ = MID$(l$, L%, R% - L%) : L% = R% + LEN d$ ELSE a$ = MID$(l$, L%) : L% = 0 =a$ DEF FNtl_size(l$) LOCAL P%, I%, d$ d$ = RIGHT$(l$) : P% = INSTR(l$, d$) WHILE P% : I% += 1 : P% = INSTR(l$, d$, P% + 1) : ENDWHILE =I% DEF FNtl_explode(l$, RETURN a$(), S%) LOCAL I%, J% J% = S% IF ASC RIGHT$(l$) THEN WHILE INSTR(l$, CHR$13, I% + 1) : a$(J%) = $(PTR(l$) + I%) : I% += LEN a$(J%) + 1 : J% += 1 : ENDWHILE ELSE WHILE INSTR(l$, CHR$0, I% + 1) : a$(J%) = $$(PTR(l$) + I%) : I% += LEN a$(J%) + 1 : J% += 1 : ENDWHILE ENDIF =J%-S% DEF FNisAlphabetic(A%) IF A% < 65 =FALSE IF A% < 91 =TRUE IF A% < 97 =FALSE IF A% < 123 =TRUE =FALSE DEF FNmax(a,b) IFa>b:=a =b DEF FNmin(a,b) IFa> 8 AND &FF, C% >> 16 AND &FF : ENDPROC