Δευτέρα, 30 Απριλίου 2018

Notepad (M2000 code) using 9.3 version interpreter

Notepad code are not new for this blog. But because the GUI in 9.3 get some additions: Control Box, Icon, Reversing the icons in title, Maximize/Restore, Minimized, Move (by keyboard), I decide to make it public again, with some lines of information, to explain what statements do.

M2000 Interpreter is written with VB6, but it is different from VB6, and has own window manager, written in VB6 and included in M2000.dlll, using a flat VB6 form with one User Control (can load multiple instances), to act as Title of form and any control on it, including Button, TextBox, EditBox, CheckBox, ListBox, ComboBox, and the new Control Box. This can be done without subclassing the User Control, but with other objects which get events from controls, where controls are in form. When an event form these objects happen call code in M2000 using information from form (which hold a reference as CallBack). So every event sent to the level of module which make the form. If an event found function to served then inform a list in form that this event is ok. But if no event service found then inform that this event excluded, so next time this event automatic dropped, using a black list. When we activate a form (if we have a second one then we get an internal active event) the black list deleted for new insertions. This happen because in a module functions exist when code pass from declaration of it. So maybe we want to declare an event later, in the next activation of form. When we perform a "Show" method, in a form, we get activation too.
Console Form it's not a form of internal window manager. We can use modal windows, in any level, and we can open non modal forms when we use a modal form, but these forms can be "deactivated" if we open a new modal on top of these. Modality of forms, are not disabling. Only keystrokes and Mouse clicks are "lost". We can display and refresh any of "deactivated" form behind a modal form. Here in this example NotePad is a modal form, with no form behind (console form is just hidden, and can be visible if we insert an Input command in any event, butt not including in a Layer Pad {} block, where we get error for using it in form's layer).
We can make a small alteration to make NotePad form not a modal form, and use a A$=Get$ for waiting a keypress in console, and if we choose console and press a key then interpreter continue to delete the form (without method "CloseNow"),  All forms closed if we press Escape key in keyboard, and console is visible. We can insert command Escape Off to exclude this key for breaking the running code. Also the Break Button not work if cosole is hidden. When the NotePad wait for event, we have zero cpu execution.

EditBox has some forms and logic for task as find/replace, search the marked text up/down, with F6 to F8 we set/goto/reset Bookmarks (from F1 to F11 all functions keys used, also Shift +F2, Shift+F3). Because Tab and Shift-Tab move focus to other controls, we use Ctrl+Tab, Ctrl+Shift+tab to indent lines. Ctrl+Tab ued from internal window manager to change forms, but EditBox use it before window manager. Title Bar can get focus too. Alt+F4 close form (but with event before).

All dialogs from window manager (msgbox, inputbox, openfile, openfolder, font, color, popup menu for editor, plus control form (testing code/display), help form/ settings) have a feature to not just resize, but magnify the text. Also in some dialogs we can expand forms in horizontal dimension without text magnification (open dialog has a second list of settings which we open clicking an icon with three horizontal lines). Handling vertical (for text magnification) and horizontal (for expansion), it is easy. The closing square icon is always in left position for these dialogs. As we see in this notepad we choose to use "UseReverse" with value True, to change the icons position.

We can run A using Test A to open Control Form. Clicking third from right label we change display from stack to code display). (click anywhere to see what happen).

Form title size and control size can be altered, but for this example we use standard size.

Here is the form with reverse the icons positions. We see from left the Icon of M2000 (we choose to show that), after this is the three line icon which is the control box button, next is the title, and next is the minimize button, the maximize and the close button. We can move the form in any monitor. The border line from Editbox is the form layer, which is visible there. ComboBoxes as MenuStyle are the File, Edit, Help. To open File we have to click and move to open (just a click set focus only), or if focus is in that Combobox we can use down arrow to open and left-right to open the next menu. The locked button is this with the caption 1-1, and used as label (here used with same color as the forms layer). Text in title can be wrap, if we make to short the width of form.


Here is the control box. When we press tab we change focus and we get to icon with three lines, change to white color when have focus, and then we press down aarrow to open it, or just click with the right button of mouse. If we choose Move, title flashes and we can use arrows to move the form. Using any other key we change focus to last control before control box icon get focus.





