Demonstration Program MonoTextEdit
// *******************************************************************************************
// MonoTextEdit.c CARBON EVENT MODEL
// *******************************************************************************************
//
// This program demonstrates:
//
// o A "bare-bones" monostyled text editor.
//
// o A Help dialog which features the integrated scrolling of multistyled text and pictures.
//
// In the monostyled text editor demonstration, a panel is displayed at the bottom of all
// opened windows. This panel displays the edit record length, number of lines, line height,
// destination rectangle (top), scroll bar/scroller value, and scroll bar/scroller maximum
// value.
//
// The bulk of the source code for the Help dialog is contained in the file HelpDialog.c.
// The dialog itself displays information intended to assist the user in adapting the Help
// dialog source code and resources to the requirements of his/her own application.
//
// The program utilises the following resources:
//
// o A 'plst' resource.
//
// o An 'MBAR' resource, and 'MENU' resources for Apple, File, Edit, and Help dialog pop-up
// menus (preload, non-purgeable).
//
// o A 'CNTL' resources (purgeable) for the vertical scroll bar in the text editor window.
//
// o 'TEXT' and associated 'styl' resources (all purgeable) for the Help dialog.
//
// o 'PICT' resources (purgeable) for the Help dialog.
//
// o A 'STR#' resource (purgeable) containing error text strings.
//
// o A 'SIZE' resource with the acceptSuspendResumeEvents, canBackground,
// doesActivateOnFGSwitch, and isHighLevelEventAware flags set.
//
// *******************************************************************************************
// .................................................................................. includes
#include <Carbon.h>
// ................................................................................... defines
#define rMenubar 128
#define mAppleApplication 128
#define iAbout 1
#define iHelp 2
#define mFile 129
#define iNew 1
#define iOpen 2
#define iClose 4
#define iSaveAs 6
#define iQuit 12
#define mEdit 130
#define iUndo 1
#define iCut 3
#define iCopy 4
#define iPaste 5
#define iClear 6
#define iSelectAll 7
#define rVScrollbar 128
#define rErrorStrings 128
#define eMenuBar 1
#define eWindow 2
#define eDocStructure 3
#define eEditRecord 4
#define eExceedChara 5
#define eNoSpaceCut 6
#define eNoSpacePaste 7
#define kMaxTELength 32767
#define kTab 0x09
#define kBackSpace 0x08
#define kForwardDelete 0x7F
#define kReturn 0x0D
#define kEscape 0x1B
#define topLeft(r) (((Point *) &(r))[0])
#define botRight(r) (((Point *) &(r))[1])
// .................................................................................. typedefs
typedef struct
{
TEHandle textEditStrucHdl;
ControlRef vScrollbarRef;
} docStructure, **docStructureHandle;
// .......................................................................... global variables
Boolean gRunningOnX = false;
MenuID gHelpMenu;
ControlActionUPP gScrollActionFunctionUPP;
TEClickLoopUPP gCustomClickLoopUPP;
SInt16 gNumberOfWindows = 0;
SInt16 gOldControlValue;
// ....................................................................... function prototypes
void main (void);
void doPreliminaries (void);
OSStatus appEventHandler (EventHandlerCallRef,EventRef,void *);
OSStatus windowEventHandler (EventHandlerCallRef,EventRef,void *);
void doIdle (void);
void doKeyEvent (SInt8);
void scrollActionFunction (ControlRef,SInt16);
void doInContent (Point,Boolean);
void doDrawContent (WindowPtr);
void doActivateDeactivate (WindowRef,Boolean);
WindowRef doNewDocWindow (void);
EventHandlerUPP doGetHandlerUPP (void);
Boolean customClickLoop (void);
void doSetScrollBarValue (ControlRef,SInt16 *);
void doAdjustMenus (void);
void doMenuChoice (MenuID,MenuItemIndex);
void doFileMenu (MenuItemIndex);
void doEditMenu (MenuItemIndex);
SInt16 doGetSelectLength (TEHandle);
void doAdjustScrollbar (WindowRef);
void doAdjustCursor (WindowRef);
void doCloseWindow (WindowRef);
void doSaveAsFile (TEHandle);
void doOpenCommand (void);
void doOpenFile (FSSpec);
void doDrawDataPanel (WindowRef);
void doErrorAlert (SInt16);
void navEventFunction (NavEventCallbackMessage,NavCBRecPtr,
NavCallBackUserData);
extern void doHelp (void);
// ************************************************************************************** main
void main(void)
{
MenuBarHandle menubarHdl;
SInt32 response;
MenuRef menuRef;
EventTypeSpec applicationEvents[] = { { kEventClassApplication, kEventAppActivated },
{ kEventClassCommand, kEventProcessCommand },
{ kEventClassMenu, kEventMenuEnableItems },
{ kEventClassMouse, kEventMouseMoved } };
// ........................................................................ do preliminaries
doPreliminaries();
// ............................................................... set up menu bar and menus
menubarHdl = GetNewMBar(rMenubar);
if(menubarHdl == NULL)
doErrorAlert(eMenuBar);
SetMenuBar(menubarHdl);
DrawMenuBar();
Gestalt(gestaltMenuMgrAttr,&response);
if(response & gestaltMenuMgrAquaLayoutMask)
{
menuRef = GetMenuRef(mFile);
if(menuRef != NULL)
{
DeleteMenuItem(menuRef,iQuit);
DeleteMenuItem(menuRef,iQuit - 1);
}
menuRef = GetMenuRef(mAppleApplication);
DeleteMenuItem(menuRef,iHelp);
HMGetHelpMenu(&menuRef,NULL);
InsertMenuItem(menuRef,"\pMonoTextEdit Help",0);
gHelpMenu = GetMenuID(menuRef);
gRunningOnX = true;
}
else
{
menuRef = GetMenuRef(mFile);
if(menuRef != NULL)
SetMenuItemCommandID(menuRef,iQuit,kHICommandQuit);
}
// ..................................................... create universal procedure pointers
gScrollActionFunctionUPP = NewControlActionUPP((ControlActionProcPtr) scrollActionFunction);
gCustomClickLoopUPP = NewTEClickLoopUPP((TEClickLoopProcPtr) customClickLoop);
// ....................................................... install application event handler
InstallApplicationEventHandler(NewEventHandlerUPP((EventHandlerProcPtr) appEventHandler),
GetEventTypeCount(applicationEvents),applicationEvents,
0,NULL);
// ......................................................................... install a timer
InstallEventLoopTimer(GetCurrentEventLoop(),0,TicksToEventTime(GetCaretTime()),
NewEventLoopTimerUPP((EventLoopTimerProcPtr) doIdle),NULL,
NULL);
// ................................................................. open an untitled window
doNewDocWindow();
// .............................................................. run application event loop
RunApplicationEventLoop();
}
// *************************************************************************** doPreliminaries
void doPreliminaries(void)
{
MoreMasterPointers(192);
InitCursor();
}
// *************************************************************************** appEventHandler
OSStatus appEventHandler(EventHandlerCallRef eventHandlerCallRef,EventRef eventRef,
void * userData)
{
OSStatus result = eventNotHandledErr;
UInt32 eventClass;
UInt32 eventKind;
HICommand hiCommand;
MenuID menuID;
MenuItemIndex menuItem;
eventClass = GetEventClass(eventRef);
eventKind = GetEventKind(eventRef);
switch(eventClass)
{
case kEventClassApplication:
if(eventKind == kEventAppActivated)
SetThemeCursor(kThemeArrowCursor);
break;
case kEventClassCommand:
if(eventKind == kEventProcessCommand)
{
GetEventParameter(eventRef,kEventParamDirectObject,typeHICommand,NULL,
sizeof(HICommand),NULL,&hiCommand);
menuID = GetMenuID(hiCommand.menu.menuRef);
menuItem = hiCommand.menu.menuItemIndex;
if((hiCommand.commandID != kHICommandQuit) &&
((menuID >= mAppleApplication && menuID <= mEdit)) || menuID == gHelpMenu)
{
doMenuChoice(menuID,menuItem);
result = noErr;
}
}
break;
case kEventClassMenu:
if(eventKind == kEventMenuEnableItems)
{
GetWindowClass(FrontWindow(),&windowClass);
if(windowClass == kDocumentWindowClass)
doAdjustMenus();
result = noErr;
}
break;
case kEventClassMouse:
if(eventKind == kEventMouseMoved)
{
GetWindowClass(FrontWindow(),&windowClass);
if(windowClass == kDocumentWindowClass)
doAdjustCursor(FrontWindow());
result = noErr;
}
break;
return result;
}
// ************************************************************************ windowEventHandler
OSStatus windowEventHandler(EventHandlerCallRef eventHandlerCallRef,EventRef eventRef,
void* userData)
{
OSStatus result = eventNotHandledErr;
UInt32 eventClass;
UInt32 eventKind;
WindowRef windowRef;
UInt32 modifiers;
Point mouseLocation;
Boolean shiftKeyDown = false;
ControlRef controlRef;
ControlPartCode controlPartCode;
SInt8 charCode;
eventClass = GetEventClass(eventRef);
eventKind = GetEventKind(eventRef);
switch(eventClass)
{
case kEventClassWindow: // event class window
GetEventParameter(eventRef,kEventParamDirectObject,typeWindowRef,NULL,sizeof(windowRef),
NULL,&windowRef);
switch(eventKind)
{
case kEventWindowDrawContent:
doDrawContent(windowRef);
result = noErr;
break;
case kEventWindowActivated:
doActivateDeactivate(windowRef,true);
result = noErr;
break;
case kEventWindowDeactivated:
doActivateDeactivate(windowRef,false);
result = noErr;
break;
case kEventWindowClickContentRgn:
GetEventParameter(eventRef,kEventParamMouseLocation,typeQDPoint,NULL,
sizeof(mouseLocation),NULL,&mouseLocation);
SetPortWindowPort(FrontWindow());
GlobalToLocal(&mouseLocation);
GetEventParameter(eventRef,kEventParamKeyModifiers,typeUInt32,NULL,
sizeof(modifiers),NULL,&modifiers);
if(modifiers & shiftKey)
shiftKeyDown = true;
doInContent(mouseLocation,shiftKeyDown);
result = noErr;
break;
case kEventWindowClose:
doCloseWindow(windowRef);
result = noErr;
break;
}
break;
case kEventClassMouse: // event class mouse
switch(eventKind)
{
case kEventMouseDown:
GetEventParameter(eventRef,kEventParamMouseLocation,typeQDPoint,NULL,
sizeof(mouseLocation),NULL,&mouseLocation);
SetPortWindowPort(FrontWindow());
GlobalToLocal(&mouseLocation);
controlRef = FindControlUnderMouse(mouseLocation,FrontWindow(),&controlPartCode);
if(controlRef)
{
gOldControlValue = GetControlValue(controlRef);
TrackControl(controlRef,mouseLocation,gScrollActionFunctionUPP);
result = noErr;
}
break;
}
break;
case kEventClassKeyboard: // event class keyboard
switch(eventKind)
{
case kEventRawKeyDown:
case kEventRawKeyRepeat:
GetEventParameter(eventRef,kEventParamKeyMacCharCodes,typeChar,NULL,
sizeof(charCode),NULL,&charCode);
GetEventParameter(eventRef,kEventParamKeyModifiers,typeUInt32,NULL,
sizeof(modifiers),NULL,&modifiers);
if((modifiers & cmdKey) == 0)
doKeyEvent(charCode);
result = noErr;
break;
}
break;
}
return result;
}
// ************************************************************************************ doIdle
void doIdle(void)
{
WindowRef windowRef;
docStructureHandle docStrucHdl;
windowRef = FrontWindow();
if(GetWindowKind(windowRef) == kApplicationWindowKind)
{
docStrucHdl = (docStructureHandle) (GetWRefCon(windowRef));
if(docStrucHdl != NULL)
TEIdle((*docStrucHdl)->textEditStrucHdl);
}
}
// ******************************************************************************** doKeyEvent
void doKeyEvent(SInt8 charCode)
{
WindowRef windowRef;
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
SInt16 selectionLength;
if(charCode <= kEscape && charCode != kBackSpace && charCode != kReturn)
return;
windowRef = FrontWindow();
docStrucHdl = (docStructureHandle) (GetWRefCon(windowRef));
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
if(charCode == kTab)
{
// Do tab key handling here if required.
}
else if(charCode == kForwardDelete)
{
selectionLength = doGetSelectLength(textEditStrucHdl);
if(selectionLength == 0)
(*textEditStrucHdl)->selEnd += 1;
TEDelete(textEditStrucHdl);
doAdjustScrollbar(windowRef);
}
else
{
selectionLength = doGetSelectLength(textEditStrucHdl);
if(((*textEditStrucHdl)->teLength - selectionLength + 1) < kMaxTELength)
{
TEKey(charCode,textEditStrucHdl);
doAdjustScrollbar(windowRef);
}
else
doErrorAlert(eExceedChara);
}
doDrawDataPanel(windowRef);
}
// ********************************************************************** scrollActionFunction
void scrollActionFunction(ControlRef controlRef,SInt16 partCode)
{
WindowRef windowRef;
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
SInt16 linesToScroll;
SInt16 controlValue, controlMax;
windowRef = GetControlOwner(controlRef);
docStrucHdl = (docStructureHandle) (GetWRefCon(windowRef));;
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
controlValue = GetControlValue(controlRef);
controlMax = GetControlMaximum(controlRef);
if(partCode)
{
if(partCode != kControlIndicatorPart)
{
switch(partCode)
{
case kControlUpButtonPart:
case kControlDownButtonPart:
linesToScroll = 1;
break;
case kControlPageUpPart:
case kControlPageDownPart:
linesToScroll = (((*textEditStrucHdl)->viewRect.bottom -
(*textEditStrucHdl)->viewRect.top) /
(*textEditStrucHdl)->lineHeight) - 1;
break;
}
if((partCode == kControlDownButtonPart) || (partCode == kControlPageDownPart))
linesToScroll = -linesToScroll;
linesToScroll = controlValue - linesToScroll;
if(linesToScroll < 0)
linesToScroll = 0;
else if(linesToScroll > controlMax)
linesToScroll = controlMax;
SetControlValue(controlRef,linesToScroll);
linesToScroll = controlValue - linesToScroll;
}
else
{
linesToScroll = gOldControlValue - controlValue;
gOldControlValue = controlValue;
}
if(linesToScroll != 0)
{
TEScroll(0,linesToScroll * (*textEditStrucHdl)->lineHeight,textEditStrucHdl);
doDrawDataPanel(windowRef);
}
}
}
// ******************************************************************************* doInContent
void doInContent(Point mouseLocation,Boolean shiftKeyDown)
{
WindowRef windowRef;
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
windowRef = FrontWindow();
docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
if(PtInRect(mouseLocation,&(*textEditStrucHdl)->viewRect))
TEClick(mouseLocation,shiftKeyDown,textEditStrucHdl);
}
// ***************************************************************************** doDrawContent
void doDrawContent(WindowRef windowRef)
{
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
GrafPtr oldPort;
RgnHandle visibleRegionHdl = NewRgn();
Rect portRect;
docStrucHdl = (docStructureHandle) (GetWRefCon(windowRef));
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
GetPort(&oldPort);
SetPortWindowPort(windowRef);
GetPortVisibleRegion(GetWindowPort(windowRef),visibleRegionHdl);
EraseRgn(visibleRegionHdl);
UpdateControls(windowRef,visibleRegionHdl);
GetWindowPortBounds(windowRef,&portRect);
TEUpdate(&portRect,textEditStrucHdl);
doDrawDataPanel(windowRef);
DisposeRgn(visibleRegionHdl);
SetPort(oldPort);
}
// *********************************************************************** doActivateDocWindow
void doActivateDeactivate(WindowRef windowRef,Boolean becomingActive)
{
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
docStrucHdl = (docStructureHandle) (GetWRefCon(windowRef));
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
if(becomingActive)
{
SetPortWindowPort(windowRef);
(*textEditStrucHdl)->viewRect.bottom = ((((*textEditStrucHdl)->viewRect.bottom -
(*textEditStrucHdl)->viewRect.top) /
(*textEditStrucHdl)->lineHeight) *
(*textEditStrucHdl)->lineHeight) +
(*textEditStrucHdl)->viewRect.top;
(*textEditStrucHdl)->destRect.bottom = (*textEditStrucHdl)->viewRect.bottom;
TEActivate(textEditStrucHdl);
ActivateControl((*docStrucHdl)->vScrollbarRef);
doAdjustScrollbar(windowRef);
doAdjustCursor(windowRef);
}
else
{
TEDeactivate(textEditStrucHdl);
DeactivateControl((*docStrucHdl)->vScrollbarRef);
}
}
// **************************************************************************** doNewDocWindow
WindowRef doNewDocWindow(void)
{
WindowRef windowRef;
OSStatus osError;
Rect contentRect = { 100,100,400,595 };
WindowAttributes attributes = kWindowStandardHandlerAttribute |
kWindowStandardDocumentAttributes;
docStructureHandle docStrucHdl;
Rect portRect, destAndViewRect;
EventTypeSpec windowEvents[] = { { kEventClassWindow, kEventWindowDrawContent },
{ kEventClassWindow, kEventWindowActivated },
{ kEventClassWindow, kEventWindowDeactivated },
{ kEventClassWindow, kEventWindowClickContentRgn },
{ kEventClassWindow, kEventWindowClose },
{ kEventClassMouse, kEventMouseDown },
{ kEventClassKeyboard, kEventRawKeyDown },
{ kEventClassKeyboard, kEventRawKeyRepeat } };
osError = CreateNewWindow(kDocumentWindowClass,attributes,&contentRect,&windowRef);
if(osError != noErr)
{
doErrorAlert(eWindow);
return NULL;
}
ChangeWindowAttributes(windowRef,0,kWindowResizableAttribute);
RepositionWindow(windowRef,NULL,kWindowCascadeOnMainScreen);
SetWTitle(windowRef,"\puntitled");
SetPortWindowPort(windowRef);
TextSize(10);
InstallWindowEventHandler(windowRef,doGetHandlerUPP(),GetEventTypeCount(windowEvents),
windowEvents,0,NULL);
if(!(docStrucHdl = (docStructureHandle) NewHandle(sizeof(docStructure))))
{
doErrorAlert(eDocStructure);
return NULL;
}
SetWRefCon(windowRef,(SInt32) docStrucHdl);
gNumberOfWindows ++;
(*docStrucHdl)->vScrollbarRef = GetNewControl(rVScrollbar,windowRef);
GetWindowPortBounds(windowRef,&portRect);
destAndViewRect = portRect;
destAndViewRect.right -= 15;
destAndViewRect.bottom -= 15;
InsetRect(&destAndViewRect,2,2);
MoveHHi((Handle) docStrucHdl);
HLock((Handle) docStrucHdl);
if(!((*docStrucHdl)->textEditStrucHdl = TENew(&destAndViewRect,&destAndViewRect)))
{
DisposeWindow(windowRef);
gNumberOfWindows --;
DisposeHandle((Handle) docStrucHdl);
doErrorAlert(eEditRecord);
return NULL;
}
HUnlock((Handle) docStrucHdl);
TESetClickLoop(gCustomClickLoopUPP,(*docStrucHdl)->textEditStrucHdl);
TEAutoView(true,(*docStrucHdl)->textEditStrucHdl);
TEFeatureFlag(teFOutlineHilite,1,(*docStrucHdl)->textEditStrucHdl);
ShowWindow(windowRef);
return windowRef;
}
// *************************************************************************** doGetHandlerUPP
EventHandlerUPP doGetHandlerUPP(void)
{
static EventHandlerUPP windowEventHandlerUPP;
if(windowEventHandlerUPP == NULL)
windowEventHandlerUPP = NewEventHandlerUPP((EventHandlerProcPtr) windowEventHandler);
return windowEventHandlerUPP;
}
// *************************************************************************** customClickLoop
Boolean customClickLoop(void)
{
WindowRef windowRef;
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
GrafPtr oldPort;
RgnHandle oldClip;
Rect tempRect, portRect;
Point mouseXY;
SInt16 linesToScroll = 0;
windowRef = FrontWindow();
docStrucHdl = (docStructureHandle) (GetWRefCon(windowRef));
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
GetPort(&oldPort);
SetPortWindowPort(windowRef);
oldClip = NewRgn();
GetClip(oldClip);
SetRect(&tempRect,-32767,-32767,32767,32767);
ClipRect(&tempRect);
GetMouse(&mouseXY);
GetWindowPortBounds(windowRef,&portRect);
if(mouseXY.v < portRect.top)
{
linesToScroll = 1;
doSetScrollBarValue((*docStrucHdl)->vScrollbarRef,&linesToScroll);
if(linesToScroll != 0)
TEScroll(0,linesToScroll * ((*textEditStrucHdl)->lineHeight),textEditStrucHdl);
}
else if(mouseXY.v > portRect.bottom)
{
linesToScroll = -1;
doSetScrollBarValue((*docStrucHdl)->vScrollbarRef,&linesToScroll);
if(linesToScroll != 0)
TEScroll(0,linesToScroll * ((*textEditStrucHdl)->lineHeight),textEditStrucHdl);
}
if(linesToScroll != 0)
doDrawDataPanel(windowRef);
SetClip(oldClip);
DisposeRgn(oldClip);
SetPort(oldPort);
return true;
}
// *********************************************************************** doSetScrollBarValue
void doSetScrollBarValue(ControlRef controlRef,SInt16 *linesToScroll)
{
SInt16 controlValue, controlMax;
controlValue = GetControlValue(controlRef);
controlMax = GetControlMaximum(controlRef);
*linesToScroll = controlValue - *linesToScroll;
if(*linesToScroll < 0)
*linesToScroll = 0;
else if(*linesToScroll > controlMax)
*linesToScroll = controlMax;
SetControlValue(controlRef,*linesToScroll);
*linesToScroll = controlValue - *linesToScroll;
}
// ***************************************************************************** doAdjustMenus
void doAdjustMenus(void)
{
MenuRef fileMenuHdl, editMenuHdl;
WindowRef windowRef;
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
ScrapRef scrapRef;
OSStatus osError;
ScrapFlavorFlags scrapFlavorFlags;
fileMenuHdl = GetMenuRef(mFile);
editMenuHdl = GetMenuRef(mEdit);
if(gNumberOfWindows > 0)
{
windowRef = FrontWindow();
docStrucHdl = (docStructureHandle) (GetWRefCon(windowRef));
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
EnableMenuItem(fileMenuHdl,iClose);
if((*textEditStrucHdl)->selStart < (*textEditStrucHdl)->selEnd)
{
EnableMenuItem(editMenuHdl,iCut);
EnableMenuItem(editMenuHdl,iCopy);
EnableMenuItem(editMenuHdl,iClear);
}
else
{
DisableMenuItem(editMenuHdl,iCut);
DisableMenuItem(editMenuHdl,iCopy);
DisableMenuItem(editMenuHdl,iClear);
}
GetCurrentScrap(&scrapRef);
osError = GetScrapFlavorFlags(scrapRef,kScrapFlavorTypeText,&scrapFlavorFlags);
if(osError == noErr)
EnableMenuItem(editMenuHdl,iPaste);
else
DisableMenuItem(editMenuHdl,iPaste);
if((*textEditStrucHdl)->teLength > 0)
{
EnableMenuItem(fileMenuHdl,iSaveAs);
EnableMenuItem(editMenuHdl,iSelectAll);
}
else
{
DisableMenuItem(fileMenuHdl,iSaveAs);
DisableMenuItem(editMenuHdl,iSelectAll);
}
}
else
{
DisableMenuItem(fileMenuHdl,iClose);
DisableMenuItem(fileMenuHdl,iSaveAs);
DisableMenuItem(editMenuHdl,iClear);
DisableMenuItem(editMenuHdl,iSelectAll);
}
DrawMenuBar();
}
// ****************************************************************************** doMenuChoice
void doMenuChoice(MenuID menuID, MenuItemIndex menuItem)
{
if(menuID == 0)
return;
if(gRunningOnX)
if(menuID == gHelpMenu)
if(menuItem == 1)
doHelp();
switch(menuID)
{
case mAppleApplication:
if(menuItem == iAbout)
SysBeep(10);
else if(menuItem == iHelp)
doHelp();
break;
case mFile:
doFileMenu(menuItem);
break;
case mEdit:
doEditMenu(menuItem);
break;
}
}
// ******************************************************************************** doFileMenu
void doFileMenu(MenuItemIndex menuItem)
{
WindowRef windowRef;
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
switch(menuItem)
{
case iNew:
if(windowRef = doNewDocWindow())
ShowWindow(windowRef);
break;
case iOpen:
doOpenCommand();
doAdjustScrollbar(FrontWindow());
break;
case iClose:
doCloseWindow(FrontWindow());
break;
case iSaveAs:
docStrucHdl = (docStructureHandle) (GetWRefCon(FrontWindow()));
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
doSaveAsFile(textEditStrucHdl);
break;
}
}
// ******************************************************************************** doEditMenu
void doEditMenu(MenuItemIndex menuItem)
{
WindowRef windowRef;
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
SInt32 totalSize, contigSize, newSize;
SInt16 selectionLength;
ScrapRef scrapRef;
Size sizeOfTextData;
windowRef = FrontWindow();
docStrucHdl = (docStructureHandle) (GetWRefCon(windowRef));
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
switch(menuItem)
{
case iUndo:
break;
case iCut:
if(ClearCurrentScrap() == noErr)
{
PurgeSpace(&totalSize,&contigSize);
selectionLength = doGetSelectLength(textEditStrucHdl);
if(selectionLength > contigSize)
doErrorAlert(eNoSpaceCut);
else
{
TECut(textEditStrucHdl);
doAdjustScrollbar(windowRef);
TEToScrap();
if(TEToScrap() != noErr)
ClearCurrentScrap();
}
}
break;
case iCopy:
if(ClearCurrentScrap() == noErr)
TECopy(textEditStrucHdl);
TEToScrap();
if(TEToScrap() != noErr)
ClearCurrentScrap();
break;
case iPaste:
GetCurrentScrap(&scrapRef);;
GetScrapFlavorSize(scrapRef,kScrapFlavorTypeText,&sizeOfTextData);
newSize = (*textEditStrucHdl)->teLength + sizeOfTextData;
if(newSize > kMaxTELength)
doErrorAlert(eNoSpacePaste);
else
{
if(TEFromScrap() == noErr)
{
TEPaste(textEditStrucHdl);
doAdjustScrollbar(windowRef);
}
}
break;
case iClear:
TEDelete(textEditStrucHdl);
doAdjustScrollbar(windowRef);
break;
case iSelectAll:
TESetSelect(0,(*textEditStrucHdl)->teLength,textEditStrucHdl);
break;
}
doDrawDataPanel(windowRef);
}
// ************************************************************************* doGetSelectLength
SInt16 doGetSelectLength(TEHandle textEditStrucHdl)
{
SInt16 selectionLength;
selectionLength = (*textEditStrucHdl)->selEnd - (*textEditStrucHdl)->selStart;
return selectionLength;
}
// ************************************************************************* doAdjustScrollbar
void doAdjustScrollbar(WindowRef windowRef)
{
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
SInt16 numberOfLines, controlMax, controlValue;
docStrucHdl = (docStructureHandle) (GetWRefCon(windowRef));;
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
numberOfLines = (*textEditStrucHdl)->nLines;
if(*(*(*textEditStrucHdl)->hText + (*textEditStrucHdl)->teLength - 1) == kReturn)
numberOfLines += 1;
controlMax = numberOfLines - (((*textEditStrucHdl)->viewRect.bottom -
(*textEditStrucHdl)->viewRect.top) /
(*textEditStrucHdl)->lineHeight);
if(controlMax < 0)
controlMax = 0;
SetControlMaximum((*docStrucHdl)->vScrollbarRef,controlMax);
controlValue = ((*textEditStrucHdl)->viewRect.top - (*textEditStrucHdl)->destRect.top) /
(*textEditStrucHdl)->lineHeight;
if(controlValue < 0)
controlValue = 0;
else if(controlValue > controlMax)
controlValue = controlMax;
SetControlValue((*docStrucHdl)->vScrollbarRef,controlValue);
SetControlViewSize((*docStrucHdl)->vScrollbarRef,(*textEditStrucHdl)->viewRect.bottom -
(*textEditStrucHdl)->viewRect.top);
TEScroll(0,((*textEditStrucHdl)->viewRect.top - (*textEditStrucHdl)->destRect.top) -
(GetControlValue((*docStrucHdl)->vScrollbarRef) *
(*textEditStrucHdl)->lineHeight),textEditStrucHdl);
}
// **************************************************************************** doAdjustCursor
void doAdjustCursor(WindowRef windowRef)
{
GrafPtr oldPort;
RgnHandle arrowRegion, iBeamRegion;
Rect portRect, cursorRect;
Point mouseXY;
GetPort(&oldPort);
SetPortWindowPort(windowRef);
arrowRegion = NewRgn();
iBeamRegion = NewRgn();
SetRectRgn(arrowRegion,-32768,-32768,32766,32766);
GetWindowPortBounds(windowRef,&portRect);
cursorRect = portRect;
cursorRect.bottom -= 15;
cursorRect.right -= 15;
LocalToGlobal(&topLeft(cursorRect));
LocalToGlobal(&botRight(cursorRect));
RectRgn(iBeamRegion,&cursorRect);
DiffRgn(arrowRegion,iBeamRegion,arrowRegion);
GetGlobalMouse(&mouseXY);
if(PtInRgn(mouseXY,iBeamRegion))
SetThemeCursor(kThemeIBeamCursor);
else
SetThemeCursor(kThemeArrowCursor);
DisposeRgn(arrowRegion);
DisposeRgn(iBeamRegion);
SetPort(oldPort);
}
// ***************************************************************************** doCloseWindow
void doCloseWindow(WindowRef windowRef)
{
docStructureHandle docStrucHdl;
docStrucHdl = (docStructureHandle) (GetWRefCon(windowRef));;
DisposeControl((*docStrucHdl)->vScrollbarRef);
TEDispose((*docStrucHdl)->textEditStrucHdl);
DisposeHandle((Handle) docStrucHdl);
DisposeWindow(windowRef);
gNumberOfWindows --;
}
// ****************************************************************************** doSaveAsFile
void doSaveAsFile(TEHandle textEditStrucHdl)
{
OSErr osError = noErr;
NavDialogOptions dialogOptions;
NavEventUPP navEventFunctionUPP;
WindowRef windowRef;
OSType fileType;
NavReplyRecord navReplyStruc;
AEKeyword theKeyword;
DescType actualType;
FSSpec fileSpec;
SInt16 fileRefNum;
Size actualSize;
SInt32 dataLength;
Handle editTextHdl;
osError = NavGetDefaultDialogOptions(&dialogOptions);
if(osError == noErr)
{
windowRef = FrontWindow();
fileType = 'TEXT';
navEventFunctionUPP = NewNavEventUPP((NavEventProcPtr) navEventFunction);
osError = NavPutFile(NULL,&navReplyStruc,&dialogOptions,navEventFunctionUPP,fileType,
'kjBb',NULL);
DisposeNavEventUPP(navEventFunctionUPP);
if(navReplyStruc.validRecord && osError == noErr)
{
if((osError = AEGetNthPtr(&(navReplyStruc.selection),1,typeFSS,&theKeyword,
&actualType,&fileSpec,sizeof(fileSpec),&actualSize)) == noErr)
{
if(!navReplyStruc.replacing)
{
osError = FSpCreate(&fileSpec,'kjBb',fileType,navReplyStruc.keyScript);
if(osError != noErr)
{
NavDisposeReply(&navReplyStruc);
}
}
if(osError == noErr)
osError = FSpOpenDF(&fileSpec,fsRdWrPerm,&fileRefNum);
if(osError == noErr)
{
SetWTitle(windowRef,fileSpec.name);
dataLength = (*textEditStrucHdl)->teLength;
editTextHdl = (*textEditStrucHdl)->hText;
FSWrite(fileRefNum,&dataLength,*editTextHdl);
}
NavCompleteSave(&navReplyStruc,kNavTranslateInPlace);
}
NavDisposeReply(&navReplyStruc);
}
}
}
// ***************************************************************************** doOpenCommand
void doOpenCommand(void)
{
OSErr osError = noErr;
NavDialogOptions dialogOptions;
NavEventUPP navEventFunctionUPP;
NavReplyRecord navReplyStruc;
SInt32 index, count;
AEKeyword theKeyword;
DescType actualType;
FSSpec fileSpec;
Size actualSize;
FInfo fileInfo;
osError = NavGetDefaultDialogOptions(&dialogOptions);
if(osError == noErr)
{
navEventFunctionUPP = NewNavEventUPP((NavEventProcPtr) navEventFunction);
osError = NavGetFile(NULL,&navReplyStruc,&dialogOptions,navEventFunctionUPP,NULL,NULL,
NULL,NULL);
DisposeNavEventUPP(navEventFunctionUPP);
if(osError == noErr && navReplyStruc.validRecord)
{
osError = AECountItems(&(navReplyStruc.selection),&count);
if(osError == noErr)
{
for(index=1;index<=count;index++)
{
osError = AEGetNthPtr(&(navReplyStruc.selection),index,typeFSS,&theKeyword,
&actualType,&fileSpec,sizeof(fileSpec),&actualSize);
{
if((osError = FSpGetFInfo(&fileSpec,&fileInfo)) == noErr)
doOpenFile(fileSpec);
}
}
}
NavDisposeReply(&navReplyStruc);
}
}
}
// ******************************************************************************** doOpenFile
void doOpenFile(FSSpec fileSpec)
{
WindowRef windowRef;
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
SInt16 fileRefNum;
SInt32 textLength;
Handle textBuffer;
if((windowRef = doNewDocWindow()) == NULL)
return;
docStrucHdl = (docStructureHandle) (GetWRefCon(windowRef));;
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
SetWTitle(windowRef,fileSpec.name);
FSpOpenDF(&fileSpec,fsCurPerm,&fileRefNum);
SetFPos(fileRefNum,fsFromStart,0);
GetEOF(fileRefNum,&textLength);
if(textLength > 32767)
textLength = 32767;
textBuffer = NewHandle((Size) textLength);
FSRead(fileRefNum,&textLength,*textBuffer);
MoveHHi(textBuffer);
HLock(textBuffer);
TESetText(*textBuffer,textLength,textEditStrucHdl);
HUnlock(textBuffer);
DisposeHandle(textBuffer);
FSClose(fileRefNum);
(*textEditStrucHdl)->selStart = 0;
(*textEditStrucHdl)->selEnd = 0;
doDrawContent(windowRef);
}
// *************************************************************************** doDrawDataPanel
void doDrawDataPanel(WindowRef windowRef)
{
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
RGBColor whiteColour = { 0xFFFF, 0xFFFF, 0xFFFF };
RGBColor blackColour = { 0x0000, 0x0000, 0x0000 };
RGBColor blueColour = { 0x1818, 0x4B4B, 0x8181 };
ControlRef controlRef;
Rect panelRect;
Str255 textString;
SetPortWindowPort(windowRef);
docStrucHdl = (docStructureHandle) (GetWRefCon(windowRef));;
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
controlRef = (*docStrucHdl)->vScrollbarRef;
MoveTo(0,282);
LineTo(495,282);
RGBForeColor(&whiteColour);
RGBBackColor(&blueColour);
SetRect(&panelRect,0,283,495,300);
EraseRect(&panelRect);
MoveTo(3,295);
DrawString("\pteLength nLines lineHeight");
MoveTo(225,295);
DrawString("\pdestRect.top controlValue contrlMax");
SetRect(&panelRect,47,284,88,299);
EraseRect(&panelRect);
SetRect(&panelRect,124,284,149,299);
EraseRect(&panelRect);
SetRect(&panelRect,204,284,222,299);
EraseRect(&panelRect);
SetRect(&panelRect,286,284,323,299);
EraseRect(&panelRect);
SetRect(&panelRect,389,284,416,299);
EraseRect(&panelRect);
SetRect(&panelRect,472,284,495,299);
EraseRect(&panelRect);
NumToString((SInt32) (*textEditStrucHdl)->teLength,textString);
MoveTo(47,295);
DrawString(textString);
NumToString((SInt32) (*textEditStrucHdl)->nLines,textString);
MoveTo(124,295);
DrawString(textString);
NumToString((SInt32) (*textEditStrucHdl)->lineHeight,textString);
MoveTo(204,295);
DrawString(textString);
NumToString((SInt32) (*textEditStrucHdl)->destRect.top,textString);
MoveTo(286,295);
DrawString(textString);
NumToString((SInt32) GetControlValue(controlRef),textString);
MoveTo(389,295);
DrawString(textString);
NumToString((SInt32) GetControlMaximum(controlRef),textString);
MoveTo(472,295);
DrawString(textString);
RGBForeColor(&blackColour);
RGBBackColor(&whiteColour);
}
// ****************************************************************************** doErrorAlert
void doErrorAlert(SInt16 errorCode)
{
Str255 errorString;
SInt16 itemHit;
GetIndString(errorString,rErrorStrings,errorCode);
if(errorCode < eWindow)
{
StandardAlert(kAlertStopAlert,errorString,NULL,NULL,&itemHit);
ExitToShell();
}
else
{
StandardAlert(kAlertCautionAlert,errorString,NULL,NULL,&itemHit);
}
}
// ************************************************************************** navEventFunction
void navEventFunction(NavEventCallbackMessage callBackSelector,NavCBRecPtr callBackParms,
NavCallBackUserData callBackUD)
{
}
// *******************************************************************************************
// HelpDialog.c
// *******************************************************************************************
// .................................................................................. includes
#include <Carbon.h>
// ................................................................................... defines
#define eHelpDialog 8
#define eHelpDocStructure 9
#define eHelpText 10
#define eHelpPicture 11
#define eHelpControls 12
#define rTextIntroduction 128
#define rTextCreatingText 129
#define rTextModifyHelp 130
#define rPictIntroductionBase 128
#define rPictCreatingTextBase 129
#define kTextInset 4
// .................................................................................. typedefs
typedef struct
{
Rect bounds;
PicHandle pictureHdl;
} pictInfoStructure;
typedef struct
{
TEHandle textEditStrucHdl;
ControlRef scrollbarHdl;
SInt16 pictCount;
pictInfoStructure *pictInfoStructurePtr;
} docStructure, ** docStructureHandle;
typedef struct
{
RGBColor backColour;
PixPatHandle backPixelPattern;
Pattern backBitPattern;
} backColourPattern;
// .......................................................................... global variables
GrafPtr gOldPort;
EventHandlerUPP helpWindowEventHandlerUPP;
ControlUserPaneDrawUPP userPaneDrawFunctionUPP;
ControlActionUPP actionFunctionUPP;
SInt16 gTextResourceID;
SInt16 gPictResourceBaseID;
RgnHandle gSavedClipRgn = NULL;
// ....................................................................... function prototypes
void doHelp (void);
OSStatus helpWindowEventHandler (EventHandlerCallRef,EventRef,void *);
void userPaneDrawFunction (ControlRef,SInt16);
Boolean doGetText (WindowRef,SInt16,Rect);
Boolean doGetPictureInfo (WindowRef,SInt16);
void actionFunction (ControlRef,SInt16);
void doScrollTextAndPicts (WindowRef);
void doDrawPictures (WindowRef,Rect *);
void doCloseHelp (WindowRef);
void doDisposeDescriptors (void);
void doSetBackgroundWhite (void);
extern void doErrorAlert (SInt16);
// ************************************************************************************ doHelp
void doHelp(void)
{
OSStatus osError;
WindowRef windowRef;
docStructureHandle docStrucHdl;
ControlRef controlRef;
ControlID controlID;
Rect windowRect = { 0, 0, 353,382 };
Rect pushButtonRect = { 312,297,332,366 };
Rect userPaneRect = { 16, 16, 296,351 };
Rect scrollBarRect = { 16, 350,296,366 };
Rect popupButtonRect = { 312,12, 332,256 };
Rect destRect, viewRect;
EventTypeSpec dialogEvents[] = {{ kEventClassControl, kEventControlClick } };
GetPort(&gOldPort);
// ..................................................... create universal procedure pointers
helpWindowEventHandlerUPP = NewEventHandlerUPP((EventHandlerProcPtr)
helpWindowEventHandler);
userPaneDrawFunctionUPP = NewControlUserPaneDrawUPP((ControlUserPaneDrawProcPtr)
userPaneDrawFunction);
actionFunctionUPP = NewControlActionUPP((ControlActionProcPtr) actionFunction);
// ............................................................... create modal class window
osError = CreateNewWindow(kMovableModalWindowClass,kWindowStandardHandlerAttribute,
&windowRect,&windowRef);
if(osError == noErr)
{
RepositionWindow(windowRef,FrontWindow(),kWindowAlertPositionOnMainScreen);
SetThemeWindowBackground(windowRef,kThemeBrushDialogBackgroundActive,false);
InstallWindowEventHandler(windowRef,helpWindowEventHandlerUPP,
GetEventTypeCount(dialogEvents),dialogEvents,windowRef,NULL);
if(!(docStrucHdl = (docStructureHandle) NewHandle(sizeof(docStructure))))
{
doErrorAlert(eHelpDocStructure);
DisposeWindow(windowRef);
doDisposeDescriptors();
return;
}
SetWRefCon(windowRef,(SInt32) docStrucHdl);
SetPortWindowPort(windowRef);
// .......................... create root, push button, user pane, and scroll bar controls
CreateRootControl(windowRef,&controlRef);
if((osError = CreatePushButtonControl(windowRef,&pushButtonRect,CFSTR("OK"),&controlRef))
== noErr)
{
SetWindowDefaultButton(windowRef,controlRef);
controlID.id = 'done';
SetControlID(controlRef,&controlID);
}
if(osError == noErr)
{
if((osError = CreateUserPaneControl(windowRef,&userPaneRect,0,&controlRef)) == noErr)
{
SetControlData(controlRef,kControlEntireControl,kControlUserPaneDrawProcTag,
sizeof(userPaneDrawFunctionUPP),(Ptr) &userPaneDrawFunctionUPP);
}
}
if(osError == noErr)
{
if((osError = CreateScrollBarControl(windowRef,&scrollBarRect,0,0,1,0,true,
actionFunctionUPP,&controlRef)) == noErr)
(*docStrucHdl)->scrollbarHdl = controlRef;
controlID.id = 'scro';
SetControlID(controlRef,&controlID);
}
if(osError == noErr)
{
if((osError = CreatePopupButtonControl(windowRef,&popupButtonRect,CFSTR("Title:"),131,
false,-1,0,0,&controlRef)) == noErr)
controlID.id = 'popu';
SetControlID(controlRef,&controlID);
}
if(osError != noErr)
{
doErrorAlert(eHelpControls);
DisposeWindow(windowRef);
doDisposeDescriptors();
return;
}
}
else
{
doErrorAlert(eHelpDialog);
doDisposeDescriptors();
return;
}
// .......................... set destination and view rectangles, create TextEdit structure
InsetRect(&userPaneRect,kTextInset,kTextInset / 2);
destRect = viewRect = userPaneRect;
(*docStrucHdl)->textEditStrucHdl = TEStyleNew(&destRect,&viewRect);
// .................... initialise picture information structure field of document structure
(*docStrucHdl)->pictInfoStructurePtr = NULL;
// ............................ assign resource IDs of first topic's 'TEXT'/'styl' resources
gTextResourceID = rTextIntroduction;
gPictResourceBaseID = rPictIntroductionBase;
// ...................................... load text resources and insert into edit structure
if(!(doGetText(windowRef,gTextResourceID,viewRect)))
{
doCloseHelp(windowRef);
doDisposeDescriptors();
return;
}
// ......... search for option-space charas in text and load same number of 'PICT' resources
if(!(doGetPictureInfo(windowRef,gPictResourceBaseID)))
{
doCloseHelp(windowRef);
doDisposeDescriptors();
return;
}
// ............................... create an empty region for saving the old clipping region
gSavedClipRgn = NewRgn();
// .......................................................... show window and run modal loop
ShowWindow(windowRef);
RunAppModalLoopForWindow(windowRef);
}
// ******************************************************************** helpWindowEventHandler
OSStatus helpWindowEventHandler(EventHandlerCallRef eventHandlerCallRef,EventRef eventRef,
void *userData)
{
OSStatus result = eventNotHandledErr;
WindowRef windowRef;
UInt32 eventClass;
UInt32 eventKind;
Point mouseLocation;
ControlRef controlRef;
ControlPartCode controlPartCode;
ControlID controlID;
MenuItemIndex menuItem;
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
Rect viewRect;
windowRef = userData;
eventClass = GetEventClass(eventRef);
eventKind = GetEventKind(eventRef);
if(eventClass == kEventClassControl)
{
if(eventKind == kEventControlClick)
{
GetEventParameter(eventRef,kEventParamMouseLocation,typeQDPoint,NULL,
sizeof(mouseLocation),NULL,&mouseLocation);
GlobalToLocal(&mouseLocation);
controlRef = FindControlUnderMouse(mouseLocation,windowRef,&controlPartCode);
if(controlRef)
{
GetControlID(controlRef,&controlID);
if(controlID.id == 'done') // push button
{
if(TrackControl(controlRef,mouseLocation,NULL))
{
QuitAppModalLoopForWindow(windowRef);
doCloseHelp(windowRef);
doDisposeDescriptors();
result = noErr;
}
}
if(controlID.id == 'scro') // scroll bar
{
TrackControl(controlRef,mouseLocation,actionFunctionUPP);
result = noErr;
}
else if(controlID.id == 'popu') // pop-up menu button
{
TrackControl(controlRef,mouseLocation,(ControlActionUPP) -1);
menuItem = GetControlValue(controlRef);
switch(menuItem)
{
case 1:
gTextResourceID = rTextIntroduction;
gPictResourceBaseID = rPictIntroductionBase;
break;
case 2:
gTextResourceID = rTextCreatingText;
gPictResourceBaseID = rPictCreatingTextBase;
break;
case 3:
gTextResourceID = rTextModifyHelp;
break;
}
docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
viewRect = (*textEditStrucHdl)->viewRect;
if(!(doGetText(windowRef,gTextResourceID,viewRect)))
{
doCloseHelp(windowRef);
doDisposeDescriptors();
return;
}
if(!(doGetPictureInfo(windowRef,gPictResourceBaseID)))
{
doCloseHelp(windowRef);
doDisposeDescriptors();
return;
}
doDrawPictures(windowRef,&viewRect);
result = noErr;
}
}
}
}
return result;
}
// ********************************************************************** userPaneDrawFunction
void userPaneDrawFunction(ControlRef controlRef,SInt16 thePart)
{
Rect itemRect, viewRect;
WindowRef windowRef;
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
Boolean inState;
windowRef = GetControlOwner(controlRef);
GetControlBounds(controlRef,&itemRect);
InsetRect(&itemRect,1,1);
itemRect.right += 15;
if(IsWindowVisible(windowRef))
inState = IsWindowHilited(windowRef);
DrawThemeListBoxFrame(&itemRect,inState);
doSetBackgroundWhite();
EraseRect(&itemRect);
docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
viewRect = (*textEditStrucHdl)->viewRect;
TEUpdate(&viewRect,textEditStrucHdl);
doDrawPictures(windowRef,&viewRect);
}
// ********************************************************************************* doGetText
Boolean doGetText(WindowRef windowRef,SInt16 textResourceID,Rect viewRect)
{
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
Handle helpTextHdl;
StScrpHandle stylScrpStrucHdl;
SInt16 numberOfLines, heightOfText, heightToScroll;
doSetBackgroundWhite();
docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
TESetSelect(0,32767,textEditStrucHdl);
TEDelete(textEditStrucHdl);
(*textEditStrucHdl)->destRect = (*textEditStrucHdl)->viewRect;
SetControlValue((*docStrucHdl)->scrollbarHdl,0);
helpTextHdl = GetResource('TEXT',textResourceID);
if(helpTextHdl == NULL)
{
doErrorAlert(eHelpText);
return false;
}
stylScrpStrucHdl = (StScrpHandle) GetResource('styl',textResourceID);
if(stylScrpStrucHdl == NULL)
{
doErrorAlert(eHelpText);
return false;
}
TEStyleInsert(*helpTextHdl,GetHandleSize(helpTextHdl),stylScrpStrucHdl,textEditStrucHdl);
ReleaseResource(helpTextHdl);
ReleaseResource((Handle) stylScrpStrucHdl);
numberOfLines = (*textEditStrucHdl)->nLines;
heightOfText = TEGetHeight((SInt32) numberOfLines,1,textEditStrucHdl);
if(heightOfText > (viewRect.bottom - viewRect.top))
{
heightToScroll = TEGetHeight((SInt32) numberOfLines,1,textEditStrucHdl) -
(viewRect.bottom - viewRect.top);
SetControlMaximum((*docStrucHdl)->scrollbarHdl,heightToScroll);
ActivateControl((*docStrucHdl)->scrollbarHdl);
SetControlViewSize((*docStrucHdl)->scrollbarHdl,(*textEditStrucHdl)->viewRect.bottom -
(*textEditStrucHdl)->viewRect.top);
}
else
{
DeactivateControl((*docStrucHdl)->scrollbarHdl);
}
return true;
}
// ************************************************************************** doGetPictureInfo
Boolean doGetPictureInfo(WindowRef windowRef,SInt16 firstPictID)
{
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
Handle textHdl;
SInt32 offset, textSize;
SInt16 numberOfPicts, a, lineHeight, fontAscent;
SInt8 optionSpace[1] = "\xCA";
pictInfoStructure *pictInfoPtr;
Point picturePoint;
TextStyle whatStyle;
docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
if((*docStrucHdl)->pictInfoStructurePtr != NULL)
{
for(a=0;a<(*docStrucHdl)->pictCount;a++)
ReleaseResource((Handle) (*docStrucHdl)->pictInfoStructurePtr[a].pictureHdl);
DisposePtr((Ptr) (*docStrucHdl)->pictInfoStructurePtr);
(*docStrucHdl)->pictInfoStructurePtr = NULL;
}
(*docStrucHdl)->pictCount = 0;
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
textHdl = (*textEditStrucHdl)->hText;
textSize = GetHandleSize(textHdl);
offset = 0;
numberOfPicts = 0;
HLock(textHdl);
offset = Munger(textHdl,offset,optionSpace,1,NULL,0);
while((offset >= 0) && (offset <= textSize))
{
numberOfPicts++;
offset++;
offset = Munger(textHdl,offset,optionSpace,1,NULL,0);
}
if(numberOfPicts == 0)
{
HUnlock(textHdl);
return true;
}
pictInfoPtr = (pictInfoStructure *) NewPtr(sizeof(pictInfoStructure) * numberOfPicts);
(*docStrucHdl)->pictInfoStructurePtr = pictInfoPtr;
offset = 0L;
for(a=0;a<numberOfPicts;a++)
{
pictInfoPtr[a].pictureHdl = GetPicture(firstPictID + a);
if(pictInfoPtr[a].pictureHdl == NULL)
{
doErrorAlert(eHelpPicture);
return false;
}
offset = Munger(textHdl,offset,optionSpace,1,NULL,0);
picturePoint = TEGetPoint((SInt16)offset,textEditStrucHdl);
TEGetStyle(offset,&whatStyle,&lineHeight,&fontAscent,textEditStrucHdl);
picturePoint.v -= lineHeight;
offset++;
pictInfoPtr[a].bounds = (**pictInfoPtr[a].pictureHdl).picFrame;
OffsetRect(&pictInfoPtr[a].bounds,
(((*textEditStrucHdl)->destRect.right + (*textEditStrucHdl)->destRect.left) -
(pictInfoPtr[a].bounds.right + pictInfoPtr[a].bounds.left) ) / 2,
- pictInfoPtr[a].bounds.top + picturePoint.v);
}
(*docStrucHdl)->pictCount = a;
HUnlock(textHdl);
return true;
}
// **************************************************************************** actionFunction
void actionFunction(ControlRef scrollbarHdl,SInt16 partCode)
{
WindowRef windowRef;
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
SInt16 delta, oldValue, offset, lineHeight, fontAscent;
Point thePoint;
Rect viewRect, portRect;
TextStyle style;
if(partCode)
{
windowRef = GetControlOwner(scrollbarHdl);
docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
viewRect = (*textEditStrucHdl)->viewRect;
thePoint.h = viewRect.left + kTextInset;
if(partCode != kControlIndicatorPart)
{
switch(partCode)
{
case kControlUpButtonPart:
thePoint.v = viewRect.top - 4;
offset = TEGetOffset(thePoint,textEditStrucHdl);
thePoint = TEGetPoint(offset,textEditStrucHdl);
TEGetStyle(offset,&style,&lineHeight,&fontAscent,textEditStrucHdl);
delta = thePoint.v - lineHeight - viewRect.top;
break;
case kControlDownButtonPart:
thePoint.v = viewRect.bottom + 2;
offset = TEGetOffset(thePoint,textEditStrucHdl);
thePoint = TEGetPoint(offset,textEditStrucHdl);
delta = thePoint.v - viewRect.bottom;
break;
case kControlPageUpPart:
thePoint.v = viewRect.top + 2;
offset = TEGetOffset(thePoint,textEditStrucHdl);
thePoint = TEGetPoint(offset,textEditStrucHdl);
TEGetStyle(offset,&style,&lineHeight,&fontAscent,textEditStrucHdl);
thePoint.v += lineHeight - fontAscent;
thePoint.v -= viewRect.bottom - viewRect.top;
offset = TEGetOffset(thePoint,textEditStrucHdl);
thePoint = TEGetPoint(offset,textEditStrucHdl);
TEGetStyle(offset,&style,&lineHeight,&fontAscent,textEditStrucHdl);
delta = thePoint.v - viewRect.top;
if(offset == 0)
delta -= lineHeight;
break;
case kControlPageDownPart:
thePoint.v = viewRect.bottom - 2;
offset = TEGetOffset(thePoint,textEditStrucHdl);
thePoint = TEGetPoint(offset,textEditStrucHdl);
TEGetStyle(offset,&style,&lineHeight,&fontAscent,textEditStrucHdl);
thePoint.v -= fontAscent;
thePoint.v += viewRect.bottom - viewRect.top;
offset = TEGetOffset(thePoint,textEditStrucHdl);
thePoint = TEGetPoint(offset,textEditStrucHdl);
TEGetStyle(offset,&style,&lineHeight,&fontAscent,textEditStrucHdl);
delta = thePoint.v - lineHeight - viewRect.bottom;
if(offset == (**textEditStrucHdl).teLength)
delta += lineHeight;
break;
}
oldValue = GetControlValue(scrollbarHdl);
if(((delta < 0) && (oldValue > 0)) || ((delta > 0) &&
(oldValue < GetControlMaximum(scrollbarHdl))))
{
GetClip(gSavedClipRgn);
GetWindowPortBounds(windowRef,&portRect);
ClipRect(&portRect);
SetControlValue(scrollbarHdl,oldValue + delta);
SetClip(gSavedClipRgn);
}
}
doScrollTextAndPicts(windowRef);
}
}
// ********************************************************************** doScrollTextAndPicts
void doScrollTextAndPicts(WindowRef windowRef)
{
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
SInt16 scrollDistance, oldScroll;
Rect updateRect;
doSetBackgroundWhite();
docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
oldScroll = (*textEditStrucHdl)->viewRect.top -(*textEditStrucHdl)->destRect.top;
scrollDistance = oldScroll - GetControlValue((*docStrucHdl)->scrollbarHdl);
if(scrollDistance == 0)
return;
TEScroll(0,scrollDistance,textEditStrucHdl);
if((*docStrucHdl)->pictCount == 0)
return;
updateRect = (*textEditStrucHdl)->viewRect;
if(scrollDistance > 0)
{
if(scrollDistance < (updateRect.bottom - updateRect.top))
updateRect.bottom = updateRect.top + scrollDistance;
}
else
{
if( - scrollDistance < (updateRect.bottom - updateRect.top))
updateRect.top = updateRect.bottom + scrollDistance;
}
doDrawPictures(windowRef,&updateRect);
}
// **************************************************************************** doDrawPictures
void doDrawPictures(WindowRef windowRef,Rect *updateRect)
{
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
SInt16 pictCount, pictIndex, vOffset;
PicHandle thePictHdl;
Rect pictLocRect, dummyRect;
docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
vOffset = (*textEditStrucHdl)->destRect.top -
(*textEditStrucHdl)->viewRect.top - kTextInset;
pictCount = (*docStrucHdl)->pictCount;
for(pictIndex = 0;pictIndex < pictCount;pictIndex++)
{
pictLocRect = (*docStrucHdl)->pictInfoStructurePtr[pictIndex].bounds;
OffsetRect(&pictLocRect,0,vOffset);
if(!SectRect(&pictLocRect,updateRect,&dummyRect))
continue;
thePictHdl = (*docStrucHdl)->pictInfoStructurePtr[pictIndex].pictureHdl;
LoadResource((Handle) thePictHdl);
HLock((Handle) thePictHdl);
GetClip(gSavedClipRgn);
ClipRect(updateRect);
DrawPicture(thePictHdl,&pictLocRect);
SetClip(gSavedClipRgn);
HUnlock((Handle) thePictHdl);
}
}
// ******************************************************************************* doCloseHelp
void doCloseHelp(WindowRef windowRef)
{
docStructureHandle docStrucHdl;
TEHandle textEditStrucHdl;
SInt16 a;
docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
textEditStrucHdl = (*docStrucHdl)->textEditStrucHdl;
if(gSavedClipRgn)
DisposeRgn(gSavedClipRgn);
if((*docStrucHdl)->textEditStrucHdl)
TEDispose((*docStrucHdl)->textEditStrucHdl);
if((*docStrucHdl)->pictInfoStructurePtr)
{
for(a=0;a<(*docStrucHdl)->pictCount;a++)
ReleaseResource((Handle) (*docStrucHdl)->pictInfoStructurePtr[a].pictureHdl);
DisposePtr((Ptr) (*docStrucHdl)->pictInfoStructurePtr);
}
DisposeHandle((Handle) docStrucHdl);
DisposeWindow(windowRef);
SetPort(gOldPort);
}
// ********************************************************************** doDisposeDescriptors
void doDisposeDescriptors(void)
{
DisposeEventHandlerUPP(helpWindowEventHandlerUPP);
DisposeControlUserPaneDrawUPP(userPaneDrawFunctionUPP);
DisposeControlActionUPP(actionFunctionUPP);
}
// ********************************************************************** doSetBackgroundWhite
void doSetBackgroundWhite(void)
{
RGBColor whiteColour = { 0xFFFF, 0xFFFF, 0xFFFF };
Pattern whitePattern;
RGBBackColor(&whiteColour);
BackPat(GetQDGlobalsWhite(&whitePattern));
}
// *******************************************************************************************
Demonstration Program MonoTextEdit Comments
When this program is run, the user should explore both the text editor and the Help dialog.
Text Editor
In the text editor, the user should perform all the actions usually associated with a simple
text editor, that is:
o Open a new document window, open an existing 'TEXT' file for display in a new document
window, and save a document to a 'TEXT' file. (A 'TEXT' file titled "MonoTextEdit Document"
is included.)
o Enter new text and use the Edit menu Cut, Copy, Paste, and Clear commands to edit the text.
(Pasting between documents and other applications is supported.)
o Select text by clicking and dragging, double-clicking a word, shift-clicking, and choosing
the Select All command from the Edit menu. Also select large amounts of text by clicking in
the text and dragging the cursor above or below the window so as to invoke auto-scrolling.
o Scroll a large document by dragging the scroll box/scroller (live scrolling is used),
clicking once in a scroll arrow or gray area/track, and holding the mouse down in a scroll
arrow or gray area/track.
Whenever any action is taken, the user should observe the changes to the values displayed in
the data panel at the bottom of each window. In particular, the relationship between the
destination rectangle and scroll bar control value should be noted.
The user should also note that outline highlighting is activated for all windows and that the
forward-delete key is supported by the application. (The forward-delete key is not supported
by TextEdit.)
Help Dialog
The user should choose MonoTextEdit Help from the Mac OS 8/9 Apple menu or Mac OS X Help menu
to open the Help dialog and then scroll through the three help topics, which may be chosen in
the pop-up menu at the bottom of the dialog. The help topics contain documentation on the Help
dialog which supplements the source code comments below.
MonoTextEdit.c
defines
kMaxTELength represents the maximum allowable number of bytes in a TextEdit structure. kTab,
kBackSpace, kForwardDelete, kReturn, and kEscape representing the character codes generated by
the tab, delete, forward delete, Return and escape keys.
typedefs
The docStructure data type will be used for a small document structure comprising a handle to a
TextEdit structure and a handle to a vertical scroll bar.
Global Variables
scrollActionFunctionUPP will be assigned a universal procedure pointer to an action (callback)
function for the scroll bar. customClickLoopUPP will be assigned a universal procedure pointer
to a custom click loop (callback) function. gOldControlValue will be assigned the scroll bar's
control value.
main
The main function creates universal procedure pointers for the application-defined scroll
action and custom click loop (callback) functions and installs a timer set to fire repeatedly
at the interval returned by a call to GetCaretTime. When the timer fires, the function doIdle
is called.
windowEventHandler
When the kEventClassMouse event type is received, if the call to FindControlUnderMouse reveals
that a control (that is, the vertical scroll bar) is under the mouse, TrackControl is called
with a universal procedure pointer to an action function passed in the third parameter.
When the kEventRawKeyDown and kEventRawKeyRepeat event types are received, the function
doKeyEvent is called only if the Command key was not down.
doIdle
doIdle is called whenever the installed timer fires.
The first line gets a reference to the front window. If the front window is a document window,
a handle to the window's document structure is retrieved. A handle to the TextEdit structure
associated with the window is stored in the document structure's textEditStrucHdl field. This
is passed in the call to TEIdle, which blinks the insertion point caret.
doKeyEvent
doKeyEvent is called when the kEventRawKeyDown and kEventRawKeyRepeat event types are received.
It handles all key-down events that are not Command key equivalents.
If the character code is equal to that for the escape key or lower, and except if it is the
carriage return or backspace character, the function simply returns.
The first three lines get a handle to the TextEdit structure whose handle is stored in the
front window's document structure.
The next line filters out the tab key character code. (TextEdit does not support the tab key
and some applications may need to provide a tab key handler.)
The next character code to be filtered out is the forward-delete key character code. TextEdit
does not recognise this key, so this else if block provides forward-delete key support for the
program. The first line in this block gets the current selection length from the TextEdit
structure. If this is zero (that is, there is no selection range and an insertion point is
being displayed), the selEnd field is incremented by one. This, in effect, creates a selection
range comprising the character following the insertion point. TEDelete deletes the current
selection range from the TextEdit structure. Such deletions could change the number of text
lines in the TextEdit structure, requiring the vertical scroll bar to be adjusted; hence the
call to the function doAdjustScrollbar.
Processing of those character codes which have not been filtered out is performed in the else
block. A new character must not be allowed to be inserted if the TextEdit limit of 32,767
characters will be exceeded. Accordingly, and given that TEKey replaces the selection range
with the character passed to it, the first step is to get the current selection length. If the
current number of characters minus the selection length plus 1 is less than 32,767, the
character code is passed to TEKey for insertion into the TextEdit structure. In addition, and
since all this could change the number of lines in the TextEdit structure, the scroll bar
adjustment function is called.
If the TextEdit limit will be exceeded by accepting the character, an alert is invoked advising
the user of the situation.
The last line calls a function which prints data extracted from the edit text and control
structures at the bottom of the window.
scrollActionFunction
scrollActionFunction is associated with the vertical scroll bar. It is the callback function
which will be repeatedly called by TrackControl when the kEventMouseDown event type is
received. It will be called repeatedly while the mouse button remains down in the scroll
box/scroller, scroll arrows or gray areas/track of the vertical scroll bar.
The first line gets a reference to the window object for the window which "owns" the control.
The next two lines get a handle to the TextEdit structure associated with the window.
Within the outer if block, the first if block executes if the control part is not the scroll
box/scroller (that is, the indicator). The purpose of the switch is to get a value into the
variable linesToScroll. If the mouse-down was in a scroll arrow, that value will be 1. If the
mouse-down was in a gray area/track, that value will be equivalent to one less than the number
of text lines that will fit in the view rectangle. (Subtracting 1 from the total number of
lines that will fit in the view rectangle ensures that the line of text at the bottom/top of
the view rectangle prior to a gray area/track scroll will be visible at the top/bottom of the
window after the scroll.)
Immediately after the switch, the value in linesToScroll is changed to a negative value if the
mouse-down occurred in either the down scroll arrow or down gray area/track.
The next block ensures that no scrolling action will occur if the document is currently
scrolled fully up (control value equals control maximum) or fully down (control value equals
0). In either case, linesToScroll will be set to 0, meaning that the call to TEScroll near the
end of the function will not occur.
SetControlValue sets the control value to the value just previously calculated, that is, to the
current control value minus the value in linesToScroll.
The next line sets the value in linesToScroll back to what it was before the line linesToScroll
= controlvalue - linesToScroll executed. This value, multiplied by the value in the lineHeight
field of the TextEdit structure, is later passed to TEScroll as the parameter which specifies
the number of pixels to scroll.
If the control part is the scroll box/scroller (that is, the indicator), the variable
linesToScroll is assigned a value equal to the control's value as it was the last time this
function was called minus the control's current value. The global variable which holds the
control's "old" value is then assigned the control's current value preparatory to the next call
to this function.
With the number of lines to scroll determined, TEScroll is called to scroll the text within the
view rectangle by the number of pixels specified in the second parameter. (Positive values
scroll the text towards the bottom of the screen. Negative values scroll the text towards the
top.)
The last line is for demonstration purposes only. It calls the function which prints data
extracted from the edit and control structures at the bottom of the window.
doInContent
doInContent is called when the kEventWindowClickContentRgn event type is received.
The first three lines retrieve a handle to the TextEdit structure associated with the front
window. The call to PtInRect checks whether the mouse-down occurred within the view rectangle.
(Note that the view rectangle is in local coordinates, so the mouse-down coordinates passed as
the first parameter to the PtInRect call must also be in local coordinates.) If the mouse-down
was in the view rectangle, TEClick is called to advise TextEdit of the mouse-down event. Note
that the position of the shift key is passed in the second parameter. (TEClick's behaviour
depends on the position of the shift key.)
doDrawContent
doDrawContent is called when the kEventWindowDrawContent event type is received.
The first two lines get the handle to the TextEdit structure associated with the window.
UpdateControls is called to draw the scroll bar. The call to TEUpdate draws the text currently
in the TextEdit structure.
doActivateDeactivate
doActivateDeactivatew performs window activation/deactivation. It is called when the
kEventWindowActivated and kEventWindowDecativated event types are received.
The first two lines retrieve a handle to the TextEdit structure for the window. If the window
is becoming active, its graphics port is set as the current graphics port. The bottom of the
view rectangle is then adjusted so that the height of the view rectangle is an exact multiple
of the value in the lineHeight field of the TextEdit structure. (This avoids the possibility
of only part of the full height of a line of text appearing at the bottom of the view
rectangle.) TEActivate activates the TextEdit structure associated with the window,
ActivateControl activates the scroll bar, doAdjustScrollbar adjusts the scroll bar, and
doAdjustCursor adjusts the cursor shape.
If the window is becoming inactive, TEDeactivate deactivates the TextEdit structure associated
with the window and DeactivateControl deactivates the scroll bar.
doNewDocWindow
doNewDocWindow is called at program launch and when the user chooses New or Open from the File
menu. It opens a new window, associates a document structure with that window, creates a
vertical scroll bar, creates a monostyled TextEdit structure, installs the custom click loop
(callback) function, enables automatic scrolling, and enables outline highlighting.
The call to CreateNewWindow and the following block creates a new window with the standard
document window attributes less the size box/resize control. Note that the window's graphics
port is set as the current port before the later call to TENew. (Since the TextEdit structure
assumes the drawing environment specified in the graphics port structure, setting the graphics
port must be done before TENew creates the TextEdit structure.)
The call to TextSize sets the text size. This, together with the default application font,
will be copied from the graphics port to the TextEdit structure when TENew is called.)
After the window event handler is installed, a document structure is created and the handle
stored in the window's window object. The following line increments the global variable which
keeps track of the number of open windows. GetNewControl creates a vertical scroll bar and
assigns a handle to it to the appropriate field of the document structure. The next block
establishes the view and destination rectangles two pixels inside the window's port rectangle
less the scroll bar.
MoveHHi and HLock move the document structure high and lock it. A monostyled TextEdit
structure is then created by TENew and its handle is assigned to the appropriate field of the
document structure. (If this call is not successful, the window and scroll bar are disposed
of, an error alert is displayed, and the function returns.) The handle to the document
structure is then unlocked.
TESetClickLoop installs the universal procedure pointer to the custom click loop (callback)
function customClickLoop in the clickLoop field of the TextEdit structure. TEAutoView enables
automatic scrolling for the TextEdit structure. TEFeatureFlag enables outline highlighting for
the TextEdit structure.
The last line returns a reference to the newly opened window's window object.
customClickLoop
customClickLoop replaces the default click loop function so as to provide for scroll bar
adjustment in concert with automatic scrolling. Following a mouse-down within the view
rectangle, customClickLoop is called repeatedly by TEClick as long as the mouse button remains
down.
The first three lines retrieve a handle to the TextEdit structure associated with the window.
The next two lines save the current graphics port and set the window's graphics port as the
current port.
The window's current clip region will have been set by TextEdit to be equivalent to the view
rectangle. Since the scroll bar has to be redrawn, the clipping region must be temporarily
reset to include the scroll bar. Accordingly, GetClip saves the current clipping region and
the following two lines set the clipping region to the bounds of the coordinate plane.
GetMouse gets the current position of the cursor. If the cursor is above the top of the port
rectangle, the text must be scrolled downwards. Accordingly, the variable linesToScroll is set
to 1. The subsidiary function doSetScrollBarValue (see below) is then called to, amongst other
things, reset the scroll bar's value. Note that the value in linesToScroll may be modified by
doSetScrollBarValue. If linesToScroll is not set to 0 by doSetScrollBarValue, TEScroll is
called to scroll the text by a number of pixels equivalent to the value in the lineHeight field
of the TextEdit structure, and in a downwards direction.
If the cursor is below the bottom of the port rectangle, the same process occurs except that
the variable linesToScroll is set to -1, thus causing an upwards scroll of the text (assuming
that the value in linesToScroll is not changed to 0 by doSetScrollBarValue).
If scrolling has occurred, doDrawDataPanel redraws the data panel. SetClip restores the
clipping region to that established by the view rectangle and SetPort restores the saved
graphics port. Finally, the last line returns true. (A return of false would cause TextEdit
to stop calling customClickLoop, as if the user had released the mouse button.)
doSetScrollBarValue
doSetScrollBarValue is called from customClickLoop. Apart from setting the scroll bar's value
so as to cause the scroll box to follow up automatic scrolling, the function checks whether the
limits of scrolling have been reached.
The first two lines get the current control value and the current control maximum value. At
the next block, the value in the variable linesToScroll will be set to either 0 (if the current
control value is 0) or equivalent to the control maximum value (if the current control value is
equivalent to the control maximum value. If these modifications do not occur, the value in
linesToScroll will remain as established at the first line in this block, that is, the current
control value minus the value in linesToScroll as passed to the function.
SetControlValue sets the control's value to the value in linesToScroll. The last line sets the
value in linesToScroll to 0 if the limits of scrolling have already been reached, or to the
value as it was when the doSetScrollBarValue function was entered.
doAdjustMenus
doAdjustMenus adjusts the menus. Much depends on whether any windows are currently open.
If at least one window is open, the first three lines in the if block get a handle to the
TextEdit structure associated with the front window and the first call to EnableMenuItem
enables the Close item in the File menu. If there is a current selection range, the Cut, Copy,
and Clear items are enabled, otherwise they are disabled. If there is data of flavour type
'TEXT' in the scrap (the call to GetScrapFlavourFlags), the Paste item is enabled, otherwise it
is disabled. If there is any text in the TextEdit structure, the SaveAs and Select All items
are enabled, otherwise they are disabled.
If no windows are open, the Close, SaveAs, Clear, and Select All items are disabled.
doMenuChoice
If the MonoTextEdit Help item in the Mac OS 8/9 Apple menu or Mac OS X Help menu is chosen, the
function doHelp is called.
doFileMenu
doFileMenu handles File menu choices, calling the appropriate functions according to the menu
item chosen. In the SaveAs case, a handle to the TextEdit structure associated with the front
window is retrieved and passed as a parameter to the function doSaveAsFile.
Note that, because TextEdit, rather than file operations, is the real focus of this program,
the file-related code has been kept to a minimum, even to the extent of having no Save-related,
as opposed to SaveAs-related, code.
doEditMenu
doEditMenu handles choices from the Edit menu. Recall that, in the case of monostyled TextEdit
structures, TECut, TECopy, and TEPaste do not copy/paste text to/from the scrap. This program,
however, supports copying/pasting to/from the scrap.
Before the usual switch is entered, a handle to the TextEdit structure associated with the
front window is retrieved.
The iCut case handles the Cut command. Firstly, the call to ClearCurrentScrap attempts to
clear the scrap. If the call succeeds, PurgeSpace establishes the size of the largest block in
the heap that would be available if a general purge were to occur. The next line gets the
current selection length. If the selection length is greater than the available memory, the
user is advised via an error message. Otherwise, TECut is called to remove the selected text
from the TextEdit structure and copy it to the TextEdit private scrap. The scroll bar is
adjusted, and TEToScrap is called to copy the private scrap to the scrap. If the TEToScrap
call is not successful, ClearCurrentScrap cleans up as best it can by emptying the scrap.
The iCopy case handles the Copy command. If the call to ClearCurrentScrap to empty the scrap
is successful, TECopy is called to copy the selected text |