home *** CD-ROM | disk | FTP | other *** search
- Turbo Vision Palettes
-
- Objects in Turbo Vision can be grouped into two broad classes: those which are
- descendants of TView (such as TWindow or TButton), and those which are not
- (such as TCollection). The difference, of course, is that objects which are
- descended from TView (also called "views" or "view objects") are intended to
- be displayed on the computer's screen at some point in their lifetimes. Every
- descendant of TView contains a Draw method, which is executed whenever the
- view needs to redraw itself. Although every view's Draw method is different,
- they all share one characteristic: they call GetColor to determine what
- on-screen colors to use when drawing the various parts of the view.
-
- GetColor in turn calls GetPalette, which returns a pointer to the view's
- palette. What is a palette? In Turbo Vision, a palette acts as a translation
- table. In much the same way that the ASCII code maps byte values onto
- characters, a view's palette maps the set of colors used by the view onto the
- palette of the view's owner.
-
- Let's look at the palette of the TLabel view as an example. (It's shown at the
- end of the description of TLabel in the Turbo Vision Guide.) We see that the
- palette has four entries, numbered 1 through 4. TLabel's Draw method knows
- that when it wants to draw normal text, it should use color number 1. But it
- doesn't know what color number 1 really is, and it doesn't care. It simply
- calls GetColor (1) and uses the color that GetColor returns.
-
- GetColor calls GetPalette, which returns a pointer to TLabel's palette. From
- the values contained in the palette, GetColor determines that for TLabel,
- color number 1 is equivalent to TLabel's owner's color number 7. GetColor then
- calls Owner^.GetColor (7); the owner view then goes through the same
- procedure, using its own palette to perform another level of translation, and
- so on, until the ultimate owner is reached, which in most Turbo Vision
- programs is a TApplication object (or descendant). The TApplication object is
- the final color arbiter, and provides all of the views with the actual video
- attributes to use.
-
- Let's trace through the TLabel color hierarchy: We've already determined that
- TLabel color number 1 maps onto its owner's color number 7. The description of
- TLabel's palette in the TV Guide states that TLabel's palette maps onto the
- standard dialog palette. This tells us that TLabel objects are intended to be
- owned by (i.e., inserted into) TDialog objects. If we now turn to TDialog's
- palette description, we see that color number 7 (called "Label Normal") is
- mapped onto TDialog's owner's color number 38. Well, dialog boxes are usually
- inserted into the desktop, so let's look at TDeskTop's palette. When we do
- that, we see that TDeskTop doesn't have a palette; this means that TDeskTop
- doesn't do any color translation--TDialog's color number 38 "falls through" to
- TDeskTop's owner's palette. Well, the desktop is owned by the application, so
- we've reached the end of the chain. When TLabel's Draw method wants to use
- color number 1, it eventually gets told to use the application's color number
- 38.
-
- TApplication's palettes are not shown in the TV Guide, but we can find them in
- the file APP.PAS in the TVISION directory. TApplication actually uses one of
- three different palettes, depending on whether the program is being run on a
- color, black and white, or monochrome monitor. For the purposes of this
- example, we'll assume that we're using a color monitor. If we locate the 38th
- entry in TApplication's palette, we find that it is equal to $70. The upper
- nybble of the byte gives the background color, and the lower nybble the
- foreground color, according to the following table:
-
- 0 - black 4 - red 8 - dark gray C - light red
- 1 - blue 5 - magenta 9 - light blue D - light magenta
- 2 - green 6 - brown A - light green E - yellow
- 3 - cyan 7 - light gray B - light cyan F - white
-
- So, we see that a normal label has black text on a light gray background. All
- of the other colors may be tracked down in a similar manner.
-
- What happens if rather than inserting a TLabel into a TDialog, we insert it
- into a TWindow? Well, let's follow the mapping, again using the "Normal Text"
- color: TLabel color number 1 -> TWindow color number 7 -> TApplication color
- number 14, 22, or 30, depending on whether the window is a blue, cyan, or gray
- window, respectively. These entries correspond to blue text on gray, blue text
- on green, or white text on light gray. Obviously, none of these are the same
- as the black text on light gray of a TLabel inserted into a TDialog. This
- points out a universal truth of Turbo Vision palettes: If a view is designed
- to be inserted into a particular type of owner view, inserting it into a
- different type of owner will almost always result in a change in color.
-
- Anyone who has played around much with Turbo Vision has encountered the
- situation where a view is displayed in flashing white text on a red
- background. This happens when a call to GetColor is made with a color number
- that exceeds the size of the view's palette. For example, let's see what
- happens when we insert a TListBox into a TWindow, rather than a TDialog.
- (Note: The TV Guide says that TListBox's palette maps onto the application
- palette. This is incorrect; it actually maps onto TDialog's palette.) TListBox
- has a five-entry palette which maps onto entries 26 through 29 in its owner's
- palette. Well, lo and behold, a TWindow has only eight entries in its
- palette--obtaining the 26th entry is impossible. In this situation, GetColor
- returns the flashing white on red color to signal the error.
-
- Here is a list of all of the entries in TApplication's palette, along with the
- objects that use them:
-
- 1 Background (DeskTop)
- 2 Text Normal (Menu)
- 3 Text Disabled (Menu)
- 4 Text Shortcut (Menu)
- 5 Selected Normal (Menu)
- 6 Selected Disabled (Menu)
- 7 Selected Shortcut (Menu)
- 8 Frame Passive (Blue Window)
- 9 Frame Active (Blue Window)
- 10 Frame Icon (Blue Window)
- 11 ScrollBar Page (Blue Window)
- 12 ScrollBar Reserved (Blue Window)
- 13 Scroller Normal Text (Blue Window)
- 14 Scroller Selected Text (Blue Window)
- 15 Reserved (Blue Window)
- 16 Frame Passive (Cyan Window)
- 17 Frame Active (Cyan Window)
- 18 Frame Icon (Cyan Window)
- 19 ScrollBar Page (Cyan Window)
- 20 ScrollBar Reserved (Cyan Window)
- 21 Scroller Normal Text (Cyan Window)
- 22 Scroller Selected Text (Cyan Window)
- 23 Reserved (Cyan Window)
- 24 Frame Passive (Gray Window)
- 25 Frame Active (Gray Window)
- 26 Frame Icon (Gray Window)
- 27 ScrollBar Page (Gray Window)
- 28 ScrollBar Reserved (Gray Window)
- 29 Scroller Normal Text (Gray Window)
- 30 Scroller Selected Text (Gray Window)
- 31 Reserved (Gray Window)
- 32 Frame Passive (Dialog)
- 33 Frame Active (Dialog)
- 34 Frame Icon (Dialog)
- 35 ScrollBar Page (Dialog)
- 36 ScrollBar Controls (Dialog)
- 37 StaticText (Dialog)
- 38 Label Normal (Dialog)
- 39 Label Highlight(Dialog)
- 40 Label Shortcut (Dialog)
- 41 Button Normal (Dialog)
- 42 Button Default (Dialog)
- 43 Button Selected (Dialog)
- 44 Button Disabled (Dialog)
- 45 Button Shortcut (Dialog)
- 46 Button Shadow (Dialog)
- 47 Cluster Normal (Dialog)
- 48 Cluster Selected (Dialog)
- 49 Cluster Shortcut (Dialog)
- 50 InputLine Normal (Dialog)
- 51 InputLine Selected (Dialog)
- 52 InputLine Arrows (Dialog)
- 53 History Arrow (Dialog)
- 54 History Sides (Dialog)
- 55 HistoryWindow ScrollBar page (Dialog)
- 56 HistoryWindow ScrollBar controls (Dialog)
- 57 ListViewer Normal (Dialog)
- 58 ListViewer Focused (Dialog)
- 59 ListViewer Selected (Dialog)
- 60 ListViewer Divider (Dialog)
- 61 InfoPane (Dialog)
- 62 Reserved (Dialog)
- 63 Reserved (Dialog)
-
- What about changing colors in Turbo Vision? If all you want to do is change
- the color of all instances of an object, say, by making all of your TButtons
- cyan instead of green, you've got it easy. You just change the appropriate
- entries in TApplication's palette (41 through 46), and you're set.
-
- That was easy. Now, what about creating a new, unique view which is unlike any
- predefined Turbo Vision objects? How will we color it? Let's say we want to
- insert our new view (call it a TNewView) into a TDialog, and we want to use
- two different colors, one for normal text and one for highlighted text. First,
- we add two entries to TApplication's palette (numbers 64 and 65) that will
- correspond to the two colors used by our new view. For the purposes of this
- example, we'll say we want blue on light gray ($71) for normal text and light
- green on light gray ($7A) for highlighted text (assuming a color monitor). Our
- TApplication palette will now look like this:
-
- CColor =
- #$71#$70#$78#$74#$20#$28#$24#$17#$1F#$1A#$31#$31#$1E#$71#$00 +
- #$37#$3F#$3A#$13#$13#$3E#$21#$00#$70#$7F#$7A#$13#$13#$70#$7F#$00 +
- #$70#$7F#$7A#$13#$13#$70#$70#$7F#$7E#$20#$2B#$2F#$78#$2E#$70#$30 +
- #$3F#$3E#$1F#$2F#$1A#$20#$72#$31#$31#$30#$2F#$3E#$31#$13#$00#$00 +
- #$71#$7A; { <- these last two are the new entries }
-
- We must make similar changes in the black & white and monochrome palettes, of
- course. Next, since we will be inserting TNewView into a TDialog, we need to
- override TDialog's GetPalette method so that it will supply GetColor with the
- proper palette:
-
- const
- CNewDialog = CDialog + #64#65;
-
- type
- TNewDialog = object (TDialog)
- function GetPalette: PPalette; virtual;
- end;
- .
- .
- .
- function TNewDialog.GetPalette: PPalette;
-
- const
- P: String[Length (CNewDialog)] = CNewDialog;
-
- begin
- GetPalette := @P;
- end;
-
- Since we added our two new colors to the end of the standard TDialog palette,
- which contains 32 entries, they will be the 33rd and 34th entries in
- TNewDialog's palette. Now we have to define our TNewView so that it maps onto
- the 33rd and 34th entry of its owner's palette:
-
- const
- CNewView = #33#34;
-
- type
- TNewView = object (TView)
- function GetPalette: PPalette; virtual;
- .
- .
- .
- end;
-
- function TNewView.GetPalette: PPalette;
-
- const
- P: String[Length (CNewView)] = CNewView;
-
- begin
- GetPalette := @P;
- end;
-
- There. That wasn't so bad, was it? When TNewView's Draw method asks for color
- number 1, it will get color number 64 from TApplication's palette; similarly,
- color number 2 leads to TApplication's color number 65. If we ever want to
- change the colors of our TNewView object, we simply change the entries in
- TApplication's palette.
-
- Okay, let's try something a bit trickier. Let's say we want to insert a view
- into an owner which is not of the "correct" type. We already know that unless
- we modify the palettes and associated methods, the colors will come out wrong.
- The most general solution to the problem is to define a new object type, as in
- the previous example. Thus, if we wanted to insert a TButton into a TWindow,
- we would define a descendant of TButton (called TWindowButton, perhaps) and
- follow the same steps we performed above to give it a set of colors to use.
-
- In some cases, we don't need to add to TApplication's palette. In the previous
- example, if all we want to do is put a button in a window, and we want the
- button to look just like an ordinary TButton inserted into a TDialog, we can
- use the same TApplication palette entries (41 through 46):
-
- const
- CNewWindow = CGrayWindow + #41#42#43#44#45#46;
- CWindowButton = #9#10#11#12#13#13#13#14;
-
- type
- TNewWindow = object (TWindow)
- function GetPalette: PPalette; virtual;
- end;
-
- TWindowButton = object (TButton)
- function GetPalette: PPalette; virtual;
- end;
-
- The GetPalette method code is analogous to that of the previous example. Now,
- when TWindowButton.Draw asks for color number 2, it is mapped to TNewWindow's
- color number 10, which is mapped to TApplication's color number 42, just as if
- it had been a TButton inserted into a TDialog. Note that I used CGrayWindow as
- the basis for CNewWindow's palette. Since a TButton is normally inserted into
- a TDialog, two of its colors (44 and 46) use a gray background. If you wanted
- to put buttons into cyan or blue windows, you would need to use the more
- general method of adding to TApplication's palette, as in the previous
- example.
-
- Last but not least, what about objects which can be instantiated with one of
- several palettes? TWindow is a good example of this type of object; you can
- have windows with blue, gray, or cyan color schemes. One of TWindow's fields
- (Palette) is used to indicate which color scheme GetPalette should return.
- TWindow.GetPalette might look something like this:
-
- function TWindow.GetPalette: PPalette;
-
- const
- PGray: string[Length (CGrayWindow)] = CGrayWindow;
- PCyan: string[Length (CCyanWindow)] = CCyanWindow;
- PBlue: string[Length (CBlueWindow)] = CBlueWindow;
-
- begin
- case Palette of
- wpGrayWindow: GetPalette = @PGray;
- wpCyanWindow: GetPalette = @PCyan;
- wpBlueWindow: GetPalette = @PBlue;
- end;
- end;
-
- You can use the same technique with any objects of your own devising.
-
- Well, that's about it for Turbo Vision palettes. Are you thoroughly confused
- yet? Just remember: figuring out what color a view is going to be drawn with
- is as simple as tracing the color mapping up the ownership hierarchy, until
- you reach the TApplication object.
-
- Please direct comments or suggestions to Steve Schafer [71121,1771].
-