Post by tsh73 on May 1, 2021 13:48:19 GMT
I mean Windows, the OS ;)
I had this code lying in Unfinished since 2010
It draws something rectangular with a titlebar, allows it to be dragged/resized
some 250 lines
only one "window", though by title, my ambitions were higher ;)
I remember thinking about using dictionary-like system on strings to store window properties, to make several windows
(I think everybody has some sort of dictionary code lying around, be it one own re-invention or saved from forum)
So I dusted it off and finally added that "Multiple windows" part
What it does:
* F5 redraws screen if you obscure it
* multiple windows, active one has colored title bar
* windows are selected by mouse (it needs Z-order so for now it rather quirky)
* active window could be moved by titlebar
* active window could be resized by lower left corner
* you can add window
* close active window (menu or Ctrl-F4)
* windows could be cycled with Ctrl-Tab and Ctrl-Shift-Tab
Some menu items are not implemented
* minimize/maximize - needs decision if I need doing something like taskbar for that?
* tile/cascade
As I said, it could be made better by implementing Z-order (then determining which window gets mouse click)
Probably close button on window frame (minimize/maximize - see above)
So. It is nice toy.
The only problem could it be actually used for something?
Last time I thought on it on 2010, I got an idea that it will need some programming language to "fill" these windows with something.
I had this code lying in Unfinished since 2010
It draws something rectangular with a titlebar, allows it to be dragged/resized
some 250 lines
only one "window", though by title, my ambitions were higher ;)
I remember thinking about using dictionary-like system on strings to store window properties, to make several windows
(I think everybody has some sort of dictionary code lying around, be it one own re-invention or saved from forum)
'800x600, with menu, not sizable, with graphic box filling all space
'nomainwin
'get size for graphic box first
UpperLeftX = 1
UpperLeftY = 1
WindowWidth = 800
WindowHeight = 600
MENU #gr, " "
open "Ajusting..." for graphics_nsb_nf as #gr
#gr, "home ; down ; posxy x y"
'x, y give us width, height
clientWidth = 2*x : clientHeight = 2*y
'client area
'print clientWidth, clientHeight '792 546
close #gr
' center window
' UpperLeftX=int((DisplayWidth-WindowWidth)/2)
' UpperLeftY=int((DisplayHeight-WindowHeight)/2)
menu #main, "File", "Exit", [onFileExit]
menu #main, "Window", "Create New Window", [onWindowNewWindow], _
|, "Close window", [onWindowClose], _
|, "Minimize window", [onWindowMinimize], _
"Maximize window", [onWindowMaximize], _
|, "Tile windows", [onWindowTile], _
"Cascade windows", [onWindowCascade], _
|, "Close all windows", [onWindowCloseAll]
menu #main, "Help", "About", [onHelpAbout]
'graphicbox #main.gr, 1, 1, width, height
graphicbox #main.gr, 0, 0, clientWidth+2, clientHeight+2
open "Multiple windows" for window_nf as #main
#main, "trapclose [quit.main]"
#main.gr, "down; fill white; flush"
'some bg
gosub [makeBG]
'now, single window
winTitle = 20
winTitle$ = "Test window"
winSizer = 15
winMinH = winTitle+winSizer
winMinW = 100
winTop = 100
winLeft = 150
winHeight = 200
winWidth = 300
gosub [drawWindow]
'#main.gr, "when leftButtonDown [test]"
#main.gr, "when leftButtonDown [startDrag]"
#main.gr, "when leftButtonMove [doDrag]"
#main.gr, "when leftButtonUp [endDrag]"
doDrag = 0
#main.gr, "flush"
wait
'-------------------------------------------
[quit.main]
timer 0 'just for a case
Close #main
END
[startDrag]
'is in header?
doDrag = isInRect(MouseX, MouseY, winLeft, winTop, winWidth, winTitle)
doResize = isInRect(MouseX, MouseY, winLeft+winWidth-winSizer, winTop+winHeight-winSizer, winSizer, winSizer)
if doDrag or doResize then
refX = MouseX: refY = MouseY
#main.gr, "rule XOR"
end if
if doDrag then
'draw first frame
x = winLeft: y = winTop
gosub [drawWinRect]
oldX =x: oldY = y
end if
if doResize then
'draw first frame
x = winWidth: y = winHeight
gosub [drawWinResizer]
oldX =x: oldY = y
end if
wait
[doDrag]
if doDrag then
'drag, rubber rectangle (with XOR)
'clear old one
'winLeft = MouseX + dx => dx = winLeft - MouseX
gosub [drawWinRect]
'update vars
oldX =x: oldY = y
'draw new one
x = winLeft - refX + MouseX
y = winTop - refY + MouseY
gosub [drawWinRect]
end if
if doResize then
gosub [drawWinResizer]
oldX =x: oldY = y
x = winWidth - refX + MouseX
y = winHeight - refY + MouseY
'check min size
if x< winMinW then x = winMinW
if y< winMinH then y = winMinH
gosub [drawWinResizer]
end if
wait
[endDrag]
if not(doDrag or doResize) then wait
'clear old one
if doDrag then gosub [drawWinRect]
if doResize then gosub [drawWinResizer]
#main.gr, "rule OVER"
'redraw window on new place
'clear old window
gosub [makeBG]
'draw on a new place
if doDrag then winLeft=x: winTop=y
if doResize then winWidth=x: winHeight=y
gosub [drawWindow]
wait
[test]
'MouseX and MouseY.
'is in header?
if isInRect(MouseX, MouseY, winLeft, winTop, winWidth, winTitle) then
#main.gr, "color red"
else
#main.gr, "color black"
end if
#main.gr, "place ";winLeft;" ";winTop
#main.gr, "box ";winLeft+winWidth;" ";winTop+winTitle
'is in window?
if isInRect(MouseX, MouseY, winLeft, winTop, winWidth, winHeight) then
#main.gr, "color blue"
else
#main.gr, "color black"
end if
#main.gr, "place ";winLeft;" ";winTop
#main.gr, "box ";winLeft+winWidth;" ";winTop+winHeight
wait
'-- menu subs ------------------------------
[onFileExit] 'Perform action for menu 'File', item 'Exit'
goto [quit.main]
wait
[onHelpAbout] 'Perform action for menu 'Help', item 'About'
ttl$ = "Multiple windows : About"
msg$ = "Multiple windows demo" _
+ chr$(13) + "tsh73 march 2010" _
+ chr$(13) + "inspired by JB desktop shells"
notice ttl$ + chr$(13) + msg$
wait
[onWindowNewWindow]
wait
[onWindowClose]
wait
[onWindowMinimize]
wait
[onWindowMaximize]
wait
[onWindowTile]
wait
[onWindowCascade]
wait
[onWindowCloseAll]
wait
'//- menu subs ------------------------------
'-- returnable subs -------------------------
[drawWinResizer]
#main.gr, "place ";winLeft;" ";winTop
#main.gr, "box ";winLeft+x;" ";winTop+y
return
[drawWinRect]
#main.gr, "place ";x;" ";y
#main.gr, "box ";x+winWidth;" ";y+winHeight
return
[makeBG]
#main.gr, "cls"
'single diagonal
'#main.gr, "line 0 0 ";clientWidth;" "; clientHeight
nLines = 10
for i = 1 to nLines
x0 = i*clientWidth/ nLines
y0 = i* clientHeight/ nLines
#main.gr, "line 0 0 ";x0;" "; clientHeight
#main.gr, "line 0 0 ";clientWidth;" "; y0
' #main.gr, "line ";x0;" "; 0;" ";clientWidth;" "; clientHeight
' #main.gr, "line ";0;" "; y0;" ";clientWidth;" "; clientHeight
next
return
[drawWindow]
#main.gr, "backcolor lightgray"
'body
#main.gr, "place ";winLeft;" ";winTop
#main.gr, "boxfilled ";winLeft+winWidth;" ";winTop+winHeight
'resizer rect
#main.gr, "place ";winLeft+winWidth-winSizer;" ";winTop+winHeight-winSizer
#main.gr, "boxfilled ";winLeft+winWidth;" ";winTop+winHeight
'title bar
#main.gr, "backcolor darkgray"
#main.gr, "place ";winLeft;" ";winTop
#main.gr, "boxfilled ";winLeft+winWidth;" ";winTop+winTitle
#main.gr, "place ";winLeft+5;" ";winTop+winTitle-5
#main.gr, "\";winTitle$
return
'//- returnable subs ------------------------
'-- subs and functions ----------------------
function isInRect(x, y, l, t, w, h)
'is point x, y in rectangle with left top l t and width height w h?
isInRect = (l<=x) and (x<=l+w) and (t<=y) and (y<=t+h)
end function
'//- subs and functions ---------------------
So I dusted it off and finally added that "Multiple windows" part
What it does:
* F5 redraws screen if you obscure it
* multiple windows, active one has colored title bar
* windows are selected by mouse (it needs Z-order so for now it rather quirky)
* active window could be moved by titlebar
* active window could be resized by lower left corner
* you can add window
* close active window (menu or Ctrl-F4)
* windows could be cycled with Ctrl-Tab and Ctrl-Shift-Tab
Some menu items are not implemented
* minimize/maximize - needs decision if I need doing something like taskbar for that?
* tile/cascade
As I said, it could be made better by implementing Z-order (then determining which window gets mouse click)
Probably close button on window frame (minimize/maximize - see above)
So. It is nice toy.
The only problem could it be actually used for something?
Last time I thought on it on 2010, I got an idea that it will need some programming language to "fill" these windows with something.
'800x600, with menu, not sizable, with graphic box filling all space
'v4: 2 windows?
' +objStr library
' 'data in format "key=value|key=value". So = and | reserved.
' +window data in objStr
' (+) kinda works
'v5: cosmetics
' redraw on menu (+)/ on F5 (+)
' colored border / title(+) of active window?
'multiple windows: menu add (+)/close window(+)/ close all(+)
' bonus: CtrlTab, CtrlShiftTab window cycling
'nomainwin
'get size for graphic box first
UpperLeftX = 1
UpperLeftY = 1
WindowWidth = 800
WindowHeight = 600
maxWindows=100 'pretty much arbitrary
dim wind$(maxWindows)
global nWindows, topActiveWindow
nWindows = 0
topActiveWindow = 0
MENU #gr, " "
open "Ajusting..." for graphics_nsb_nf as #gr
#gr, "home ; down ; posxy x y"
'x, y give us width, height
clientWidth = 2*x : clientHeight = 2*y
'client area
'print clientWidth, clientHeight '792 546
close #gr
' center window
' UpperLeftX=int((DisplayWidth-WindowWidth)/2)
' UpperLeftY=int((DisplayHeight-WindowHeight)/2)
menu #main, "File", "Exit", [onFileExit]
menu #main, "Window", "Create New Window", [onWindowNewWindow], _
|, "Close window Ctrl-F4", [onWindowClose], _
|, "Next window Ctrl-Tab", [onNextWindow], _
"Previous window Ctrl-Shift-Tab", [onPrevWindow], _
|, "Minimize window", [onWindowMinimize], _
"Maximize window", [onWindowMaximize], _
|, "Tile windows", [onWindowTile], _
"Cascade windows", [onWindowCascade], _
|, "Close all windows", [onWindowCloseAll], _
|, "Redraw All F5", [onRedrawAll]
menu #main, "Help", "About", [onHelpAbout]
'graphicbox #main.gr, 1, 1, width, height
graphicbox #main.gr, 0, 0, clientWidth+2, clientHeight+2
open "Multiple windows" for window_nf as #main
#main, "trapclose [quit.main]"
#main.gr, "down; fill white; flush"
'some bg
gosub [makeBG]
'now, single window
global winTitle, winSizer, winMinH, winMinW
winTitle = 20
winSizer = 15
winMinH = winTitle+winSizer
winMinW = 100
lastCreaWinTop = 0
lastCreaWinLeft = 0
nWindows = nWindows+1
nWin = nWindows
winTitle$ = "Test window ";nWin
winTop = 100
winLeft = 150
winHeight = 200
winWidth = 300
'manual way of creating objStr
wind$ = "Title"+"="+winTitle$
wind$ = wind$ +"|"+"Top=";winTop
wind$ = wind$ +"|"+"Left=";winLeft
wind$ = wind$ +"|"+"Height=";winHeight
wind$ = wind$ +"|"+"Width=";winWidth
wind$(nWin)=wind$
topActiveWindow = nWin 'before drawing, so it has colored titlebar
gosub [RedrawAll]
'goto [skip2nd]
'another one
nWindows = nWindows+1
nWin = nWindows
winTitle$ = "Test window ";nWin
winTop = 150
winLeft = 250
winHeight = 220
winWidth = 330
'using subs for working with objStr
wind$ =""
call SetVal wind$, "Title", winTitle$
call SetValN wind$, "Top", winTop
call SetValN wind$, "Left", winLeft
call SetValN wind$, "Height", winHeight
call SetValN wind$, "Width", winWidth
wind$(nWin)=wind$
topActiveWindow = nWin
gosub [RedrawAll]
[skip2nd]
'#main.gr, "when leftButtonDown [test]"
#main.gr, "when leftButtonDown [startDrag]"
#main.gr, "when leftButtonMove [doDrag]"
#main.gr, "when leftButtonUp [endDrag]"
#main.gr, "when characterInput [key]"
#main.gr, "setfocus"
doDrag = 0
#main.gr, "flush"
wait
'-------------------------------------------
[quit.main]
timer 0 'just for a case
Close #main
END
[startDrag]
doDrag=0: doResize=0
'is it in active window?
nWin =topActiveWindow
wind$=wind$(nWin)
winLeft = GetValN(wind$, "Left")
winTop = GetValN(wind$, "Top")
winHeight = GetValN(wind$, "Height")
winWidth = GetValN(wind$, "Width")
hit = isInRect(MouseX, MouseY, winLeft, winTop, winWidth, winHeight)
'print "topActiveWindow is ";nWin; " ";
'print wind$
'print "hit ";hit
if not(hit) then 'could be another window
'other windows?
'actually needs z-order
for nWin = 1 to nWindows
if nWin = topActiveWindow then [skipActiveWindow1]
wind$=wind$(nWin)
winLeft = GetValN(wind$, "Left")
winTop = GetValN(wind$, "Top")
winHeight = GetValN(wind$, "Height")
winWidth = GetValN(wind$, "Width")
hit = isInRect(MouseX, MouseY, winLeft, winTop, winWidth, winHeight)
'print "nWin ";nWin; " ";
'print wind$
'print "hit ";hit
if hit then exit for
[skipActiveWindow1]
next
'if not(hit) then print "click not in window":wait
if not(hit) then wait
if nWin <> topActiveWindow then 'draw on top, make topActive
topActiveWindow = nWin
gosub [RedrawAll] 'becuase I have to change color of previously active window
wait
end if
'else try to move
end if
'is in header?
doDrag = isInRect(MouseX, MouseY, winLeft, winTop, winWidth, winTitle)
doResize = isInRect(MouseX, MouseY, winLeft+winWidth-winSizer, winTop+winHeight-winSizer, winSizer, winSizer)
if doDrag or doResize then
refX = MouseX: refY = MouseY
#main.gr, "rule XOR"
end if
if doDrag then
'draw first frame
x = winLeft: y = winTop
gosub [drawWinRect]
oldX =x: oldY = y
end if
if doResize then
'draw first frame
x = winWidth: y = winHeight
gosub [drawWinResizer]
oldX =x: oldY = y
end if
wait
[doDrag]
if doDrag then
'drag, rubber rectangle (with XOR)
'clear old one
'winLeft = MouseX + dx => dx = winLeft - MouseX
gosub [drawWinRect]
'update vars
oldX =x: oldY = y
'draw new one
x = winLeft - refX + MouseX
y = winTop - refY + MouseY
gosub [drawWinRect]
end if
if doResize then
gosub [drawWinResizer]
oldX =x: oldY = y
x = winWidth - refX + MouseX
y = winHeight - refY + MouseY
'check min size
if x< winMinW then x = winMinW
if y< winMinH then y = winMinH
gosub [drawWinResizer]
end if
wait
[endDrag]
if not(doDrag or doResize) then wait
'clear old one
if doDrag then gosub [drawWinRect]
if doResize then gosub [drawWinResizer]
#main.gr, "rule OVER"
'!! store new values in an obj strings
if doDrag then
wind$ = wind$(topActiveWindow)
'print "SetValN"; wind$
call SetValN wind$, "Top", y
call SetValN wind$, "Left", x
wind$(topActiveWindow)=wind$
end if
if doResize then
wind$ = wind$(topActiveWindow)
'print "SetValN"; wind$
call SetValN wind$, "Height", y
call SetValN wind$, "Width", x
wind$(topActiveWindow)=wind$
end if
'redraw window on new place
gosub [RedrawAll]
'print wind$(1)
'print wind$(2)
wait
[test]
'MouseX and MouseY.
'is in header?
if isInRect(MouseX, MouseY, winLeft, winTop, winWidth, winTitle) then
#main.gr, "color red"
else
#main.gr, "color black"
end if
#main.gr, "place ";winLeft;" ";winTop
#main.gr, "box ";winLeft+winWidth;" ";winTop+winTitle
'is in window?
if isInRect(MouseX, MouseY, winLeft, winTop, winWidth, winHeight) then
#main.gr, "color blue"
else
#main.gr, "color black"
end if
#main.gr, "place ";winLeft;" ";winTop
#main.gr, "box ";winLeft+winWidth;" ";winTop+winHeight
wait
[key]
key$ = Inkey$
if key$ = chr$(0)+chr$(116) then gosub [RedrawAll] 'F5
if key$ = chr$(8)+chr$(9) then gosub [NextWindow] 'ctrlTab - next window
if key$ = chr$(12)+chr$(9) then gosub [PrevWindow] 'ctrlShiftTab - prev window
if key$ = chr$(8)+chr$(115) then gosub [CloseWindow] 'ctrl-F4 - close window
wait
'-- menu subs ------------------------------
[onFileExit] 'Perform action for menu 'File', item 'Exit'
goto [quit.main]
wait
[onHelpAbout] 'Perform action for menu 'Help', item 'About'
ttl$ = "Multiple windows : About"
msg$ = "Multiple windows demo" _
+ chr$(13) + "tsh73 march 2010" _
+ chr$(13) + "inspired by JB desktop shells" _
+ chr$(13) + "continued on may 2021"
notice ttl$ + chr$(13) + msg$
wait
[onWindowNewWindow]
Title$=""
gosub [mkNewWindow]
wait
[onWindowClose]
gosub [CloseWindow]
wait
[onWindowMinimize]
wait
[onWindowMaximize]
wait
[onWindowTile]
wait
[onWindowCascade]
wait
[onWindowCloseAll]
nWindows = 0
topActiveWindow = nWindows
gosub [RedrawAll]
wait
[onRedrawAll]
gosub [RedrawAll]
wait
[onNextWindow]
gosub [NextWindow]
wait
[onPrevWindow]
gosub [PrevWindow]
wait
'//- menu subs ------------------------------
'-- returnable subs -------------------------
[drawWinResizer]
#main.gr, "place ";winLeft;" ";winTop
#main.gr, "box ";winLeft+x;" ";winTop+y
return
[drawWinRect]
#main.gr, "place ";x;" ";y
#main.gr, "box ";x+winWidth;" ";y+winHeight
return
[makeBG]
#main.gr, "cls"
'single diagonal
'#main.gr, "line 0 0 ";clientWidth;" "; clientHeight
nLines = 10
for i = 1 to nLines
x0 = i*clientWidth/ nLines
y0 = i* clientHeight/ nLines
#main.gr, "line 0 0 ";x0;" "; clientHeight
#main.gr, "line 0 0 ";clientWidth;" "; y0
' #main.gr, "line ";x0;" "; 0;" ";clientWidth;" "; clientHeight
' #main.gr, "line ";0;" "; y0;" ";clientWidth;" "; clientHeight
next
return
[RedrawAll]
' print nWindows, topActiveWindow
' for nWin = 1 to nWindows
' print nWin, wind$(nWin)
' next
#main.gr, "rule OVER"
'clear old window
gosub [makeBG]
'draw on a new place
'!! redraw all windows, active - last
for nWin = 1 to nWindows
if nWin <> topActiveWindow then
call drawWindow nWin
end if
next
call drawWindow topActiveWindow
return
[NextWindow]
if nWindows = 0 then wait 'MOD doesn't work
topActiveWindow = (topActiveWindow mod nWindows) +1
gosub [RedrawAll]
return
[PrevWindow]
if nWindows = 0 then wait
topActiveWindow = ((topActiveWindow-2+nWindows) mod nWindows) +1
gosub [RedrawAll]
return
[mkNewWindow]
if Title$="" then
Title$="Test window ";nWindows+1
prompt "Enter a new window title";Title$
end if
if Title$="" then wait 'consider user refused
nWindows = nWindows+1
winHeight = 200
winWidth = 300
winTop = lastCreaWinTop+winTitle
if winTop + winHeight>clientHeight then winTop = 0
lastCreaWinTop = winTop
winLeft = lastCreaWinLeft+winTitle
if winLeft + winWidth>clientWidth then winLeft = 0
lastCreaWinLeft = winLeft
wind$ =""
call SetVal wind$, "Title", Title$
call SetValN wind$, "Top", winTop
call SetValN wind$, "Left", winLeft
call SetValN wind$, "Height", winHeight
call SetValN wind$, "Width", winWidth
wind$(nWindows)=wind$
topActiveWindow = nWindows 'before drawing, so it has colored titlebar
gosub [RedrawAll]
return
[CloseWindow]
if topActiveWindow = 0 then notice "There is no active window to close":wait
if topActiveWindow = nWindows then
nWindows = nWindows-1
topActiveWindow = nWindows 'last one becames active
else
wind$(topActiveWindow) = wind$(nWindows)
nWindows = nWindows-1 'lst one moved instead of active, bacames active
end if
gosub [RedrawAll]
return
'//- returnable subs ------------------------
'-- subs and functions ----------------------
sub drawWindow nWin
wind$=wind$(nWin)
winLeft = GetValN(wind$, "Left")
winTop = GetValN(wind$, "Top")
winHeight = GetValN(wind$, "Height")
winWidth = GetValN(wind$, "Width")
winTitle$ = GetVal$(wind$, "Title")
#main.gr, "backcolor lightgray"
'body
#main.gr, "place ";winLeft;" ";winTop
#main.gr, "boxfilled ";winLeft+winWidth;" ";winTop+winHeight
'resizer rect
#main.gr, "place ";winLeft+winWidth-winSizer;" ";winTop+winHeight-winSizer
#main.gr, "boxfilled ";winLeft+winWidth;" ";winTop+winHeight
'title bar
if nWin <> topActiveWindow then
#main.gr, "backcolor darkgray"
else
#main.gr, "backcolor 0 128 255"
end if
#main.gr, "place ";winLeft;" ";winTop
#main.gr, "boxfilled ";winLeft+winWidth;" ";winTop+winTitle
#main.gr, "place ";winLeft+5;" ";winTop+winTitle-5
#main.gr, "\";winTitle$
'topActiveWindow = nWin 'not here
end sub
function isInRect(x, y, l, t, w, h)
'is point x, y in rectangle with left top l t and width height w h?
isInRect = (l<=x) and (x<=l+w) and (t<=y) and (y<=t+h)
end function
'//- subs and functions ---------------------
' objStr library (testObjects)
' there is ability to do nested stuff if neded at tstRecursObj
'**************************************
function GetVal$(objStr$, key$)
p = instr("|"+objStr$, "|"+key$+"=")
if p then
pair$ = word$(mid$(objStr$,p), 1, "|")
GetVal$ = word$(pair$, 2, "=")
end if
end function
function GetValN(objStr$, key$)
GetValN = val(GetVal$(objStr$, key$))
end function
function HasKey(objStr$, key$) 'shortcut. If no extra spaces...
HasKey = (instr("|"+objStr$, "|"+key$+"=")<>0)
end function
sub SetVal byRef objStr$, key$, value$
p = instr("|"+objStr$, "|"+key$+"=")
if p=0 then
objStr$ = objStr$ + left$("|", len(objStr$)) +key$+"="+value$
else
p = p-1
head$=left$(objStr$, p-1)
p = instr(objStr$, "|", p+1)
if p then tail$=mid$(objStr$, p) else tail$=""
pair$=key$+"="+value$
objStr$ = head$+left$("|", len(head$)) + pair$+tail$
end if
end sub
sub SetValN byRef objStr$, key$, value
call SetVal objStr$, key$, str$(value)
end sub
sub DelKey byRef objStr$, key$
p = instr("|"+objStr$, "|"+key$+"=")
if p=0 then
exit sub
else
p = p-1
head$=left$(objStr$, p-1)
p = instr(objStr$, "|", p+1)
if p then tail$=mid$(objStr$, p+1) else tail$=""
objStr$ = head$+left$("|", len(head$) * len(tail$))+tail$
end if
end sub
function CountKeys(objStr$)
pair$ = "?"
while pair$ <> ""
CountKeys = CountKeys + 1
pair$ = word$(objStr$, CountKeys, "|")
wend
CountKeys = CountKeys - 1
end function
function ListKeys$(objStr$)
pair$ = "?"
while pair$ <> ""
i = i + 1
pair$ = word$(objStr$, i, "|")
ListKeys$ = ListKeys$ + left$(" ", len(ListKeys$)) + trim$(word$(pair$, 1, "="))
wend
end function
function GetValByI$(objStr$, i)
pair$ = word$(objStr$,i, "|")
GetValByI$ = word$(pair$, 2, "=")
end function
function GetValByIN(objStr$, i)
GetValByIN = val(GetValByI$(objStr$, i))
end function
function GetKeyByI$(objStr$, i)
pair$ = word$(objStr$,i, "|")
GetKeyByI$ = word$(pair$, 1, "=")
end function