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; { <- the 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].
-