home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 18 REXX
/
18-REXX.zip
/
netrexx.zip
/
NetRexx
/
Tablet.nrx
< prev
next >
Wrap
Text File
|
1997-06-30
|
18KB
|
408 lines
/* ---------------------------------------------------------- */
/* Tablet -- use the composite tab gif [tablet.gif] */
/* */
/* Use as: */
/* */
/* <applet code="Tablet.class" width=100% height=40> */
/* <param name=tab1 value="News nrnews.htm"> */
/* <param name=tab2 value="Documentation nrdocs.htm"> */
/* <param name=show value="2"> */
/* </applet> */
/* */
/* The 'name' parameters define the data for each tab: */
/* */
/* word 1 -- Text to show on the tab. Use an underscore */
/* ('_') to include a blank. */
/* */
/* word 2 -- URI to be shown when the tab is clicked. */
/* This is relative to the directory in which the */
/* current document appears. */
/* */
/* rest -- (not yet implemented) bubble-help for the tab. */
/* */
/* The 'show' parameter either gives the number of the tab */
/* that will be brought to the front (numbered 1-n, from the */
/* left), or will be 0 (meaning show the lower edge of the */
/* 'card index'). The default show is 1. */
/* For show=0, the height in the applet tag should be 15. */
/* ---------------------------------------------------------- */
options binary -- optional; runs a bit faster if set
class Tablet extends Applet
properties constant -- private
-- Positions in the 'original' image (proto) of the pieces
-- that we want; note the two risers must be the same width.
-- The parts up, down, and downb are extended (repeated) to
-- form tabs and shoulders.
-- For each slice we need the start offset (x) and width (w)
xrise = 0; wrise =14 -- rise (rise left tab)
xup = 14; wup = 6 -- up (tab top)
xdrop = 20; wdrop =14 -- drop (drop from top to shoulder)
xdown = 34; wdown = 6 -- down (flat shoulder)
xterm = 40; wterm =14 -- term (right shoulder; termination)
xstar = 54; wstar =15 -- start (left shoulder)
xrism = 69; wrism =14 -- rism (rise middle)
xstarb= 83; wstarb=15 -- starb (start bottom)
xdownb= 98; wdownb= 6 -- downb (down bottom)
xtermb=104; wtermb=14 -- termb (termination bottom)
xfin =128 -- finish offset (= total width)
-- Heights of the full tabs and 'bottom' pieces
yproto =40 -- full size pieces
ybottom=15 -- bottom pieces
properties private
tabfont ='Helvetica' -- font face for tab text
tabweight=Font.BOLD -- weight
tabcol =Color.black -- color
tabcolhi =Color.blue -- color, when highlit
tabcollo =Color.gray -- color, when current (fronttab)
tabpoints=int -- size for desired text height [points]
tabheight=16 -- desired text height [pels]
tabbasey =22 -- text baseline
tabbasex = 0 -- text baseline x adjustment
shadow=Image -- the Image to draw (null if no good)
proto =Image -- the Image prototype
wid =0 -- working tabs width
hig =0 -- working tabs height
xscale=float -- scale factor in x
yscale=float -- scale factor in y
-- data
tabs =int -- number of tabs
wtab =int[] -- tab widths array
otab =int[] -- tab body offsets array
fronttab =int 0 -- tab focus number [0->tabs-1]
mousetab =int(-1) -- tab under mouse [0->tabs-1, or -1]
mouselast=int(-1) -- tab under mouse [0->tabs-1, or -1]
tabword =String[] -- String for the tab
taburl =String[] -- URL for the tab
--tabhelp =String[] -- help String for the tab [nyi]
/* ---------------------------------------------------------- */
/* init is called once the applet is loaded. It sets up the */
/* master 'tabs' image, using pieces from the prototype. */
/* Note that if the prototype image used to form the tabs */
/* cannot be loaded for some reason, we'll still get the */
/* text segments, and they'll work as expected. */
/* ---------------------------------------------------------- */
method init
s='Copyright (c) IBM, 1997'
/* Get the parameters */
-- Determine the most forward, if any
s=getParameter('show') -- the number of the front tab (default 1)
if s\=null then do
i=Integer.parseInt(s, 10)
if i<0 then signal NumberFormatException
fronttab=i-1 -- OK, it's valid; -1 will mean bottom-edge
catch NumberFormatException
System.out.println('Bad show parameter:' s)
end
/* Get the prototype image. It has a transparent background. */
/* The prototype is of height yproto. */
proto=getgif('tablet.gif') -- get the template
-- [will be null if not loaded, but we still get Text]
/* Take quick path if just drawing bottom edge */
if fronttab<0 then do
hig=ybottom -- bottom edge is less high than full
wid=getSize.width -- fixed image size
shadow=createImage(wid, hig) -- working image
draw=shadow.getGraphics -- for graphics
draw.setColor(Color.white) -- background
draw.fillRect(0, 0, wid, hig) -- ..
if proto\=null then drawunder -- draw using pieces from prototype
else /* missing image */ do
draw.setColor(Color.gray) -- make a default line
draw.fillRect(0, 2, wid, 4) -- ..
end
return
end
/* real tabs */
-- Count the tabs
tabs=0
loop n=1 by 1
s=getParameter('tab'n)
if s=null then leave
tabs=tabs+1
end
if tabs=0 then return -- give up (will display 'no tabs')
if fronttab>=tabs then fronttab=tabs-1 -- clamp
-- Parse the tabs
tabword=String[tabs]
taburl =String[tabs]
loop n=1 to tabs
c=getParameter('tab'n).toCharArray
/* [This is where we really *need* NetRexx parse, or Rexx.word(x) :-)] */
-- First word is for tab [we allow multi-word with '_']
loop i=0 to c.length-1 while c[i] =' '; end -- i to first non-blank
loop j=i to c.length-1 while c[j]\=' ' -- j to next blank
if c[j]=='_' then c[j]=' ' -- [translate underscore]
end j
if j<=i then tabword[n-1]='?'
else tabword[n-1]=String(c, i, j-i)
-- Second word is URL
loop i=j to c.length-1 while c[i] =' '; end -- i to next non-blank
loop j=i to c.length-1 while c[j]\=' '; end -- j to next blank
if j<=i then taburl[n-1]='?'
else taburl[n-1]=String(c, i, j-i)
-- Remainder would be help [currently ignored]
-- say 'tab'n': "'tabword[n-1]'" "'taburl[n-1]'"'
end n
/* Prepare the drawing area, and measure the tab text */
wid=getSize.width -- default image size
hig=yproto -- full height
shadow=createImage(wid, hig) -- working image
draw=shadow.getGraphics -- for graphics
-- measure the height of the font, and choose size to match
draw.setFont(Font(tabfont, tabweight, 36)) -- measure at this size
h36=draw.getFontMetrics.getAscent -- height at size '36'
tabpoints=int(36*(tabheight/h36)+0.5) -- size for required height (round)
draw.setFont(Font(tabfont, tabweight, tabpoints)) -- set actual font
fm=draw.getFontMetrics -- find out about font
-- say 'Font' tabfont':' tabheight h36 tabpoints fm.getAscent
-- measure the width of each text segment; save in wtab array
wtab=int[tabs] -- width of each tab body
otab=int[tabs] -- offset of each tab body
wtotal=0 -- total of all bodies
loop t=0 to tabs-1
otab[t]=wtotal+wrise*(t+1) -- offset of body start
wtab[t]=fm.stringWidth(tabword[t]) -- actual width
wtotal=wtotal+wtab[t]
-- say 'wtab['t']:' wtab[t]
end t
minwid=wtotal+wrise*tabs+wdrop+wterm -- minimum width needed
if minwid>wid then do -- requested width is wider
wid=minwid
shadow=createImage(wid, hig) -- need new, wider image
draw=shadow.getGraphics -- for graphics
end
xscale=wid/getSize.width -- record scale factors
yscale=hig/getSize.height -- ..
-- say 'wid scales:' wid xscale yscale
draw.setColor(Color.white) -- background
draw.fillRect(0, 0, wid, hig) -- ..
drawtabs -- lay out the tabs
/* ---------------------------------------------------------- */
/* Update a tab's text [and front shoulder, if needed]. */
/* ---------------------------------------------------------- */
method updatetext(t=int)
drawtext(otab[t], tabword[t], t=mousetab, t\=fronttab)
--- draw shoulder in front if not front tab
if t=fronttab then return
x=otab[t]
wdowns=wtab[t] -- how many downs to fill
loop while wdowns>0
if wdowns>wdown then w=wdown
else w=wdowns
drawslice(x, xdown, w)
wdowns=wdowns-w
x=x+w
end
return
/* ---------------------------------------------------------- */
/* Draw an under-image (the bottom of an index card). */
/* ---------------------------------------------------------- */
method drawunder
drawslice(0, xstarb, wstarb) -- start
x=wstarb
wdowns=wid-(wstarb+wtermb) -- how many downs to fill
loop while wdowns>0
if wdowns>wdownb then w=wdownb
else w=wdowns
drawslice(x, xdownb, w)
wdowns=wdowns-w
x=x+w
end
drawslice(x, xtermb, wtermb) -- terminator
this.repaint -- ensure onscreen
/* ---------------------------------------------------------- */
/* Update all the tab drawings. */
/* ---------------------------------------------------------- */
method drawtabs
/* Display all the tabs, from hindmost to front. Only the front tab
will have shoulders, added after the tab body. */
loop t=tabs-1 to 0 by -1
n=t+fronttab -- tab to display
if n>=tabs then n=n-tabs -- ..
-- draw riser [note different if tab 0]
x=otab[n]-wrise
if n=0 then xr=xrise
else xr=xrism
drawslice(x, xr, wrise)
x=x+wrise
-- draw uppers
wups=wtab[n]
loop while wups>0
if wups>wup then w=wup
else w=wups
drawslice(x, xup, w)
wups=wups-w
x=x+w
end
-- draw drop
drawslice(x, xdrop, wdrop)
-- draw the text for the tab
drawtext(otab[n], tabword[n], n=mousetab, n\=fronttab)
end t
/* shoulders of the front tab */
if fronttab>0 then do label leftshoulder
drawslice(0, xstar, wstar) -- start
x=wstar
wdowns=otab[fronttab]-wrise-x -- how many downs to fill
loop while wdowns>0
if wdowns>wdown then w=wdown
else w=wdowns
drawslice(x, xdown, w)
wdowns=wdowns-w
x=x+w
end
end leftshoulder
/* always a right shoulder */
x=otab[fronttab]+wtab[fronttab]+wdrop -- right edge of focus tab, +1
wdowns=wid-wterm-x -- how many downs to fill
loop while wdowns>0
if wdowns>wdown then w=wdown
else w=wdowns
drawslice(x, xdown, w)
wdowns=wdowns-w
x=x+w
end
drawslice(x, xterm, wterm) -- terminator
this.repaint -- ensure onscreen
/* ---------------------------------------------------------- */
/* Draw a vertical slice from the prototype into the shadow. */
/* Note for 1.0.x we don't have setClip, so we must keep */
/* creating Graphics contexts. */
/* ---------------------------------------------------------- */
method drawslice(x=int, xfrom=int, wfrom=int)
if proto=null then return -- nothing to draw
draw=shadow.getGraphics -- needed to reset clip
draw.clipRect(x, 0, wfrom, hig) -- where to draw
draw.drawImage(proto, x-xfrom, 0, this) -- trickily shift the source
/* ---------------------------------------------------------- */
/* Draw the text for a tab. */
/* ---------------------------------------------------------- */
method drawtext(x=int, s=String, high=boolean, enabled=boolean)
draw=shadow.getGraphics -- needed to reset clip
draw.setFont(Font(tabfont, tabweight, tabpoints))
select
when \enabled then draw.setColor(tabcollo)
when high then draw.setColor(tabcolhi)
otherwise draw.setColor(tabcol)
end
draw.drawString(s, x+tabbasex, tabbasey)
/* ---------------------------------------------------------- */
/* The following methods respond to mouse movements and */
/* actions. */
/* MouseEnter and MouseExit are not called on some platforms, */
/* but are allowed for in any case. */
/* ---------------------------------------------------------- */
/* mouseDown takes an action if over a tab */
method mouseDown(e=Event, x=int, y=int) returns boolean
t=hit(e, x, y)
if t<0 then return 0
if t=fronttab then return 0 -- this one's inactive
-- don't change the current drawing; browser may be lazy
do
this.getAppletContext.showDocument(URL(this.getDocumentBase, taburl[t]))
catch MalformedURLException
System.out.println('Bad URL:' taburl[t])
end
return 1
/* Actions to take as mouse moves */
method mouseMove(e=Event, x=int, y=int) returns boolean
t=hit(e, x, y)
if mouselast\=t then do -- change noted
mousetab=t
if mouselast>=0 then
updatetext(mouselast) -- will revert old tab
if t>=0 then
updatetext(t) -- will highlight new tab
mouselast=t
this.repaint
end
return 1
/* Drag is treated just like Move (redraws button if leaves button) */
method mouseDrag(e=Event, x=int, y=int) returns boolean
return mouseMove(e, x, y)
/* Enter and exit call our mouseMove to ensure known state */
method mouseEnter(e=Event, x=int, y=int) returns boolean
return mouseMove(e, x, y)
method mouseExit(e=Event, x=int, y=int) returns boolean
return mouseMove(e, x, y)
/* Returns number of tab/card we are over, or -1 if none */
method hit(e=Event, x=int, y=int) returns int
if e=null then return -1 -- no event
x=(x*xscale)%1 -- apply scaling in X
y=(y*yscale)%1 -- .. and Y
if x<5 then return -1
if x>wid-5 then return -1
if y<5 then return -1 -- above tabs
if y>hig-5 then return -1 -- edge detector
-- next effect isn't very nice; disable
-- if y>31 then return fronttab -- below shoulder must be front
o=0
loop t=0 to tabs-1
if t=fronttab then do
if x>=o then
if x<o+wrise+wtab[t]+wdrop then return t
end
else /* behind tab */ do
if x>=o+wrise/2 then
if x<o+wrise+wtab[t]+wdrop/2 then return t
end
o=o+wrise+wtab[t]
end t
return -1
/* ---------------------------------------------------------- */
/* Utility routine to load a GIF and await its arrival. */
/* The argument is a URI (relative to the document base). */
/* ---------------------------------------------------------- */
method getgif(gif=String) returns Image
newimage=getImage(getDocumentBase(), gif) -- get the image
tracker=MediaTracker(this) -- 'this' is the "observer"
tracker.addImage(newimage, 0) -- track image arrival, ID=0
do
tracker.waitForID(0) -- wait for image 0 to complete
catch InterruptedException -- something stopped us
return null -- can do no more
end
-- Good images have useful dimensions, bad images have -1 or 0 in X or Y
if newimage.getWidth(this) <=0 then return null
if newimage.getHeight(this)<=0 then return null
return newimage -- looks good
/* ---------------------------------------------------------- */
/* paint(g) draws the whole image to size, if available. */
/* ---------------------------------------------------------- */
method update(g=Graphics) -- override Applet's update
paint(g) -- method to avoid flicker
method paint(g=Graphics)
if shadow=null
then g.drawString('[no tabs]', 2, 12) -- alternative
else g.drawImage(shadow, 0, 0, getSize.width, getSize.height, this)