/* 
Copyright (c) 1991-2000 UserLand Software, Inc. 

Permission is hereby granted, free of charge, to any person obtaining a 
copy of this software and associated documentation files (the 
"Software"), to deal in the Software without restriction, including 
without limitation the rights to use, copy, modify, merge, publish, 
distribute, sublicense, and/or sell copies of the Software, and to 
permit persons to whom the Software is furnished to do so, subject to the 
following conditions: 

The above copyright notice and this permission notice shall be 
included in all copies or substantial portions of the Software. 

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
*/ 


#include "appletdefs.h"
#include "appletmemory.h"
#include "appletfont.h"
#include "appletstrings.h"
#include "appletquickdraw.h"
#include "applettextedit.h"



typedef struct tyscrolldata {
	
	Rect origdestrect;
	
	short origlen;
	} tyscrolldata;
	
tyscrolldata scrolldata;




static boolean getmacbuffer (hdleditrecord hbuffer, TEHandle *macbuffer) {

	if (hbuffer == nil)
		return (false);
		
	*macbuffer = (**hbuffer).macbuffer;
	
	return (*macbuffer != nil);
	} /*getmacbuffer*/
	

static void editprescroll (hdleditrecord hbuffer) {

	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return;

	scrolldata.origdestrect = (**macbuffer).destRect;
	
	scrolldata.origlen = (**macbuffer).teLength;
	} /*editprescroll*/
	
	
static void editsetscrollvalues (hdleditrecord hbuffer) {

	TEHandle macbuffer;
	Rect destrect, viewrect;
	boolean flscrolled;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
	
	flscrolled = scrolldata.origlen != (**macbuffer).teLength;
	
	if (!flscrolled)
		flscrolled = !equalrects (scrolldata.origdestrect, (**macbuffer).destRect);
	
	if (!(**hbuffer).flscrolled) /*DW 12/4/94*/
		(**hbuffer).flscrolled = flscrolled;
	
	destrect = (**macbuffer).destRect;
	
	viewrect = (**macbuffer).viewRect;
	
	(**hbuffer).vertcurrent = viewrect.top - destrect.top;
	
	(**hbuffer).horizcurrent = viewrect.left - destrect.left;
	} /*editsetscrollvalues*/
	
	
static short getTEjustification (tyjustification justification) {
	
	switch (justification) {
		
		case leftjustified:
			return (teJustLeft);
			
		case centerjustified:
			return (teJustCenter);
			
		case rightjustified:
			return (teJustRight);
		} /*switch*/

	return (teJustLeft);
	} /*getTEjustification*/
	

boolean editnewbuffer (Rect r, boolean flwordwrap, bigstring bs, hdleditrecord *hrecord) {
	
	hdleditrecord h;
	TEHandle macbuffer;
	
	if (!newclearhandle (longsizeof (tyeditrecord), (Handle *) hrecord))
		return (false);
		
	h = *hrecord; /*copy into register*/
	
	InsetRect (&r, texthorizinset, textvertinset);
		
	macbuffer = TENew (&r, &r);
	
	if (macbuffer == nil) { /*memory error*/
		
		disposehandle ((Handle) h);
		
		*hrecord = nil;
		
		return (false);
		}
		
	if (flwordwrap)
		(**macbuffer).crOnly = 1;
	else
		(**macbuffer).crOnly = -1;

	TESetText (&bs [1], (long) stringlength (bs), macbuffer);
	
	TEActivate (macbuffer);
	
	(**h).macbuffer = macbuffer;
	
	return (true);
	} /*editnewbuffer*/
	
	
static boolean rectneedsupdate (Rect r) {
	
	WindowPtr w = (WindowPtr) quickdrawglobal (thePort);
	
	return (RectInRgn (&r, (*w).visRgn));
	} /*rectneedsupdate*/
	
	
