status.t | documentation |
#charset "us-ascii" /* * Copyright (c) 2000, 2006 Michael J. Roberts. All Rights Reserved. * * TADS 3 Library - Status Line * * This module defines the framework for displaying the status line, * which is the area conventionally displayed at the top of the screen * showing information such as the current location, score (if scoring is * used at all), and number of turns. */ /* include the library header */ #include "adv3.h" /* ------------------------------------------------------------------------ */ /* * In case the 'score' module isn't included, make sure we can refer to * totalScore as a property. Likewise for the banner API and Web UI * frame API. */ property totalScore; property showBanner, setSize, sizeToContents; property flushWin, resize; /* ------------------------------------------------------------------------ */ /* * A special OutputStream for the <BANNER> tag contents. This is really * just part of the main output stream, but we use a separate output * stream object so that we have our own separate stream state variables * (for paragraph breaking and so forth). */ transient statusTagOutputStream: OutputStream /* * We're really part of the main window's output stream as far as the * underlying interpreter I/O system is concerned, so we have to * coordinate with the main game window's input manager. */ myInputManager = inputManager /* we sit atop the system-level main console output stream */ writeFromStream(txt) { /* write the text directly to the main output stream */ tadsSay(txt); } ; /* * A special OutputStream for the left half of the status line (the * short description area) in text mode. We use a separate stream for * this because we must write the text using the output mode switching * for the status line. * * We only use this stream when we use the old-style text-mode status * line interface, which explicitly separates the status line into a * left part and a right part. When we have the banner API available in * the interpreter, we'll use banners instead, since banners give us * much more flexibility. */ transient statusLeftOutputStream: OutputStream /* we sit atop the system-level main console output stream */ writeFromStream(txt) { /* write the text directly to the main output stream */ tadsSay(txt); } ; /* * A special OutputStream for the right half of the status line (the * score/turn count area) in text mode. We use a separate stream for * this because we have to write this text with the special * statusRight() intrinsic in text mode. * * We only use this stream when we use the old-style text-mode status * line interface, which explicitly separates the status line into a * left part and a right part. When we have the banner API available in * the interpreter, we'll use banners instead, since banners give us * much more flexibility. */ transient statusRightOutputStream: OutputStream /* * Write from the stream. We simply buffer up text until we're * asked to display the final data. */ writeFromStream(txt) { /* buffer the text */ buf_ += txt; } /* * Flush the buffer. This writes whatever we've buffered up to the * right half of the text-mode status line. */ flushStream() { /* write the text to the system console */ statusRight(buf_); /* we no longer have anything buffered */ buf_ = ''; } /* our buffered text */ buf_ = '' ; /* ------------------------------------------------------------------------ */ /* * Statusline modes. We have three different ways to display the * statusline, depending on the level of support in the interpreter. * * StatusModeApi - use the banner API. This is preferred method, because * it gives us uniform capabilities on text and graphical interpreters, * and provides an output stream for the statusline that is fully * independent on the main game window's output stream. * * StatusModeTag - use the <BANNER> tag. This is the method we must use * for HTML-enabled interpreters that don't support the banner API. This * gives us the full formatting capabilities of HTML, but isn't as good * as StatusModeApi because we have to share our output stream with the * main game window. * * StatusModeText - use the old-style dedicated statusline in a text-only * interpreter. This is the least desirable method, because it gives us * a rigid format for the statusline (exactly one line high, no control * over colors, and with the strict left/right bifurcation). We'll only * use this method if we're on a text-only interpreter that doesn't * support the banner API. * * StatusModeBrowser - use the Web UI. This is similar to API mode, but * instead of using banner windows we use Web UI windows, which are * implemented as IFRAMEs in the browser. */ enum StatusModeApi, StatusModeTag, StatusModeText, StatusModeBrowser; /* ------------------------------------------------------------------------ */ /* * Status line - this is an abstract object that controls the status line * display. * * We provide two main methods: showStatusHtml, which shows the status * line in HTML format, and showStatusText, which shows the status line * in plain text mode. To display the status line, we invoke one or the * other of these methods, according to the current mode, to display the * statusline. The default implementations of these methods generate the * appropriate formatting codes for a statusline with a left part and a * right part, calling showStatusLeft and showStatusRight, respectively, * to display the text for the parts. * * Games can customize the statusline at two levels. At the simpler * level, a game can modify showStatusLeft and/or showStatusRight to * change the text displayed on the left and/or right of the statusline. * Since these two methods are used regardless of the statusline style of * the underlying interpreter, games don't have to worry about the * different modes when overriding these. * * At the more complex level, a game can modify showStatusHtml and/or * showStatusText. Modifying these routines provides complete control * over the formatting of the entir status line. If a game wants to use * something other than the traditional left/right display, it must * modify these methods. * * This object is transient, because the statusline style is a function * of the interpreter we're currently running on, and thus isn't suitable * for saving persistently. */ transient statusLine: object /* * Show the status line, in HTML or text mode, as appropriate. By * default, the library sets this up as a "prompt daemon," which * means that this will be called automatically just before each * command line is read. */ showStatusLine() { local oldStr; /* if the status line isn't active, or there's no PC, skip this */ if (statusDispMode == nil || gPlayerChar == nil) return; /* * showing the status line doesn't normally change any game * state, so we can turn on the sense cache while generating the * display */ libGlobal.enableSenseCache(); /* * Enter status-line mode. This will do whatever is required for * our current status-line display style to prepare the output * manager so that any text we display to the default output * stream is displayed on the status line. */ oldStr = beginStatusLine(); /* make sure we restore statusline mode before we're done */ try { /* * Generate a text or HTML status line, as appropriate. If * we're in <BANNER> tag mode or banner API mode, use HTML to * format the contents of the status line; if we're using the * old-style text mode, use plain text, since the formatting * is rigidly defined in this mode. */ switch (statusDispMode) { case StatusModeTag: case StatusModeApi: case StatusModeBrowser: /* show the HTML status line */ showStatusHtml(); break; case StatusModeText: /* show the status line in plain text mode */ showStatusText(); break; } } finally { /* end status-line mode */ endStatusLine(oldStr); /* turn off sense caching */ libGlobal.disableSenseCache(); } } /* prompt-daemon showing the status line */ showStatusLineDaemon() { /* show the status line as normal */ showStatusLine(); /* * Explicitly flush the status line if it's in a banner window. * This will ensure that we'll redraw the status line on each * turn if we're reading an input script, which is nice because * it provides a visual indication that something's happening. */ if (statusDispMode is in (StatusModeApi, StatusModeBrowser)) statuslineBanner.flushBanner(); } /* * Show the status line in HTML format. Our default implementation * shows the traditional two-part (left/right) status line, using * showStatusLeft() and showStatusRight() to display the parts. */ showStatusHtml() { /* * start the left half, and write the <A HREF> to hyperlink the * location name to a "look around" command */ "<<statusHTML(0)>><< aHref(gLibMessages.commandLookAround, nil, nil, AHREF_Plain)>>"; /* show the left part of the status line */ showStatusLeft(); /* * end the left portion and start the right portion, then * generate the <A HREF> to link the score to a FULL SCORE * command */ "<./a></a><<statusHTML(1)>><< aHref(gLibMessages.commandFullScore, nil, nil, AHREF_Plain)>>"; /* show the right part of the status line */ showStatusRight(); /* end the score link, and end the right half wrapper */ "<./a></a><<statusHTML(2)>>"; /* add the status-line exit list, if desired */ if (gPlayerChar.location != nil) gPlayerChar.location.showStatuslineExits(); } /* * Get the estimated HTML-style banner height, in lines of text. * This is used to set the status line banner size for platforms * where sizing to the exact height of the rendered contents isn't * supported. * * If showStatusHtml() is overridden to display more or fewer lines * of text than the basic implementation here, then this routine must * be overridden as well to reflect the new height. */ getEstimatedHeightHtml() { local ht; /* * we need one line for the basic display (the location name and * score/turn count) */ ht = 1; /* add in the estimated height of the exits display, if appropriate */ if (gPlayerChar.location != nil) ht += gPlayerChar.location.getStatuslineExitsHeight(); /* return the result */ return ht; } /* * Show the statusline in text mode. Our default implementation * shows the traditional two-part (left/right) status line, using * showStatusLeft() and showStatusRight() to display the parts. */ showStatusText() { /* show the left part of the display */ showStatusLeft(); /* switch to the right-side status stream */ outputManager.setOutputStream(statusRightOutputStream); /* show the right-half text */ showStatusRight(); /* flush the right-side stream */ statusRightOutputStream.flushStream(); } /* * Show the left part of a standard left/right statusline. By * default, we'll show the player character's location, by calling * statusName() on the PC's immediate container. */ showStatusLeft() { local actor; /* get the player character actor */ actor = gPlayerChar; "<.statusroom>"; /* show the actor's location's status name */ if (actor != nil && actor.location != nil) actor.location.statusName(actor); "<./statusroom>"; } /* * Show the right part of a standard left/right statusline. By * default, we'll show the current score, a slash, and the number of * turns. */ showStatusRight() { local s; /* if there's a score object, show the score */ if ((s = libGlobal.scoreObj) != nil) { /* show the score and the number of turns so far */ "<.statusscore><<s.totalScore>>/<< libGlobal.totalTurns>><./statusscore>"; } } /* * Set up the status line's color scheme. This is called each time * we redraw the status line to set the background and text colors. * We call the statusline banner window to do the work, since the * mechanism is different between the traditional and Web UIs. */ setColorScheme() { /* call the banner window to do the work */ statuslineBanner.setColorScheme(); } /* * Begin status-line mode. This sets up the output manager so that * text written to the default output stream is displayed on the * status line. Returns the original output stream. */ beginStatusLine() { local oldStr; /* check what kind of statusline display we're using */ switch(statusDispMode) { case StatusModeApi: /* * We have a banner API window. Start by clearing the * window, so we can completely replace everything in it. */ statuslineBanner.clearWindow(); /* * If the platform doesn't support size-to-contents, then set * the height to our best estimate for the size. * * If we do support size-to-contents, we'll set the height to * the exact rendered size when we're done, so we don't need * to worry about setting an estimate; indicate this to the * interpreter by setting the is-advisory flag to true. */ statuslineBanner.setSize(getEstimatedHeightHtml(), BannerSizeAbsolute, true); /* switch to the banner's output stream */ oldStr = statuslineBanner.setOutputStream(); /* set up the statusline color in the window */ setColorScheme(); /* done */ break; case StatusModeBrowser: /* browser UI - clear the window */ statuslineBanner.clearWindow(); /* switch to its output stream */ oldStr = statuslineBanner.setOutputStream(); break; case StatusModeTag: /* * We're using <BANNER> tags. Switch to our statusline * output stream. */ oldStr = outputManager.setOutputStream(statusTagOutputStream); /* set up the <BANNER> tag */ "<banner id=StatusLine height=previous border>"; /* set up the color scheme */ setColorScheme(); /* done */ break; case StatusModeText: /* flush the main window */ flushOutput(); /* plain text mode - enter text status mode */ statusMode(StatModeStatus); /* switch to the status-left output stream */ oldStr = outputManager.setOutputStream(statusLeftOutputStream); /* done */ break; } /* return the original output stream */ return oldStr; } /* end statusline display */ endStatusLine(oldStr) { /* restore the old default output stream */ outputManager.setOutputStream(oldStr); /* check the type of statusline we're generating */ switch (statusDispMode) { case StatusModeApi: /* banner API mode - end the last line */ statuslineBanner.writeToBanner('\n'); /* * Size the window to its current contents. This doesn't * work everywhere - on a few platforms, it does nothing - * but this will give us the optimal size where it's * supported. On platforms that don't support this, it'll do * nothing, which means we'll simply be left with the * "advisory" size we established earlier. */ statuslineBanner.sizeToContents(); break; case StatusModeBrowser: /* browser mode - flush the window and update the content size */ statuslineBanner.flushWin(); break; case StatusModeTag: /* HTML <BANNER> mode - end the <BANNER> tag */ statusTagOutputStream.writeToStream('</banner>'); break; case StatusModeText: /* plain text statusline - end status mode */ statusMode(StatModeNormal); } } /* * Initialize the banner window, given the BannerWindow object * representing the status line banner API window. */ initBannerWindow(win) { /* * Try showing the banner API window. If that succeeds, use the * banner API window, since it's the most portable and flexible * way to show the status line. If we can't create the banner * API window, it means we're on an interpreter that doesn't * support the banner API, so fall back on one of the older, less * flexible mechanisms; which older mechanism we choose depends * on what kind of interpreter we're on. * * Since we create the status line banner during initialization * and normally leave it as the first item in the display list at * all times, we can attach to an existing status line banner * window if there is one. This will avoid unnecessary redrawing * on RESTART. */ if (win.showBanner(nil, BannerFirst, nil, BannerTypeText, BannerAlignTop, nil, nil, BannerStyleBorder | BannerStyleTabAlign)) { /* * we successfully created the banner window - use the banner * API to show the status line */ statusDispMode = StatusModeApi; } else if (outputManager.htmlMode) { /* * We failed to create a banner API window, and we're running * on a full HTML interpreter, so use <BANNER> tags to * produce the status line. */ statusDispMode = StatusModeTag; } else { /* * We failed to create a banner API window, and we're running * on a text-only interpreter - use the old-style * fixed-format status line mechanism. */ statusDispMode = StatusModeText; } } /* * The status mode we're using. If this is nil, it means we haven't * chosen a mode yet. */ statusDispMode = nil ;
TADS 3 Library Manual
Generated on 5/16/2013 from TADS version 3.1.3
Generated on 5/16/2013 from TADS version 3.1.3