A popular style of window seen in SCI1 games like Police Quest and Space Quest is the BorderWindow
. By default it’s thick and gray, but it can really have any thickness and set of five colors you want.
![]() |
The default looks something like this. Your exact colors may vary as I use a custom palette instead of the standard SCI1 palette, and Space Quest 5 has somewhat tinted grays. |
![]() |
If one were to edit the BorderWindow script a little bit to enable title bars, and did it in a naive way, they’d get something like this. So let’s not do that. |
![]() |
The bevelWid and shadowWid properties can of course be changed on a per-window basis… |
![]() |
…as can the back and four edge colors, topBordColor et al. |
But how does this work exactly? Let’s take the actual BorderWindow
script code and walk through it.
(class BorderWindow of SysWindow (properties ; All other properties inherited from SysWindow back 5 topBordColor 7 lftBordColor 6 rgtBordColor 4 botBordColor 3 bevelWid 3 shadowWid 2 ) (method (dispose) (super dispose:) (SetPort 0) ) (method (show) (Graph grUPDATE_BOX top left bottom right VISUAL) ) (method (open &tmp oldPort screens) (SetPort 0) ; Use the entire screen. ; If we have a priority set, render to that screen too. (= screens VISUAL) (if (!= priority -1) (= screens (| screens PRIORITY))) ; Make some room in the "last seen" rect to fit the border. (= lsTop (- top bevelWid)) (= lsLeft (- left bevelWid)) (= lsRight (+ right bevelWid shadowWid)) (= lsBottom (+ bottom bevelWid shadowWid)) (= type 128) ; We are custom, as described in the ; previous post. (super open:) ; Let a SysWindow open itself. ; This actually just calls the NewWindow kernel call ; and saves the returned handle to our window property. (drawWindow top left bottom right back topBordColor lftBordColor botBordColor rgtBordColor bevelWid shadowWid priority screens ) (= oldPort (GetPort)) ; Remember our current port. (SetPort 0) ; Use the whole screen again. ; Show what we have wrought. (Graph grUPDATE_BOX lsTop lsLeft lsBottom lsRight VISUAL) (SetPort oldPort) ) )
That’s not so bad. The meat of the dish is in drawWindow
, obviously:
(procedure (drawWindow t l b r theColor topColor leftColor bottomColor rightColor theBevelWid theShadowWid thePri theMaps &tmp savePort i) ; Again, we remember the current port and use the whole screen. (= savePort (GetPort)) (SetPort 0) ; Fill in the window background. (Graph grFILL_BOX t l (+ b 1) (+ r 1) theMaps theColor thePri) ; Extend our rect to include the bevel. (-= t theBevelWid) (-= l theBevelWid) (+= r theBevelWid) (+= b theBevelWid) ; Draw the top and bottom bevels as simple boxes. (Graph grFILL_BOX t l (+ t theBevelWid) r theMaps topColor thePri ) (Graph grFILL_BOX (- b theBevelWid) l b r theMaps bottomColor thePri ) ; Draw the left and right bevels line by line. (for ((= i 0)) (< i theBevelWid) ((++ i)) (Graph grDRAW_LINE (+ t i) (+ l i) (- b (+ i 1)) (+ l i) leftColor thePri -1 ) (Graph grDRAW_LINE (+ t i) (- r (+ i 1)) (- b (+ i 1)) (- r (+ i 1)) rightColor thePri -1 ) ) ; Draw the shadow last. Unlike SysWindows, ; these are done as two boxes. (if theShadowWid (Graph grFILL_BOX (+ t theShadowWid) r (+ b theShadowWid) (+ r theShadowWid) theMaps 0 thePri ) (Graph grFILL_BOX b (+ l theShadowWid) (+ b theShadowWid) r theMaps 0 thePri ) ) (SetPort savePort) )
To visualize, a BorderWindow (sans shadow) renders like this:
Next time, we take a step back and look at King’s Quest.