mirror of
https://github.com/aaronsgiles/uuUndo.git
synced 2024-11-24 14:31:25 +00:00
1 line
18 KiB
C
1 line
18 KiB
C
#include <Folders.h>
|
|
#include <ImageCompression.h>
|
|
#include <AppleEvents.h>
|
|
#include "DSDialogs.h"
|
|
#include "DSUserProcs.h"
|
|
#include "DSUtilsASG.h"
|
|
|
|
PrefsHandle gPrefs = nil;
|
|
|
|
Prefs gDefaultPrefs = {
|
|
kVersion,
|
|
false,
|
|
false,
|
|
{ 0, 0 },
|
|
{ 0, 0 }
|
|
};
|
|
|
|
Handle gMapResource = nil;
|
|
|
|
extern void DoMenu ( long retVal );
|
|
|
|
#define kPrefsFileName "\puuUndo Preferences"
|
|
|
|
static Fixed gProgressPercent = 0;
|
|
|
|
//=====================================================================================
|
|
// pascal OSErr GenericProgress(short theMessage, Fixed thePercent, long refCon)
|
|
//=====================================================================================
|
|
// Generic progress procedure, which displays a dialog with a progress bar and a cancel
|
|
// button. This function can be called as often as desired; the display is never
|
|
// updated more than 6 times/second.
|
|
//=====================================================================================
|
|
|
|
pascal OSErr GenericProgress(short theMessage, Fixed thePercent, long refCon)
|
|
{
|
|
static UserItemUPP gUpdateBar = nil;
|
|
static DialogPtr gTheDialog = nil;
|
|
static long gLastTime;
|
|
OSErr theErr = noErr;
|
|
GrafPtr oldPort;
|
|
Point thePoint;
|
|
long ticks;
|
|
|
|
GetPort(&oldPort);
|
|
switch (theMessage) {
|
|
case codecProgressOpen:
|
|
if (gTheDialog = GetNewDialog(rProgressDialog, nil, (WindowPtr)-1)) {
|
|
SetPort(gTheDialog);
|
|
|
|
// set up the user item handler, either for indefinite progress
|
|
// (thePercent == kIndefProgress) or for standard progress
|
|
if (!gUpdateBar) gUpdateBar = NewUserItemProc((ProcPtr)UpdateBar);
|
|
SetItemHandle(gTheDialog, progressUser, (Handle)gUpdateBar);
|
|
SetWindowPosition(gTheDialog, (*gPrefs)->progressLoc);
|
|
UserDialogActivate(FrontWindow(), false);
|
|
ShowWindow(gTheDialog);
|
|
DrawDialog(gTheDialog);
|
|
}
|
|
|
|
// reset the last time so that we draw right away, and update the initial
|
|
// percentage
|
|
gLastTime = 0;
|
|
theErr = GenericProgress(codecProgressForceUpdatePercent, 0, refCon);
|
|
break;
|
|
|
|
case codecProgressForceUpdatePercent:
|
|
gLastTime = 0;
|
|
case codecProgressUpdatePercent:
|
|
if (gTheDialog) {
|
|
|
|
// update our user item no more than 3x a second; do this by setting the
|
|
// gProgressPercent global, and forcing an update of the bar userItem
|
|
if ((TickCount() - gLastTime) < 10L) break;
|
|
gLastTime = TickCount();
|
|
gProgressPercent = thePercent;
|
|
UpdateDialogItem(gTheDialog, progressUser);
|
|
}
|
|
break;
|
|
|
|
case codecProgressClose:
|
|
|
|
// display the final percentage and delay for an instant
|
|
GenericProgress(codecProgressForceUpdatePercent, 0x10000, refCon);
|
|
Delay(1, &ticks);
|
|
GetWindowPosition(gTheDialog, &thePoint);
|
|
(*gPrefs)->progressLoc = thePoint;
|
|
if (gTheDialog) DisposeDialog(gTheDialog);
|
|
gTheDialog = nil;
|
|
UserDialogActivate(FrontWindow(), true);
|
|
break;
|
|
}
|
|
|
|
// restore the original port and check for aborts
|
|
SetPort(oldPort);
|
|
if (theErr == noErr && theMessage != codecProgressForceUpdatePercent) theErr = (CheckAbort()) ? codecAbortErr : noErr;
|
|
|
|
// if there was an abort signalled, and the dialog is visible, hide it immediately
|
|
// to give better user feedback
|
|
if (theErr == codecAbortErr && gTheDialog && ((WindowPeek)gTheDialog)->visible) HideWindow(gTheDialog);
|
|
|
|
return theErr;
|
|
}
|
|
|
|
/*
|
|
* CheckAbort()
|
|
*
|
|
* Purpose: Scans the event queue for an aborting keypress
|
|
* Inputs: none
|
|
* Returns: true if we should abort
|
|
*
|
|
*/
|
|
|
|
Boolean CheckAbort()
|
|
{
|
|
static long gLastTime = 0;
|
|
Boolean aborted = false, callWNE = false;
|
|
EventRecord theEvent;
|
|
GrafPtr oldPort;
|
|
|
|
// if we're not in the background, ensure that we get at least 2 ticks of continuous
|
|
// operation before giving up a full amount of time to others
|
|
if ((TickCount() - gLastTime) >= 5) callWNE = true;
|
|
GetPort(&oldPort);
|
|
SetPort(FrontWindow());
|
|
|
|
// get the next event; if sleepTime is zero, check event availability first
|
|
if (callWNE || EventAvail(everyEvent, &theEvent)) {
|
|
|
|
// handle any pending events normally
|
|
while (WaitNextEvent(everyEvent, &theEvent, 0, nil)) {
|
|
|
|
// dispatch the event as appropriate
|
|
switch (theEvent.what) {
|
|
case mouseDown:
|
|
aborted = HandleAbortMouseDown(&theEvent);
|
|
break;
|
|
|
|
case keyDown:
|
|
case autoKey:
|
|
aborted = HandleAbortKeyDown(&theEvent);
|
|
break;
|
|
|
|
case updateEvt:
|
|
SetPort((WindowPtr)theEvent.message);
|
|
BeginUpdate((WindowPtr)theEvent.message);
|
|
if (((WindowPeek)theEvent.message)->windowKind == dialogKind)
|
|
UpdtDialog((DialogPtr)theEvent.message, ((DialogPtr)theEvent.message)->visRgn);
|
|
EndUpdate((WindowPtr)theEvent.message);
|
|
break;
|
|
|
|
case kHighLevelEvent:
|
|
gProcessing = true;
|
|
AEProcessAppleEvent(&theEvent);
|
|
gProcessing = false;
|
|
break;
|
|
}
|
|
}
|
|
if (callWNE) gLastTime = TickCount();
|
|
}
|
|
SetPort(oldPort);
|
|
return aborted;
|
|
}
|
|
|
|
Boolean GiveTime()
|
|
{
|
|
EventRecord theEvent;
|
|
GrafPtr oldPort;
|
|
|
|
GetPort(&oldPort);
|
|
SetPort(FrontWindow());
|
|
|
|
// handle any pending events normally
|
|
while (WaitNextEvent(everyEvent & ~(mDownMask + keyDownMask + autoKeyMask), &theEvent, 0, nil)) {
|
|
|
|
// dispatch the event as appropriate
|
|
switch (theEvent.what) {
|
|
case updateEvt:
|
|
SetPort((WindowPtr)theEvent.message);
|
|
BeginUpdate((WindowPtr)theEvent.message);
|
|
if (((WindowPeek)theEvent.message)->windowKind == dialogKind)
|
|
UpdtDialog((DialogPtr)theEvent.message, ((DialogPtr)theEvent.message)->visRgn);
|
|
EndUpdate((WindowPtr)theEvent.message);
|
|
break;
|
|
|
|
case kHighLevelEvent:
|
|
gProcessing = true;
|
|
AEProcessAppleEvent(&theEvent);
|
|
gProcessing = false;
|
|
break;
|
|
}
|
|
}
|
|
SetPort(oldPort);
|
|
return true;
|
|
}
|
|
|
|
Boolean HandleAbortMouseDown(EventRecord *theEvent)
|
|
{
|
|
Boolean aborted = false;
|
|
|
|
// handle dialog events properly; if button 3 was hit on the progress dialog,
|
|
// we abort the drawing
|
|
if (IsDialogEvent(theEvent)) {
|
|
DialogPtr theDialog;
|
|
short itemHit;
|
|
SetCursor(&qd.arrow);
|
|
if (DialogSelect(theEvent, &theDialog, &itemHit)) {
|
|
if (GetWRefCon(theDialog) == kProgressDialogID && itemHit == progressCancel) return true;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// otherwise, do it the hard way....
|
|
else {
|
|
WindowPtr theWindow;
|
|
short thePart = FindWindow(theEvent->where, &theWindow);
|
|
|
|
// track dragging and menus as normal; check specially for clicks in
|
|
// the slide show controls floating window, and beep about everything else
|
|
switch (thePart) {
|
|
case inDrag:
|
|
if (theWindow == FrontWindow()) DragWindow(theWindow, theEvent->where, &qd.screenBits.bounds);
|
|
break;
|
|
case inMenuBar:
|
|
SetCursor(&qd.arrow);
|
|
DoMenu ( MenuSelect ( theEvent->where ));
|
|
break;
|
|
default:
|
|
SysBeep(1);
|
|
break;
|
|
}
|
|
}
|
|
return aborted;
|
|
}
|
|
|
|
Boolean HandleAbortKeyDown(EventRecord *theEvent)
|
|
{
|
|
char theChar = theEvent->message & charCodeMask;
|
|
DialogPtr theDialog = FrontWindow();
|
|
Boolean aborted = false;
|
|
|
|
if (GetWRefCon(theDialog) == kProgressDialogID) {
|
|
|
|
// if escape, set the proper abort flag
|
|
if (((theEvent->modifiers & cmdKey) && theChar == '.') || theChar == 0x1b) {
|
|
long ticks;
|
|
aborted = true;
|
|
HiliteDControl(theDialog, progressCancel, 1);
|
|
Delay(8, &ticks);
|
|
HiliteDControl(theDialog, progressCancel, 0);
|
|
}
|
|
}
|
|
return aborted;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// pascal void UpdateBar(DialogPtr theDialog, short theItem)
|
|
//=====================================================================================
|
|
// Draws the progress bar for the generic progress dialog, according to the percentage
|
|
// stored in the global gProgressPercent.
|
|
//=====================================================================================
|
|
|
|
pascal void UpdateBar(DialogPtr theDialog, short theItem)
|
|
{
|
|
static RGBColor gBarBackground = { 0xcccc, 0xcccc, 0xffff };
|
|
static RGBColor gBarForeground = { 0x4000, 0x4000, 0x4000 };
|
|
static RGBColor gBlack = { 0x0000, 0x0000, 0x0000 };
|
|
static RGBColor gWhite = { 0xffff, 0xffff, 0xffff };
|
|
Boolean useBW = !(((CGrafPtr)theDialog)->portVersion & 0xc000) || (*((CGrafPtr)theDialog)->portPixMap)->pixelSize == 1;
|
|
Rect itemRect, leftRect, rightRect;
|
|
Handle itemHandle;
|
|
GrafPtr oldPort;
|
|
Fixed thePercent;
|
|
short itemType;
|
|
|
|
GetPort(&oldPort);
|
|
SetPort(theDialog);
|
|
thePercent = gProgressPercent;
|
|
GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
|
|
PenSize(1, 1);
|
|
if (useBW) PenPat(&qd.black);
|
|
else RGBForeColor(&gBlack);
|
|
FrameRect(&itemRect);
|
|
InsetRect(&itemRect, 1, 1);
|
|
rightRect = leftRect = itemRect;
|
|
leftRect.right = itemRect.left + FixRound(FixMul(thePercent, Long2Fix(itemRect.right - itemRect.left)));
|
|
rightRect.left = leftRect.right;
|
|
if (leftRect.right > leftRect.left) {
|
|
if (useBW) PenPat(&qd.black);
|
|
else RGBForeColor(&gBarForeground);
|
|
PaintRect(&leftRect);
|
|
}
|
|
if (rightRect.left < rightRect.right) {
|
|
if (useBW) PenPat(&qd.white);
|
|
else RGBForeColor(&gBarBackground);
|
|
PaintRect(&rightRect);
|
|
}
|
|
if (useBW) PenPat(&qd.black);
|
|
else RGBForeColor(&gBlack);
|
|
SetPort(oldPort);
|
|
}
|
|
|
|
void SetItemHandle(DialogPtr theDialog, short theItem, Handle newHandle)
|
|
{
|
|
Handle itemHandle;
|
|
short itemType;
|
|
Rect itemRect;
|
|
|
|
GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
|
|
SetDItem(theDialog, theItem, itemType, newHandle, &itemRect);
|
|
}
|
|
|
|
Handle GetItemHandle(DialogPtr theDialog, short theItem)
|
|
{
|
|
Handle itemHandle;
|
|
short itemType;
|
|
Rect itemRect;
|
|
|
|
GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
|
|
return itemHandle;
|
|
}
|
|
|
|
void UpdateDialogItem(DialogPtr theDialog, short theItem)
|
|
{
|
|
Handle itemHandle;
|
|
RgnHandle theRgn;
|
|
short itemType;
|
|
Rect itemRect;
|
|
GrafPtr oldPort;
|
|
|
|
if (theRgn = NewRgn()) {
|
|
GetPort(&oldPort);
|
|
SetPort(theDialog);
|
|
GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
|
|
RectRgn(theRgn, &itemRect);
|
|
UpdateDialog(theDialog, theRgn);
|
|
SetPort(oldPort);
|
|
DisposeRgn(theRgn);
|
|
}
|
|
}
|
|
|
|
void HiliteDControl(DialogPtr theDialog, short theItem, short theVal)
|
|
{
|
|
Handle itemHandle;
|
|
short itemType;
|
|
Rect itemRect;
|
|
GrafPtr oldPort;
|
|
|
|
GetPort(&oldPort);
|
|
SetPort(theDialog);
|
|
GetDItem(theDialog, theItem, &itemType, &itemHandle, &itemRect);
|
|
HiliteControl((ControlHandle)itemHandle, theVal);
|
|
SetPort(oldPort);
|
|
}
|
|
|
|
//==================================================================================================================================
|
|
// OSErr LoadPrefsHandle(OSType type, short index, Handle *theHandle)
|
|
//==================================================================================================================================
|
|
// Reads the specified resource from the Pathmaker preferences file.
|
|
//==================================================================================================================================
|
|
|
|
OSErr LoadPrefsHandle(OSType type, short index, Handle *theHandle)
|
|
{
|
|
return LoadHandleFromResource(GetPrefsSpec(), type, index, theHandle);
|
|
}
|
|
|
|
//==================================================================================================================================
|
|
// OSErr SavePrefsHandle(OSType type, short index, Handle theHandle, short *id)
|
|
//==================================================================================================================================
|
|
// Saves the specified handle to the Pathmaker preferences file as a resource.
|
|
//==================================================================================================================================
|
|
|
|
OSErr SavePrefsHandle(OSType type, short index, Handle theHandle, short *id)
|
|
{
|
|
return SaveHandleAsResource(GetPrefsSpec(), 'pref', type, index, theHandle, id);
|
|
}
|
|
|
|
//==================================================================================================================================
|
|
// OSErr LoadHandleFromResource(FSSpec *file, OSType type, short index, Handle *theHandle)
|
|
// OSErr LoadHandleFromResource(short theFile, OSType type, short index, Handle *theHandle)
|
|
//==================================================================================================================================
|
|
// Reads the specified resource from the given file file and detaches it.
|
|
//==================================================================================================================================
|
|
|
|
OSErr LoadHandleFromResource(FSSpec *file, OSType type, short index, Handle *theHandle)
|
|
{
|
|
OSErr theErr = noErr;
|
|
short theFile = FSpOpenResFile(file, fsRdPerm);
|
|
if (theFile != -1) {
|
|
theErr = LoadHandleFromResource(theFile, type, index, theHandle);
|
|
CloseResFile(theFile);
|
|
} else theErr = ResError();
|
|
return theErr;
|
|
}
|
|
|
|
OSErr LoadHandleFromResource(short theFile, OSType type, short index, Handle *theHandle)
|
|
{
|
|
short oldRes = CurResFile();
|
|
UseResFile(theFile);
|
|
OSErr theErr = noErr;
|
|
if (*theHandle = Get1Resource(type, index)) DetachResource(*theHandle);
|
|
else theErr = fnfErr; // need to signal something since ResError() == 0
|
|
UseResFile(oldRes);
|
|
return theErr;
|
|
}
|
|
|
|
//==================================================================================================================================
|
|
// OSErr SaveHandleAsResource(FSSpec *file, OSType fileType, OSType type, short index, Handle *theHandle, short *id)
|
|
// OSErr SaveHandleAsResource(short theFile, OSType type, short index, Handle theHandle, short *id)
|
|
//==================================================================================================================================
|
|
// Writes the specified handle to the given file as a resource.
|
|
//==================================================================================================================================
|
|
|
|
OSErr SaveHandleAsResource(FSSpec *file, OSType fileType, OSType type, short index, Handle theHandle, short *id)
|
|
{
|
|
OSErr theErr = noErr;
|
|
FSpCreateResFile(file, kCreator, fileType, 0);
|
|
short theFile = FSpOpenResFile(file, fsRdWrPerm);
|
|
if (theFile != -1) {
|
|
theErr = SaveHandleAsResource(theFile, type, index, theHandle, id);
|
|
CloseResFile(theFile);
|
|
} else theErr = ResError();
|
|
return theErr;
|
|
}
|
|
|
|
OSErr SaveHandleAsResource(short theFile, OSType type, short index, Handle theHandle, short *id)
|
|
{
|
|
short oldRes = CurResFile();
|
|
UseResFile(theFile);
|
|
OSErr theErr = noErr;
|
|
if (id) *id = index;
|
|
Handle oldResource = Get1Resource(type, index);
|
|
if (oldResource) {
|
|
RmveResource(oldResource);
|
|
theErr = ResError();
|
|
if (theErr == noErr) {
|
|
DisposeHandle(oldResource);
|
|
UpdateResFile(theFile);
|
|
} else ReleaseResource(oldResource);
|
|
}
|
|
if (theErr == noErr) {
|
|
AddResource(theHandle, type, index, (StringPtr)"\p");
|
|
theErr = ResError();
|
|
if (theErr == noErr) {
|
|
WriteResource(theHandle);
|
|
theErr = ResError();
|
|
if (theErr == noErr) {
|
|
UpdateResFile(theFile);
|
|
theErr = ResError();
|
|
}
|
|
DetachResource(theHandle);
|
|
}
|
|
}
|
|
UseResFile(oldRes);
|
|
return theErr;
|
|
}
|
|
|
|
//==================================================================================================================================
|
|
// FSSpec *GetPrefsSpec(void)
|
|
//==================================================================================================================================
|
|
// Returns an FSSpec pointing to our preferences file.
|
|
//==================================================================================================================================
|
|
|
|
FSSpec *GetPrefsSpec(void)
|
|
{
|
|
static FSSpec theSpec = { 0, 0, "\p" };
|
|
if (!*theSpec.name) {
|
|
FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder, &theSpec.vRefNum, &theSpec.parID);
|
|
FSMakeFSSpec(theSpec.vRefNum, theSpec.parID, kPrefsFileName, &theSpec);
|
|
}
|
|
return &theSpec;
|
|
}
|
|
|
|
void LoadPrefs(void)
|
|
{
|
|
Handle theHandle;
|
|
OSErr theErr = LoadPrefsHandle('Pref', 0, &theHandle);
|
|
if (theErr != noErr) {
|
|
theErr = PtrToHand(&gDefaultPrefs, &theHandle, sizeof(Prefs));
|
|
theErr = SavePrefsHandle('Pref', 0, theHandle);
|
|
}
|
|
gPrefs = (PrefsHandle)theHandle;
|
|
theErr = LoadPrefsHandle('E2Ty', 0, &theHandle);
|
|
if (theErr != noErr) {
|
|
theHandle = Get1Resource('E2Ty', 0);
|
|
if (theHandle) {
|
|
DetachResource(theHandle);
|
|
theErr = SavePrefsHandle('E2Ty', 0, theHandle);
|
|
}
|
|
}
|
|
gMapResource = theHandle;
|
|
}
|
|
|
|
void SavePrefs(void)
|
|
{
|
|
OSErr theErr = SavePrefsHandle('Pref', 0, (Handle)gPrefs);
|
|
if (theErr == noErr) theErr = SavePrefsHandle('E2Ty', 0, gMapResource);
|
|
}
|
|
|
|
void SetWindowPosition(WindowPtr theWindow, Point thePosition)
|
|
{
|
|
Point centerPos;
|
|
Rect monRect;
|
|
|
|
if (gHasCQD) monRect = (*GetMainDevice())->gdRect;
|
|
else monRect = qd.screenBits.bounds;
|
|
|
|
centerPos.h = (monRect.right - monRect.left) - (theWindow->portRect.right - theWindow->portRect.left);
|
|
centerPos.v = (monRect.bottom - monRect.top) - (theWindow->portRect.bottom - theWindow->portRect.top);
|
|
centerPos.h /= 2;
|
|
centerPos.v /= 3;
|
|
centerPos.h += monRect.left;
|
|
centerPos.v += monRect.top + 20;
|
|
if (thePosition.h || thePosition.v) {
|
|
Rect newRect = theWindow->portRect;
|
|
RgnHandle theRgn;
|
|
OffsetRect(&newRect, thePosition.h - newRect.left, thePosition.v - newRect.top);
|
|
if (theRgn = NewRgn()) {
|
|
SetRectRgn(theRgn, newRect.left + 4, newRect.top - 20 + 4, newRect.right - 4, newRect.top - 4);
|
|
SectRgn(theRgn, GetGrayRgn(), theRgn);
|
|
if (EmptyRgn(theRgn)) thePosition = centerPos;
|
|
DisposeRgn(theRgn);
|
|
}
|
|
} else thePosition = centerPos;
|
|
MoveWindow(theWindow, thePosition.h, thePosition.v, false);
|
|
}
|
|
|
|
void GetWindowPosition(WindowPtr theWindow, Point *thePosition)
|
|
{
|
|
GrafPtr oldPort;
|
|
GetPort(&oldPort);
|
|
SetPort(theWindow);
|
|
thePosition->h = thePosition->v = 0;
|
|
LocalToGlobal(thePosition);
|
|
SetPort(oldPort);
|
|
}
|
|
|
|
void ForceFolderUpdate(long dirID, short vRefNum)
|
|
{
|
|
static CInfoPBRec block;
|
|
|
|
block.hFileInfo.ioCompletion = nil;
|
|
block.hFileInfo.ioNamePtr = nil;
|
|
block.hFileInfo.ioVRefNum = vRefNum;
|
|
block.hFileInfo.ioDirID = dirID;
|
|
block.hFileInfo.ioFDirIndex = -1;
|
|
PBGetCatInfoAsync(&block);
|
|
while (block.hFileInfo.ioResult == 1) GiveTime();
|
|
GetDateTime(&block.dirInfo.ioDrMdDat);
|
|
PBSetCatInfoAsync(&block);
|
|
// while (block.hFileInfo.ioResult == 1) GiveTime();
|
|
}
|