Sep 87 Letters
Volume Number: 3
Issue Number: 9
Column Tag: Letters
Letters
Plotting Small Icons
David Dunham
Goleta, CA
A frequent question on the networks is, “how do you draw small icons (SICNs)?”
A quick look at a SICN resource shows it to be simply the bits of the images. SICNs
resemble ICN#s in that there can be multiple small icons in the same resource, but
there is no count, and no data is presumed to be a mask. Each image is 32 bytes of data.
So the SICN with ID=-15744 (in the system file), has the hexadecimal
representation:
0000 0000 3FF0 48A8 48A4 4824 47C4 4004 4004 47C4 4824 4824 4824 3FFC
0000 0000. (See figure 1)
This is the sort of bit image which CopyBits() manipulates, so drawing the SICN
is a simple matter of stuffing the appropriate bit image into a BitMap data structure
and calling CopyBits().
/*
PLOTSICN - Draw the sicnNUMth small icon of sicn in sicnRect of
window.
*/
PlotSICN (sicn, sicnRect, sicnNum, window)
Handle sicn;
Rect *sicnRect;
short sicnNum;
WindowPtr window;
{
BitMap sicnBits;
/* Set up the bit map */
sicnBits.rowBytes = 2;
SetRect(&sicnBits.bounds,0,0,16,16);
sicnBits.baseAddr = *sicn + (sicnNum * 32);
/* Blit the SICN */
CoptBits(&sicnBits,& window->portBits,
&sicnBits.bounds, sicnRect, srcCopy, NIL);
}
Note that we’re passing a dereferenced handle (*sicn). But according to
Professor Mac (Steve Brecher), there’s no need to lock the handle, since CopyBits()
won’t alter the heap configuration unless a picture or region is being recorded.
Fig. 1 A Mini-disk icon from the system file
Colorizing Logos
David Dunham
Goleta, CA
With the advent of the Macintosh II, programs can use color. Doing so effectively
and correctly isn’t easy (both technically and from a user interface standpoint). But
it’s easy to add a little spice to a program by colorizing the logo in its “about” dialog.
This note assumes that logos are normally PICT items in a dialog, and explains
how to make them appear in color on a Macintosh II.
The simplest way to create color logos is to use SuperPaint. Copy a bitmap to the
object layer, activate the color palette, and give the bitmap color. If you want to use
different colors, you’ll have to use multiple bitmaps. Note that SuperPaint’s color
names are misleading. What it calls “orange” displays on the Mac II screen as red.
Since you have to run SuperPaint in 1-bit color, the easiest way to see what your
graphic really looks like is to copy it into a desk accessory like Acta or Scrapbook and
use Control Panel to turn color on.
If you don’t own SuperPaint, you can edit a ‘PICT’ resource with ResEdit. The
fgColor opcode is 0E, and it takes a longword of color data (see Tech Note 21).
An advantage of this technique is that you can use it even without owning a
Macintosh II. I gave Acta 1.2 a color logo even though it was released before the
Macintosh II was introduced. I was able to check my work by printing with an
ImageWriter II and a color ribbon. Also, this technique takes no programming, you can
color arbitrary shapes, and it’s compatible with all machines. The disadvantage is that
you’re limited to the 6 colors (not counting black and white) supported by the original
QuickDraw.
If you want to use colors which aren’t black, white, or the additive and
subtractive primaries, you’ve got to use Color QuickDraw. But at the time I’m
writing this, there are no programs which create Color QuickDraw pictures. (Even if
there were, these pictures can’t be used on machines which aren’t running System 4.1
or later. The structure of a version 2 picture pr events it from crashing a machine
without ColorQuickDraw or the patches, but also means the picture will come out
blank.) And pictures are played back in their original colors-- you can’t use an old
‘PICT’ and just call RGBForeColor and then DrawPicture.
I use a technique similar to the way you dim text-- draw it, then Bic a grey
pattern over it. In color, use the new max transfer mode. This replaces the
destination color with a color whose individual RGB values are the larger of the source
and destination colors’ RGB values. Since the original art is in black, and the dialog
backround is white, this simply replaces all black pixels with the color we want (the
RGB values for a black pixel are all 0, so our color is used; the RGB values for white
are all 65535, so our color is ignored).
There is a catch-- this only works if the dialog is a color window (i.e. has a
color grafPort). GetNewDialog creates color windows if there ‘s a ‘dctb’ resource with
the same ID as the ‘DLOG’ resource. The easiest way to create a ‘dctb’ it to use ResEdit
to copy the one from the Control Panel desk accessory and change its ID.
Note that in a 1-bit deep bitmap, max maps to Bic. Painting in this mode would
erase the picture, so we don’t do anything. (I’m assuming that the dialog doesn’t extend
over different screens; if it did, the picture could be colorized on one screen and erased
on another.)
I used this technique to give Findswell a color logo that matched the logo on the
box. The C routine below is the one I used. It’s hardcoded to Findswell’s color, but you
could pass the color as an argument.
#define max (37)
#define RGBBlack ((RGBColor *)0xc10)
#define ROM85 (*(int *)0x28e)
/*
COLORIZE -- change the color of an item in a
(color) dialog
*/
void colorize( dialog, item) DialogPtr dialog; int item;
{
int type;
Handle handle;
GDHandle gh;
PixMapHandle pm;
Rect box;
RGBColor colour;
If (!(ROM85 & 0x4000)) { /* Mac II ROMs? */
/* Figure out screen depth of our dialog */
gh=GetMaxDevice(&((DialogPeek) dialog)-> window.port.portRect);
pm=(*gh)->gdPMap; /* Device’s PixMap */
if ((*pm)->pixelSize > 1) { /* Enough pixels */
/* Choose FindSwell’sgolden-brown */
colour.red=39921;
colour.green=26421;
colour.blue=0;
RGBForeColor(&colour); /* Set the color */
PenMode(max);
GetDItem( dialog, item, &type, & handle, &box);
PaintRect(&box); /* Colorize */
RGBForeColor(RGBBlack); /* default color */
PenNormal(); /* Restore default pen */
}
}
}
One disadvantage of this technique is that you can see the logo being drawn in
black, then painted in brown. The operation is pretty quick, though, and doesn’t
require much code.
What if you don’t want to color an entire picture? You can define a userItem, and
pass its item number to colorize. This lets you color any rectangular area. To color an
arbitrary shape, you can define a bitmap and use CopyMask (CopyMask is not available
with 64K ROMs, but we’re not colorizing in that situation). Icons are probably the
easiest bitmaps to work with. The routine below will plot the black bits of an icon in
the current color; white bits are unchanged.
/*
PAINT_ICON -- Draw transparent icon in current color
*/
void paint_icon(icon, box) Handle icon; Rect *box;
{
BitMap iconBits;
GrafPtr thePort;
GetPort(&thePort); /* Get current grafPort */
/* Set up the bit map */
iconBits.rowBytes=4;
SetRect(&iconBits.bounds, 0,0,32,32);
iconBits.baseAddr=(char *) (*icon);
/* Blit the icon */
CopyMask(&iconBits, &iconBits, &thePort->portBits,
&iconBits.bounds, &iconBits.bounds, box);
}
ModalDialog Filter Procs from MS FORTRAN
Jeff E. Mandel, MD MS
New Orleans, LA
When writing code in MS FORTRAN, it is occasionally necessary to have a pointer
to a piece of code to pass to a toolbox call -- a proc pointer. Absoft has provided a glue
routine called ctlprc to perform this function. Ctlprc has a limitation in that it does
not return anything on the stack, which is necessary for implementing a filter proc
for ModalDialog. An assembly language glue routine for this is described herein.
ModalDialog filter procs are called each time ModalDialog gets an event from
GetNextEvent (note that the event mask excludes disk insert and application events). It
passes a pointer to the FrontWindow, and two VARs; the EventRecord and the ItemHit.
Note that VARs are longword addresses to the data structures, which is exactly how
FORTRAN passes calling arguments. ModalDialog expects the filter proc to return a
Boolean result; True if ModalDialog should process the event, and False if the filter
proc has done so already. A Boolean result should be passed as a word on the stack
above the calling arguments, and this is where ModalDialog expects to find it.
FORTRAN passes calling arguments as long word addresses, and ctlprc restores the
stack on return from the called procedure. Function results are passed register D0,
and ctlprc trashes this register. Thus, we must write some assembly code to fix this if
we want to write our filter proc in FORTRAN. The following MDS code does just that.
XDEF xfilt
INCLUDE MacTraps.D
INCLUDE SysEqu.D
INCLUDE ToolEqu.D
INCLUDE QuickEqu.D
; Xfilt is the initialization code. It stores the
; address of the FORTRAN subroutine returned from
; ctlprc and returns a proc pointer which can be
; passed to ModalDialog.
xFilt:
MOVEM.L A0-A1,-(SP) ; Save registers
MOVE.L 16(SP),A0 ; calling FORTRAN passes ptr
LEA service,A1 ; to filter subroutine
MOVE.L (A0),(A1) ; which we store locally
LEA action,A0 ; glue procedure address is
MOVE.L 12(SP),A1 ; returned to FORTRAN on the
MOVE.L A0,(A1) ; stack
MOVEM.L (SP)+,A0-A1 ; Registers restored
; Action is the proc which gets called by ModalDialog.
; It massages the stack after FORTRAN finishes with it
; so that a Boolean result can be returned to
; ModalDialog.
action:
MOVEM.L A1/D0,-(SP) ; Save registers
PEA result ; Pass FORTRAN an address to
; store the BOOLEAN result
; Clone the stack