mirror of
https://github.com/nickshanks/ResKnife.git
synced 2024-06-03 01:29:40 +00:00
1803 lines
57 KiB
C++
1803 lines
57 KiB
C++
#include "FileWindow.h"
|
||
#include "Application.h"
|
||
#include "Asynchronous.h"
|
||
#include "ResourceObject.h"
|
||
#include "Errors.h"
|
||
#include "InspectorWindow.h"
|
||
#include "PlugObject.h" // for LoadEditor()
|
||
#include "PickerWindow.h"
|
||
#include "Utility.h"
|
||
extern globals g;
|
||
|
||
#pragma mark Constructor
|
||
|
||
/*** FILE WINDOW CONSTRUCTOR ***/
|
||
FileWindow::FileWindow(FSSpecPtr spec)
|
||
{
|
||
OSStatus error = noErr;
|
||
|
||
#if USE_NIBS
|
||
// create a nib reference (only searches the application bundle)
|
||
IBNibRef nibRef = null;
|
||
error = CreateNibReference(CFSTR("ResKnife"), &nibRef);
|
||
if(error != noErr || nibRef == null)
|
||
{
|
||
DisplayError("\pThe nib file reference could not be obtained.");
|
||
return;
|
||
}
|
||
|
||
// create window
|
||
error = CreateWindowFromNib(nibRef, CFSTR("File Window"), &window);
|
||
if(error != noErr || window == null)
|
||
{
|
||
DisposeNibReference(nibRef);
|
||
DisplayError("\pA file window could not be obtained from the nib file.");
|
||
return;
|
||
}
|
||
|
||
// dispose of nib ref
|
||
DisposeNibReference(nibRef);
|
||
|
||
#elif TARGET_API_MAC_CARBON
|
||
// create window
|
||
Rect creationBounds, sectRect;
|
||
SetRect(&creationBounds, 0, 0, kDefaultFileWindowWidth, kDefaultFileWindowHeight);
|
||
GetAvailableWindowPositioningBounds(GetMainDevice(), §Rect);
|
||
InsetRect(§Rect, 0, 10);
|
||
SectRect(§Rect, &creationBounds, &creationBounds);
|
||
OffsetRect(&creationBounds, 10, 0);
|
||
WindowAttributes attributes = kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute;
|
||
if(g.systemVersion >= kMacOSX) attributes |= kWindowLiveResizeAttribute;
|
||
error = CreateNewWindow(kDocumentWindowClass, attributes, &creationBounds, &window);
|
||
if(error) return;
|
||
#else
|
||
if(g.useAppearance && g.systemVersion >= kMacOS8)
|
||
{
|
||
window = GetNewCWindow(kFileWindow8, null, kFirstWindowOfClass);
|
||
themeSavvy = true;
|
||
}
|
||
else
|
||
{
|
||
window = GetNewCWindow(kFileWindow7, null, kFirstWindowOfClass);
|
||
themeSavvy = false;
|
||
}
|
||
#endif
|
||
|
||
// save FileWindow class in window's refcon
|
||
SetWindowRefCon(window, (UInt32) this);
|
||
SetWindowKind(window, kFileWindowKind);
|
||
SetWindowTitle(window, spec->name);
|
||
#if TARGET_API_MAC_CARBON
|
||
// set title used in window menu
|
||
SetWindowAlternateTitle(window, null); // bug: should use path here
|
||
#endif
|
||
|
||
// set window's background to default for theme
|
||
if(g.useAppearance)
|
||
SetThemeWindowBackground(window, kThemeBrushModelessDialogBackgroundActive, false);
|
||
|
||
#if USE_NIBS // Carbon nib file on Public Beta doesn't let me set this
|
||
WindowAttributes setThese = null, clearThese = null;
|
||
setThese = kWindowInWindowMenuAttribute;
|
||
ChangeWindowAttributes(window, setThese, clearThese);
|
||
#endif
|
||
|
||
// initalise file variables
|
||
fileSpec = (FSSpecPtr) NewPtrClear(sizeof(FSSpec));
|
||
tempSpec = (FSSpecPtr) NewPtrClear(sizeof(FSSpec));
|
||
fileDirty = false;
|
||
SetFileSpec(spec);
|
||
#if TARGET_API_MAC_CARBON
|
||
dataBrowser = null;
|
||
#endif
|
||
|
||
// initalise resource variables
|
||
numTypes = 0;
|
||
numResources = 0;
|
||
dataFork = null;
|
||
resourceMap = null;
|
||
|
||
#if TARGET_API_MAC_CARBON
|
||
// install window event handler
|
||
EventHandlerRef ref = null;
|
||
EventHandlerUPP handler = NewEventHandlerUPP(FileWindowEventHandler);
|
||
EventTypeSpec events[] = { { kEventClassWindow, kEventWindowClose },
|
||
{ kEventClassWindow, kEventWindowBoundsChanging },
|
||
{ kEventClassWindow, kEventWindowBoundsChanged },
|
||
{ kEventClassWindow, kEventWindowGetIdealSize },
|
||
{ kEventClassWindow, kEventWindowZoomed } };
|
||
InstallWindowEventHandler(window, handler, GetEventTypeCount(events), (EventTypeSpec *) &events, this, &ref);
|
||
|
||
EventTypeSpec update = { kEventClassMenu, kEventMenuEnableItems };
|
||
EventTypeSpec process = { kEventClassCommand, kEventCommandProcess };
|
||
|
||
// install menu update handler
|
||
handler = NewEventHandlerUPP(FileWindowUpdateMenus);
|
||
InstallWindowEventHandler(window, handler, 1, &update, this, &ref);
|
||
|
||
// install menu selection handler
|
||
handler = NewEventHandlerUPP(FileWindowParseMenuSelection);
|
||
InstallWindowEventHandler(window, handler, 1, &process, this, &ref);
|
||
#endif
|
||
|
||
#if USE_NIBS
|
||
// set window property
|
||
ControlRef dataBrowser;
|
||
ControlID id = { kDataBrowserSignature, 0 };
|
||
GetControlByID(window, &id, &dataBrowser);
|
||
SetWindowProperty(window, kResKnifeCreator, kWindowPropertyDataBrowser, sizeof(ControlRef), &dataBrowser);;
|
||
|
||
#elif TARGET_API_MAC_CARBON // CarbonLib 1.1+ only
|
||
// create root control
|
||
ControlRef root;
|
||
CreateRootControl(window, &root);
|
||
|
||
// create header control
|
||
Rect windowBounds, rect;
|
||
GetWindowPortBounds(window, &windowBounds);
|
||
SetRect(&rect, windowBounds.left, windowBounds.top, windowBounds.right, windowBounds.bottom);
|
||
InsetRect(&rect, -1, -1);
|
||
rect.bottom = rect.top + kDefaultHeaderHeight +1;
|
||
CreateWindowHeaderControl(window, &rect, true, &header);
|
||
ControlID id = { kHeaderSignature, 0 };
|
||
SetControlID(header, &id);
|
||
|
||
// create text controls
|
||
ControlFontStyleRec fontStyle;
|
||
fontStyle.flags = kControlUseFontMask + kControlUseJustMask;
|
||
fontStyle.font = kControlFontSmallSystemFont;
|
||
fontStyle.just = teJustLeft;
|
||
SetRect(&rect, windowBounds.left +4, windowBounds.top +4, (windowBounds.right - windowBounds.left) /5 *3, windowBounds.top + kDefaultHeaderHeight -4);
|
||
CreateStaticTextControl(window, &rect, CFSTR("left"), &fontStyle, &left);
|
||
id.id = 0;
|
||
id.signature = kLeftTextSignature;
|
||
SetControlID(left, &id);
|
||
|
||
fontStyle.just = teJustRight;
|
||
SetRect(&rect, (windowBounds.right - windowBounds.left) /5 *2, windowBounds.top +4, windowBounds.right -4, windowBounds.top + kDefaultHeaderHeight -4);
|
||
CreateStaticTextControl(window, &rect, CFSTR("right"), &fontStyle, &right);
|
||
id.id = 0;
|
||
id.signature = kRightTextSignature;
|
||
SetControlID(right, &id);
|
||
|
||
// embed text controls within header
|
||
EmbedControl(left, header);
|
||
EmbedControl(right, header);
|
||
|
||
// create data browser
|
||
SetRect(&rect, windowBounds.left, windowBounds.top + kDefaultHeaderHeight +1, windowBounds.right, windowBounds.bottom);
|
||
CreateDataBrowserControl(window, &rect, kDataBrowserListView, &dataBrowser);
|
||
id.id = 0;
|
||
id.signature = kDataBrowserSignature;
|
||
SetControlID(dataBrowser, &id);
|
||
SetControlReference(dataBrowser, (UInt32) this);
|
||
SetWindowProperty(window, kResKnifeCreator, kWindowPropertyDataBrowser, sizeof(ControlRef), &dataBrowser);
|
||
SetKeyboardFocus(window, dataBrowser, kControlDataBrowserPart);
|
||
|
||
#elif !TARGET_API_MAC_CARBON
|
||
// create controls
|
||
if(themeSavvy)
|
||
{
|
||
// create basic window controls
|
||
header = GetNewControl(kFileHeaderControl, window);
|
||
horizScroll = GetNewControl(kAppearanceScrollBarControl, window);
|
||
vertScroll = GetNewControl(kAppearanceScrollBarControl, window);
|
||
|
||
// create sort buttons
|
||
Rect bounds = {};
|
||
sortName = NewControl(window, &bounds, "\pName", true, 0, kControlBehaviorSticky + kControlContentTextOnly, 0, kControlBevelButtonSmallBevelProc, 0);
|
||
sortType = NewControl(window, &bounds, "\pType", true, 0, kControlBehaviorSticky + kControlContentTextOnly, 0, kControlBevelButtonSmallBevelProc, 0);
|
||
sortID = NewControl(window, &bounds, "\pID", true, 0, kControlBehaviorSticky + kControlContentTextOnly, 0, kControlBevelButtonSmallBevelProc, 0);
|
||
sortSize = NewControl(window, &bounds, "\pSize", true, 0, kControlBehaviorSticky + kControlContentTextOnly, 0, kControlBevelButtonSmallBevelProc, 0);
|
||
sortAttrs = NewControl(window, &bounds, "\pAttributes", true, 0, kControlBehaviorSticky + kControlContentTextOnly, 0, kControlBevelButtonSmallBevelProc, 0);
|
||
sortDir = NewControl(window, &bounds, "\p", true, 0, kControlContentIconSuiteRes, kSortUpIcon, kControlBevelButtonSmallBevelProc, 0);
|
||
nameColumnWidth = kFileWindowDefaultNameColumnWidth;
|
||
|
||
// put the text in the right place
|
||
SetBevelButtonTextAlignment(sortName, kControlBevelButtonAlignTextFlushLeft, kFileWindowNameColumnTextOffset -1);
|
||
SetBevelButtonTextAlignment(sortType, kControlBevelButtonAlignTextFlushRight, 5);
|
||
SetBevelButtonTextAlignment(sortSize, kControlBevelButtonAlignTextFlushRight, 5);
|
||
SetBevelButtonTextAlignment(sortID, kControlBevelButtonAlignTextFlushRight, 5);
|
||
SetBevelButtonTextAlignment(sortAttrs, kControlBevelButtonAlignTextCenter, 0);
|
||
|
||
// set up font details
|
||
ControlFontStylePtr fontStyle = (ControlFontStylePtr) NewPtrClear(sizeof(ControlFontStyleRec));
|
||
fontStyle->flags = kControlUseFontMask + kControlUseSizeMask;
|
||
fontStyle->font = kControlFontSmallSystemFont;
|
||
|
||
// apply font details to controls
|
||
SetControlFontStyle(sortName, fontStyle);
|
||
SetControlFontStyle(sortType, fontStyle);
|
||
SetControlFontStyle(sortSize, fontStyle);
|
||
SetControlFontStyle(sortID, fontStyle);
|
||
SetControlFontStyle(sortAttrs, fontStyle);
|
||
|
||
// depress type control
|
||
SetControlValue(sortType, 1);
|
||
sortOrder = kSortType;
|
||
|
||
// size the controls correctly
|
||
MoveControl(sortName, -1, kDefaultHeaderHeight +1);
|
||
SizeControl(sortName, nameColumnWidth, kBevelButtonHeight);
|
||
|
||
MoveControl(sortType, nameColumnWidth -1, kDefaultHeaderHeight +1);
|
||
SizeControl(sortType, kFileWindowTypeColumnWidth, kBevelButtonHeight);
|
||
|
||
MoveControl(sortID, nameColumnWidth + kFileWindowTypeColumnWidth -1, kDefaultHeaderHeight +1);
|
||
SizeControl(sortID, kFileWindowIDColumnWidth, kBevelButtonHeight);
|
||
|
||
MoveControl(sortSize, nameColumnWidth + kFileWindowTypeColumnWidth + kFileWindowIDColumnWidth -1, kDefaultHeaderHeight +1);
|
||
SizeControl(sortSize, kFileWindowSizeColumnWidth, kBevelButtonHeight);
|
||
|
||
MoveControl(sortAttrs, nameColumnWidth + kFileWindowTypeColumnWidth + kFileWindowIDColumnWidth + kFileWindowSizeColumnWidth -1, kDefaultHeaderHeight +1);
|
||
SizeControl(sortAttrs, kFileWindowAttributesColumnWidth, kBevelButtonHeight);
|
||
|
||
MoveControl(sortDir, nameColumnWidth + kFileWindowTypeColumnWidth + kFileWindowIDColumnWidth + kFileWindowSizeColumnWidth + kFileWindowAttributesColumnWidth -1, kDefaultHeaderHeight +1);
|
||
SizeControl(sortDir, kFileWindowSortColumnWidth, kBevelButtonHeight);
|
||
}
|
||
else
|
||
{
|
||
nameColumnWidth = kFileWindowDefaultNameColumnWidth;
|
||
horizScroll = GetNewControl(kSystem7ScrollBarControl, window);
|
||
vertScroll = GetNewControl(kSystem7ScrollBarControl, window);
|
||
}
|
||
|
||
// move & update scroll bars to where they should be :)
|
||
BoundsChanged(null);
|
||
#endif
|
||
|
||
// read forks into memory and
|
||
error = ReadResourceFork();
|
||
error = ReadDataFork(error);
|
||
if(error)
|
||
{
|
||
delete this;
|
||
return;
|
||
}
|
||
|
||
#if TARGET_API_MAC_CARBON // CarbonLib 1.1+ or OS X only
|
||
// initalise data browser
|
||
InitDataBrowser();
|
||
#endif
|
||
|
||
// now finally we can show the window
|
||
ShowWindow(window);
|
||
new InspectorWindow;
|
||
}
|
||
|
||
/*** DESTRUCTOR ***/
|
||
FileWindow::~FileWindow(void)
|
||
{
|
||
DisposeWindow(window);
|
||
if(fileSpec) DisposePtr((Ptr) fileSpec);
|
||
if(resourceMap) DisposeResourceMap();
|
||
}
|
||
|
||
/*** WINDOW ACCESSOR ***/
|
||
WindowRef FileWindow::Window(void)
|
||
{
|
||
return window;
|
||
}
|
||
|
||
/********************/
|
||
/* EVENT PROCESSING */
|
||
/********************/
|
||
|
||
#if TARGET_API_MAC_CARBON
|
||
|
||
/*** FILE WINDOW EVENT HANDLER ***/
|
||
pascal OSStatus FileWindowEventHandler(EventHandlerCallRef callRef, EventRef event, void *userData)
|
||
{
|
||
#pragma unused(callRef)
|
||
OSStatus error = eventNotHandledErr;
|
||
unsigned long eventClass = GetEventClass(event);
|
||
unsigned long eventKind = GetEventKind(event);
|
||
FileWindowPtr file = (FileWindowPtr) userData;
|
||
if(!file) return eventNotHandledErr;
|
||
|
||
switch(eventClass)
|
||
{
|
||
case kEventClassWindow:
|
||
switch(eventKind)
|
||
{
|
||
case kEventWindowClose:
|
||
{ WindowRef window = FrontNonFloatingWindow(), nextWindow;
|
||
while(window)
|
||
{
|
||
nextWindow = GetNextWindow(window);
|
||
SInt32 kind = GetWindowKind(window);
|
||
if(kind == kPickerWindowKind || kind == kEditorWindowKind)
|
||
{
|
||
FileWindowPtr owner = (FileWindowPtr) ((PlugWindowPtr) GetWindowRefCon(window))->File();
|
||
if(owner == file)
|
||
{
|
||
// DisposeWindow(window); // bug: windows didn't used to close when sent a WindowClose event! (seems to work now though)
|
||
EventRef event;
|
||
CreateEvent(null, kEventClassWindow, kEventWindowClose, kEventDurationNoWait, kEventAttributeNone, &event);
|
||
SendEventToWindow(event, window);
|
||
ReleaseEvent(event);
|
||
}
|
||
}
|
||
window = nextWindow;
|
||
}
|
||
|
||
// feature to add: user chooses either resource-level or file-level (or both) save sheets
|
||
if(file->IsFileDirty())
|
||
if(g.useSheets) error = file->DisplayModelessAskSaveChangesDialog();
|
||
else error = file->DisplaySaveDialog();
|
||
else error = noErr;
|
||
if(error != userCanceledErr)
|
||
delete file;
|
||
} break;
|
||
|
||
case kEventWindowBoundsChanging:
|
||
error = file->BoundsChanging(event);
|
||
break;
|
||
|
||
case kEventWindowBoundsChanged:
|
||
error = file->BoundsChanged(event);
|
||
break;
|
||
|
||
case kEventWindowZoomed:
|
||
error = file->Zoomed(event);
|
||
break;
|
||
|
||
case kEventWindowGetIdealSize:
|
||
error = file->SetIdealSize(event);
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case kEventClassCommand:
|
||
HICommand command;
|
||
error = GetEventParameter(event, kEventParamDirectObject, typeHICommand, null, sizeof(HICommand), null, &command);
|
||
if(error) return eventNotHandledErr;
|
||
else error = eventNotHandledErr;
|
||
switch(eventKind)
|
||
{
|
||
case kEventCommandProcess:
|
||
/* switch(command.commandID)
|
||
{
|
||
}
|
||
*/ break;
|
||
}
|
||
break;
|
||
}
|
||
return error;
|
||
}
|
||
|
||
/*** FILE WINDOW UPDATE MENUS ***/
|
||
pascal OSStatus FileWindowUpdateMenus(EventHandlerCallRef callRef, EventRef event, void *userData)
|
||
{
|
||
#pragma unused(callRef, event)
|
||
// OSStatus error = eventNotHandledErr;
|
||
|
||
// get file window
|
||
FileWindowPtr file = (FileWindowPtr) userData;
|
||
if(!file) return eventNotHandledErr;
|
||
|
||
// get number of resources selected
|
||
UInt32 numSelected;
|
||
GetDataBrowserItemCount(file->GetDataBrowser(), kDataBrowserNoItem, true, kDataBrowserItemIsSelected, &numSelected);
|
||
|
||
// determine if selected resource is of type 'snd '
|
||
Boolean canPlaySound = false;
|
||
ResourceObjectPtr resource = null;
|
||
DataBrowserItemID first, last, n;
|
||
GetDataBrowserSelectionAnchor(file->GetDataBrowser(), &first, &last);
|
||
if(first != kDataBrowserNoItem && last != kDataBrowserNoItem)
|
||
{
|
||
for(n = first; n <= last; n++)
|
||
{
|
||
resource = file->GetResource(n);
|
||
if(resource->Type() == soundListRsrc)
|
||
canPlaySound = true;
|
||
}
|
||
}
|
||
|
||
// edit menu
|
||
EnableCommand(null, kHICommandUndo, false);
|
||
EnableCommand(null, kHICommandRedo, false);
|
||
/* EnableCommand(null, kHICommandCut, numSelected > 0);
|
||
EnableCommand(null, kHICommandCopy, numSelected > 0);
|
||
EnableCommand(null, kHICommandPaste, numSelected > 0);
|
||
EnableCommand(null, kHICommandClear, numSelected > 0);
|
||
*/ EnableCommand(null, kHICommandCut, false);
|
||
EnableCommand(null, kHICommandCopy, false);
|
||
EnableCommand(null, kHICommandPaste, false);
|
||
EnableCommand(null, kHICommandClear, false);
|
||
EnableCommand(null, kHICommandSelectAll, true);
|
||
EnableCommand(null, kMenuCommandFind, false);
|
||
EnableCommand(null, kMenuCommandFindAgain, false);
|
||
|
||
// resource menu
|
||
EnableCommand(null, kMenuCommandNewResource, true);
|
||
EnableCommand(null, kMenuCommandOpenHex, numSelected > 0);
|
||
EnableCommand(null, kMenuCommandOpenDefault, numSelected > 0);
|
||
EnableCommand(null, kMenuCommandOpenTemplate, numSelected > 0);
|
||
EnableCommand(null, kMenuCommandOpenSpecific, numSelected > 0);
|
||
EnableCommand(null, kMenuCommandRevertResource, numSelected > 0);
|
||
EnableCommand(null, kMenuCommandPlaySound, numSelected > 0 && canPlaySound);
|
||
return eventNotHandledErr;
|
||
}
|
||
|
||
/*** FILE WINDOW PARSE MENU SELECTION ***/
|
||
pascal OSStatus FileWindowParseMenuSelection(EventHandlerCallRef callRef, EventRef event, void *userData)
|
||
{
|
||
#pragma unused(callRef)
|
||
|
||
// get menu command
|
||
HICommand menuCommand;
|
||
OSStatus error = GetEventParameter(event, kEventParamDirectObject, typeHICommand, null, sizeof(HICommand), null, &menuCommand);
|
||
if(error) return eventNotHandledErr;
|
||
|
||
// get file window
|
||
FileWindowPtr file = (FileWindowPtr) userData;
|
||
if(!file) return eventNotHandledErr;
|
||
|
||
switch(menuCommand.commandID)
|
||
{
|
||
// file menu
|
||
case kMenuCommandCloseWindow:
|
||
case kMenuCommandCloseFile:
|
||
EventRef event;
|
||
CreateEvent(null, kEventClassWindow, kEventWindowClose, kEventDurationNoWait, kEventAttributeNone, &event);
|
||
SendEventToWindow(event, file->Window());
|
||
ReleaseEvent(event);
|
||
break;
|
||
|
||
case kMenuCommandSaveFile:
|
||
error = file->SaveFile(null);
|
||
break;
|
||
|
||
case kMenuCommandSaveFileAs:
|
||
if(g.useSheets) error = file->DisplayModelessPutFileDialog();
|
||
else error = file->DisplaySaveAsDialog();
|
||
break;
|
||
|
||
case kMenuCommandRevertFile:
|
||
if(g.useSheets) error = file->DisplayModelessAskDiscardChangesDialog();
|
||
else error = file->DisplayRevertFileDialog();
|
||
break;
|
||
|
||
// edit menu
|
||
/* case kHICommandOK:
|
||
case kHICommandCancel:
|
||
case kHICommandQuit:
|
||
case kHICommandUndo:
|
||
case kHICommandRedo:
|
||
case kHICommandCut:
|
||
case kHICommandCopy:
|
||
case kHICommandPaste:
|
||
case kHICommandClear:
|
||
*/ case kHICommandSelectAll:
|
||
ForEachDataBrowserItem(file->GetDataBrowser(), kDataBrowserNoItem, true, kDataBrowserItemIsSelected, null, null);
|
||
break;
|
||
/* case kHICommandHide:
|
||
case kHICommandPreferences:
|
||
case kHICommandZoomWindow:
|
||
case kHICommandMinimizeWindow:
|
||
case kHICommandArrangeInFront:
|
||
case kHICommandAbout:
|
||
break;
|
||
*/
|
||
// resource menu
|
||
case kMenuCommandNewResource:
|
||
if(g.useSheets) error = file->DisplayNewResourceSheet();
|
||
else error = file->DisplayNewResourceDialog();
|
||
break;
|
||
|
||
case kMenuCommandOpenDefault:
|
||
case kMenuCommandOpenTemplate:
|
||
case kMenuCommandOpenSpecific:
|
||
case kMenuCommandOpenHex:
|
||
#if TARGET_API_MAC_CARBON
|
||
for(DataBrowserItemID item = 1; item <= file->GetResourceCount(); item++)
|
||
{
|
||
if(IsDataBrowserItemSelected(file->GetDataBrowser(), item))
|
||
error = file->OpenResource(item, menuCommand.commandID);
|
||
if(error) return eventNotHandledErr;
|
||
}
|
||
#else
|
||
DisplayDialog("\pAs I haven't wired up Classic Events, no Editors work in classic mode.");
|
||
#endif
|
||
break;
|
||
|
||
case kMenuCommandRevertResource:
|
||
break;
|
||
|
||
case kMenuCommandPlaySound:
|
||
DataBrowserItemID first, last, n;
|
||
GetDataBrowserSelectionAnchor(file->GetDataBrowser(), &first, &last);
|
||
for(n = first; n <= last; n++)
|
||
{
|
||
ResourceObjectPtr resource = file->GetResource(n);
|
||
if(resource->Type() == soundListRsrc)
|
||
file->PlaySound(n);
|
||
}
|
||
break;
|
||
|
||
default:
|
||
return eventNotHandledErr;
|
||
}
|
||
return error;
|
||
}
|
||
|
||
#endif
|
||
|
||
/*** WINDOW BOUNDS ARE CHANGING ***/
|
||
OSStatus FileWindow::BoundsChanging(EventRef event)
|
||
{
|
||
OSStatus error = noErr;
|
||
#if TARGET_API_MAC_CARBON
|
||
// check that window is not just being dragged
|
||
UInt32 attributes;
|
||
error = GetEventParameter(event, kEventParamAttributes, typeUInt32, null, sizeof(UInt32), null, &attributes);
|
||
if(error || attributes & kWindowBoundsChangeUserDrag) return eventNotHandledErr;
|
||
if(g.systemVersion < kMacOSX) return noErr;
|
||
|
||
// resize window's contents
|
||
error = eventNotHandledErr;
|
||
if(g.systemVersion >= kMacOSX)
|
||
{
|
||
Rect windowBounds;
|
||
error = GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, null, sizeof(Rect), null, &windowBounds);
|
||
if(error) return eventNotHandledErr;
|
||
SizeControl(dataBrowser, windowBounds.right - windowBounds.left, windowBounds.bottom - windowBounds.top - kDefaultHeaderHeight -1);
|
||
}
|
||
#else
|
||
#pragma unused(event)
|
||
#endif
|
||
return error;
|
||
}
|
||
|
||
/*** WINDOW BOUNDS HAVE CHANGED ***/
|
||
OSStatus FileWindow::BoundsChanged(EventRef event)
|
||
{
|
||
#if TARGET_API_MAC_CARBON
|
||
if(event)
|
||
{
|
||
// check that window is not just being dragged
|
||
UInt32 attributes;
|
||
OSStatus error = GetEventParameter(event, kEventParamAttributes, typeUInt32, null, sizeof(UInt32), null, &attributes);
|
||
if(error || attributes & kWindowBoundsChangeUserDrag) return eventNotHandledErr;
|
||
}
|
||
#else
|
||
#pragma unused(event)
|
||
#endif
|
||
|
||
GrafPtr oldPort;
|
||
GetPort(&oldPort);
|
||
SetPortWindowPort(window);
|
||
|
||
// move everything and invalidate the area
|
||
Rect windowBounds;
|
||
if(g.windowMgrAvailable) GetWindowBounds(window, kWindowContentRgn, &windowBounds);
|
||
else GetPortBounds((CGrafPtr) window, &windowBounds);
|
||
OffsetRect(&windowBounds, -windowBounds.left, -windowBounds.top);
|
||
|
||
#if TARGET_API_MAC_CARBON
|
||
// resize header & data browser
|
||
SizeControl(header, (windowBounds.right - windowBounds.left) +2, kDefaultHeaderHeight +1);
|
||
SizeControl(left, (windowBounds.right - windowBounds.left) /2 -4, kDefaultHeaderHeight -4);
|
||
SizeControl(right, (windowBounds.right - windowBounds.left) /2 -4, kDefaultHeaderHeight -4);
|
||
MoveControl(right, (windowBounds.right - windowBounds.left) /2, 2);
|
||
SizeControl(dataBrowser, windowBounds.right - windowBounds.left, windowBounds.bottom - windowBounds.top - kDefaultHeaderHeight -1);
|
||
#else
|
||
if(themeSavvy)
|
||
{
|
||
nameColumnWidth = windowBounds.right - kFileWindowAllOtherColumnWidths -6;
|
||
if(nameColumnWidth < kFileWindowMinimumNameColumnWidth) nameColumnWidth = kFileWindowMinimumNameColumnWidth;
|
||
SizeControl(header, windowBounds.right +2 - windowBounds.left, kDefaultHeaderHeight +2);
|
||
SizeControl(sortName, nameColumnWidth, kBevelButtonHeight);
|
||
MoveControl(sortType, (nameColumnWidth -1), kDefaultHeaderHeight +1);
|
||
MoveControl(sortID, (nameColumnWidth -1) + kFileWindowTypeColumnWidth, kDefaultHeaderHeight +1);
|
||
MoveControl(sortSize, (nameColumnWidth -1) + kFileWindowTypeColumnWidth + kFileWindowIDColumnWidth, kDefaultHeaderHeight +1);
|
||
MoveControl(sortAttrs, (nameColumnWidth -1) + kFileWindowTypeColumnWidth + kFileWindowIDColumnWidth + kFileWindowSizeColumnWidth, kDefaultHeaderHeight +1);
|
||
MoveControl(sortDir, (nameColumnWidth -1) + kFileWindowTypeColumnWidth + kFileWindowIDColumnWidth + kFileWindowSizeColumnWidth + kFileWindowAttributesColumnWidth, kDefaultHeaderHeight +1);
|
||
}
|
||
MoveControl(horizScroll, -1, windowBounds.bottom - (kScrollBarWidth -1));
|
||
SizeControl(horizScroll, windowBounds.right - (kScrollBarWidth -3), kScrollBarWidth);
|
||
MoveControl(vertScroll, windowBounds.right - (kScrollBarWidth -1), kFileWindowHeaderHeight);
|
||
SizeControl(vertScroll, kScrollBarWidth, windowBounds.bottom - kFileWindowHeaderHeight - (kScrollBarWidth -2));
|
||
if(themeSavvy && g.systemVersion >= kMacOS85)
|
||
{
|
||
SetControlViewSize(horizScroll, nameColumnWidth + kFileWindowAllOtherColumnWidths);
|
||
SetControlViewSize(vertScroll, windowBounds.bottom - (kScrollBarWidth -1) - kFileWindowHeaderHeight);
|
||
}
|
||
UpdateScrollBars();
|
||
#endif
|
||
|
||
#if TARGET_API_MAC_CARBON
|
||
InvalidateWindowRect(window, &windowBounds);
|
||
#else
|
||
if(g.windowMgrAvailable) InvalidateWindowRect(window, &windowBounds);
|
||
else InvalidateRect(&windowBounds);
|
||
#endif
|
||
SetPort(oldPort);
|
||
return noErr;
|
||
}
|
||
|
||
#if TARGET_API_MAC_CARBON
|
||
|
||
/*** WINDOW HAS BEEN ZOOMED ***/
|
||
OSStatus FileWindow::Zoomed(EventRef event)
|
||
{
|
||
// get new bounds
|
||
WindowRef window;
|
||
Rect windowBounds;
|
||
OSStatus error = GetEventParameter(event, kEventParamDirectObject, typeWindowRef, null, sizeof(WindowRef), null, &window);
|
||
if(error) return eventNotHandledErr;
|
||
GetWindowBounds(window, kWindowGlobalPortRgn, &windowBounds);
|
||
OffsetRect(&windowBounds, -windowBounds.left, -windowBounds.top);
|
||
|
||
// resize controls to the window size
|
||
SizeControl(header, windowBounds.right - windowBounds.left +2, kDefaultHeaderHeight +1);
|
||
SizeControl(left, (windowBounds.right - windowBounds.left) /5 *3 - windowBounds.left +4, kDefaultHeaderHeight - windowBounds.top -8);
|
||
MoveControl(right, (windowBounds.right - windowBounds.left) /5 *2, windowBounds.top +4);
|
||
SizeControl(right, windowBounds.right - ((windowBounds.right - windowBounds.left) /5 *2) -4, kDefaultHeaderHeight - windowBounds.top -8);
|
||
SizeControl(dataBrowser, windowBounds.right - windowBounds.left, windowBounds.bottom - windowBounds.top - kDefaultHeaderHeight -1);
|
||
return error;
|
||
}
|
||
|
||
/*** SET IDEAL SIZE OF WINDOW ***/
|
||
OSStatus FileWindow::SetIdealSize(EventRef event)
|
||
{
|
||
Point idealSize;
|
||
SetPoint(&idealSize, 512, 512);
|
||
OSStatus error = SetEventParameter(event, kEventParamDimensions, typeQDPoint, sizeof(Point), &idealSize);
|
||
return error? eventNotHandledErr:noErr;
|
||
}
|
||
|
||
#endif
|
||
#if !TARGET_API_MAC_CARBON
|
||
|
||
/*** UPDATE WINDOW ***/
|
||
OSStatus FileWindow::Update(RgnHandle update)
|
||
{
|
||
GrafPtr oldPort;
|
||
GetPort(&oldPort);
|
||
SetPortWindowPort(window);
|
||
|
||
// get rect into which I can draw
|
||
Rect windowBounds, rect;
|
||
if(g.windowMgrAvailable) GetWindowBounds(window, kWindowContentRgn, &windowBounds);
|
||
else GetPortBounds((CGrafPort *) window, &windowBounds);
|
||
SetRect(&rect, 0, 0, windowBounds.right - windowBounds.left, windowBounds.bottom - windowBounds.top);
|
||
rect.top += kFileWindowHeaderHeight +1;
|
||
rect.bottom -= (kScrollBarWidth -1);
|
||
rect.right -= (kScrollBarWidth -1);
|
||
|
||
// only draw resources if they are in the update region
|
||
if(!update || RectInRgn(&windowBounds, update))
|
||
{
|
||
RgnHandle clip = NewRgn(), oldClip = NewRgn();
|
||
RectToRegion(clip, &rect);
|
||
GetPortClipRegion(GetWindowPort(window), oldClip);
|
||
SetPortClipRegion(GetWindowPort(window), clip);
|
||
|
||
SInt16 value = GetControlValue(vertScroll);
|
||
if(themeSavvy)
|
||
{
|
||
// create light bg for all columns
|
||
RGBBackColor(&g.bgColour);
|
||
EraseRect(&rect);
|
||
|
||
// add dark bg for sorted column
|
||
Rect controlBounds;
|
||
switch(sortOrder)
|
||
{
|
||
case kSortName:
|
||
GetControlBounds(sortName, &controlBounds);
|
||
rect.left = controlBounds.left;
|
||
rect.right = controlBounds.right;
|
||
break;
|
||
|
||
case kSortType:
|
||
GetControlBounds(sortType, &controlBounds);
|
||
rect.left = controlBounds.left;
|
||
rect.right = controlBounds.right;
|
||
break;
|
||
|
||
case kSortID:
|
||
GetControlBounds(sortID, &controlBounds);
|
||
rect.left = controlBounds.left;
|
||
rect.right = controlBounds.right;
|
||
break;
|
||
|
||
case kSortSize:
|
||
GetControlBounds(sortSize, &controlBounds);
|
||
rect.left = controlBounds.left;
|
||
rect.right = controlBounds.right;
|
||
break;
|
||
|
||
case kSortAttrs:
|
||
GetControlBounds(sortAttrs, &controlBounds);
|
||
rect.left = controlBounds.left;
|
||
rect.right = controlBounds.right;
|
||
break;
|
||
|
||
default:
|
||
GetControlBounds(sortAttrs, &controlBounds);
|
||
rect.left = controlBounds.right;
|
||
rect.right = controlBounds.right +1;
|
||
}
|
||
|
||
RGBBackColor(&g.sortColour);
|
||
EraseRect(&rect);
|
||
}
|
||
else
|
||
{
|
||
// erase background
|
||
RGBBackColor(&g.white);
|
||
EraseRect(&rect);
|
||
}
|
||
|
||
// draw all resources
|
||
ResourceObjectPtr current = resourceMap;
|
||
for(UInt16 line = 1; line <= numResources; line++)
|
||
{
|
||
// draw resource icon
|
||
DrawResourceIcon(current, line);
|
||
|
||
// reset text incase it was condensed or emboldened
|
||
RGBForeColor(&g.black);
|
||
TextFace(normal);
|
||
|
||
// resource type
|
||
Str255 typeStr = "\p";
|
||
TypeToPString(current->Type(), typeStr);
|
||
MoveTo(nameColumnWidth + kFileWindowTypeColumnOffset + kFileWindowTypeColumnWidth - StringWidth(typeStr) -5, kFileWindowHeaderHeight + (kFileWindowRowHeight * line) - (kFileWindowRowHeight - kFileWindowTextHeight)/2 - 3 - value);
|
||
DrawString(typeStr);
|
||
|
||
// resource ID
|
||
Str255 idStr;
|
||
NumToString(current->ID(), idStr);
|
||
MoveTo(nameColumnWidth + kFileWindowIDColumnOffset + kFileWindowIDColumnWidth - StringWidth(idStr) -5, kFileWindowHeaderHeight + (kFileWindowRowHeight * line) - (kFileWindowRowHeight - kFileWindowTextHeight)/2 - 3 - value);
|
||
DrawString(idStr);
|
||
|
||
// resource size
|
||
Str255 sizeStr;
|
||
NumToString(current->Size(), sizeStr);
|
||
MoveTo(nameColumnWidth + kFileWindowSizeColumnOffset + kFileWindowSizeColumnWidth - StringWidth(sizeStr) -5, kFileWindowHeaderHeight + (kFileWindowRowHeight * line) - (kFileWindowRowHeight - kFileWindowTextHeight)/2 - 3 - value);
|
||
DrawString(sizeStr);
|
||
|
||
// resource attribute icons
|
||
/* Rect iconRect;
|
||
SetRect(&iconRect, 0, 0, 16, 16);
|
||
OffsetRect(&iconRect, kFileWindowSizeColumnWidth + kAttrColumnOffset, (kFileLineHeight * line) +1);
|
||
if(current->Attributes() & resPreload) PlotIconID(&iconRect, kAlignNone, kTransformNone, kPreloadIcon);
|
||
else PlotIconID(&iconRect, kAlignNone, kTransformDisabled, kPreloadIcon);
|
||
OffsetRect(&iconRect, kAttrIconSep, 0);
|
||
if(current->Attributes() & resProtected) PlotIconID(&iconRect, kAlignNone, kTransformNone, kProtectedIcon);
|
||
else PlotIconID(&iconRect, kAlignNone, kTransformDisabled, kProtectedIcon);
|
||
OffsetRect(&iconRect, kAttrIconSep, 0);
|
||
if(current->Attributes() & resLocked) PlotIconID(&iconRect, kAlignNone, kTransformNone, kLockedIcon);
|
||
else PlotIconID(&iconRect, kAlignNone, kTransformDisabled, kLockedIcon);
|
||
OffsetRect(&iconRect, kAttrIconSep, 0);
|
||
if(current->Attributes() & resPurgeable) PlotIconID(&iconRect, kAlignNone, kTransformNone, kPurgableIcon);
|
||
else PlotIconID(&iconRect, kAlignNone, kTransformDisabled, kPurgableIcon);
|
||
OffsetRect(&iconRect, kAttrIconSep, 0);
|
||
if(current->Attributes() & resSysHeap) PlotIconID(&iconRect, kAlignNone, kTransformNone, kSysHeapIcon);
|
||
else PlotIconID(&iconRect, kAlignNone, kTransformDisabled, kSysHeapIcon);
|
||
OffsetRect(&iconRect, kAttrIconSep, 0);
|
||
if(current->Attributes() & null) PlotIconID(&iconRect, kAlignNone, kTransformNone, kCompressedIcon);
|
||
else PlotIconID(&iconRect, kAlignNone, kTransformDisabled, kCompressedIcon);
|
||
*/
|
||
/* resSysHeap = 64, // System or application heap?
|
||
resPurgeable = 32, // Purgeable resource?
|
||
resLocked = 16, // Load it in locked?
|
||
resProtected = 8, // Protected?
|
||
resPreload = 4, // Load in on OpenResFile?
|
||
resChanged = 2, // Resource changed? - not used by ResKnife */
|
||
|
||
if(themeSavvy)
|
||
{
|
||
// draw divider line
|
||
MoveTo(0, kFileWindowHeaderHeight + (kFileWindowRowHeight * line) - value);
|
||
RGBForeColor(&g.white);
|
||
Line(windowBounds.right - windowBounds.left -1, 0);
|
||
}
|
||
|
||
// move on
|
||
current = current->Next();
|
||
}
|
||
|
||
SetPortClipRegion(GetWindowPort(window), oldClip);
|
||
DisposeRgn(clip);
|
||
DisposeRgn(oldClip);
|
||
}
|
||
|
||
// update the controls
|
||
if(!themeSavvy) DrawGrowIcon(window);
|
||
UpdateControls(window, update);
|
||
SetPort(oldPort);
|
||
return noErr;
|
||
}
|
||
|
||
/*** ACTIVATE WINDOW ***/
|
||
OSStatus FileWindow::Activate(Boolean active)
|
||
{
|
||
// invalidate the whole window
|
||
GrafPtr oldPort;
|
||
GetPort(&oldPort);
|
||
SetPortWindowPort(window);
|
||
|
||
Rect windowBounds;
|
||
if(g.windowMgrAvailable) GetWindowBounds(window, kWindowContentRgn, &windowBounds);
|
||
else GetPortBounds((CGrafPort *) window, &windowBounds);
|
||
if(g.windowMgrAvailable) InvalidateWindowRect(window, &windowBounds);
|
||
else InvalidateRect(&windowBounds);
|
||
SetPort(oldPort);
|
||
|
||
// set the controls to display correctly
|
||
ControlPartCode hiliteState = active? kControlNoPart:kControlInactivePart;
|
||
if(themeSavvy)
|
||
{
|
||
HiliteControl(header, hiliteState);
|
||
HiliteControl(sortName, hiliteState);
|
||
HiliteControl(sortType, hiliteState);
|
||
HiliteControl(sortID, hiliteState);
|
||
HiliteControl(sortSize, hiliteState);
|
||
HiliteControl(sortAttrs, hiliteState);
|
||
HiliteControl(sortDir, hiliteState);
|
||
}
|
||
HiliteControl(horizScroll, hiliteState);
|
||
HiliteControl(vertScroll, hiliteState);
|
||
return noErr;
|
||
}
|
||
|
||
/*** MOUSE CLICK ***/
|
||
OSStatus FileWindow::Click(Point globalMouse, EventModifiers modifiers)
|
||
{
|
||
// set the mouse location to local co-ords
|
||
GrafPtr oldPort;
|
||
GetPort(&oldPort);
|
||
SetPortWindowPort(window);
|
||
Point localMouse = globalMouse, windowLoc = {0,0};
|
||
GlobalToLocal(&localMouse);
|
||
LocalToGlobal(&windowLoc);
|
||
SetPort(oldPort);
|
||
|
||
// handle a click on a control first
|
||
ControlHandle control;
|
||
SInt16 controlPart;
|
||
if(themeSavvy) control = FindControlUnderMouse(localMouse, window, &controlPart);
|
||
else controlPart = FindControl(localMouse, window, &control);
|
||
if(control && controlPart != kControlNoPart)
|
||
{
|
||
// scroll the windoow
|
||
if(themeSavvy)
|
||
{
|
||
ControlActionUPP scrollAction = NewControlActionUPP(FileWindowScrollAction);
|
||
controlPart = HandleControlClick(control, localMouse, modifiers, scrollAction);
|
||
DisposeControlActionUPP(scrollAction);
|
||
}
|
||
else if(controlPart != kControlIndicatorPart)
|
||
{
|
||
ControlActionUPP scrollAction = NewControlActionUPP(FileWindowScrollAction);
|
||
TrackControl(control, localMouse, scrollAction);
|
||
DisposeControlActionUPP(scrollAction);
|
||
}
|
||
else // clicks in the thumb cause crashes if given a ControlActionUPP
|
||
{
|
||
controlPart = TrackControl(control, localMouse, nil);
|
||
Update();
|
||
}
|
||
|
||
// save new offset & return
|
||
UpdateScrollBars();
|
||
return noErr;
|
||
}
|
||
else
|
||
{
|
||
// click was not on a control<6F>
|
||
ResourceObjectPtr resource = resourceMap;
|
||
static unsigned long clickTime;
|
||
|
||
// check shift key status
|
||
Boolean shiftKeyDown = false,
|
||
optionKeyDown = false;
|
||
|
||
KeyMap theKeys;
|
||
GetKeys(theKeys);
|
||
if(theKeys[1] & (shiftKey >> shiftKeyBit)) shiftKeyDown = true;
|
||
if(theKeys[1] & (optionKey >> shiftKeyBit)) optionKeyDown = true;
|
||
|
||
// clicked on a part of the window where no resource is listed
|
||
SInt16 newSelection = (localMouse.v + GetControlValue(vertScroll) - kFileWindowHeaderHeight) / kFileWindowRowHeight +1;
|
||
if(newSelection > numResources)
|
||
{
|
||
ClearSelection(); // should go to drag selection instead
|
||
Update();
|
||
return noErr;
|
||
}
|
||
|
||
// cycle to clicked resource
|
||
for(newSelection; newSelection > 1; newSelection--)
|
||
resource = resource->Next();
|
||
|
||
// check for click on attributes
|
||
/* if(mouse.h >= g.nameColumnWidth + kAttrColumnOffset) // clicked on attribute
|
||
{
|
||
short attrClicked = mouse.h;
|
||
attrClicked -= g.nameColumnWidth + kAttrColumnOffset;
|
||
attrClicked /= kAttrIconSep;
|
||
attrClicked += resPreloadBit;
|
||
if((r.attrs >> attrClicked) & 0x01) r.attrs -= 1 << attrClicked;
|
||
else r.attrs += 1 << attrClicked;
|
||
|
||
// mark file & resource for saving
|
||
dirty = true;
|
||
r.dirty = true;
|
||
ChangedResource(r.resource);
|
||
|
||
// update the window
|
||
Update();
|
||
}
|
||
|
||
// if in nameIconRgn, must be a click on a resource
|
||
else*/ if(PtInRgn(localMouse, resource->nameIconRgn))
|
||
{
|
||
if(resource->Selected() == false)
|
||
{
|
||
if(shiftKeyDown) // shift click on unselected
|
||
{
|
||
resource->Select(true);
|
||
numSelected += 1;
|
||
}
|
||
else // click on unselected
|
||
{
|
||
clickTime = TickCount();
|
||
ClearSelection();
|
||
resource->Select(true);
|
||
numSelected = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if(TickCount() <= clickTime + GetDblTime()) // double click
|
||
{
|
||
ClearSelection();
|
||
resource->Select(true);
|
||
numSelected = 1;
|
||
OpenResource(resource->Number(), optionKeyDown? kMenuCommandOpenHex:kMenuCommandOpenDefault);
|
||
}
|
||
else if(shiftKeyDown) // shift click on selected
|
||
{
|
||
resource->Select(false);
|
||
numSelected -= 1;
|
||
}
|
||
else // click on selected
|
||
{
|
||
clickTime = TickCount();
|
||
resource->Select(true);
|
||
}
|
||
}
|
||
|
||
// update the window
|
||
Update();
|
||
|
||
// check for resource drags
|
||
if(WaitMouseMoved(globalMouse)) // drag activated
|
||
{
|
||
OSErr error = noErr;
|
||
DragReference theDragRef;
|
||
ItemReference theItemRef = 1;
|
||
FlavorFlags theFlags = flavorNotSaved;
|
||
DragSendDataUPP sendProc = null; // bug: NewDragSendDataProc(SendFileDataProc);
|
||
|
||
// setup imaginary file
|
||
PromiseHFSFlavor theFile;
|
||
theFile.fileType = kResourceTransferType;
|
||
theFile.fileCreator = kResKnifeCreator;
|
||
theFile.fdFlags = null; // finder flags
|
||
theFile.promisedFlavor = kResourceTransferType;
|
||
|
||
// create the drag reference
|
||
NewDrag(&theDragRef);
|
||
error = MemError();
|
||
if(error) return error;
|
||
SetDragSendProc(theDragRef, sendProc, this);
|
||
|
||
RgnHandle dragRgn = NewRgn(),
|
||
subtractRgn = NewRgn();
|
||
|
||
// get region of dragged items, using translucent dragging where possible
|
||
GWorldPtr imageGWorld = null;
|
||
|
||
resource = resourceMap;
|
||
while(resource)
|
||
{
|
||
if(resource->Selected())
|
||
UnionRgn(resource->nameIconRgn, dragRgn, dragRgn); // add new region to rest of drag region
|
||
resource = resource->Next();
|
||
}
|
||
|
||
/* if(g.translucentDrag)
|
||
{
|
||
Point dragOffset;
|
||
DataBrowserItemID resCounter = 0;
|
||
SetPt(&dragOffset, 0, kFileWindowHeaderHeight);
|
||
resource = resourceMap;
|
||
|
||
while(!resource->Selected())
|
||
{
|
||
resCounter++;
|
||
resource = resource->Next();
|
||
}
|
||
|
||
error = CreateDragImage(resource, &imageGWorld);
|
||
if(!error)
|
||
{
|
||
// init mask region
|
||
RgnHandle maskRgn = NewRgn();
|
||
CopyRgn(resource->nameIconRgn, maskRgn);
|
||
OffsetRgn(maskRgn, 0, -kFileWindowRowHeight * resCounter);
|
||
|
||
// init rects
|
||
Rect sourceRect, destRect;
|
||
SetRect(&sourceRect, 0, 0, nameColumnWidth, kFileWindowRowHeight);
|
||
SetRect(&destRect, 0, 0, nameColumnWidth, kFileWindowRowHeight);
|
||
OffsetRect(&destRect, 0, kFileWindowHeaderHeight);
|
||
|
||
// init GWorld
|
||
PixMapHandle imagePixMap = GetGWorldPixMap(imageGWorld);
|
||
DragImageFlags imageFlags = kDragStandardTranslucency | kDragRegionAndImage;
|
||
error = SetDragImage(theDragRef, imagePixMap, maskRgn, dragOffset, imageFlags);
|
||
CopyBits(&GrafPtr(imageGWorld)->portBits, &GrafPtr(window)->portBits, &sourceRect, &destRect, srcCopy, maskRgn);
|
||
if(error) SysBeep(0);
|
||
DisposeGWorld(imageGWorld);
|
||
DisposeRgn(maskRgn);
|
||
}
|
||
}
|
||
*/
|
||
// subtract middles from icons
|
||
CopyRgn(dragRgn, subtractRgn); // duplicate region
|
||
InsetRgn(subtractRgn, 2, 2); // inset it by 2 pixels
|
||
DiffRgn(dragRgn, subtractRgn, dragRgn); // subtract subRgn from addRgn, save in nameIconRgn
|
||
OffsetRgn(dragRgn, windowLoc.h, windowLoc.v); // change drag region to global coords
|
||
|
||
// add flavour data to drag
|
||
error = AddDragItemFlavor(theDragRef, theItemRef, flavorTypePromiseHFS, &theFile, sizeof(PromiseHFSFlavor), theFlags);
|
||
error = AddDragItemFlavor(theDragRef, theItemRef, kResourceTransferType, null, 0, theFlags);
|
||
|
||
// track the drag, then clean up
|
||
EventRecord event;
|
||
event.what = mouseDown;
|
||
event.message = null;
|
||
event.when = TickCount();
|
||
event.where = globalMouse;
|
||
event.modifiers = modifiers;
|
||
|
||
error = TrackDrag(theDragRef, &event, dragRgn);
|
||
if(theDragRef) DisposeDrag(theDragRef);
|
||
if(subtractRgn) DisposeRgn(subtractRgn);
|
||
if(dragRgn) DisposeRgn(dragRgn);
|
||
}
|
||
}
|
||
|
||
// otherwise, must be a drag selection or de-selection
|
||
else
|
||
{
|
||
// clear current selections
|
||
if(shiftKeyDown == false)
|
||
{
|
||
ClearSelection();
|
||
Update();
|
||
}
|
||
|
||
// check for resource drags
|
||
if(WaitMouseMoved(globalMouse))
|
||
{
|
||
// set pen
|
||
PenState oldState, dragState;
|
||
GetPenState(&oldState);
|
||
PenSize(2, 2);
|
||
PenPat(&qd.gray);
|
||
PenMode(srcXor);
|
||
GetPenState(&dragState);
|
||
SetPenState(&oldState);
|
||
|
||
// do drag selection
|
||
|
||
// RgnHandle oldClip = NewRgn();
|
||
// GetClip(oldClip);
|
||
// SetClip(bodyRgn);
|
||
|
||
Point mouse, savedMouse = globalMouse, oldMouse = globalMouse;
|
||
Rect dragRect = {0,0,0,0};
|
||
while(WaitMouseUp())
|
||
{
|
||
GetMouse(&mouse);
|
||
SetPortWindowPort(window);
|
||
if(mouse.h != oldMouse.h || mouse.v != oldMouse.v)
|
||
{
|
||
SetPenState(&dragState);
|
||
FrameRect(&dragRect);
|
||
SetRect(&dragRect, (savedMouse.h < mouse.h)? savedMouse.h : mouse.h,
|
||
(savedMouse.v < mouse.v)? savedMouse.v : mouse.v,
|
||
(savedMouse.h > mouse.h)? savedMouse.h : mouse.h,
|
||
(savedMouse.v > mouse.v)? savedMouse.v : mouse.v);
|
||
OffsetRect(&dragRect, -windowLoc.h, -windowLoc.v);
|
||
FrameRect(&dragRect);
|
||
SetPenState(&oldState);
|
||
|
||
// check to see if selection region coincides with resources
|
||
short i;
|
||
RgnHandle dragRgn = NewRgn(), resultRgn = NewRgn();
|
||
RectRgn(dragRgn, &dragRect);
|
||
ResourceObjectPtr resource = resourceMap;
|
||
for(i = 1; i <= GetControlValue(vertScroll); i++)
|
||
resource = resource->Next(); // move to first res in window
|
||
for(i = GetControlValue(vertScroll); i < numResources - GetControlValue(vertScroll); i++)
|
||
{
|
||
SetEmptyRgn(resultRgn);
|
||
SectRgn(dragRgn, resource->nameIconRgn, resultRgn);
|
||
resource->Select(!EmptyRgn(resultRgn));
|
||
DrawResourceIcon(resource, i+1);
|
||
resource = resource->Next();
|
||
}
|
||
DisposeRgn(resultRgn);
|
||
DisposeRgn(dragRgn);
|
||
}
|
||
SetPort(oldPort);
|
||
oldMouse = mouse;
|
||
}
|
||
|
||
// restore clip region
|
||
// SetClip(oldClip);
|
||
}
|
||
|
||
// update the window
|
||
Update();
|
||
}
|
||
return eventNotHandledErr;
|
||
}
|
||
}
|
||
|
||
/*** FILE WINDOW SCROLL ACTION ***/
|
||
pascal void FileWindowScrollAction(ControlHandle control, SInt16 controlPart)
|
||
{
|
||
// get owning window
|
||
if(!controlPart) return;
|
||
SInt8 state = HGetState((Handle) control);
|
||
HLock((Handle) control);
|
||
WindowRef window = GetControlOwner(control);
|
||
HSetState((Handle) control, state);
|
||
WindowObjectPtr winObj = (WindowObjectPtr) GetWindowRefCon(window);
|
||
|
||
// get window bounds
|
||
Rect windowBounds;
|
||
if(g.windowMgrAvailable) GetWindowBounds(window, kWindowContentRgn, &windowBounds);
|
||
else GetPortBounds((CGrafPort *) window, &windowBounds);
|
||
windowBounds.top += kFileWindowHeaderHeight +1;
|
||
windowBounds.bottom -= (kScrollBarWidth -1);
|
||
windowBounds.right -= (kScrollBarWidth -1);
|
||
UInt16 windowHeight = windowBounds.bottom - windowBounds.top;
|
||
|
||
// decide how many pixels to scroll (and in which direction)
|
||
SInt16 delta = 0;
|
||
switch(controlPart)
|
||
{
|
||
case kControlUpButtonPart: // up (20)
|
||
delta = -kFileWindowRowHeight;
|
||
break;
|
||
|
||
case kControlDownButtonPart: // down (21)
|
||
delta = kFileWindowRowHeight;
|
||
break;
|
||
|
||
case kControlPageUpPart: // page up (22)
|
||
delta = kFileWindowRowHeight - windowHeight;
|
||
break;
|
||
|
||
case kControlPageDownPart: // page down (23)
|
||
delta = windowHeight - kFileWindowRowHeight;
|
||
break;
|
||
}
|
||
|
||
// calculate and correct control value
|
||
SInt16 max = GetControlMaximum(control);
|
||
SInt16 startValue = GetControlValue(control);
|
||
SInt16 endValue = startValue + delta;
|
||
if(endValue < 0) endValue = 0;
|
||
if(endValue > max) endValue = max;
|
||
|
||
// only update window if anything changed
|
||
if(endValue != startValue || controlPart == kControlIndicatorPart)
|
||
{
|
||
SetControlValue(control, endValue);
|
||
winObj->Update();
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|
||
/*** NEW RESOURCE SHEET WINDOW EVENT HANDLER ***/
|
||
pascal OSStatus NewResourceEventHandler(EventHandlerCallRef callRef, EventRef event, void *userData)
|
||
{
|
||
#pragma unused(callRef, userData)
|
||
// get control that was hit
|
||
UInt32 command;
|
||
ControlRef control;
|
||
GetEventParameter(event, kEventParamDirectObject, typeControlRef, null, sizeof(ControlRef), null, &control);
|
||
GetControlCommandID(control, &command);
|
||
|
||
// get parent window (so resource is added to correct file)
|
||
WindowRef parent;
|
||
WindowRef sheet = GetControlOwner(control);
|
||
GetSheetWindowParent(sheet, &parent);
|
||
FileWindowPtr file = (FileWindowPtr) GetWindowRefCon(parent);
|
||
|
||
// do the button action
|
||
switch(command)
|
||
{
|
||
case kHICommandOK:
|
||
{ // close the sheet
|
||
HideSheetWindow(sheet);
|
||
DisposeWindow(sheet);
|
||
|
||
// extract all the info about the resource we need
|
||
Str255 name = "\pTest Resource Beta";
|
||
ResType type = 'test';
|
||
SInt16 resID = 129;
|
||
SInt16 attribs = 0;
|
||
file->CreateNewResource(name, type, resID, attribs);
|
||
} break;
|
||
|
||
case kHICommandCancel:
|
||
// close the sheet
|
||
HideSheetWindow(sheet);
|
||
DisposeWindow(sheet);
|
||
break;
|
||
|
||
default:
|
||
DebugError("\pCommand assigned to that control was not dealt with.");
|
||
}
|
||
return noErr;
|
||
}
|
||
|
||
/********************************/
|
||
/* FILE WINDOW DRAWING ROUTINES */
|
||
/********************************/
|
||
|
||
#if !TARGET_API_MAC_CARBON
|
||
|
||
/*** UPDATE SCROLL BARS ***/
|
||
OSStatus FileWindow::UpdateScrollBars(void)
|
||
{
|
||
// get rect into which I can draw
|
||
Rect windowBounds;
|
||
if(g.windowMgrAvailable) GetWindowBounds(window, kWindowContentRgn, &windowBounds);
|
||
else GetPortBounds((CGrafPort *) window, &windowBounds);
|
||
windowBounds.top += kFileWindowHeaderHeight +1;
|
||
windowBounds.bottom -= (kScrollBarWidth -1);
|
||
windowBounds.right -= (kScrollBarWidth -1);
|
||
UInt16 windowHeight = windowBounds.bottom - windowBounds.top;
|
||
|
||
// horizontal scroll bar
|
||
if(nameColumnWidth + kFileWindowAllOtherColumnWidths - windowBounds.right <= 0)
|
||
SetControlMaximum(horizScroll, 0);
|
||
else SetControlMaximum(horizScroll, nameColumnWidth + kFileWindowAllOtherColumnWidths - windowBounds.right);
|
||
|
||
// vertical scroll bar
|
||
SInt16 value = GetControlValue(vertScroll);
|
||
if(windowHeight > numResources * kFileWindowRowHeight - value)
|
||
SetControlMaximum(vertScroll, value);
|
||
else SetControlMaximum(vertScroll, numResources * kFileWindowRowHeight - windowHeight);
|
||
return noErr;
|
||
}
|
||
|
||
/*** DRAW RESOURCE ICON ***/
|
||
OSStatus FileWindow::DrawResourceIcon(ResourceObjectPtr resource, UInt16 line)
|
||
{
|
||
OSStatus error = noErr;
|
||
Rect nameRect, iconRect;
|
||
Str255 nameStr;
|
||
IconAlignmentType alignment;
|
||
IconTransformType transformation;
|
||
SInt16 value = GetControlValue(vertScroll);
|
||
|
||
// resource icon
|
||
alignment = kAlignNone;
|
||
if(resource->Selected()) transformation = kTransformSelected;
|
||
else transformation = kTransformNone;
|
||
SetRect(&iconRect, 0, 0, 16, 16);
|
||
OffsetRect(&iconRect, kFileWindowNameColumnTextOffset -20, kFileWindowHeaderHeight + (kFileWindowRowHeight * line) - (kFileWindowRowHeight/2) - 8 - value);
|
||
|
||
IconSuiteRef iconSuite;
|
||
GetIconSuite(&iconSuite, kDefaultResourceIcon, kSelectorAllSmallData);
|
||
error = PlotIconSuite(&iconRect, alignment, transformation, iconSuite);
|
||
if(error) return error;
|
||
|
||
/* IconSelectorValue whichIcons = kSelectorSmall32Bit | kSelectorSmall8BitMask;
|
||
IconFamilyHandle iconFamily;
|
||
IconSuiteRef iconSuite;
|
||
|
||
iconFamily = (IconFamilyHandle) Get1Resource(kIconFamilyType, kDefaultResourceIcon);
|
||
IconFamilyToIconSuite(iconFamily, whichIcons, &iconSuite);
|
||
PlotIconSuite(&iconRect, alignment, transformation, iconSuite);
|
||
DisposeIconSuite(iconSuite, false);
|
||
ReleaseResource((Handle) iconFamily);
|
||
*/
|
||
// get name
|
||
if(*resource->Name() != 0x00)
|
||
{
|
||
CopyPString(resource->name, nameStr);
|
||
}
|
||
else
|
||
{
|
||
Str255 unnamedStr;
|
||
if(resource->dataFork) GetIndString(unnamedStr, kResourceNameStrings, kStringDataFork);
|
||
else if(resource->ID() == -16455 && (resource->Type() == 'icns' || resource->Type() == 'icl8' || resource->Type() == 'icl4' || resource->Type() == 'ICN#' || resource->Type() == 'ics8' || resource->Type() == 'ics4' || resource->Type() == 'ics#'))
|
||
GetIndString(unnamedStr, kResourceNameStrings, kStringCustomIcon);
|
||
else GetIndString(unnamedStr, kResourceNameStrings, kStringUntitledResource);
|
||
CopyPString(unnamedStr, nameStr);
|
||
}
|
||
|
||
// condense & italicise if necessary
|
||
if(StringWidth(nameStr) > nameColumnWidth - 45)
|
||
{
|
||
if(resource->Dirty()) TextFace(condense | bold);
|
||
else TextFace(condense);
|
||
}
|
||
else
|
||
{
|
||
if(resource->Dirty()) TextFace(bold);
|
||
else TextFace(normal);
|
||
}
|
||
|
||
// add ellipsis if necessary
|
||
while(StringWidth(nameStr) > nameColumnWidth - kFileWindowNameColumnTextOffset -3)
|
||
{
|
||
nameStr[0] -= 1; // shorten string
|
||
nameStr[ nameStr[0] ] = 0xC9; // replace new last char with '<27>'
|
||
}
|
||
|
||
// set text/box colour
|
||
if(*resource->Name() == 0x00)
|
||
RGBForeColor(&g.frameColour);
|
||
else RGBForeColor(&g.black);
|
||
|
||
// draw hilight box if selected
|
||
if(resource->Selected())
|
||
{
|
||
SetRect(&nameRect, 0, 0, StringWidth(nameStr) +4, kFileWindowTextHeight);
|
||
OffsetRect(&nameRect, kFileWindowNameColumnTextOffset -2, kFileWindowHeaderHeight + (kFileWindowRowHeight * line) - (kFileWindowRowHeight - kFileWindowTextHeight)/2 - kFileWindowTextHeight - value);
|
||
PaintRect(&nameRect);
|
||
RGBForeColor(&g.white); // set text colour to white
|
||
}
|
||
|
||
// draw name in set colour
|
||
SInt16 font;
|
||
GetFNum("\pGeneva", &font);
|
||
TextFont(font);
|
||
TextSize(10);
|
||
// TextFont(kControlFontSmallSystemFont); // doesn't give right effect
|
||
MoveTo(kFileWindowNameColumnTextOffset, kFileWindowHeaderHeight + (kFileWindowRowHeight * line) - (kFileWindowRowHeight - kFileWindowTextHeight)/2 - 3 - value);
|
||
DrawString(nameStr);
|
||
RGBForeColor(&g.black);
|
||
|
||
// create name & icon region for click detection and dragging
|
||
RgnHandle addRgn = NewRgn();
|
||
if(!addRgn)
|
||
{
|
||
DisposeIconSuite(iconSuite, true);
|
||
return memFullErr;
|
||
}
|
||
|
||
if(resource->nameIconRgn)
|
||
DisposeRgn(resource->nameIconRgn);
|
||
resource->nameIconRgn = NewRgn();
|
||
if(!resource->nameIconRgn)
|
||
{
|
||
DisposeRgn(addRgn);
|
||
DisposeIconSuite(iconSuite, true);
|
||
return memFullErr;
|
||
}
|
||
|
||
// resource icon
|
||
SetRect(&iconRect, 0, 0, 16, 16);
|
||
OffsetRect(&iconRect, 22, kFileWindowHeaderHeight + (kFileWindowRowHeight * (line-1)) +2);
|
||
IconSuiteToRgn(resource->nameIconRgn, &iconRect, kAlignNone, iconSuite);
|
||
|
||
// resource name
|
||
SetRect(&nameRect, 0, 0, StringWidth(nameStr) +4, kFileWindowTextHeight);
|
||
OffsetRect(&nameRect, 40, kFileWindowHeaderHeight + (kFileWindowRowHeight * (line-1)) +3);
|
||
RectRgn(addRgn, &nameRect); // convert textRect to region
|
||
UnionRgn(addRgn, resource->nameIconRgn, resource->nameIconRgn); // add new region to icon region
|
||
DisposeRgn(addRgn);
|
||
DisposeIconSuite(iconSuite, true);
|
||
return error;
|
||
}
|
||
|
||
#endif
|
||
|
||
/*****************************/
|
||
/* RESOURCE MAP MANIPULATION */
|
||
/*****************************/
|
||
|
||
/*** DISPLAY NEW RESOURCE SHEET ***/
|
||
OSStatus FileWindow::DisplayNewResourceSheet(void)
|
||
{
|
||
#if TARGET_API_MAC_CARBON
|
||
// create a nib reference (only searches the application bundle)
|
||
IBNibRef nibRef = null;
|
||
OSStatus error = CreateNibReference(CFSTR("ResKnife"), &nibRef);
|
||
if(error != noErr)
|
||
{
|
||
DisplayError("\pThe nib file reference could not be obtained.");
|
||
return error;
|
||
}
|
||
|
||
// create save sheet
|
||
WindowRef sheet;
|
||
error = CreateWindowFromNib(nibRef, CFSTR("New Resource"), &sheet);
|
||
if(error != noErr)
|
||
{
|
||
DisplayError("\pA sheet window could not be obtained from the nib file.");
|
||
return error;
|
||
}
|
||
|
||
// dispose of nib ref
|
||
DisposeNibReference(nibRef);
|
||
|
||
// install window event handler
|
||
EventTypeSpec events = { kEventClassControl, kEventControlHit };
|
||
EventHandlerUPP eventHandler = NewEventHandlerUPP(NewResourceEventHandler);
|
||
InstallWindowEventHandler(sheet, eventHandler, 1, &events, 0, null);
|
||
|
||
// show sheet window
|
||
ShowSheetWindow(sheet, window);
|
||
return error;
|
||
#else
|
||
return eventNotHandledErr;
|
||
#endif
|
||
}
|
||
|
||
/*** DISPLAY NEW RESOURCE DIALOG ***/
|
||
OSStatus FileWindow::DisplayNewResourceDialog(void)
|
||
{
|
||
// create and show dialog
|
||
OSStatus error = noErr;
|
||
GrafPtr oldPort;
|
||
DialogRef dialog = GetNewDialog(kNewResourceDialog, null, kFirstWindowOfClass);
|
||
SetDialogDefaultItem(dialog, ok);
|
||
GetPort(&oldPort);
|
||
SetPortWindowPort(GetDialogWindow(dialog));
|
||
ShowWindow(GetDialogWindow(dialog));
|
||
|
||
// set up variables
|
||
Str255 name = "\pTest Resource Alpha";
|
||
ResType type = 'test';
|
||
SInt16 resID = 128;
|
||
SInt16 attributes = 0x0000;
|
||
|
||
// handle dialog events
|
||
Rect box;
|
||
Handle item;
|
||
short itemHit;
|
||
DialogItemType itemType;
|
||
do
|
||
{
|
||
ModalDialog(null, &itemHit);
|
||
GetDialogItem(dialog, itemHit, &itemType, &item, &box);
|
||
switch(itemHit)
|
||
{
|
||
case 5:
|
||
{ Str255 popupText;
|
||
MenuRef popupMenu = GetMenu(140);
|
||
SInt16 popupItem = GetControlValue((ControlRef) item);
|
||
GetMenuItemText(popupMenu, popupItem, popupText);
|
||
GetDialogItem(dialog, 4, &itemType, &item, &box);
|
||
SetDialogItemText(item, popupText);
|
||
if(popupItem == 1) SelectDialogItemText(dialog, 4, 0x0000, 0x0000);
|
||
else SelectDialogItemText(dialog, 4, 0x0000, 0xFFFF);
|
||
RgnHandle updateRgn = NewRgn();
|
||
RectRgn(updateRgn, &box);
|
||
UpdateDialog(dialog, updateRgn);
|
||
DisposeRgn(updateRgn);
|
||
DisposeMenu(popupMenu);
|
||
} break;
|
||
|
||
case 7:
|
||
case 8:
|
||
case 9:
|
||
case 10:
|
||
case 11:
|
||
{ attributes ^= 1 << (itemHit -5);
|
||
SetControlValue((ControlRef) item, (short) (attributes & 1 << (itemHit -5)));
|
||
} break;
|
||
}
|
||
} while(itemHit != ok && itemHit != cancel);
|
||
|
||
HideWindow(GetDialogWindow(dialog));
|
||
if(itemHit == cancel)
|
||
{
|
||
DisposeDialog(dialog);
|
||
SetPort(oldPort);
|
||
return userCanceledErr;
|
||
}
|
||
else
|
||
{
|
||
|
||
// get resource name
|
||
GetDialogItem(dialog, 3, &itemType, &item, &box);
|
||
GetDialogItemText(item, name);
|
||
|
||
// get resource type
|
||
Str255 string;
|
||
GetDialogItem(dialog, 4, &itemType, &item, &box);
|
||
GetDialogItemText(item, string);
|
||
if(*string != sizeof(ResType))
|
||
{
|
||
DisplayError("\pInvalid resource type given", "\pYou should either choose a type from the pop-up menu, or enter a four character resource type of your own.");
|
||
SetPort(oldPort);
|
||
DisposeDialog(dialog);
|
||
return paramErr;
|
||
}
|
||
BlockMoveData(string +1, &type, sizeof(ResType));
|
||
|
||
// get resource ID
|
||
long number;
|
||
GetDialogItem(dialog, 6, &itemType, &item, &box);
|
||
GetDialogItemText(item, string);
|
||
StringToNum(string, &number);
|
||
if(number < -32768 || number > 32767)
|
||
{
|
||
DisplayError("\pInvalid resource ID chosen", "\pYou have to pick a number between -32768 and +32767. All ID numbers less than 128 are reserved by Apple.");
|
||
SetPort(oldPort);
|
||
DisposeDialog(dialog);
|
||
return paramErr;
|
||
}
|
||
resID = (short) number;
|
||
|
||
// create resource
|
||
error = CreateNewResource(name, type, resID, attributes);
|
||
}
|
||
SetPort(oldPort);
|
||
DisposeDialog(dialog);
|
||
return error;
|
||
}
|
||
|
||
/*** CREATE NEW RESOURCE ***/
|
||
OSStatus FileWindow::CreateNewResource(ConstStr255Param name, ResType type, SInt16 resID, SInt16 attributes)
|
||
{
|
||
// cycle through ResourceObject chain
|
||
OSStatus error = noErr;
|
||
ResourceObjectPtr last = resourceMap, addition = (ResourceObjectPtr) NewPtrClear(sizeof(ResourceObject));
|
||
while(last->next) last = last->next;
|
||
|
||
// append new resource to chain
|
||
last->next = addition;
|
||
addition->file = this;
|
||
addition->number = last->number + 1;
|
||
addition->data = NewHandleClear(0);
|
||
BlockMoveData(name, addition->name, sizeof(Str255));
|
||
addition->size = 0;
|
||
addition->type = type;
|
||
addition->resID = resID;
|
||
addition->attribs = attributes;
|
||
|
||
// update the file's resource counts
|
||
numResources += 1;
|
||
if(GetResourceCount(type) == 0)
|
||
numTypes += 1;
|
||
|
||
#if TARGET_API_MAC_CARBON
|
||
// add the resource to the databrowser
|
||
error = AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, 1, &addition->number, kDataBrowserItemNoProperty);
|
||
#endif
|
||
|
||
// mark file as dirty
|
||
fileDirty = true;
|
||
SetWindowModified(window, fileDirty);
|
||
|
||
return error;
|
||
}
|
||
|
||
/*** OPEN RESOURCE ***/
|
||
OSStatus FileWindow::OpenResource(DataBrowserItemID itemID, MenuCommand command)
|
||
{
|
||
#pragma unused(command)
|
||
// get opened resource
|
||
OSStatus error = noErr;
|
||
// Boolean stop = false;
|
||
ResourceObjectPtr resource = GetResource(itemID);
|
||
|
||
// check for null resource
|
||
if(resource == null)
|
||
{
|
||
DisplayError("\pYou just double-clicked on a non-existant resource!");
|
||
return paramErr;
|
||
}
|
||
|
||
// open correct editor
|
||
switch(command)
|
||
{
|
||
case kMenuCommandOpenHex:
|
||
LoadEditor(resource, "\pHex Editor");
|
||
break;
|
||
|
||
case kMenuCommandOpenDefault:
|
||
Str255 typeStr;
|
||
TypeToPString(resource->Type(), typeStr);
|
||
AppendPString(typeStr, "\p Editor");
|
||
LoadEditor(resource, typeStr);
|
||
break;
|
||
|
||
case kMenuCommandOpenTemplate:
|
||
LoadEditor(resource, "\pTemplate Editor");
|
||
error = eventNotHandledErr;
|
||
break;
|
||
|
||
case kMenuCommandOpenSpecific:
|
||
// bug: display template selection dialog here
|
||
error = eventNotHandledErr;
|
||
break;
|
||
|
||
default:
|
||
DebugError("\pWrong command sent to FileWindow::OpenResource()");
|
||
error = eventNotHandledErr;
|
||
break;
|
||
}
|
||
return error;
|
||
}
|
||
|
||
/*** DISPOSE RESOURCE MAP ***/
|
||
OSStatus FileWindow::DisposeResourceMap()
|
||
{
|
||
if(!resourceMap) return noErr; // resource map already disposed
|
||
|
||
UInt32 numDeleted = 0;
|
||
ResourceObjectPtr current = resourceMap, next;
|
||
while(current)
|
||
{
|
||
next = current->Next();
|
||
if(current->nameIconRgn) DisposeRgn(current->nameIconRgn);
|
||
if(current->data) DisposeHandle(current->data);
|
||
DisposePtr((Ptr) current);
|
||
// delete current;
|
||
numDeleted += 1;
|
||
current = next;
|
||
}
|
||
if(numResources != numDeleted) return paramErr; // my lazy way of saying I don't know what happened
|
||
else return noErr;
|
||
}
|
||
|
||
/******************/
|
||
/* SOUND ROUTINES */
|
||
/******************/
|
||
|
||
/*** PLAY SOUND ***/
|
||
OSStatus FileWindow::PlaySound(DataBrowserItemID itemID)
|
||
{
|
||
long refNum = 0; // unused
|
||
ResourceObjectPtr resource = GetResource(itemID);
|
||
if(resource->Data())
|
||
{
|
||
SInt8 state = HGetState(resource->Data());
|
||
HLock(resource->Data());
|
||
if(g.asyncSound) SHPlayByHandle(resource->Data(), &refNum);
|
||
else SndPlay(nil, (SndListHandle) resource->Data(), false);
|
||
HSetState(resource->Data(), state);
|
||
}
|
||
return noErr;
|
||
}
|
||
|
||
/*******************************/
|
||
/* VARIABLE ACCESSOR FUNCTIONS */
|
||
/*******************************/
|
||
|
||
/*** GET FILE SPEC ***/
|
||
FSSpecPtr FileWindow::GetFileSpec(void)
|
||
{
|
||
return fileSpec;
|
||
}
|
||
|
||
/*** SET FILE SPEC ***/
|
||
void FileWindow::SetFileSpec(FSSpecPtr spec)
|
||
{
|
||
fileExists = spec? true:false;
|
||
if(fileExists)
|
||
{
|
||
BlockMoveData((Ptr) spec, (Ptr) fileSpec, sizeof(FSSpec));
|
||
SetWindowProxyFSSpec(window, fileSpec);
|
||
SetWindowModified(window, fileDirty);
|
||
}
|
||
else
|
||
{
|
||
DisposePtr((Ptr) fileSpec);
|
||
fileSpec = (FSSpecPtr) NewPtrClear(sizeof(FSSpec));
|
||
SetWindowProxyCreatorAndType(window, kResKnifeCreator, kResourceFileType, kOnSystemDisk);
|
||
SetWindowModified(window, true);
|
||
}
|
||
}
|
||
|
||
/*** IS FILE DIRTY ***/
|
||
Boolean FileWindow::IsFileDirty(void)
|
||
{
|
||
return fileDirty;
|
||
}
|
||
|
||
/*** SET FILE DIRTY ***/
|
||
void FileWindow::SetFileDirty(Boolean dirty)
|
||
{
|
||
fileDirty = dirty; // bug: used to crash my machine but mysteriously doesn't any more
|
||
SetWindowModified(window, dirty);
|
||
}
|
||
|
||
#if TARGET_API_MAC_CARBON
|
||
|
||
/*** GET DATA BROWSER ***/
|
||
ControlRef FileWindow::GetDataBrowser(void)
|
||
{
|
||
return dataBrowser;
|
||
}
|
||
|
||
#endif
|
||
|
||
/**********************/
|
||
/* RESOURCE ACCESSORS */
|
||
/**********************/
|
||
|
||
/*** GET RESOURCE COUNT ***/
|
||
UInt32 FileWindow::GetResourceCount(ResType wanted)
|
||
{
|
||
#pragma unused(wanted)
|
||
return numResources;
|
||
}
|
||
|
||
/*** GET RESOURCE ***/
|
||
ResourceObjectPtr FileWindow::GetResource(DataBrowserItemID itemID)
|
||
{
|
||
ResourceObjectPtr res = resourceMap;
|
||
if(itemID == kDataBrowserNoItem) return null;
|
||
while(itemID != res->Number())
|
||
{
|
||
res = res->Next();
|
||
if(res == null) return null;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
/*** GET RESOURCE NAME ***/
|
||
UInt8* FileWindow::GetResourceName(DataBrowserItemID itemID)
|
||
{
|
||
ResourceObjectPtr resource = GetResource(itemID);
|
||
if(resource == null) return null;
|
||
return resource->Name();
|
||
}
|
||
|
||
/*** GET RESOURCE SIZE ***/
|
||
UInt32 FileWindow::GetResourceSize(DataBrowserItemID itemID)
|
||
{
|
||
ResourceObjectPtr resource = GetResource(itemID);
|
||
if(resource == null) return null;
|
||
return resource->Size();
|
||
}
|
||
|
||
/*** GET RESOURCE TYPE ***/
|
||
ResType FileWindow::GetResourceType(DataBrowserItemID itemID)
|
||
{
|
||
ResourceObjectPtr resource = GetResource(itemID);
|
||
if(resource == null) return null;
|
||
return resource->Type();
|
||
}
|
||
|
||
/*** GET RESOURCE ID ***/
|
||
SInt16 FileWindow::GetResourceID(DataBrowserItemID itemID)
|
||
{
|
||
ResourceObjectPtr resource = GetResource(itemID);
|
||
if(resource == null) return null;
|
||
return resource->ID();
|
||
}
|
||
|
||
/*** GET RESOURCE ATTRIBUTES ***/
|
||
SInt16 FileWindow::GetResourceAttributes(DataBrowserItemID itemID)
|
||
{
|
||
ResourceObjectPtr resource = GetResource(itemID);
|
||
if(resource == null) return null;
|
||
return resource->Attributes();
|
||
} |