executor/src/teInsert.c

1268 lines
31 KiB
C

/* Copyright 1986-1995 by Abacus Research and
* Development, Inc. All rights reserved.
*/
#if !defined (OMIT_RCSID_STRINGS)
char ROMlib_rcsid_teInsert[] =
"$Id: teInsert.c 88 2005-05-25 03:59:37Z ctm $";
#endif
#include "rsys/common.h"
#include "WindowMgr.h"
#include "ControlMgr.h"
#include "EventMgr.h"
#include "TextEdit.h"
#include "OSUtil.h"
#include "ToolboxEvent.h"
#include "ToolboxUtil.h"
#include "MemoryMgr.h"
#include "rsys/cquick.h"
#include "rsys/mman.h"
#include "rsys/tesave.h"
#include "rsys/smash.h"
#include "rsys/hook.h"
#include "rsys/region.h"
#include "rsys/text.h"
int16
ROMlib_StyleTextWidth (TEPtr tep,
int16 start, int16 count)
{
Handle hText;
SignedByte hText_flags;
Ptr Text;
TEStyleHandle te_style;
StyleRun *runs;
SignedByte te_style_flags;
STHandle style_table;
SignedByte style_table_flags;
STElement *styles;
int16 current_run_index;
int16 save_size, save_font;
Style save_face;
int16 length;
int16 retval;
length = TEP_LENGTH (tep);
if (start > length)
return 0;
hText = TEP_HTEXT (tep);
hText_flags = HGetState (hText);
HLock (hText);
Text = STARH (hText);
if (! TEP_STYLIZED_P (tep))
{
retval = TextWidth (Text, start, count);
goto cleanup;
}
if (start + count > length)
count = length - start;
te_style = TEP_GET_STYLE (tep);
te_style_flags = HGetState ((Handle) te_style);
HLock ((Handle) te_style);
runs = TE_STYLE_RUNS (te_style);
style_table = TE_STYLE_STYLE_TABLE (te_style);
style_table_flags = HGetState ((Handle) style_table);
styles = STARH (style_table);
save_size = PORT_TX_SIZE_X (thePort);
save_face = PORT_TX_FACE (thePort);
save_font = PORT_TX_FONT_X (thePort);
current_run_index = te_char_to_run_index (te_style, start);
retval = 0;
for (; count > 0; current_run_index ++)
{
StyleRun *current_run, *next_run;
STElement *style;
int16 next_run_start, run_len;
current_run = &runs[current_run_index];
next_run = &runs[current_run_index + 1];
next_run_start = RUN_START_CHAR (next_run);
run_len = next_run_start - start;
if (run_len > count)
run_len = count;
style = &styles[RUN_STYLE_INDEX (current_run)];
PORT_TX_SIZE_X (thePort) = ST_ELT_SIZE_X (style);
PORT_TX_FACE (thePort) = ST_ELT_FACE (style);
PORT_TX_FONT_X (thePort) = ST_ELT_FONT_X (style);
retval += TextWidth (Text, start, run_len);
count -= run_len;
start = next_run_start;
}
PORT_TX_SIZE_X (thePort) = save_size;
PORT_TX_FACE (thePort) = save_face;
PORT_TX_FONT_X (thePort) = save_font;
HSetState ((Handle) style_table, style_table_flags);
HSetState ((Handle) te_style, te_style_flags);
cleanup:
HSetState (hText, hText_flags);
return retval;
}
void
te_char_to_point (const TEPtr tep, int16 sel, Point *p)
{
SignedByte hText_flags;
Handle hText;
Ptr Text;
int16 *line_starts, line_start, line_end;
int16 just;
/* offset from the left edge of the dest rect to the beginning of
text for this line */
int16 left_offset;
int16 lineno, lineno_i;
int16 top, left;
Rect *dest_rect;
int on_break_p;
hText = TEP_HTEXT (tep);
hText_flags = HGetState (hText);
HLock (hText);
Text = STARH (hText);
dest_rect = &TEP_DEST_RECT (tep);
lineno = TEP_CHAR_TO_LINENO (tep, sel);
line_starts = TEP_LINE_STARTS (tep);
line_start = LINE_START (line_starts, lineno);
line_end = LINE_START (line_starts, lineno + 1);
on_break_p = (sel && sel == TEP_LENGTH (tep) && Text[sel - 1] == '\r');
just = TEP_JUST (tep);
if (just == teFlushDefault)
just = teFlushLeft;
else if (just != teCenter && just != teFlushRight && just != teFlushLeft)
{
warning_unexpected ("unknown justification `%d'", just);
just = teFlushLeft;
}
if (just == teCenter || just == teFlushRight)
{
int16 line_len;
line_len = line_end - line_start;
if (on_break_p)
left_offset = RECT_WIDTH (dest_rect) - 1;
else
left_offset = (RECT_WIDTH (dest_rect)
- TEP_TEXT_WIDTH (tep, Text, line_start, line_len)
/* ### the old code did this, i'm not quite sure
why it is necessary */
- 1);
if (just == teCenter)
left_offset /= 2;
}
else if (just == teFlushLeft)
left_offset = 0;
else
gui_fatal ("unknown justification");
if (on_break_p)
left = (CW (dest_rect->left) + left_offset);
else
left = (CW (dest_rect->left)
+ left_offset
+ TEP_TEXT_WIDTH (tep, Text, line_start, sel - line_start));
for (top = CW (dest_rect->top), lineno_i = 0; lineno_i < lineno; lineno_i ++)
/* ### hoist alot of the internal constants out of this loop */
top += TEP_HEIGHT_FOR_LINE (tep, lineno_i);
if (on_break_p)
top += TEP_HEIGHT_FOR_LINE (tep, lineno_i);
HSetState (hText, hText_flags);
p->v = top;
p->h = left;
}
static void
togglehilite (TEHandle te)
{
TE_DO_TEXT (te, TE_SEL_START (te), TE_SEL_END (te), teHilite);
}
static void
togglecaret (TEHandle teh, int16 sel, boolean_t paint_p)
{
Point p;
int16 pm;
pm = PORT_PEN_MODE (thePort);
TE_CHAR_TO_POINT (teh, sel, &p);
MoveTo(p.h, p.v);
PORT_PEN_MODE_X (thePort) = CWC(patXor);
if (TE_STYLIZED_P (teh))
{
TEStyleHandle te_style;
int lineno;
te_style = TE_GET_STYLE (teh);
lineno = TE_CHAR_TO_LINENO (teh, sel);
SetRect (&TE_SEL_RECT (teh), p.h, p.v,
p.h + 1, (p.v
+ LH_ASCENT (&(STARH (TE_STYLE_LH_TABLE
(te_style)))[lineno])
+ 1));
}
else
SetRect (&TE_SEL_RECT (teh), p.h, p.v, p.h + 1,
p.v + TE_LINE_HEIGHT (teh));
if (paint_p)
PaintRect(&TE_SEL_RECT (teh));
PenMode(pm);
}
PUBLIC void
ROMlib_recompute_caret (TEHandle te)
{
int16 state;
state = TE_CARET_STATE (te);
if (state == caret_vis || state == caret_invis)
togglecaret (te, TE_SEL_START (te), FALSE);
}
void
ROMlib_togglelite (TEHandle te)
{
int16 state;
state = TE_CARET_STATE (te);
if (state == caret_vis || state == caret_invis)
togglecaret (te, TE_SEL_START (te), TRUE);
else
togglehilite (te);
}
void
ROMlib_tesave (tesave *t, TEHandle teh)
{
TEPtr tp;
tp = STARH (teh);
t->_tport = thePortX;
thePortX = tp->inPort;
t->_tpvis = PORT_PEN_VIS_X (thePort);
t->_tfont = PORT_TX_FONT_X (thePort);
t->_tmode = PORT_TX_MODE_X (thePort);
t->_tsize = PORT_TX_SIZE_X (thePort);
t->_tstyle = PORT_TX_FACE_X (thePort);
t->fg_color = PORT_FG_COLOR_X (thePort);
t->bk_color = PORT_BK_COLOR_X (thePort);
if (CGrafPort_p (thePort))
{
t->rgb_fg_color = CPORT_RGB_FG_COLOR (thePort);
t->rgb_bk_color = CPORT_RGB_BK_COLOR (thePort);
}
GetPenState (&t->_tpstate);
PORT_PEN_SIZE (thePort).h = PORT_PEN_SIZE (thePort).v = CWC (1);
PORT_PEN_MODE_X (thePort) = CWC (patCopy);
PORT_TX_FONT_X (thePort) = tp->txFont;
PORT_TX_MODE_X (thePort) = tp->txMode;
PORT_TX_SIZE_X (thePort) = tp->txSize;
PORT_TX_FACE_X (thePort) = tp->txFace;
PenPat (black);
t->_tsaveclip = PORT_CLIP_REGION_X (thePort);
PORT_CLIP_REGION_X (thePort) = RM (NewRgn ());
HxX (PORT_CLIP_REGION (thePort), rgnBBox) = HxX (teh, viewRect);
SectRgn (PORT_CLIP_REGION (thePort), MR (t->_tsaveclip),
PORT_CLIP_REGION (thePort));
}
void
ROMlib_terestore (tesave *t)
{
SetPenState (&t->_tpstate);
DisposeRgn (PORT_CLIP_REGION (thePort));
PORT_CLIP_REGION_X (thePort) = t->_tsaveclip;
PORT_TX_FACE_X (thePort) = t->_tstyle;
PORT_TX_SIZE_X (thePort) = t->_tsize;
PORT_TX_MODE_X (thePort) = t->_tmode;
PORT_TX_FONT_X (thePort) = t->_tfont;
PORT_PEN_VIS_X (thePort) = t->_tpvis;
PORT_FG_COLOR_X (thePort) = t->fg_color;
PORT_BK_COLOR_X (thePort) = t->bk_color;
if (CGrafPort_p (thePort))
{
CPORT_RGB_FG_COLOR (thePort) = t->rgb_fg_color;
CPORT_RGB_BK_COLOR (thePort) = t->rgb_bk_color;
}
thePortX = t->_tport;
}
P1 (PUBLIC pascal trap, void, TEIdle, TEHandle, teh)
{
INTEGER sel, state;
LONGINT ticks;
TESAVE (teh);
TE_SLAM (teh);
if ((ticks = TickCount()) > Hx(teh, caretTime) + CL(CaretTime)
&& Hx(teh, active)
&& (sel = Hx(teh, selStart)) == Hx(teh, selEnd)
&& (state = Hx(teh, caretState)))
{
togglecaret(teh, sel, TRUE);
HxX(teh, caretState) = CW (state ^ 0xFF00);
HxX(teh, caretTime) = CL (ticks);
}
TE_SLAM (teh);
TERESTORE ();
}
void
style_update_port (STElement *style)
{
PORT_TX_SIZE_X (thePort) = ST_ELT_SIZE_X (style);
PORT_TX_FONT_X (thePort) = ST_ELT_FONT_X (style);
PORT_TX_FACE (thePort) = ST_ELT_FACE (style);
RGBForeColor (&ST_ELT_COLOR (style));
}
/* ### the old code did something whacky related to italics */
void
te_draw (TEPtr tep,
int16 start, int16 end)
{
Handle hText;
Ptr Text;
SignedByte hText_flags;
/* these are only used if the TE record is stylized */
TEStyleHandle te_style = NULL;
SignedByte te_style_flags = -1;
StyleRun *runs, *current_run;
int16 n_runs;
STHandle style_table = NULL;
SignedByte style_table_flags = -1;
STElement *styles;
int16 n_styles;
/* all drawing is done per-line; before any drawing we erase the
entire target rectangle */
Point start_pt, end_pt;
int16 start_lineno, end_lineno, current_lineno, *line_starts;
int16 first_visible_lineno, last_visible_lineno;
int16 start_line_start;
Rect *dest_rect, r;
int16 dest_rect_left, dest_rect_right, dest_rect_bottom, dest_rect_top;
int16 current_line_top, top, bottom;
Rect *view_rect;
int16 view_rect_bottom;
int16 current_run_start, current_run_end;
int16 current_line_start, current_line_end;
int16 current_posn;
int16 start_run_index;
int16 n_lines;
start_lineno = TEP_CHAR_TO_LINENO (tep, start);
end_lineno = TEP_CHAR_TO_LINENO (tep, end);
n_lines = TEP_N_LINES (tep);
dest_rect = &TEP_DEST_RECT (tep);
dest_rect_left = CW (dest_rect->left);
dest_rect_right = CW (dest_rect->right);
dest_rect_top = CW (dest_rect->top);
dest_rect_bottom = CW (dest_rect->bottom);
view_rect = &TEP_VIEW_RECT (tep);
view_rect_bottom = CW (view_rect->bottom);
{
int16 height;
Rect *view_rect, *clip_rect, *vis_rect;
int16 clip_rect_top, clip_rect_bottom;
view_rect = &TEP_VIEW_RECT (tep);
vis_rect = &RGN_BBOX (PORT_VIS_REGION (thePort));
clip_rect = alloca (sizeof *clip_rect);
#if 0
#warning this code appears to cause trouble with TTSs logbook
/* the problem is that they have a picture open and expect the text
calls to be logged into the picture even though they can't make it to the
screen */
SectRect (view_rect, vis_rect, clip_rect);
#else
#warning this section of code should be cleaned up
SectRect (view_rect, view_rect, clip_rect);
#endif
clip_rect_top = CW (clip_rect->top);
clip_rect_bottom = CW (clip_rect->bottom);
/* clip the lines to draw by the visible lines */
for (current_lineno = 0, height = dest_rect_top;; current_lineno ++)
{
height += TEP_HEIGHT_FOR_LINE (tep, current_lineno);
if (height > clip_rect_top)
break;
}
first_visible_lineno = current_lineno;
for (; current_lineno < n_lines - 1; current_lineno ++)
{
if (height > clip_rect_bottom)
break;
height += TEP_HEIGHT_FOR_LINE (tep, current_lineno);
}
last_visible_lineno = current_lineno;
}
if (end_lineno < first_visible_lineno
|| start_lineno > last_visible_lineno)
return;
if (start_lineno < first_visible_lineno)
start_lineno = first_visible_lineno;
if (end_lineno > last_visible_lineno)
end_lineno = last_visible_lineno;
line_starts = TEP_LINE_STARTS (tep);
start_line_start = LINE_START (line_starts, start_lineno);
TEP_CHAR_TO_POINT (tep, start_line_start, &start_pt);
/* we only care about the vertical component */
TEP_CHAR_TO_POINT (tep, end, &end_pt);
hText = TEP_HTEXT (tep);
hText_flags = HGetState (hText);
HLock (hText);
Text = STARH (hText);
top = start_pt.v;
bottom = (end == TEP_LENGTH (tep)
? view_rect_bottom
: end_pt.v + TEP_HEIGHT_FOR_LINE (tep, end_lineno));
SetRect (&r, dest_rect_left, top, dest_rect_right, bottom);
EraseRect (&r);
if (TEP_STYLIZED_P (tep))
{
te_style = TEP_GET_STYLE (tep);
te_style_flags = HGetState ((Handle) te_style);
HLock ((Handle) te_style);
n_runs = TE_STYLE_N_RUNS (te_style);
runs = TE_STYLE_RUNS (te_style);
n_styles = TE_STYLE_N_STYLES (te_style);
style_table = TE_STYLE_STYLE_TABLE (te_style);
style_table_flags = HGetState ((Handle) style_table);
HLock ((Handle) style_table);
styles = STARH (style_table);
start_run_index
= te_char_to_run_index (te_style,
LINE_START (line_starts, start_lineno));
}
else
{
/* allocate bogo runs/styles */
n_runs = 1;
runs = alloca (sizeof *runs * 2);
RUN_START_CHAR_X (&runs[0]) = CWC (0);
RUN_STYLE_INDEX_X (&runs[0]) = CWC (0);
RUN_START_CHAR_X (&runs[1]) = CW (TEP_LENGTH (tep) + 1);
RUN_STYLE_INDEX_X (&runs[1]) = CWC (-1);
n_styles = 1;
styles = alloca (sizeof *styles);
ST_ELT_FACE (styles) = TEP_TX_FACE (tep);
ST_ELT_HEIGHT_X (styles) = TEP_LINE_HEIGHT_X (tep);
ST_ELT_ASCENT_X (styles) = TEP_FONT_ASCENT_X (tep);
ST_ELT_FONT_X (styles) = TEP_TX_FONT_X (tep);
ST_ELT_SIZE_X (styles) = TEP_TX_SIZE_X (tep);
GetForeColor (&ST_ELT_COLOR (styles));
/* and for completeness */
ST_ELT_COUNT_X (styles) = CWC (1);
start_run_index = 0;
}
current_line_top = start_pt.v;
current_lineno = start_lineno;
current_posn = current_line_start = start_line_start;
current_line_end = LINE_START (line_starts, current_lineno + 1);
current_run = &runs[start_run_index];
current_run_start = RUN_START_CHAR (current_run);
current_run_end = RUN_START_CHAR (current_run + 1);
style_update_port (&styles[RUN_STYLE_INDEX (current_run)]);
MoveTo (start_pt.h, (current_line_top
+ TEP_ASCENT_FOR_LINE (tep, current_lineno)));
for (; current_lineno <= end_lineno;)
{
if (current_run_end < current_line_end)
{
#if 0
Point orig_pn = PORT_PEN_LOC (thePort);
#endif
DrawText (Text, current_posn, current_run_end - current_posn);
#if 0
gui_assert (CW (orig_pn.h)
+ TextWidth (Text, current_posn,
current_run_end - current_posn)
== CW (PORT_PEN_LOC (thePort).h));
#endif
current_run ++;
style_update_port (&styles[RUN_STYLE_INDEX (current_run)]);
current_run_start = current_posn = current_run_end;
current_run_end = RUN_START_CHAR (current_run + 1);
}
else if (current_run_end > current_line_end)
{
DrawText (Text, current_posn, current_line_end - current_posn);
if (current_lineno == end_lineno)
break;
current_line_top += TEP_HEIGHT_FOR_LINE (tep, current_lineno);
current_lineno ++;
current_posn = current_line_start = current_line_end;
current_line_end = LINE_START (line_starts, current_lineno + 1);
TEP_CHAR_TO_POINT (tep, current_line_start, &start_pt);
MoveTo (start_pt.h, (current_line_top
+ TEP_ASCENT_FOR_LINE (tep, current_lineno)));
}
else
{
gui_assert (current_run_end == current_line_end);
DrawText (Text, current_posn, current_line_end - current_posn);
if (current_lineno == end_lineno)
break;
/* advance the run */
current_run ++;
style_update_port (&styles[RUN_STYLE_INDEX (current_run)]);
current_run_start = current_posn = current_run_end;
current_run_end = RUN_START_CHAR (current_run + 1);
/* advance the line */
current_line_top += TEP_HEIGHT_FOR_LINE (tep, current_lineno);
current_lineno ++;
current_line_start = current_line_end;
current_line_end = LINE_START (line_starts, current_lineno + 1);
TEP_CHAR_TO_POINT (tep, current_line_start, &start_pt);
MoveTo (start_pt.h, (current_line_top
+ TEP_ASCENT_FOR_LINE (tep, current_lineno)));
}
}
if (TEP_STYLIZED_P (tep))
{
HSetState ((Handle) style_table, style_table_flags);
HSetState ((Handle) te_style, te_style_flags);
}
HSetState (hText, hText_flags);
}
void
te_hilite (TEPtr tep,
int16 start, int16 end)
{
Handle hText;
SignedByte hText_flags;
Ptr Text;
Point start_pt, end_pt;
int16 start_lineno, end_lineno, lineno_i, *line_starts;
int16 top, left, bottom, right;
Rect *dest_rect, r;
int16 dest_rect_left, dest_rect_right;
int16 length;
hText = TEP_HTEXT (tep);
hText_flags = HGetState (hText);
HLock (hText);
Text = STARH (hText);
TEP_CHAR_TO_POINT (tep, start, &start_pt);
TEP_CHAR_TO_POINT (tep, end, &end_pt);
start_lineno = TEP_CHAR_TO_LINENO (tep, start);
end_lineno = TEP_CHAR_TO_LINENO (tep, end);
line_starts = TEP_LINE_STARTS (tep);
dest_rect = &TEP_DEST_RECT (tep);
dest_rect_left = CW (dest_rect->left);
dest_rect_right = CW (dest_rect->right);
length = TEP_LENGTH (tep);
/* highlight the first line */
left = (start == LINE_START (line_starts, start_lineno)
? dest_rect_left
: start_pt.h);
right = ((start_lineno != end_lineno
|| end == length)
? dest_rect_right
: end_pt.h);
top = start_pt.v;
bottom = top + TEP_HEIGHT_FOR_LINE (tep, start_lineno);
SetRect (&r, left, top, right, bottom);
CLEAR_HILITE_BIT ();
InvertRect (&r);
if (start_lineno == end_lineno)
goto DONE;
top = bottom;
for (lineno_i = start_lineno + 1;
(end == length && Text[length - 1] == '\r'
? lineno_i <= end_lineno
: lineno_i < end_lineno);
lineno_i ++)
bottom += TEP_HEIGHT_FOR_LINE (tep, lineno_i);
if (bottom != top)
{
SetRect (&r, dest_rect_left, top, dest_rect_right, bottom);
CLEAR_HILITE_BIT ();
InvertRect (&r);
}
if (end != LINE_START (line_starts, end_lineno))
{
top = end_pt.v;
right = (end == length
? dest_rect_right
: end_pt.h);
bottom = top + TEP_HEIGHT_FOR_LINE (tep, end_lineno);
SetRect (&r, dest_rect_left, top, right, bottom);
CLEAR_HILITE_BIT ();
InvertRect (&r);
}
DONE:
HSetState (hText, hText_flags);
}
int16
te_find (TEPtr tep, int16 start, int16 end)
{
Handle hText;
SignedByte hText_flags;
Ptr Text;
int16 length;
int16 just;
int16 v, h;
int16 dest_rect_top, dest_rect_left;
Rect *dest_rect;
int16 line_start, line_end, end_limit, lineno, *line_starts;
int16 current_posn;
int height, width, char_width = 0;
int16 n_lines;
int16 left_offset;
int16 retval;
hText = TEP_HTEXT (tep);
hText_flags = HGetState (hText);
HLock (hText);
Text = STARH (hText);
dest_rect = &TEP_DEST_RECT (tep);
dest_rect_top = CW (dest_rect->top);
dest_rect_left = CW (dest_rect->left);
length = TEP_LENGTH (tep);
n_lines = TEP_N_LINES (tep);
line_starts = TEP_LINE_STARTS (tep);
v = CW (TEP_SEL_POINT (tep).v);
h = CW (TEP_SEL_POINT (tep).h) - dest_rect_left;
if (! Text)
{
retval = -1;
goto DONE;
}
if (v < dest_rect_top)
{
retval = 0;
goto DONE;
}
/* compute the line the click is on */
for (lineno = 0, height = dest_rect_top; lineno < n_lines; lineno ++)
{
height += TEP_HEIGHT_FOR_LINE (tep, lineno);
if (v < height)
break;
}
line_start = LINE_START (line_starts, lineno);
line_end = LINE_START (line_starts, lineno + 1);
just = TEP_JUST (tep);
if (just == teFlushDefault)
just = teFlushLeft;
else if (just != teCenter && just != teFlushRight && just != teFlushLeft)
{
warning_unexpected ("unknown justification `%d'", just);
just = teFlushLeft;
}
/* compute the left offset for this line */
if (just == teCenter || just == teFlushRight)
{
int16 line_len;
line_len = line_end - line_start;
left_offset = (RECT_WIDTH (dest_rect)
- TEP_TEXT_WIDTH (tep, Text, line_start, line_len)
/* ### the old code did this, i'm not quite sure
why it is necessary */
- 1);
if (just == teCenter)
left_offset /= 2;
}
else /* if (just == teFlushLeft) */
left_offset = 0;
if (h < left_offset)
{
retval = line_start;
goto DONE;
}
end_limit = ((line_end && line_end == length
&& Text[line_end - 1] != '\r')
? line_end
: line_end - 1);
for (width = left_offset, current_posn = line_start;
width < h && current_posn < end_limit; current_posn ++)
{
if (TEP_STYLIZED_P (tep))
char_width = ROMlib_StyleTextWidth (tep, current_posn, 1);
else
char_width = CharWidth (Text[current_posn]);
width += char_width;
}
if (current_posn > line_start
&& h < width - char_width / 2)
current_posn --;
retval = current_posn;
DONE:
HSetState (hText, hText_flags);
return retval;
}
/* custom text hook; this is the defualt text hook stored in
`TEDoText'.
for calling conventions, see IM Text, 2-63 */
A4 (PUBLIC, int16, C_ROMlib_dotext, TEPtr, tep, /* INTERNAL */
int16, start, int16, end, int16, what)
{
if (what == teHilite)
te_hilite (tep, start, end);
else if (what == teDraw)
te_draw (tep, start, end);
else if (what == teFind)
return te_find (tep, start, end);
return 0;
}
PUBLIC INTEGERRET ROMlib_dotext (void)
{
INTEGERRET retval;
TEPtr tep;
INTEGER first, last, what;
tep = (TEPtr) (long) SYN68K_TO_US(EM_A3);
first = EM_D3;
last = EM_D4;
what = EM_D7;
retval = C_ROMlib_dotext(tep, first, last, what);
EM_A0 = (LONGINT) (long) US_TO_SYN68K(thePort);
EM_D0 = retval;
return retval;
}
/* return TRUE if click at location `cl' was a double click; otherwise
save away this click information (location, time) */
static boolean_t
double_click_p (TEHandle te, int16 cl)
{
int32 ticks;
ticks = TickCount ();
if (cl == TE_CLICK_LOC (te)
&& ticks <= TE_CLICK_TIME (te) + CL (DoubleTime))
return TRUE;
TE_CLICK_LOC_X (te) = CW (cl);
TE_CLICK_TIME_X (te) = CL (ticks);
return FALSE;
}
typedef BOOLEAN (*cliklooptype) (void);
A1 (static inline, BOOLEAN, CALLCLIKOK, TEHandle, teh)
{
BOOLEAN retval;
cliklooptype cp;
if ((cp = (cliklooptype)HxP(teh, clikLoop))) {
ROMlib_hook(te_clikloopnumber);
{
LONGINT saved0, saved1, saved2, saved3,
savea0, savea1, savea2, savea3;
saved0 = EM_D0;
saved1 = EM_D1;
saved2 = EM_D2;
saved3 = EM_D3;
savea0 = EM_A0;
savea1 = EM_A1;
savea2 = EM_A2;
savea3 = EM_A3;
CALL_EMULATOR((syn68k_addr_t) US_TO_SYN68K ((long)cp));
#define USE_Z_BIT_NOT_D0_FOR_CLIK_DETERMINATION /* as per Tom Pittman */
#if !defined(USE_Z_BIT_NOT_D0_FOR_CLIK_DETERMINATION)
retval = EM_D0;
#else
retval = !!cpu_state.ccnz;
#endif
EM_D0 = saved0;
EM_D1 = saved1;
EM_D2 = saved2;
EM_D3 = saved3;
EM_A0 = savea0;
EM_A1 = savea1;
EM_A2 = savea2;
EM_A3 = savea3;
}
} else
retval = TRUE;
return retval;
}
typedef enum
{
forward = 1, backward = -1,
} word_break_dir_t;
static int
tep_find_word_break (TEPtr tep, int start, word_break_dir_t dir)
{
Handle hText;
SignedByte hText_flags;
Ptr Text;
int length;
int current_index;
int retval;
hText = TEP_HTEXT (tep);
hText_flags = HGetState (hText);
HLock (hText);
Text = STARH (hText);
length = TEP_LENGTH (tep);
for (current_index = start;
current_index > 0 && current_index < length;
current_index += dir)
{
if (ROMlib_wordb ((char *) &Text[current_index]))
{
retval = current_index;
if (dir == backward)
retval ++;
goto done;
}
}
retval = current_index;
done:
HSetState (hText, hText_flags);
return retval;
}
P3 (PUBLIC pascal trap, void, TEClick, Point, pt, BOOLEAN, extend,
TEHandle, te)
{
EventRecord evt;
SignedByte te_flags;
TEPtr tep;
int16 start, end;
int16 click_posn;
int16 origin = -1, true_origin = -1;
int16 left_origin = -1, right_origin = -1;
int16 length;
int16 state;
boolean_t word_hilite_p = FALSE;
TESAVE (te);
te_flags = HGetState ((Handle) te);
HLock ((Handle) te);
tep = STARH (te);
length = TEP_LENGTH (tep);
if (TEP_STYLIZED_P (tep))
{
TEStyleHandle te_style = TEP_GET_STYLE (tep);
SCRAP_N_STYLES_X (TE_STYLE_NULL_SCRAP (te_style)) = CWC (0);
}
start = TEP_SEL_START (tep);
end = TEP_SEL_END (tep);
TEP_CLICK_STUFF_X (tep) = CWC (0);
TEP_SEL_POINT (tep).h = CW (pt.h);
TEP_SEL_POINT (tep).v = CW (pt.v);
click_posn = TEP_DO_TEXT (tep, 0, length, teFind);
state = TEP_CARET_STATE (tep);
#define te_toggle_hilite_range(start, end) \
TEP_DO_TEXT (tep, start, end, teHilite)
#define te_find() \
TEP_DO_TEXT (tep, 0, length, teFind)
/* extend the current selection range; else nuke it */
if (extend
&& (click_posn <= start
|| click_posn >= end)
&& (start != end
|| start != click_posn))
{
if (state == caret_vis)
togglecaret (te, start, TRUE);
state = hilite_vis;
if (click_posn < start)
{
te_toggle_hilite_range (click_posn, start);
start = click_posn;
origin = end;
}
else if (click_posn > end)
{
if (state == caret_vis)
togglecaret (te, start, TRUE);
te_toggle_hilite_range (end, click_posn);
end = click_posn;
origin = start;
}
/* ### need else */
}
else
{
if (state == hilite_vis || state == caret_vis)
ROMlib_togglelite (te);
state = caret_invis;
if (double_click_p (te, click_posn))
{
word_hilite_p = TRUE;
true_origin = click_posn;
left_origin = start
= tep_find_word_break (tep, click_posn, backward);
right_origin = end
= tep_find_word_break (tep, click_posn, forward);
if (start != end)
{
te_toggle_hilite_range (start, end);
state = hilite_vis;
}
else
{
/* draw the caret */
togglecaret (te, start, TRUE);
state = caret_vis;
}
}
else
{
origin = start = end = click_posn;
/* draw the caret */
togglecaret (te, start, TRUE);
state = caret_vis;
}
}
#define te_sel_new_end(_new_end) \
({ \
typeof (_new_end) new_end = (_new_end); \
\
if (end != new_end) \
{ \
if (start == end) \
{ \
gui_assert (state == caret_vis); \
togglecaret (te, start, TRUE); \
state = caret_invis; \
} \
\
if (new_end < end) \
te_toggle_hilite_range (new_end, end); \
else if (new_end > end) \
te_toggle_hilite_range (end, new_end); \
end = new_end; \
\
if (start == end) \
{ \
togglecaret (te, start, TRUE); \
state = caret_vis; \
} \
else \
state = hilite_vis; \
} \
})
#define te_sel_new_start(_new_start) \
({ \
typeof (_new_start) new_start = (_new_start); \
\
if (start != new_start) \
{ \
if (start == end) \
{ \
gui_assert (state == caret_vis); \
togglecaret (te, start, TRUE); \
state = caret_invis; \
} \
\
if (new_start < start) \
te_toggle_hilite_range (new_start, start); \
else if (new_start > start) \
te_toggle_hilite_range (start, new_start); \
start = new_start; \
\
if (start == end) \
{ \
togglecaret (te, start, TRUE); \
state = caret_vis; \
} \
else \
state = hilite_vis; \
} \
})
TEP_SEL_START_X (tep) = CW (start);
TEP_SEL_END_X (tep) = CW (end);
TEP_CARET_STATE_X (tep) = CW (state);
while (Button () && CALLCLIKOK (te))
{
if (STARH (TEHIDDENH (te))->flags & CLC (TEAUTOVIEWBIT))
ROMlib_teautoloop (te);
GetOSEvent (0, &evt);
GlobalToLocal (&evt.where);
TEP_SEL_POINT (tep) = evt.where;
click_posn = TEP_DO_TEXT (tep, 0, length, teFind);
if (word_hilite_p)
{
if (click_posn < true_origin)
click_posn = tep_find_word_break (tep, click_posn, backward);
else
click_posn = tep_find_word_break (tep, click_posn, forward);
if (click_posn <= left_origin)
{
origin = right_origin;
if (end != right_origin)
{
te_toggle_hilite_range (right_origin, end);
end = right_origin;
}
}
else
{
origin = left_origin;
if (start != left_origin)
{
te_toggle_hilite_range (start, left_origin);
start = left_origin;
}
}
}
if (click_posn != -1)
{
if (origin == start)
{
if ((click_posn > end)
|| (click_posn >= start
&& click_posn < end))
te_sel_new_end (click_posn);
else if (click_posn < start)
{
te_sel_new_end (start);
te_sel_new_start (click_posn);
origin = end;
}
}
else if (origin == end)
{
if (click_posn < start
|| (click_posn <= end
&& click_posn > start))
te_sel_new_start (click_posn);
else if (click_posn > end)
{
te_sel_new_start (end);
te_sel_new_end (click_posn);
origin = start;
}
}
else
gui_fatal ("origin is neither start nor end");
}
TEP_SEL_START_X (tep) = CW (start);
TEP_SEL_END_X (tep) = CW (end);
TEP_CARET_STATE_X (tep) = CW (state);
}
/* suck out the up event if it is there */
GetOSEvent (mUpMask, &evt);
HSetState ((Handle) te, te_flags);
TERESTORE ();
}
P3 (PUBLIC pascal trap, void, TESetSelect, int32, start, int32, stop,
TEHandle, teh)
{
int16 length;
TE_SLAM (teh);
length = TE_LENGTH (teh);
if (start < 0)
start = 0;
if (stop > length)
stop = length;
if (start > stop)
start = stop;
if (start != TE_SEL_START (teh)
|| stop != TE_SEL_END (teh))
{
TESAVE (teh);
if (TE_CARET_STATE (teh) != caret_invis)
ROMlib_togglelite (teh);
if (start != stop && TE_ACTIVE (teh))
TE_DO_TEXT (teh, start, stop, teHilite);
TERESTORE ();
TE_SEL_START_X (teh) = CW (start);
TE_SEL_END_X (teh) = CW (stop);
if (TE_ACTIVE (teh))
TE_CARET_STATE_X (teh) = (start != stop
? CWC (0)
: CWC (255));
}
TE_SLAM (teh);
}
P1 (PUBLIC pascal trap, void, TEActivate, TEHandle, teh)
{
int16 start, end;
TE_SLAM (teh);
if (TE_ACTIVE_X (teh))
return;
start = TE_SEL_START (teh);
end = TE_SEL_END (teh);
if (start != end)
{
TESAVE (teh);
TE_DO_TEXT (teh, start, end, teHilite);
TE_CARET_STATE_X (teh) = CWC (hilite_vis);
TERESTORE ();
}
TE_ACTIVE_X (teh) = CWC (-256);
TE_SLAM (teh);
}
P1 (PUBLIC pascal trap, void, TEDeactivate, TEHandle, teh)
{
TE_SLAM (teh);
if (! TE_ACTIVE_X (teh))
return;
{
TESAVE (teh);
if (TE_CARET_STATE (teh) != caret_invis)
ROMlib_togglelite (teh);
TE_CARET_STATE_X (teh) = CWC (caret_invis);
TERESTORE ();
}
TE_ACTIVE_X (teh) = CWC (FALSE);
}