home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Info-Mac 3
/
Info_Mac_1994-01.iso
/
HyperCard
/
TIFFWindow1.1
/
TIFFWindow.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-12
|
28KB
|
1,234 lines
/*
* This software is copyright 1992 by Robert Morris.
* You may freely redistribute this software as shareware
* if you do so in the same form as you got it. If you find
* this software useful, please send $12 to:
* Robert Morris
* P.O. Box 1044
* Harvard Square Station
* Cambridge, MA 02238
* ecognome@aol.com
* If you incorporate any of this software in any kind of
* commercial product, please send $2 per copy distributed
* to the above address.
*/
/*
* TIFFWindow file, windowStyle, visible, depth, customPalette
*
* If no file is supplied, or if the file is "", TIFFWindow prompts the user.
* It uses hypercard's file search path.
*
* WindowStyle has no effect right now.
*
* Visible controls whether the window starts out visible.
*
* Depth sets the depth of the off-screen buffer; such a buffer greatly improves
* redraw and scroll speed. 0 means no buffer
* at all: all drawing is done from the disk. Only 0, 16 and 32 are universal; 1, 2, 4,
* and 8 only work well if the TIFF image is actually that depth.
* TIFFWindow will reduce the off-screen depth to the depth of the TIFF image.
* If there is not enough memory, it won't use an off-screen buffer.
*
* CustomPalette is true, a cpmt resource number, or false. The default is true,
* which causes TIFFWindow to call the Picture Utilities to compute a reasonable
* palette for the deepest CLUT screen at the time when TIFFWindow is called.
* A number indicates the resource number of a custom sampling method.
* False means use the color map in the TIFF file, or none if there was none.
* Computing a palette can take a few seconds. Custom palettes only work with
* an off-screen buffer.
*
* If the result is not empty, it contains an error message. TIFFWindow usually
* produces an error message if it doesn't understand the TIFF file format, but
* occasionally it doesn't find this out until too late, in which case it will
* display an empty window.
*
* The dithering property controls dithering. This only works well from an off-screen
* graphics buffer.
*
* The scrollbars property controls whether scrollbars are visible.
*
* The picturewidth and pictureheight properties yield the size of the image
* in pixels.
*
* The scale property, a number, controls zooming of the image. Each displayed
* pixel represents a square 2^scale pixels on a side in the original. So, for
* instance, a scale of 0 (the default) means no change, 1 means double the image
* size, and -1 means halve it.
*
* The picturedepth property yields the pixel depth of the TIFF image.
*
* If the user clicks on the picture, TIFFWindow sends to HyperTalk messages,
* one when the user presses the mouse button, and one when he or she releases
* the button. The messages are MouseDownInPicture and MouseUpInPicture. The
* messages have two arguments, the window name and the image coordinates.
*/
#include <HyperXCmd.h>
#include <stdlib.h>
#include "SetUpA4.h"
#include <string.h>
#include <ctype.h>
#include "tiffinfo.h"
#include <QDOffscreen.h>
#include <Palette.h>
#include <PictUtil.h>
typedef struct thunk{
TIFFPtr ti;
CGrafPtr gw; /* off-screen graphics world */
ControlHandle hScroll, vScroll;
int ref; /* keep the file open */
Boolean active;
/* properties */
Boolean visible;
Boolean scrollbars;
int depth; /* desired off-screen depth, or 0 for none */
double scale;
Boolean dither;
Boolean customPalette;
Boolean customMethod;
} ThunkRec, **Thunk;
Thunk th;
WindowPtr w;
XCmdPtr xptr;
#define SBWIDTH 15
void InitPalette(void);
void DisposeThunk(Thunk);
Handle HStr(char *);
int pstrcmp(StringPtr, StringPtr);
int SetUpWindow(StringPtr);
void UpdateWindow(void);
void DoContent(EventRecord *theEvent);
void MyGrowWindow(Point);
int cmp(char *, char *);
void FileOfPath(StringPtr path, StringPtr file);
OSErr CopyToGWorld();
int FixDepth(int depth);
Boolean SetProp(StringPtr prop, Handle h);
Handle GetProp(StringPtr prop);
int DeepestCLUTScreen();
long myatoi(char *);
Point MaxWindowSize();
void MySizeWindow(short width, short height);
double myatof(char *s);
double OldScaleToNew(int scale);
int NewScaleToOld(double scale);
void myftoa(double d, char *s);
void myitoa(long i, char *a);
/* there was no GetGWorldPixMap() before System 7 */
#define GWPM(gw) (HasSystem7() ? GetGWorldPixMap(gw) : (gw)->portPixMap)
pascal void
main(paramPtr)
XCmdPtr paramPtr;
{
XWEventInfoPtr ei;
WindowPtr whichWindow;
GrafPtr oport;
int theChar, err, ref, vref, findCode;
Point pt;
Rect r;
char **h;
StringPtr prop;
Str255 tmp, fullname, ttl;
PaletteHandle pltt;
Thunk oth;
WindowPtr ow;
XCmdPtr oxptr;
SFReply sf;
SFTypeList types;
OSType type;
CGrafPtr agw;
RememberA0();
SetUpA4();
/* save old values */
oth = th;
ow = w;
oxptr = xptr;
xptr = paramPtr;
if(paramPtr->paramCount == -1){
/* it's a window event */
ei = (XWEventInfoPtr) (paramPtr->params[0]);
w = ei->eventWindow;
th = (Thunk) GetWRefCon(w);
if(th == 0){
paramPtr->passFlag = TRUE;
goto out;
}
GetPort(&oport);
SetPort(w);
switch(ei->event.what){
case xOpenEvt:
XWAllowReEntrancy(paramPtr, w, TRUE, TRUE);
if((*th)->visible)
SelectWindow(w); /* if I don't do this, it's not highlighted... */
break;
case xCloseEvt:
XWAllowReEntrancy(paramPtr, w, FALSE, FALSE);
DisposeThunk(th);
SetWRefCon(w, 0L);
if(HasColorQD() && (pltt = GetPalette(w))){
SetPalette(w, 0L, FALSE);
DisposePalette(pltt);
}
paramPtr->passFlag = TRUE; /* yes, we're willing to close */
break;
case xCursorWithin:
paramPtr->passFlag = TRUE; /* ask HyperCard for an arrow cursor */
break;
case xSetPropEvt:
paramPtr->passFlag = !SetProp((StringPtr)ei->eventParams[0],
(Handle)ei->eventParams[1]);
break;
case xGetPropEvt:
h = GetProp((StringPtr) (ei->eventParams[0]));
if(h){
ei->eventResult = h;
paramPtr->passFlag = FALSE;
} else {
paramPtr->passFlag = TRUE; /* ask HyperCard to handle it for us */
ei->eventResult = (char **) 0;
}
break;
case xGiveUpEditEvt:
EndXWEdit(paramPtr, w);
break;
case xEditUndo:
/* what should I do here? */
break;
case xEditCut:
break;
case xEditCopy:
break;
case xEditPaste:
break;
case xEditClear:
break;
case nullEvent:
break;
case activateEvt:
if((*th)->scrollbars){
if (ei->event.modifiers & activeFlag) {
ShowControl((*th)->vScroll);
ShowControl((*th)->hScroll);
(*th)->active = TRUE;
} else {
HideControl((*th)->vScroll);
HideControl((*th)->hScroll);
(*th)->active = FALSE;
}
DrawGrowIcon(w);
}
break;
case mouseDown:
switch(findCode = FindWindow(ei->event.where, &whichWindow)){
case inGoAway:
if(TrackGoAway(w, ei->event.where)){
CloseXWindow(paramPtr, w); /* ask HyperCard to close us */
}
break;
case inDrag:
/*
* ask HyperCard to deal with moving the window. this is
* an undocumented feature as of B39.
*/
paramPtr->passFlag = TRUE;
break;
case inContent:
DoContent(&(ei->event));
break;
case inGrow:
MyGrowWindow(ei->event.where);
break;
case inZoomIn:
case inZoomOut:
if(TrackBox(w, ei->event.where, findCode) == TRUE){
ZoomWindow(w, findCode, TRUE);
FixScrollBars();
}
break;
}
break;
case keyDown:
case autoKey:
theChar = ei->event.message & charCodeMask;
if ((ei->event.modifiers & cmdKey) != 0){
} else {
}
break;
case updateEvt:
UpdateWindow();
break;
}
SetPort(oport);
} else {
th = (Thunk) NewHandle((long) sizeof(**th));
if(th == 0){
paramPtr->returnValue = HStr("out of memory");
goto out;
}
(*th)->ref = -1;
(*th)->ti = 0;
(*th)->gw = 0;
(*th)->hScroll = (*th)->vScroll = 0;
(*th)->active = FALSE;
(*th)->visible = TRUE;
(*th)->scrollbars = TRUE;
(*th)->depth = 32;
(*th)->dither = FALSE;
(*th)->scale = 1;
(*th)->customPalette = TRUE;
(*th)->customMethod = systemMethod;
if(paramPtr->paramCount > 2 && cmp(*(paramPtr->params[2]), "true") != 1)
(*th)->visible = FALSE;
if(paramPtr->paramCount > 3)
(*th)->depth = myatoi(*(paramPtr->params[3]));
if(paramPtr->paramCount > 4){
if(cmp(*(paramPtr->params[4]), "true")){
(*th)->customPalette = TRUE;
(*th)->customMethod = systemMethod;
} else if(cmp(*(paramPtr->params[4]), "false")){
(*th)->customPalette = FALSE;
} else {
(*th)->customPalette = TRUE;
(*th)->customMethod = myatoi(*(paramPtr->params[4]));
}
}
if(paramPtr->paramCount > 0 && (*(paramPtr->params[0]))[0] != '\0'){
strncpy((char *)tmp, *(paramPtr->params[0]), sizeof(tmp) - 1);
CtoPstr(tmp);
types[0] = 'TIFF';
type = 'TIFF';
if(GetFilePath(xptr, tmp, -1, types, TRUE, &type, fullname) != TRUE){
paramPtr->returnValue = HStr("cannot find file");
goto out;
}
err = FSOpen(fullname, 0, &ref);
FileOfPath(fullname, ttl);
} else {
pt.h = pt.v = 75;
types[0] = 'TIFF';
SFGetFile(pt, "\pWhat TIFF file?", 0L, 1, types, 0L, &sf);
if(sf.good == 0){
paramPtr->returnValue = HStr("cancel");
goto out;
}
err = FSOpen(sf.fName, sf.vRefNum, &ref);
FileOfPath(sf.fName, ttl);
}
if(err != 0){
DisposeThunk(th);
paramPtr->returnValue = HStr("cannot open file");
goto out;
}
(*th)->ref = ref;
(*th)->ti = ScanTIFF((*th)->ref);
if((*th)->ti == 0 || GetTIFFError((*th)->ti, tmp) != 0){
DisposeThunk(th);
paramPtr->returnValue = HStr("cannot understand TIFF file");
goto out;
}
if(TIFFDrawable((*th)->ti) == FALSE){
DisposeThunk(th);
paramPtr->returnValue = HStr("Cannot draw the picture on this Macintosh.");
goto out;
}
/* attempt to set up an off-screen copy */
if((*th)->depth > 0 && HasQD32()){
/* eliminate excess depth */
if((*th)->ti->samplesPerPixel == 1 &&
(*th)->ti->bitsPerSample[0] < (*th)->depth){
(*th)->depth = FixDepth((*th)->ti->bitsPerSample[0]);
}
r.left = 0;
r.right = (*th)->ti->imageWidth;
r.top = 0;
r.bottom = (*th)->ti->imageLength;
err = NewGWorld(&agw, (*th)->depth, &r, (*th)->ti->colorMap, 0L, 0);
if(err == 0){
(*th)->gw = agw;
if((err = CopyToGWorld()) != 0){
if(GetTIFFError((*th)->ti, tmp) != 0 && tmp[0] != 0)
paramPtr->returnValue = PasToZero(xptr, tmp);
else if(err == memFullErr)
paramPtr->returnValue = HStr("out of memory");
else
paramPtr->returnValue = HStr("could not understand TIFF file");
DisposeThunk(th);
goto out;
}
FSClose((*th)->ref);
(*th)->ref = -1;
}
}
if(SetUpWindow(ttl) < 0){
DisposeThunk(th);
paramPtr->returnValue = HStr("window creation failed");
goto out;
}
InitPalette();
}
out:
/* restore old globals in case of reentrance */
xptr = oxptr;
w = ow;
th = oth;
RestoreA4();
}
OSErr
CopyToGWorld()
{
CGrafPtr oldPort;
GDHandle oldGD;
PixMapHandle pm;
OSErr err;
Rect r;
GetGWorld(&oldPort, &oldGD);
SetGWorld((*th)->gw, 0);
pm = GWPM((*th)->gw);
if(LockPixels(pm) != TRUE){
SetGWorld(oldPort, oldGD);
return(memFullErr);
}
r = (*th)->gw->portRect;
err = DrawTIFF((*th)->ref, (*th)->ti, r, r, 0);
UnlockPixels(pm);
SetGWorld(oldPort, oldGD);
return(err);
}
void
DisposeThunk(Thunk th)
{
if(th){
if((*th)->ti)
DisposeTIFF((*th)->ti);
(*th)->ti = 0;
if((*th)->ref != -1)
FSClose((*th)->ref);
(*th)->ref = -1;
if((*th)->gw)
DisposeGWorld((*th)->gw);
(*th)->gw = 0;
DisposHandle(th);
}
}
/*
* returns < 0 if there was a problem.
*/
int
SetUpWindow(StringPtr ttl)
{
Rect wr, sr, r;
GDHandle gd;
int iheight, iwidth, wwidth, wheight;
GrafPtr wmport;
/*
* Choose a window size: try to show the whole image, but stay on
* the screen.
*/
if(HasColorQD()){
gd = GetMainDevice();
sr = (*gd)->gdRect;
} else {
GetWMgrPort(&wmport);
sr = wmport->portRect;
}
iwidth = (*th)->ti->imageWidth;
iheight = (*th)->ti->imageLength;
#define MIN(a, b) ((a) < (b) ? (a) : (b))
wwidth = MIN(iwidth+SBWIDTH, sr.right - sr.left - 40);
wheight = MIN(iheight+SBWIDTH, sr.bottom - sr.top - 70);
wr.left = ((sr.right - sr.left) / 2) - (wwidth / 2);
wr.right = wr.left + wwidth;
wr.top = ((sr.bottom - sr.top - 30) / 2) - (wheight / 2) + 30;
wr.bottom = wr.top + wheight;
w = NewXWindow(xptr,
&wr,
ttl, /* title */
(*th)->visible,
documentProc,
HasColorQD(), /* color? */
FALSE); /* floating? */
if(w == 0)
return(-1);
SetWRefCon(w, (long)th);
r.right = wr.right;
r.left = r.right - SBWIDTH;
r.top = wr.top;
r.bottom = wr.bottom;
(*th)->vScroll = NewControl(w, &r, "", TRUE, 0, 0, 1, scrollBarProc, 0L);
r.left = wr.left;
r.right = wr.right;
r.bottom = wr.bottom;
r.top = r.bottom - SBWIDTH;
(*th)->hScroll = NewControl(w, &r, "", TRUE, 0, 0, 1, scrollBarProc, 0L);
FixScrollBars();
return(0);
}
/*
* the window has changed size, and the scroll bars will have to be
* resized, and their max and min values re-set.
*/
FixScrollBars()
{
Rect wr, r;
int oh, ov, iheight, iwidth, wheight, wwidth;
wr = w->portRect;
iheight = (*th)->ti->imageLength;
iwidth = (*th)->ti->imageWidth;
HideControl((*th)->vScroll);
HideControl((*th)->hScroll);
oh = GetCtlValue((*th)->hScroll);
ov = GetCtlValue((*th)->vScroll);
#define MAX(a, b) ((a) > (b) ? (a) : (b))
wheight = UnScaleIt(wr.bottom - wr.top - ((*th)->scrollbars ? SBWIDTH : 0));
SetCtlMin((*th)->vScroll, 0);
SetCtlMax((*th)->vScroll, MAX(0, iheight - wheight));
wwidth = UnScaleIt(wr.right - wr.left - ((*th)->scrollbars ? SBWIDTH : 0));
SetCtlMin((*th)->hScroll, 0);
SetCtlMax((*th)->hScroll, MAX(0, iwidth - wwidth));
if(oh != GetCtlValue((*th)->hScroll) || ov != GetCtlValue((*th)->vScroll)){
InvalRect(&(w->portRect));
}
MoveControl((*th)->vScroll, wr.right - SBWIDTH, wr.top - 1);
SizeControl((*th)->vScroll, SBWIDTH+1, wr.bottom - wr.top - SBWIDTH + 2);
MoveControl((*th)->hScroll, wr.left - 1, wr.bottom - SBWIDTH);
SizeControl((*th)->hScroll, wr.right - wr.left - SBWIDTH + 2, SBWIDTH+1);
if((*th)->scrollbars){
if((*th)->active){
ShowControl((*th)->vScroll);
ShowControl((*th)->hScroll);
DrawGrowIcon(w);
}
}
}
int
UnScaleIt(x)
int x;
{
return(x / (*th)->scale);
}
int
ScaleIt(x)
int x;
{
return(x * (*th)->scale);
}
double
OldScaleToNew(int scale)
{
double x;
int i;
x = 1;
/* calculate how to scale the picture */
if(scale > 0){
for(i = 0; i < scale; i++)
x *= 2;
} else if(scale < 0){
for(i = 0; i > scale; --i)
x /= 2;
}
return(x);
}
int
NewScaleToOld(double scale)
{
long i, x, sign;
if(scale <= 0.0)
return(0);
if(scale < 1.0){
scale = 1 / scale;
sign = -1;
} else
sign = 1;
x = 1;
for(i = 0; x < scale && i < 32; i++, x *= 2)
;
return(i * sign);
}
void
UpdateWindow()
{
BeginUpdate( w );
DrawControls( w );
if((*th)->scrollbars)
DrawGrowIcon( w );
ReDraw();
EndUpdate( w );
}
ReDraw()
{
Rect ir, dr, gr;
int xoff, yoff, dh, dv;
PixMapHandle pm;
xoff = GetCtlValue((*th)->hScroll);
yoff = GetCtlValue((*th)->vScroll);
ir.left = xoff;
ir.top = yoff;
ir.right = (*th)->ti->imageWidth;
ir.bottom = (*th)->ti->imageLength;
dr = w->portRect;
dr.right = dr.left + ScaleIt(ir.right - ir.left);
dr.bottom = dr.top + ScaleIt(ir.bottom - ir.top);
dh = dr.right - (w->portRect.right - ((*th)->scrollbars ? SBWIDTH : 0));
if(dh > 0){
dr.right -= dh;
ir.right -= UnScaleIt(dh);
}
dv = dr.bottom - (w->portRect.bottom - ((*th)->scrollbars ? SBWIDTH : 0));
if(dv > 0){
dr.bottom -= dv;
ir.bottom -= UnScaleIt(dv);
}
if((*th)->gw){
pm = GWPM((*th)->gw);
LockPixels(pm);
CopyBits(*pm, &(w->portBits), &ir, &dr,
(*th)->dither ? 64 : srcCopy, 0L);
UnlockPixels(pm);
} else if((*th)->ref != -1){
DrawTIFF((*th)->ref, (*th)->ti, ir, dr, (*th)->dither);
}
/* now gray out invalid parts of the window */
gr.left = dr.right;
gr.right = w->portRect.right - ((*th)->scrollbars ? SBWIDTH : 0);
gr.top = 0;
gr.bottom = w->portRect.bottom - ((*th)->scrollbars ? SBWIDTH : 0);
FillRect(&gr, &gray);
gr.left = 0;
gr.top = dr.bottom;
FillRect(&gr, &gray);
}
/*
* Give the window an appropriate palette. Such a palette should have a separate
* set of colors for each different depth CLUT device the window intersects.
* This is possible using inhibited entries, but would be expensive since it
* would require multiple calls to GetPixMapInfo(). And the palette might have
* to be recomputed whenever the user moves the window onto a different screen
* or changes the depth with the Monitors control panel.
*
* It would be nice if the color sampling methods used by GetPixMapInfo() returned
* a palette with the most important colors first, or with multiple sets of
* inhibited colors; such a palette would be useful at multiple depths.
*
* This routine computes a palette for the deepest CLUT device existing at the
* time the TIFF window was created. This isn't perfect; the user might put
* the window on a shallower screen, or change the depth.
*
* InitPalette the color map in the TIFF file if it can. Otherwise it uses the
* Picture Utilities. The sampling method cpmt resource number can be set with
* the 5th argument to TIFFWindow.
*/
void
InitPalette()
{
CTabHandle cth;
PaletteHandle pltt = 0, opltt;
PictInfo pi;
PixMapHandle pm;
OSErr err;
int deepest, size;
if(HasColorQD() == 0)
return;
deepest = DeepestCLUTScreen();
size = DepthToSize(deepest);
/*
* Don't bother if there are no color CLUT screens.
*/
if(deepest <= 1)
return;
if((cth = (*th)->ti->colorMap) && ((*cth)->ctSize+1) <= size){
/*
* Use the color map in the TIFF file if it isn't too large.
*/
pltt = NewPalette((*cth)->ctSize + 1, cth, pmTolerant, 0);
} else if(((*th)->ti->samplesPerPixel > 1 || (*th)->ti->bitsPerSample[0] > 1) &&
(*th)->customPalette && (*th)->gw && HasSystem7()){
pm = GWPM((*th)->gw);
if(LockPixels(pm) == TRUE){
err = GetPixMapInfo(pm, &pi, returnPalette|suppressBlackAndWhite,
size - 2, (*th)->customMethod, 0);
if(err == 0){
pltt = pi.thePalette;
pi.thePalette = 0;
}
UnlockPixels(pm);
}
}
if(pltt)
SetPalette(w, pltt, TRUE);
}
/*
* Return the depth of the deepest CLUT screen, or zero if there are no
* CLUT screens.
*/
int
DeepestCLUTScreen()
{
GDHandle gd;
int depth = 0;
PixMapHandle pm;
gd = GetDeviceList();
while(gd){
if(TestDeviceAttribute(gd, screenDevice) == TRUE &&
TestDeviceAttribute(gd, screenActive) == TRUE &&
(*gd)->gdType == 0){
pm = (*gd)->gdPMap;
if(pm && (*pm)->cmpCount == 1 && (*pm)->cmpSize > depth)
depth = (*pm)->cmpSize;
}
gd = GetNextDevice(gd);
}
return(depth);
}
int
DepthToSize(int depth)
{
switch(depth){
case 1: return(2);
case 2: return(4);
case 4: return(16);
default: return(256);
}
}
pascal void
TrackIt(ctl, part)
ControlHandle ctl;
int part;
{
int amount, pagesize;
if(ctl == (*th)->hScroll)
pagesize = UnScaleIt((w->portRect.right - w->portRect.left) / 2);
else
pagesize = UnScaleIt((w->portRect.bottom - w->portRect.top) / 2);
switch (part){
case inUpButton:
amount = -4;
break;
case inDownButton:
amount = 4;
break;
case inPageUp:
amount = -pagesize;
break;
case inPageDown:
amount = pagesize;
break;
default:
return;
}
SetCtlValue(ctl, GetCtlValue(ctl) + amount);
ReDraw();
}
void
DoContent(EventRecord *theEvent)
{
Point pt;
ControlHandle ctl;
int part, x, y;
char tmp[256], ttl[256], tmp1[64];
if (w != FrontDocWindow(xptr)){
SelectWindow(w);
return;
}
pt = theEvent->where;
GlobalToLocal(&pt);
part = FindControl(pt, w, &ctl);
if(part == inThumb){
part = TrackControl(ctl, pt, 0L);
if(part)
ReDraw();
} else if(part != 0){
part = TrackControl(ctl, pt, TrackIt);
} else {
x = UnScaleIt(pt.h - w->portRect.left) + GetCtlValue((*th)->hScroll);
y = UnScaleIt(pt.v - w->portRect.top) + GetCtlValue((*th)->vScroll);
GetWTitle(w, ttl);
PtoCstr(ttl);
strcpy(tmp, "mouseDownInPicture \"");
strcat(tmp, ttl);
strcat(tmp, "\", \"");
myitoa(x, tmp1);
strcat(tmp, tmp1);
strcat(tmp, ",");
myitoa(y, tmp1);
strcat(tmp, tmp1);
strcat(tmp, "\"");
CtoPstr(tmp);
SendCardMessage(xptr, (StringPtr)tmp);
while(StillDown() == TRUE)
;
GetMouse(&pt);
x = UnScaleIt(pt.h - w->portRect.left) + GetCtlValue((*th)->hScroll);
y = UnScaleIt(pt.v - w->portRect.top) + GetCtlValue((*th)->vScroll);
strcpy(tmp, "mouseUpInPicture \"");
strcat(tmp, ttl);
strcat(tmp, "\", \"");
myitoa(x, tmp1);
strcat(tmp, tmp1);
strcat(tmp, ",");
myitoa(y, tmp1);
strcat(tmp, tmp1);
strcat(tmp, "\"");
CtoPstr(tmp);
SendCardMessage(xptr, (StringPtr)tmp);
}
}
Point
MaxWindowSize()
{
Point pt;
int iwidth, iheight;
iwidth = (*th)->ti->imageWidth;
iheight = (*th)->ti->imageLength;
pt.h = ScaleIt(iwidth) +
((*th)->scrollbars ? SBWIDTH : 0);
pt.v = ScaleIt(iheight) +
((*th)->scrollbars ? SBWIDTH : 0);
return(pt);
}
void
MyGrowWindow(p)
Point p;
{
long theResult;
Rect r;
Point max;
max = MaxWindowSize();
SetRect(&r, 80, 80, max.h + 1, max.v + 1);
theResult = GrowWindow( w, p, &r );
if (theResult == 0)
return;
MySizeWindow(LoWord(theResult), HiWord(theResult));
}
/*
* change the size of the window, making sure it's not bigger than the
* displayed image, and making sure the old grow box is destroyed.
*/
void
MySizeWindow(short width, short height)
{
Point max;
Rect r;
max = MaxWindowSize();
if(width > max.h)
width = max.h;
if(height > max.v)
height = max.v;
if((*th)->scrollbars){
/* we want to make sure the old grow box is redrawn */
r = w->portRect;
r.left = r.right - SBWIDTH;
r.top = r.bottom - SBWIDTH;
InvalRect(&r);
EraseRect(&r);
}
SizeWindow( w, width, height, TRUE);
FixScrollBars();
}
/* case-insensitive pascal string compare */
int
pstrcmp(StringPtr a, StringPtr b)
{
int alen, blen;
if(EqualString(a, b, FALSE, FALSE) == TRUE)
return(0);
return(1);
}
/* case-insensitive C string compare; returns 1 if equal */
int
cmp(char *a, char *b)
{
int i, ac, bc;
for(i = 0; a[i] && b[i]; i++){
ac = a[i];
if(isupper(ac))
ac = tolower(ac);
bc = b[i];
if(isupper(bc))
bc = tolower(bc);
if(ac != bc)
return(0);
}
if(a[i] == b[i])
return(1);
return(0);
}
Handle
HStr(str)
char *str;
{
Handle newHndl;
newHndl = (Handle) NewHandle((long) strlen(str) + 1);
if(newHndl == 0)
return(0);
strcpy((char *) (*newHndl), str);
return(newHndl);
}
void
FileOfPath(StringPtr path, StringPtr file)
{
int i, len;
/* search backwards for the last : */
for(i = path[0] - 1; i >= 0; --i){
if(path[i+1] == ':'){
len = path[0] - i - 1;
strncpy((char *) file+1, (char *)path + i + 2, len);
file[0] = len;
return;
}
}
strncpy((char *)file+1, (char *)path+1, path[0]);
file[0] = path[0];
}
/*
* Take whatever depth the user provided and round it up to the nearest
* legal QuickDraw depth.
*/
int
FixDepth(int depth)
{
if(depth < 1)
return(0);
if(depth <= 1)
return(1);
if(depth <= 2)
return(2);
if(depth <= 4)
return(4);
if(depth <= 8)
return(8);
if(depth <= 16)
return(16);
return(32);
}
/*
* Returns TRUE if it could handle the property.
*/
Boolean
SetProp(StringPtr prop, Handle h)
{
Boolean handled = TRUE;
Rect r;
Point pt;
Str255 tmp;
int ndither;
double nscale;
Handle lh;
MoveHHi(h);
HLock(h);
if(pstrcmp(prop, "\pdithering") == 0){
ndither = cmp(*h, "true");
if(HasQD32() == 0)
ndither = FALSE;
if(ndither != (*th)->dither){
(*th)->dither = ndither;
ReDraw();
}
} else if(pstrcmp(prop, "\pscrollbars") == 0){
int nscrollbars = cmp(*h, "true");
if((*th)->scrollbars != nscrollbars){
(*th)->scrollbars = nscrollbars;
r = w->portRect;
if(nscrollbars == TRUE){
/* make room for them */
SizeWindow(w, r.right - r.left + SBWIDTH,
r.bottom - r.top + SBWIDTH, TRUE);
} else {
/* get rid of them */
SizeWindow(w, r.right - r.left - SBWIDTH,
r.bottom - r.top - SBWIDTH, TRUE);
}
FixScrollBars();
}
} else if(pstrcmp(prop, "\pscale") == 0){
nscale = OldScaleToNew(myatoi(*h));
if(nscale != (*th)->scale){
(*th)->scale = nscale;
FixScrollBars();
ReDraw();
}
} else if(pstrcmp(prop, "\pnscale") == 0){
nscale = myatof(*h);
if(nscale != (*th)->scale && nscale > 0.001){
(*th)->scale = nscale;
FixScrollBars();
ReDraw();
}
} else if(pstrcmp(prop, "\pscroll") == 0){
ZeroToPas(xptr, *h, tmp);
StrToPoint(xptr, tmp, &pt);
SetCtlValue((*th)->hScroll, pt.h);
SetCtlValue((*th)->vScroll, pt.v);
ReDraw();
} else if(pstrcmp(prop, "\prect") == 0 || pstrcmp(prop, "\prectangle") == 0){
ZeroToPas(xptr, *h, tmp);
StrToRect(xptr, tmp, &r);
lh = EvalExpr(xptr, "\pthe loc of the card window");
ZeroToPas(xptr, *lh, tmp);
StrToPoint(xptr, tmp, &pt);
DisposHandle(h);
OffsetRect(&r, pt.h, pt.v);
MoveWindow(w, r.left, r.top, FALSE);
MySizeWindow(r.right - r.left, r.bottom - r.top);
} else if(pstrcmp(prop, "\pglobalrect") == 0){
ZeroToPas(xptr, *h, tmp);
StrToRect(xptr, tmp, &r);
MoveWindow(w, r.left, r.top, FALSE);
MySizeWindow(r.right - r.left, r.bottom - r.top);
} else if(pstrcmp(prop, "\pgloballoc") == 0){
ZeroToPas(xptr, *h, tmp);
StrToPoint(xptr, tmp, &pt);
MoveWindow(w, pt.h, pt.v, FALSE);
} else
handled = FALSE;
HUnlock(h);
return(handled);
}
Handle
GetProp(StringPtr prop)
{
Handle h = 0;
Point pt;
Rect r;
Str255 tmp;
/* hypercard deals with loc and visible */
if(pstrcmp(prop, "\pdithering") == 0){
h = HStr((*th)->dither ? "true" : "false");
} else if(pstrcmp(prop, "\pscrollbars") == 0){
h = HStr((*th)->scrollbars ? "true" : "false");
} else if(pstrcmp(prop, "\pglobalrect") == 0){
pt.h = w->portRect.left;
pt.v = w->portRect.top;
LocalToGlobal(&pt);
r.left = pt.h;
r.top = pt.v;
r.right = r.left + (w->portRect.right - w->portRect.left);
r.bottom = r.top + (w->portRect.bottom - w->portRect.top);
RectToStr(xptr, &r, tmp);
h = PasToZero(xptr, tmp);
} else if(pstrcmp(prop, "\pgloballoc") == 0){
pt.h = w->portRect.left;
pt.v = w->portRect.top;
LocalToGlobal(&pt);
PointToStr(xptr, pt, tmp);
h = PasToZero(xptr, tmp);
} else if(pstrcmp(prop, "\pscroll") == 0){
pt.h = GetCtlValue((*th)->hScroll);
pt.v = GetCtlValue((*th)->vScroll);
PointToStr(xptr, pt, tmp);
h = PasToZero(xptr, tmp);
} else if(pstrcmp(prop, "\ppicturewidth") == 0){
NumToString((long) (*th)->ti->imageWidth, tmp);
h = PasToZero(xptr, tmp);
} else if(pstrcmp(prop, "\ppictureheight") == 0){
NumToString((long) (*th)->ti->imageLength, tmp);
h = PasToZero(xptr, tmp);
} else if(pstrcmp(prop, "\pscale") == 0){
NumToString((long) NewScaleToOld((*th)->scale), tmp);
h = PasToZero(xptr, tmp);
} else if(pstrcmp(prop, "\pnscale") == 0){
myftoa((*th)->scale, (char *)tmp);
CtoPstr(tmp);
h = PasToZero(xptr, tmp);
} else if(pstrcmp(prop, "\ppicturedepth") == 0){
NumToString((long)(*th)->ti->samplesPerPixel * (*th)->ti->bitsPerSample[0], tmp);
h = PasToZero(xptr, tmp);
}
return(h);
}
long
myatoi(char *s)
{
long l;
char tmp[256];
strncpy(tmp, s, sizeof(tmp)-1);
CtoPstr(tmp);
StringToNum(tmp, &l);
return(l);
}
double
myatof(char *s)
{
double d, denom;
d = 0;
while(isdigit(*s)){
d *= 10;
d += *s - '0';
s++;
}
if(*s == '.'){
s++;
denom = 10;
while(isdigit(*s)){
d += (*s - '0') / denom;
s++;
denom *= 10;
}
}
return(d);
}
/* only two digits after the decimal point */
void
myftoa(double d, char *s)
{
char f[256];
myitoa((long) d, s);
d -= (long) d;
myitoa((long) (d * 100), f);
strcat(s, ".");
if(strlen(f) == 1)
strcat(s, "0");
strcat(s, f);
}
void
myitoa(long i, char *a)
{
NumToString(i, a);
PtoCstr(a);
}