NCL 304: Drawing a Screen
In the last lesson, we learned that the Display is a 32×12 grid of character positions.
We can move the cursor to any visible position:
D.CUR 10 4
and decide exactly where the next text will be written.
So far, we've mostly used that to place individual pieces of text.
Now we're going to use those positions together to build a complete screen.
Filling the Display
Before drawing a new screen, it's often useful to replace everything already on the Display.
D.FIL fills the entire Display with a repeating pattern.
Let's make that pattern obvious:
D.FIL "@"
D.BLT
The entire Display fills with @ characters.
The pattern can contain more than one character:
D.FIL "123"
D.BLT
Now the Display contains a repeating pattern:
12312312312312312312312312312312
12312312312312312312312312312312
12312312312312312312312312312312
...
D.FIL changes the Display contents, but does not move the cursor.
Most of the time, though, we aren't going to fill the Display with 123.
A particularly useful pattern is:
D.FIL " "
A Display filled with spaces is a blank Display.
The current colour
In NCL 210, we changed the appearance of text using inline style codes such as:
D.TXT "\s0BHELLO"
The B selects palette entry B, or decimal 11.
Display commands can also select palette entries directly.
D.COL changes the current Display colour:
D.COL #D.COL.PINK
NCL provides names for each of the 16 palette entries:
| Integer | Hex | Style Code | Constant | Default colour |
|---|---|---|---|---|
0 |
0 |
\s00 |
#D.COL.BLACK |
|
1 |
1 |
\s01 |
#D.COL.RED |
|
2 |
2 |
\s02 |
#D.COL.BLUE |
|
3 |
3 |
\s03 |
#D.COL.PURPLE |
|
4 |
4 |
\s04 |
#D.COL.GREEN |
|
5 |
5 |
\s05 |
#D.COL.GRAY |
|
6 |
6 |
\s06 |
#D.COL.MEDBLUE |
|
7 |
7 |
\s07 |
#D.COL.LIGHTBLUE |
|
8 |
8 |
\s08 |
#D.COL.BROWN |
|
9 |
9 |
\s09 |
#D.COL.ORANGE |
|
10 |
A |
\s0A |
#D.COL.LIGHTGRAY |
|
11 |
B |
\s0B |
#D.COL.PINK |
|
12 |
C |
\s0C |
#D.COL.LIGHTGREEN |
|
13 |
D |
\s0D |
#D.COL.YELLOW |
|
14 |
E |
\s0E |
#D.COL.AQUA |
|
15 |
F |
\s0F |
#D.COL.WHITE |
The constant is simply a readable name for the integer in the first column.
For example:
#D.COL.PINK
has the value 11, which is hexadecimal B.
It therefore selects the same palette entry as the B in:
\s0B
Palette colours
These constants refer to entries in the Display palette. The colours shown above are those of the standard palette.
Programs can change the palette, so #D.COL.PINK selects palette entry 11; it does not guarantee that entry 11 is currently pink.
Filling with a style
D.FIL uses the current Display style when it fills the Display.
We can see this easily with a visible pattern:
D.COL #D.COL.PINK
D.FIL "123"
D.BLT
The repeating 123 pattern is now pink.
What if we fill with spaces instead?
D.COL #D.COL.PINK
D.FIL " "
D.BLT
The Display looks blank.
A normal space has no visible foreground pixels, so changing its foreground colour doesn't give us a coloured background.
But we already know another style from NCL 210: inversion.
D.COL can set that at the same time:
D.COL #D.COL.PINK #D.TXT.INVERT
D.FIL " "
D.BLT
Now every space is inverted.
Instead of an empty Display, we have a solid pink one.
Try changing #D.COL.PINK to another colour from the table.
Display state sticks around
Just like registers, the Display keeps its current state until something changes it.
After:
D.COL #D.COL.PINK #D.TXT.INVERT
the current colour is still pink and the current text mode is still inverted after D.FIL finishes.
If we now start writing our interface, that text will use the same style.
So after creating our background, we'll choose the style we want for ordinary text:
D.COL #D.COL.PINK #D.TXT.INVERT
D.FIL " "
D.COL #D.COL.WHITE #D.TXT.NORMAL
We've established the background, then changed the current style for whatever we draw next.
Nothing needed to reset automatically.
We changed the Display state, so we change it again when we want something different.
Building a layout
Let's build a simple status screen.
We want it to contain a title and three fields:
NCS/e SYSTEM STATUS
NAME: TERMINAL 1
STATUS: READY
MODE: LOCAL
PRESS ANY KEY
Instead of producing this as one long string, we can think about where each part belongs.
For example:
| Text | X | Y |
|---|---|---|
NCS/e SYSTEM STATUS |
5 |
1 |
NAME: |
3 |
4 |
TERMINAL 1 |
15 |
4 |
STATUS: |
3 |
6 |
READY |
15 |
6 |
MODE: |
3 |
8 |
LOCAL |
15 |
8 |
PRESS ANY KEY |
8 |
10 |
Notice what we've done with the fields.
The labels all begin at X position 3.
Their values all begin at X position 15.
That gives the screen columns.
Now we can translate the layout directly into NCL:
D.COL #D.COL.BLUE #D.TXT.INVERT
D.FIL " "
D.COL #D.COL.WHITE #D.TXT.NORMAL
D.CUR 5 1
D.TXT "NCS/e SYSTEM STATUS"
D.CUR 3 4
D.TXT "NAME:"
D.CUR 15 4
D.TXT "TERMINAL 1"
D.CUR 3 6
D.TXT "STATUS:"
D.CUR 15 6
D.TXT "READY"
D.CUR 3 8
D.TXT "MODE:"
D.CUR 15 8
D.TXT "LOCAL"
D.CUR 8 10
D.TXT "PRESS ANY KEY"
D.BLT
SYS.AKEY s0
There aren't many new ideas in this program.
We're mostly combining things we already know:
D.COLchooses the style we're drawing with;D.FILestablishes the background;D.CURchooses a position;D.TXTchanges the Display contents at that position;D.BLTshows the completed result;SYS.AKEYwaits for a key.
The important difference is how we're using them together.
We're no longer asking only:
What text should I write next?
We're also asking:
Where does this part of the screen belong?
Drawing before showing
Notice that we didn't do this:
D.COL #D.COL.BLUE #D.TXT.INVERT
D.FIL " "
D.BLT
and then refresh again after every individual piece of text.
Instead, we prepared everything first:
D.FIL " "
D.CUR 5 1
D.TXT "NCS/e SYSTEM STATUS"
D.CUR 3 4
D.TXT "NAME:"
-- More of the screen...
None of those changes need to be shown individually.
Only when the complete screen is ready do we use:
D.BLT
The physical Display then refreshes with the completed layout.
This is one of the reasons D.TXT is useful when drawing a screen.
We can make many changes to the Display state and show them together.
A screen has structure
Our little status screen already has structure.
It has:
- a title;
- a group of labels;
- a group of values;
- a prompt at the bottom.
And each part has an assigned place.
That makes the layout easier to change.
If we decide that the values should begin farther to the right, we can change their X coordinates.
If the title should be lower, we can change its Y coordinate.
The text itself doesn't need to change.
This is also where fixed-width strings become useful.
If a particular field has a known amount of space available, the string operations we learned in NCL 206 and used again in NCL 211 can prepare text that fits that space.
The Display decides where the field goes.
Our string operations can decide what fits inside it.
Try it
Change the status screen.
First, give it a different background:
D.COL #D.COL.PINK #D.TXT.INVERT
D.FIL " "
Your serious computer terminal is now salmon pink.
Then try changing the contents and positions.
You could:
- change
TERMINAL 1to another name; - change
READYto another status; - move the title;
- move the labels and values into different columns;
- add another field;
- use a different foreground colour;
- place a message in one of the unused rows.
Try to decide where each piece belongs before writing its D.CUR.
You can even make a small table like the one above first, then translate those positions into NCL.
The goal isn't to make the prettiest interface yet.
It's to start thinking of the Display as a complete layout rather than a stream of text.
We can now establish a background, position fields deliberately, prepare an entire screen in Display state, and reveal it with one D.BLT.
But our status screen has a problem.
Suppose:
STATUS: READY
needs to become:
STATUS: BUSY
We could build the entire screen again.
But only one small part actually changed.
In NCL 305: Updating the Screen, we'll learn how to update the parts of a screen that need to change.