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.