home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Garbo
/
Garbo.cdr
/
mac
/
source
/
clintsrc.sit
/
DAtextedit.c
< prev
next >
Wrap
Text File
|
1990-06-19
|
14KB
|
578 lines
/*========================================================================
=== DAtextedit.c
===
=== Greg Anderson
=== 29 Kerr Hall
=== Social Sciences Computing
=== University of California at Santa Cruz
=== Santa Cruz CA 95062
===
=== (408) 459-2658
=== sirkm@ssyx.ucsc.edu
===
=== Textedit routines.
===
========================================================================*/
#include <types.h>
#include <osutils.h>
#include <memory.h>
#include <devices.h>
#include <events.h>
#include <quickdraw.h>
#include <fonts.h>
#include <windows.h>
#include <files.h>
#include <errors.h>
#include <toolutils.h>
#include <packages.h>
#include <Limits.h>
#include <Controls.h>
#include <TextEdit.h>
#include <Dialogs.h>
#include <Desk.h>
#include <Scrap.h>
#include <Traps.h>
#include <Lists.h>
#include <Menus.h>
#include "unixDA.h"
#include "DA.h"
/*----------------------------------------------------------------------
| Make a new TextEdit record
----------------------------------------------------------------------*/
TEHandle makeTE( Rect destRect, Rect viewRect )
{
TEHandle te;
TextStyle tStyle;
te = TEStylNew(&destRect, &viewRect);
if( te == nil ) return(te);
/*
* Set the textedit style to small plain monaco
*/
tStyle.tsFont = monaco;
tStyle.tsFace = 0;
tStyle.tsSize = teSize;
TESetStyle(doFont|doFace|doSize,&tStyle,false,te);
adjustViewRect(te);
TEAutoView(true, te);
return( te );
}
/*----------------------------------------------------------------------
| Respond to a non-COMMAND keypress.
----------------------------------------------------------------------*/
void doKeyDown( EventRecord *event, DCtlPtr dCtl)
{
long newCrs = 0;
char key,
code,
msg[8];
int selLen = ((*DA_te)->selEnd - (*DA_te)->selStart);
key = (event->message & charCodeMask);
code = (event->message & keyCodeMask) >> 8;
/*
* Control-C is special.
*/
if( key == 3 )
{
doAbort(dCtl);
return;
}
switch( code )
{
case 122: doUndo(dCtl);
return;
case 120: doCut(dCtl);
return;
case 99: doCopy(dCtl);
return;
case 118: doPaste(dCtl);
return;
case 116: /* pg up */
pageTE( dCtl, ((*DA_te)->viewRect.bottom - (*DA_te)->viewRect.top) );
return;
case 121: /* pg dn */
pageTE( dCtl,-((*DA_te)->viewRect.bottom - (*DA_te)->viewRect.top) );
return;
case 119: /* end */
newCrs = 40000L;
case 115: /* home */
TESetSelect(newCrs,newCrs, DA_te );
adjustScrollbars(DA_window, false);
adjustTE(DA_window);
return;
}
/*
* If there is a connection, then keys are sent to the
* server instead of the window. Translate RETURN to LF,
* because that's what the unix SuperServer likes to see.
*/
if( connectionState( dCtl ) >= 8 )
{
if( key == '\n') key = '\r';
msg[0] = key;
msg[1] = 0;
SendTCP( dCtl, msg );
}
/*
* Did the user type DELETE?
*/
else if( key == kDelChar )
{
/*
* If there is no selection, we make DELETE act like a
* backspace by making a small one-character selection
* (to the left) and then deleting it
*/
if( !selLen )
{
if( (*DA_te)->selStart )
--((*DA_te)->selStart);
}
setUndoCut( dCtl );
TEDelete( DA_te );
adjustScrollbars(DA_window, false);
adjustTE(DA_window);
}
/*
* A non-delete-type character was entered: do we have room for it?
*/
else if( ((*DA_te)->teLength - selLen + 1) < kMaxTELength )
{
if( (DA_global->undoType == undoNothing) || (selLen > 0) )
setUndoCut( dCtl );
++(DA_global->undoTo);
TEKey(key, DA_te);
adjustScrollbars(DA_window, false);
adjustTE(DA_window);
}
else
alertUser(dCtl, eExceedChar);
}
/*----------------------------------------------------------------------
| Process a COMMAND-key.
----------------------------------------------------------------------*/
void doCommandKey( EventRecord *event, DCtlPtr dCtl)
{
char key;
key = event->message & charCodeMask;
switch( key )
{
case 'z': doUndo(dCtl);
break;
case 'x': doCut(dCtl);
break;
case 'c': doCopy(dCtl);
break;
case 'v': doPaste(dCtl);
break;
case '.': doAbort(dCtl);
break;
case 'a': TESetSelect(0,kMaxTELength,DA_te);
break;
case 'r': doReconnect(dCtl);
break;
}
}
/*----------------------------------------------------------------------
| Hilite the 'Edit' menu. (Pretty funky technique, but it works.)
----------------------------------------------------------------------*/
HiliteEditMenu( )
{
HiliteMenu( (short)(( MenuKey('c') >> 16 ) & 0xFF) );
}
/*----------------------------------------------------------------------
| Scroll the TE record one page
----------------------------------------------------------------------*/
void pageTE( DCtlPtr dCtl, int amount)
{
TEScroll(0, amount , DA_te );
adjustScrollbars(DA_window, false);
adjustTE(DA_window);
}
/*----------------------------------------------------------------------
| Cut or copy the selected region of text.
----------------------------------------------------------------------*/
void doCutCopy( DCtlPtr dCtl, int CutOrCopy )
{
long total, contig;
/*
* If the selection start == the selection end, then there
* is no selection. Exit if this is the case.
*/
if( (*DA_te)->selEnd == (*DA_te)->selStart ) return;
HiliteEditMenu();
/*
* Zero the scrap, as we are about to replace it.
*/
if ( ZeroScrap() == noErr )
{
PurgeSpace(&total, &contig);
if ((*DA_te)->selEnd - (*DA_te)->selStart + kTESlop > contig)
alertUser(dCtl, eNoSpaceCut);
else
{
/*
* Cut or copy the text and export the TextEdit scrap to the
* system scrap.
*/
if( CutOrCopy )
{
setUndoCut( dCtl );
TECut(DA_te);
}
else
TECopy(DA_te);
if ( TEToScrap() != noErr )
{
alertUser(dCtl, eNoCut);
ZeroScrap();
}
}
}
adjustScrollbars(DA_window, false);
adjustTE(DA_window);
shortPause();
HiliteMenu(0);
}
/*----------------------------------------------------------------------
| Cut the selected region of text.
----------------------------------------------------------------------*/
void doCut( DCtlPtr dCtl )
{
doCutCopy(dCtl, 1);
}
/*----------------------------------------------------------------------
| Copy the selected region of text.
----------------------------------------------------------------------*/
void doCopy( DCtlPtr dCtl )
{
doCutCopy(dCtl, 0);
}
/*----------------------------------------------------------------------
| Check if the handle of a textedit record has enough
| room for the text about to be pasted into it.
----------------------------------------------------------------------*/
int roomToPaste( TEHandle te )
{
Handle aHandle;
long newSize,
oldSize;
int saveErr;
aHandle = (Handle) TEGetText( te );
oldSize = GetHandleSize(aHandle);
newSize = oldSize + TEGetScrapLen() + kTESlop;
SetHandleSize(aHandle, newSize);
saveErr = MemError();
SetHandleSize(aHandle, oldSize);
return(saveErr);
}
/*----------------------------------------------------------------------
| Paste the system scrap into the TextEdit window.
----------------------------------------------------------------------*/
void doPaste( DCtlPtr dCtl )
{
Handle aHandle;
char *scan;
long newSize,
oldSize;
int saveErr;
HiliteEditMenu();
/*
* If there is an established connection, paste goes to
* server instead of window.
*/
if( connectionState( dCtl ) >= 8 )
{
aHandle = NewHandle(1L);
MoveHHi(aHandle);
HLock(aHandle);
GetScrap(aHandle,'TEXT',&oldSize);
HLock(aHandle);
scan = *aHandle;
while( *scan )
*scan++ = ( *scan == '\n' ? '\r' : *scan );
SendTCP( dCtl, *aHandle );
DisposHandle(aHandle);
}
/*
* Import the system scrap to the TextEdit scrap.
*/
else if ( TEFromScrap() == noErr )
{
if ( TEGetScrapLen() + ((*DA_te)->teLength -
((*DA_te)->selEnd - (*DA_te)->selStart)) > kMaxTELength )
alertUser(dCtl, eExceedPaste);
else
{
setUndoPaste(dCtl);
TEFromScrap();
if( roomToPaste( DA_te ) != noErr )
alertUser(dCtl, eNoSpacePaste);
else
TEPaste(DA_te);
}
}
else
alertUser(dCtl, eNoPaste);
adjustScrollbars(DA_window, false);
adjustTE(DA_window);
shortPause();
HiliteMenu(0);
}
/*----------------------------------------------------------------------
| Clear the current selection.
----------------------------------------------------------------------*/
void doClear( DCtlPtr dCtl )
{
setUndoCut( dCtl );
HiliteEditMenu();
TECut(DA_te);
adjustScrollbars(DA_window, false);
adjustTE(DA_window);
shortPause();
HiliteMenu(0);
}
/*----------------------------------------------------------------------
| Set up a style for addTEstring
----------------------------------------------------------------------*/
void setStyle( ScrpSTElement *thisSty,long start,int face )
{
thisSty->scrpStartChar = start;
thisSty->scrpHeight = teLineHeight;
thisSty->scrpAscent = teAscent;
thisSty->scrpFont = monaco;
thisSty->scrpFace = face;
thisSty->scrpSize = teSize;
thisSty->scrpColor.red = 0;
thisSty->scrpColor.green = 0;
thisSty->scrpColor.blue = ( face == 0 ? 0 : 30000 );
}
/*----------------------------------------------------------------------
| Decide what style the current character should use based on what
| character preceeded the backspace.
|
| [underscore] [BS] [character] == underlined text
| [character] [BS] [character] == bold text
----------------------------------------------------------------------*/
Style decideStyle( char lastC, char nextC )
{
if( lastC == nextC )
return( bold );
if( (lastC == '_') || (nextC == '_') )
return( underline );
return(0);
}
/*----------------------------------------------------------------------
| Add a string to the END of the TextEdit window.
|
| This code scans through the input string looking for backspaces;
| if found, they are removed & the style of the preceeding character
| may be modified.
----------------------------------------------------------------------*/
void addTEstring( DCtlPtr dCtl, char *string )
{
StScrpHandle addStyle;
ScrpSTElement *thisSty;
CharsHandle textHandle;
Handle tmpHandle;
Style curSty = 0,
nextSty;
short *runPtr,
*startRec,
styleRuns = 0,
maxRuns = 10;
Size styLen,
tmpLen;
long len = 0,
teLen,
atChar;
char lastC,
*walk,
*follow;
int saveStart = (*DA_te)->selStart,
saveEnd = (*DA_te)->selEnd;
len = fix_cr(string);
while( (*string) && (*string == 8) )
{
--len;
++string;
textHandle = TEGetText( DA_te );
teLen = (*DA_te)->teLength;
if( teLen )
{
lastC = (char)( (*textHandle)[teLen-1] );
TEKey(8, DA_te);
curSty = decideStyle( lastC, *string );
if( *string == '_' )
*string = lastC;
}
}
if( !len ) return;
/*
* Set up style information
*/
styLen = (Size)sizeof(short) + maxRuns * (Size)sizeof(ScrpSTElement);
addStyle = (StScrpHandle)NewHandle( styLen );
if( !addStyle )
{
alertUser( dCtl, eNoMemory );
return;
}
runPtr = (short *)*addStyle;
startRec = runPtr + 1;
thisSty = (ScrpSTElement *)(startRec);
styleRuns = 1;
setStyle( thisSty,0L,curSty );
/*
* Walk through the string looking for backspaces
*/
follow = string;
walk = string + 1;
atChar = 0;
while( *walk )
{
lastC = *follow;
++atChar;
if( *walk == 8 )
{
++walk;
len -= 2;
--atChar;
if( !(*walk) )
{
--follow;
break;
}
nextSty = decideStyle( lastC, *walk );
if( atChar == 0 )
{
thisSty->scrpFace = nextSty;
curSty = nextSty;
}
if( *walk == '_' )
*walk = lastC;
}
else
{
++follow;
if( *(walk+1) != 8 )
nextSty = 0;
}
if( nextSty != curSty )
{
if( styleRuns >= maxRuns )
{
tmpLen = styLen;
tmpHandle = NewHandle( tmpLen );
BlockMove( (Ptr)*addStyle, (Ptr)*tmpHandle, tmpLen );
maxRuns += 10;
styLen = (Size)sizeof(short) + maxRuns * (Size)sizeof(ScrpSTElement);
ReallocHandle( (Handle)addStyle, styLen );
BlockMove( (Ptr)*tmpHandle, (Ptr)*addStyle, tmpLen );
DisposHandle( tmpHandle );
runPtr = (short *)*addStyle;
startRec = runPtr + 1;
thisSty = (ScrpSTElement *)(startRec) + (styleRuns-1);
}
++styleRuns;
thisSty += 1;
curSty = nextSty;
setStyle( thisSty,atChar,curSty );
}
*follow = *walk++;
}
*runPtr = styleRuns;
/*
*(++follow) = 0;
*/
if( (*DA_te)->teLength + len < kMaxTELength )
{
TEDeactivate(DA_te);
TESetSelect(kMaxTELength,kMaxTELength,DA_te);
TEStylInsert(string,len,addStyle,DA_te);
/* TEInsert(string,len,DA_te); */
TESetSelect(kMaxTELength,kMaxTELength,DA_te);
/* TESetSelect(saveStart,saveEnd,DA_te); */
TEActivate(DA_te);
adjustScrollbars(DA_window, false);
adjustTE(DA_window);
DisposHandle( (Handle)addStyle );
}
else
{
DisposHandle( (Handle)addStyle );
alertUser(dCtl, eExceedChar);
doAbort( dCtl );
}
}
/*----------------------------------------------------------------------
| Update the TERec's view rect so that it is the greatest multiple of
| the lineHeight that still fits in the old viewRect.
----------------------------------------------------------------------*/
void adjustViewRect(docTE)
TEHandle docTE;
{
TEPtr te;
te = *docTE;
te->viewRect.bottom = (((te->viewRect.bottom - te->viewRect.top) / teLineHeight)
* teLineHeight) + te->viewRect.top;
}
/*----------------------------------------------------------------------
| Scroll the TERec around to match up to the potentially updated
| scrollbar values. This is really useful when the window has been
| resized such that the scrollbars became inactive but the TERec was
| already scrolled.
----------------------------------------------------------------------*/
void adjustTE(window)
WindowPtr window;
{
TEPtr te;
te = *((DocumentPeek)window)->docTE;
TEScroll((te->viewRect.left - te->destRect.left) -
GetCtlValue(((DocumentPeek)window)->docHScroll),
(te->viewRect.top - te->destRect.top) -
(GetCtlValue(((DocumentPeek)window)->docVScroll) *
teLineHeight),
((DocumentPeek)window)->docTE);
}