NCL 210: Styling the Display

In the previous lessons, we've looked at several ways characters can be represented inside strings.

We learned that an escape sequence such as:

\n

represents a character.

We learned that characters have numeric codes, and that Unicode assigns those characters code points.

Now we're going to use all of that for something a little unusual.

NCS/e defines some Unicode characters of its own.

The Display interprets these characters as instructions for changing how following text is displayed.

Changing text colour

Consider:

D.TXT "\s01ERROR\s0F"
D.BLT

The word:

ERROR

is displayed using palette entry 1.

The escape:

\s01

changes the Display's active text attributes.

Then:

\s0F

changes them back to normal, non-inverted text using palette entry F.

Neither escape produces a visible glyph of its own.

Instead, the Display interprets them as attribute commands.

Choosing a colour

For normal text, we can use:

\s0X

where X is the hexadecimal number of a palette entry.

The standard palette contains sixteen entries:

X Standard colour
0 Black
1 Red
2 Blue
3 Purple
4 Green
5 Gray
6 Medium blue
7 Light blue
8 Brown
9 Orange
A Light gray
B Pink
C Light green
D Yellow
E Aqua
F White

The hexadecimal digits A through F should look familiar from NCL 208.

For example:

D.TXT "\s01RED \s02BLUE \s0DYELLOW\s0F"
D.BLT

Each attribute command changes the colour used by the text that follows it.

Palette entries can be changed

These names describe the colours in the standard NCS/e palette.

The Display's palette can be changed, so palette entry 1 does not necessarily have to contain red.

We'll work with the Display and its palette more directly in later lessons.

Attribute changes persist

An inline attribute doesn't apply only to the next character.

It changes the Display's active attributes.

Consider:

D.TXT "\s01RED "
D.TXT "STILL RED "
D.TXT "\s0FNORMAL"
D.BLT

The second D.TXT does not contain an attribute command.

Its text is still red because palette entry 1 remains active from the previous write.

The final:

\s0F

restores normal white text.

This means the active attributes can continue beyond the string that originally changed them.

Restore the Display attributes

Styled text can affect text written afterward.

The examples in this lesson finish with:

text \s0F

which restores normal, non-inverted text using palette entry F.

When controlling the Display attributes separately, the equivalent is:

ncl D.COL 15 0 0

Restoring the attributes prevents one piece of styled output from unexpectedly affecting whatever is displayed next.

Inverting text

The Display can also invert its text.

So far, our attribute escapes have started with:

\s0

Changing that 0 to 1 enables inversion:

\s1X

The final hexadecimal digit still chooses the palette entry.

For example:

D.TXT "\s02BLUE "
D.TXT "\s12INVERTED BLUE"
D.TXT "\s0F"
D.BLT

Both sections use palette entry 2.

The difference is inversion:

Escape Colour Inverted
\s02 Palette entry 2 No
\s12 Palette entry 2 Yes

We can combine different colours and inversion in the same string:

D.TXT "\s04READY \s1DWARNING \s11ERROR\s0F"
D.BLT

Each attribute command changes how the text following it is displayed.

What's actually in the string?

So far, \s01 may look like a special command embedded in an NCL string.

But we've spent the last few lessons learning to look more closely at what escape sequences actually represent.

\s01 inserts a character.

Specifically, it inserts the Unicode character:

U+F101

Likewise:

NCL escape Unicode character Display meaning
\s01 U+F101 Normal, palette entry 1
\s0F U+F10F Normal, palette entry F
\s12 U+F112 Inverted, palette entry 2
\s1F U+F11F Inverted, palette entry F

These characters are really present in the string.

Consider:

#message "\s01ERROR\s0F"
#length r0

SLEN #length #message

D.TXT #length
D.TXT "\r\n"
D.TXT #message
D.BLT

The visible word:

ERROR

contains five characters.

But #message contains seven Unicode characters:

Position Character
0 U+F101
1 E
2 R
3 R
4 O
5 R
6 U+F10F

So SLEN reports:

7

The two attribute characters are part of the string even though the Display doesn't draw them as glyphs.

Private-use characters

Why does Unicode have a character at U+F101 for changing the colour of an NCS/e Display?

It doesn't.

Unicode reserves some ranges of code points for private use.

These are called the Private Use Areas, or PUA.

Unicode doesn't assign a universal meaning to characters in these ranges. A particular system can define meanings for them itself.

NCS/e uses the range:

U+F100–U+F1FF

for inline Display attributes.

The escape:

\s01

is a convenient way to insert U+F101 into a string.

But it isn't the only way.

We can identify the same character directly by its Unicode code point:

D.TXT "\uF101RED\s0F"
D.BLT

The word RED is displayed using palette entry 1, just as it would be with:

D.TXT "\s01RED\s0F"
D.BLT

Or we can construct the character from its numeric code using CHAR:

#attribute s0

CHAR #attribute 57601

D.TXT #attribute
D.TXT "RED"
D.TXT "\s0F"
D.BLT

