Vintage code retrospective

Apr 22, 2012 00:44

Backing up your data is important. Early trials and tribulations experimenting with Linux (Redhat 2, Slackware and Caldera) and OS/2 Warp when I was a teenager quickly taught me that. I screwed up my PC on more than one occasion which got me into the habit of making sure I had copies of my important stuff stashed away on floppies, then removable Syquest cartridges, then Zip disks and finally on to CDs and DVDs. Handily as a result I now have an archive of my work dating back a little over 14 years. It's some of that really old stuff I'd like to talk a bit about today.

I've never liked Windows. But I was a PC user for about 5 years from 1995 through 2000. As I've already alluded to, I've experimented with many alternative operating systems (some kids did drugs, I did operating systems - I wonder which caused the most longterm mental damage). Unfortunately they were all pretty universally shit in one respect or another. This combined with a strong interest in programming often had me pottering away building my own GUIs (graphical user interfaces) on top of DOS. If you're too young (or old) to remember DOS, it was a command line driven operating system that sat beneath Windows until they switched to using the Windows NT kernel from Windows 2000 onward. You typed a command and it either did something or gave you an unhelpful error message. Abort, Retry, Fail?

At first I wrote software with DOS's bundled QBasic, where I cut my programming teeth, then on to a dodgy copy of the commercial version of QBasic (QuickBASIC) which could actually compile executables (which was a big deal as the speed difference between interpreted and compiled code was very noticeable back then). Then finally I bought a copy of PowerBASIC which was much more powerful and faster than QBasic.

Building a GUI is actually rather involved, especially when you're starting from scratch, which on DOS I was. It took a lot of trial and error but over several years I built up a set of libraries which I termed "Widgets". It grew from version to version adding features and functionality. I went from the very basic act of drawing a grey box on the screen with a 3D bevel around it to make it look like a button, to making that button clickable with the mouse, then to creating the fonts and text layout functions needed to write a title on it. Building a GUI in DOS was like building a chair out of a tree and some iron ore. Each element required a number of steps of increasing complexity to refine the raw materials into the components needed to make the end product.

This is an early font demo I made to show a friend, circa 1996.



Each letter was encoded in a bitmap format, for example this is how the letter 'A' was stored:
"A 000 n0 0 n0 0 n0 0 n00000 n0 0 n0 0 n0 0 n0 0 n n n "
Which if you break it up onto multiple lines after each 'n' you'd see a recognisable representation of the letter "A". The bold and italic variants were made by simply changing the way the bitmaps were drawn at runtime.

As an aside, back then I used to publish my work under the brand name of New Technologies which I usually abbreviated to "Nt" which you'll see in a few of the screenshots.



Getting a bit more interesting, this is a screenshot of an early icon designer I wrote (I've always liked drawing icons and they're essential when you want to make your own shiny GUI). When I got this code running again at first I thought there was a problem with the mouse driver in my DOS emulator but then I realised at this point I didn't have the mouse working in QBasic so it was all keyboard driven.



This is my first stab at a full on GUI environment called AdvanceOS. This particular GUI drew inspiration in particular from early builds of BeOS which at the time looked like it would form the foundation of the next Mac operating system and was of major interest to me even though I lacked the hardware to run it. This was a late QBasic app and still lacked mouse support so it was all keyboard driven. Widgets at this point was still quite basic. In brief AdvanceOS comprised of a note viewer which supported limited rich text, a picture viewer that only supported my own proprietary bitmap format and a file browser. To my amusement I discovered that I'd also built in quite a decent graphical error logger which I got to see in action as the file browser choked on some metadata files MacOS had dumped on the disk at some point prior to it being imaged.



This is a graphical font designer I wrote. Note the mouse cursor! Things are much more sophisticated now with pull down menus, a draggable window and more control types. The font format too has evolved a lot, in particular I did a lot of work to make it as fast as possible. You could watch each line of text being drawn with my earlier attempts, my later font system which I dubbed the "Advanced Font System", could fill the screen with text in an instant. Rather than simply storing a bitmap for each letter, it instead used a vertical run length encoding (RLE) algorithm. Here is how the letter A was encoded in a similar font to the one shown above:

