/*********************************************************/ /* This source code copyright (c) 1991-2001, Aaron Giles */ /* See the Read Me file for licensing information. */ /* Contact email: mac@aarongiles.com */ /*********************************************************/ #if THINK_C #include "THINK.Header" #elif applec #pragma load ":Headers:MPW.Header" #elif __MWERKS__ //#include "MW.Header" #else #include "JPEGView.h" #endif static void HandleUpdateError(ImageHandle theImage, OSErr theErr); static void DoDragSelection(ImageHandle theImage, EventRecord *theEvent); static pascal OSErr SendItemData(FlavorType theType, void *dragSendRefCon, ItemReference theItem, DragReference theDrag); extern void DeferImageUpdate(ImageHandle theImage) { Pattern whitePat = { 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00 }; Pattern blackPat = { 0xff, 0xfd, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff }; RgnHandle theRgn; Rect theRect; PushPort(); MySetPort((CGrafPtr)(*theImage)->window); InvalRgn((*theImage)->update); BeginUpdate((*theImage)->window); PenNormal(); RGBForeColor(&gBlack); RGBBackColor(&gWhite); theRect = (*theImage)->wrect; if (theRgn = NewRgn()) { RectRgn(theRgn, &theRect); if (gDrawing && theImage == gDrawing) DiffRgn(theRgn, (*theImage)->update, theRgn); SetClip(theRgn); DisposeRgn(theRgn); } else ClipRect(&theRect); HideAnts((*theImage)->ants); FillRgn((*theImage)->window->visRgn, NeedsWhiteBG(theImage) ? &whitePat : &blackPat); ShowAnts((*theImage)->ants); ClipRect(&(*theImage)->window->portRect); UnionRgn((*theImage)->update, (*theImage)->window->visRgn, (*theImage)->update); EndUpdate((*theImage)->window); (*theImage)->flags &= ~ifAborted; PopPort(); } extern OSErr UpdateImage(ImageHandle theImage) { Point thePoint = { 0, 0 }; OSErr theErr = noErr; RgnHandle oldVisRgn; StartSpinning(); PushPort(); MySetPort((CGrafPtr)(*theImage)->window); if (oldVisRgn = NewRgn()) CopyRgn((*theImage)->window->visRgn, oldVisRgn); ClipRect(&(*theImage)->window->portRect); InvalRgn((*theImage)->update); BeginUpdate((*theImage)->window); SetClip((*theImage)->window->visRgn); EndUpdate((*theImage)->window); CopyRgn((*theImage)->window->clipRgn, (*theImage)->window->visRgn); GetMinMaxMonitor(theImage); gIntError = 0; if (!EmptyRgn(oldVisRgn)) { HideAnts((*theImage)->ants); theErr = DrawImage(theImage, bfOnscreen, nil); ShowAnts((*theImage)->ants); } CalcVis((WindowPeek)(*theImage)->window); if (IsAboutBox(theImage)) { Rect theRect = (*theImage)->wrect; FontInfo theFontInfo; Str63 theText; TextFont(geneva); TextSize(9); TextMode(srcOr); ClipRect(&theRect); GetFontInfo(&theFontInfo); #if defined(powerc) || defined(__powerc) BlockMove(gString[strVersionPPC], theText, *gString[strVersionPPC] + 1); #else BlockMove(gString[strVersion68k], theText, *gString[strVersion68k] + 1); #endif StuffNumber(theText, 1, (kVersion >> 8) & 0xf); StuffNumber(theText, 2, (kVersion >> 4) & 0xf); MoveTo((*theImage)->wrect.right - StringWidth(theText) - 3, (*theImage)->wrect.top + theFontInfo.ascent + theFontInfo.leading + 3); DrawString(theText); } if (oldVisRgn && EqualRgn(oldVisRgn, (*theImage)->window->visRgn) && !Aborted(theImage)) { SetEmptyRgn((*theImage)->update); DisposeRgn(oldVisRgn); } if (theErr) HandleUpdateError(theImage, theErr); SetStatistics(); PopPort(); StopSpinning(&qd.arrow); return theErr; } static void HandleUpdateError(ImageHandle theImage, OSErr theErr) { if ((theErr == codecBadDataErr) || (gIntError == errCorruptImage)) { if (Corrupt(theImage)) return; (*theImage)->flags |= ifCorrupt; } HandleAEError(theErr, errNoDrawMemory, theImage ? FileName(theImage) : nil); if (theErr == memFullErr) DoCloseWindow((*theImage)->window, gThePrefs.restoreColors); } extern void HandleImageActivate(ImageHandle theImage, Boolean nowActive) { if (theImage) { if (nowActive) ActivateAnts((*theImage)->ants); else DeactivateAnts((*theImage)->ants); } } extern void HandleImageClick(ImageHandle theImage, EventRecord *theEvent) { Boolean inFront = (!gInBackground && (*theImage)->window == FWFrontWindow()); Rect theRect = { 0, 0, 0, 0 }, selRect; Point where = theEvent->where; GetAntsSelection((*theImage)->ants, &selRect); PushPort(); MySetPort((CGrafPtr)(*theImage)->window); // hidden feature: cmd-click forces redraw of window if (theEvent->modifiers & cmdKey) { KillGWorld(theImage); theRect = (*theImage)->wrect; InvalRect(&theRect); inFront = true; goto done; } // check to see if we're even inside the drawing area of the window GlobalToLocal(&where); if (!gSlideShow && !IsAboutBox(theImage) && PtInRect(where, &(*theImage)->wrect)) { // if we're in the size box area, resize the window if (inFront && (((*theImage)->wrect.right - where.h) < 16) && (((*theImage)->wrect.bottom - where.v) < 16)) { Boolean modified = (theEvent->modifiers & (optionKey + cmdKey + shiftKey)) != 0; if (TrackGrowWindow(where, theImage, !modified, &theRect)) { SendSetDrawBounds((*theImage)->window, &theRect); goto done; } } else if (!Full(theImage) || (*theImage)->dmon != gMainMonitor || !gMenuVisible) { // if we're selected, either drag or cancel the selection if (AntsHaveSelection((*theImage)->ants)) { if (PtInRect(where, &selRect) && !EqualRect(&selRect, &(*theImage)->wrect)) { if ((inFront && TrackDragRect(where, theImage) && gDragMgrPresent) || (!inFront && gDragMgrPresent && WaitMouseMoved(theEvent->where))) { DoDragSelection(theImage, theEvent); inFront = true; } GetAntsSelection((*theImage)->ants, &theRect); SendSetSelection(theImage, &theRect); goto done; } } // if we fall through here, we need to track a new selection if (inFront) { SendSetSelection(theImage, &theRect); TrackAntsSelection((*theImage)->ants, where); GetAntsSelection((*theImage)->ants, &theRect); SendSetSelection(theImage, &theRect); if (AntsHaveSelection((*theImage)->ants)) goto done; } // special case: if full screen image overlapped by menubar, treat as window in background } else if (AntsHaveSelection((*theImage)->ants) && PtInRect(where, &selRect) && gDragMgrPresent && WaitMouseMoved(theEvent->where)) { DoDragSelection(theImage, theEvent); inFront = true; } } // if we fall all the way through here, we need to flip the menu bar AdjustMenus(); if (Full(theImage) && (*theImage)->dmon == gMainMonitor && gSlideShow != kPaused) { if (gMenuVisible) { RehideMenuBar(); ActivateAnts((*theImage)->ants); } else { DeactivateAnts((*theImage)->ants); UnhideMenuBar(); } } done: if (!inFront) ChangeActive((*theImage)->window); AdjustMenus(); PopPort(); } static void DoDragSelection(ImageHandle theImage, EventRecord *theEvent) { static DragSendDataProc gSendItemData = nil; RgnHandle theRgn = NewRgn(), tempRgn = NewRgn(); DragReference theDrag; Rect startRect; OSErr theErr; GetAntsSelection((*theImage)->ants, &startRect); if (!gSendItemData) gSendItemData = NewDragSendDataProc((ProcPtr)SendItemData); if (theRgn && tempRgn) { theErr = NewDrag(&theDrag); if (theErr == noErr) { AddDragItemFlavor(theDrag, (ItemReference)theImage, 'PICT', nil, 0, 0); GlobalRect(&startRect, (*theImage)->window); RectRgn(theRgn, &startRect); RectRgn(tempRgn, &startRect); InsetRgn(tempRgn, 1, 1); DiffRgn(theRgn, tempRgn, theRgn); SetDragItemBounds(theDrag, (ItemReference)theImage, &(*theRgn)->rgnBBox); SetDragSendProc(theDrag, gSendItemData, nil); SetCursor(&qd.arrow); theErr = TrackDrag(theDrag, theEvent, theRgn); DisposeDrag(theDrag); } } if (theRgn) DisposeRgn(theRgn); if (tempRgn) DisposeRgn(tempRgn); } static pascal OSErr SendItemData(FlavorType theType, void *dragSendRefCon, ItemReference theItem, DragReference theDrag) { #if applec #pragma unused(dragSendRefCon) #endif Boolean dontDispose = false; PicHandle thePicture; OSErr theErr; switch (theType) { case 'PICT': theErr = GetSelectedPICT((ImageHandle)theItem, &thePicture); if (theErr == noErr) { if (!thePicture) { thePicture = (PicHandle)(*(ImageHandle)theItem)->data; dontDispose = true; } HLock((Handle)thePicture); theErr = SetDragItemFlavorData(theDrag, theItem, 'PICT', *thePicture, GetHandleSize((Handle)thePicture), 0); if (!dontDispose) DisposeHandle((Handle)thePicture); } break; default: theErr = badDragFlavorErr; break; } return theErr; } /* * NewImage() * * Purpose: Adds a new image to the linked list * Inputs: none * Returns: a pointer to the new image * */ ImageHandle NewImage(void) { ImageHandle theImage; if (gImageRoot) { theImage = LastImage(); theImage = (*theImage)->next = (ImageHandle)NewHandleClear(sizeof(ImageItem)); } else theImage = gImageRoot = (ImageHandle)NewHandleClear(sizeof(ImageItem)); (*theImage)->id = kImageID; (*theImage)->update = NewRgn(); (*theImage)->ants = NewAnts(); return theImage; } /* * DisposeImage(theImage) * * Purpose: Removes the given image from the linked list * Inputs: theImage = the image record to be removed * Returns: nothing * */ void DisposeImage(ImageHandle theImage) { Boolean foundData = false, foundGWorld = false; ImageHandle tempImage; PushPort(); MySetPort(nil); (*theImage)->id = 0; for (tempImage = gImageRoot; tempImage; tempImage = (*tempImage)->next) if (tempImage != theImage) { if ((*tempImage)->data == (*theImage)->data) foundData = true; if ((*tempImage)->gworld == (*theImage)->gworld) foundGWorld = true; } if (!foundData && (*theImage)->data) DisposeHandle((*theImage)->data); if (!foundGWorld) KillGWorld(theImage); if ((*theImage)->ipalette) DisposePalette((*theImage)->ipalette); if ((*theImage)->qpalette) DisposePalette((*theImage)->qpalette); if ((*theImage)->palette) DisposePalette((*theImage)->palette); if ((*theImage)->comments) DisposeHandle((*theImage)->comments); if ((*theImage)->window) { FWCloseWindow((*theImage)->window); DeallocateWindow((*theImage)->window); } if ((*theImage)->update) DisposeRgn((*theImage)->update); if ((*theImage)->format && (*theImage)->format->close) (*theImage)->format->close(theImage); if ((*theImage)->privateData) DisposeHandle((*theImage)->privateData); if (theImage != gImageRoot) (*PreviousImage(theImage))->next = (*theImage)->next; else gImageRoot = (*gImageRoot)->next; if ((*theImage)->ants) DisposeAnts((*theImage)->ants); DisposeHandle((Handle)theImage); PopPort(); } /* * CopyImage(theImage) * * Purpose: Makes a copy of the given image * Inputs: theImage = the image record to be copied * Returns: a pointer to a new copy of the image * */ ImageHandle CopyImage(ImageHandle srcImage) { ImageHandle dstImage, theImage; PaletteHandle newPalette; AntsReference oldAnts; RgnHandle oldUpdate; Handle tmpHandle; if (dstImage = NewImage()) { oldUpdate = (*dstImage)->update; oldAnts = (*dstImage)->ants; BlockMove(*srcImage, *dstImage, sizeof(ImageItem)); (*dstImage)->update = oldUpdate; (*dstImage)->ants = oldAnts; (*dstImage)->next = nil; (*dstImage)->window = nil; if ((*srcImage)->palette) { newPalette = NewPalette((*(*srcImage)->palette)->pmEntries, nil, pmTolerant, 0); if (newPalette) { CopyPalette((*srcImage)->palette, newPalette, 0, 0, (*(*srcImage)->palette)->pmEntries); (*dstImage)->palette = newPalette; } } if ((*srcImage)->qpalette) { newPalette = NewPalette((*(*srcImage)->qpalette)->pmEntries, nil, pmTolerant, 0); if (newPalette) { CopyPalette((*srcImage)->qpalette, newPalette, 0, 0, (*(*srcImage)->qpalette)->pmEntries); (*dstImage)->qpalette = newPalette; } } if ((*srcImage)->ipalette) { newPalette = NewPalette((*(*srcImage)->ipalette)->pmEntries, nil, pmTolerant, 0); if (newPalette) { CopyPalette((*srcImage)->ipalette, newPalette, 0, 0, (*(*srcImage)->ipalette)->pmEntries); (*dstImage)->ipalette = newPalette; } } tmpHandle = (*dstImage)->comments; if (tmpHandle) { HandToHand(&tmpHandle); (*dstImage)->comments = tmpHandle; } tmpHandle = (*dstImage)->privateData; if (tmpHandle) { HandToHand(&tmpHandle); (*dstImage)->privateData = tmpHandle; } if ((*srcImage)->format->clone) (*srcImage)->format->clone(srcImage, dstImage); (*dstImage)->flags &= ~(ifSelected + ifSelVisible + ifAborted + ifScreenSize + ifFilename); for (theImage = gImageRoot; theImage; theImage = (*theImage)->next) if ((theImage != dstImage) && ((*theImage)->num >= (*dstImage)->num)) (*dstImage)->num = (*theImage)->num + 1; } return dstImage; } /* * LastImage() * * Purpose: Returns a pointer to the last image in the linked list * Inputs: none * Returns: a pointer to the last image, or nil if no images exist * */ ImageHandle LastImage(void) { ImageHandle theImage; if (!gImageRoot) return nil; for (theImage = gImageRoot; (*theImage)->next; theImage = (*theImage)->next); return theImage; } /* * PreviousImage(theImage) * * Purpose: Returns a pointer to the image preceding theImage in the linked list * Inputs: none * Returns: a pointer to the preceding image, or nil if theImage is gImageRoot * */ ImageHandle PreviousImage(ImageHandle theImage) { ImageHandle curImage; if (theImage == gImageRoot) return nil; for (curImage = gImageRoot; curImage && ((*curImage)->next != theImage); curImage = (*curImage)->next); return curImage; } /* * AnotherFull(theImage) * * Purpose: Determines if there is another full-screen image on the same monitor as * theImage * Inputs: theImage = a handle to the image * Returns: true if there is another full-screen image; false otherwise * */ Boolean AnotherFull(ImageHandle theImage) { MonitorHandle imageMon = theImage ? (*theImage)->dmon : gMainMonitor; ImageHandle fullImage; if (imageMon == gMainMonitor && GetSlideBackWindow()) return true; for (fullImage = gImageRoot; fullImage; fullImage = (*fullImage)->next) if ((fullImage != theImage) && Full(fullImage) && (*fullImage)->dmon == imageMon) break; return (fullImage != nil); } /* * FindImage(theWindow) * * Purpose: Scans the list of images for one who owns the given window * Inputs: theWindow = a pointer to the window record * Returns: a pointer to the associated image, or nil if none found * */ ImageHandle FindImage(WindowPtr theWindow) { ImageHandle theImage; if (theWindow) for (theImage = gImageRoot; theImage; theImage = (*theImage)->next) if ((*theImage)->window == theWindow) return theImage; return nil; } /* * UpdateImages(theMonitor) * * Purpose: Updates any images whose deepest monitor happens to be theMonitor * Inputs: theMonitor = the monitor whose state has changed * Returns: nothing * */ void UpdateImages(MonitorHandle theMonitor) { #if applec #pragma unused(theMonitor) #endif short depth, palette; ImageHandle theImage; Boolean grey; for (theImage = gImageRoot; theImage; theImage = (*theImage)->next) { GetMinMaxMonitor(theImage); depth = (*(*theImage)->dmon)->depth; grey = !(*(*theImage)->dmon)->color; if (grey || (depth < 4)) palette = plGrey; else if (depth > 8) palette = plSys; else palette = (*theImage)->npalette; switch (palette) { case plSys: DoSetPalette((*theImage)->window, kAEPSystem); break; case plGrey: DoSetPalette((*theImage)->window, kAEPGrayscale); break; case plImage: if ((*(*theImage)->ipalette)->pmEntries <= (1L << depth)) DoSetPalette((*theImage)->window, kAEPImage); else DoSetPalette((*theImage)->window, kAEPSystem); break; case plQuant: if ((*theImage)->qpalette && ((1L << depth) != ((*(*theImage)->qpalette)->pmEntries))) { DisposePalette((*theImage)->qpalette); (*theImage)->qpalette = nil; DoSetPalette((*theImage)->window, kAEPSystem); } else DoSetPalette((*theImage)->window, kAEPQuantized); break; } if (!gThePrefs.ditherQuant && ((*theImage)->npalette == plQuant || ((*theImage)->npalette == plImage && (*theImage)->depth >= 16))) (*theImage)->flags &= ~ifDithered; else (*theImage)->flags |= ifDithered; } } /* * DrawImage(theImage) * * Purpose: Draws the given image in its window * Inputs: theImage = the image record to be drawn * bitsFlags = the initial set of bitsFlags * Returns: nothing * */ OSErr DrawImage(ImageHandle theImage, short bitsFlags, NestedProgressPtr progProc) { Rect theRect = (*theImage)->wrect; OSErr theErr = noErr; RgnHandle tmpRgn; PushPort(); MySetPort((CGrafPtr)(*theImage)->window); /* If we're drawing onscreen, erase the region to be updated, draw a border around * full screen images, reset the clipping rectangle, and limit the visRgn to the * clipped area (since we assume we're doing this from within an update event */ if (bitsFlags & bfOnscreen) { CopyRgn((*theImage)->window->visRgn, (*theImage)->update); if (Full(theImage) && (tmpRgn = NewRgn())) { ClipRect(&(*theImage)->window->portRect); RectRgn(tmpRgn, &theRect); DiffRgn((*theImage)->window->clipRgn, tmpRgn, (*theImage)->window->clipRgn); if (NeedsWhiteBG(theImage) && !Full(theImage)) EraseRgn((*theImage)->window->visRgn); else PaintRgn((*theImage)->window->visRgn); DrawFullBorder(theImage); DisposeRgn(tmpRgn); DiffRgn((*theImage)->update, (*theImage)->window->clipRgn, (*theImage)->update); DiffRgn((*theImage)->window->visRgn, (*theImage)->window->clipRgn, (*theImage)->window->visRgn); } } ClipRect(&theRect); /* If we have anything to draw, then set up the global bitsFlags, point to our * special drawing procedures, and do the appropriate method of drawing */ if (bitsFlags != bfOnscreen || !EmptyRgn((*theImage)->window->visRgn)) { if ((*theImage)->gworld) LockPixels(GetGWorldPixMap((*theImage)->gworld)); if ((*theImage)->gworld && !(bitsFlags & bfForceFull)) theErr = DrawImageGWorld(theImage, bitsFlags, progProc); else theErr = DrawImageFull(theImage, bitsFlags, progProc); } if ((theErr == noErr) && Full(theImage) && (bitsFlags & bfOnscreen) && ShowFilename(theImage)) DrawFileName(theImage); if (bitsFlags & bfOnscreen) { if (theErr == codecAbortErr && !(bitsFlags & bfQuantize)) { if (NeedToRedraw(theImage)) (*theImage)->flags &= ~(ifNeedToRedraw + ifAborted); else { Pattern whitePat = { 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x00 }; Pattern blackPat = { 0x7d, 0xbb, 0xd7, 0xef, 0xd7, 0xbb, 0x7d, 0xff }; RGBForeColor(&gBlack); RGBBackColor(&gWhite); SetClip((*theImage)->update); FillRgn((*theImage)->update, NeedsWhiteBG(theImage) ? &whitePat : &blackPat); (*theImage)->flags |= ifAborted; } } else (*theImage)->flags &= ~ifAborted; } if ((*theImage)->gworld) UnlockPixels(GetGWorldPixMap((*theImage)->gworld)); PopPort(); return theErr; } /* * DrawImageGWorld(theImage, bitsFlags) * * Purpose: Handles drawing from the offscreen GWorld * Inputs: theImage = the image record to be drawn * bitsFlags = set of flags to be passed on to the custom copybits * Returns: nothing * */ OSErr DrawImageGWorld(ImageHandle theImage, short bitsFlags, NestedProgressPtr progProc) { PixMapHandle src = GetGWorldPixMap((*theImage)->gworld); Boolean deepGWorld = ((*(*theImage)->dmon)->depth < PixMapDepth(src)) && !gThePrefs.origSize; Rect srcRect = GWOrigSize(theImage) ? (*theImage)->crect : (*theImage)->gworld->portRect; GWorldPtr oldGWorld = (*theImage)->gworld; Rect theRect = (*theImage)->wrect; JVDrawParamsHandle theParams; OSErr theErr = noErr; KeepSpinning(); if (theParams = NewDrawParams(&(*theImage)->gworld->portRect, (*theImage)->quality, (bitsFlags & bfQuantize) != 0, progProc, (*theImage)->privateData)) { SetUpDrawPort(theParams, kOnscreenPort, (CGrafPtr)(*theImage)->window, &srcRect, &theRect, Dithered(theImage)); (*theParams)->newupdates = (*theImage)->update; // if the GWorld is too deep, we need to delete it and make a new one if (deepGWorld) { (*theImage)->gworld = nil; (*theImage)->flags &= ~ifGWOrigSize; if (!MakeImageGWorld(theImage, false)) { DisposeGWorld(oldGWorld); DisposeHandle((Handle)theParams); if (gThePrefs.useBitmaps == ubAlways && !gSlideShow) return gIntError = errNoOffscreenMemory, memFullErr; else return DrawImageFull(theImage, bitsFlags, progProc); } SetUpDrawPort(theParams, kOffscreenPort1, (*theImage)->gworld, &srcRect, &(*theImage)->gworld->portRect, true); LockPixels(GetGWorldPixMap((*theImage)->gworld)); } // save the port, lock the handles, and initialize the drawing theErr = PreflightDrawing(theParams); // If everything's okay, CopyBits to the dummy port and clean up if (theErr == noErr) { SpinIndef(); CopyGWorldToGWorld(oldGWorld, (*theParams)->dummy, &srcRect, &srcRect, srcCopy, nil); theErr = PostflightDrawing(theParams); } KeepSpinning(); if (deepGWorld) { UnlockPixels(GetGWorldPixMap((*theImage)->gworld)); DisposeGWorld(oldGWorld); } if (progProc) *progProc = (*theParams)->progress; DisposeHandle((Handle)theParams); } else theErr = MemError(); if (theErr == codecAbortErr && (bitsFlags & bfOffscreen)) KillGWorld(theImage); return theErr; } /* * DrawImageFull(theImage, bitsFlags) * * Purpose: Handles drawing from scratch * Inputs: theImage = the image record to be drawn * bitsFlags = set of flags to be passed on to the custom copybits * progProc = pointer to the progress procedure, or nil to use the default * Returns: nothing * */ OSErr DrawImageFull(ImageHandle theImage, short bitsFlags, NestedProgressPtr progProc) { NestedProgress localProg = { { nil, 0L }, 0, 0L, 0x10000L, false }; Rect crect = (*theImage)->crect, theRect = (*theImage)->wrect; JVDrawParamsHandle theParams; OSErr theErr; long dtime; KeepSpinning(); // erase the area we're drawing into before doing anything else if (bitsFlags & bfOnscreen) { if (NeedsWhiteBG(theImage)) EraseRgn((*theImage)->window->visRgn); else PaintRgn((*theImage)->window->visRgn); } // set up the progress procedure, according to flags & current situation & such if (progProc) localProg = *progProc; else { if (bitsFlags & bfOnscreen) { if (NoOnscreenProg(theImage)) localProg.prog.progressProc = gDummyProg.prog.progressProc; else localProg.prog.progressProc = gDrawProgress; } else if (bitsFlags & bfUseSlideProgress) localProg.prog.progressProc = gSlideProgress; else localProg.prog.progressProc = gGenericProgress; } // allocate and initialize the drawing parameters if (theParams = NewDrawParams(&(*theImage)->grect, (*theImage)->quality, (bitsFlags & bfQuantize) != 0, &localProg, (*theImage)->privateData)) { if (localProg.prog.progressProc == gDrawProgress) (*theParams)->drawProgressRect = (*theImage)->wrect; // set up the onscreen port if (bitsFlags & bfOnscreen) { SetUpDrawPort(theParams, kOnscreenPort, (CGrafPtr)(*theImage)->window, &crect, &theRect, Dithered(theImage)); (*theParams)->newupdates = (*theImage)->update; } // try to make a GWorld for this image; if successful, set the bitsFlags // and ClipRgn appropriately; otherwise, if we've required bitmaps, close the // image and return an error if (!(*theImage)->gworld) { if (MakeImageGWorld(theImage, bitsFlags & bfQuantize)) { LockPixels(GetGWorldPixMap((*theImage)->gworld)); bitsFlags |= bfOffscreen; } else if (gThePrefs.useBitmaps == ubAlways && !gSlideShow && ((*theImage)->compression || !gThePrefs.noUncomp)) return gIntError = errNoOffscreenMemory, memFullErr; } // set up the offscreen port if ((bitsFlags & bfOffscreen) && (*theImage)->gworld) SetUpDrawPort(theParams, kOffscreenPort1, (*theImage)->gworld, GWOrigSize(theImage) ? &(*theImage)->gworld->portRect : &crect, &(*theImage)->gworld->portRect, !GWOrigSize(theImage)); // spin the cursor, start the timer, and preflight our drawing KeepSpinning(); StartTimer(); theErr = PreflightDrawing(theParams); KeepSpinning(); PushPort(); if (theErr == noErr) { // indicate globally that we are drawing, and actually call the function gDrawing = theImage; MySetPort((*theParams)->dummy); CallICMProgressProc((*theParams)->progress.prog.progressProc, codecProgressOpen, 0L, (*theParams)->progress.prog.progressRefCon); theErr = (*theImage)->format->draw((*theImage)->data, theParams); CallICMProgressProc((*theParams)->progress.prog.progressProc, codecProgressClose, 0L, (*theParams)->progress.prog.progressRefCon); // reset everything now and stop the timer gDrawing = nil; KeepSpinning(); dtime = StopTimer(); // if we were drawing a full-size image, save the time from the timer if (EqualSizeRect(&theRect, &(*(*theImage)->window->visRgn)->rgnBBox) && theErr == noErr && (bitsFlags & (bfOnscreen + bfOffscreen))) (*theImage)->dtime = dtime; // postflight the drawing, saving the error if (theErr == noErr) theErr = PostflightDrawing(theParams); else PostflightDrawing(theParams); } PopPort(); if (progProc) *progProc = (*theParams)->progress; DisposeHandle((Handle)theParams); } else theErr = memFullErr; if (theErr == memFullErr) gIntError = errNoDrawMemory; else if (theErr == codecAbortErr && (bitsFlags & bfOffscreen)) KillGWorld(theImage); return theErr; } /* * DrawFullBorder(theImage) * * Purpose: Draws the border for a full-screen window * Inputs: theImage = the image record to be drawn * Returns: nothing * */ void DrawFullBorder(ImageHandle theImage) { Rect outerRect = (*theImage)->wrect; InsetRect(&outerRect, -1, -1); RGBForeColor(&gFGrey); RGBBackColor(&gWhite); FrameRect(&outerRect); MoveTo(outerRect.left + 1, outerRect.bottom); LineTo(outerRect.right, outerRect.bottom); LineTo(outerRect.right, outerRect.top + 1); RGBForeColor(&gBlack); } /* * DrawFileName(theImage) * * Purpose: Draws a filename on a full-screen window for the slide show * Inputs: theImage = the image record to be drawn * Returns: nothing * */ void DrawFileName(ImageHandle theImage) { short height, width, i, j; FontInfo theInfo; Str255 theText; Point start; if (!theImage || !(*theImage)->window) return; PushPort(); MySetPort((CGrafPtr)(*theImage)->window); ClipRect(&(*theImage)->window->portRect); CalcVis((WindowPeek)(*theImage)->window); // Do this to get the real visRgn of the window TextFont(systemFont); TextFace(normal); TextSize(12); TextMode(srcOr); GetFontInfo(&theInfo); BlockMove((*theImage)->file.name, theText, *(*theImage)->file.name + 1); height = theInfo.ascent + theInfo.descent + theInfo.leading; width = StringWidth(theText); /* If there's enough room, simply draw the file name below the image's rect */ if (((*theImage)->wrect.bottom + height) < (*(*theImage)->dmon)->rect.bottom) { start.h = (*theImage)->wrect.right - width - theInfo.leading; start.v = (*theImage)->wrect.bottom + height - theInfo.leading; RGBForeColor(&gWhite); MoveTo(start.h, start.v); DrawString(theText); /* Or we could draw it to the right of the image's rect */ } else if (((*theImage)->wrect.right + width + 4) < (*(*theImage)->dmon)->rect.right) { start.h = (*theImage)->wrect.right + 4; start.v = (*theImage)->wrect.bottom - theInfo.descent - theInfo.leading; RGBForeColor(&gWhite); MoveTo(start.h, start.v); DrawString(theText); /* If there's not enough room, we draw the filename on top of the lower-right corner */ } else { start.h = (*theImage)->wrect.right - width - theInfo.leading; start.v = (*theImage)->wrect.bottom - theInfo.descent - theInfo.leading; RGBForeColor(&gBlack); for (i = -1; i <= 1; i++) for (j = -1; j <= 1; j++) { MoveTo(start.h + i, start.v + j); DrawString(theText); } RGBForeColor(&gWhite); MoveTo(start.h, start.v); DrawString(theText); } RGBForeColor(&gBlack); PopPort(); } /* * MakeImageGWorld(theImage) * * Purpose: Attempts to create a new offscreen bitmap for the given image * Inputs: theImage = the image record * quantizing = flag: true if we're quantizing * Returns: true if it worked; false otherwise * */ Boolean MakeImageGWorld(ImageHandle theImage, Boolean quantizing) { short imageDepth = ((*theImage)->depth < 8) ? 8 : (*theImage)->depth; short theDepth = (*(*theImage)->dmon)->depth; Rect theRect = (*theImage)->wrect; CTabHandle theColors = nil; if (gThePrefs.noUncomp && !(*theImage)->compression) return false; if (gThePrefs.useBitmaps == ubNever && (!gSlideShow || !(*gSlideOptions)->offscreen)) return false; if (gThePrefs.origSize && (!Banded(theImage) || !Cropped(theImage))) theRect = (*theImage)->grect; if (theDepth > imageDepth || gThePrefs.origSize || quantizing) theDepth = imageDepth; if (theDepth == 24) theDepth = 32; else if (theDepth <= 8) theColors = GetGWorldColors(theImage, theDepth); OffsetRect(&theRect, (*theImage)->grect.left - theRect.left, (*theImage)->grect.top - theRect.top); (*theImage)->gworld = nil; if (IsMemAvailable(EstGWorldSize(&theRect, theDepth))) (*theImage)->gworld = MyNewGWorld(&theRect, theDepth, theColors, nil, NeedsWhiteBG(theImage), false); if (!(*theImage)->gworld && gSlideShow && (*gSlideOptions)->offscreen && !HasVirtualMemory()) { (*theImage)->gworld = MyNewGWorld(&theRect, theDepth, theColors, nil, NeedsWhiteBG(theImage), true); if ((*theImage)->gworld) (*theImage)->flags |= ifGWTempMem; } if ((*theImage)->gworld) { (*theImage)->flags &= ~ifGWOrigSize; if (EqualSizeRect(&theRect, &(*theImage)->grect) && theDepth >= (*theImage)->depth && (gThePrefs.origSize || theDepth >= 16)) (*theImage)->flags |= ifGWOrigSize; if (theColors) DisposeHandle((Handle)theColors); return true; } if (theColors) DisposeHandle((Handle)theColors); return false; } /* * KillGWorld(theImage) * * Purpose: Kills the given image's GWorld and checks for others who might share it * Inputs: theImage = the image record whose GWorld we are about to kill * Returns: nothing * */ void KillGWorld(ImageHandle theImage) { GWorldPtr theGWorld, curPort = (GWorldPtr)qd.thePort; Boolean foundOthers = false; ImageHandle image; if (theImage && (theGWorld = (*theImage)->gworld)) { if (curPort == theGWorld) MySetPort(nil); for (image = gImageRoot; image; image = (*image)->next) if (image != theImage && (*image)->gworld == theGWorld) foundOthers = true; if (!foundOthers) DisposeGWorld(theGWorld); (*theImage)->gworld = nil; } } /* * GetGWorldColors(theImage, gwDepth) * * Purpose: Creates an appropriate color table for the given image's GWorld at the * given depth * Inputs: theImage = the image record * gwDepth = the depth of the GWorld we'd like to create * Returns: a CTabHandle containing the color table * */ CTabHandle GetGWorldColors(ImageHandle theImage, short gwDepth) { short imDepth = (*theImage)->depth; PaletteHandle thePalette = nil; CTabHandle theColors = nil; if (!gThePrefs.origSize) { // can only copy from screen if not original size if ((theImage == FrontImage()) && !gInBackground && (*theImage)->window && WindowVisible((*theImage)->window) && (gwDepth == (*(*theImage)->dmon)->depth) && (gwDepth <= 8)) { theColors = (*(*(*(*theImage)->dmon)->device)->gdPMap)->pmTable; if (HandToHand((Handle *)&theColors) != noErr) theColors = nil; return theColors; } } if (gwDepth >= imDepth) { if (imDepth <= 8) { if (gwDepth <= 8) thePalette = (*theImage)->ipalette ? (*theImage)->ipalette : (*theImage)->palette; else thePalette = nil; } else thePalette = nil; } else { if (imDepth <= 8) thePalette = (*theImage)->palette; else { if (gwDepth <= 8) thePalette = (*theImage)->palette; else thePalette = nil; } } if (thePalette && ((1L << gwDepth) == (*thePalette)->pmEntries)) { if (theColors = (CTabHandle)NewHandle(4)) { Palette2CTab(thePalette, theColors); (*theColors)->ctSeed = GetCTSeed(); } } return theColors; } /* * DoImageHelp(theWindow, globalPt) * * Purpose: Pops up help for an image window; needed because they can be called anything * Inputs: theWindow = the window whose help we're getting * globalPt = point, in global coordinates, where the mouse is * Returns: nothing * */ void DoImageHelp(WindowPtr theWindow, Point globalPt) { ImageHandle theImage = FindImage(theWindow); HMMessageRecord theRecord; Point tip = { 0, 0 }; Rect aRect; if (HMIsBalloon() || gInBackground) return; PushPort(); SetPort(theWindow); if (HMExtractHelpMsg(kHMRectListResType, rImageWindow, 1, kHMEnabledItem, &theRecord) == noErr) { tip = globalPt; aRect = theWindow->portRect; GlobalRect(&aRect, theWindow); HMShowBalloon(&theRecord, tip, &aRect, nil, 0, 0, kHMRegularWindow); } PopPort(); }