mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-13 18:27:35 +00:00
2071 lines
52 KiB
C++
2071 lines
52 KiB
C++
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|||
|
*
|
|||
|
* The contents of this file are subject to the Netscape Public License
|
|||
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|||
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|||
|
* http://www.mozilla.org/NPL/
|
|||
|
*
|
|||
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|||
|
* for the specific language governing rights and limitations under the
|
|||
|
* NPL.
|
|||
|
*
|
|||
|
* The Initial Developer of this code under the NPL is Netscape
|
|||
|
* Communications Corporation. Portions created by Netscape are
|
|||
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|||
|
* Reserved.
|
|||
|
*/
|
|||
|
|
|||
|
/***********************************************************************************
|
|||
|
* macutil.cp
|
|||
|
*
|
|||
|
* Various mac utility routines
|
|||
|
*
|
|||
|
***********************************************************************************/
|
|||
|
|
|||
|
#include <stdarg.h>
|
|||
|
|
|||
|
#include <Traps.h>
|
|||
|
#include <LPlaceHolder.h>
|
|||
|
#include <LHandleStream.h>
|
|||
|
//#include <LTextEngine.h>
|
|||
|
#include "macutil.h"
|
|||
|
#include "resgui.h"
|
|||
|
#include "uprefd.h"
|
|||
|
#include "ufilemgr.h"
|
|||
|
#include "uerrmgr.h"
|
|||
|
#include "xp.h"
|
|||
|
#include "cstring.h"
|
|||
|
#include "xpassert.h"
|
|||
|
#include "xp_trace.h"
|
|||
|
#include "macgui.h"
|
|||
|
#include "prefapi.h"
|
|||
|
#include "MoreDesktopMgr.h"
|
|||
|
extern "C" {
|
|||
|
#include "asyncCursors.h"
|
|||
|
}
|
|||
|
|
|||
|
#include "mfinder.h" // needed for workaround function to bug in Apple's
|
|||
|
// ::TruncText and ::TruncString - andrewb 6/20/97
|
|||
|
|
|||
|
#include "MoreMixedMode.h"
|
|||
|
#include "PascalString.h"
|
|||
|
|
|||
|
/*-----------------------------------------------------------------------------
|
|||
|
Layout Utilities
|
|||
|
-----------------------------------------------------------------------------*/
|
|||
|
|
|||
|
// Another mlanett special
|
|||
|
static void GetImageRect( LView* view, SPoint32* topLeft, SPoint32* botRight );
|
|||
|
static void GetImageRect( LView* view, SPoint32* topLeft, SPoint32* botRight )
|
|||
|
{
|
|||
|
/*
|
|||
|
Return the visible image of this view.
|
|||
|
*/
|
|||
|
SPoint32 frameLocation;
|
|||
|
SDimension16 frameSize;
|
|||
|
SPoint32 imageLocation;
|
|||
|
|
|||
|
view->GetFrameLocation( frameLocation );
|
|||
|
view->GetFrameSize( frameSize );
|
|||
|
view->GetImageLocation( imageLocation );
|
|||
|
|
|||
|
// convert local rectangle to image rectangle
|
|||
|
topLeft->h = frameLocation.h - imageLocation.h; // frameLocation.h - portOrigin.h - imageLocation.h;
|
|||
|
botRight->h = topLeft->h + frameSize.width;
|
|||
|
topLeft->v = frameLocation.v - imageLocation.v; // frameLocation.v - portOrigin.v - imageLocation.v;
|
|||
|
botRight->v = topLeft->v + frameSize.height;
|
|||
|
}
|
|||
|
|
|||
|
void RevealInImage( LView* view, SPoint32 selTopLeft, SPoint32 selBotRight )
|
|||
|
{
|
|||
|
/*
|
|||
|
Scroll the minimum amount necessary to reveal this image rectangle.
|
|||
|
In this diagram, the selection is scrolled above the visible rectangle.
|
|||
|
Therefore selection-top is less than image-top, so we need to scroll
|
|||
|
down by above-amount.
|
|||
|
/---\
|
|||
|
/---| |
|
|||
|
| \---/
|
|||
|
v
|
|||
|
/--------------\
|
|||
|
| |
|
|||
|
| |
|
|||
|
| |
|
|||
|
| |
|
|||
|
\--------------/
|
|||
|
*/
|
|||
|
SPoint32 iTopLeft;
|
|||
|
SPoint32 iBotRight;
|
|||
|
|
|||
|
GetImageRect( view, &iTopLeft, &iBotRight );
|
|||
|
|
|||
|
Int32 aboveAmount = selTopLeft.v - 20 - iTopLeft.v;
|
|||
|
Int32 belowAmount = selTopLeft.v + 20 - iTopLeft.v;
|
|||
|
Int32 leftAmount = selTopLeft.h - iTopLeft.h;
|
|||
|
Int32 rightAmount = selBotRight.h - iBotRight.h;
|
|||
|
|
|||
|
if ( aboveAmount < 0 )
|
|||
|
view->ScrollImageBy( 0, aboveAmount, TRUE );
|
|||
|
else if ( ( selBotRight.v - iBotRight.v ) > 0 )
|
|||
|
{
|
|||
|
// don't scroll the top off!
|
|||
|
// belowAmount and aboveAmount are negative
|
|||
|
// belowAmount must be (absolute) less than aboveAmount
|
|||
|
view->ScrollImageBy( 0, belowAmount > aboveAmount ? aboveAmount : belowAmount, TRUE );
|
|||
|
}
|
|||
|
|
|||
|
if ( leftAmount < 0 )
|
|||
|
view->ScrollImageBy( leftAmount, 0, TRUE );
|
|||
|
else if ( rightAmount > 0 )
|
|||
|
{
|
|||
|
// don't scroll the left off!
|
|||
|
// belowAmount and leftAmount are negative
|
|||
|
// belowAmount must be (absolute) less than aboveAmount
|
|||
|
view->ScrollImageBy( rightAmount > leftAmount? leftAmount: rightAmount, 0, TRUE );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Boolean TooDifferent( const Point& a, const Point& b )
|
|||
|
{
|
|||
|
return abs( b.h - a.h ) >= MOUSE_HYSTERESIS || abs( b.v - a.v ) >= MOUSE_HYSTERESIS;
|
|||
|
}
|
|||
|
|
|||
|
short WaitForMouseAction( const Point& initial, long clickStart, long delay )
|
|||
|
{
|
|||
|
Point current;
|
|||
|
long now;
|
|||
|
|
|||
|
while ( ::StillDown() )
|
|||
|
{
|
|||
|
::GetMouse( ¤t );
|
|||
|
if ( TooDifferent( initial, current ) )
|
|||
|
return MOUSE_DRAGGING;
|
|||
|
now = ::TickCount();
|
|||
|
if ( abs( now - clickStart ) > delay)
|
|||
|
return MOUSE_TIMEOUT;
|
|||
|
}
|
|||
|
|
|||
|
return MOUSE_UP_EARLY;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int // offset
|
|||
|
CalcCurrentSelected (lo_FormElementSelectData * selectData, Boolean fromDefaults)
|
|||
|
{
|
|||
|
int offset = 0;
|
|||
|
|
|||
|
lo_FormElementOptionData * optionData;
|
|||
|
PA_LOCK(optionData, lo_FormElementOptionData *, selectData->options);
|
|||
|
for (int i=0; i<selectData->option_cnt; i++) {
|
|||
|
char * itemName = NULL;
|
|||
|
PA_LOCK(itemName, char*, optionData[i].text_value);
|
|||
|
if (fromDefaults) {
|
|||
|
if (optionData[i].def_selected) {
|
|||
|
offset = i;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
if (optionData[i].selected) {
|
|||
|
offset = i;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
PA_UNLOCK(optionData[i].text_value);
|
|||
|
}
|
|||
|
PA_UNLOCK(selectData->options);
|
|||
|
|
|||
|
return offset;
|
|||
|
}
|
|||
|
|
|||
|
/*-----------------------------------------------------------------------------
|
|||
|
Generic Utilities
|
|||
|
-----------------------------------------------------------------------------*/
|
|||
|
|
|||
|
Rect CenterInRect( Point thing, Rect destSpace )
|
|||
|
{
|
|||
|
Point destSize;
|
|||
|
Point centeredSize;
|
|||
|
Rect centeredThing;
|
|||
|
|
|||
|
destSize.h = destSpace.right - destSpace.left;
|
|||
|
destSize.v = destSpace.bottom - destSpace.top;
|
|||
|
centeredSize.h = MIN( destSize.h, thing.h );
|
|||
|
centeredSize.v = MIN( destSize.v, thing.v );
|
|||
|
centeredThing.left = destSpace.left + ( destSize.h - centeredSize.h ) / 2;
|
|||
|
centeredThing.top = destSpace.top + ( destSize.v - centeredSize.v ) / 2;
|
|||
|
centeredThing.right = centeredThing.left + centeredSize.h;
|
|||
|
centeredThing.bottom = centeredThing.top + centeredSize.v;
|
|||
|
return centeredThing;
|
|||
|
}
|
|||
|
|
|||
|
/*-----------------------------------------------------------------------------
|
|||
|
String Copying
|
|||
|
-----------------------------------------------------------------------------*/
|
|||
|
|
|||
|
unsigned char* CopyString( unsigned char* destination, const unsigned char* source )
|
|||
|
{
|
|||
|
BlockMove (source, destination, source[0]+1);
|
|||
|
return destination;
|
|||
|
}
|
|||
|
|
|||
|
unsigned char* CopyString( unsigned char* destination, const char* source )
|
|||
|
{
|
|||
|
destination[0] = strlen (source);
|
|||
|
BlockMove (source, destination + 1, destination[0]);
|
|||
|
return destination;
|
|||
|
}
|
|||
|
|
|||
|
char* CopyString( char* destination, const unsigned char* source )
|
|||
|
{
|
|||
|
BlockMove (source + 1, destination, source[0]);
|
|||
|
destination[source[0]] = 0;
|
|||
|
return destination;
|
|||
|
}
|
|||
|
|
|||
|
char* CopyString( char* destination, const char* source )
|
|||
|
{
|
|||
|
register int length = strlen (source);
|
|||
|
BlockMove (source, destination, length + 1);
|
|||
|
return destination;
|
|||
|
}
|
|||
|
|
|||
|
void CopyAlloc(char ** destination, StringPtr source)
|
|||
|
{
|
|||
|
// NET_SACopy frees a non-null destination itself
|
|||
|
//if (*destination != NULL)
|
|||
|
// XP_FREE(*destination);
|
|||
|
p2cstr(source);
|
|||
|
|
|||
|
// We don't really want to delete any existing storage for destination so borrow
|
|||
|
// some code from NET_SACopy and skip the XP_FREE of destination
|
|||
|
//NET_SACopy(destination, (char*)source);
|
|||
|
if (! source)
|
|||
|
{
|
|||
|
*destination = NULL;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
*destination = (char *) XP_ALLOC (XP_STRLEN((const char *)source) + 1);
|
|||
|
if (*destination != NULL)
|
|||
|
XP_STRCPY (*destination, (const char *)source);
|
|||
|
}
|
|||
|
|
|||
|
c2pstr((char*)source);
|
|||
|
}
|
|||
|
|
|||
|
// Takes colons out of a string
|
|||
|
void StripColons( CStr31& fileName )
|
|||
|
{
|
|||
|
short count;
|
|||
|
|
|||
|
for ( count = 1; count <= fileName.Length(); count++ )
|
|||
|
if ( fileName[count] == ':' )
|
|||
|
fileName[count] = ' ';
|
|||
|
}
|
|||
|
|
|||
|
// strips single instances of ch from the given string.
|
|||
|
// If ch appears twice in a row, the second one is not removed.
|
|||
|
void StripChar( CStr255& str, char ch )
|
|||
|
{
|
|||
|
int len = str.Length();
|
|||
|
for (short i = 1; i <= len; i++)
|
|||
|
if (str[i] == ch) {
|
|||
|
BlockMoveData(&str[i + 1], &str[i], len - i);
|
|||
|
i++;
|
|||
|
len -= 1;
|
|||
|
}
|
|||
|
str[0] = len;
|
|||
|
}
|
|||
|
|
|||
|
// <20> Takes a string of text (dragged/pasted), and turns
|
|||
|
// it into a URL (strips CR, whitespace preceeding/trailing <>
|
|||
|
void CleanUpTextToURL(char* text)
|
|||
|
{
|
|||
|
if (text == NULL)
|
|||
|
return;
|
|||
|
|
|||
|
long len = XP_STRLEN(text);
|
|||
|
|
|||
|
int i=0;
|
|||
|
|
|||
|
if (text[0] == '<') // Swallow the surrounding '<' and '>'
|
|||
|
::BlockMoveData(&text[1], &text[0], len);
|
|||
|
|
|||
|
while (text[i] != 0) // Loop till whitespace
|
|||
|
{
|
|||
|
if (XP_IS_SPACE(text[i]))
|
|||
|
break;
|
|||
|
i++;
|
|||
|
}
|
|||
|
if (text[i-1] == '>') // Swallow the ending '>'
|
|||
|
i--;
|
|||
|
|
|||
|
text[i] = 0;
|
|||
|
}
|
|||
|
|
|||
|
void CleanUpLocationString (CStr255 & url)
|
|||
|
{
|
|||
|
// Strips spaces & returns at end of url (happens often
|
|||
|
// when you paste into url box)
|
|||
|
int last;
|
|||
|
while ((last = url.Length()) != 0) {
|
|||
|
if (url[last] == '\n' || url[last] == ' ' || url[last] == '\r')
|
|||
|
url.Length()--;
|
|||
|
else break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// TRUE if the key is down. Bypasses the event loop
|
|||
|
Boolean IsThisKeyDown(const UInt8 theKey)
|
|||
|
{
|
|||
|
KeyMap map;
|
|||
|
|
|||
|
GetKeys(map);
|
|||
|
|
|||
|
return ((*((UInt8 *)map + (theKey >> 3)) >> (theKey & 7)) & 1) != 0;
|
|||
|
} // IsThisKeyDown - don's improved non-union (as in struct) version
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// A mess that figures out if cmd-. was pressed
|
|||
|
/* Borrowed from tech note 263 */
|
|||
|
|
|||
|
#define kMaskModifiers 0xFE00 // we need the modifiers without the
|
|||
|
// command key for KeyTrans
|
|||
|
#define kMaskVirtualKey 0x0000FF00 // get virtual key from event message
|
|||
|
// for KeyTrans
|
|||
|
#define kUpKeyMask 0x0080
|
|||
|
#define kShiftWord 8 // we shift the virtual key to mask it
|
|||
|
// into the keyCode for KeyTrans
|
|||
|
#define kMaskASCII1 0x00FF0000 // get the key out of the ASCII1 byte
|
|||
|
#define kMaskASCII2 0x000000FF // get the key out of the ASCII2 byte
|
|||
|
#define kPeriod 0x2E // ascii for a period
|
|||
|
Boolean CmdPeriod()
|
|||
|
{
|
|||
|
EvQElPtr eventQ = (EvQElPtr)LMGetEventQueue()->qHead;
|
|||
|
|
|||
|
while (eventQ != NULL)
|
|||
|
{
|
|||
|
EventRecord * theEvent = (EventRecord *)&eventQ->evtQWhat;
|
|||
|
|
|||
|
UInt16 keyCode;
|
|||
|
UInt32 state;
|
|||
|
long virtualKey, keyInfo, lowChar, highChar, keyCId;
|
|||
|
Handle hKCHR;
|
|||
|
Ptr KCHRPtr;
|
|||
|
|
|||
|
|
|||
|
if (((*theEvent).what == keyDown) || ((*theEvent).what == autoKey)) {
|
|||
|
|
|||
|
// see if the command key is down. If it is, find out the ASCII
|
|||
|
// equivalent for the accompanying key.
|
|||
|
|
|||
|
if ((*theEvent).modifiers & cmdKey ) {
|
|||
|
|
|||
|
virtualKey = ((*theEvent).message & kMaskVirtualKey) >> kShiftWord;
|
|||
|
// And out the command key and Or in the virtualKey
|
|||
|
keyCode = short(((*theEvent).modifiers & kMaskModifiers) | virtualKey);
|
|||
|
state = 0;
|
|||
|
|
|||
|
|
|||
|
hKCHR = nil; /* set this to nil before starting */
|
|||
|
KCHRPtr = (Ptr)GetScriptManagerVariable(smKCHRCache);
|
|||
|
|
|||
|
if ( !KCHRPtr ) {
|
|||
|
keyCId = ::GetScriptVariable(short(GetScriptManagerVariable(smKeyScript)), smScriptKeys);
|
|||
|
|
|||
|
hKCHR = GetResource('KCHR',short(keyCId));
|
|||
|
KCHRPtr = *hKCHR;
|
|||
|
}
|
|||
|
if (KCHRPtr) {
|
|||
|
keyInfo = KeyTranslate(KCHRPtr, keyCode, &state);
|
|||
|
if (hKCHR)
|
|||
|
ReleaseResource(hKCHR);
|
|||
|
} else
|
|||
|
keyInfo = (*theEvent).message;
|
|||
|
|
|||
|
lowChar = keyInfo & kMaskASCII2;
|
|||
|
highChar = (keyInfo & kMaskASCII1) >> 16;
|
|||
|
if (lowChar == kPeriod || highChar == kPeriod)
|
|||
|
return TRUE;
|
|||
|
|
|||
|
} // end the command key is down
|
|||
|
} // end key down event
|
|||
|
eventQ = (EvQElPtr)eventQ->qLink;
|
|||
|
}
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
// Sets button state and redraws it
|
|||
|
void SetEnable( LPane* button, Boolean enable )
|
|||
|
{
|
|||
|
if ( !button->IsEnabled() && enable )
|
|||
|
button->Enable();
|
|||
|
else if ( button->IsEnabled() && !enable )
|
|||
|
button->Disable();
|
|||
|
}
|
|||
|
|
|||
|
// Changes the string to something acceptable to mac menu manager
|
|||
|
void CreateMenuString( CStr255& itemName )
|
|||
|
{
|
|||
|
itemName=NET_UnEscape(itemName);
|
|||
|
if ( itemName.Length() > 50 ) // Cut it down to reasonable size
|
|||
|
{
|
|||
|
itemName.Length() = 50;
|
|||
|
itemName += "...";
|
|||
|
}
|
|||
|
if ( itemName.Length() && itemName[ 1 ] == '-' )
|
|||
|
itemName[ 1 ] = '<EFBFBD>';
|
|||
|
}
|
|||
|
|
|||
|
// TextHandleToHardLineBreaks
|
|||
|
// converts TextEdit handle to text handle that has hard carriage returns.
|
|||
|
|
|||
|
Handle TextHandleToHardLineBreaks( CSimpleTextView &inTextView )
|
|||
|
{
|
|||
|
Handle theOldText = inTextView.GetTextHandle();
|
|||
|
ThrowIfNULL_(theOldText);
|
|||
|
|
|||
|
SInt32 theTotalLength = inTextView.GetTextLength();
|
|||
|
|
|||
|
// TextRangeT theTotalRange = inEngine->GetTotalRange();
|
|||
|
|
|||
|
// Int32 theLineCount = inEngine->CountParts(theTotalRange, cLine);
|
|||
|
|
|||
|
Int32 theLineCount = inTextView.CountLines();
|
|||
|
|
|||
|
// text will expand by at most as many line breaks as there are lines
|
|||
|
Handle theNewText = ::NewHandle(theTotalLength + theLineCount);
|
|||
|
ThrowIfNULL_(theNewText);
|
|||
|
|
|||
|
// Lock down both text buffers
|
|||
|
StHandleLocker theOldLock(theOldText);
|
|||
|
StHandleLocker theNewLock(theNewText);
|
|||
|
|
|||
|
Int32 theBreakCount = 0;
|
|||
|
Int32 theNewTextOffset = 0;
|
|||
|
SInt32 lineStart = 0;
|
|||
|
SInt32 lineEnd = 0;
|
|||
|
|
|||
|
Boolean bEatAgain = false;
|
|||
|
|
|||
|
for (Int32 theIndex = 1; theIndex <= theLineCount; theIndex++)
|
|||
|
{
|
|||
|
// TextRangeT theLineRange;
|
|||
|
// inEngine->FindNthPart(theTotalRange, cLine, theIndex, &theLineRange);
|
|||
|
|
|||
|
// Waste appears to be Zero based rather than 1
|
|||
|
inTextView.GetLineRange( theIndex - 1, &lineStart, &lineEnd );
|
|||
|
|
|||
|
::BlockMoveData(*theOldText + lineStart, *theNewText + theNewTextOffset, lineEnd - lineStart );
|
|||
|
theNewTextOffset += lineEnd - lineStart;
|
|||
|
|
|||
|
Boolean eatNextLine = ((theIndex + 1) < theLineCount) && // This is to prevent overflow on end
|
|||
|
(((*theOldText)[lineStart] == '>' &&
|
|||
|
(*theOldText)[lineEnd + 1] != '>')) ||
|
|||
|
bEatAgain;
|
|||
|
|
|||
|
if ((*theNewText)[theNewTextOffset -1 ] == CR)
|
|||
|
{
|
|||
|
(*theNewText)[theNewTextOffset - 1] = CR;
|
|||
|
bEatAgain = false;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (eatNextLine)
|
|||
|
bEatAgain = true; // Only
|
|||
|
else
|
|||
|
{
|
|||
|
(*theNewText)[++theNewTextOffset - 1] = CR;
|
|||
|
bEatAgain = false;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
::SetHandleSize(theNewText, theNewTextOffset); // Reduce the size of the handle
|
|||
|
return theNewText;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ConstrainTo( const long& min, const long& max, long& value )
|
|||
|
{
|
|||
|
XP_WARN_ASSERT( min <= value && value <= max );
|
|||
|
if ( value < min )
|
|||
|
value = min;
|
|||
|
else if ( value > max )
|
|||
|
value = max;
|
|||
|
}
|
|||
|
|
|||
|
void * StructCopy(const void * struc, UInt32 size)
|
|||
|
{
|
|||
|
if (struc == NULL)
|
|||
|
return NULL;
|
|||
|
|
|||
|
void * newStruct = XP_ALLOC(size);
|
|||
|
if (newStruct == NULL)
|
|||
|
return NULL;
|
|||
|
::BlockMoveData(struc, newStruct, size);
|
|||
|
return newStruct;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void SetMenuSize( LStdPopupMenu* popup, short shouldBe )
|
|||
|
{
|
|||
|
MenuHandle menu;
|
|||
|
short count;
|
|||
|
|
|||
|
menu = popup->GetMacMenuH();
|
|||
|
count = ::CountMItems( menu );
|
|||
|
|
|||
|
while ( shouldBe > count )
|
|||
|
{
|
|||
|
InsertMenuItem( menu, "\p ", count );
|
|||
|
count++;
|
|||
|
}
|
|||
|
|
|||
|
while ( shouldBe < count )
|
|||
|
{
|
|||
|
DeleteMenuItem( menu, count );
|
|||
|
count--;
|
|||
|
}
|
|||
|
|
|||
|
popup->SetMinValue( 1 );
|
|||
|
popup->SetMaxValue( shouldBe );
|
|||
|
}
|
|||
|
|
|||
|
void SetMenuSizeForLGAPopup( LGAPopup* popup, short shouldBe )
|
|||
|
{
|
|||
|
MenuHandle menu;
|
|||
|
short count;
|
|||
|
|
|||
|
menu = popup->GetMacMenuH();
|
|||
|
count = ::CountMItems( menu );
|
|||
|
|
|||
|
while ( shouldBe > count )
|
|||
|
{
|
|||
|
InsertMenuItem( menu, "\p ", count );
|
|||
|
count++;
|
|||
|
}
|
|||
|
|
|||
|
while ( shouldBe < count )
|
|||
|
{
|
|||
|
DeleteMenuItem( menu, count );
|
|||
|
count--;
|
|||
|
}
|
|||
|
|
|||
|
popup->SetMinValue( 1 );
|
|||
|
popup->SetMaxValue( shouldBe );
|
|||
|
}
|
|||
|
|
|||
|
void SetMenuItem( CommandT whichItem, Boolean toState )
|
|||
|
{
|
|||
|
ResIDT menuID;
|
|||
|
MenuHandle menu = NULL;
|
|||
|
Int16 item;
|
|||
|
LMenuBar* currentMenuBar;
|
|||
|
|
|||
|
currentMenuBar = LMenuBar::GetCurrentMenuBar();
|
|||
|
|
|||
|
if (currentMenuBar)
|
|||
|
currentMenuBar->FindMenuItem( whichItem, menuID, menu, item );
|
|||
|
if (menu)
|
|||
|
{
|
|||
|
if ( toState )
|
|||
|
SetItemMark( menu, item, checkMark );
|
|||
|
else
|
|||
|
SetItemMark( menu, item, noMark );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// ---------------------------------------------------------------------------
|
|||
|
// <09> myStringToNum [static]
|
|||
|
// ---------------------------------------------------------------------------
|
|||
|
// Utility used the USizeMenu routines to convert strings to numbers that
|
|||
|
// ignores anything that's not a number
|
|||
|
|
|||
|
#define IsNumber_( x ) (( x ) >= '0' && ( x ) <= '9')
|
|||
|
|
|||
|
void myStringToNum( const CStr255& inString, Int32* outNum )
|
|||
|
{
|
|||
|
CStr255 temp;
|
|||
|
short j = 1;
|
|||
|
|
|||
|
for ( short i = 1; i <= inString[ 0 ]; i++ )
|
|||
|
{
|
|||
|
if ( IsNumber_( inString[ i ] ) )
|
|||
|
temp[ j++ ] = inString[ i ];
|
|||
|
}
|
|||
|
|
|||
|
temp[0] = j - 1;
|
|||
|
if (temp.Length() > 0)
|
|||
|
StringToNum( temp, outNum );
|
|||
|
}
|
|||
|
|
|||
|
short PointsToPixels( short inPoints, short iRes )
|
|||
|
{
|
|||
|
return ( (float)inPoints / 120.0 ) * iRes;
|
|||
|
}
|
|||
|
|
|||
|
void SetCaptionDescriptor( LCaption* captionToSet, const CStr255& newText,
|
|||
|
const TruncCode trunc )
|
|||
|
{
|
|||
|
XP_ASSERT( captionToSet );
|
|||
|
|
|||
|
CStr255 tempText( newText );
|
|||
|
SDimension16 captionSize;
|
|||
|
|
|||
|
captionToSet->GetFrameSize( captionSize );
|
|||
|
|
|||
|
// DANGER! There is a hideous crashing bug in Apple's ::TruncString
|
|||
|
// (and ::TruncText) when called with TruncMiddle
|
|||
|
if (trunc == truncMiddle)
|
|||
|
MiddleTruncationThatWorks(tempText, captionSize.width - 4);
|
|||
|
else
|
|||
|
TruncString( captionSize.width - 4, tempText, trunc );
|
|||
|
captionToSet->SetDescriptor( tempText );
|
|||
|
captionToSet->Refresh();
|
|||
|
}
|
|||
|
|
|||
|
void GetDateTimeString( CStr255& dateTime )
|
|||
|
{
|
|||
|
unsigned long dt;
|
|||
|
|
|||
|
::GetDateTime( &dt );
|
|||
|
::DateString( dt, longDate, dateTime, NULL );
|
|||
|
}
|
|||
|
|
|||
|
unsigned short GetTextLengthInPixels( LTextEdit* textEdit );
|
|||
|
unsigned short GetTextLengthInPixels( LTextEdit* textEdit )
|
|||
|
{
|
|||
|
XP_ASSERT( textEdit );
|
|||
|
|
|||
|
unsigned short width = 0;
|
|||
|
TEHandle macTEH = NULL;
|
|||
|
Handle text = NULL;
|
|||
|
short length = 0;
|
|||
|
|
|||
|
// <20> this sets up the current port with the right text traits
|
|||
|
if ( textEdit->FocusDraw() )
|
|||
|
{
|
|||
|
macTEH = textEdit->GetMacTEH();
|
|||
|
XP_ASSERT( macTEH );
|
|||
|
|
|||
|
text = (*macTEH)->hText;
|
|||
|
if ( text )
|
|||
|
{
|
|||
|
length = (*macTEH)->teLength;
|
|||
|
HLock( text );
|
|||
|
width = TextWidth( *text, 0, length );
|
|||
|
HUnlock( text );
|
|||
|
}
|
|||
|
}
|
|||
|
return width;
|
|||
|
}
|
|||
|
|
|||
|
// Could be optimized
|
|||
|
char * GetPaneDescriptor(LPane * pane)
|
|||
|
{
|
|||
|
char * ret = nil;
|
|||
|
CStr255 ptempStr;
|
|||
|
pane->GetDescriptor(ptempStr);
|
|||
|
cstring ctempStr((unsigned char*)ptempStr);
|
|||
|
if (ctempStr.length() > 0)
|
|||
|
StrAllocCopy(ret, ctempStr);
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
void TurnOn( LControl* control )
|
|||
|
{
|
|||
|
control->SetValue( TRUE );
|
|||
|
control->BroadcastMessage( msg_ControlClicked, (void*)control );
|
|||
|
}
|
|||
|
|
|||
|
Boolean SetPopupToNamedItem( LStdPopupMenu* whichMenu, const CStr255& itemText )
|
|||
|
{
|
|||
|
MenuHandle menuH;
|
|||
|
short menuSize;
|
|||
|
Str255 fontName;
|
|||
|
|
|||
|
menuH = whichMenu->GetMacMenuH();
|
|||
|
menuSize = CountMItems( menuH );
|
|||
|
|
|||
|
for ( short i = 1; i <= menuSize; i++ )
|
|||
|
{
|
|||
|
::GetMenuItemText( menuH, i, fontName );
|
|||
|
if ( itemText == (CStr255)fontName )
|
|||
|
{
|
|||
|
whichMenu->SetValue( i );
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
Boolean SetLGAPopupToNamedItem( LGAPopup* whichMenu, const CStr255& itemText )
|
|||
|
{
|
|||
|
MenuHandle menuH;
|
|||
|
short menuSize;
|
|||
|
Str255 fontName;
|
|||
|
|
|||
|
menuH = whichMenu->GetMacMenuH();
|
|||
|
menuSize = CountMItems( menuH );
|
|||
|
|
|||
|
for ( short i = 1; i <= menuSize; i++ )
|
|||
|
{
|
|||
|
::GetMenuItemText( menuH, i, fontName );
|
|||
|
if ( itemText == (CStr255)fontName )
|
|||
|
{
|
|||
|
whichMenu->SetValue( i );
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
unsigned long GetFreeSpaceInBytes( short vRefNum )
|
|||
|
{
|
|||
|
HVolumeParam pb;
|
|||
|
OSErr err;
|
|||
|
unsigned long result;
|
|||
|
|
|||
|
pb.ioCompletion = NULL;
|
|||
|
pb.ioVolIndex = 0;
|
|||
|
pb.ioNamePtr = NULL;
|
|||
|
pb.ioVRefNum = vRefNum;
|
|||
|
|
|||
|
err = PBHGetVInfoSync( (HParmBlkPtr)&pb );
|
|||
|
|
|||
|
if ( err == noErr )
|
|||
|
result = pb.ioVFrBlk * pb.ioVAlBlkSiz;
|
|||
|
else
|
|||
|
result = 0;
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
// <20> force a window to appear on the desktop
|
|||
|
void ForceWindowOnScreen( LWindow* window )
|
|||
|
{
|
|||
|
// <20><>get the desktop region
|
|||
|
StRegion desktopRgn( LMGetGrayRgn() );
|
|||
|
|
|||
|
Rect windowFrame;
|
|||
|
window->CalcPortFrameRect( windowFrame );
|
|||
|
windowFrame = PortToGlobalRect( window, windowFrame );
|
|||
|
|
|||
|
StRegion windowRgn( windowFrame );
|
|||
|
|
|||
|
StRegion destRgn;
|
|||
|
Rect newRect;
|
|||
|
|
|||
|
::SectRgn( windowRgn, desktopRgn, destRgn );
|
|||
|
|
|||
|
if ( ::EmptyRgn( destRgn ) ||
|
|||
|
!::EqualRgn( destRgn, windowRgn ) )
|
|||
|
{
|
|||
|
newRect = (**(static_cast<RgnHandle>(destRgn))).rgnBBox;
|
|||
|
|
|||
|
// <20> add 20 for title, 20 for menu bar
|
|||
|
newRect.top = 40 + 2;
|
|||
|
newRect.bottom = newRect.top + ( windowFrame.bottom - windowFrame.top );
|
|||
|
newRect.left = 2;
|
|||
|
newRect.right = newRect.left + ( windowFrame.right - windowFrame.left );
|
|||
|
|
|||
|
window->DoSetBounds( newRect );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
void GrowWindowToScreenHeight( LWindow* win )
|
|||
|
{
|
|||
|
GDHandle device;
|
|||
|
Rect windowFrame;
|
|||
|
|
|||
|
win->CalcPortFrameRect( windowFrame );
|
|||
|
windowFrame = PortToGlobalRect( win, windowFrame );
|
|||
|
|
|||
|
device = WindowOnSingleDevice( win );
|
|||
|
if ( device )
|
|||
|
{
|
|||
|
windowFrame.bottom = (**device).gdRect.bottom - 5;
|
|||
|
win->DoSetBounds( windowFrame );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static
|
|||
|
Boolean WillBeVisible( Rect& windowRect )
|
|||
|
{
|
|||
|
Rect newRect;
|
|||
|
Boolean result = FALSE;
|
|||
|
|
|||
|
StRegion desktopRgn( LMGetGrayRgn() );
|
|||
|
StRegion windowRgn( windowRect );
|
|||
|
StRegion destRgn;
|
|||
|
|
|||
|
::SectRgn( windowRgn, desktopRgn, destRgn );
|
|||
|
|
|||
|
newRect = (**static_cast<RgnHandle>(destRgn)).rgnBBox;
|
|||
|
|
|||
|
if ( EmptyRgn( destRgn ) )
|
|||
|
result = FALSE;
|
|||
|
else if ( !EqualRect( &newRect, &windowRect ) )
|
|||
|
result = FALSE;
|
|||
|
else
|
|||
|
result = TRUE;
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
void StaggerWindow( LWindow* win )
|
|||
|
{
|
|||
|
WindowPtr nextWindow;
|
|||
|
LWindow* similarWindow;
|
|||
|
Rect similarBounds;
|
|||
|
Rect bounds;
|
|||
|
Boolean changed = FALSE;
|
|||
|
|
|||
|
win->CalcPortFrameRect( bounds );
|
|||
|
bounds = PortToGlobalRect( win, bounds );
|
|||
|
// <20><>find the window with the same ID
|
|||
|
// if it has the same top left corner, offset our rect by 20, 5
|
|||
|
nextWindow = ::FrontWindow();
|
|||
|
while ( nextWindow )
|
|||
|
{
|
|||
|
similarWindow = LWindow::FetchWindowObject( nextWindow );
|
|||
|
nextWindow = (WindowPtr)( (WindowPeek)nextWindow )->nextWindow;
|
|||
|
if ( similarWindow &&
|
|||
|
similarWindow->GetPaneID() == win->GetPaneID() )
|
|||
|
{
|
|||
|
similarWindow->CalcPortFrameRect( similarBounds );
|
|||
|
similarBounds = PortToGlobalRect( similarWindow, similarBounds );
|
|||
|
|
|||
|
if ( ( similarBounds.top == bounds.top ) &&
|
|||
|
( similarBounds.left == bounds.left ) )
|
|||
|
{
|
|||
|
::OffsetRect( &bounds, 5, 20) ;
|
|||
|
changed = TRUE;
|
|||
|
// <20> loop again, because we might run into another window
|
|||
|
nextWindow = ::FrontWindow();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if ( changed )
|
|||
|
win->DoSetBounds( bounds );
|
|||
|
}
|
|||
|
|
|||
|
GDHandle WindowOnSingleDevice( LWindow* win )
|
|||
|
{
|
|||
|
// <20> loop thru all GDevices
|
|||
|
Rect windowFrame;
|
|||
|
GDHandle device;
|
|||
|
|
|||
|
win->CalcPortFrameRect( windowFrame );
|
|||
|
windowFrame = PortToGlobalRect( win, windowFrame );
|
|||
|
|
|||
|
device = GetDeviceList();
|
|||
|
|
|||
|
while ( device )
|
|||
|
{
|
|||
|
if ( UDrawingUtils::IsActiveScreenDevice( device ) )
|
|||
|
{
|
|||
|
Rect intersection;
|
|||
|
// <20> find intersection of Window with this active screen Device
|
|||
|
if ( ::SectRect( &windowFrame, &(**device).gdRect, &intersection ) )
|
|||
|
{
|
|||
|
// <20> window intersects this Device
|
|||
|
if ( ::EqualRect( &windowFrame, &intersection ) )
|
|||
|
return device;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
device = GetNextDevice( device );
|
|||
|
}
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
#define SAVE_VERSION 23
|
|||
|
|
|||
|
// <20> saving/restoring of the window's default state
|
|||
|
Boolean RestoreDefaultWindowState(LWindow* inWindow)
|
|||
|
{
|
|||
|
if (inWindow == NULL)
|
|||
|
return false;
|
|||
|
|
|||
|
// We are responsible for disposing of the window data
|
|||
|
Handle theWindowData = CPrefs::ReadWindowData(inWindow->GetPaneID());
|
|||
|
if (theWindowData == NULL)
|
|||
|
return false;
|
|||
|
|
|||
|
// The destructor of the stream will kill the window data
|
|||
|
LHandleStream stream(theWindowData);
|
|||
|
|
|||
|
Int32 version;
|
|||
|
stream.ReadData(&version, sizeof( version ) );
|
|||
|
if ( version != SAVE_VERSION )
|
|||
|
return false;
|
|||
|
|
|||
|
Rect theWindowBounds;
|
|||
|
stream.ReadData(&theWindowBounds, sizeof(theWindowBounds));
|
|||
|
|
|||
|
if (theWindowBounds.right > theWindowBounds.left &&
|
|||
|
theWindowBounds.bottom > theWindowBounds.top &&
|
|||
|
WillBeVisible(theWindowBounds) )
|
|||
|
inWindow->DoSetBounds(theWindowBounds);
|
|||
|
|
|||
|
inWindow->RestorePlace(&stream);
|
|||
|
ForceWindowOnScreen(inWindow);
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
void StoreDefaultWindowState( LWindow* win )
|
|||
|
{
|
|||
|
if ( !win )
|
|||
|
return;
|
|||
|
|
|||
|
LHandleStream stream;
|
|||
|
Rect windowBounds;
|
|||
|
Int32 version = SAVE_VERSION;
|
|||
|
|
|||
|
stream.WriteData( &version, sizeof( version ) );
|
|||
|
|
|||
|
win->EstablishPort();
|
|||
|
win->CalcPortFrameRect( windowBounds );
|
|||
|
windowBounds = PortToGlobalRect( win, windowBounds );
|
|||
|
stream.WriteData( &windowBounds, sizeof( windowBounds ) );
|
|||
|
|
|||
|
win->SavePlace( &stream );
|
|||
|
|
|||
|
CPrefs::WriteWindowData( stream.GetDataHandle(), win->GetPaneID() );
|
|||
|
}
|
|||
|
|
|||
|
// Is front window modal? Used for command enabling
|
|||
|
Boolean IsFrontWindowModal()
|
|||
|
{
|
|||
|
return UDesktop::FrontWindowIsModal();
|
|||
|
}
|
|||
|
|
|||
|
// <20><>Fetch a window title resource and fill in the current profile name
|
|||
|
void GetUserWindowTitle(short id, CStr255& title)
|
|||
|
{
|
|||
|
char profileName[32];
|
|||
|
int len = 32;
|
|||
|
PREF_GetCharPref("profile.name", profileName, &len);
|
|||
|
|
|||
|
::GetIndString( title, WINDOW_TITLES_RESID, id );
|
|||
|
|
|||
|
StringParamText(title, profileName);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// Returns true if we are the front application
|
|||
|
Boolean IsFrontApplication()
|
|||
|
{
|
|||
|
ProcessSerialNumber netscapeProcess;
|
|||
|
ProcessSerialNumber frontProcess;
|
|||
|
Boolean inFront;
|
|||
|
|
|||
|
OSErr err = ::GetCurrentProcess( &netscapeProcess );
|
|||
|
if ( err != noErr )
|
|||
|
return FALSE;
|
|||
|
err = ::GetFrontProcess( &frontProcess );
|
|||
|
if ( err != noErr )
|
|||
|
return FALSE;
|
|||
|
err = ::SameProcess( &frontProcess, &netscapeProcess, &inFront );
|
|||
|
if ( err != noErr )
|
|||
|
return FALSE;
|
|||
|
return inFront;
|
|||
|
}
|
|||
|
|
|||
|
void MakeFrontApplication()
|
|||
|
{
|
|||
|
ProcessSerialNumber netscapeProcess;
|
|||
|
OSErr err = ::GetCurrentProcess( &netscapeProcess );
|
|||
|
if (err == noErr)
|
|||
|
SetFrontProcess(&netscapeProcess);
|
|||
|
}
|
|||
|
|
|||
|
void FrameSubpaneSubtle( LView* view, LPane* pane )
|
|||
|
{
|
|||
|
Rect subFrame;
|
|||
|
|
|||
|
GetSubpaneRect( view, pane, subFrame );
|
|||
|
::InsetRect( &subFrame, -1, -1 );
|
|||
|
UGraphics::FrameRectSubtle( subFrame, true );
|
|||
|
}
|
|||
|
|
|||
|
void GetSubpaneRgn( LView* view, LPane* pane, RgnHandle rgn )
|
|||
|
{
|
|||
|
Rect frame;
|
|||
|
GetSubpaneRect( view, pane, frame );
|
|||
|
::RectRgn( rgn, &frame );
|
|||
|
}
|
|||
|
|
|||
|
void GetSubpaneRect( LView* view, LPane* pane, Rect& frame )
|
|||
|
{
|
|||
|
XP_ASSERT( view );
|
|||
|
XP_ASSERT( pane );
|
|||
|
pane->CalcPortFrameRect( frame );
|
|||
|
view->PortToLocalPoint( *(Point*)&( frame.top ) );
|
|||
|
view->PortToLocalPoint( *(Point*)&( frame.bottom) );
|
|||
|
}
|
|||
|
|
|||
|
void WriteVersionTag( LStream* stream, Int32 version )
|
|||
|
{
|
|||
|
stream->WriteData( &version, sizeof( version ) );
|
|||
|
}
|
|||
|
|
|||
|
Boolean ReadVersionTag( LStream* stream, Int32 version )
|
|||
|
{
|
|||
|
Int32 versionTag;
|
|||
|
stream->ReadData( &versionTag, sizeof( versionTag ) );
|
|||
|
return ( versionTag == version );
|
|||
|
}
|
|||
|
|
|||
|
void TrySetCursor( int whichCursor )
|
|||
|
{
|
|||
|
Cursor** c = GetCursor( whichCursor );
|
|||
|
if ( c )
|
|||
|
SetCursor( *c );
|
|||
|
#ifdef DEBUG
|
|||
|
else
|
|||
|
SysBeep( 1 );
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
void StripNewline( CStr255& msg )
|
|||
|
{
|
|||
|
if ( msg[ msg.Length() ] == '\n' )
|
|||
|
msg[ msg.Length() ] = 0;
|
|||
|
}
|
|||
|
|
|||
|
void StripDoubleCRs( CStr255& msg )
|
|||
|
{
|
|||
|
Boolean lastCR = FALSE;
|
|||
|
for ( UInt32 i = 1; i < msg.Length(); i++ )
|
|||
|
{
|
|||
|
if ( msg[ i ] == CR)
|
|||
|
{
|
|||
|
if ( lastCR )
|
|||
|
{
|
|||
|
msg[ i - 1 ] = ' ';
|
|||
|
lastCR = FALSE;
|
|||
|
}
|
|||
|
else
|
|||
|
lastCR = TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
lastCR = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
int ConvertCRtoLF(CStr255 & msg)
|
|||
|
{
|
|||
|
int ret = 0;
|
|||
|
for ( long i = 1; i <= msg[0]; i++ )
|
|||
|
if ( msg[ i ] == LF )
|
|||
|
{
|
|||
|
msg[ i ] = CR;
|
|||
|
ret++;
|
|||
|
}
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
Rect RectFromTwoPoints( Point p1, Point p2 )
|
|||
|
{
|
|||
|
Rect r;
|
|||
|
r.top = MIN( p1.v, p2.v );
|
|||
|
r.bottom = MAX( p1.v, p2.v );
|
|||
|
r.left = MIN( p1.h, p2.h );
|
|||
|
r.right = MAX( p1.h, p2.h );
|
|||
|
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
// Return true if inEnclosingRect encloses any portion of inCheckRect
|
|||
|
Boolean RectInRect(const Rect *inCheckRect, const Rect *inEnclosingRect) {
|
|||
|
|
|||
|
return (!::EmptyRect(inEnclosingRect) &&
|
|||
|
!((inCheckRect->right <= inEnclosingRect->left) ||
|
|||
|
(inCheckRect->bottom <= inEnclosingRect->top) ||
|
|||
|
(inCheckRect->left >= inEnclosingRect->right) ||
|
|||
|
(inCheckRect->top >= inEnclosingRect->bottom)));
|
|||
|
}
|
|||
|
|
|||
|
const RGBColor rgbBlack = { 0x0000, 0x0000, 0x0000 };
|
|||
|
const RGBColor rgbWhite = { 0xFFFF, 0xFFFF, 0xFFFF };
|
|||
|
|
|||
|
|
|||
|
void DrawAntsRect( Rect&r, short mode )
|
|||
|
{
|
|||
|
::PenPat( &(UQDGlobals::GetQDGlobals()->gray) );
|
|||
|
::PenMode( mode );
|
|||
|
::RGBForeColor( &rgbBlack );
|
|||
|
::RGBBackColor( &rgbWhite );
|
|||
|
::FrameRect( &r );
|
|||
|
}
|
|||
|
|
|||
|
FontInfo SafeGetFontInfo(ResIDT textTraits)
|
|||
|
{
|
|||
|
StTextState textState;
|
|||
|
UTextTraits::SetPortTextTraits(textTraits);
|
|||
|
FontInfo fInfo;
|
|||
|
::GetFontInfo(&fInfo);
|
|||
|
return fInfo;
|
|||
|
}
|
|||
|
|
|||
|
void FrameButton( const Rect& box, Boolean pushed )
|
|||
|
{
|
|||
|
UGraphics::FrameRectSubtle(box, pushed);
|
|||
|
}
|
|||
|
|
|||
|
void HiliteRect( const Rect& r )
|
|||
|
{
|
|||
|
LMSetHiliteMode( LMGetHiliteMode() & ! ( 1 << hiliteBit ) ) ;
|
|||
|
::InvertRect( &r );
|
|||
|
}
|
|||
|
|
|||
|
void HiliteRgn( const RgnHandle& r )
|
|||
|
{
|
|||
|
LMSetHiliteMode( LMGetHiliteMode() & ! ( 1 << hiliteBit ) ) ;
|
|||
|
::InvertRgn( r );
|
|||
|
}
|
|||
|
|
|||
|
LPane* FindPaneHitBy( const Point& globalMouse )
|
|||
|
{
|
|||
|
Int16 part;
|
|||
|
WindowPtr macWindowP;
|
|||
|
LPane* inPane = NULL;
|
|||
|
|
|||
|
part = ::FindWindow( globalMouse, &macWindowP );
|
|||
|
if ( macWindowP && part == inContent )
|
|||
|
{
|
|||
|
LWindow* whichWin;
|
|||
|
whichWin = LWindow::FetchWindowObject( macWindowP );
|
|||
|
if ( whichWin )
|
|||
|
{
|
|||
|
Point localMouse;
|
|||
|
LPane* nextPane;
|
|||
|
|
|||
|
localMouse = globalMouse;
|
|||
|
whichWin->GlobalToPortPoint( localMouse );
|
|||
|
inPane = whichWin->FindSubPaneHitBy( localMouse.h, localMouse.v );
|
|||
|
nextPane = inPane;
|
|||
|
while ( nextPane )
|
|||
|
{
|
|||
|
inPane = nextPane;
|
|||
|
nextPane = nextPane->FindSubPaneHitBy( localMouse.h, localMouse.v );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return inPane;
|
|||
|
}
|
|||
|
|
|||
|
// ---------------------------------------------------------------
|
|||
|
// Good 'ol Mac File Utilities
|
|||
|
// ---------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
/*----------------------------------------------------------------------
|
|||
|
Get a full pathname given a sig and type
|
|||
|
In: sig of process to look for ('MOSS' for nav but should use emSignature instead)
|
|||
|
type of process to look for (typically APPL)
|
|||
|
Out:Returns the file path as a nul-terminated allocated block
|
|||
|
that must be freed by the caller using XP_FREE.
|
|||
|
Returns NULL on error;
|
|||
|
|
|||
|
Q: Should the path contain / for the root? i.e. should it be
|
|||
|
file:///MacHD/...
|
|||
|
or file://MacHD/.. ** this form used now.
|
|||
|
------------------------------------------------------------------------*/
|
|||
|
char *PathURLFromProcessSignature (OSType sig, OSType type)
|
|||
|
{
|
|||
|
ProcessSerialNumber targetPSN; // return process number
|
|||
|
FSSpec targetFileSpec; // return file spec
|
|||
|
char *appPath = NULL;
|
|||
|
char *urlPath = NULL;
|
|||
|
char prefix[] = "file:/";
|
|||
|
OSErr err;
|
|||
|
|
|||
|
// Get the file spec of our app
|
|||
|
err = FindProcessBySignature(sig, type, targetPSN, &targetFileSpec);
|
|||
|
if (err != noErr) return NULL;
|
|||
|
|
|||
|
appPath = CFileMgr::EncodedPathNameFromFSSpec(targetFileSpec, true);
|
|||
|
if (appPath == NULL) return NULL;
|
|||
|
|
|||
|
urlPath = (char *)XP_ALLOC(strlen(appPath) + strlen(prefix) + 1);
|
|||
|
if (urlPath == NULL) {
|
|||
|
XP_FREE(appPath);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
XP_STRCPY(urlPath, prefix);
|
|||
|
XP_STRCPY(urlPath + strlen(prefix), appPath),
|
|||
|
|
|||
|
XP_FREE(appPath);
|
|||
|
|
|||
|
return urlPath;
|
|||
|
}
|
|||
|
|
|||
|
// Given a process signature, gets its serial number
|
|||
|
ProcessSerialNumber GetPSNBySig( OSType sig )
|
|||
|
{
|
|||
|
OSErr err;
|
|||
|
FSSpec fileSpec;
|
|||
|
ProcessInfoRec info;
|
|||
|
ProcessSerialNumber psn;
|
|||
|
|
|||
|
info.processAppSpec = &fileSpec;
|
|||
|
psn.highLongOfPSN = 0;
|
|||
|
psn.lowLongOfPSN = kNoProcess;
|
|||
|
while ( GetNextProcess( &psn ) == noErr)
|
|||
|
{
|
|||
|
info.processInfoLength = sizeof( ProcessInfoRec );
|
|||
|
info.processName = NULL;
|
|||
|
err= GetProcessInformation( &psn, &info );
|
|||
|
if ( info.processSignature == sig )
|
|||
|
return psn;
|
|||
|
}
|
|||
|
Throw_( paramErr );
|
|||
|
return psn;
|
|||
|
}
|
|||
|
|
|||
|
#define NO_PROCESS -1 // Constant used to indicate that there is no process in the PSN
|
|||
|
// Creates an NoProcess serial number
|
|||
|
ProcessSerialNumber MakeNoProcessPSN()
|
|||
|
{
|
|||
|
ProcessSerialNumber psn;
|
|||
|
psn.highLongOfPSN = NO_PROCESS;
|
|||
|
psn.lowLongOfPSN = NO_PROCESS;
|
|||
|
return psn;
|
|||
|
}
|
|||
|
|
|||
|
// Do we have a process
|
|||
|
Boolean HasProcess( const ProcessSerialNumber& psn )
|
|||
|
{
|
|||
|
return ( ( psn.highLongOfPSN != NO_PROCESS ) ||
|
|||
|
( psn.lowLongOfPSN!=NO_PROCESS ) );
|
|||
|
}
|
|||
|
|
|||
|
// Given an application signature, finds the process
|
|||
|
OSErr FindProcessBySignature(OSType sig,
|
|||
|
OSType processType,
|
|||
|
ProcessSerialNumber& psn,
|
|||
|
FSSpec* fileSpec)
|
|||
|
{
|
|||
|
OSErr err;
|
|||
|
|
|||
|
ProcessInfoRec info;
|
|||
|
|
|||
|
psn.highLongOfPSN = 0;
|
|||
|
psn.lowLongOfPSN = kNoProcess;
|
|||
|
do
|
|||
|
{
|
|||
|
err= GetNextProcess(&psn);
|
|||
|
if( err == noErr )
|
|||
|
{
|
|||
|
|
|||
|
info.processInfoLength = sizeof(ProcessInfoRec);
|
|||
|
info.processName = NULL;
|
|||
|
info.processAppSpec = fileSpec;
|
|||
|
|
|||
|
err= GetProcessInformation(&psn, &info);
|
|||
|
}
|
|||
|
} while( (err == noErr) &&
|
|||
|
((info.processSignature != sig) ||
|
|||
|
(info.processType != processType)));
|
|||
|
|
|||
|
if( err == noErr )
|
|||
|
psn = info.processNumber;
|
|||
|
|
|||
|
return err;
|
|||
|
} // FindProcessBySignature
|
|||
|
|
|||
|
|
|||
|
extern Boolean HasAppleEventObjects();
|
|||
|
|
|||
|
// On the 68K, the OSL glue checks to see whether it is
|
|||
|
// installed. If it's not, the functions do nothing. On the PPC,
|
|||
|
// if the Code Fragment Manager is unable to resolve an OSL
|
|||
|
// stub, it performs an ExitToShell. Therefore we must
|
|||
|
// insure that the OSL is available before calling any of
|
|||
|
// its functions. These are called throughout PowerPlant's
|
|||
|
// LModel* classes.
|
|||
|
|
|||
|
// gestaltObjectSupportLibraryInSystem = 1,
|
|||
|
// gestaltObjectSupportLibraryPowerPCSupport = 2
|
|||
|
// gestaltAppleEventsPresent
|
|||
|
// gestaltScriptingSupport
|
|||
|
// gestaltOSLInSystem <20><><EFBFBD> not gestaltObjectSupportLibraryPowerPCSupport
|
|||
|
Boolean HasAppleEventObjects()
|
|||
|
{
|
|||
|
static Boolean isKnown = false, isInstalled = false;
|
|||
|
|
|||
|
|
|||
|
if (!isKnown)
|
|||
|
{
|
|||
|
long attr = 0;
|
|||
|
Boolean ae = UEnvironment::HasGestaltAttribute(gestaltAppleEventsAttr, gestaltAppleEventsPresent);
|
|||
|
Boolean ppc = UEnvironment::HasGestaltAttribute(gestaltAppleEventsAttr, gestaltOSLInSystem);
|
|||
|
#ifdef powerc
|
|||
|
isInstalled = ae && ppc;
|
|||
|
#else
|
|||
|
isInstalled = 1; // we're linked with glue which always works
|
|||
|
#endif
|
|||
|
isKnown = true;
|
|||
|
}
|
|||
|
return isInstalled;
|
|||
|
}
|
|||
|
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
GetDropLocationDirectory
|
|||
|
|
|||
|
Given an 'alis' drop location AEDesc, return the volume reference
|
|||
|
number and directory ID of the directory.
|
|||
|
|
|||
|
Entry: dropLocation = pointer to 'alis' AEDesc record.
|
|||
|
|
|||
|
Exit: function result = error code.
|
|||
|
*volumeID = volume reference number.
|
|||
|
*directoryID = directory ID.
|
|||
|
|
|||
|
From Apple "HFS Drag Sample" sample code.
|
|||
|
----------------------------------------------------------------------------*/
|
|||
|
OSErr GetDropLocationDirectory (AEDesc *dropLocation, long *directoryID, short *volumeID)
|
|||
|
{
|
|||
|
OSErr result;
|
|||
|
AEDesc targetDescriptor; // 'fss ' descriptor for target directory
|
|||
|
FSSpec targetLocation; // FSSpec for target directory
|
|||
|
CInfoPBRec getTargetInfo; // paramBlock to get targetDirID
|
|||
|
|
|||
|
// Coerce the 'alis' descriptor to a 'fss ' descriptor
|
|||
|
result = AECoerceDesc(dropLocation, typeFSS, &targetDescriptor);
|
|||
|
if (result != noErr)
|
|||
|
return (result);
|
|||
|
|
|||
|
// Extract the FSSpec from targetDescriptor
|
|||
|
BlockMoveData((Ptr)(*targetDescriptor.dataHandle), (Ptr)&targetLocation, sizeof(FSSpec));
|
|||
|
|
|||
|
result = AEDisposeDesc(&targetDescriptor);
|
|||
|
if (result != noErr)
|
|||
|
return (result);
|
|||
|
|
|||
|
// Use PBGetCatInfo to get the directoryID of the target directory from the FSSpec
|
|||
|
|
|||
|
getTargetInfo.dirInfo.ioNamePtr = targetLocation.name;
|
|||
|
getTargetInfo.dirInfo.ioVRefNum = targetLocation.vRefNum;
|
|||
|
getTargetInfo.dirInfo.ioFDirIndex = 0;
|
|||
|
getTargetInfo.dirInfo.ioDrDirID = targetLocation.parID;
|
|||
|
|
|||
|
result = PBGetCatInfoSync(&getTargetInfo);
|
|||
|
if (result != noErr)
|
|||
|
return (result);
|
|||
|
|
|||
|
// return directory ID and volume reference number
|
|||
|
|
|||
|
*directoryID = getTargetInfo.dirInfo.ioDrDirID;
|
|||
|
*volumeID = targetLocation.vRefNum;
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
DragTargetWasTrash
|
|||
|
|
|||
|
Check to see if the target of a drag and drop was the Finder trashcan.
|
|||
|
|
|||
|
Entry: dragRef = drag reference.
|
|||
|
|
|||
|
Exit: function result = true if target was trash.
|
|||
|
----------------------------------------------------------------------------*/
|
|||
|
|
|||
|
Boolean DragTargetWasTrash (DragReference dragRef)
|
|||
|
{
|
|||
|
AEDesc dropLocation;
|
|||
|
OSErr err = noErr;
|
|||
|
long dropDirID, trashDirID;
|
|||
|
short dropVRefNum, trashVRefNum;
|
|||
|
|
|||
|
err = GetDropLocation(dragRef, &dropLocation);
|
|||
|
if (err != noErr) return false;
|
|||
|
|
|||
|
if (dropLocation.descriptorType == typeNull) goto exit;
|
|||
|
|
|||
|
err = GetDropLocationDirectory(&dropLocation, &dropDirID, &dropVRefNum);
|
|||
|
if (err != noErr) goto exit;
|
|||
|
|
|||
|
err = FindFolder(dropVRefNum, kTrashFolderType, false, &trashVRefNum,
|
|||
|
&trashDirID);
|
|||
|
if (err != noErr) goto exit;
|
|||
|
|
|||
|
if (dropVRefNum != trashVRefNum || dropDirID != trashDirID) goto exit;
|
|||
|
|
|||
|
AEDisposeDesc(&dropLocation);
|
|||
|
return true;
|
|||
|
|
|||
|
exit:
|
|||
|
|
|||
|
AEDisposeDesc(&dropLocation);
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
long LArrowControl::fLastTicks = 0;
|
|||
|
long LArrowControl::fDelay = 20;
|
|||
|
long LArrowControl::fHits = 0;
|
|||
|
|
|||
|
LArrowControl::LArrowControl( const SPaneInfo& inPaneInfo, MessageT valueMessage ):
|
|||
|
LControl( inPaneInfo, valueMessage, 0, 0, 0 )
|
|||
|
{
|
|||
|
mCurrPict = mArrowsPict;
|
|||
|
}
|
|||
|
|
|||
|
void LArrowControl::HiliteControl( Int16 inHotSpot, Boolean inCurrInside )
|
|||
|
{
|
|||
|
if ( inCurrInside )
|
|||
|
{
|
|||
|
if ( inHotSpot == mTopHalf )
|
|||
|
mCurrPict = mArrowsTopLit;
|
|||
|
else if ( inHotSpot == mBottomHalf )
|
|||
|
mCurrPict = mArrowsBotLit;
|
|||
|
}
|
|||
|
else
|
|||
|
mCurrPict = mArrowsPict;
|
|||
|
|
|||
|
DrawSelf();
|
|||
|
}
|
|||
|
|
|||
|
void LArrowControl::DrawSelf()
|
|||
|
{
|
|||
|
PicHandle macPictureH = GetPicture( mCurrPict );
|
|||
|
if ( macPictureH )
|
|||
|
{
|
|||
|
Rect pictureBounds;
|
|||
|
|
|||
|
CalcLocalFrameRect( pictureBounds );
|
|||
|
::DrawPicture( macPictureH, &pictureBounds );
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Boolean LArrowControl::PointInHotSpot( Point inPoint, Int16 inHotSpot )
|
|||
|
{
|
|||
|
Rect localFrame;
|
|||
|
Int16 midPoint;
|
|||
|
|
|||
|
CalcLocalFrameRect( localFrame );
|
|||
|
midPoint = ( localFrame.bottom - localFrame.top ) / 2;
|
|||
|
|
|||
|
if ( inHotSpot == mTopHalf )
|
|||
|
localFrame.bottom = midPoint;
|
|||
|
else
|
|||
|
localFrame.top = midPoint;
|
|||
|
|
|||
|
return PtInRect( inPoint, &localFrame );
|
|||
|
}
|
|||
|
|
|||
|
Int16 LArrowControl::FindHotSpot( Point inPoint )
|
|||
|
{
|
|||
|
Rect localFrame;
|
|||
|
Int16 midPoint;
|
|||
|
|
|||
|
CalcLocalFrameRect( localFrame );
|
|||
|
midPoint = ( localFrame.bottom - localFrame.top ) / 2;
|
|||
|
|
|||
|
if ( inPoint.v < midPoint )
|
|||
|
return mTopHalf;
|
|||
|
else
|
|||
|
return mBottomHalf;
|
|||
|
}
|
|||
|
|
|||
|
void LArrowControl::HotSpotAction( Int16 inHotSpot, Boolean inCurrInside, Boolean inPrevInside )
|
|||
|
{
|
|||
|
|
|||
|
if ( inCurrInside != inPrevInside )
|
|||
|
{
|
|||
|
FocusDraw();
|
|||
|
HiliteControl( inHotSpot, inCurrInside );
|
|||
|
}
|
|||
|
|
|||
|
if ( inCurrInside )
|
|||
|
{
|
|||
|
if ( ( ::TickCount() - fLastTicks ) < fDelay )
|
|||
|
return;
|
|||
|
|
|||
|
if ( fDelay == 0 )
|
|||
|
fDelay = 20;
|
|||
|
|
|||
|
fHits++;
|
|||
|
if ( fHits > 6 )
|
|||
|
fDelay = 5;
|
|||
|
|
|||
|
fLastTicks = TickCount();
|
|||
|
|
|||
|
BroadcastMessage( mValueMessage, &inHotSpot );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
fHits = 0;
|
|||
|
fDelay = 20;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void LArrowControl::HotSpotResult( Int16 /*inHotSpot*/ )
|
|||
|
{
|
|||
|
mCurrPict = mArrowsPict;
|
|||
|
|
|||
|
DrawSelf();
|
|||
|
|
|||
|
fHits = 0;
|
|||
|
fDelay = 0;
|
|||
|
}
|
|||
|
|
|||
|
/*=============================================================================
|
|||
|
File & Stream Classes Utilities
|
|||
|
=============================================================================*/
|
|||
|
|
|||
|
/*-----------------------------------------------------------------------------
|
|||
|
StOpenResFile opens the resource fork and closes it later
|
|||
|
-----------------------------------------------------------------------------*/
|
|||
|
|
|||
|
StOpenResFile::StOpenResFile (LFile *file, short perms)
|
|||
|
{
|
|||
|
fFile = file;
|
|||
|
file->OpenResourceFork (perms);
|
|||
|
}
|
|||
|
|
|||
|
StOpenResFile::~StOpenResFile ()
|
|||
|
{
|
|||
|
// LAM may not be required to UpdateResFile
|
|||
|
// CloseResFile is supposed to call UpdateResFile
|
|||
|
//::UpdateResFile (fFile->GetResourceForkRefNum());
|
|||
|
fFile->CloseResourceFork();
|
|||
|
}
|
|||
|
|
|||
|
/*-----------------------------------------------------------------------------
|
|||
|
StUseResFile uses an open resource fork and stops using it later.
|
|||
|
-----------------------------------------------------------------------------*/
|
|||
|
|
|||
|
StUseResFile::StUseResFile( short refnum )
|
|||
|
{
|
|||
|
fPrevResFile = CurResFile();
|
|||
|
|
|||
|
if (refnum != -1)
|
|||
|
UseResFile( refnum );
|
|||
|
}
|
|||
|
|
|||
|
StUseResFile::~StUseResFile()
|
|||
|
{
|
|||
|
UseResFile( fPrevResFile );
|
|||
|
}
|
|||
|
|
|||
|
//========================================================================================
|
|||
|
// CLASS CStringListRsrc
|
|||
|
//========================================================================================
|
|||
|
|
|||
|
typedef short** IntegerHandle;
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
// CStringListRsrc::GetString:
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
|
|||
|
void CStringListRsrc::GetString(short index, CStr255& theString) const
|
|||
|
{
|
|||
|
if (fStrListID != 0)
|
|||
|
GetIndString(theString, fStrListID, index);
|
|||
|
} // CStringListRsrc::GetString
|
|||
|
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
// CStringListRsrc::FindString:
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
|
|||
|
short CStringListRsrc::FindString(const CStr255& theString, Boolean addString)
|
|||
|
{
|
|||
|
CStr255 testString;
|
|||
|
short numStrings = this->CountStrings();
|
|||
|
|
|||
|
for (short i = 1; i <= numStrings; ++i)
|
|||
|
{
|
|||
|
this->GetString(i, testString);
|
|||
|
|
|||
|
if (testString == theString)
|
|||
|
return i; // found it! return the index
|
|||
|
}
|
|||
|
|
|||
|
// CString is not found, should we add it?
|
|||
|
if (addString == kAddString)
|
|||
|
return this->AppendString(theString); // added it! return the index
|
|||
|
|
|||
|
// CString not found...sigh!
|
|||
|
return 0;
|
|||
|
} // CStringListRsrc::FindString
|
|||
|
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
// CStringListRsrc::AppendString:
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
|
|||
|
short CStringListRsrc::AppendString(const CStr255& theString)
|
|||
|
{
|
|||
|
long result;
|
|||
|
short totalStringLength = theString.Length() + kLengthByte;
|
|||
|
Handle aHandle = Get1Resource('STR#', fStrListID);
|
|||
|
if (aHandle)
|
|||
|
{
|
|||
|
if (!*aHandle)
|
|||
|
::LoadResource(aHandle);
|
|||
|
|
|||
|
if (*aHandle)
|
|||
|
{
|
|||
|
SInt8 flags = ::HGetState(aHandle);
|
|||
|
::HNoPurge(aHandle);
|
|||
|
Size itsSize = GetHandleSize(aHandle);
|
|||
|
if (itsSize > 0)
|
|||
|
{
|
|||
|
short numStrings = this->CountStrings();
|
|||
|
SetHandleSize(aHandle, itsSize + totalStringLength);
|
|||
|
(**((IntegerHandle) aHandle)) = ++numStrings; // increment the count of strings in the STR# resource
|
|||
|
|
|||
|
// needs a failure handler
|
|||
|
result = Munger(aHandle, itsSize, NULL, totalStringLength, &theString, totalStringLength);
|
|||
|
if (result > 0)
|
|||
|
{
|
|||
|
// mark it as changed
|
|||
|
ChangedResource(aHandle);
|
|||
|
::HSetState(aHandle, flags);
|
|||
|
|
|||
|
return numStrings;
|
|||
|
}
|
|||
|
::HSetState(aHandle, flags);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// must create the resource...
|
|||
|
aHandle = NewHandle(sizeof(short) + totalStringLength);
|
|||
|
(**((IntegerHandle) aHandle)) = 1; // set the count of strings in the STR# resource
|
|||
|
result = Munger(aHandle, sizeof(short), NULL, totalStringLength, &theString, totalStringLength);
|
|||
|
if (result > 0)
|
|||
|
{
|
|||
|
AddResource(aHandle, 'STR#', fStrListID, fStrListRsrcName);
|
|||
|
ThrowIfResError_(); // if fails, it's most likely because the file is read-only
|
|||
|
|
|||
|
SetResAttrs(aHandle, resPurgeable);
|
|||
|
|
|||
|
// Need the following ChangedResource call because the SetResAttrs call on the previous
|
|||
|
// line cleared the "resChanged" attribute of the resource.
|
|||
|
ChangedResource(aHandle);
|
|||
|
|
|||
|
return 1;
|
|||
|
}
|
|||
|
}
|
|||
|
return 0;
|
|||
|
} // CStringListRsrc::AppendString
|
|||
|
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
// CStringListRsrc::ClearAll:
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
|
|||
|
void CStringListRsrc::ClearAll()
|
|||
|
{
|
|||
|
Handle aHandle = Get1Resource('STR#', fStrListID);
|
|||
|
if (aHandle)
|
|||
|
{
|
|||
|
if (!*aHandle)
|
|||
|
::LoadResource(aHandle);
|
|||
|
|
|||
|
if (*aHandle)
|
|||
|
{
|
|||
|
SInt8 flags = ::HGetState(aHandle);
|
|||
|
::HNoPurge(aHandle);
|
|||
|
SetHandleSize(aHandle, sizeof(short));
|
|||
|
(**((IntegerHandle) aHandle)) = 0; // set the count of strings in the STR# resource
|
|||
|
|
|||
|
// mark it as changed
|
|||
|
ChangedResource(aHandle);
|
|||
|
::HSetState(aHandle, flags);
|
|||
|
}
|
|||
|
}
|
|||
|
} // CStringListRsrc::ClearAll
|
|||
|
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
// CStringListRsrc::CountStrings:
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
|
|||
|
short CStringListRsrc::CountStrings() const
|
|||
|
{
|
|||
|
// return the leading integer in the STR# resource:
|
|||
|
//
|
|||
|
// type 'STR#' {
|
|||
|
// integer = $$Countof(StringArray);
|
|||
|
// array StringArray {
|
|||
|
// pstring;
|
|||
|
// };
|
|||
|
// };
|
|||
|
|
|||
|
Handle aHandle = Get1Resource('STR#', fStrListID);
|
|||
|
if (aHandle)
|
|||
|
{
|
|||
|
if (!*aHandle)
|
|||
|
::LoadResource(aHandle);
|
|||
|
|
|||
|
if (*aHandle)
|
|||
|
return **((IntegerHandle) aHandle);
|
|||
|
}
|
|||
|
return 0;
|
|||
|
} // CStringListRsrc::CountStrings
|
|||
|
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
// CStringListRsrc::GetListName:
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
|
|||
|
void CStringListRsrc::GetListName(CStr255& theString)
|
|||
|
{
|
|||
|
// Do we have the name in our field?
|
|||
|
if ( fStrListRsrcName.Length () > 0 )
|
|||
|
theString = fStrListRsrcName;
|
|||
|
else // We don't have the name so try and get it from the resource
|
|||
|
{
|
|||
|
short itsRsrcID;
|
|||
|
CStr255 itsName;
|
|||
|
ResType itsType;
|
|||
|
|
|||
|
// Get the resource's handle
|
|||
|
Handle aHandle = Get1Resource('STR#', fStrListID);
|
|||
|
if (aHandle)
|
|||
|
{
|
|||
|
// Extract the resource info from the handle
|
|||
|
GetResInfo ( aHandle, &itsRsrcID, &itsType, itsName );
|
|||
|
if ( itsName.Length () > 0 )
|
|||
|
{
|
|||
|
theString = itsName;
|
|||
|
|
|||
|
// Store the name in our field
|
|||
|
fStrListRsrcName = theString;
|
|||
|
}
|
|||
|
|
|||
|
ReleaseResource ( aHandle );
|
|||
|
}
|
|||
|
else // Sorry we don't have anything so return an empty CString
|
|||
|
theString = CStr255::sEmptyString;
|
|||
|
|
|||
|
}
|
|||
|
} // CStringListRsrc::GetListName
|
|||
|
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
// CStringListRsrc::RemoveAt:
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
|
|||
|
void CStringListRsrc::RemoveAt(short index)
|
|||
|
{
|
|||
|
if ((index > 0) && (index <= this->CountStrings()))
|
|||
|
{
|
|||
|
Handle aHandle = Get1Resource('STR#', fStrListID);
|
|||
|
if (aHandle)
|
|||
|
{
|
|||
|
if (!*aHandle)
|
|||
|
::LoadResource(aHandle);
|
|||
|
|
|||
|
if (*aHandle)
|
|||
|
{
|
|||
|
SInt8 flags = ::HGetState(aHandle);
|
|||
|
::HNoPurge(aHandle);
|
|||
|
|
|||
|
Size originalSize = GetHandleSize(aHandle);
|
|||
|
|
|||
|
// determine the accumulated size
|
|||
|
Size accumulatedSize = sizeof(short); // the accumulated size is the size of the count
|
|||
|
for (short i = 1; i < index; ++i)
|
|||
|
accumulatedSize += (*((CStringPtr) (*aHandle + accumulatedSize))).Length() + kLengthByte;
|
|||
|
|
|||
|
// determine the actual CString size
|
|||
|
Size stringSize = (*((CStringPtr) (*aHandle + accumulatedSize))).Length() + kLengthByte;
|
|||
|
|
|||
|
// move the the data in the handle
|
|||
|
BlockMoveData(*aHandle + accumulatedSize + stringSize, *aHandle + accumulatedSize,
|
|||
|
originalSize - accumulatedSize - stringSize);
|
|||
|
|
|||
|
// trim the handle down to its new size
|
|||
|
SetHandleSize(aHandle, originalSize - stringSize);
|
|||
|
|
|||
|
// decrement count of strings in STR# resource
|
|||
|
--(**((IntegerHandle) aHandle));
|
|||
|
|
|||
|
// mark it as changed
|
|||
|
ChangedResource(aHandle);
|
|||
|
|
|||
|
::HSetState(aHandle, flags);
|
|||
|
}
|
|||
|
#if qDebugMsg
|
|||
|
else
|
|||
|
fprintf(stderr, "CStringListRsrc::RemoveAt can't load STR# = %d.\n", fStrListID);
|
|||
|
#endif
|
|||
|
}
|
|||
|
#if qDebugMsg
|
|||
|
else
|
|||
|
fprintf(stderr, "CStringListRsrc::RemoveAt can't find STR# = %d.\n", fStrListID);
|
|||
|
#endif
|
|||
|
}
|
|||
|
#if qDebugMsg
|
|||
|
else
|
|||
|
fprintf(stderr, "CStringListRsrc::RemoveAt there's no CString at %d to remove!\n", index);
|
|||
|
#endif
|
|||
|
} // CStringListRsrc::RemoveAt
|
|||
|
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
// CStringListRsrc::ReplaceAt:
|
|||
|
//----------------------------------------------------------------------------------------
|
|||
|
|
|||
|
void CStringListRsrc::ReplaceAt(const CStr255& theString, short index)
|
|||
|
{
|
|||
|
if ((index > 0) && (index <= this->CountStrings()))
|
|||
|
{
|
|||
|
Handle aHandle = Get1Resource('STR#', fStrListID);
|
|||
|
if (aHandle)
|
|||
|
{
|
|||
|
if (!*aHandle)
|
|||
|
::LoadResource(aHandle);
|
|||
|
|
|||
|
if (*aHandle)
|
|||
|
{
|
|||
|
SInt8 flags = ::HGetState(aHandle);
|
|||
|
::HNoPurge(aHandle);
|
|||
|
|
|||
|
Size newStringSize = theString.Length() + kLengthByte; // the actual CString size
|
|||
|
Size originalSize = GetHandleSize(aHandle);
|
|||
|
|
|||
|
// determine the accumulated size of the valid portion of the resource
|
|||
|
Size accumulatedSize = sizeof(short); // the accumulated size is the size of the count
|
|||
|
for (short i = 1; i < index; ++i)
|
|||
|
accumulatedSize += (*((CStringPtr) (*aHandle + accumulatedSize))).Length() + kLengthByte;
|
|||
|
|
|||
|
// determine the actual CString size
|
|||
|
Size oldStringSize = (*((CStringPtr) (*aHandle + accumulatedSize))).Length() + kLengthByte;
|
|||
|
|
|||
|
// determine the new handle size
|
|||
|
Size newHandleSize = originalSize + (newStringSize - oldStringSize);
|
|||
|
|
|||
|
// determine whether to grow or shrink the handle?
|
|||
|
if (newStringSize > oldStringSize)
|
|||
|
{
|
|||
|
// grow the handle
|
|||
|
SetHandleSize(aHandle, newHandleSize);
|
|||
|
|
|||
|
// move the bytes
|
|||
|
BlockMoveData(*aHandle + accumulatedSize + oldStringSize, *aHandle + accumulatedSize + newStringSize,
|
|||
|
originalSize - accumulatedSize - oldStringSize);
|
|||
|
}
|
|||
|
else if (oldStringSize > newStringSize)
|
|||
|
{
|
|||
|
// move the bytes
|
|||
|
BlockMoveData(*aHandle + accumulatedSize + oldStringSize, *aHandle + accumulatedSize + newStringSize,
|
|||
|
originalSize - accumulatedSize - oldStringSize);
|
|||
|
|
|||
|
// shrink the handle
|
|||
|
SetHandleSize(aHandle, newHandleSize);
|
|||
|
}
|
|||
|
|
|||
|
// assign the CString
|
|||
|
*((CStr255*) (*aHandle + accumulatedSize)) = theString;
|
|||
|
|
|||
|
// mark it as changed
|
|||
|
ChangedResource(aHandle);
|
|||
|
|
|||
|
::HSetState(aHandle, flags);
|
|||
|
}
|
|||
|
#if qDebugMsg
|
|||
|
else
|
|||
|
fprintf(stderr, "CStringListRsrc::ReplaceAt can't load STR# = %d.\n", fStrListID);
|
|||
|
#endif
|
|||
|
}
|
|||
|
#if qDebugMsg
|
|||
|
else
|
|||
|
fprintf(stderr, "CStringListRsrc::ReplaceAt can't find STR# = %d.\n", fStrListID);
|
|||
|
#endif
|
|||
|
}
|
|||
|
#if qDebugMsg
|
|||
|
else
|
|||
|
fprintf(stderr, "CStringListRsrc::ReplaceAt there's no CString at %d to replace!\n", index);
|
|||
|
#endif
|
|||
|
} // CStringListRsrc::ReplaceAt
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
StWatchCursor::StWatchCursor() { ::SetCursor( (CursPtr)*(::GetCursor(watchCursor)) ); }
|
|||
|
StWatchCursor::~StWatchCursor() { ::SetCursor( &(UQDGlobals::GetQDGlobals()->arrow) ); }
|
|||
|
|
|||
|
//-----------------------------------
|
|||
|
void StringParamText(
|
|||
|
CStr255& ioFormatString,
|
|||
|
SInt32 inReplaceNumber0,
|
|||
|
SInt32 inReplaceNumber1,
|
|||
|
SInt32 inReplaceNumber2,
|
|||
|
SInt32 inReplaceNumber3)
|
|||
|
// Replace the characters "^0" ..."^3"within ioString with numerals.
|
|||
|
// If "^0" or "^1" is not found in ioString, the method does nothing.
|
|||
|
//-----------------------------------
|
|||
|
{
|
|||
|
char t0[15], t1[15], t2[15], t3[15];
|
|||
|
sprintf(t0, "%ld", inReplaceNumber0);
|
|||
|
sprintf(t1, "%ld", inReplaceNumber1);
|
|||
|
sprintf(t2, "%ld", inReplaceNumber2);
|
|||
|
sprintf(t3, "%ld", inReplaceNumber3);
|
|||
|
::StringParamText(ioFormatString, t0, t1, t2, t3);
|
|||
|
}
|
|||
|
|
|||
|
//-----------------------------------
|
|||
|
void StringParamText(
|
|||
|
CStr255& ioFormatString,
|
|||
|
const char* inReplaceText0,
|
|||
|
const char* inReplaceText1,
|
|||
|
const char* inReplaceText2,
|
|||
|
const char* inReplaceText3)
|
|||
|
// Replace the substrings "^0" ..."^3" within ioString with inReplaceText0 ... inReplaceText3.
|
|||
|
// (substring is just removed if inReplaceTextn is null).
|
|||
|
// If any of the substrings "^0"..."^3" is not found in ioString, nothing happens there.
|
|||
|
//-----------------------------------
|
|||
|
{
|
|||
|
LStr255 resultString = (ConstStringPtr)&ioFormatString;
|
|||
|
char target[] = "^0";
|
|||
|
const char* replaceString[] = {
|
|||
|
inReplaceText0,
|
|||
|
inReplaceText1,
|
|||
|
inReplaceText2,
|
|||
|
inReplaceText3 };
|
|||
|
for (int i = 0; i < 4; i++)
|
|||
|
{
|
|||
|
UInt8 position = resultString.Find(target, 1);
|
|||
|
if ( position )
|
|||
|
{
|
|||
|
const char* rs = replaceString[i];
|
|||
|
if ( rs )
|
|||
|
resultString.Replace(position, 2, rs, strlen(rs));
|
|||
|
else
|
|||
|
resultString.Remove(position, 2);
|
|||
|
}
|
|||
|
target[1]++; // morph it into "^1" etc. ASCII standard supports this.
|
|||
|
}
|
|||
|
ioFormatString = (ConstStringPtr)resultString;
|
|||
|
}
|
|||
|
|
|||
|
// This code is taken from June 97 Dev.CD
|
|||
|
enum
|
|||
|
{
|
|||
|
kPromisedFlavor = 'fssP',
|
|||
|
kPromisedFlavorFindFile = 'rWm1'
|
|||
|
};
|
|||
|
|
|||
|
static Size MinimumBytesForFSSpec (const FSSpec *fss)
|
|||
|
{
|
|||
|
//
|
|||
|
// Some senders don't bother sending the unused bytes of the
|
|||
|
// file name. This function helps make sure the FSSpec is
|
|||
|
// minimally sane by computing the minimum number of bytes it
|
|||
|
// would take to store it.
|
|||
|
//
|
|||
|
// THIS FUNCTION CANNOT MOVE MEMORY.
|
|||
|
//
|
|||
|
|
|||
|
return sizeof (*fss) - sizeof (fss->name) + *(fss->name) + 1;
|
|||
|
}
|
|||
|
|
|||
|
OSErr GetHFSFlavorFromPromise
|
|||
|
(DragReference dragRef, ItemReference itemRef,
|
|||
|
HFSFlavor *hfs, Boolean isSupposedlyFromFindFile)
|
|||
|
{
|
|||
|
OSErr err = noErr;
|
|||
|
PromiseHFSFlavor phfs;
|
|||
|
Size size = sizeof (phfs);
|
|||
|
|
|||
|
err = GetFlavorData
|
|||
|
(dragRef,itemRef,flavorTypePromiseHFS,&phfs,&size,0);
|
|||
|
|
|||
|
if (!err)
|
|||
|
{
|
|||
|
if (size != sizeof (phfs))
|
|||
|
err = cantGetFlavorErr;
|
|||
|
else
|
|||
|
{
|
|||
|
Boolean isFromFindFile =
|
|||
|
phfs.promisedFlavor == kPromisedFlavorFindFile;
|
|||
|
|
|||
|
if (isSupposedlyFromFindFile != isFromFindFile)
|
|||
|
err = paramErr;
|
|||
|
else
|
|||
|
{
|
|||
|
size = sizeof (hfs->fileSpec);
|
|||
|
err = GetFlavorData
|
|||
|
(dragRef,itemRef,phfs.promisedFlavor,
|
|||
|
&(hfs->fileSpec),&size,0);
|
|||
|
|
|||
|
if (!err)
|
|||
|
{
|
|||
|
Size minSize = MinimumBytesForFSSpec
|
|||
|
(&(hfs->fileSpec));
|
|||
|
|
|||
|
if (size < minSize)
|
|||
|
err = cantGetFlavorErr;
|
|||
|
else
|
|||
|
{
|
|||
|
hfs->fileType = phfs.fileType;
|
|||
|
hfs->fileCreator = phfs.fileCreator;
|
|||
|
hfs->fdFlags = phfs.fdFlags;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return err;
|
|||
|
}
|
|||
|
// End of cut and paste
|
|||
|
|
|||
|
void GetDesktopIconSuiteFor( OSType inFileCreator, OSType inFileType, short inSize, Handle** ioHandle )
|
|||
|
{
|
|||
|
Assert_( inSize == kLargeIcon || inSize == kSmallIcon );
|
|||
|
|
|||
|
Handle* h = *ioHandle;
|
|||
|
|
|||
|
if (inFileCreator && inFileType )
|
|||
|
{
|
|||
|
Handle handle;
|
|||
|
OSErr err = ::NewIconSuite(h);
|
|||
|
short i = 0;
|
|||
|
if (!err && *h)
|
|||
|
{
|
|||
|
for ( i = 0; i< 3; i++ )
|
|||
|
{
|
|||
|
err = ::DTGetIcon(nil, 0, inSize , inFileCreator, inFileType, &handle);
|
|||
|
|
|||
|
if (!err)
|
|||
|
err = ::AddIconToSuite(handle, *h, ::DTIconToResIcon( inSize ) );
|
|||
|
inSize++;
|
|||
|
if( err )
|
|||
|
break;
|
|||
|
}
|
|||
|
if( !err && i == 0 ) // Didn't find at least the B&W icon
|
|||
|
{
|
|||
|
::DisposeIconSuite(*h, true);
|
|||
|
*h = nil;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (!*h)
|
|||
|
{
|
|||
|
::GetIconSuite(h, 133,
|
|||
|
inSize == kLargeIcon ? kSelectorAllLargeData : kSelectorAllSmallData );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
StSpinningBeachBallCursor::StSpinningBeachBallCursor ()
|
|||
|
{
|
|||
|
startAsyncCursors();
|
|||
|
}
|
|||
|
|
|||
|
StSpinningBeachBallCursor::~StSpinningBeachBallCursor()
|
|||
|
{
|
|||
|
stopAsyncCursors();
|
|||
|
}
|