Banner Windows

The “tadsio” function set provides a group of functions that allow the program to perform sophisticated manipulation of the display layout.  This group of functions, called the Banner Window API, lets the program divide the screen into separate “window” areas that can show independent information.

 

The banner window API provides much of the same functionality that was available in TADS 2’s full HTML interpreters using the <BANNER> tag.  However, the banner window API goes beyond the <BANNER> tag from TADS 2 in several important ways:

 

Screen Layout Overview

TADS interpreters display everything on what we call the “screen,” by which we mean the physical display area devoted to the interpreter.  The screen isn’t necessarily the same as the physical display device (the user’s monitor, or the terminal, for example), although on some systems it is.  The most typical examples are:

 

 

When a TADS interpreter first loads a new game program, it devotes the entire “screen” to one window, which we call the “main game window.”  This main window acts a lot like banner windows, which we’ll come to in a moment, but it has some differences, so we use the special designation, “main game window,” to refer to this window.

 

At any time while the game program is running, it can create new “banner windows.”  A banner window is a rectangular area of the screen that can be separately controlled: each banner has its own contents, background color, text color, and so on.

 

All of the banner windows that are shown at any given time share space on the screen with one another and with the main game window.  Two windows can never overlap, and all of the windows taken together must fill the entire screen.  These are important constraints that determine precisely how the screen looks with a given arrangement of windows, and make it relatively simple to specify the screen layout; the disadvantage of these constraints is that they don’t allow the game program to create any arbitrary display, but the compensating advantage is that the constraints are simple to apply across a wide range of platforms, so the program can count on consistent results without having to include special-case code for many different machines and display types.

 

Each banner window has two main parameters that control its layout on the screen.  First, each banner has an alignment type, which can be Top, Bottom, Left, or Right.  The alignment specifies where the banner goes relative to the main window (the alignment is always relative to the main window).  A top-aligned banner runs the entire width of the main window, and is positioned above the main window; a bottom-aligned banner also runs the entire width of the main window, but is positioned under the main window.  Left and right banners run the entire height of the main window, and are positioned to the left and right, respectively, of the main window.  Second, each banner has a size, which gives the size of the “free” dimension, as determined by the alignment: a top or bottom banner’s size specifies its height, and the left or right banner’s size specifies its width.

 

The set of current banner windows is always arranged into an ordered list: one banner window is designated as the first one, another as the second, and so on, so that all of the windows are in a simple linear order.  The main game window is always effectively the last window in this list.  Whenever the game program creates a new banner window, it specifies where the new window goes in the list; the program can specify the list order relative to an existing window, or it can indicate that the new window should be the first or last banner in the list (but remember that the last banner is always followed by the main game window, so a banner can never truly be last in the sense of following the main game window in the layout order list).

 

The screen layout is dynamic: each time a new banner window is created, or a banner window is removed, or a banner is resized, or the screen size changes (which can happen, for example, when the user resizes “xterm” window displaying the interpreter), TADS must recalculate the screen layout.  Every time any of these events occurs, TADS completely recalculates the screen layout; this means that the layout is always predictable, because it’s always calculated the same way, regardless of what caused a change.

 

To calculate the screen layout, TADS starts with a rectangle equal in size to the entire “screen” (as defined earlier).   We call this the remaining space rectangle (it’ll change as we proceed).  The interpreter then goes through the list of banners, one window at a time. 

 

  1. For each window, the interpreter looks at the window’s alignment and size, and allocates the given space to the window out of the remaining space rectangle: for a top-aligned window, the interpreter positions the banner so that it has the same horizontal boundaries as the remaining space rectangle, has its top at the top of the rectangle, and has its bottom at the top of the rectangle plus the window’s size (which is interpreted as the window’s height, since the window is top-aligned).  For a bottom-aligned window, the horizontal boundaries are the same as those of the remaining space rectangle, the bottom is the same as the bottom of the remaining space, and the top is at the bottom minus the size (i.e., height).  Left and right banners are handled similarly, but the banner size is interpreted as a width.
  2. If the banner’s size parameter exceeds the available height or width of the remaining space, the actual size is limited to the remaining space.
  3. Now that the banner’s on-screen position is known, the interpreter “subtracts” the banner’s screen area from the remaining space rectangle.  Because of the way the banner’s area is calculated, this always yields another rectangle.  The result of the subtraction is the new remaining space rectangle that we use for calculating the next window’s position.

 

