// MenuBox.bcpl -- a BCPL package to define and manipulate areas // on the display screen. // A box is defined by an "origin" (upper left corner) and // a "corner" (lower right corner). If a bitmap exists // for the box then a dcb is specified and the origin // and corner are given relative to the dcb bitmap. get "MenuDefs.d" external // incoming OS statics and procedures [ dsp sysZone Allocate GetFont CharWidth ] let CreateBox(Xo,Yo,Xc,Yc,inputZone;numargs na) = valof [ // if corners not specified then go home if na ls 4 then resultis false // use input zone or sysZone let zone= ((na ls 5) % (inputZone eq 0)) ? sysZone,inputZone let box=Allocate(zone,lBOX) if box eq 0 then resultis false // set default to no dcb and input absolute coords box>>BOX.dcb=0 box>>BOX.outline=0 box>>BOX.xorigin=Xo box>>BOX.yorigin=Yo box>>BOX.xcorner=Xc box>>BOX.ycorner=Yc if Xo eq Xc % Yo eq Yc then resultis false // see if a dcb exists and change coords to relative to dcb ConvertToRelative(box) resultis box ] and CursorInside(box,XCursor,YCursor;numargs na) = valof [ // default cursor location to center of cursor if (na eq 0) % (box eq 0) then resultis false if na ls 3 then [ XCursor=0 ; YCursor=0 ] XCursor=@#424+XCursor YCursor=@#425+YCursor // define box coords let Xo=box>>BOX.xorigin let Xc=box>>BOX.xcorner let Yo=box>>BOX.yorigin let Yc=box>>BOX.ycorner if Xo eq Xc % Yo eq Yc then resultis false // if dcb was specified, find absolute coords from dcb chain let top=FindDCB(box) // returns # lines to the dcb if top eq true then resultis false // couldn't find the dcb let left=top ? 16*((box>>BOX.dcb)>>DCB.indentation),0 Xo=Xo+left Yo=Yo+top Xc=Xc+left Yc=Yc+top // compare cursor coords to absolute coords if (XCursor ge Xo) & (XCursor le Xc) then [ if (YCursor ge Yo) & (YCursor le Yc) then resultis true ] resultis false ] and OutlineBox(box,bits,flag;numargs na) = valof [ // bits -- width of outline in bits // flag=0 -- outline with zeroes (white in normal mode) // flag=1 -- outline with ones (black in normal mode) // flag=-1 -- outline by flipping memory // set defaults if (na eq 0) % (box eq 0) then resultis false if na ls 2 then bits=1 if bits eq 0 then [ box>>BOX.outline=0 ; resultis true ] if na ls 3 then flag=-1 // define boundaries of the box let Xo=box>>BOX.xorigin let Yo=box>>BOX.yorigin let Xc=box>>BOX.xcorner let Yc=box>>BOX.ycorner if Xo eq Xc % Yo eq Yc then resultis false // get dcb let dcb=box>>BOX.dcb if dcb eq 0 then resultis false let width=dcb>>DCB.width // draw in top border // using erase function from BoxUtils.asm // erase(nbits,wordstart,bitstart,nwords,nlines,flag [0]) let nbits=Xc-Xo+1 let wordstart=dcb>>DCB.bitmap+Yo*width erase(nbits,wordstart,Xo,width,bits,flag) // draw in left and right sides let nlines=Yc-Yo+1-2*bits unless nlines le 0 do [ // draw in left side erase(bits,wordstart+bits*width,Xo,width,nlines,flag) // draw in right side erase(-bits,wordstart+bits*width,Xc,width,nlines,flag) ] // draw in bottom border wordstart=dcb>>DCB.bitmap+(Yc-bits+1)*width erase(-nbits,wordstart,Xc,width,bits,flag) // put in how outlined box>>BOX.flag=flag box>>BOX.bits=bits resultis true ] and FlipBox(box,flag;numargs na) = valof [ // check arguments if (na eq 0) % (box eq 0) then resultis false if na ls 2 then flag=true // get dcb let dcb=box>>BOX.dcb if dcb eq 0 then resultis false let width=dcb>>DCB.width // define boundaries of the box let bits=box>>BOX.bits let Xo=box>>BOX.xorigin let Yo=box>>BOX.yorigin let Xc=box>>BOX.xcorner let Yc=box>>BOX.ycorner if Xo eq Xc % Yo eq Yc then resultis false // flip the box let nbits=Xc-Xo+1-2*bits let wordstart=dcb>>DCB.bitmap+(Yo+bits)*width let nlines=Yc-Yo+1-2*bits if (nbits le 0) % (nlines le 0) then resultis false erase(nbits,wordstart,Xo+bits,width,nlines,flag) resultis true ] and NearestBox(menu;numargs na) = valof [ // returns number of the box that is // geometrically closest to the cursor // return if conditions wrong if (na eq 0) % (menu eq 0) % (@menu eq 0) resultis false // define some needed variables let distance=nil let number=1 let mindist=DistanceToBox(menu!number) // major loop for n=1 to @menu-1 do [ distance=DistanceToBox(menu!(n+1)) if distance ls mindist then [ mindist=distance number=n+1 ] ] resultis number ] and DistanceToBox(box) = valof [ // calculates delta x and delta y // if delta is > 127 then divide by 8 and square // if delta is < 128 then square and divide by 64 // this insures that there is no overflow // while maintaining good accuracy for small distances // returns the sum of the squares of the distances let dx=(@#424-box>>BOX.xcorner) let dy=(@#425-box>>BOX.ycorner) if dx ls 0 then dx=-dx if dy ls 0 then dy=-dy let s1,s2=0,0 test dx ls 128 ifso s1=s1+dx*dx ifnot [ dx=dx/8 ; s2=s2+dx*dx ] test dy ls 128 ifso s1=s1+dy*dy ifnot [ dy=dy/8 ; s2=s2+dy*dy ] s1=s1/64 resultis s1+s2 ] and FindDCB(box,dcb;numargs na) = valof [ // return number of lines to top of dcb for box // return false if dcb entry eq 0 // return true if dcb supposed to be but not there // check if no dcb if (na eq 0) % (box>>BOX.dcb eq 0) then resultis false if (na le 1) % (dcb eq 0) then dcb=@#420 // look for dcb and count lines let top=0 while dcb do [ if dcb eq box>>BOX.dcb then resultis top top=top+2*(dcb>>DCB.height) dcb=@dcb ] resultis true ] and ConvertToRelative(box,dcb;numargs na) be [ // check if no dcb if (na eq 0) % (box eq 0) then return if (na le 1) % (dcb eq 0) then dcb=@#420 if box>>BOX.dcb then return // run over chain // see if a dcb exists and change coords to relative to dcb let top,height,left,width=0,0,0,0 let Xo=box>>BOX.xorigin let Yo=box>>BOX.yorigin let Xc=box>>BOX.xcorner let Yc=box>>BOX.ycorner if Xo eq Xc % Yo eq Yc then return while dcb do [ height=2*(dcb>>DCB.height) if top gr Yo then return if top+height gr Yc then [ left=16*(dcb>>DCB.indentation) width=16*(dcb>>DCB.width) if (left le Xo) & (left+width gr Xc) then [ box>>BOX.dcb=dcb box>>BOX.xorigin=Xo-left box>>BOX.yorigin=Yo-top box>>BOX.xcorner=Xc-left box>>BOX.ycorner=Yc-top ] return ] top=top+height dcb=@dcb ] ] and WriteBox(box,string,font;numargs na) be [ // Jiggered up for left justified // set defaults if (na ls 1) % (box eq 0) then return if (na ls 2) % (string eq 0) then return if (na ls 3) % (font eq 0) then font=GetFont(dsp) // calculate the bit length of the string let length=0 for n=1 to string>>STRING.length do [ length=length+CharWidth(font,string>>STRING.char↑n) ] // get coordinates let Xo=box>>BOX.xorigin let Yo=box>>BOX.yorigin let Xc=box>>BOX.xcorner let Yc=box>>BOX.ycorner if Xo eq Xc % Yo eq Yc then return // calculate where the string goes let charheight=font!(-2) let bits=box>>BOX.bits let width=Xc-Xo+1-2*bits let height=Yc-Yo+1-2*bits let xstart=Xo+(width-length)/2+bits if xstart ls Xo then xstart=Xo+bits if box>>BOX.ljustified ne 0 then xstart = Xo+bits+box>>BOX.joffset let ystart=Yo+(height-charheight)/2+bits if ystart ls Yo then ystart=Yo+bits // now put it out // write(StringPointer,nwrds,dba,wad,bitlimit,FontPointer) let dcb=box>>BOX.dcb let wordstart=dcb>>DCB.bitmap+ystart*(dcb>>DCB.width) write(string,dcb>>DCB.width,xstart+1,wordstart,width,font) return ]