uuUndo/DSUtilsASG.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();
}