Source to jet/events.c
#include <Desk.h>
#include <Events.h>
#include <Fonts.h>
#include <Menus.h>
#include <Resources.h>
#include <Scrap.h>
#include <SysEqu.h>
#include <ToolUtils.h>
#include <Windows.h>
#include <Controls.h>
#define HiliteFlag (*(Ptr)HiliteMode)
#include <AppleEvents.h>
#include <GestaltEqu.h>
#include <Traps.h>
#include "jet.h"
/* constants */
#define TRANS /* define this if you want a transfer menu */
/* #define LAYERS define this if you want layers style cmd-/ */
#define SBARWIDTH 16
#define abs(a) ((a) < 0 ? -(a) : (a))
#define topLeft(r) (((Point *) &(r))[0])
#define botRight(r) (((Point *) &(r))[1])
/* types */
typedef struct {
OSErr (*handler)(AppleEvent *theAppleEvent, AppleEvent *reply,
long handlerRefcon);
long handlerRefcon;
} AEDispatchRec;
/* functions */
static void trackCursor(void);
static void handledrag(Point pt);
static void handlegrow(Point pt);
static void handlekey(long message, short modifiers);
static void setupmenu(void);
static void updatemenu(void);
static void handlemenu(long mResult);
INLINE static void tscroll(int dist);
static void handlescroll(short part, Point pt);
static void handleselect(long when, Point where);
static void handleDoubleClick(Point where);
static void handleMouseDrag(Point where, Boolean extend);
static void copySelection(void);
static void invertSelection(Boolean);
static RgnHandle selectedRgn(Point start, Point cur, RgnHandle rgn);
static Boolean specialChar(char c);
static void rectToScreen(Rect *r);
static int ptToY(Point p);
static int ptToX(Point p);
static OSErr OAppHandler(AppleEvent *theAppleEvent, AppleEvent *reply,
long handlerRefcon);
static OSErr ODocHandler(AppleEvent *theAppleEvent, AppleEvent *reply,
long handlerRefcon);
static OSErr PDocHandler(AppleEvent *theAppleEvent, AppleEvent *reply,
long handlerRefcon);
static OSErr QuitHandler(AppleEvent *theAppleEvent, AppleEvent *reply,
long handlerRefcon);
/* variables */
WindowPtr myWindow;
Rect conRect;
short fascent, fheight, fwidth, ftotal;
short curVal, maxVal;
Rect selectedChars; /* selection in x,y coords */
static WindowRecord wRecord;
static ControlHandle myScrollbar;
static Handle clip;
static long cliplen, clipoff;
static Boolean wactive = true;
static Boolean quitFlag = false;
static int wneSupport;
static void (*nextmenu)(short theMenu, short theItem);
static int aeSupport;
AEDispatchRec aeDT[] = {
{ OAppHandler, 0 },
{ ODocHandler, 0 },
{ PDocHandler, 0 },
{ QuitHandler, 0 }
};
#ifndef XXX
#define NewAEEventHandlerProc(userRoutine) (ProcPtr)(userRoutine)
#endif
void init_events(void)
{
FontInfo fInfo;
long response;
OSErr s;
Boolean fail;
sysvar.eventloop = eventloop;
setupmenu();
myWindow = NewWindow(&wRecord, &pref.wrect, "\pConsole", false, 0,
(WindowPtr)-1L, 0, 0L);
SetPort(myWindow);
myScrollbar = NewControl(myWindow, &pref.wrect, "\pScrollbar",
false, 0, 0, 0, scrollBarProc, 0L);
TextFont(monaco);
TextSize(9);
TextMode(srcCopy);
GetFontInfo(&fInfo);
fascent = fInfo.ascent;
ftotal = fInfo.ascent + fInfo.descent + fInfo.leading;
fheight = ftotal + 1;
fwidth = fInfo.widMax;
curVal = maxVal = TOTROWS - maxy - 1;
SetRect(&conRect, 0, 0,
(maxx+1) * fwidth + (LEFT*2), (maxy+1) * fheight);
SizeWindow(myWindow,
conRect.right + SBARWIDTH, conRect.bottom, false);
ShowWindow(myWindow);
SizeControl(myScrollbar, SBARWIDTH,
myWindow->portRect.bottom - myWindow->portRect.top - 13);
MoveControl(myScrollbar,
myWindow->portRect.right-(SBARWIDTH-1),
myWindow->portRect.top - 1);
SetCtlMax(myScrollbar, maxVal);
SetCtlValue(myScrollbar, curVal);
ShowControl(myScrollbar);
clip = NewHandle(0L);
SetRect(&selectedChars, -1, -1, -1, -1);
updatemenu();
/* At this point it should be safe to use the console */
c_conws("\033Yz "); /* jump to bottom of console */
wneSupport = TrapAvailable(_WaitNextEvent);
Gestalt(gestaltAppleEventsAttr, &response);
aeSupport = response & (1 << gestaltAppleEventsPresent);
if (aeSupport) {
fail = false;
s = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
NewAEEventHandlerProc(pAEHandler), 0, false);
fail |= s != noErr;
s = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
NewAEEventHandlerProc(pAEHandler), 1, false);
fail |= s != noErr;
s = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
NewAEEventHandlerProc(pAEHandler), 2, false);
fail |= s != noErr;
s = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
NewAEEventHandlerProc(pAEHandler), 3, false);
fail |= s != noErr;
if (fail) {
c_conws("Error installing AppleEvent handlers\r\n");
p_term0();
}
}
eventloop();
}
void eventloop(void)
{
EventRecord myEvent;
Boolean gotEvent;
short code;
GrafPtr whichWindow;
ControlHandle whichControl;
Rect r;
int i, n;
SetPort(myWindow);
while (1) {
if (wneSupport)
gotEvent = WaitNextEvent(everyEvent, &myEvent, 0, 0L);
else {
gotEvent = GetNextEvent(everyEvent, &myEvent);
SystemTask();
}
if (!gotEvent) {
if (cliplen) {
HLock(clip);
n = cliplen > 8 ? 8 : cliplen;
for (i = 0; i < n; i++) {
keymsg = (*clip)[clipoff++];
keymod = 0;
(*(void (*)(void))kbd.ikbdsys)();
}
HUnlock(clip);
cliplen -= n;
if (cliplen == 0)
SetHandleSize(clip, 0L);
}
if (wactive && EmptyRgn(((WindowPeek)myWindow)->updateRgn))
swap_curs();
trackCursor();
return;
}
switch(myEvent.what) {
case mouseDown:
code = FindWindow(myEvent.where, &whichWindow);
switch (code) {
case inMenuBar:
updatemenu();
handlemenu(MenuSelect(myEvent.where));
break;
case inSysWindow:
SystemClick(&myEvent, whichWindow);
break;
case inDrag:
handledrag(myEvent.where);
break;
case inGrow:
handlegrow(myEvent.where);
break;
case inContent:
if (whichWindow != FrontWindow())
SelectWindow(whichWindow);
else {
GlobalToLocal(&myEvent.where);
code = FindControl(myEvent.where,
whichWindow,
&whichControl);
if (whichControl == myScrollbar)
handlescroll(code,
myEvent.where);
else
handleselect(myEvent.when,
myEvent.where);
}
break;
}
break;
case activateEvt:
if(myEvent.message == (long)myWindow) {
SetPort(myWindow);
wactive = (myEvent.modifiers & activeFlag) != 0;
invertSelection(false);
HiliteControl(myScrollbar, wactive ? 0 : 255);
if (!wactive) {
curs_off();
curs_disable();
} else {
curs_enable();
}
SetRectRgn(myWindow->clipRgn,
conRect.right + 1,
conRect.bottom - 14,
conRect.right + SBARWIDTH,
conRect.bottom);
DrawGrowIcon(myWindow);
RectRgn(myWindow->clipRgn,
&myWindow->portRect);
}
break;
case updateEvt:
if(myEvent.message == (long)myWindow) {
SetPort(myWindow);
BeginUpdate(myWindow);
if (wactive)
invertSelection(true);
refresh();
if (wactive)
invertSelection(false);
r.top = conRect.top;
r.bottom = conRect.bottom;
r.left = conRect.right + 1;
r.right = r.left + SBARWIDTH;
if (RectInRgn(&r, myWindow->visRgn)) {
RectRgn(myWindow->clipRgn,
&r);
DrawGrowIcon(myWindow);
DrawControls(myWindow);
RectRgn(myWindow->clipRgn,
&myWindow->portRect);
}
EndUpdate(myWindow);
swap_curs();
}
break;
case keyDown:
case autoKey:
handlekey(myEvent.message, myEvent.modifiers);
break;
case kHighLevelEvent:
if (aeSupport)
AEProcessAppleEvent(&myEvent);
if (quitFlag)
ExitToShell();
break;
}
}
return;
}
/* Cursor Stuff */
static void trackCursor(void)
{
GrafPtr savePort;
Point pt;
static Cursor *cursor, *oldcursor = 0, ibeam;
CursHandle ch;
if (!(FrontWindow() == myWindow))
return;
if (!oldcursor) { /* if first time */
if ((ch = GetCursor(iBeamCursor))) {
HLock((Handle)ch);
ibeam = **ch;
ReleaseResource((Handle)ch);
} else
ibeam = qd.arrow;
}
GetPort(&savePort);
SetPort(myWindow);
GetMouse(&pt); /* local coords */
if (PtInRect(pt, &conRect))
cursor = &ibeam;
else
cursor = &qd.arrow;
#ifdef notdef
if (cursor != oldcursor)
#endif
SetCursor(cursor);
oldcursor = cursor;
SetPort(savePort);
}
/* Drag Stuff */
static void handledrag(Point pt)
{
Rect dragRect;
SetRect(&dragRect, 4, 24,
qd.screenBits.bounds.right-4, qd.screenBits.bounds.bottom-4);
DragWindow(myWindow, pt, &dragRect);
writeprefs();
}
/* Grow Stuff */
static void handlegrow(Point pt)
{
long wsize;
Rect r;
short v, h, rows, columns;
SetRect(&r, LEFT*2+fwidth*20+SBARWIDTH, 10*fheight,
qd.screenBits.bounds.right, qd.screenBits.bounds.bottom);
if ((wsize = GrowWindow(myWindow, pt, &r)) == 0)
return;
v = ((short *)&wsize)[0];
h = ((short *)&wsize)[1];
h -= LEFT*2+SBARWIDTH;
rows = v / fheight;
columns = h / fwidth;
if (columns > TOTCOLS)
columns = TOTCOLS;
resize(rows, columns);
offsetSelection(curVal - (TOTROWS - maxy - 1));
curVal = maxVal = TOTROWS - maxy - 1;
SetRect(&conRect, 0, 0,
(maxx+1) * fwidth + (LEFT*2), (maxy+1) * fheight);
SizeWindow(myWindow,
conRect.right + SBARWIDTH, conRect.bottom, false);
SizeControl(myScrollbar,
SBARWIDTH,
myWindow->portRect.bottom - myWindow->portRect.top - 13);
MoveControl(myScrollbar,
myWindow->portRect.right-(SBARWIDTH-1),
myWindow->portRect.top - 1);
SetCtlMax(myScrollbar, maxVal);
SetCtlValue(myScrollbar, curVal);
RectRgn(myWindow->clipRgn, &myWindow->portRect);
EraseRect(&myWindow->portRect);
InvalRect(&myWindow->portRect);
writeprefs();
}
/* Keyboard Stuff */
static void handlekey(long message, short modifiers)
{
long scrollVal;
if (modifiers & cmdKey) {
handlemenu(MenuKey(message & charCodeMask));
} else {
switch ((unsigned short)message >> 8) {
case 0x74: /* page up */
scrollVal = -maxy;
goto scroll;
case 0x79: /* page down */
scrollVal = maxy;
goto scroll;
case 0x73: /* home */
scrollVal = -curVal;
goto scroll;
case 0x77: /* end */
scrollVal = maxVal - curVal;
scroll:
curs_off();
tscroll(scrollVal);
break;
default:
keymsg = message;
keymod = modifiers;
(*(void (*)(void))kbd.ikbdsys)();
break;
}
}
}
/* Menu Stuff */
#ifdef DEBUG
/* This is used to add a debugging menu. It is also an example of
* how to add menus to the default menus. This can also be done
* from a MiNT process.
*/
static void loadfile(void)
{
Point where;
SFTypeList typeList;
SFReply reply;
char buf[1024], *p;
short f;
long count;
where.h = 40;
where.v = 60;
typeList[0] = TEXT;
SFGetFile(where, "\p", 0L, 1, typeList, 0L, &reply);
if (!reply.good)
return;
if (FSOpen(reply.fName, reply.vRefNum, &f) != 0)
return;
while (1) {
count = 1024;
FSRead(f, &count, (Ptr)buf);
if (count == 0)
break;
for (p = buf; count; count--)
b_conout(2, *p++);
}
FSClose(f);
}
static short debugMenu;
static void (*debugnextmenu)(short theMenu, short theItem);
static void debugmenu(short theMenu, short theItem)
{
if (theMenu == debugMenu) {
switch (theItem) {
case 1:
c_conws("\033H"); /* Home */
break;
case 2:
c_conws("\033E"); /* Clear Home */
break;
case 3:
c_conws("\033J"); /* Clear End of Screen */
break;
case 4:
c_conws("\033M"); /* Delete Line */
break;
case 5:
c_conws("\033L"); /* Insert Line */
break;
case 6:
c_conws("\033p"); /* Inverse On */
break;
case 7:
c_conws("\033q"); /* Inverse Off */
break;
case 8:
loadfile();
break;
}
} else {
if (debugnextmenu)
(*debugnextmenu)(theMenu, theItem);
}
}
static void setupdebugmenu(void)
{
MenuHandle debugM;
debugMenu = 255;
while (GetMHandle(debugMenu) != 0)
debugMenu++;
debugM = NewMenu(debugMenu, "\pDebug");
AppendMenu(debugM, "\pHome");
AppendMenu(debugM, "\pClear Home");
AppendMenu(debugM, "\pClear End of Screen");
AppendMenu(debugM, "\pDelete Line");
AppendMenu(debugM, "\pInsert Line");
AppendMenu(debugM, "\pInverse On");
AppendMenu(debugM, "\pInverse Off");
AppendMenu(debugM, "\pLoad FileÉ");
InsertMenu(debugM, 0);
debugnextmenu = nextmenu;
nextmenu = debugmenu;
}
#endif
#ifdef TRANS
#define TRANS_ALPHA 1
#define TRANS_BBEDIT 2
static short transMenu;
static void (*transnextmenu)(short theMenu, short theItem);
static void switchTo(long sig)
{
ProcessSerialNumber process;
ProcessInfoRec infoRec;
FSSpec spec;
Str255 name;
process.highLongOfPSN = 0;
process.lowLongOfPSN = kNoProcess;
infoRec.processInfoLength = sizeof(ProcessInfoRec);
infoRec.processName = name;
infoRec.processAppSpec = &spec;
while (GetNextProcess(&process) == noErr) {
if (GetProcessInformation(&process, &infoRec) == noErr) {
if ((infoRec.processType == APPL) &&
(infoRec.processSignature == sig)) {
SetFrontProcess(&process);
return;
}
}
}
SysBeep(5);
}
static void transmenu(short theMenu, short theItem)
{
if (theMenu == transMenu) {
switch (theItem) {
case TRANS_ALPHA:
switchTo(ALPHA);
break;
case TRANS_BBEDIT:
switchTo(BBEDIT);
break;
}
} else {
if (transnextmenu)
(*transnextmenu)(theMenu, theItem);
}
}
static void setuptransmenu(void)
{
long response;
MenuHandle transM;
Gestalt(gestaltSystemVersion, &response);
if (response & 0xff00 < 0x700)
return;
transMenu = 255;
while (GetMHandle(transMenu) != 0)
transMenu++;
transM = NewMenu(transMenu, "\pTransfer");
AppendMenu(transM, "\p/`Alpha");
AppendMenu(transM, "\pBBEdit");
InsertMenu(transM, 0);
transnextmenu = nextmenu;
nextmenu = transmenu;
}
#endif
#define appleMenu 255
#define APPLE_ABOUT 1
#define fileMenu 256
#define FILE_QUIT 1
#define editMenu 257
#define EDIT_UNDO 1
#define EDIT_CUT 3
#define EDIT_COPY 4
#define EDIT_PASTE 5
#define EDIT_COPY_PASTE 6
#define optionsMenu 258
#define OPTIONS_SWAPDEL 1
#define OPTIONS_SWAPCNTL 2
#define OPTIONS_CFLASH 3
#define OPTIONS_WRAP 4
#define DRVR 0x44525652
MenuHandle appleM;
MenuHandle fileM;
MenuHandle editM;
MenuHandle optionsM;
static void setupmenu(void)
{
nextmenu = 0;
appleM = NewMenu(appleMenu, "\p\024");
AppendMenu(appleM, "\pHelp\311");
AppendMenu(appleM, "\p(-");
AddResMenu(appleM, DRVR);
InsertMenu(appleM, 0);
fileM = NewMenu(fileMenu, "\pFile");
AppendMenu(fileM, "\p(/QQuit\311");
InsertMenu(fileM, 0);
editM = NewMenu(editMenu, "\pEdit");
AppendMenu(editM, "\pUndo");
AppendMenu(editM, "\p(-");
AppendMenu(editM, "\p(/XCut");
AppendMenu(editM, "\p(/CCopy");
AppendMenu(editM, "\p(/VPaste");
#ifdef LAYERS
AppendMenu(editM, "\p(//Copy-Paste");
#endif
InsertMenu(editM, 0);
optionsM = NewMenu(optionsMenu, "\pOptions");
AppendMenu(optionsM, "\pSwap Delete Key");
AppendMenu(optionsM, "\pSwap Control Modifier");
AppendMenu(optionsM, "\pFlash Cursor");
AppendMenu(optionsM, "\pAuto Wrap");
InsertMenu(optionsM, 0);
#ifdef DEBUG
setupdebugmenu();
#endif
#ifdef TRANS
setuptransmenu();
#endif
DrawMenuBar();
}
static void updatemenu(void)
{
EnableItem(fileM, FILE_QUIT);
EnableItem(editM, EDIT_PASTE);
if (!emptySelection())
EnableItem(editM, EDIT_COPY);
else
DisableItem(editM, EDIT_COPY);
#ifdef LAYERS
if (!emptySelection())
EnableItem(editM, EDIT_COPY_PASTE);
else
DisableItem(editM, EDIT_COPY_PASTE);
#endif
CheckItem(optionsM, OPTIONS_SWAPDEL, pref.swap_delete);
CheckItem(optionsM, OPTIONS_SWAPCNTL, pref.swap_control);
CheckItem(optionsM, OPTIONS_CFLASH, pref.curs_flash);
CheckItem(optionsM, OPTIONS_WRAP, pref.fwrap);
}
static void handlemenu(long mResult)
{
short theItem, theMenu;
Str255 name;
long offset;
theMenu = ((short *)&mResult)[0];
theItem = ((short *)&mResult)[1];
switch(theMenu) {
case appleMenu:
if (theItem == APPLE_ABOUT) {
c_conws("\r\nSorry. Try the man pages, the faq, etc.\r\n");
} else {
GetItem(appleM, theItem, name);
OpenDeskAcc(name);
}
break;
case fileMenu:
if (theItem == FILE_QUIT) {
c_conws("\r\nAre you sure you want to quit? ");
if ((b_conin(2) & 0xff) == 'y')
ExitToShell();
c_conws("\r\n");
}
break;
case editMenu:
if (!SystemEdit(theItem - 1)) {
switch (theItem) {
case EDIT_PASTE:
cliplen = GetScrap(clip, TEXT, &offset);
clipoff = 0;
break;
case EDIT_COPY:
copySelection();
break;
#ifdef LAYERS
case EDIT_COPY_PASTE:
copySelection();
cliplen = GetScrap(clip, TEXT, &offset);
clipoff = 0;
break;
#endif
}
}
break;
case optionsMenu:
switch (theItem) {
case OPTIONS_SWAPDEL:
pref.swap_delete = !pref.swap_delete;
break;
case OPTIONS_SWAPCNTL:
pref.swap_control = !pref.swap_control;
break;
case OPTIONS_CFLASH:
pref.curs_flash = !pref.curs_flash;
break;
case OPTIONS_WRAP:
pref.fwrap = !pref.fwrap;
break;
}
writeprefs();
break;
default:
if (nextmenu)
(*nextmenu)(theMenu, theItem);
break;
}
HiliteMenu(0);
}
/* Scroll Stuff */
INLINE static void tscroll(int dist)
{
int delta; /* amount to adjust scroll region */
if (!dist)
return;
delta = curVal;
curVal += dist;
if (curVal < 0)
curVal = 0;
else
if (curVal > maxVal)
curVal = maxVal;
SetCtlValue(myScrollbar, curVal);
InvalRect(&conRect);
offsetSelection(delta - curVal);
refresh();
}
void ScrollText(ControlHandle cntl, short part)
{
switch (part) {
case inUpButton:
tscroll(-1);
break;
case inDownButton:
tscroll(1);
break;
case inPageUp:
tscroll(-maxy);
break;
case inPageDown:
tscroll(maxy);
break;
}
}
#ifndef XXX
typedef ProcPtr ControlActionUPP;
#define NewControlActionProc(userRoutine) (ProcPtr)(userRoutine)
#endif
static ControlActionUPP theScrollTextUPP = NULL;
static void handlescroll(short part, Point pt)
{
int delta; /* amount to adjust selection */
curs_off();
delta = curVal;
if (part == inThumb) {
part = TrackControl(myScrollbar, pt, 0L);
curVal = GetCtlValue(myScrollbar);
InvalRect(&conRect);
offsetSelection(delta - curVal);
refresh();
} else {
if (theScrollTextUPP == NULL)
theScrollTextUPP = NewControlActionProc(pScrollText);
part = TrackControl(myScrollbar, pt, theScrollTextUPP);
}
}
void scrollBottom(void)
{
if (curVal != maxVal) {
offsetSelection(curVal - maxVal);
curVal = maxVal;
SetCtlValue(myScrollbar, curVal);
InvalRect(&conRect);
refresh();
}
}
/* Selection Stuff */
static void handleselect(long when, Point where)
{
static long lastWhen = 0;
static Point lastWhere = {0, 0};
if (((when - lastWhen) < GetDblTime()) &&
(abs(where.h - lastWhere.h) < 5) &&
(abs(where.v - lastWhere.v) < 5)) {
handleDoubleClick(where);
if (StillDown())
handleMouseDrag(where, true);
} else
handleMouseDrag(where, false);
lastWhen = when;
lastWhere = where;
}
static void handleMouseDrag(Point where, Boolean extend)
{
Point start, pt; /* local coords */
GrafPtr savePort;
RgnHandle newRgn = 0, oldRgn = 0, diffRgn = 0, tmpRgn;
Rect boundary;
newRgn = NewRgn();
oldRgn = NewRgn();
diffRgn = NewRgn();
if (!newRgn || !oldRgn || !diffRgn)
goto xit;
GetPort(&savePort);
SetPort(myWindow);
if (!extend) {
clearSelection();
start = where; /* get initial point (already local) */
SetRect(&boundary, 0, 0, 0, 0);
} else {
boundary = selectedChars;
rectToScreen(&boundary);
InsetRect(&boundary, 1, 1);
start = topLeft(boundary);
pt = botRight(boundary);
oldRgn = selectedRgn(start, pt, oldRgn);
}
while (StillDown()) {
GetMouse(&pt);
/*
* If extending and we are within the original rectangle,
* always set the selection to the original rectangle.
*/
if (extend && PtInRect(pt, &boundary)) {
start = topLeft(boundary);
pt = botRight(boundary);
}
/*
* If extend, we have to dynamically pick start appropriately,
* depending on if we are moving to the left or right of the
* initial starting rectangle.
*/
if (extend) {
int x1, y1, x2, y2;
x1 = ptToX(start);
y1 = ptToY(start);
x2 = ptToX(pt);
y2 = ptToY(pt);
if ((y1 > y2) ||
((y1 == y2) && (x1 > x2))) /* if reverse direction */
start = botRight(boundary);
else
start = topLeft(boundary);
}
newRgn = selectedRgn(start, pt, newRgn);
XorRgn(newRgn, oldRgn, diffRgn);
if (!EmptyRgn(diffRgn)) {
HiliteFlag &= ~(1 << hiliteBit);
InvertRgn(diffRgn);
}
tmpRgn = oldRgn; /* swap regions */
oldRgn = newRgn;
newRgn = tmpRgn;
}
xit:
if (newRgn)
DisposeRgn(newRgn);
if (oldRgn)
DisposeRgn(oldRgn);
if (diffRgn)
DisposeRgn(diffRgn);
SetPort(savePort);
updatemenu();
}
/*
* Erase or Invert the selection region
*/
static void invertSelection (Boolean erase)
{
Rect r;
RgnHandle rgn;
GrafPtr savePort;
if (emptySelection())
return;
if (!(rgn = NewRgn()))
return;
GetPort(&savePort);
SetPort(myWindow);
r = selectedChars;
rectToScreen(&r);
r.bottom -= 1; /* account for line height fudge */
rgn = selectedRgn(topLeft(r), botRight(r), rgn);
if (erase)
EraseRgn(rgn);
else {
HiliteFlag &= ~(1 << hiliteBit);
InvertRgn(rgn);
}
DisposeRgn(rgn);
SetPort(savePort);
}
Boolean emptySelection(void)
{
if ((selectedChars.top == -1) && (selectedChars.bottom == -1) &&
(selectedChars.left == -1) && (selectedChars.right == -1))
return true;
return false;
}
void clearSelection(void)
{
invertSelection(false);
SetRect(&selectedChars, -1, -1, -1, -1);
updatemenu();
}
static RgnHandle selectedRgn (Point start, Point cur, RgnHandle rgn)
{
int y, x1, y1, x2, y2, t, curx, startx;
Rect r;
RgnHandle tmp;
SetEmptyRgn(rgn);
if ((abs(start.h-cur.h) < 2) && (abs(start.v-cur.v) < 2)) /* if move too small */
return rgn;
x1 = ptToX(start);
y1 = ptToY(start);
x2 = ptToX(cur);
y2 = ptToY(cur);
curx = cur.h;
startx = start.h;
/* check for out of bounds */
if ((y1 == y2) &&
(((cur.h < LEFT) && (start.h < LEFT)) ||
((cur.h > (maxx*fwidth + LEFT)) && (start.h > (maxx*fwidth + LEFT)))))
return rgn;
if ((y1 > y2) ||
((y1 == y2) && (x1 > x2))) { /* if reverse direction */
t = x1; /* flip start, end */
x1 = x2;
x2 = t;
t = y1;
y1 = y2;
y2 = t;
curx = start.h;
startx = cur.h;
}
/*
* Handle cases where we drag past left or right margins.
*/
if ((curx < (LEFT + fwidth/2)) && (y2 > y1)) {
y2--;
x2 = maxx;
}
if ((startx > (maxx*fwidth + LEFT)) && (y1 < y2)) {
y1++;
x1 = 0;
}
if (!(tmp = NewRgn()))
return rgn;
SetRect(&selectedChars, x1, y1, x2, y2); /* save current selection */
if (y1 == y2) { /* if one line */
SetRect(&r, x1, y1, x2, y2);
rectToScreen(&r);
RectRgn(rgn, &r);
} else {
SetRect(&r, x1, y1, maxx, y1); /* first line */
rectToScreen(&r);
RectRgn(tmp, &r);
UnionRgn(rgn, tmp, rgn);
for (y = y1+1; y < y2; y++) { /* full lines inbetween */
SetRect(&r, 0, y, maxx, y);
rectToScreen(&r);
RectRgn(tmp, &r);
UnionRgn(rgn, tmp, rgn);
}
SetRect(&r, 0, y2, x2, y2); /* last line */
rectToScreen(&r);
RectRgn(tmp, &r);
UnionRgn(rgn, tmp, rgn);
}
DisposeRgn(tmp);
return rgn;
}
static void copySelection(void)
{
long l, n, y;
char *src, *dst, *buf, *buflim;
/*
* Calc max buffer which is the number of lines times the
* max line size, and allocate it.
*/
l = selectedChars.bottom - selectedChars.top + 1;
l *= (long)(TOTCOLS + 1);
if (!(buf = (char *)NewPtr(l)))
return;
dst = buf;
buflim = &buf[l];
for (y = selectedChars.top; y <= selectedChars.bottom; y++) {
src = base[y+curVal];
if (y == selectedChars.top) /* if first line */
src += selectedChars.left;
if (selectedChars.top == selectedChars.bottom) /* if one line */
n = selectedChars.right - selectedChars.left + 1; /* sel length */
else if (y == selectedChars.top) /* if first line */
n = maxx + 1 - selectedChars.left; /* first to eol */
else if (y == selectedChars.bottom) /* if last line */
n = selectedChars.right + 1; /* bol to last */
else
n = maxx + 1;
while (n--) {
if (dst >= buflim)
break;
*dst++ = *src++;
}
/* trim trailing blanks */
while ((dst != buf) && (dst[-1] == ' '))
dst--;
/*
* Add eol if not last line. If last line, add eol if the whole line is
* selected. This seems a little hokey, but there is no other way to
* tell if we selected the whole line or just part of it.
*/
if ((dst < buflim) &&
((y != selectedChars.bottom) || /* if not last line */
(selectedChars.right == maxx))) /* last line selected to right margin */
*dst++ = 0x0d;
}
ZeroScrap();
PutScrap(dst-buf, 0x54455854, (Ptr)buf); /* TEXT */
DisposePtr(buf);
clearSelection();
}
static void handleDoubleClick(Point where)
{
int x1, x2, y;
char *left, *right;
Rect r;
RgnHandle rgn;
GrafPtr savePort;
GetPort(&savePort);
SetPort(myWindow);
x1 = x2 = ptToX(where); /* get mouse down point */
y = ptToY(where);
left = right = (char *)base[y+curVal] + x1;
/*
* Expand selection to boundaries.
* If double click on a special char, just select that char.
*/
if (!specialChar(*left)) {
while ((x1 > 0) && !specialChar(left[-1])) {
x1--;
left--;
}
while ((x2 < maxx) && !specialChar(right[1])) {
x2++;
right++;
}
}
SetRect(&selectedChars, x1, y, x2, y);
r = selectedChars;
rectToScreen(&r);
r.bottom -= 1; /* account for line height fudge */
rgn = NewRgn();
rgn = selectedRgn(topLeft(r), botRight(r), rgn);
HiliteFlag &= ~(1 << hiliteBit);
InvertRgn(rgn);
DisposeRgn(rgn);
SetPort(savePort);
updatemenu();
}
void offsetSelection(int delta)
{
if (delta && !emptySelection()) {
invertSelection(true);
selectedChars.top += delta;
selectedChars.bottom += delta;
}
}
/* Utility Stuff */
static Boolean specialChar(char c)
{
if ((c >= 'A') && (c <= 'Z'))
return false;
if ((c >= 'a') && (c <= 'z'))
return false;
if ((c >= '0') && (c <= '9'))
return false;
return true;
}
/*
* Convert a rect in x,y coords to screen coords (local)
*/
static void rectToScreen (Rect *r)
{
r->left = r->left * fwidth + LEFT;
r->right = r->right * fwidth + LEFT + (fwidth - 1); /* flush right char */
r->top *= fheight;
r->bottom *= fheight;
r->bottom += fheight;
}
/*
* Convert a point to x (chars)
*/
static int ptToX (Point p)
{
int x;
x = p.h - LEFT;
if (x < 0)
x = 0;
x /= fwidth;
if (x > maxx)
x = maxx;
return x;
}
/*
* Convert a point to y (chars)
*/
static int ptToY (Point p)
{
int y;
y = p.v;
if (y >= 0)
y /= fheight;
else
y = (y - fheight + 1) / fheight;
return y;
}
/* AppleEvent Stuff */
OSErr AEHandler(AppleEvent *theAppleEvent, AppleEvent *reply,
long handlerRefcon)
{
OSErr result;
result = (*aeDT[handlerRefcon].handler)
(theAppleEvent, reply, aeDT[handlerRefcon].handlerRefcon);
return result;
}
static OSErr OAppHandler(AppleEvent *theAppleEvent, AppleEvent *reply,
long handlerRefcon)
{
return noErr;
}
static OSErr ODocHandler(AppleEvent *theAppleEvent, AppleEvent *reply,
long handlerRefcon)
{
return errAEEventNotHandled;
}
static OSErr PDocHandler(AppleEvent *theAppleEvent, AppleEvent *reply,
long handlerRefcon)
{
return errAEEventNotHandled;
}
static OSErr QuitHandler(AppleEvent *theAppleEvent, AppleEvent *reply,
long handlerRefcon)
{
quitFlag = true;
return noErr;
}