void editupdate (hdleditrecord hbuffer) {
	
	TEHandle macbuffer;
	Rect r, rerase;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
		
	r = (**macbuffer).viewRect;
	
	if ((**macbuffer).teLength == 0)
		EraseRect (&r);
	
	TEUpdate (&r, macbuffer);
	
	InsetRect (&r, -(texthorizinset - 1), -(textvertinset - 1));
	
	/*erase the top sliver*/ {
	
		rerase = r; 
	
		rerase.bottom = rerase.top + textvertinset;
	
		if (rectneedsupdate (rerase)) 
			eraserect (rerase);
		}
	
	/*erase the bottom sliver*/ {
	
		rerase = r; 
	
		rerase.top = rerase.bottom - textvertinset;
	
		if (rectneedsupdate (rerase)) 
			eraserect (rerase);
		}
	
	/*erase the left sliver*/ {
	
		rerase = r; 
	
		rerase.right = rerase.left + texthorizinset;
		
		if (rectneedsupdate (rerase)) 
			eraserect (rerase);
		}
	
	/*erase the right sliver*/ {
	
		rerase = r; 
	
		rerase.left = rerase.right - texthorizinset;
		
		#if false /*DW 2/15/95 live with the schmutz for now -- it's breaking other things*/
		
			/*DW 1/28/95 hack for LSE -- noticed schmutz on the right edge when you resize to make the window narrower*/
			
			/*DW 1/6/96 -- LSE is no longer supported, no app record in MacBird Runtime
			
			if (app.creator == 'CAML')
				rerase.right++; 
			*/
		#endif
	
		if (rectneedsupdate (rerase)) 
			eraserect (rerase);
		}
	} /*editupdate*/
	
	
void editupdateport (hdleditrecord hbuffer, Rect rport, WindowPtr w) {
	
	/*
	8/26/92 DW: update the TE handle, but do it in a port different from the
	one it lives inside of. need this to support printing in MinApp.
	
	9/3/92 DW: add "rport" parameter, to allow the caller to determine the
	temporary viewRect for the TE buffer.
	*/
	
	TEHandle macbuffer;
	Rect oldview, olddest;
	WindowPtr oldport;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
		
	oldview = (**macbuffer).viewRect; 
	
	olddest = (**macbuffer).destRect; 
	
	oldport = (**macbuffer).inPort;
	
	(**macbuffer).viewRect = rport;
	
	(**macbuffer).destRect = rport;
	
	(**macbuffer).inPort = w;
	
	TEUpdate (&rport, macbuffer);
	
	(**macbuffer).viewRect = oldview;
	
	(**macbuffer).destRect = olddest;
	
	(**macbuffer).inPort = oldport;
	} /*editupdateport*/
	
	
void editactivate (hdleditrecord hbuffer, boolean flactive) {
	
	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
		
	if (flactive)
		TEActivate (macbuffer);
	else
		TEDeactivate (macbuffer);
	} /*editactivate*/
	
	
void editsetrect (hdleditrecord hbuffer, Rect r) {

	TEHandle macbuffer;

	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
		
	InsetRect (&r, texthorizinset, textvertinset);
			
	(**macbuffer).viewRect = r;
	
	/*if (!(**hbuffer).flwindowbased) -- commented DW 1/16/95 -- for Little Script Editor*/
		(**macbuffer).destRect = r;
	
	TECalText (macbuffer);
	
	/*editupdate (hbuffer);*/
	} /*editsetrect*/
	
	
void editsetfont (hdleditrecord hbuffer, short fontnum, short fontsize) {

	TEHandle macbuffer;

	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
		
	editprescroll (hbuffer);
	
	(**macbuffer).txFont = fontnum;
	
	(**macbuffer).txSize = fontsize;
	
	pushstyle (fontnum, fontsize, (**macbuffer).txFace);
	
	(**macbuffer).fontAscent = globalfontinfo.ascent;
	
	(**macbuffer).lineHeight = globalfontinfo.ascent + globalfontinfo.descent + globalfontinfo.leading;
	
	popstyle ();
		
	TECalText (macbuffer);
	
	editsetscrollvalues (hbuffer);
	
	(**hbuffer).flscrolled = true;
	} /*editsetfont*/
	
	
void editautoscroll (hdleditrecord hbuffer) {

	TEHandle macbuffer;

	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
		
	TEAutoView (true, macbuffer);
	} /*editautoscroll*/
	
	
void editsetwordwrap (hdleditrecord hbuffer, boolean fl) {
	
	TEHandle macbuffer;
	short cronly;

	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
	
	if (fl)
		cronly = 1; /*word-wrap on*/
	else
		cronly = -1; /*no word-wrap*/
		
	(**macbuffer).crOnly = cronly; 
	} /*editsetwordwrap*/
	
	
void editrewrap (hdleditrecord hbuffer) {

	TEHandle macbuffer;

	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
		
	editprescroll (hbuffer);
	
	TECalText (macbuffer);
	
	editsetscrollvalues (hbuffer);
	
	(**hbuffer).flscrolled = true;
	} /*editrewrap*/
	

void editdispose (hdleditrecord hbuffer) {
	
	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
	
	TEDeactivate (macbuffer); /*remove the caret cursor, or unhighlight selection*/
	
	TEDispose (macbuffer);
		
	disposehandle ((Handle) hbuffer);
	} /*editdispose*/