This is the Edit Menu where we have Cut and Copy disabled with a reddish color.

This is the standard popup (we see that we get an events and we redirect to internal standard popup). This dialog also can change size, changing size of text automatic


Here we have a shrunk load file dialog


And here is the input box to replace a word (in all text, with undo). Replacing is a process which we see each replace as happen, and we can stop this using shift key
.

Undo can be used with Ctrl+Z and redo with Ctrl+Y. Select all with Ctrl+A. F2 and F3 jump to same word as the selected one. Shift+F2 and Shift+F3 open dialog to get the phrase we want to find.

The background of these images are from Windows 7, in Virtual Box, but the forms are the same from Xp to Windows 10, and in Linux using Wine.

The last statement Print "Done" send to M2000 console the string "Done". We don't see that if console is not visible, but stays there for all good reasons.


MODULE A {
\\ Notepad In M2000 code
\\ The code are in Module A and we Call A to run
\\ we can make a file (note.gsb), and insert this module and A and End
\\ so when we click note.gsb we get the notepad as a form
\\ without console  (if a non trappable error happen then console opened)

\\ these three statements prepare the interpreter
\\ Latin set error messages to English, and set Locale to 1033
\\ locale needed for reading Ascii files from disk
\\ Forms and controls are Unicode capable
Latin
Clear \\ Clear all variables/objects
Flush \\ Empty the stack
Title$="M2000 Pad"
typ$="txt"
Dir User
\\ we want console to be hidden from tasklist
\\ we get only NotePad form to tasklist
title "",0
Declare NotePad Form
\\ Our form we wish to have an EditBox, as text editor
\\ and a label for output cursor position.
\\ we use a button as locked to act as label
\\ locked buttons excluded from internal tabstop sequence
Declare Pad EditBox Form NotePad
Declare Inform1 Button Form NotePad
Method Inform1, "Colors", 15, #FFA000
With Inform1, "Locked", true

\\ Also we want to have a menu,
\\ and we can do making comboboxes as dropdown menus
\\ we have to inform that File1 is a ComboBox, and belong to Notepad Form
Declare File1 Combobox Form NotePad
Declare Edit1 Combobox Form NotePad
Declare Help1 Combobox Form NotePad

With File1,"label","File", "listtext" As list$, "list" As list$()
\\ we want to have disabled menuitems with a reddish color
\\ for cut,copy, paste
With Edit1,"label","Edit",  "Mark", Color(255,100,0)
With Help1,"label","Help"
\\ Using With we can set value or make variables bound to object properties
With NotePad, "Title" As Caption$, "Visible" As Visible, "TitleHeight" As tHeight

\\ we want to change size of form, so we have to inform that
With NotePad, "Sizable", True

\\ we set icon view and change icon/control box to the left (default right) using UseReverse
With NotePad,"UseIcon", True, "UseReverse", True

\\ MakeStandardInfo make control box to use stantard menou with english captions (1).
\\ always execute this after setting "Sizable"
Method NotePad,"MakeStandardInfo", 1
With Pad, "Text" As Pad.Text$, "ShowAlways", True,"NoColor", True,"SelLength" as SelLength

\\ New to 9.3 we can set a control as default, so at the opening we have focus to default control
With Pad, "Default", True

\\ we make a on line function to prepate the title of form
Def TitleStr$(a$)=ucase$(left$(a$,1))+mid$(a$,2)

\\ using Dir$ as current directory
Filename$=Dir$+"Untitled.txt"

\\ Caption$ is form property now  see with notepad, "Title" as caption$
\\ it is read/write proprty
Caption$=TitleStr$(File.Name$(Filename$)) +" - M2000 Pad"

\\ Form NotePad is not visible now, but is loaded
\\ we use twips (is standard for M2000)
Method NotePad,"move", 2000, 4000, 8000, 4000

\\ We have access to NotePad Layer. We can print/report/draw like in console
\\ layers for forms not support input commands, we have to use controls,
\\ or the use of events for input.
\\ Colors can be in Html form (as numbers only)
Layer NotePad {Cls #FFA000}

\\ Now we wish to set the style of comboboxes, and set a widh for dropdownlist
With File1,"MenuStyle", True, "MenuWidth", 3000
\\ also we want to handle enabled property (has an index) for Edt1 menu
\\ for cut copy paste
With Edit1,"MenuStyle", True, "MenuWidth", 3000,"menuEnabled" as Enabled()
With Help1,"MenuStyle", True, "MenuWidth", 3000
\\ also we want to disable some menu items in File1 menoy
With File1, "MenuEnabled" As mEnable()

\\ We use For This  {} which open a block for temporary definitions
\\ here mi$ created only for this block
For This {
      mi$="MenuItem"  \\ is a temporary variable only for For This Block
      \\ Creating a group of menu ("This" can be any name)
      \\ we can move with arrows from one menu to other
      With File1, "MenuGroup","This"
      Method File1, mi$,"Open",True
      Method File1, mi$,"Save",True
      Method File1, mi$,""    \\  only  a line here
      \\ here we make two radio menu items
      \\ one of it can be "marked" with a square big dot
      Method File1,"MenuRadio","txt files",True,True
      Method File1,"MenuRadio","bas files",True,False
    
      Method File1, mi$,""
      Method File1, mi$,"Close",True
      Method File1, mi$,""
      Method File1, mi$,"Quit",True
    
      With Edit1, "MenuGroup","This"
      Method Edit1, mi$,"Cut",False
      Method Edit1, mi$,"Copy",False
      Method Edit1, mi$,"Paste",True
      Method Edit1, mi$,""
      Method Edit1, mi$,"Less Indent",True
      Method Edit1, mi$,"More Indent",True
      With Help1, "MenuGroup","This"
      \\ in menu Help1 we don't create anything, instead we use the event for opening the menu
      \\ before actually systme finds that is not an item in dropdown list and skip the showing
}
\\ This is a Document object. We use it here because has own Load/Save statements in M2000
Document BackUp$="Write something..."

\\ Pad.text$ is a bound property of Pad (see With Pad statements)
Pad.Text$=BackUp$

\\ Now we set the events
\\Event Unload sent a byreference parameter among others
\\Because events are served from "fake" functions,
\\ where the name of function change to name of module, to have access to anything in module
\\ we have to make the Read statement as Read New to make always new variable (shadowing a same named variable)
\\ shadowing ends at the exit of function (this hold true for For Object {} blocks too)
Function NotePad.Unload {
      Read New &Ok
      \\ we "choose" menu item in File1 after 50 milliseconds
      \\ "After" is  one time running thread, and lost after execution
      \\ so this is an async call, to "quit" from menu only
      \\ this event called from anywhere, tasklist, taskbar, when we close the form
      After 50 {call local File1.DblClick(8)}
      Ok=True
      \\ we say not to close by default;
}

\\ we set the control box, and this box send event also
\\ because control box has an About item, we have to get this event and call the help1.OpenMenu()
\\ using Call Local we simulate the event call
\\ We don't use here async call
\\ There are two types of events, the Unload need to take a response, and this is the one kind
\\ and the InfoClick is async, can be executed in later time
Function Notepad.InfoClick {
      Read New X
      If X=0 then Call Local Help1.OpenMenu() ' no parameter passing here
}
\\ This is a "trick" event, because it is not the actuall form resize event
\\ so we can resize notpad inside Notepad.Resize without raising a second event
\\ Also we have to make resizing dpi-aware
\\ See a Method to Pad to "resize", means not only to wrap text,
\\ but to move cursor to a visible part of EditBox
Function Notepad.Resize {
      Layer NotePad { Cls Color(255, 160, 0) ,0}
      With NotePad, "Width" As NP.Width, "Height" As NP.Height, "TitleHeight" As tHeight
      tHeight1=theight*2
      Method File1,"move", twipsX*2, tHeight, twipsX*80, tHeight
      Method Edit1,"move", twipsX*2+twipsX*80, tHeight, twipsX*80, tHeight
      Method Help1,"move", twipsX*2+twipsX*160, tHeight, twipsX*80, tHeight
      Method Inform1,"move", twipsX*2+twipsX*240, tHeight, twipsX*160, tHeight
      If NP.height>1000 Then {
            Method Pad,"move", twipsX*2, tHeight1, NP.Width-twipsX*5, NP.Height-tHeight1-twipsx*3
            With Pad, "NoWrap" As NoWrap
            If Not NoWrap Then Method Pad,"Resize"
      }
}

\\ So now we have to do something with Edi1 menu
\\ before opening menu (maybe the setting can be visible because of async operation)
\\ at 0 and 1 we have the Cut and Copy items
Function Edit1.OpenMenu {
            Local X
            X=SelLength>0
            Enabled(0)=X
            Enabled(1)=X
}
\\ so this is the click on menu
\\ we call methods of Pad to response to clicks
\\ Also we can simulate key press using "PressKey" method
\\ we need ths to perform Tab abd shift - Tab
\\  these used for adding/removing spaces or non break spaces
\\ from the left of line
\\ (can be used for more than on line if we select more than one, at once)
Function Edit1.DblClick {
      Read Local Edit1index
      Select Case Edit1index
      Case 0
            {
            Method Pad,"mn1sub"
            Method Pad,"Resize"
            }
      Case 1
            Method Pad,"mn2sub"
      Case 2
            {
                 Method Pad, "mn3sub"
                 Method Pad,"GetFocus"
                 Method Pad,"Resize"
           }
        Case 4
           {
                  Method Pad,"PressKey", 9, 1
            }
        Case 5
           {
                  Method Pad,"PressKey", 9, 0
            }
      End Select

}

\\ This is an event from Pad to get cursor
Function Pad.Inform {
      Read New L, P
      With Inform1, "Caption", format$("{0}-{1}", L,P)
      Method Pad,"Show"
}

\\ this is the popup event
\\we redirect to Pad, to use it as ready made popup
Function Pad.PopUp {
      Read Local X, Y
      Method Pad,"PopUpMenu", "",X , Y
}

\\ Menu itemsraise events too, while list is open
\\ We want this for File1 menu
\\ When we choose Bas file Pad colored the text. We have to setup the object to color the code
Function File1.MenuChecked {
      Read New RadioIndex \\ 3 or 4
      If RadioIndex =3 then {
            local a$="."+file.type$(Filename$), b$=File.name$(Filename$)
            Filename$=File.path$(Filename$)+Left$(B$,Len(B$)-Len(a$))+".txt"
            Caption$=TitleStr$(File.Name$(Filename$)) +" - M2000 Pad"
            typ$="txt"
            With Pad, "ColorCollection1", "","NoColor", True
            Method Pad, "Show"
      } else.if RadioIndex =4 then {
           local a$="."+file.type$(Filename$), b$=File.name$(Filename$)
            Filename$=File.path$(Filename$)+Left$(B$,Len(B$)-Len(a$))+".bas"
            Caption$=TitleStr$(File.Name$(Filename$)) +" - M2000 Pad"
            typ$="bas"
            With Pad, "ColorCollection1", "|TYPE|AND|OR|XOR|NOT|CLS|DEBUG.|PRINT|DECLARE|CONST|GOTO|DO|LOOP|WHILE|WEND|WITH|REFRESH|LET|GET|SET|DOEVENTS|SELECT|CASE|FALSE|TRUE|OPTION|EXPLICIT|LIB|DIM|REDIM|PUBLIC|PRIVATE|FUNCTION|SUB|IF|THEN|ELSE|ELSEIF|END|SELECT|FOR|NEXT|TO|AS|LONG|BOOLEAN|STRING|OBJECT|EXIT|BYVAL|NEW|LEFT$(|LEFT(|RIGHT$(|RIGHT(|MID$(|MID(|UBOUND(|LBOUND(|CSTR(|CDBL(|CLNG(|STR$(|STRING$(|INSTR(|ASC(|CHR(|CHR$(|COS(|SIN(|LOG(|RGB(|REPLACE(|","NoColor", False
            Method Pad, "ReColor"
            Method Pad, "Show"
      }
}

\\ This is the most tricky function. Because it has logic to do things based on the state of Pad
\\ We use a On X Goto statement to choose label
\\ We want some time to perform goto to specific label from some point of code
\\ This is a spaggeti coding, but perform well, so it can be accepted.
\\ Event calls have no processing code for goto and gosubs. We have to use a block of code.
\\ A goto performed with an exit from block and entering again to specific label
\\ The real exit from program happen when we call method "CloseNow"  for Pad form
\\ this method break the modal form (we see that we open the form as modal)
\\ and has no event (it is a software selection only for closing forms)
Function File1.DblClick {
      Read New File1index
      Local cont, cont2, f$, NL$={
      }
      File1index++
      \\ on Goto need here a block
      {
      On File1index Goto Open1, Save1, ExitNow, ExitNow, ExitNow, ExitNow, Save2, ExitNow, Unload
Exitnow:
      Exit
Open1:
      If Pad.Text$<>BackUp$ Then {
            If Ask("Save Changes first?",Title$, "Yes","No")=1 Then Goto Save1
      }
     Layer NotePad {
           Open.file filename$,,"Load Text ("+typ$+") File",typ$
     }
     Method Pad,"GetFocus"
     Read f$
     If f$<>"" Then {
           Filename$=f$
           If exist(F$) then {
           Clear BackUp$
           \\ we can use a parameter after name, as locale to read using specific Ascii locale
           \\ Always Load.Doc finds what type of file is (Utf-8, Utf-16LE, Utf-16BE, ASCII)
           \\ But can't imagine the ascii locale;
           \\ so using Load.Doc BackUp$, f$, 1049 we read ascii in russian language
           \\ internal document use UTF-16LE.
           \\ Saving done to the way loading happen, or we can choose a way.
           Load.Doc BackUp$, f$
           Caption$=TitleStr$(File.Name$(Filename$)) +" - M2000 Pad"
           Pad.Text$=BackUp$
           } else Pad.text$="": Clear BackUp$
           Method Pad, "ReColor"
      }
      Exit
Save1:
      Layer NotePad {
            Save.As Filename$,,"Save Text ("+typ$+") File",typ$
      }
      if not cont2 then Method Pad,"GetFocus"
      Read f$
      If f$="" Then Exit
      If lcase$(file.type$(f$))<>typ$ then f$=f$+"."+typ$
      If Exist(f$) Then If Ask(NL$+"Overwrite"+NL$+f$,Title$, "Yes","No")<>1 Then Exit
      Try ok {
        Clear BackUp$
        BackUp$=Pad.Text$
        \\ we leave save.doc to save as we load.
        Save.Doc BackUp$, f$
        filename$=f$
        Caption$=TitleStr$(File.Name$(Filename$)) +" - M2000 Pad"
      }
     If ok else beep
     If not cont then Exit
Save2:
      cont=True
      If Pad.Text$<>BackUp$ Then {
            If Ask("Save Changes?",Title$, "Yes","No")=1 Then Goto Save1
      }
      Clear BackUp$
      Pad.Text$=""
      If Cont2 then {
           Method NotePad, "CloseNow"
      } Else {
            FileName$=Dir$+"Untitled."+typ$
            Caption$=TitleStr$(File.Name$(Filename$)) +" - M2000 Pad"
            Method Pad, "Resize"
      }
      Exit
Unload:
      Cont2=True : Goto Save2
      }
}
Function Help1.OpenMenu {
      Local A, info$
      Info$={
            This is an example
            of a notepad
            written for M2000 Environment
            use F1 to change wrap
            }
      A=Ask(info$,Title$,"","")
     ' Method Pad, "GetFocus"

}

\\ so before we actual open the form we perform a resize
\\ to set all controls in positions
\\ (for is loaded, but is not visible)
Call Local Notepad.Resize()

\\ open As modal
Method NotePad,"Show" , 1
\\ after the "CloseNow", we have to clear Pad and NotePad
\\ for other controls there is no need to specific clear it
\\ We call deconstructors at specific time
Declare Pad Nothing
Declare NotePad Nothing
Print "Done"
\\ so now we exit the module, and M2000 erase all variables
\\ deconstructing objects where variables are objects.
}
A: end