Once the interpreter finishes with the list of banners, it gives the entire area of the remaining space rectangle to the main game window.

Banner Types

When the game creates a banner window, it can specify the type of window to use.  The following types are defined:

 

 

Note that text grids are mostly provided for character-mode platforms, but they’re also supported on the full HTML interpreters for compatibility.  In most cases, the kinds of effects for which text grids are most useful can be presented more elegantly on the full HTML interpreters by other means; for example, a “menu” window that uses cursor positioning to move around a selection pointer in response to keyboard inputs could be better presented in HTML interpreters using a list of hyperlinks.  Games that use text grids should consider

Sizing Banners

The banner API provides three different ways of setting the size of a banner.  Which sizing method is best for a particular banner depends on how the banner is used.

 

Note that when we talk about the “size” of a banner, we’re talking about the free dimension of the banner, because the other dimension is always determined by the layout rules and thus can’t be controlled independently.  For a top-aligned or bottom-aligned banner, the size is the height; for a left- or right-aligned banner, the size is the width.

 

Percentage sizing:  The first method is to size a banner in proportion to the available screen area, by specifying the size as a percentage when creating the banner (with bannerCreate()) or changing its size (with bannerSetSize()).  The size of the banner will always be the given percentage of the “remaining space” rectangle; see the Screen Layout Overview for details of how the remaining space rectangle is calculated.  When you set a percentage size, the banner specifically remembers the percentage value; whenever the layout changes (because the user resizes the application window, for example, or because another banner is created or destroyed), the banner automatically adjusts to the new layout using the same proportion of the available space.

 

Absolute sizing:  The second method of sizing a banner is to state the size in terms of the “natural units” of the banner window.  The natural units depend on the type of banner:

 

 

Contents-based sizing:  The third method is to size the banner so that its current contents exactly fit.  In many cases, it’s desirable for a banner to be exactly big enough to show some specific contents; this is the case when a banner is used to display something like a status line or an interactive menu.  Even absolute sizing is inherently imprecise for regular text windows, because the natural sizing units are character cells that might not represent the actual mix of characters and fonts displayed.  To accommodate the need for exact content-based sizing, the banner API provides a function, bannerSizeToContents(), that sets the size of a banner window so that the actual current contents exactly fit.

 

Unfortunately, contents-based sizing is not available on all platforms, because some platforms are not capable of supporting it.  It is always safe to call bannerSizeToContents(), but on platforms where content-based sizing isn’t supported, the function will simply do nothing.  Because of this, programs must use the following procedure when contents-based sizing is desired:

 

  1. Calculate an estimate of the required size, in the window’s natural units.  For text windows, this is usually just a matter of determining how many lines of text will be displayed; it’s not possible to take into account any line wrapping that might occur, so if line wrapping is probable, it might be desirable to pad the estimate accordingly.
  2. Call bannerSetSize() to set the banner size to the estimated size.  Pass true for the isAdvisory flag, to indicate that an exact contents-based size will be set later.
  3. Display the contents.
  4. Call bannerSizeToContents() to set the exact contents-based size, if possible.  For platforms where this is not implemented, it will have no effect, so the estimated size will remain in effect; where contents-based sizing is available, the estimated size will be discarded and the exact size set instead.

 

By using this procedure, a program can ensure that it will look reasonably good on all platforms, and that it will look exactly as desired on those platforms that do support size-to-contents (as most platforms do).

Banner Functions

The banner API is part of the “tads-io” function set, which provides programmatic control over the TADS user interface.  The banner functions all have names of the form bannerXxx.

 

bannerClear(handle) – clears the banner’s display.  Removes all text from the banner, and moves the output position back to the upper left corner of the banner’s window.

 

bannerCreate(where, other, windowType, align, size, sizeUnits, style) – creates a new banner window with the given parameters.  where and other together indicate where the banner goes in the layout order (see “Screen Layout Overview”); where can be one of the following values:

 

 

The windowType parameter indicates the type of banner to create; this is one of the following (see “Banner Types” for more information):

 

 