void editdrawtext (bigstring bs, Rect r, tyjustification justification) {
	
	InsetRect (&r, texthorizinset, textvertinset);
	
	TETextBox (&bs [1], stringlength (bs), &r, getTEjustification (justification));
	} /*editdrawtext*/
	

void editdrawtexthandle (Handle htext, Rect r, tyjustification justification) {
	
	if (htext == nil)
		return;
		
	InsetRect (&r, texthorizinset, textvertinset);
	
	lockhandle (htext);
	
	TETextBox (*htext, GetHandleSize (htext), &r, getTEjustification (justification));
	
	unlockhandle (htext);
	} /*editdrawtexthandle*/
	

void editcut (hdleditrecord hbuffer) {
	
	#ifdef onlineOutliner
		Handle htext;
		TEHandle macbuffer;
		
		if (editgetselectedtexthandle (hbuffer, &htext)) {
		
			ZeroScrap ();
		
			PutScrap (GetHandleSize (htext), 'TEXT', *htext);
		
			DisposeHandle (htext);
					
			getmacbuffer (hbuffer, &macbuffer);
			
			if ((**macbuffer).selStart != (**macbuffer).selEnd)
				TEDelete (macbuffer);
			}
	#else
		TEHandle macbuffer;
		
		if (!getmacbuffer (hbuffer, &macbuffer))
			return;
	
		editprescroll (hbuffer);
		
		TECut (macbuffer);
		
		ZeroScrap (); /*dmb 1.0b24*/
		
		TEToScrap (); /*dmb 1.0b24*/
		
		editsetscrollvalues (hbuffer);
	#endif
	} /*editcut*/


void editcopy (hdleditrecord hbuffer) {
	
	#ifdef onlineOutliner
		Handle htext;
		
		if (editgetselectedtexthandle (hbuffer, &htext)) {
		
			ZeroScrap ();
		
			PutScrap (GetHandleSize (htext), 'TEXT', *htext);
		
			DisposeHandle (htext);
			}
	#else
		TEHandle macbuffer;
	
		if (!getmacbuffer (hbuffer, &macbuffer))
			return;

		TECopy (macbuffer);
		
		ZeroScrap (); /*dmb 1.0b24*/
		
		TEToScrap (); /*dmb 1.0b24*/
		
	#endif
	} /*editcopy*/


void editpaste (hdleditrecord hbuffer) {
	
	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return;

	editprescroll (hbuffer);
	
	TEFromScrap (); /*DW 4/8/95*/
		
	TEPaste (macbuffer);
	
	editsetscrollvalues (hbuffer);
	} /*editpaste*/
	
	
boolean editgettext (hdleditrecord hbuffer, bigstring bs) {

	TEHandle macbuffer;
	short len;
	
	setstringlength (bs, 0);
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return (false);

	len = (**macbuffer).teLength;
	
	if (len > lenbigstring) /*8/17/93 DW*/
		len = lenbigstring;
		
	setstringlength (bs, len);
			
	moveleft (*(**macbuffer).hText, &bs [1], (long) len);
	
	return (true);
	} /*editgettext*/


void editkeystroke (char chkb, hdleditrecord hbuffer) {

	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
	
	editprescroll (hbuffer);
	
	TEKey (chkb, macbuffer);
	
	editsetscrollvalues (hbuffer);
	} /*editkeystroke*/
	
	
void editclick (Point pt, boolean flshiftkey, hdleditrecord hbuffer) {

	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
		
	editprescroll (hbuffer);

	pushclip ((**macbuffer).viewRect);
	
	TEClick (pt, flshiftkey, macbuffer);
	
	popclip ();
	
	editsetscrollvalues (hbuffer);
	} /*editclick*/
	

boolean editsetselection (hdleditrecord hbuffer, short selstart, short selend) {

	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return (false);
		
	editprescroll (hbuffer);

	TESetSelect (selstart, selend, macbuffer);
	
	editsetscrollvalues (hbuffer);
		
	return (true);
	} /*editsetselection*/
	
	
boolean editvisiselection (hdleditrecord hbuffer) { /*DW 1/16/95 -- new feature*/

	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return (false);
		
	editprescroll (hbuffer);

	TESelView (macbuffer);
	
	editsetscrollvalues (hbuffer);
		
	return (true);
	} /*editvisiselection*/


void editselectall (hdleditrecord hbuffer) {
	
	editsetselection (hbuffer, 0, 32767);
	} /*editselectall*/
	

void editidle (hdleditrecord hbuffer) {
	
	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
	
	if ((**hbuffer).flselectall) {
		
		editselectall (hbuffer);
		
		(**hbuffer).flselectall = false;
		}
	
	TEIdle (macbuffer);
	} /*editidle*/
	
	
