Well, I have to admit, much to my partner's extreme annoyance, I had another day of boredom. I get bored easily... I've only got half a dozen businesses to run (including my IT / Legal compliance consultancy, an advertising agency which I run with my
partner, an Immigration consultancy which I am trying to close which I ran with my ex-partner and a new online tabloid-esq newspaper which I've just launched... because I was bored and got even more bored of various editors and sub-editors taking my
perfectly well argued freelance articles, and making a dogs dinner of them because they don't like content which is too aggressive).
For anyone looking for a read, or to write something knowing that our editors will correct your grammar and spelling, but will not try to censor your political views, check out my week old baby ... www.news-cyprus.com
Now back to the topic at hand.. (I know... I need a beer).
I am really quite surprised that this little thing has gone down so well. Last night, I sat down for a couple of hours, and made a series of improvements, which really helped with usability and the practicalness of the concept.
So here we go, v 0.12 of rexx tui, which now works in a cls file.
-- class file --
/*
tui.cls
Text Mode UI
v0.12
Tom Dyer
[email protected]
2020
Free to use
*/
call rxFuncAdd "SysLoadFuncs", "REXXUTIL", "SysLoadFuncs"
call SysLoadFuncs
::class WindowManager public inherit SanityCheckSupported
::attribute running
::attribute logger
::attribute keyboard
::attribute screen
::attribute window
::attribute focusableitems
::attribute activeitem
::attribute activewindow
::attribute keybindabletasks
::attribute wmdms /* data management service for window manager, provides some validation etc */
::method init
expose logger screen
use arg logger
self~window = .list~new
self~focusableitems = .list~new
self~keybindabletasks= .list~new
screen= .screen~new()
::method run unguarded
expose keyboard screen
keyboard= .keyboard~new()
keyboard~logger= self~logger
keyboard~wm=self
self~findfocusable
self~drawwindows
self~logger~log("Within the WM code, about to poll keyboard",1)
self~keyboard~poll
self~logger~log("We have returned from polling the keyboard",1 )
return
/*
shortcode
*/
::method add
use arg obj
if .SanityChecker~new~check(obj ,self) = .false then return
if obj~isInstanceOf(.window) then do
self~addWindow(obj)
end
if obj~isInstanceOf(.keybindable) then do
self~addKeyBindableTask(obj)
end
if obj~isInstanceOf(.WMDataManagementService) then do
self~logger~log("added wdms",1)
self~wmdms = obj
end
if obj~isInstanceOf(.screen) then do
self~logger~log("added screen",1)
self~screen = obj
end
::method addKeyBindableTask
use arg keyBindableTask
illegaltobindkey1 = .key~new("[")
illegaltobindkey1~alt=.true
illegaltobindkey2 = .key~new("O")
illegaltobindkey2~alt=.true
if keyBindableTask~key~detail = illegaltobindkey1~detail | keyBindableTask~key~detail = illegaltobindkey2~detail
then do
self~logger~log("tried to add an illegal key binding, refused for" keyBindableTask~key~detail,1)
end
else do
self~logger~log("added keybindanble task to" keyBindableTask~key~detail,1)
self~keybindabletasks~insert(keyBindableTask)
end
::method addWindow
use arg window
if .SanityChecker~new~check(window,self) = .false then return
window~screen = self~screen
window~wm=self
self~window~insert(window)
if self~window~items=1 then do
self~activewindow = 0
end
::method gotoWindow
use arg windowNumber
self~activewindow= windowNumber
self~findfocusable
::method findfocusable
self~focusableitems = .list~new
do i = 0 to self~window~at(self~activewindow)~objects~items -1
if (self~window~at(self~activewindow)~objects~at(i))~isInstanceOf(.focusable) then do
self~focusableitems~insert(self~window~at(self~activewindow)~objects~at(i))
end
end
self~focusableitems~at(0)~hasFocus = .true
self~activeitem= self~focusableitems~at(0)
::method nextFocus
self~logger~log("Changing to next focus" self~focusableitems~items,0)
do i = 0 to self~focusableitems~items -1
if self~focusableitems~at(i)~hasFocus = .true then do
self~focusableitems~at(i)~lostFocus
if i = self~focusableitems~items -1 then do
self~focusableitems~at(0)~gotFocus
self~activeitem=self~focusableitems~at(0)
return
end
else do
self~focusableitems~at(i+1)~gotFocus
self~activeitem=self~focusableitems~at(i+1)
return
end
end
end
::method drawwindows
do i = 0 to self~window~items
self~window~at(self~activewindow)~draw
end
::method sendkey
use arg key
self~logger~log("WM - key pressed was" key~detail,0)
select
when key~alt= .true & upper(key~value) = "X" then do
self~keyboard~running= .false
self~screen~running = .false
self~logger~log("shutdown called",0)
end
when key~alt= .true & upper(key~value) = "R" then do
self~drawwindows
self~screen~draw
end
when key~tab=.true then do
self~nextFocus
end
when key~alt= .true then do
/*
send it to anything with global keybindability on alt
*/
do i = 0 to self~keybindabletasks~items -1
self~logger~log("WM sending keystroke to keybindabletask",2)
self~keybindabletasks~at(i)~sendkey(key)
end
end
otherwise
/*
then send the key to the active item
*/
self~activeitem~sendkey(key)
end
self~drawwindows
::class screen public inherit AlarmNotification SanityCheckSupported
::attribute logger
::attribute rows
::attribute columns
::attribute platform
::attribute running
::attribute data
::constant ansi '1b5b'x
::constant black 0
::constant red 1
::constant green 2
::constant yellow 3
::constant blue 4
::constant magenta 5
::constant cyan 6
::constant white 7
::constant grey 8
::constant brightred 9
::constant brightgreen 10
::constant brightyellow 11
::constant brightblue 12
::constant brightmagenta 13
::constant brightcyan 14
::constant brightwhite 15
::attribute recheckScreensize
::attribute forceClear
::method ansiclear
say self~ansi||'2J'
::constant isLinux linux
::constant isWindows windows
::method init
use arg logger
self~logger
self~data = .mutablebuffer~new()
self~recheckScreensize = 30 /* check every 30 seconds on repaint for screen size change */
self~forceClear = .false
if pos("Linux", SysVersion()) <> 0 then do
self~platform=self~isLinux
end
if pos("Windows", SysVersion()) <> 0 then do
self~platform =self~isWindows
end
self~getscreensize
self~setalarm
::method setalarm
if self~running = .false then exit
alarm = .alarm~new(1, self)
::method setcursor
use arg widget
/* ansi movement code in screen */
output=self~ansi||self~getPositionRow(widget)||";"self~getPositionColumn(widget)||"H "
return output
::method setcolour
use arg obj
output = ""
if obj~isInstanceOf(.coloured) then do
output = self~getColourForObject(obj)
end
return output
/*
relies on ansi colours working
*/
::method getColourForObject
use arg obj
if obj~fgcolour= "FGCOLOUR" then do
/* default */
output = self~ansi||"39m"
end
else do
output = self~ansi||"38;5;"||obj~fgcolour||"m"
end
/*
bgcolour doesn't work reliably
*/
if obj~bgcolour= "BGCOLOUR" then do
output = output /* don't deal with no bg colour */
end
else do
output = output||self~ansi||"48;5;"||obj~bgcolour||"m"
end
return output
::method getscreensize
expose rows columns
if self~platform = self~isLinux then do
/* linux */
do line over .SystemQueue~new("stty size ") ; nop ; end
parse var line rows columns
end
if self~platform = self~isWindows then do
/* not tested but should work eh */
parse value SysTextScreenSize() with rows columns
end
::method triggered
t = time(Seconds)
if t // self~recheckScreensize = 1 then do
self~getscreensize
end
self~draw
::method draw
if self~forceClear = .true then do
self~clear
end
say self~data
self~setalarm
::method clear
self~ansiclear
/* call SysCls */
::method getPositionRow
use arg widget
return widget~row
::method getPositionColumn
use arg widget
return widget~column
/*
Virtual Screen
This class treats the screen as if the itens were positioned on a 80/25 display and then moves the items to fit the actual display
*/
::class VirtualScreen public subclass Screen
::constant vColumns 80
::constant vRows 25
::method init
use arg logger
self~init:super(logger) /* normal init */
self~recheckScreensize = 5 /* set to check screen more frequently for size changes */
self~PlatformCheck /* run platform specific checks - this isolates some platform specific code */
::method PlatformCheck
if self~isLinux = .true then do
/*
Set the screen to run line by line, rather than char by char, used for high latency links
and ideal for making a programme which paints the entire screen at a time
function correctly.
*/
"stty extproc"
do line over .SystemQueue~new("echo $TERM") ; nop ; end /* $ */
parse var line terminal
if upper(terminal) = upper("LINUX") then do
/* I think we have been opened using a full screen window on a hard tty */
self~recheckScreensize = 60 /* so lets minimise the number of times we check the screen size to the minimum */
end
end
::method getPositionColumn
use arg widget
wcol = self~getPositionColumn:super(widget)
factor = self~columns / self~vColumns
rc=lineout("position", "factor c"||factor)
posC = (factor * wcol ) %1
rc=lineout("position", "C"||posC)
return posC
::method getPositionRow
use arg widget
wrow = self~getPositionRow:super(widget)
factor = self~rows / self~vRows
rc=lineout("position", "factor r"||factor)
posR = (factor * wrow)%1
rc=lineout("position", "R"||posR)
return posR
::class keyboard inherit SanityCheckSupported
::attribute logger
::attribute running
::attribute wm
::method poll unguarded
if self~running = .false then exit
/*
get key from keyboard
*/
k = sysgetkey("noecho")
/* now create an object for the key */
key = .key~new
/* now work out the correct treatment */
select
/* tab pressed, probably used for moving between fields */
when c2x(k) = .key~tabcode then do
key~tab=.true
key~value=""
end
/* backspace which will have special treatment */
when c2x(k) = .key~bscode then do
key~bs=.true
key~value=""
end
/* space needs some care as well */
when c2x(k) = .key~spacecode then do
key~space=.true
key~value=" "
end
/* if an alt button pressed, we need the next key to determine what was actually pressed */
/* special keyboard control characters such as F1 -> F12, and arrow keys need multiple buttons */
when c2x(k) = .key~altcode then do
k2 = sysgetkey("noecho")
select
when k2 = "O" then do
/* We've got a special control character such as fn buttons which use 3 parts */
k3 = sysgetkey("noecho")
/* note, you cannot bind to ALT-O alone */
select
when k3 = .key~fn1code then do
key~fn1 = .true
end
when k3 = .key~fn2code then do
key~fn2 = .true
end
when k3 = .key~fn3code then do
key~fn3 = .true
end
when k3 = .key~fn4code then do
key~fn4 = .true
end
when k3 = .key~fn5code then do
key~fn5 = .true
end
when k3 = .key~fn6code then do
key~fn6 = .true
end
when k3 = .key~fn7code then do
key~fn7 = .true
end
when k3 = .key~fn8code then do
key~fn8 = .true
end
when k3 = .key~fn9code then do
key~fn9 = .true
end
when k3 = .key~fn10code then do
key~fn10 = .true
end
when k3 = .key~fn11code then do
key~fn11 = .true
end
when k3 = .key~fn12code then do
key~fn12 = .true
end
otherwise do
end
end
end
when k2 = "[" then do
/* We've got a special control character such as an arrow key which uses 3 parts */
k3 = sysgetkey("noecho")
select
when k3 = .key~backtabcode then do
key~backtab = .true
end
when k3 = .key~uparrowcode then do
key~uparrow = .true
end
when k3 = .key~downarrowcode then do
key~downarrow = .true
end
when k3 = .key~rightarrowcode then do
key~rightarrow = .true
end
when k3 = .key~leftarrowcode then do
key~leftarrow = .true
end
/* we are not handling these keys */
otherwise do
nop
end
end
key~value=""
end
/* the key that was pressed was a standard ALT key such as ALT-P which uses 2 parts */
otherwise do
key~alt=.true
key~value= k2
end
end
end
/* it seems that it was a normal keystroke, so let's just set the value */
otherwise do
key~value = k
end
end
self~logger~log("keyboard class sending " key~detail(), 2)
/*
Now hand the job of working out what to do to the Window Manager
*/
self~wm~sendkey(key)
/*
and kick off the poll again...
*/
self~poll
/*
Class for keys used to handle input
*/
::class key public
::constant altcode "1B"
::constant tabcode "09"
::constant spacecode "20"
::constant bscode "7F"
::constant backtabcode "5A" /* 1B 5B 5A */
::constant uparrowcode "41" /* 1B 5B 41 */
::constant downarrowcode "42" /* 1B 5B 42 */
::constant rightarrowcode "43" /* 1B 5B 43 */
::constant leftarrowcode "44" /* 1B 5B 44 */
::constant fn1code
::constant fn2code
::constant fn3code
::constant fn4code
::constant fn5code
::constant fn6code
::constant fn7code
::constant fn8code
::constant fn9code
::constant fn10code
::constant fn11code
::constant fn12code
::attribute alt
::attribute tab
::attribute value
::attribute space
::attribute bs
::attribute uparrow
::attribute downarrow
::attribute rightarrow
::attribute leftarrow
::attribute backtab
::attribute fn1
::attribute fn2
::attribute fn3
::attribute fn4
::attribute fn5
::attribute fn6
::attribute fn7
::attribute fn8
::attribute fn9
::attribute fn10
::attribute fn11
::attribute fn12
/*
Comparison method for keys
*/
::method "="
use arg obj
/*
By default they don't match
*/
rc = .false
select
when obj~isInstanceOf(.Key) then do
/* if both keys then compare detail */
if obj~detail = self~detail then rc = .true
end
when obj~isInstanceOf(.String) then do
/* if one is a string and the other is special, they can't match */
if self~isSpecial = .true then rc = .false
else do
/* if it's not a special, then try comparing the letters themselves caseless*/
if upper(obj)= upper(self~value) then rc = .true
end
end
otherwise
rc = .false
end
return rc
::method get
expose value
return value
::method isSpecial
if self~alt = .true | self~tab = .true | self~space = .true | self~bs = .true | self~uparrow = .true | self~downarrow = .true | self~rightarrow = .true | self~leftarrow = .true | self~backtab = .true | self~fn1 = .true | self~fn2 = .true | self~fn3 = .
true | self~fn4 = .true | self~fn5 = .true | self~fn6 = .true | self~fn7 = .true | self~fn8 = .true | self~fn9 = .true | self~fn10 = .true | self~fn11 = .true | self~fn12 = .true then return .true
else
return .false
::method init
use arg kv=""
self~value= kv
/*
detail of the key - in long form
*/
::method detail
return self~value c2x(self~value) self~alt self~tab self~space self~bs self~uparrow self~downarrow self~rightarrow self~leftarrow self~backtab self~fn1 self~fn2 self~fn3 self~fn4 self~fn5 self~fn6 self~fn7 self~fn8 self~fn9 self~fn10 self~fn11 self~fn12
/*
This isn't anywhere near working but if you uncomment the lineouts.. you can get some output
*/
::class logger public
::attribute logdata
::attribute running
::method init
expose stem
use arg stem=.nil
self~logdata = .list~new
::method log
expose loglevel
use arg message, level
if level > loglevel then do
self~logdata~insert(message)
rc=lineout("logfile",message)
end
::method setloglevel
expose loglevel
parse arg loglevel
::method unknown
expose stem
use arg msg, text
stem[0] += 1
index = stem[0]
stem[index] = text~makeString
self~log(msg,9)
self~log(text,9)
self~log(text~makeString,9)
/*
A window to the soul
*/
::class Window public inherit SanityCheckSupported coloured
::attribute name
::attribute screen
::attribute objects
::attribute wm
::attribute logger
::method init
self~objects = .list~new
::method draw
self~makewindow
self~screen~data = self~makewindow
::method maketitlebar
titlebar = center( self~name, self~screen~columns, "*")
return titlebar
::method makewindow
d = self~screen~setcolour(self)
d = d||self~maketitlebar
do i = 1 to self~screen~rows-2
d = D||"*" || right("*",self~screen~columns-1," ")
end
time = time()
d = d||center(time, self~screen~columns, "*")
do i = 1 to self~objects~items
d=d||self~screen~setcolour(self~objects~at(i-1))
d=d||self~screen~setcursor(self~objects~at(i-1))
d=d||self~objects~at(i-1)~draw
end
return d
::method add
use arg obj
if .SanityChecker~new~check(obj,self) = .false then return
if obj~isInstanceOf(.widget) then do
self~objects~insert(obj)
end
if obj~isInstanceOf(.keybindable) then do /* bind against the wm instead - fix for common error */
self~wm~add(obj)
end
::class logwindow subclass window
::attribute logger
::method draw
super~draw
do i = 1 to logger~logdata~allItems
self~screen~data(logger~logdata[i])
end
/*
The standard widget class
*/
::class widget inherit coloured
::attribute row
::attribute column
::attribute data
::attribute disdata
::attribute validator
::method predraw
self~disdata = self~data
::method draw
self~predraw
return self~disdata
::method init
expose data row column
use arg data, row , column
row = row + 2
column = column + 2
::method add
use arg obj
if .SanityChecker~new~check(obj) = .false then return
if obj~isInstanceOf(.validator) = .true then self~validator = obj
/* assume that any label being added to a widget is actually the field help field */
if obj~isInstanceOf(.label) = .true then self~validator~fieldhelp = obj
/* assume that we are trying to set the field help */
if obj~isInstanceOf(.string) = .true then self~validator~fieldhelpstring = obj
/* labels are boring but necessary */
::class label public subclass widget
/*everyone needs a button */
::class button public subclass widget inherit focusable focuscoloured ::attribute length
::attribute task
::method init
expose length
use arg data, row, column, length
self~init:super(data,row, column)
::method predraw
self~disdata = "["||center(self~data,self~length-2," ")||"]"
if self~hasFocus = .true then do
self~disdata = self~disdata ||" * "
end
::method sendkey
self~task~run
/*
Input box
*/
::class inputbox public subclass widget inherit focusable clearable focuscoloured
::attribute length
::attribute fixedlength
::attribute showlength
::method init
expose data row column length
use arg data, row, column, length
self~validator = .validator~new() /* default validator used */
self~fixedlength = .nil
self~init:super(data, row, column)
::method predraw
self~disdata = left(self~data,self~length,"_")
if self~hasFocus = .true then do
self~disdata = self~disdata ||" * "
end
if self~showlength= .true then do
if self~fixedlength = .true then do
self~disdata = self~disdata length(self~data)||"/"||self~length
end
else self~disdata = self~disdata length(self~data)
end
::method sendkey
use arg key
if key~bs = .true & length(self~data ) > 0 then do
self~data = left(self~data, length(self~data)-1 )
end
else do
if self~validator~isNil = .false then do
if self~validator~isValidKey(key) = .false then key~value = ""
end
/*
can't type too much in a fixed length field
*/
if self~fixedlength = .true then do
if length(self~data)+1 > self~length then key~value = ""
end
self~data = self~data||key~value
end
/*
*/
::class searchbox public subclass inputbox
::attribute list
::attribute keyed
::attribute matching
::method init
use arg data, row, column, length
self~keyed=""
self~matching=0
self~init:super(data,row,column,length)
::method sendkey
use arg key
self~sendkey:super(key)
self~matching = 0
if key~bs = .true then do
if length(self~keyed) >= 1 then do
self~keyed = strip(left(self~keyed,length(self~keyed)-1))
end
end
else do
self~keyed = self~keyed||key~value
end
do i = 0 to self~list~items -1
if upper(self~keyed) = upper(left(self~list~at(i),length(self~keyed))) then do
self~matching = self~matching + 1
self~data = self~list~at(i)
end
end
if self~matching = 0 then self~data = ""
::method predraw
self~predraw:super()
self~disdata = self~disdata || "Matching " self~matching
/*
Password box
*/
::class passwordbox public subclass inputbox
::method predraw
self~disdata = left(copies("*",self~data~length),self~length,"_")
if self~hasFocus = .true then do
self~disdata = self~disdata ||" P "
end
/*
Radio box
*/
::class radiobox public subclass inputbox
::attribute options
::attribute selected
::method init
use arg opts, row, column, length
if .SanityChecker~new~check(opts) = .false then do
self~lackingrequiredobject = .true
end
self~options= .list~new
self~options= opts
self~selected = 0
self~init:super(self~options~at(0),row, column, length)
::method predraw
self~disdata = ""
do i = 0 to self~options~items -1
if i = self~selected then do
self~disdata = self~disdata || " X " || self~options~at(i)
end
else do
self~disdata = self~disdata || " . " || self~options~at(i)
end
end
if self~hasFocus = .true then do
self~disdata = self~disdata ||" * "
end
::method sendkey
self~selected = self~selected + 1
if self~selected = self~options~items then self~selected = 0
self~data = self~options~at(self~selected)
::method clear
self~selected = 0
self~data=self~options~at(0)
/*
data entry validators
*/
::class validator public
/*
normal validator letters and numbers
*/
::attribute validkeys
::attribute fieldhelpstring
::attribute fieldhelp
::method init
use arg fieldhelp=.nil
self~validkeys = .string~graph || " £"
self~fieldhelpstring = "This field is alphanumeric"
self~fieldhelp = fieldhelp
::method isValidKey
use arg key
if self~fieldhelp~isNil = .false then do
self~fieldhelp~data = self~fieldhelpstring
end
if pos(key~value, self~validkeys) > 0 then return .true
else return .false
::method fieldContentValidate
use arg widget
if widget~isInstanceOf(.validatable) then do
self~validatedata(widget)
end
::class numericvalidator public subclass validator
/*
numeric validator
*/
::method init
use arg fieldhelp=.nil
self~init:super(fieldhelp)
self~validkeys = .string~digit
self~fieldhelpstring = "This field is numeric only"
/*
mixinclasses here
*/
::class focusable mixinclass object
::attribute hasFocus
::method gotFocus
self~hasfocus = .true
if self~isInstanceOf(.focuscoloured) then do
self~changetoFocusColour()
end
::method lostFocus
self~hasfocus = .false
if self~isInstanceOf(.focuscoloured) then do
self~changetoDefaultColour()
end
/*
*/
::class validatable mixinclass object
::attribute valid
/*
clears fields to have blank by default. radio boxes need different treatment and to override this
*/
::class clearable mixinclass object
::method clear
self~data = ""
/*
allows items to be coloured
*/
::class coloured mixinclass object
::attribute fgcolour
::attribute bgcolour
/*
focus coloured
*/
::class focuscoloured mixinclass object inherit coloured
::attribute focusfgcolour
::attribute defaultfgcolour
::method changetoFocusColour
if self~focusfgcolour != "FOCUSFGCOLOUR" then do
self~fgcolour = self~focusfgcolour
end
::method changetoDefaultColour
if self~defaultfgcolour != "DEFAULTFGCOLOUR" then do
self~fgcolour = self~defaultfgcolour
end
/*
used to make keybindable tasks
*/
::class keybindable mixinclass object
::attribute key
::method sendkey
use arg keypressed
if upper(self~key~value) = upper(keypressed~value) then do
self~run()
end
::class SanityCheckSupported mixinclass object
::method SanityCheckLog
use arg msg
self~logger~log(self " " message)
/*
because it's nice to have nice code
*/
::class SystemQueue subclass RexxQueue
::method init
use strict arg command
command "| rxqueue"
self~init:super
/*
crashfile
*/
::class trapout public
::method init
expose stem
use arg stem
::method unknown
expose stem
use arg msg, text
stem[0] += 1
index = stem[0]
stem[index] = text~makeString
.error~destination
call lineout("crashfile", msg " " text~makeString)
/*
Because it's not particularly easy if you insert a misformed object or widget, this SanityChecker is called to ensure that objects are correctly initialised
prior to adding them to a window, windowmanager, task etc.
*/
::class SanityChecker
::attribute errorcheckcode
::method check
use arg obj, callingobj=.nil
if callingobj <> .nil then do
if callingobj~isInstanceOf(.SanityCheckSupported) then do
response = self~performcheck(obj)
if response = .false then do
callingobj~SanityCheckLog("Problem "self~errorcheckcode "with object" obj "called from" callingobj)
end
end
end
else do /* not able to notify back */
response = self~performcheck(obj)
end
return response
::method performcheck
expose checkerrorcode
use arg obj
if obj = .nil then do
say "SanityChecker failed on" obj
return .false
end
return .true
/*
override this to perform a job when action occurs
*/
::class Task public
::attribute window
::method init
use arg window
self~window= window
::method run
/* override this method */
/*
example task to clear the fields
*/
::class clearEntryTask public subclass Task
::method run
do i = 0 to (self~window~objects~items -1)
if self~window~objects~at(i)~isInstanceOf(.clearable) = .true then do
self~window~objects~at(i)~clear
end
end
/*
Task to move to a specific window
*/
::class goToWindowTask public subclass Task
::attribute windownumber
::method init
use arg win, windownumber
self~windownumber = windownumber
self~init:super(win)
::method run
self~window~wm~gotoWindow(self~windownumber)
/*
this isn't a button, this is registered against a keystroke. Works the same way though
*/
::class goToWindowTaskkey public subclass goToWindowTask inherit keybindable
::class printAllFieldsToFile public subclass Task
::method init
use arg win
self~init:super(win)
::method run
do i over self~window~wm~wmdms~allIndexes
call lineout "fields", i " " self~window~wm~wmdms~at(i) " " self~window~wm~wmdms~at(i)~data
end
/*
WindowManager Data Management Service
Provides information on whether fields and windows have been displayed, whether they validated, and allows the registration of certain data requirements
to help for timely development
at the moment it's just a directory of fields
*/
::class WMDataManagementService public subclass Directory
::method getValue
use arg obj
field = self~get(obj)
if field~isNil = .false then return .nil
else do
return field~data
end
===================== END CLASS FILE =====================
===================== Test Application ===================
/*
rexxTUI.rex
Test rexx app for UI
version 0.12
*/
/*
some code to get a crash file in case everything goes pearshaped
*/
out.0 = 0 -- create the stem
pdest = .error~destination(.trapout~new(out.))
/*
main example code
*/
/*
create the window manager and set logging level
*/
wm = .windowmanager~new(.logger~new)
wm~logger~setloglevel(-1)
wmdms =.WMDataManagementService~new
/*
create a window
*/
win = .window~new
win~logger=wm~logger
win= .window~new
win~name = "Window number 1"
win~bgcolour= .screen~blue
win~fgcolour= .screen~white
secondwin= .window~new
secondwin~name = "Window number 2"
secondwin~logger = wm~logger
secondwin~bgcolour= .screen~blue
secondwin~fgcolour= .screen~brightyellow
/*
create some elements for the windows
*/
label1 = .label~new("this is a label",2,1)
label2 = .label~new("a second label", 3,1)
input1 = .inputbox~new("", 2, 20, 30)
input1~fixedlength=.false
input1~showlength=.true
input1~focusfgcolour = .screen~brightgreen
input2 = .inputbox~new("", 3, 20, 30)
input2~showlength=.true
input2~fixedlength=.true
input2~fgcolour = .screen~green
input2~focusfgcolour = .screen~brightyellow
input3 = .passwordbox~new("", 4, 20, 30)
input3~fgcolour = .screen~green
input3~focusfgcolour = .screen~brightgreen
radiooptions = .list~new
radiooptions~insert("Free like beer")
radiooptions~insert( "Free like speech")
radiooptions~insert("Freedom to bare arms")
input4 = .radiobox~new(radiooptions, 5,20,40)
input4~fgcolour = .screen~yellow
fieldhelplabel = .label~new("** I am sure I am not here **",15,20)
input1s2 = .inputbox~new("",2, 20, 30)
input2s2 = .searchbox~new("", 3, 20, 30)
input2s2~list=.list~new()
input2s2~list~insert("Dasha")
input2s2~list~insert("Dusy")
input2s2~list~insert("Thomas")
input2s2~list~insert("Bob")
input2s2~list~insert("Marina")
input2s2~list~insert("Martin")
input2s2~list~insert("Arthur")
input2s2~list~insert("Tamsyn")
input2s2~fgcolour=.screen~brightyellow
/*
set up a couple of field validators
The
*/
input1~add(.validator~new(fieldhelplabel))
input2~add(.numericvalidator~new(fieldhelplabel))
/*
keyboard listening tasks which executes code ... the same tasks can also be used on buttons
*/
task1= .goToWindowTaskKey~new(win,1)
task1~key=.key~new("N")
task1~key~alt=.true
task2= .goToWindowTaskKey~new(win,0)
[continued in next message]
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)