The align setting indicates where the window will appear on the display, relative to the main game window.  This can have one of the following values:

 

 

The size parameter gives the initial size of the banner, the meaning of which depends on sizeUnits:

 

 

style is a combination of flag values specifying the desired behavior for the banner.  Some of the style flags directly indicate particular aspects of the on-screen appearance of the banner; other styles are advisory, giving the interpreter some hints about how you’re planning to use the banner, so that the interpreter can select appearance or behavior variations that are appropriate to the current platform.  Not all interpreters support all styles, so you have to think of the style flags as hints to the interpreter about the desired appearance, rather than a specification of the actual appearance.  After you create the banner, you can use bannerGetInfo() to retrieve the actual style flags, which will give you some indication of how the interpreter treated your request.

 

The style flags are:

 

 

This function returns a handle to the new banner, or nil if an error occurs creating the banner.  The banner handle can be used to operate on the banner in other bannerXxx() functions.

 

bannerDelete(handle) – delete the given banner.  This removes the banner from the display, and recalculates the layout for all of the other banners remaining on the screen.  After this function is called, the banner handle becomes invalid and must not be used for anything else.

 

bannerFlush(handle) – flushes the text output buffer for the given banner, immediately updating the display with any pending text.

 

bannerGetInfo(banner) – retrieves information on the banner.  This function returns a list of values, as follows:

 

 

bannerGoTo(handle, row, col) – move the output position in the given text grid banner to the given row and column.  Rows and columns are numbered from 1 at the upper left corner.  This function can be used only in text grid windows; in other types of windows, it has no effect.

 

bannerSay(handle, …) – writes one or more text items to the banner.  This function treats the parameters following handle the same way that tadsSay() does.

 

bannerSetScreenColor(handle, color) – set the background color in the banner.  This immediately changes the entire window’s background to the given color (in other words, this doesn’t merely affect subsequent text, but also affects everything already displayed in the banner).  The color values are the same as for bannerSetTextColor(), except that ColorTransparent is not meaningful here.

 

bannerSetSize(handle, size, sizeUnits, isAdvisory) – set the size of the banner.  The size and sizeUnits parameters have the same meanings they do in bannerCreate().  If isAdvisory is true, it indicates that the size setting is only an estimate, and that a call to bannerSizeToContents() will be made later; in this case, the interpreter might simply ignore this estimated size setting entirely, to avoid unnecessary redrawing.  Platforms that do not support contents-based sizing will always set the estimated size, even when isAdvisory is true.  If isAdvisory is nil, the platform will set the banner size as requested; set isAdvisory to nil when you will not follow up with a call to bannerSizeToContents().

 

bannerSetTextColor(handle, fg, bg) – set the text color in the given banner to the given foreground and background colors.  The new color settings are used for text subsequently displayed; any text already displayed is not affected.  This can be used only in text grid windows; in ordinary text windows, use HTML <FONT COLOR> tags instead. 

 

The foreground and background colors can have the following values:

 

 

In addition, the special value ColorTransparent can be used for the background color.  This indicates that the text should be drawn with a transparent background, and thus should simply be drawn against the banner’s current background color.

 

bannerSizeToContents(handle) – resizes the given banner based on the current contents of the banner.  For a top-aligned or bottom-aligned banner, this sets the banner’s height so that the banner is just tall enough to show all of the contents as currently laid out.  For a left-aligned or right-aligned banner, this sets the banner’s width so that the banner is just wide enough to hold the banner’s single widest indivisible element (such as a single word or a picture).  This routine can be used to set the banner’s size based on the actual size of the contents; it’s impossible to know the exact size of a banner’s contents until you actually display the contents, because the sizes of fonts and other display elements vary from one machine to another, and can even change on the same machine in response to user preference settings and other factors.

 

Note that this routine might not be implemented on all platforms; on platforms where it’s not implemented, this routine will simply do nothing at all.  Therefore, it’s legal to call the routine on all platforms (there will be no error or other adverse effect where the routine isn’t implemented), but programs cannot rely on this routine being available.  To ensure a reasonable size is always set regardless of platform, callers should always use bannerSetSize() to set an approximate size, and also call bannerSizeToContents() to set the exact content-based size, if appropriate.