boolean editgetselection (hdleditrecord hbuffer, short *selstart, short *selend) {

	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return (false);
		
	*selstart = (**macbuffer).selStart;
	
	*selend = (**macbuffer).selEnd;
	
	return (true);
	} /*editgetselection*/


boolean editpointinrect (Point pt, hdleditrecord hbuffer) {

	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return (false);

	return (PtInRect (pt, &(**macbuffer).viewRect));
	} /*editpointinrect*/
	

boolean editreplace (bigstring bs, hdleditrecord hbuffer) {

	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return (false);
	
	editprescroll (hbuffer);
	
	if ((**macbuffer).selStart != (**macbuffer).selEnd)
		TEDelete (macbuffer);
	
	if (stringlength (bs) > 0)
		TEInsert (&bs [1], stringlength (bs), macbuffer);
	
	editsetscrollvalues (hbuffer);
	
	return (true); /*TE gives no way to return an error*/
	} /*editreplace*/
	
	
void editsetjustification (tyjustification justification, hdleditrecord hbuffer) {

	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
	
	TESetAlignment (getTEjustification (justification), macbuffer);
	} /*editsetjustification*/


void editgetsize (Handle htext, short *height, short *width) {
	
	/*
	return the size of a rectangle that could contain the indicated string
	observing the defaults for inset both vertically and horizontally, and 
	a minimum width for text display.
	
	assumes that the font/size/style info are correct in globalfontinfo.
	
	8/8/92 DW: upgrade to not use a bigstring to hold the text to be measured.
	we were encountering lines that were longer than 255 chars.
	
	12/30/92 DW: if you just deleted the last char of the buffer and it
	was a carriage return, we'd tell you that you have one more line than
	you actually have. I was tempted to fix the i <= textlength thing in 
	the for loop, but it broke other things. the klooginess is contained
	within this routine.
	*/
	
	long textlength;
	long i;
	short ctlines = 1;
	short maxwidth = 0;
	short vertpixels;
	short ixlinestart = 0, linelength = 0;
	
	textlength = GetHandleSize (htext);
		
	for (i = 0; i <= textlength; i++) {
		
		char ch = (*htext) [i];
			
		if ((ch == chreturn) || (i == textlength)) {
			
			short w;
			
			w = TextWidth (*htext, ixlinestart, linelength);
			
			if (w > maxwidth)
				maxwidth = w;
			
			if (i != textlength) { /*don't count the char after the last valid char*/

				if (ch == chreturn)
					ctlines++;
				}
			
			ixlinestart += linelength + 1;
			
			linelength = 0;
			}
		else
			linelength++;
		} /*for*/

	maxwidth = max (maxwidth, mintextwidth);
	
	maxwidth += 2 * texthorizinset;
	
	maxwidth++; /*ask for one extra pixel, work around TE display anomaly*/
	
	*width = maxwidth;
	
	vertpixels = ctlines * (globalfontinfo.ascent + globalfontinfo.descent + globalfontinfo.leading);
	
	*height = vertpixels + (2 * textvertinset);
	} /*editgetsize*/
	
	
void editgetbuffersize (hdleditrecord hbuffer, short *height, short *width) {
	
	/*
	8/8/92 DW for Snuffy: can't rely on the value for height returned by editgetsize, 
	since it doesn't take word-wrapping into account.
	*/
	
	TEHandle macbuffer;
	char lastchar;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
	
	editgetsize ((**macbuffer).hText, height, width);
	
	if ((**hbuffer).flwindowbased) {
	
		*height = ((**macbuffer).nLines * (**macbuffer).lineHeight) + globalfontinfo.descent;
		
		lastchar = (*(**macbuffer).hText) [(**macbuffer).teLength - 1];
		
		if (lastchar != chreturn) /*a quirk of TE*/
			*height += (**macbuffer).lineHeight;
		
		if ((**macbuffer).crOnly == 1) { /*word-wrapping turned on*/
		
			Rect r = (**macbuffer).destRect;
		
			*width = r.right - r.left;
			}
		}
		
	*width += 2 * texthorizinset;
	
	*height += 2 * textvertinset;
	} /*editgetbuffersize*/
	
	
boolean editgettexthandle (hdleditrecord hbuffer, Handle *htext) {
	
	/*
	return the text handle from the edit buffer. do not dispose the handle or
	alter the length of the text.
	*/

	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return (false);
		
	*htext = (**macbuffer).hText;
	
	return (true);
	} /*editgettexthandle*/


