Until now, everything you've printed has flowed onto the screen like words in a document: left to right, wrapping onto the next line when it runs out of room. That's perfect for text, but most applications want a fixed layout: a title bar along the top, a menu down the side, a status bar at the bottom. This chapter shows how to put things exactly where you want them.
Every presentation tag has an inline field, which is true unless you say otherwise. An inline tag takes its place in the flow of content, just after whatever came before it.
Set inline=false, and the tag is taken out of the flow. Instead, you position it using its
top, left, right and bottom fields, which
measure the distance from each edge of its container to the same edge of the tag:
<box inline=false top=60 right=10 width=200 border=1 {Top right corner}>
This box sits 60 pixels below the top of the console and 10 pixels in from the right, wherever the rest of the content happens to be. Content in the flow carries on as if it weren't there.
Give a tag both of a pair of edges, like left and right, and it stretches to fill the space between them. This makes a bar right across the top of the console:
<box inline=false top=0 left=0 right=0 height=40 backgroundColor={navy} {Title}>
Give it all four edges, and it fills a rectangle.
Distances in % are a percentage of the container's size. This makes layouts that adapt to the size of the window:
<box inline=false top=50,% left=50,% width=25,% height=10,% border=1 {Starts halfway across and halfway down}>
The edges are those of the tag's container. For something you print at the top level, that's the console. For something inside a box, it's that box:
<box inline=false top=360 left=20 width=300 height=150 border=1 {
<box inline=false bottom=5 right=5 border=1 {In the corner of the outer box}>
}>
The console has a small margin around its edges by default. For a layout that goes right up to
the edges of the window, print <console.margin 0> first.
Tags positioned with inline=false can overlap. The layer field decides which is
in front: a tag with a higher layer number is drawn over one with a lower number, whichever was created first.
<box inline=false top=20 left=20 width=150 height=80 backgroundColor={red} layer=2 {In front}>
<box inline=false top=50 left=80 width=150 height=80 backgroundColor={blue} layer=1 {Behind}>
If a box has a fixed size and its content is too big for it, whatever doesn't fit is hidden. Set
scroll=true, and the box gets scroll bars instead, so the user can scroll through the content:
<box width=200 height=70 border=1 scroll=true {line 1</n>line 2</n>line 3</n>line 4</n>line 5}>
To line things up in rows and columns, use a table. Each row is a tabRow tag, and each value in a row goes in its own column:
<table
<tabRow {Name}, {Score}>
<tabRow {Ada}, 100>
<tabRow {Grace}, 95>
>
| Name | Score |
| Ada | 100 |
| Grace | 95 |
The columns are as wide as they need to be to fit their contents, so everything lines up. Remember the commas between the columns.
The console's width and height fields give its current size in pixels. Its onResize code field is carried out whenever the size changes, for example when the user resizes the window. If your program lays things out itself, it can ask to be told:
<console.onResize.push <putLn {/resize }, console.width, { }, console.height>>
Most of the time you won't need this: positions and sizes in %, and tags stretched between edges, adjust by themselves.
Here's a typical application screen: a title bar, a sidebar of buttons, a scrolling main area, and a status bar.
Each of the four parts is a box positioned against the edges of the console. Notice how they fit together: the
sidebar and main area start just below the title bar (top=2,em) and stop just above the status bar
(bottom=1.5,em).
print('''
<console.title {Notes}>
<console.margin 0>
<box inline=false top=0 left=0 right=0 height=2,em border=0 margin=0.4,em
backgroundColor={midnightblue} color={white} bold=true {Notes}>
<box inline=false top=2,em left=0 bottom=1.5,em width=10,em border=0 margin=0.5,em
backgroundColor={darkslategray} {
<button {New note} onClick=<putLn {/new}>></p>
<button {Quit} onClick=<putLn {/quit}>>
}>
<page:box inline=false top=2,em left=10,em right=0 bottom=1.5,em border=0 margin=1,em scroll=true {}>
<status:box inline=false bottom=0 left=0 right=0 height=1.5,em border=0 margin=0.2,em
backgroundColor={darkgreen} {Ready}>
''')
count = 0
while True:
command = input()
if command == '/quit':
break
if command == '/new':
count += 1
print('<page.push <box width=90,% border=1 margin=0.5,em spacing=0.5,em {Note number '
+ str(count) + '.}>>')
print('<status {' + str(count) + ' notes.}>')
When there are more notes than fit, the main area gets a scroll bar, and the title, sidebar and status bar stay where they are.