mirror of
https://github.com/aaronsgiles/JPEGView.git
synced 2024-06-14 12:29:33 +00:00
These are the sources for the final official release of JPEGView for the Mac, back in 1994.
1 line
30 KiB
C
1 line
30 KiB
C
/*********************************************************/
|
|
/* This source code copyright (c) 1991-2001, Aaron Giles */
|
|
/* See the Read Me file for licensing information. */
|
|
/* Contact email: mac@aarongiles.com */
|
|
/*********************************************************/
|
|
|
|
//=====================================================================================
|
|
// Generic includes for Macintosh headers
|
|
//=====================================================================================
|
|
|
|
#if THINK_C
|
|
#include "THINK.Header"
|
|
#elif applec
|
|
#pragma load ":Headers:MPW.Header"
|
|
#elif __MWERKS__
|
|
//#include "MW.Header"
|
|
#else
|
|
#include "JPEGView.h"
|
|
#endif
|
|
|
|
//=====================================================================================
|
|
// Includes specific to this module
|
|
//=====================================================================================
|
|
|
|
#include "SlideShow.h"
|
|
|
|
//=====================================================================================
|
|
// Constants local to this module
|
|
//=====================================================================================
|
|
|
|
enum {
|
|
kEndSlideShow = -1,
|
|
kAdvanceSlide = -2,
|
|
kReloadSlide = -3,
|
|
kReverseSlide = -4
|
|
};
|
|
|
|
//=====================================================================================
|
|
// Global variables local to this module
|
|
//=====================================================================================
|
|
|
|
static Boolean gSlideWarned = false, gStatsHidden, gColorsHidden, gCommentsHidden;
|
|
static ImageHandle gSlideNextImage = nil;
|
|
static WindowPtr gSlideBackWindow = nil;
|
|
static SlideHandle gSlideNext = nil;
|
|
static SlideHandle gSlideRoot = nil;
|
|
static long gSlideTimer = 0L;
|
|
static long gSlideCount = 0L;
|
|
|
|
//=====================================================================================
|
|
// Prototypes for functions local to this module
|
|
//=====================================================================================
|
|
|
|
static void OpenSlideBackWindow(void);
|
|
static SlideHandle NewSlide(Boolean memory, FSSpec *spec);
|
|
static void DisposeSlide(SlideHandle theSlide);
|
|
static SlideHandle LastSlide(void);
|
|
static SlideHandle PreviousSlide(SlideHandle theSlide);
|
|
static SlideHandle DisplayedSlide(void);
|
|
static void ShuffleSlides(void);
|
|
static ImageHandle LoadSlideFromMem(void);
|
|
static ImageHandle LoadSlideFromDisk(void);
|
|
static ImageHandle HandleLoadError(OSErr theErr, StringPtr fileName);
|
|
static Boolean WarnSlideShowMemory(void);
|
|
|
|
//=====================================================================================
|
|
// void OpenSlideBackWindow(void)
|
|
//
|
|
// Creates and displays the background window for the slide show.
|
|
//
|
|
// External calls: GetDeepMonitor, PushPort, MySetPort, FullScreen, PopPort
|
|
//=====================================================================================
|
|
|
|
static void OpenSlideBackWindow(void)
|
|
{
|
|
MonitorHandle deepMonitor;
|
|
PaletteHandle thePalette;
|
|
|
|
deepMonitor = GetDeepMonitor(true);
|
|
thePalette = SystemPalette((*deepMonitor)->depth <= 8 ? (*deepMonitor)->depth : 8);
|
|
PushPort();
|
|
MySetPort(nil);
|
|
FullScreen(gMainMonitor);
|
|
gSlideBackWindow = FWGetNewCWindow(rFullImageWindow, (Ptr)gSlideBackWindow, (WindowPtr)-1);
|
|
SizeWindow(gSlideBackWindow, Width(&(*GetGrayRgn())->rgnBBox),
|
|
Height(&(*GetGrayRgn())->rgnBBox), true);
|
|
FWMoveWindow(gSlideBackWindow, (*GetGrayRgn())->rgnBBox.left, (*GetGrayRgn())->rgnBBox.top, true);
|
|
SetPalette(gSlideBackWindow, thePalette, true);
|
|
ActivatePalette(gSlideBackWindow);
|
|
MySetPort((CGrafPtr)gSlideBackWindow);
|
|
SetOrigin((*GetGrayRgn())->rgnBBox.left, (*GetGrayRgn())->rgnBBox.top);
|
|
FWShowWindow(gSlideBackWindow);
|
|
DrawSlideBackWindow();
|
|
PopPort();
|
|
}
|
|
|
|
//=====================================================================================
|
|
// WindowPtr GetSlideBackWindow(void)
|
|
//
|
|
// Returns a pointer to the slide backdrop window.
|
|
//
|
|
// External calls: GetDeepMonitor, PushPort, MySetPort, FullScreen, PopPort
|
|
//=====================================================================================
|
|
|
|
extern WindowPtr GetSlideBackWindow(void)
|
|
{
|
|
return gSlideBackWindow;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// void CloseSlideBackWindow(void)
|
|
//
|
|
// Closes the slide backdrop window.
|
|
//
|
|
// External calls: none
|
|
//=====================================================================================
|
|
|
|
extern void CloseSlideBackWindow(void)
|
|
{
|
|
if (gSlideBackWindow) {
|
|
PushPort();
|
|
MySetPort(nil);
|
|
FWDisposeWindow(gSlideBackWindow);
|
|
DeallocateWindow(gSlideBackWindow);
|
|
gSlideBackWindow = nil;
|
|
if (!AnotherFull(nil)) NormalScreen(gMainMonitor);
|
|
PopPort();
|
|
}
|
|
}
|
|
|
|
//=====================================================================================
|
|
// void DrawSlideBackWindow(void)
|
|
//
|
|
// Draws a JPEGView icon in the center of each screen.
|
|
//
|
|
// External calls: none
|
|
//=====================================================================================
|
|
|
|
extern void DrawSlideBackWindow(void)
|
|
{
|
|
MonitorHandle theMonitor;
|
|
Rect theRect;
|
|
|
|
for (theMonitor = gMainMonitor; theMonitor; theMonitor = (*theMonitor)->next) {
|
|
theRect = (*theMonitor)->rect;
|
|
theRect.left += (Width(&theRect) - 32) / 2;
|
|
theRect.top += (Height(&theRect) - 32) / 2;
|
|
theRect.right = theRect.left + 32;
|
|
theRect.bottom = theRect.top + 32;
|
|
PlotIconSuite(&theRect, atAbsoluteCenter, ttNone, gIconSuite);
|
|
}
|
|
}
|
|
|
|
//=====================================================================================
|
|
// void ResetSlideTimer(void)
|
|
//
|
|
// Resets the slide timer, maintained by HandleSlideNullEvent.
|
|
//
|
|
// External calls: none
|
|
//=====================================================================================
|
|
|
|
extern void ResetSlideTimer(void)
|
|
{
|
|
gSlideTimer = TickCount();
|
|
}
|
|
|
|
//=====================================================================================
|
|
// void HandleSlideNullEvent(void)
|
|
//
|
|
// Handles null events while a slide show is active.
|
|
//
|
|
// External calls: none
|
|
//=====================================================================================
|
|
|
|
extern void HandleSlideNullEvent(void)
|
|
{
|
|
ulong newCount = TickCount();
|
|
EvQElPtr theEvent;
|
|
Boolean advance;
|
|
|
|
// if we're in screen saver mode, make sure the mouse didn't move
|
|
if (gScreenSaver) {
|
|
Point newMouse = GlobalMouse();
|
|
if (abs(newMouse.h - gScreenSaverPoint.h) > 2 ||
|
|
abs(newMouse.v - gScreenSaverPoint.v) > 2) {
|
|
SendQuitApplication();
|
|
return;
|
|
}
|
|
}
|
|
|
|
// if we're automatic, enable the play button here
|
|
if (!(*gSlideOptions)->userControl && GetSlideControlButton(kForwardButton) == disabled) {
|
|
SetSlideControlButton(kForwardButton, standard);
|
|
DrawSlideControlsWindow();
|
|
}
|
|
|
|
// if the slide show is paused, don't do this bit
|
|
if (gSlideShow == kPaused) return;
|
|
|
|
if ((*gSlideOptions)->userControl)
|
|
SetSlideControlsText(gString[strSlideReady], gNullString, gNullString, gNullString);
|
|
|
|
// if the timer isn't up yet, and we're in the foreground, post a fake
|
|
// key down event to prevent screen savers from kicking in
|
|
else if (((newCount - gSlideTimer) / kClockFreq) <= (*gSlideOptions)->delay &&
|
|
!gInBackground) {
|
|
Str32 theCount;
|
|
PPostEvent(keyDown, kCreator, &theEvent);
|
|
NumToString((*gSlideOptions)->delay - (newCount - gSlideTimer) / kClockFreq, theCount);
|
|
SetSlideControlsText(gString[strSlideDelaying], theCount, gNullString, gNullString);
|
|
return;
|
|
}
|
|
|
|
// if we're under user control, or if we're paused
|
|
if ((*gSlideOptions)->userControl || gSlideShow == kPaused) return;
|
|
|
|
// otherwise, reset the slide timer, draw this slide and then start loading the next
|
|
gSlideTimer = newCount;
|
|
do {
|
|
advance = false;
|
|
gSlideShow = NextSlide(&advance);
|
|
if (gSlideShow) gSlideShow = LoadSlide(&advance);
|
|
} while (advance && gSlideShow);
|
|
}
|
|
|
|
//=====================================================================================
|
|
// SlideHandle NewSlide(Boolean memory, FSSpec *spec)
|
|
//
|
|
// Creates a new slide handle and appends it to the beginning of the linked list.
|
|
//
|
|
// External calls: none
|
|
//=====================================================================================
|
|
|
|
static SlideHandle NewSlide(Boolean memory, FSSpec *spec)
|
|
{
|
|
long theSize = sizeof(SlideItem);
|
|
SlideHandle theSlide;
|
|
|
|
if (!IsMemAvailable(sizeof(SlideItem))) return nil;
|
|
if (gSlideRoot) {
|
|
for (theSlide = gSlideRoot; (*theSlide)->next; theSlide = (*theSlide)->next);
|
|
theSlide = (*theSlide)->next = (SlideHandle)NewHandle(sizeof(SlideItem));
|
|
} else
|
|
theSlide = gSlideRoot = (SlideHandle)NewHandle(sizeof(SlideItem));
|
|
if (theSlide) {
|
|
(*theSlide)->next = nil;
|
|
(*theSlide)->mem = memory;
|
|
(*theSlide)->spec = *spec;
|
|
gSlideCount++;
|
|
}
|
|
return theSlide;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// void DisposeSlide(SlideHandle theSlide)
|
|
//
|
|
// Removes a slide handle from the linked list.
|
|
//
|
|
// External calls: none
|
|
//=====================================================================================
|
|
|
|
static void DisposeSlide(SlideHandle theSlide)
|
|
{
|
|
Boolean found = false;
|
|
SlideHandle tempSlide;
|
|
|
|
if (theSlide != gSlideRoot) {
|
|
for (tempSlide = gSlideRoot;
|
|
tempSlide && ((*tempSlide)->next != theSlide);
|
|
tempSlide = (*tempSlide)->next);
|
|
if (tempSlide) (*tempSlide)->next = (*theSlide)->next;
|
|
} else
|
|
gSlideRoot = (*gSlideRoot)->next;
|
|
DisposeHandle((Handle)theSlide);
|
|
gSlideCount--;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// SlideHandle PreviousSlide(SlideHandle theSlide)
|
|
//
|
|
// Returns the slide in the list previous to the given slide.
|
|
//
|
|
// External calls: none
|
|
//=====================================================================================
|
|
|
|
static SlideHandle LastSlide(void)
|
|
{
|
|
SlideHandle theSlide;
|
|
|
|
if (!gSlideRoot) return nil;
|
|
for (theSlide = gSlideRoot; (*theSlide)->next; theSlide = (*theSlide)->next);
|
|
return theSlide;
|
|
}
|
|
|
|
static SlideHandle PreviousSlide(SlideHandle theSlide)
|
|
{
|
|
SlideHandle slide;
|
|
|
|
if (!theSlide || theSlide == gSlideRoot || theSlide == (SlideHandle)kEndSlideShow)
|
|
return LastSlide();
|
|
for (slide = gSlideRoot; slide; slide = (*slide)->next)
|
|
if ((*slide)->next == theSlide) return slide;
|
|
return nil;
|
|
}
|
|
|
|
static SlideHandle DisplayedSlide(void)
|
|
{
|
|
SlideHandle theSlide = PreviousSlide(gSlideNext);
|
|
ImageHandle theImage = FrontImage();
|
|
short imageIndex;
|
|
|
|
if (!theImage) return nil;
|
|
imageIndex = GetDocumentIndex((*theImage)->window);
|
|
do {
|
|
if ((*theSlide)->mem) {
|
|
if ((*theSlide)->spec.vRefNum == imageIndex) return theSlide;
|
|
} else
|
|
if (SameFile(&(*theImage)->file, &(*theSlide)->spec)) return theSlide;
|
|
theSlide = PreviousSlide(theSlide);
|
|
} while (theSlide != gSlideNext);
|
|
return nil;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// void PointToPreviousSlide(void)
|
|
//
|
|
// Backs up the gSlideNext pointer by the specified count.
|
|
//
|
|
// External calls: none
|
|
//=====================================================================================
|
|
|
|
extern void PointToPreviousSlide(void)
|
|
{
|
|
SlideHandle currentSlide = DisplayedSlide();
|
|
ImageHandle frontImage = FrontImage();
|
|
|
|
if (currentSlide) {
|
|
if ((*currentSlide)->next == gSlideNext || (*(*currentSlide)->next)->next == gSlideNext)
|
|
gSlideNext = PreviousSlide(currentSlide);
|
|
else if (gSlideNext != gSlideRoot) gSlideNext = PreviousSlide(gSlideNext);
|
|
else SysBeep(1);
|
|
} else SysBeep(1);
|
|
if (gSlideNextImage && gSlideNextImage != frontImage)
|
|
DoCloseWindow((*gSlideNextImage)->window, false);
|
|
gSlideNextImage = nil;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// void InitSlideShow(void)
|
|
//
|
|
// Initializes a new slide show; does not properly set up for a resumed slide show.
|
|
//
|
|
// External calls: none
|
|
//=====================================================================================
|
|
|
|
extern void InitSlideShow(void)
|
|
{
|
|
ImageHandle theImage;
|
|
WindowPtr theWindow;
|
|
Boolean advance;
|
|
FSSpec theSpec;
|
|
|
|
gSlideShow = false;
|
|
|
|
// if we're doing a memory-based slide show, generate the slide entries here
|
|
if (!gSlideRoot && (*gSlideOptions)->fromMemory)
|
|
for (theImage = gImageRoot; theImage; theImage = (*theImage)->next) {
|
|
theSpec.vRefNum = GetDocumentIndex((*theImage)->window);
|
|
NewSlide(true, &theSpec);
|
|
}
|
|
|
|
// if for some reason we have no slides, signal the error and return
|
|
if (!gSlideCount) {
|
|
MinorError(errNoImagesFound);
|
|
MyInvalMenuBar();
|
|
return;
|
|
}
|
|
|
|
// if we are to hide the floating windows, do it now
|
|
gStatsHidden = gCommentsHidden = gColorsHidden = false;
|
|
if ((*gSlideOptions)->hideWindoids) {
|
|
if (theWindow = GetStatWindow()) gStatsHidden = true, CloseStats();
|
|
if (theWindow = GetCommentsWindow()) gCommentsHidden = true, CloseComments();
|
|
if (theWindow = GetColorsWindow()) gColorsHidden = true, CloseColors();
|
|
}
|
|
|
|
// if the slide background window has not been opened, we allocate and open it now
|
|
if (!gSlideBackWindow && (gSlideBackWindow = AllocateWindow())) OpenSlideBackWindow();
|
|
|
|
// set up the slide control buttons ahead of time here
|
|
SetSlideControlButton(kReverseButton, disabled);
|
|
SetSlideControlButton(kStopButton, standard);
|
|
SetSlideControlButton(kPauseButton, standard);
|
|
SetSlideControlButton(kForwardButton, standard);
|
|
|
|
// if this is user-controlled, pop up the controls window now
|
|
if (!(*gSlideOptions)->hideControls && OpenSlideControls() == noErr)
|
|
ChangeActive(GetSlideControlsWindow());
|
|
|
|
// if this is a disk-based slide show, close all other open images
|
|
if (!(*gSlideOptions)->fromMemory)
|
|
while (gImageRoot)
|
|
DoCloseWindow((*LastImage())->window, false);
|
|
|
|
// reset all the appropriate variables, then load, draw, and load the second slide
|
|
if ((*gSlideOptions)->random) ShuffleSlides();
|
|
gSlideNextImage = nil;
|
|
gSlideWarned = false;
|
|
gSlideNext = gSlideRoot;
|
|
gSlideShow = true;
|
|
advance = false;
|
|
if (gSlideShow = LoadSlide(&advance)) {
|
|
do {
|
|
advance = false;
|
|
gSlideShow = NextSlide(&advance);
|
|
if (gSlideShow) gSlideShow = LoadSlide(&advance);
|
|
} while (advance && gSlideShow);
|
|
}
|
|
|
|
// if we got shoved in the background, start in the paused state
|
|
if (gInBackground && !gScreenSaver) {
|
|
Boolean dummy;
|
|
gSlideShow = PauseSlideShow(&dummy);
|
|
}
|
|
}
|
|
|
|
//=====================================================================================
|
|
// void ReinitSlideShow(PrefsData *oldPrefs)
|
|
//
|
|
// Initializes a new slide show; does not properly set up for a resumed slide show.
|
|
//
|
|
// External calls: none
|
|
//=====================================================================================
|
|
|
|
extern void ReinitSlideShow(SlideOptionsPtr oldOptions)
|
|
{
|
|
WindowPtr theWindow;
|
|
|
|
if (oldOptions->hideWindoids != (*gSlideOptions)->hideWindoids) {
|
|
if ((*gSlideOptions)->hideWindoids) {
|
|
if (theWindow = GetStatWindow()) gStatsHidden = true, CloseStats();
|
|
if (theWindow = GetCommentsWindow()) gCommentsHidden = true, CloseComments();
|
|
if (theWindow = GetColorsWindow()) gColorsHidden = true, CloseColors();
|
|
} else {
|
|
if (gStatsHidden && OpenStats() == noErr) ChangeActive(GetStatWindow());
|
|
if (gCommentsHidden && OpenComments() == noErr) ChangeActive(GetCommentsWindow());
|
|
if (gColorsHidden && OpenColors() == noErr) ChangeActive(GetColorsWindow());
|
|
}
|
|
}
|
|
if (oldOptions->hideControls != (*gSlideOptions)->hideControls) {
|
|
if (!(*gSlideOptions)->hideControls && OpenSlideControls() == noErr)
|
|
ChangeActive(GetSlideControlsWindow());
|
|
else if ((*gSlideOptions)->hideControls && GetSlideControlsWindow())
|
|
CloseSlideControls();
|
|
}
|
|
|
|
gPendingButton = kForwardButton;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// void AddSlideDir(FSSpec *spec)
|
|
//
|
|
// Adds a given file or directory to the list of slides to be displayed, recognizing
|
|
// the request for recursive directory scans.
|
|
//
|
|
// External calls: none
|
|
//=====================================================================================
|
|
|
|
extern OSErr AddSlideDir(FSSpec *spec, Boolean recursive, ICMProgressProcRecordPtr theProg,
|
|
LoopCheckPtr loopList)
|
|
{
|
|
FSSpec dirSpec = *spec, theSpec;
|
|
Boolean isFolder, wasAliased;
|
|
OSErr theErr = noErr;
|
|
LoopCheck thisDir;
|
|
CInfoPBRec block;
|
|
Str255 fileName;
|
|
long dir;
|
|
|
|
if (ResolveAliasFile(&dirSpec, true, &isFolder, &wasAliased) != noErr) return noErr;
|
|
if (isFolder) {
|
|
theErr = GetDirectoryID(&dirSpec, &dir);
|
|
if (theErr != noErr) return noErr;
|
|
thisDir.prev = loopList;
|
|
thisDir.vRefNum = dirSpec.vRefNum;
|
|
thisDir.dirID = dir;
|
|
while (loopList) {
|
|
if (loopList->vRefNum == dirSpec.vRefNum && loopList->dirID == dir)
|
|
return noErr;
|
|
loopList = loopList->prev;
|
|
}
|
|
UpdateParamText(gString[strScanningDirectory], gNullString, gNullString, spec->name);
|
|
} else {
|
|
if (!NewSlide(false, &dirSpec)) return memFullErr;
|
|
return noErr;
|
|
}
|
|
block.hFileInfo.ioNamePtr = fileName;
|
|
block.hFileInfo.ioFDirIndex = 1;
|
|
block.hFileInfo.ioVRefNum = dirSpec.vRefNum;
|
|
block.hFileInfo.ioDirID = dir;
|
|
if (theProg && (OSErr)CallICMProgressProc(theProg->progressProc,
|
|
codecProgressUpdatePercent, kIndefProgress,
|
|
theProg->progressRefCon) == codecAbortErr)
|
|
return codecAbortErr;
|
|
while (PBGetCatInfo(&block, false) == noErr && theErr == noErr) {
|
|
KeepSpinning();
|
|
FSMakeFSSpec(dirSpec.vRefNum, dir, fileName, &theSpec);
|
|
if (ResolveAliasFile(&theSpec, true, &isFolder, &wasAliased) == noErr) {
|
|
if (isFolder) {
|
|
if (recursive) {
|
|
theErr = AddSlideDir(&theSpec, (*gSlideOptions)->recursive, theProg, &thisDir);
|
|
if (theErr != noErr) break;
|
|
}
|
|
} else if ((*gSlideOptions)->allFiles) {
|
|
short theFile, fileType;
|
|
if (FSpOpenDF(&theSpec, fsRdPerm, &theFile) == noErr) {
|
|
fileType = IDImage(theFile, &theSpec);
|
|
FSClose(theFile);
|
|
if (fileType != kInvalidType)
|
|
if (!NewSlide(false, &theSpec)) {
|
|
theErr = memFullErr;
|
|
break;
|
|
}
|
|
}
|
|
} else if (ValidType(block.hFileInfo.ioFlFndrInfo.fdType))
|
|
if (!NewSlide(false, &theSpec)) {
|
|
theErr = memFullErr;
|
|
break;
|
|
}
|
|
if (!(block.hFileInfo.ioFDirIndex & 0x0f))
|
|
if (theProg && (OSErr)CallICMProgressProc(theProg->progressProc,
|
|
codecProgressUpdatePercent, kIndefProgress,
|
|
theProg->progressRefCon) == codecAbortErr)
|
|
return codecAbortErr;
|
|
}
|
|
block.hFileInfo.ioFDirIndex++;
|
|
block.hFileInfo.ioDirID = dir;
|
|
}
|
|
return theErr;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// void CleanUpSlideShow(void)
|
|
//
|
|
// Cleans up for when the slide show is completely finished.
|
|
//
|
|
// External calls: none
|
|
//=====================================================================================
|
|
|
|
extern void CleanUpSlideShow(void)
|
|
{
|
|
ImageHandle theImage, nextImage;
|
|
short choice = 0;
|
|
|
|
while (gSlideRoot) DisposeSlide(gSlideRoot);
|
|
if (GetSlideControlsWindow()) CloseSlideControls();
|
|
if (GetSlideBackWindow()) CloseSlideBackWindow();
|
|
gSlideShow = false;
|
|
if (!(*gSlideOptions)->fromMemory)
|
|
for (theImage = gImageRoot; theImage; theImage = nextImage) {
|
|
nextImage = (*theImage)->next;
|
|
if (theImage != FrontImage())
|
|
DoCloseWindow((*theImage)->window, gThePrefs.restoreColors);
|
|
}
|
|
if ((*gSlideOptions)->hideWindoids) {
|
|
if (gStatsHidden && OpenStats() == noErr) ChangeActive(GetStatWindow());
|
|
if (gCommentsHidden && OpenComments() == noErr) ChangeActive(GetCommentsWindow());
|
|
if (gColorsHidden && OpenColors() == noErr) ChangeActive(GetColorsWindow());
|
|
}
|
|
for (theImage = gImageRoot; theImage; theImage = (*theImage)->next)
|
|
if (GWTempMem(theImage)) KillGWorld(theImage);
|
|
EnableMenus();
|
|
if (theImage = FrontImage()) (*theImage)->flags &= ~ifAborted;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// void ShuffleSlides(void)
|
|
//
|
|
// Shuffles the linked list of slides in a pseudo-random order.
|
|
//
|
|
// External calls: none
|
|
//=====================================================================================
|
|
|
|
static void ShuffleSlides(void)
|
|
{
|
|
SlideHandle theSlide, tempSlide;
|
|
long i, j, k;
|
|
|
|
for (i = 0; i < (gSlideCount * 4); i++) {
|
|
j = ((ushort)Random()) % gSlideCount;
|
|
if (j > 0) {
|
|
for (theSlide = gSlideRoot, k = 1; (k < j) && theSlide; k++)
|
|
theSlide = (*theSlide)->next;
|
|
if (theSlide) {
|
|
tempSlide = (*theSlide)->next;
|
|
(*theSlide)->next = (*tempSlide)->next;
|
|
(*tempSlide)->next = gSlideRoot;
|
|
gSlideRoot = tempSlide;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//=====================================================================================
|
|
// void LoadSlide(void)
|
|
//
|
|
// Loads the next slide, skipping over any that cause errors.
|
|
//
|
|
// External calls: none
|
|
//=====================================================================================
|
|
|
|
extern Boolean LoadSlide(Boolean *advance)
|
|
{
|
|
SlideHandle theSlide;
|
|
|
|
// loop until we get a good slide
|
|
while (!gSlideNextImage) {
|
|
if (!(*gSlideOptions)->userControl) ObscureCursor();
|
|
|
|
// enable the reverse button if we're not loading the first two slides
|
|
if (gSlideNext != gSlideRoot &&
|
|
(theSlide = DisplayedSlide()) && theSlide != gSlideRoot)
|
|
SetSlideControlButton(kReverseButton, standard);
|
|
else SetSlideControlButton(kReverseButton, disabled);
|
|
|
|
// load the next slide, either from memory, or from disk
|
|
if ((*gSlideNext)->mem) gSlideNextImage = LoadSlideFromMem();
|
|
else gSlideNextImage = LoadSlideFromDisk();
|
|
|
|
// if we've ended the show, clean up and return false
|
|
if (gSlideNextImage == (ImageHandle)kEndSlideShow) {
|
|
CleanUpSlideShow();
|
|
return false;
|
|
|
|
// if we're supposed to advance forward one, set the flag
|
|
} else if (gSlideNextImage == (ImageHandle)kAdvanceSlide) {
|
|
gSlideNextImage = nil;
|
|
*advance = true;
|
|
}
|
|
|
|
// if we're supposed to reload the current slide, skip this next part
|
|
if (gSlideNextImage == (ImageHandle)kReloadSlide) {
|
|
gSlideNextImage = nil;
|
|
*advance = true;
|
|
|
|
// if we're backing up, back gSlideNext up one and reload, skipping next
|
|
} else if (gSlideNextImage == (ImageHandle)kReverseSlide) {
|
|
gSlideNextImage = nil;
|
|
PointToPreviousSlide();
|
|
*advance = true;
|
|
|
|
// save the handle to the current slide, and find the next one, restarting
|
|
// and reshuffling as appropriate
|
|
} else {
|
|
theSlide = gSlideNext;
|
|
if (!(gSlideNext = (*gSlideNext)->next)) {
|
|
if (!(*gSlideOptions)->repeat) {
|
|
if (gSlideNextImage) {
|
|
gSlideNext = (SlideHandle)kEndSlideShow;
|
|
return true;
|
|
} else {
|
|
EndSlideShow();
|
|
CleanUpSlideShow();
|
|
return false;
|
|
}
|
|
} else {
|
|
if ((*gSlideOptions)->random) ShuffleSlides();
|
|
gSlideNext = gSlideRoot;
|
|
}
|
|
}
|
|
|
|
// if we got an unprocessed forward arrow, set the advance flag
|
|
if (gPendingButton == kForwardButton) {
|
|
*advance = true;
|
|
gPendingButton = -1;
|
|
}
|
|
|
|
// if there was an error in setting up the last slide, kill it from the list
|
|
if (!gSlideNextImage) {
|
|
if (gSlideNext == theSlide) {
|
|
gSlideNext = (*gSlideNext)->next;
|
|
if (!gSlideNext && gSlideRoot == theSlide) {
|
|
CleanUpSlideShow();
|
|
EndSlideShow();
|
|
return false;
|
|
} else if (!gSlideNext) gSlideNext = gSlideRoot;
|
|
}
|
|
DisposeSlide(theSlide);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// ImageHandle LoadSlideFromMem(void)
|
|
//
|
|
// Sets up the next slide for an in-memory slide show.
|
|
//
|
|
// External calls: FindImage, IndexedDocument, DoSetWindowFull
|
|
//=====================================================================================
|
|
|
|
static ImageHandle LoadSlideFromMem(void)
|
|
{
|
|
ImageHandle theImage;
|
|
OSErr theErr = noErr;
|
|
|
|
theImage = FindImage(IndexedDocument((*gSlideNext)->spec.vRefNum));
|
|
if (!Full(theImage)) theErr = DoSetWindowFull((*theImage)->window, true);
|
|
if (theErr == noErr) return theImage;
|
|
if (!(*gSlideOptions)->noErrors) HandleAEError(theErr, errNoDrawMemory, (*theImage)->file.name);
|
|
return nil;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// ImageHandle LoadSlideFromDisk(SlideHandle theSlide)
|
|
//
|
|
// Sets up the next slide for a disk-based slide show; returns nil if the image failed
|
|
// to load; returns (ImageHandle)-1 if the slide show should end.
|
|
//
|
|
// External calls: GetOpenDefaults, DoOpenDocument, StopSpinning, HandleAEError
|
|
//=====================================================================================
|
|
|
|
static ImageHandle LoadSlideFromDisk(void)
|
|
{
|
|
DescType openScreen, openFull, openPalette, drawQuality;
|
|
FSSpec theSpec = (*gSlideNext)->spec;
|
|
ImageHandle theImage;
|
|
OSErr theErr;
|
|
|
|
do {
|
|
SetSlideControlsText(gString[strSlideLoading], theSpec.name, gNullString, gNullString);
|
|
GetOpenDefaults(&openScreen, &openFull, &openPalette, &drawQuality);
|
|
StartSpinning();
|
|
theErr = DoOpenDocument(&theSpec, true, openScreen, kAEOFAlways,
|
|
gThePrefs.expandSmall, true, openPalette, drawQuality,
|
|
(*gSlideOptions)->offscreen, (*gSlideOptions)->autoComments,
|
|
gThePrefs.autoFix, gThePrefs.changeCreator);
|
|
StopSpinning(&qd.arrow);
|
|
if (theErr == noErr) {
|
|
for (theImage = gImageRoot, gSlideNextImage = nil; theImage;
|
|
theImage = (*theImage)->next)
|
|
if (SameFile(&(*theImage)->file, &theSpec)) return theImage;
|
|
} else theImage = HandleLoadError(theErr, theSpec.name);
|
|
} while (theImage == (ImageHandle)kReloadSlide);
|
|
return theImage;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// ImageHandle HandleLoadError(OSErr theErr)
|
|
//
|
|
// Handles errors that occur during a load; abort errors are assumed to be the result
|
|
// of the user pressing a control button.
|
|
//
|
|
// External calls: GetOpenDefaults, DoOpenDocument, StopSpinning, HandleAEError
|
|
//=====================================================================================
|
|
|
|
static ImageHandle HandleLoadError(OSErr theErr, StringPtr fileName)
|
|
{
|
|
Boolean advance;
|
|
|
|
switch (theErr) {
|
|
case codecAbortErr:
|
|
if (gDone) return (ImageHandle)kEndSlideShow;
|
|
else if (gPendingButton != -1) {
|
|
short button = gPendingButton;
|
|
gPendingButton = -1;
|
|
if (button == kPauseButton || button == kHideButton) {
|
|
gSlideShow = (button == kPauseButton) ? PauseSlideShow(&advance) :
|
|
HideSlideShow(&advance);
|
|
if (!gSlideShow) return (ImageHandle)kEndSlideShow;
|
|
else return (ImageHandle)kReloadSlide;
|
|
} else if (button == kForwardButton)// && (*gSlideOptions)->userControl)
|
|
return (ImageHandle)kAdvanceSlide;
|
|
else if (button == kStopButton) return (ImageHandle)kEndSlideShow;
|
|
else if (button == kReverseButton) return (ImageHandle)kReverseSlide;
|
|
}
|
|
break;
|
|
case memFullErr:
|
|
if (WarnSlideShowMemory()) return (ImageHandle)kEndSlideShow;
|
|
break;
|
|
default:
|
|
if (!(*gSlideOptions)->noErrors) HandleAEError(theErr, errNoLoadMemory, fileName);
|
|
break;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// Boolean WarnSlideShowMemory(void)
|
|
//
|
|
// Display the warning about not being able to see all slides due to low memory.
|
|
//
|
|
// External calls: PushPort, MySetPort, StopSpinning, CenterAlert, PopPort
|
|
//=====================================================================================
|
|
|
|
static Boolean WarnSlideShowMemory(void)
|
|
{
|
|
short choice;
|
|
|
|
ShowCursor();
|
|
if (!gSlideWarned && !(*gSlideOptions)->noErrors) {
|
|
gSlideWarned = true;
|
|
PushPort();
|
|
MySetPort(nil);
|
|
StopSpinning(&qd.arrow);
|
|
choice = FWCautionAlert(CenterAlert(rSlideMemAlert), gGenericFilter);
|
|
PopPort();
|
|
if (choice == 3 || choice == kDialogCancel) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// Boolean EndSlideShow(void)
|
|
//
|
|
// Display the "Slide show has ended" alert.
|
|
//
|
|
// External calls: PushPort, MySetPort, StopSpinning, CenterAlert, PopPort
|
|
//=====================================================================================
|
|
|
|
extern Boolean EndSlideShow(void)
|
|
{
|
|
ShowCursor();
|
|
if (!gSlideRoot) {
|
|
MinorError(errNoImagesFound);
|
|
MyInvalMenuBar();
|
|
} else {
|
|
PushPort();
|
|
MySetPort(nil);
|
|
StopSpinning(&qd.arrow);
|
|
FWNoteAlert(CenterAlert(rEndSlidesAlert), gGenericFilter);
|
|
PopPort();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// Boolean NextSlide(void)
|
|
//
|
|
// Switches to the next slide and forces it to be drawn.
|
|
//
|
|
// External calls: ChangeActive, DoCloseWindow, UpdateImage
|
|
//=====================================================================================
|
|
|
|
extern Boolean NextSlide(Boolean *advance)
|
|
{
|
|
ImageHandle loadErrorResult;
|
|
OSErr theErr;
|
|
|
|
// if no slide is ready tell the caller to advance
|
|
if (!gSlideNextImage) *advance = true;
|
|
|
|
// otherwise, process & draw the next slide
|
|
else {
|
|
|
|
// obscure the cursor unless it's under user control
|
|
if (!(*gSlideOptions)->userControl && !GetSlideControlsWindow()) ObscureCursor();
|
|
|
|
// bring the next window to the front
|
|
ChangeActive((*gSlideNextImage)->window);
|
|
|
|
// if we're doing a disk-based slide show, close all other images
|
|
if (!(*gSlideRoot)->mem) {
|
|
ImageHandle oldImage, nextImage;
|
|
for (oldImage = gImageRoot; oldImage; oldImage = nextImage) {
|
|
nextImage = (*oldImage)->next;
|
|
if (oldImage != gSlideNextImage)
|
|
DoCloseWindow((*oldImage)->window, gThePrefs.restoreColors);
|
|
}
|
|
}
|
|
|
|
// handle the update immediately, so we can begin loading the next guy; we
|
|
// do this in a loop so that if we get a pause/resume sequence, we can redraw
|
|
// the image
|
|
do {
|
|
SetSlideControlsText(gString[strSlideDrawing], (*gSlideNextImage)->file.name,
|
|
gNullString, gNullString);
|
|
theErr = UpdateImage(gSlideNextImage);
|
|
ResetSlideTimer();
|
|
|
|
// clear out the next slide pointer and handle any error conditions
|
|
if (theErr != noErr) {
|
|
loadErrorResult = HandleLoadError(theErr, nil);
|
|
if (loadErrorResult == (ImageHandle)kAdvanceSlide) *advance = true;
|
|
else if (loadErrorResult == (ImageHandle)kEndSlideShow) {
|
|
CleanUpSlideShow();
|
|
return false;
|
|
} else if (loadErrorResult == (ImageHandle)kReverseSlide) {
|
|
PointToPreviousSlide();
|
|
*advance = true;
|
|
}
|
|
} else loadErrorResult = nil;
|
|
if (loadErrorResult != (ImageHandle)kReloadSlide) gSlideNextImage = nil;
|
|
} while (loadErrorResult == (ImageHandle)kReloadSlide);
|
|
}
|
|
|
|
// if we hit the end of the slide show, end it now
|
|
if (!(*gSlideOptions)->repeat && DisplayedSlide() == LastSlide()) {
|
|
SetSlideControlButton(kForwardButton, disabled);
|
|
DrawSlideControlsWindow();
|
|
EndSlideShow();
|
|
CleanUpSlideShow();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|