boolean editnewbufferfromhandle (Rect r, boolean flwordwrap, Handle htext, hdleditrecord *hrecord) {
	
	hdleditrecord h;
	TEHandle macbuffer;
	
	if (!newclearhandle (longsizeof (tyeditrecord), (Handle *) hrecord))
		return (false);
		
	h = *hrecord; /*copy into register*/
	
	InsetRect (&r, texthorizinset, textvertinset);
		
	macbuffer = TENew (&r, &r);
	
	if (macbuffer == nil) { /*memory error*/
		
		disposehandle ((Handle) h);
		
		*hrecord = nil;
		
		return (false);
		}
		
	if (flwordwrap)
		(**macbuffer).crOnly = 1;
	else
		(**macbuffer).crOnly = -1;

	lockhandle (htext);
	
	TESetText (*htext, GetHandleSize (htext), macbuffer);
	
	unlockhandle (htext);
	
	TEActivate (macbuffer);
	
	(**h).macbuffer = macbuffer;
	
	return (true);
	} /*editnewbufferfromhandle*/
	
	
boolean editsettexthandle (hdleditrecord hrecord, Handle htext, boolean flselectall) {
	
	/*
	if (!getmacbuffer (hrecord, &macbuffer))
		return (false);
	
	editprescroll (hrecord);
	
	lockhandle (htext);
	
	TESetText (*htext, GetHandleSize (htext), macbuffer);
	
	unlockhandle (htext);
	
	editsetscrollvalues (hrecord);
	*/
	
	/*
	1.0b20 dmb: new implementation. The old version would not update 
	active text.
	*/
	
	if (!editsetselection (hrecord, 0, infinity))
		return (false);
	
	if (!editreplacehandle (htext, hrecord))
		return (false);
	
	if (flselectall) 
		(**hrecord).flselectall = true;
	
	return (true);
	} /*editsettexthandle*/
	
	
boolean editgettexthandlecopy (hdleditrecord hbuffer, Handle *htext) {
	
	/*
	caller must dispose of the handle we allocate.
	
	7/8/92 DW: if there is no text, return true with htext == nil.
	*/

	TEHandle macbuffer;
	Handle h;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return (false);
	
	h = (**macbuffer).hText;
	
	if (GetHandleSize (h) == 0) {
	
		*htext = nil;
		
		return (true);
		}
	
	return (copyhandle (h, htext));
	} /*editgettexthandlecopy*/


boolean edithaveselection (hdleditrecord hbuffer) {

	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return (false);
	
	return ((**macbuffer).selStart != (**macbuffer).selEnd);
	} /*edithaveselection*/
	
	
boolean editscroll (hdleditrecord hbuffer, short dh, short dv) {

	TEHandle macbuffer;
	
	if ((dh != 0) || (dv != 0)) {
	
		if (!getmacbuffer (hbuffer, &macbuffer))
			return (false);
			
		editprescroll (hbuffer);
		
		TEScroll (dh, dv, macbuffer);
		
		editsetscrollvalues (hbuffer);
		}
	
	return (true);
	} /*edithaveselection*/
	
	
void editscrollto (hdleditrecord hbuffer, short h, short v) {
		
	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return;
	
	editsetscrollvalues (hbuffer);
	
	editscroll (hbuffer, (**hbuffer).horizcurrent - h, (**hbuffer).vertcurrent - v);
	} /*editscrollto*/


boolean editreplacehandle (Handle htext, hdleditrecord hbuffer) {

	TEHandle macbuffer;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return (false);
	
	editprescroll (hbuffer);
	
	if ((**macbuffer).selStart != (**macbuffer).selEnd)
		TEDelete (macbuffer);
		
	lockhandle (htext);
	
	TEInsert (*htext, GetHandleSize (htext), macbuffer);
	
	unlockhandle (htext);
	
	editsetscrollvalues (hbuffer);
	
	return (true); /*TE gives no way to return an error*/
	} /*editreplacehandle*/
	
	
boolean editgetselectedtexthandle (hdleditrecord hbuffer, Handle *htext) {

	TEHandle macbuffer;
	short selstart, selend;
	short lensel;
	Handle h;
	boolean fl;
	
	if (!getmacbuffer (hbuffer, &macbuffer))
		return (false);
		
	selstart = (**macbuffer).selStart;
	
	selend = (**macbuffer).selEnd;
	
	lensel = selend - selstart;
	
	if (lensel < 0)
		lensel = 0;
		
	h = (**macbuffer).hText;
	
	lockhandle (h);
	
	fl = newfilledhandle (&((*h) [selstart]), (long) lensel, htext);
	
	unlockhandle (h);
	
	return (fl);
	} /*editgetselectedtexthandle*/