Color Selector
Volume Number: 9
Issue Number: 2
Column Tag: TCL Workshop
Color Quickdraw
A Floating Color Selection 
Window for TCL
Creating a floating pallette in TCL without using the Palette Manager
By Paul M. Hyman, Hughes Aircraft Co., Fullerton, CA
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
About the author
Paul Hyman is a Systems Engineer with Hughes Aircraft Company. He has
developed software on a variety of different systems including Macintosh, Unix/X
Windows, and several Hughes-built computers no one has ever heard of.
The Think Class Library provides a useful object oriented application framework
for users of Think C. It provides much of the standard Macintosh application
functionality, including scrolling windows, menus, and standard AppleEvent handling if
you’re using System 7, as well as some not-so-standard functionality such as tear-off
menus and floating windows.
This article describes some new classes which implement a floating color
selection window, which seems to be the way most color drawing and painting
programs allow users to select colors these days. This window might sometimes be
referred to as a color palette, but I will call it a color selection window to avoid
confusion with the palette manager. These classes were developed using Think C 5.0.2
with Think Class Library version 1.1.2.
The color selection window does the following. It shows the available colors in
the palette assigned to the active document (up to 256), and highlights the current
selection. The size of 256 was chosen since it is appropriate for 8 bit color displays
and is used in many programs. You could modify it to be some other size if you want.
The window allows the user to select a new color by clicking on it and allows the
application to change the currently selected color by sending it a message. It can also
inform the application of the current color in response to a message and will notify the
current document when the user selects a new color. The color selector is designed to
be used as a global object; there is only one and it is always present, even though its
window may be hidden if the user clicks in its close box.
The sample program which is shown illustrates how to use this color selection
window. It also shows how to maintain a list of objects which the user has created.
Basically, it allows the user to create colored boxes (rectangles) in a window and
recognizes when one of the boxes has been selected by being clicked on. Boxes are
created with the currently selected color. When an existing box is clicked on, its color
is selected in the floating window.
As you will unoubtedly notice, I didn’t follow the TCL convention of putting C in
front of all class names. This distinguishes the new classes from the classes provided
with the TCL.
How to Use the Color Selector
If you’re starting a new program, you might want to use the color selector
sample program as a starting point. Copy the source files from the Starter application
(which comes with Think C) into your project folder. These are needed since they
serve as superclasses for some of the sample application’s classes. If you have the
MacTutor disk, you will have the project and resource files and will be ready to go. If
not, copy the project and resource files from the Starter application and add in the
classes from the color selector sample application.
In order to make use of the color selector window in an existing program, do the
following:
1. Put the colordirector, colorselector, and selectorwindow classes into your
project.
2. In your document class’ DoCommand method, add a case for cmdColorSelect, and
#include colorselector.h (this is where cmdColorSelect is defined). This will
enable your document to receive a notice when the user selects a new color in the
color selection window. See the code in the mydoc class for how to handle this
message.
3. Copy the code from the Activate method of docwindow into your window class’
code. This Activate method sends a notification to the color selector window
informing it that a new window has been activated and that its palette should be
displayed.
4. Override CApplication’s MakeDesktop method in your application class to create a
floating window desktop. See the MakeDesktop method in the myapp class to see
how to do this.
5. Copy the code from myapp's Imyapp method into your applications initialization
method. This code creates the color selector objects.
You will need to add a few resources to your resource file. You will need to add
the windoid WDEF which is supplied with the TCL. You will also need a pltt resource
with the same ID as your document window (500 in the case of the sample program
described below) unless you build your palette in the code. (The use of palettes is
explained more in the next section.) In addition, the sample program has a menu item,
“Show Color Selector#1025” (the 1025 is the TCL command number), and ALRT
130 for the About box.
The sample program.
The sample program presented with this article allows the user to select a color
from the selection window and then create a box of that color in the document window
by clicking in some empty spot and dragging down and to the right. Clicking on an
existing box causes its color to be selected in the selection window. The program
maintains a list of boxes so that they can be drawn when the window is scrolled and so
that it can detect when a mouse click occurred in an existing box.
To use the color selection window, each document window must have a color
palette associated with it. The easiest way to create a palette is to use Resedit and
create a pltt resource with the same id as the id of the WIND resource for the window.
Since this program uses a WIND resource of ID 500 to build its document windows,
putting in a pltt resource of ID 500 automatically associates the palette with the
window. Just for illustrative purposes, the program shows how to create a palette in
the code. The first document window (the one that appears when the program starts
up) uses the palette from the pltt resource. The second window, which is created when
New is selected from the File menu, has a palette of shades of red, while the third
window, which is created when New is selected the second time, has a palette of shades
of green.
When using the TCL, every program must have an application class. For this
demo program, I created a class called myapp, which is a subclass of CStarterApp, the
application class that comes with the Starter demo program. If the application has
documents, it must also have a document class, as well as a pane class in which to do its
drawing. Just as with the application class, I created a document class, mydoc, which
is a subclass of CStarterDoc, and a pane class, mypane, which is a subclass of
CStarterPane. I could have just modified the classes in the Starter demo rather than
creating subclasses, but this would have made it difficult to explain the code which is
necessary to use the color selector. By creating subclasses, the new code is isolated in
the new classes. I also created a new subclass of CWindow, which I called doc window,
since I needed to modify the window behavior slightly.
In addition to the application, document, and pane classes, there is a class called
genericbox, which manages a box on the screen, and boxlist, which keeps a list of all
the boxes belonging to a document. The class genericbox is so named because if this
program were to be expanded into a drawing program, genericbox would probably be
used as an abstract class to give general behavior to boxes on the screen and would be
overridden to create specific shapes.
In the following paragraphs, the methods in these new classes and what they do to
support the color selection window are briefly described. For more details, refer to
the comments in the code.
The application class, myapp:
Imyapp - This is the initialization method. It creates the colordirector object
and sends it an initialize message.
DoCommand - This method processes menu selections. In the case of the “Show
Color Selector” menu item, this method sends a Show message to the color selector’s
window. (The window will be hidden if the user clicked in its close box and this is how
it gets made visible again.)
UpdateMenus - This method is responsible for enabling appropriate menu
items before a menu is displayed. It simply enables the “Show Color Selector” menu
item. It could be made smarter and only enable it if the window is hidden.
CreateDocument - This is basically the same as the CreateDocument method in
the CStarterApp class. The only difference is that it creates a mydoc document instead
of a CStarterDoc document.
MakeDesktop - This method creates a floating window desktop instead of the
normal kind.
The document class, mydoc:
Imydoc - This is the initialization method. It creates a boxlist object for this
document.
BuildWindow - This code is mostly copied from the CStarterDoc code. The main
differences are that it creates a docwindow instead of a CWindow and puts a mypane
pane in it, and it creates individual color palettes for the second and third document
windows.
selectabox - Determines whether the user clicked in an existing box by calling
the boxlist object’s hitbox method with the mouse location. If the user did click in a
box, the box is sent a doselectstuff message.
DoNewBox - Creates a new box, using the currently selected color. This is
called after the user has clicked and dragged the mouse to create a box.
DoCommand - Processes the command which is sent when the user changes the
selected color in the color selection window. The sample program doesn’t do anything
here, but it would be the place to implement changing the color of selected boxes.
The pane class, mypane:
Imypane - This is the initialization method. It merely calls the CStarterPane
initialization method.
Perform_draw - This method is passed a genericbox object as a parameter and
calls its draw method. It is used in conjunction with the DoForEach method of the CList
object to call each box to draw itself.
Draw - This method is called when all or part of the pane is to be drawn. A rectangle is passed as an argument which defines the area to be redrawn. This method
ignores the rectangle and redraws everything. It makes use of the DoForEach function
provided by the TCL’s CList class, of which boxlist is a subclass. It calls the
DoForEach method of the boxlist belonging to the current document and passes it the
Perform_draw function as the function to be executed for each box.
DoClick - This method checks whether the user clicked in an existing box. If
not, it tracks the mouse as the user drags it and then calls the document’s DoNewBox
method to create a new box.
ChangeSize - I copied some code from the ArtClass demo application in here to
make the pane scroll correctly. The Starter application does not scroll properly.
The genericbox class, which manages a box on the screen:
Igenericbox - The initialization method. Saves the box’s bounding rectangle and
its color.
draw - Draws the box by calling PaintRect.
testhit - Determines whether a point (presumably the mouse location) is inside
the box.
doselectstuff - Handles the actions to be taken when the user selects (clicks
on) the box. It erases and redraws the box to make it flash, and sends a changecolor
message to the color selector so that the box’s color will be selected in the color
selector window.
The boxlist class, which manages a list of boxes:
hitbox - This is the only method. Boxlist is a subclass of CList, which is used for
managing an ordered list of objects. The additional functionality provided by boxlist is
in this method, which calls each object’s testhit method to see whether or not the
mouse coordinates are inside its box. If one of the boxes returns true, that object is
passed back as the function result.
How the Color Selector Works
The Think Class Library provides a class called CGridSelector which allows for
the selection of an item in a grid of items. This class serves as the basis for the
colorselector class which displays the selection of colors in a 16x16 grid.
There are actually three classes necessary to implement the color selection
window: colorselector, selector window, and colordirector. The colorselector class is a
subclass of CPane, since CGridSelector (its parent class) is a subclass of CPane. In
TCL all drawing is done within Panes. The pane must be placed into a window, and in
this case a new class, selector window, which is a subclass of CWindow, is used to hold
the colorselector pane. The only difference between selectorwindow and CWindow is
that when the close box is clicked in a normal (CWindow) window, the window is closed
and the object is deleted. I wanted the object to stay around, so selector window
overrides the Close method and simply hides the window. The other class,
colordirector, is a subclass of CDirector. In TCL, each window must have a director
associated with it. The most common kind of director is CDocument, which manages a
normal document window. In the case of the color selector window, a special director,
colordirector, is required. The colordirector class has an initialization method which
places the window on the screen having the greatest pixel depth, and creates a
colorselector Pane to put in the window. It also has a DoCommand method which
processes color change commands which the color selector sends.
The following paragraphs describe the methods in these classes. For more
details, refer to the comments in the code.
colorselector:
DrawItem - This method draws a single color rectangle in the color selection
window. It uses the item number as an index and calls the palette manager to get the
appropriate entry color.
HiliteItem - Highlights the item so the user can see which color is selected.
The default hiliting method used by GridSelector is to invert the item. This doesn’t
look good with colors, so this method (which overrides HiliteItem in CGridSelector)
draws a rectangle around the item.
currentcolor - Returns the currently selected color and its palette entry
number.
windowactivated - This method is called by mydoc’s Activate method whenever
a document window is activated. It copies the document window’s palette and associates
it with the color selector window. The palette must be associated with the color
selector window because as far as the palette manager is concerned, the color selector
window is the top window and its palette takes precedence over all other windows.
changecolor - Informs the color selector that the selected color should be
changed. This method should be called when the program wishes to change the selected
color, such as when the user has selected something and its color should be shown as
selected.
colordirector:
Icolordirector - This is the initialization method. It creates the color selector
window and puts it on the screen with the greatest pixel depth.
DoCommand - This method forwards the command (which will be a notification
of a color selection change) on to the top document. (The colorselector class, by virtue
of its inheritance of CGridSelector’s behavior, sends a command to its supervisor (the