All three forms produce the same character:

Source Character
\s01 U+F101
\uF101 U+F101
CHAR s0 57601 U+F101

The difference is only how we produced it.

When the Display receives U+F101, it interprets that character as:

normal text using palette entry 1

The \sXX form is simply the convenient NCL notation intended for inline Display attributes.

There are more attribute combinations available in the U+F100–U+F1FF range than we're using in this lesson.

For now, we only need two forms:

Form Meaning
\s0X Normal text using palette entry X
\s1X Inverted text using palette entry X

The complete set of Display attributes is described in the NCL Reference.

Inspecting an attribute character

Because an inline attribute is an ordinary Unicode code point inside the string, the string operations we've already learned can inspect it.

For example:

#message "\s01ERROR\s0F"
#code r0

ORD #code #message 0

D.TXT #code
D.BLT

The result is:

57601

ORD read the first character of #message.

That character is U+F101, whose code point is 57601 in decimal.

We can therefore move between the same character using the operations from the previous lessons:

Operation Result
CHAR s0 57601 U+F101
ORD r0 "\s01" 0 integer 57601

Nothing special had to be added to ORD or CHAR.

As far as NCL's string operations are concerned, U+F101 is simply a character.

\s01 is not a separate kind of object hidden inside the string.

It is U+F101.

The Display gives it meaning

This brings us back to an important distinction from NCL 207.

Consider:

#message s0

SMOVE #message "\s01ERROR\s0F"

This does not change the Display colour.

It only stores a string.

We can measure it:

#length r0

SLEN #length #message

We can inspect its characters:

#code r1

ORD #code #message 0

We can join it with other strings:

SJOIN #message #message "!"

None of those operations cause anything to become red.

The attribute takes effect when we send the string to the Display:

D.TXT #message
D.BLT

The Display encounters U+F101, recognizes it as an inline attribute, and changes its active attributes.

It then displays ERROR using palette entry 1 until it encounters U+F10F and restores normal white text.

The ! was joined after U+F10F, so it is displayed using the restored attributes.

This is the same general idea we saw with control characters such as line feed:

  1. NCL source gives us a way to represent a character.
  2. That character becomes part of a string.
  3. Something receiving the string may interpret that character specially.

The meaning belongs to the receiving device.

Building styled strings

Because the attributes are characters inside strings, they can be combined with the string operations we've already learned.

Suppose we want to build an error message:

#message s0

SMOVE #message "\s01ERROR: "
SJOIN #message #message "DISK NOT FOUND"
SJOIN #message #message "\s0F"

D.TXT #message
D.BLT

The first part begins with U+F101, selecting normal text using palette entry 1.

Then we join ordinary text onto the string.

Finally, we append U+F10F to restore the normal attributes.

The resulting string carries its formatting with it.

We could build the contents dynamically too:

#message s0
#device "DISPLAY"

SMOVE #message "\s1DWARNING: "
SJOIN #message #message #device
SJOIN #message #message " NOT READY"
SJOIN #message #message "\s0F"

D.TXT #message
D.BLT

String construction works exactly as before.

Some of the characters simply have a special meaning when the Display receives them.

Inline attributes and D.COL

Inline attribute characters aren't the only way to change how the Display draws text.

The Display also provides:

D.COL 1 0 0

which sets its active attributes separately from the text being written.

For example:

D.COL 1 0 0
D.TXT "ERROR"
D.COL 15 0 0
D.BLT

also displays ERROR using palette entry 1, then restores the default attributes.

We'll work with D.COL and the Display more directly in later lessons.

For now, \sXX is particularly useful when attribute changes naturally belong inside the text itself.

Try it

Start with:

D.TXT "\s04READY\s0F"
D.BLT

Change the final hexadecimal digit of the first escape and see how the text changes.

Try palette entries:

1
2
6
9
D
E

Then invert one of them by changing:

\s0X

to:

\s1X

Make a line containing three differently styled sections:

READY   WARNING   ERROR

Choose the palette entries yourself, and try making one of the sections inverted.

Remember to finish the styled text with:

\s0F

Finally, store the entire line in a string register before displaying it:

#message s0

SMOVE #message "\s04READY   \s1DWARNING   \s01ERROR\s0F"

D.TXT #message
D.BLT

Use SLEN to measure #message.

Before running the program, count the visible characters and the inline attribute characters separately.

Does the resulting length match your prediction?

Then try replacing one of the \sXX escapes with the equivalent \uF1XX escape.

For an extra experiment, construct U+F101 using CHAR:

#attribute s0

CHAR #attribute 57601

D.TXT #attribute
D.TXT "HELLO"
D.TXT "\s0F"
D.BLT

The Display doesn't care which method produced U+F101.

It receives the same character either way.


Inline attributes let strings carry information about how the Display should present their text.

They're also ordinary Unicode characters inside the string, which means the string operations we've already learned can store, inspect, combine, and manipulate them.

In NCL 211: Working with Text, we'll bring the tools from the entire 200-level together.