mirror of
https://github.com/aaronsgiles/JPEGView.git
synced 2024-06-06 21:29:27 +00:00
92bdb55672
These are the sources for the final official release of JPEGView for the Mac, back in 1994.
1 line
16 KiB
C
1 line
16 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 "FileMenu.h"
|
|
|
|
//===================================================================================
|
|
// OpenData: Contains options information that is set from within the Open dialog.
|
|
//===================================================================================
|
|
|
|
typedef struct
|
|
{
|
|
Boolean showAll;
|
|
short lastVRef;
|
|
long lastDir;
|
|
} OpenData, *OpenDataPtr, **OpenDataHandle;
|
|
|
|
//===================================================================================
|
|
// SaveData: Contains options information that is set from within the Save dialog.
|
|
//===================================================================================
|
|
|
|
typedef struct
|
|
{
|
|
Boolean preview, close, palette, icons;
|
|
short cropWhat;
|
|
ImageFormatPtr format;
|
|
ImageFormatPtr formatList[kFileFormats];
|
|
ImageHandle image;
|
|
MenuHandle menuHandle;
|
|
MenuHandle cropHandle;
|
|
} SaveData, *SaveDataPtr, **SaveDataHandle;
|
|
|
|
//=====================================================================================
|
|
// Global variables local to this module
|
|
//=====================================================================================
|
|
|
|
static DlgHookYDUPP gOpenDialogHook = nil, gSaveDialogHook = nil;
|
|
static FileFilterYDUPP gOpenFileFilter = nil;
|
|
static OpenData gOpenData;
|
|
static SaveData gSaveData;
|
|
|
|
//=====================================================================================
|
|
// Prototypes for functions local to this module
|
|
//=====================================================================================
|
|
|
|
static void InitSaveMenu(ImageHandle theImage, DialogPtr theDialog);
|
|
static void DoPageSetup(void);
|
|
|
|
//===================================================================================
|
|
// void HandleFileChoice(short theItem)
|
|
//===================================================================================
|
|
// Dispatches selections from the File menu to the appropriate function.
|
|
//===================================================================================
|
|
|
|
void HandleFileChoice(short theItem)
|
|
{
|
|
switch (theItem) {
|
|
case fileImportItem:
|
|
gOpenData.showAll = true;
|
|
DoOpenDialog();
|
|
break;
|
|
case fileOpenItem:
|
|
gOpenData.showAll = false;
|
|
DoOpenDialog();
|
|
break;
|
|
case fileCloseItem:
|
|
SendCloseWindow(FWFrontWindow());
|
|
break;
|
|
case fileCloseAllItem:
|
|
SendCloseWindow((WindowPtr)kAEAll);
|
|
break;
|
|
case fileSaveItem:
|
|
DoSaveDialog();
|
|
break;
|
|
case fileSlideItem:
|
|
SendCreateWindow(kSlideShowDialogID);
|
|
break;
|
|
case fileStartSlideItem:
|
|
if (gSlideShow) gPendingButton = kPauseButton;
|
|
else SendSlideShow();
|
|
break;
|
|
case fileEndSlideItem:
|
|
gPendingButton = kStopButton;
|
|
break;
|
|
case filePageSetupItem:
|
|
DoPageSetup();
|
|
break;
|
|
case filePrintItem:
|
|
if (FrontImage()) SendPrintDocument(FrontImage());
|
|
break;
|
|
case filePrefsItem:
|
|
SendCreateWindow(kPrefsDialogID);
|
|
break;
|
|
case fileQuitItem:
|
|
SendQuitApplication();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* DoOpenDialog()
|
|
*
|
|
* Purpose: Presents the JPEGView custom open dialog & sends the
|
|
* open document AppleEvent
|
|
* Inputs: none
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void DoOpenDialog(void)
|
|
{
|
|
Point where = CenterDialogWhere((gQTVersion) ? rOpenDialog : rOpenDialogNoQT);
|
|
StandardFileReply reply;
|
|
|
|
StartSpinning();
|
|
PushPort();
|
|
MySetPort(nil);
|
|
if (!gOpenFileFilter)
|
|
gOpenFileFilter = NewFileFilterYDProc((ProcPtr)OpenFileFilter);
|
|
if (!gOpenDialogHook)
|
|
gOpenDialogHook = NewDlgHookYDProc((ProcPtr)OpenDialogHook);
|
|
RequestForeground();
|
|
if (gQTVersion) CustomGetFilePreview(gOpenFileFilter, -1, 0, &reply, rOpenDialog, where,
|
|
gOpenDialogHook, gOpenSaveModalFilter, nil, nil, &reply);
|
|
else CustomGetFile(gOpenFileFilter, -1, 0, &reply, rOpenDialogNoQT, where,
|
|
gOpenDialogHook, gOpenSaveModalFilter, nil, nil, &reply);
|
|
PopPort();
|
|
if (reply.sfGood) SendOpenDocument(&reply.sfFile);
|
|
}
|
|
|
|
/*
|
|
* OpenSaveModalFilter(theDialog, theEvent, itemHit, yourDataPtr)
|
|
*
|
|
* Purpose: Filter for handling update events
|
|
* Inputs: theDialog = pointer to the dialog
|
|
* theEvent = pointer to an event record
|
|
* itemHit = the item number that was "hit"
|
|
* yourDataPtr = the refcon
|
|
* Returns: true if we want ModalDialog to continue processing the event
|
|
*
|
|
*/
|
|
|
|
extern pascal Boolean OpenSaveModalFilter(DialogPtr theDialog, EventRecord *theEvent,
|
|
short *itemHit, void *yourDataPtr)
|
|
{
|
|
#if applec
|
|
#pragma unused(theDialog, itemHit, yourDataPtr)
|
|
#endif
|
|
Boolean isDialogEvent = IsDialogEvent(theEvent);
|
|
switch (theEvent->what) {
|
|
case updateEvt:
|
|
if (isDialogEvent) HandleUpdateDialog(theEvent);
|
|
else HandleUpdateEvent(theEvent);
|
|
break;
|
|
case activateEvt:
|
|
if (isDialogEvent) HandleActivateDialog(theEvent);
|
|
else HandleActivateEvent(theEvent);
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* OpenFileFilter(pb, dummy)
|
|
*
|
|
* Purpose: Called by CustomGetFilePreview to allow us to filter out certain types
|
|
* of files; here, depending on the status of the Show All Files button,
|
|
* we either allow all files or only PICT/JFIF/JPEG/GIFf files
|
|
* Inputs: pb = parameter block for the current file
|
|
* dummy = a dummy reference constant
|
|
* Returns: false to include the file, true otherwise
|
|
*
|
|
*/
|
|
|
|
pascal Boolean OpenFileFilter(CInfoPBPtr pb, Boolean *dummy)
|
|
{
|
|
#if applec
|
|
#pragma unused(dummy)
|
|
#endif
|
|
OSType theType = pb->hFileInfo.ioFlFndrInfo.fdType;
|
|
|
|
if (pb->dirInfo.ioDrUsrWds.frFlags & fInvisible) return true;
|
|
return !((pb->hFileInfo.ioFlAttrib & 0x10) || ValidType(theType) || gOpenData.showAll);
|
|
}
|
|
|
|
extern Boolean ValidType(OSType theType)
|
|
{
|
|
short i;
|
|
|
|
for (i = 0; i < kFileFormats; i++)
|
|
if (gFormat[i]->inType == theType || gFormat[i]->altInType == theType) return true;
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* OpenDialogHook(item, theDialog, dummy)
|
|
*
|
|
* Purpose: Called by CustomGetFilePreview to allow us to respond to our custom
|
|
* dialog items; here we have only one, the Show All Files button
|
|
* Inputs: item = the dialog item number that was hit
|
|
* theDialog = pointer to the dialog window record
|
|
* dummy = dummy reference constant
|
|
* Returns: the item that was hit, or sfHookRebuildList to redisply the files
|
|
*
|
|
*/
|
|
|
|
pascal short OpenDialogHook(short item, DialogPtr theDialog, long dummy)
|
|
{
|
|
static short gLastItem = 0, gLastVRefNum = 555;
|
|
SysEnvRec theEnvirons;
|
|
|
|
if (GetWRefCon(theDialog) != sfMainDialogRefCon) return item;
|
|
if (gLastItem == sfItemEjectButton) {
|
|
SysEnvirons(1, &theEnvirons);
|
|
if (theEnvirons.sysVRefNum != gLastVRefNum) {
|
|
UnmountVol(0, gLastVRefNum);
|
|
Eject(0, gLastVRefNum);
|
|
}
|
|
}
|
|
switch (item) {
|
|
case sfHookFirstCall:
|
|
HiliteMenu(0);
|
|
FWDeactivate();
|
|
StopSpinning(&qd.arrow);
|
|
break;
|
|
case sfHookLastCall:
|
|
FWActivate();
|
|
break;
|
|
case openScanButton:
|
|
StartSpinning();
|
|
ScanDirFiles();
|
|
DisableDControl(theDialog, openScanButton);
|
|
StopSpinning(&qd.arrow);
|
|
item = sfHookRebuildList;
|
|
break;
|
|
default:
|
|
if ((gOpenData.lastVRef != -LMGetSFSaveDisk()) ||
|
|
(gOpenData.lastDir != LMGetCurDirStore()))
|
|
EnableDControl(theDialog, openScanButton);
|
|
break;
|
|
}
|
|
gLastVRefNum = ((StandardFileReply *)dummy)->sfFile.vRefNum;
|
|
return gLastItem = item;
|
|
}
|
|
|
|
/*
|
|
* ScanDirFiles()
|
|
*
|
|
* Purpose: Scans the current standard file directory for valid input files; if it
|
|
* finds some, it changes their types accordingly
|
|
* Inputs: none
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void ScanDirFiles(void)
|
|
{
|
|
short theFile, fileType;
|
|
CInfoPBRec block;
|
|
Str255 fileName;
|
|
OSType theType;
|
|
FSSpec theSpec;
|
|
FInfo theInfo;
|
|
|
|
block.hFileInfo.ioNamePtr = fileName;
|
|
block.hFileInfo.ioVRefNum = -LMGetSFSaveDisk();
|
|
block.hFileInfo.ioDirID = LMGetCurDirStore();
|
|
block.hFileInfo.ioFDirIndex = 1;
|
|
while (PBGetCatInfo(&block, false) == noErr) {
|
|
KeepSpinning();
|
|
theType = block.hFileInfo.ioFlFndrInfo.fdType;
|
|
if (!(block.hFileInfo.ioFlAttrib & 0x10) && !ValidType(theType)) {
|
|
FSMakeFSSpec(-LMGetSFSaveDisk(), block.hFileInfo.ioFlParID, fileName, &theSpec);
|
|
if (FSpOpenDF(&theSpec, fsRdPerm, &theFile) == noErr) {
|
|
fileType = IDImage(theFile, &theSpec);
|
|
FSClose(theFile);
|
|
if (fileType != kInvalidType) {
|
|
FSpGetFInfo(&theSpec, &theInfo);
|
|
theInfo.fdType = gFormat[fileType]->inType;
|
|
theInfo.fdCreator = kCreator;
|
|
FSpSetFInfo(&theSpec, &theInfo);
|
|
}
|
|
}
|
|
}
|
|
block.hFileInfo.ioFDirIndex++;
|
|
block.hFileInfo.ioDirID = LMGetCurDirStore();
|
|
}
|
|
gOpenData.lastDir = LMGetCurDirStore();
|
|
gOpenData.lastVRef = -LMGetSFSaveDisk();
|
|
ForceFolderUpdate(LMGetCurDirStore(), -LMGetSFSaveDisk());
|
|
}
|
|
|
|
/*
|
|
* DoSaveDialog()
|
|
*
|
|
* Purpose: Presents the JPEGView save dialog and sends the save document AppleEvent
|
|
* Inputs: none
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void DoSaveDialog(void)
|
|
{
|
|
Point where = CenterDialogWhere(rSaveDialog);
|
|
ImageHandle theImage = FrontImage();
|
|
StandardFileReply reply;
|
|
Str255 defaultName;
|
|
OSErr theErr;
|
|
|
|
StartSpinning();
|
|
gSaveData.image = theImage;
|
|
gSaveData.format = (*theImage)->format;
|
|
gSaveData.preview = gThePrefs.savePrev;
|
|
gSaveData.icons = gThePrefs.makeIcons;
|
|
gSaveData.close = gSaveData.palette = false;
|
|
if ((*theImage)->qpalette && gSaveData.format->doesColors) {
|
|
if (gThePrefs.saveQuant == sqAlways) gSaveData.palette = true;
|
|
else if (gThePrefs.saveQuant == sqOnly) gSaveData.palette = !(*theImage)->ipalette;
|
|
}
|
|
gSaveData.cropWhat = kCropNothing;
|
|
BlockMove((*theImage)->file.name, defaultName, 64);
|
|
PushPort();
|
|
MySetPort(nil);
|
|
FWDeactivate();
|
|
if (!gSaveDialogHook) gSaveDialogHook = NewDlgHookYDProc((ProcPtr)SaveDialogHook);
|
|
RequestForeground();
|
|
CustomPutFile(gNullString, defaultName, &reply,
|
|
((*theImage)->compression == kJPEGCompression) ? rSaveDialog : rSimpleSaveDialog,
|
|
where, gSaveDialogHook, gOpenSaveModalFilter, nil, nil, 0);
|
|
PopPort();
|
|
if (reply.sfGood) {
|
|
if (!reply.sfReplacing) {
|
|
theErr = FSpCreate(&reply.sfFile, kCreator, gSaveData.format->outType,
|
|
reply.sfScript);
|
|
if (theErr != noErr) {
|
|
StringError(errCantCreateFile, reply.sfFile.name);
|
|
return;
|
|
}
|
|
}
|
|
theErr = SendSaveDocument(&reply.sfFile, gSaveData.format->outType,
|
|
gSaveData.preview && gQTVersion,
|
|
gSaveData.palette && gSaveData.format->doesColors &&
|
|
(*gSaveData.image)->depth > 8 &&
|
|
(*gSaveData.image)->compression == kJPEGCompression,
|
|
gSaveData.icons, gSaveData.cropWhat);
|
|
if (theErr == noErr) {
|
|
if (gSaveData.close) SendCloseWindow((*theImage)->window);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void InitSaveMenu(ImageHandle theImage, DialogPtr theDialog)
|
|
{
|
|
short itemType, i, startValue = 1, pictItem = 0, count = 0;
|
|
Handle itemHandle;
|
|
Rect itemRect;
|
|
|
|
// first get the handle to the pop-up menu
|
|
GetDItem(theDialog, savePopupMenu, &itemType, &itemHandle, &itemRect);
|
|
if (itemHandle) gSaveData.menuHandle =
|
|
(*(PopupPrivateDataHandle)(*(ControlHandle)itemHandle)->contrlData)->mHandle;
|
|
|
|
// now loop over all formats, adding them all, but only enabling those that match the
|
|
// input format, as well as any formats that have a fix routine, but then only if the
|
|
// image compression is 'jpeg'
|
|
for (i = 0; i < kFileFormats; i++) {
|
|
if (gFormat[i] == (*theImage)->format ||
|
|
(gFormat[i]->fix && (*theImage)->compression == kJPEGCompression)) {
|
|
AppendMenu(gSaveData.menuHandle, (StringPtr)"\p( ");
|
|
gSaveData.formatList[count] = gFormat[i];
|
|
SetItem(gSaveData.menuHandle, ++count, gFormat[i]->formatName);
|
|
if (gFormat[i]->outType == kPICTType) pictItem = count;
|
|
if (gFormat[i] == (*theImage)->format) startValue = count;
|
|
if (Banded(theImage) && !gFormat[i]->doesBanded) continue;
|
|
EnableItem(gSaveData.menuHandle, count);
|
|
}
|
|
}
|
|
if (gThePrefs.savePICT && (*theImage)->format->inType == kJPEGType) {
|
|
startValue = pictItem;
|
|
gSaveData.format = &gPICTFormat;
|
|
}
|
|
SetCtlMax((ControlHandle)itemHandle, count);
|
|
SetCtlValue((ControlHandle)itemHandle, startValue);
|
|
|
|
// next get the handle to the cropping pop-up menu
|
|
GetDItem(theDialog, saveCropMenu, &itemType, &itemHandle, &itemRect);
|
|
if (itemHandle) gSaveData.cropHandle =
|
|
(*(PopupPrivateDataHandle)(*(ControlHandle)itemHandle)->contrlData)->mHandle;
|
|
}
|
|
|
|
/*
|
|
* UpdateSaveButtons(theDialog)
|
|
*
|
|
* Purpose: Updates the state of the custom buttons in the save dialog
|
|
* Inputs: theDialog
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void UpdateSaveButtons(DialogPtr theDialog)
|
|
{
|
|
ImageHandle theImage = gSaveData.image;
|
|
Boolean enabled;
|
|
|
|
SetDCtlValue(theDialog, saveCloseBox, gSaveData.close);
|
|
enabled = (gQTVersion != 0);
|
|
if (enabled) EnableDControl(theDialog, savePreviewBox);
|
|
else DisableDControl(theDialog, savePreviewBox);
|
|
SetDCtlValue(theDialog, savePreviewBox, gSaveData.preview && enabled);
|
|
enabled = gSaveData.format->doesColors && (*gSaveData.image)->depth > 8 && (*gSaveData.image)->compression == kJPEGCompression;
|
|
if (enabled) EnableDControl(theDialog, savePaletteBox);
|
|
else DisableDControl(theDialog, savePaletteBox);
|
|
SetDCtlValue(theDialog, savePaletteBox, gSaveData.palette && enabled);
|
|
SetDCtlValue(theDialog, saveIconsBox, gSaveData.icons);
|
|
if (!gSaveData.icons && gSaveData.cropWhat == kCropIcon) SetDCtlValue(theDialog, saveCropMenu, kCropNothing + 1);
|
|
if (gSaveData.icons) EnableItem(gSaveData.cropHandle, kCropIcon + 1);
|
|
else DisableItem(gSaveData.cropHandle, kCropIcon + 1);
|
|
}
|
|
|
|
/*
|
|
* SaveDialogHook(item, theDialog, dummy)
|
|
*
|
|
* Purpose: Called by CustomPutFile to allow us to respond to our custom
|
|
* dialog items; here we have only one, the Show All Files button
|
|
* Inputs: item = the dialog item number that was hit
|
|
* theDialog = pointer to the dialog window record
|
|
* dummy = dummy reference constant
|
|
* Returns: the item that was hit
|
|
*
|
|
*/
|
|
|
|
pascal short SaveDialogHook(short item, DialogPtr theDialog, long dummy)
|
|
{
|
|
#if applec
|
|
#pragma unused(dummy)
|
|
#endif
|
|
short newValue;
|
|
|
|
if (GetWRefCon(theDialog) != sfMainDialogRefCon) return item;
|
|
switch (item) {
|
|
case sfHookFirstCall:
|
|
SetItemHandle(theDialog, saveLineUser1, (Handle)gLineItem);
|
|
SetItemHandle(theDialog, saveLineUser2, (Handle)gLineItem);
|
|
SetItemHandle(theDialog, saveLineUser3, (Handle)gLineItem);
|
|
if (!AntsHaveSelection((*gSaveData.image)->ants)) DisableDControl(theDialog, saveCropMenu);
|
|
InitSaveMenu(gSaveData.image, theDialog);
|
|
UpdateSaveButtons(theDialog);
|
|
FWDeactivate();
|
|
StopSpinning(&qd.arrow);
|
|
return item;
|
|
case sfHookLastCall:
|
|
FWActivate();
|
|
return item;
|
|
case saveCloseBox:
|
|
gSaveData.close = !gSaveData.close;
|
|
break;
|
|
case savePopupMenu:
|
|
newValue = GetDCtlValue(theDialog, savePopupMenu);
|
|
gSaveData.format = gSaveData.formatList[newValue - 1];
|
|
break;
|
|
case savePreviewBox:
|
|
gSaveData.preview = !gSaveData.preview;
|
|
break;
|
|
case savePaletteBox:
|
|
gSaveData.palette = !gSaveData.palette;
|
|
break;
|
|
case saveIconsBox:
|
|
gSaveData.icons = !gSaveData.icons;
|
|
break;
|
|
case saveCropMenu:
|
|
gSaveData.cropWhat = GetDCtlValue(theDialog, saveCropMenu) - 1;
|
|
break;
|
|
default:
|
|
return item;
|
|
}
|
|
UpdateSaveButtons(theDialog);
|
|
return sfHookNullEvent;
|
|
}
|
|
|
|
static void DoPageSetup(void)
|
|
{
|
|
PrOpen();
|
|
if (!gPrintRecord) {
|
|
if (LoadPrefsHandle(kPrefsPrintType, 0, (Handle *)&gPrintRecord) != noErr) {
|
|
if (!(gPrintRecord = (THPrint)NewHandle(sizeof(TPrint)))) {
|
|
MinorError(errNoMemory);
|
|
return;
|
|
}
|
|
PrintDefault(gPrintRecord);
|
|
} else PrValidate(gPrintRecord);
|
|
}
|
|
FWDeactivate();
|
|
PrStlDialog(gPrintRecord);
|
|
FWActivate();
|
|
PrClose();
|
|
SavePrefsHandle(kPrefsPrintType, 0, (Handle)gPrintRecord);
|
|
}
|