"065 05 07 .000. 1612131213121316"

The first three digits are the ASCII code of the character, then the width and height. Then there is a line that sets the initial state of each column of pixels in the character. For whatever reason I used a period to represent transparent, "don't draw anything", and 0 to represent a solid colour. Each number then corresponds to alternating lengths of transparent or filled pixels. It knows when to get to draw the next column when the number of pixels drawn (or not drawn) equals the height of the character. This would have been a nightmare to type out by hand, but was made possible by the graphical font designer. If you're wondering how it handled lines larger than 9 pixels have a look in the code listing below.

The code I wrote looks totally unintelligible to me now it's been so long since I did any work in BASIC. This is the algorithm to decode an AFS character:

Sub Decoder(x,y,char$,col) Public '-- Converts AFS to screen
Dim InitCodes(1 to 40) as Byte

w = FontW(asc(char$))
h = FontH(asc(char$))
dat$ = FontData(asc(char$))

l = 0: a = 0: oldl = 0

For i = 1 to w '-- Generate init codes
If Mid$(dat$,i,1) = "." then InitCodes(i) = 0
If Mid$(dat$,i,1) = "0" then InitCodes(i) = 1
Next i

If InitCodes(1) = 1 then d = 1 else d = 0
i = -1

Do
strt:
i = i + 1: a$ = mid$(dat$,i+w+2,1)
oldl = l

If a$ >= chr$(97) then '-- Allows very long fonts (up to 39 pixels)
i = i + 1
If a$ = "a" then l = l + 10 + val(mid$(dat$,i+w+2,1))
If a$ = "b" then l = l + 20 + val(mid$(dat$,i+w+2,1))
If a$ = "c" then l = l + 30 + val(mid$(dat$,i+w+2,1))
Else
l = l + val(mid$(dat$,i+w+2,1))
End If

If d = 1 then
If FShadow = 1 then Line (x+a+1,y+oldl+1)-(x+a+1,y+l),ShadowColor
If FShadow = 1 and bold = 1 then Line (x+a+2,y+oldl+1)-(x+a+2,y+l),ShadowColor
Line (x+a,y+oldl)-(x+a,y+l-1),col: d = 0
If Bold = 1 then d = 0 : Line (x+a+1,y+oldl)-(x+a+1,y+l-1),col
Goto ContFont
End If
If d = 0 then d = 1

ContFont: '-- Another *great* line label
If l = h then
If InitCodes(a+2) = 1 then d = 1 else d = 0
a = a + 1: l = 0
End If
Loop until a$ = ""
Erase InitCodes
End Sub

You wouldn't call this function directly, there was a nice friendly string drawing routine.



This is IconWORKS which I completed in 1998, an icon editor and animator which was built on top of my final Widgets library, by then up to version 8. It supported a rich variety of controls including text entry (which can be very complex), multiple windows and even bits of animated UI eye candy. The mouse graphic which showed the colours assigned to each mouse button moved to track the relative position of your cursor on the screen.

You may think by this point I've strayed from my original goal of building a GUI environment to focusing on developing a GUI API (application programming interface). This is some what true, but I did write one last project that I finished around the end of the 6th form that went back to my original desire to build my own self contained GUI environment. It was called Zenith. It was built using Widgets 8 and used SVGA graphics. You'll note up until now all my work has been done at VGA (640x480) resolution with 16 colours. Believe me I would have loved to work with more but this was the highest standardised resolution you could use in DOS, anything more needed specific graphics drivers and a library to interface with them). However eventually I managed to get hold of a VESA graphics library for PowerBASIC that supported SVGA (800x600) with up to 256 colours on any system with a VESA compliant graphics card. Zenith was an environment for running programs written in Ze script. A simple scripting language I devised to build graphical apps using my Widgets library. Frustratingly I'm missing a couple of important files that prevent me from showing any shiny screenshots of it running. It relied on a palette file to define the colours used without which everything looks horrible as its using arbitrary colours, most of which seem to be shades of black. I'm also missing the final version of the demo script I wrote to fully show off it's capabilities which is annoying.

