1. Image Control like a console for input and output:
The Ver11 in Info file has this code:
declare form1 form
declare image1 Image form form1
METHOD image1,"MOVE", 1000,1000, 6000, 3300
With image1,"KeyEvent", true, "Enabled" as enabled, "tabstop", true, "showcaret" as caret, "default", true
enabled=true
caret=true
layer image1 {
form 20, 10
CLS 4,0 : PEN 15
DOUBLE
REPORT 2, "Example"
NORMAL
CLS #336633, 2
REFRESH 10
}
function form1.click {
enabled= not enabled
if enabled then method image1, "GetFocus"
}
bufall=stack
buf$=""
function getline$() {
if stack.size=0 then exit
shift 1,-stack.size
exp$=""
while not empty
exp$+=letter$
end while
=exp$
}
function image1.lostfocus {
layer image1 {
cursor 0, row:print over $(0), getline$(buf$, ! stack(bufall))
}
}
function image1.gotfocus {
layer image1 {
cursor 0, row:print over $(0), buf$;
}
}
function image1.keydown {
read new &k, &s
if s<>2 then exit
if k=86 then
local clip$=clipboard$
if clip$<>"" then keyboard clip$
k=0:s=0
else.if k=67 then
local clip$=getline$(buf$, ! stack(bufall))
if clip$<>"" then clipboard clip$
k=0:s=0
end if
}
Def CheckSurrogateLead(w as integer)=uint(w)>0xD7FF and uint(w)<0xDC00
// HERE WE USE THE TAIL WHEN WE DELETE CHARS (SO WE CAN DELETE DOUBLE WORD CHARACTERS)
Def CheckSurrogateTrail(w as integer)=uint(w)>0xDBFF and uint(w)<0xE000
buf1$=""
function image1.keypress {
if not caret then caret=true
layer image1 {
LOCAL a$, onemore as boolean
a$=KEY$
DO
if a$=chr$(8) then
onemore=false
if len(buf$)>0 then
local w=chrcode(right$(buf$,1))
do
onemore=false
if CheckSurrogateTrail(w) then onemore=true
buf$=left$(buf$, len(buf$)-1)
until not onemore or len(buf$)=0
end if
if len(buf$)=0 and len(bufall)>0 then
stack bufall {read buf$}
if onemore then
buf$=left$(buf$, len(buf$)-1)
end if
cursor 0, row:print over $(0),buf$;
else
if pos>0 then cursor 0, row:print over $(0),buf$;
end if
else.if len.disp(a$)=0 and chrcode(a$)>32 or chrcode(a$)<0 then
// THIS IS FOR COMBINING_DIACRITICAL_MARKS LIKE CHRCODE$(0x301)
// COMBINING ACUTE ACCENT
// hold Alt press + 3 0 1 release Alt
buf$+=a$
cursor 0, row:print over $(0), buf$;
else.iF a$=CHR$(13) then
buf$=getline$(buf$, !bufall)
layer {print buf$:refresh}
cursor 0, row:print over $(0),buf$
print: buf$=""
else.if a$>=" " then
if len.disp(buf$)=width-1 then
stack bufall {push buf$}:buf$="": cursor 0, row:print over
end if
print a$; : buf$+=a$
end if
a$=KEY$
UNTIL a$=""
refresh
}
}
METHOD form1 "SHOW", 1
declare form1 NOTHING
The Image1.KeyPress is an event service function. The actual key retrieved using Key$ (which here not waiting for a key, as in pure M2000 console). We use a Do Until, loop to get all keys, before the end of service.
This is the first version, where we can write a big line and under the hood is a stack object, the bufall, which hold chunks of input line (those parts we didn't show). When we press Enter all chunks combined using the getline$() function. The statement: buf$=getline$(buf$, !bufall) call the getline$ and push on getline$() stack on top buf$ and under all items from bufall (so !bufall just send items from bufall which is a stack to functions stack, and this is fast, because each item in stack has one pointer to copy, the bufall get empty after that).
Some times we change the focus of Image1 so we get the lostFocus event and reset the line from the beginning (first character at the left of "console", or we say left justify). Because we have to prepare the final string, immediatetly, we use this getline$(buf$, ! stack(bufall)) where stack(bufall) return a copy of bufall, so the bufall stack remain intact. The ! operator used for arrays (tuple) and stacks, but for stacks this retrieve all items, and leave them empty.
About Stacks and Arrays.
We can make stacks from arrays, and arrays from stacks. The actual type of stack is mStiva (a com object) and for array (tuple) is mArray.
a=stack((1,2,3))
? type$(a)="mStiva"
? a
? stackitem(a,2)=2
b=array(stack:=1,2,3)
? type$(b)="mArray"
? b
? array(b, 1)=2
Variables a and b are pointers to objects. There is another interface for arrays, which used with identifiers with parenthesis. These arrays are like values. We have to define them using Dim (or Local or Global), We can use up to 10 dimensions, and we can set bounds like this A(1 to 10), B(-4 to -3, 100 to 103) . We can use pointers to arrays like the c variable in the following example:
Dim A(10)=1, B()
B()=A()
B(3)+=10
c=B()
c++
? B(3)=12, B(0)=2, A(0)=1
So c++ add one in each numeric item of B(). Also pointers to arrays handle the array as one dimension. Arrays expand from the first dimension (preserving items). The k variable now is a pointer to k(), but read items as one dimension. Using array() we can use the true dimensions. We can change dimensions with another Dim, and if we place new items these will be of type Empty.
dim K(3,2)
k(0,0)=1,2,3,4,5,6
? K()
dim K(4,2)
k(3,0)=7, 8
? K()
k=k()
? k#val(7)=8
Print array(k, 0,0)
2. Splitter Control using a Listbox
We can make a splitter control using a listbox and proper configuration, through properties and methods, and use of proper events.
In the Info file (info.gsb) included in setup file the new mEditor which utilize the splitter as vertical splitter between the editor's editbox and the help editbox (you have to reload to user directory, using Dir AppDir$ : Load Info and then press F1 to save it to M2000 user directory - also this change the current directory to user directory). Open the mEditor source using Edit mEditor statement in M2000 console.
Method Handle1, "UseVerMove"
mcol=#FFA000
handle1.locked=true
handle1.visible=false
Function Notepad.Resize {
Local FromHelp=false
if match("N") then Read FromHelp
Layer NotePad { Cls Color(255, 160, 0) ,0}
local tHeight1=theight*2
Local free=NP.Height-tHeight1-twipsX*3
local oldhelpshow=helpshow
If NP.height>1800 Then {
If helpview Then
if oldhelpshow else
Method Handle1, "move",twipsX*3, tHeight1+free-free/3-twipsX*3, NP.Width-twipsX*6,twipsY*3
end if
if handle1.locked then handle1.locked=false
local third=handle1.top-tHeight1
if third<twipsX*10 then third=twipsX*10
if free<third then third=free/3
Method Pad,"move", twipsX*3, tHeight1, NP.Width-twipsX*6, third
third+=tHeight1
Method Handle1, "move",twipsX*3, third, NP.Width-twipsX*6,twipsX*3
Method HelpPad,"move", twipsX*3, third+twipsX*3, NP.Width-twipsX*6,free-third-twipsY*3+tHeight1
handle1.visible=true
helpshow=true
Method HelpPad, "resize"
Else
helpshow=false
handle1.visible=false
Method Pad,"move", twipsX*3, tHeight1, NP.Width-twipsX*6, NP.Height-tHeight1-twipsY*3
End If
Method Pad,"Resize"
}
}
Because we want the color of splitter control (the Handle1, a listbox used as splitter) we have to handle these events:
Function Handle1.ValidMove {
Drop
Read New &Y
mcol=7
if y<tHeight+1000 then y=tHeight+1000 : exit
if y>NP.Height-tHeight then y=NP.Height-tHeight
}
Function Handle1.MouseUp {
Call Local Notepad.Resize()
mcol=#FFA000
}
The ValidMove get two byref values, we drop one and we use only the Y (vertical move). So we can stop the move by handling this Y value, if Y get out of bounds we like.
When the move stopped releasing the mouse button we get the MouseUp event and we call the resize event service function of Notepad (the form), plus we restore the color. The #77A000 is the M2000 orange color.
The Handle1 also change Y when we resize the form Notepad, but not always. See line:
if free<third then third=free/3in Notepad.resize function
Δεν υπάρχουν σχόλια:
Δημοσίευση σχολίου
You can feel free to write any suggestion, or idea on the subject.