I did find a couple of Ze scripts I wrote including this calculator. I think it works but its hard to use as it appears as a largely black box. I thought I'd include the code listing for those technically minded to have a look over.

# ZeCalc

# Example program in the Ze programming language.

init
def_window(1,300,200,200,230,"ZeCalc")
int(a,0)
int(b,0)
int(total,0)
int(number,0)
str(button,0)
str(screen,)
int(opp,0)
show(1)
focus(1)
end

# Main

window(1)
#-- Display
raise_box(5,5,190,40)
drop_box(15,15,170,20)
box(17,17,183,33,132,BF)
font(0,0,"",0)
font(20,22,$screen,0)
font(0,0,"",0)
#-- Function Buttons
raise_box(5,50,190,30)
button(10,55,20,20,"+",add)
button(35,55,20,20,"-",min)
button(60,55,20,20,"/",div)
button(85,55,20,20,"x",mul)
=($button,"-")
button(110,55,30,20,"-/+",update)
button(145,55,40,20,"C",reset)
#-- Number Buttons
raise_box(5,85,190,126)
=($button,"7")
button(12,90,55,25,"7",update)
=($button,"8")
button(72,90,55,25,"8",update)
=($button,"9")
button(132,90,55,25,"9",update)
=($button,"4")
button(12,120,55,25,"4",update)
=($button,"5")
button(72,120,55,25,"5",update)
=($button,"6")
button(132,120,55,25,"6",update)
=($button,"1")
button(12,150,55,25,"1",update)
=($button,"2")
button(72,150,55,25,"2",update)
=($button,"3")
button(132,150,55,25,"3",update)
=($button,"0")
button(12,180,55,25,"0",update)
=($button,".")
button(72,180,55,25,".",update)
button(132,180,55,25,"enter",calc)

end(1)

term

subs
sub add
val(%a,$screen)
=($screen,)
=(%opp,1)
=($button,"+")
call(screen)
end_sub

sub min
val(%a,$screen)
=($screen,)
=(%opp,2)
=($button,"-")
call(screen)
end_sub

sub div
val(%a,$screen)
=($screen,)
=(%opp,3)
=($button,"/")
call(screen)
end_sub

sub mul
val(%a,$screen)
=($screen,)
=(%opp,4)
=($button,"x")
call(screen)
end_sub

sub screen
refresh_on
box(17,17,183,33,132,BF)
font(20,22,$button,0)
refresh_off
=(%number,0)
end_sub

sub update
+(%number,%number,1)
if(%number,=<,10) then concat($screen,$button)
refresh_on
box(17,17,183,33,132,BF)
font(20,22,"",0)
font(20,22,$screen,0)
font(20,22,"",0)
refresh_off
end_sub

sub calc
val(%b,$screen)
if(%opp,=,1) then +(%total,%a,%b)
if(%opp,=,2) then -(%total,%a,%b)
if(%opp,=,3) then /(%total,%a,%b)
if(%opp,=,4) then *(%total,%a,%b)
refresh_on
box(17,17,183,33,132,BF)
font(20,22,"=",0)
font(26,22,%total,0)
font(20,22,"",0)
refresh_off
=($screen,)
=(%b,%total)
=(%number,0)
end_sub

sub reset
=(%number,0)
=(%a,0)
=(%b,0)
=(%total,0)
=($button,)
=($screen,)
call(screen)
end_sub

term.

It's a fairly basic scripting language but I'm still quite proud that I came up with this when I was 18 ^_^. A Ze script is split into three parts, initialisation where variables are declared, window declarations that define the GUI and subroutines that can be called to perform specific actions and update the GUI. You could have multiple simple apps running together as long as they were written in the same file.

So there we are, a brief history of my BASIC coding days and how I tried to build my own GUI enviroments. I hope you enjoyed looking over this old stuff as much as I did, if you're not a programmer and got this far then congrats, and remember it's never too late to learn ;) By the way, the story also has a happy ending because I finally found an OS that I liked when I got my first Mac!
Previous post Next post
Up