|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T
Length: 41853 (0xa37d)
Types: TextFile
Names: »Text.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦526ad3590⟧ »EUUGD11/gnu-31mar87/X.V10.R4.tar.Z«
└─⟦2109abc41⟧
└─⟦this⟧ »./X.V10R4/Toolkit/DECToolkit/src/Text.c«
/*
* $Source: /u1/X/DECToolkit/src/RCS/Text.c,v $
* $Header: Text.c,v 1.2 86/12/17 16:05:41 swick Exp $
*/
#ifndef lint
static char *rcsid_Text_c = "$Header: Text.c,v 1.2 86/12/17 16:05:41 swick Exp $";
#endif lint
#ifndef lint
static char *sccsid = "@(#)Text.c 1.17 12/11/86";
#endif lint
/*
* COPYRIGHT 1986
* DIGITAL EQUIPMENT CORPORATION
* MAYNARD, MASSACHUSETTS
* ALL RIGHTS RESERVED.
*
* THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
* SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
* DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
* ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
*
* IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS,
* APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT
* SET FORTH ABOVE.
*
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting documentation,
* and that the name of Digital Equipment Corporation not be used in advertising
* or publicity pertaining to distribution of the software without specific,
* written prior permission.
*/
/* File: Text.c */
#include <X/Xlib.h>
#include "Toolkit.h"
#include "TextDisplay.h" /** all text subwindow programs include **/
#include "Text.h"
static initialize()
{
FontInfo *finfo;
myContext = UniqueEntryType();
buf = (char *) Tmalloc(200);
finfo = XOpenFont(DEFAULT_FONT);
defaultSink = (TTextSink *) TCreateAsciiSink(finfo);
initialized = 1;
}
/* Utility routines for support of TextSW */
#ifndef CURSORS
static DisplayInsertCursor (w, x, y, onOff)
Window w;
int x,y, onOff;
{
int fgnd;
fgnd = onOff ? BlackPixel : WhitePixel;
if (!insertCursorMask) {
insertCursorMask = XStoreBitmap(insertCursor_width,
insertCursor_height, insertCursor_mask);
}
XBitmapBitsPut(w, x - 3, y - 3,
insertCursor_width, insertCursor_height, insertCursor_bits,
fgnd, WhitePixel, insertCursorMask, GXcopy, AllPlanes);
}
#endif
/*
* Procedure to make cursor visible. It is used on editable windows.
* The cursor will go will in ctx->i.position.
*/
static void InsertCursor (ctx, state)
TextSWContext *ctx;
enum InsertState state;
{
int x, y, onOff, line, visible;
TTextBlock text;
visible = LineAndXYForPosition(ctx, ctx->i.position, &line, &x, &y);
if (state == on)
onOff = 1;
else
onOff = 0;
/** if the insert position is not currently on the screen->go get it **/
if (x > xMargin &&
ctx->i.position > 0 &&
ctx->i.position >= (*(ctx->source->getLastPos))(ctx->source)) {
(*(ctx->source->read))(ctx->source, ctx->i.position - 1, &text, 1);
if (text.ptr[0] == '\n') {
x = xMargin;
y += (ctx->lt.entry[line + 1].y - ctx->lt.entry[line].y);
}
}
y += (ctx->lt.entry[line + 1].y - ctx->lt.entry[line].y);
if (visible)
DisplayInsertCursor(ctx->w, x, y, onOff);
}
/*
* given an x and y position this routine will return the byte offset
* of that point in the source.
*/
static int PositionForXY (ctx, x, y)
TextSWContext * ctx;
int x,y;
{
/* it is illegal to call this routine unless there is a valid line table! */
int width, fromx, line;
TTextPosition position, resultstart, resultend;
/*** figure out what line it is on ***/
for (line = 0; line < ctx->lt.lines - 1; line++) {
if (y <= ctx->lt.entry[line + 1].y)
break;
}
position = ctx->lt.entry[line].position;
fromx = ctx->lt.entry[line].x; /* starting x in line */
width = x - fromx; /* num of pix from starting of line */
(*(ctx->sink->resolve)) (ctx->sink, ctx->source, position, fromx, width,
&resultstart, &resultend);
if (resultstart > ctx->lt.entry[line + 1].position)
resultstart = ctx->lt.entry[line + 1].position;
return resultstart;
}
/***
*** Given a window context and a byte offset, this routine will return
*** the index into the line table of where the byte offset occurs.
***/
static int LineForPosition (ctx, position)
TextSWContext *ctx;
TTextPosition position;
/* it is illegal to call this routine unless there is a valid line table!*/
{
int i, line;
line = 0;
if (position > ctx->lt.entry[0].position)
for (i = 0; i < ctx->lt.lines; i++) {
if (position < ctx->lt.entry[line + 1].position
|| (position == ctx->lt.entry[line + 1].position
&& position == (*(ctx->source->getLastPos))(ctx->source)))
break;
else
line++;
}
return line;
}
/***
*** Given a window context and a byte offset, this routine figures out
*** if the position is visible, and if it is visible it returns the
*** index into the line table and the x,y coordinates.
***/
static int LineAndXYForPosition (ctx, pos, line, x, y)
TextSWContext *ctx;
TTextPosition pos;
int *line, *x, *y;
/* it is illegal to call this routine unless there is a valid line table!*/
{
TTextPosition linePos, endPos;
int visible, realW, realH;
*line = 0;
*x = ctx->leftmargin;
*y = yMargin;
visible = IsPositionVisible(ctx, pos);
/*** if it is in the line table determine the line, x, y ***/
if (visible) {
*line = LineForPosition(ctx, pos);
*y = ctx->lt.entry[*line].y;
*x = ctx->lt.entry[*line].x;
linePos = ctx->lt.entry[*line].position;
(*(ctx->sink->findDistance)) (ctx->sink, ctx->source, linePos, *x, pos,
&realW, &endPos, &realH);
*x = *x + realW;
}
return visible;
}
/***
*** this routine builds a line table for the given window context, starting
*** at the given byte offset in the source.
***/
static void BuildLineTable (ctx, position)
TextSWContext *ctx;
TTextPosition position;
{
int x, y, width, realW, realH, line, lines;
TTextPosition startPos, endPos;
int rebuild;
TTextBlock text;
rebuild = (position != ctx->lt.top);
lines = (*(ctx->sink->maxLines)) (ctx->sink, ctx->height);
if (ctx->lt.entry != NULL && lines != ctx->lt.lines) {
free((char *) ctx->lt.entry);
ctx->lt.entry = NULL;
}
if (ctx->lt.entry == NULL) {
ctx->lt.entry =
(LineTableEntry *) Tmalloc(sizeof(LineTableEntry) * (lines + 1));
for (line = 0; line < lines; line++) {
ctx->lt.entry[line].position = 0;
ctx->lt.entry[line].y = 0;
}
rebuild = TRUE;
}
else
lines = ctx->lt.lines;
if (rebuild) {
ctx->lt.top = position;
ctx->lt.lines = lines;
startPos = position;
y = yMargin;
for (line = 0; line <= ctx->lt.lines; line++) {
x = ctx->leftmargin;
ctx->lt.entry[line].x = x;
ctx->lt.entry[line].y = y;
ctx->lt.entry[line].position = startPos;
width = ctx->width - x;
/** find the position - will read more source if necessary **/
(*(ctx->sink->findPosition)) (ctx->sink, ctx->source, startPos, x,
width, (ctx->options & wordBreak),
&endPos, &realW, &realH);
/** if not using word break -> keep reading until hit \n **/
if (!(ctx->options & wordBreak)) {
(*(ctx->source->read)) (ctx->source, startPos, &text, 1);
if (text.ptr[0] != '\n')
startPos = (*(ctx->source->scan)) (ctx->source, startPos,
charSelection, right, ctx->s.not_in_word);
endPos = (*(ctx->source->scan))
(ctx->source,
(*(ctx->source->scan)) (ctx->source, startPos,
lineSelection, right, ctx->s.not_in_word),
charSelection, right, ctx->s.not_in_word);
}
ctx->lt.entry[line].endX = realW + x;
startPos = endPos;
y = y + realH;
}
}
}
static void ForceBuildLineTable (ctx)
TextSWContext *ctx;
{
TTextPosition position;
position = ctx->lt.top;
ctx->lt.top++; /* ugly, but it works -- sets the rebuild boolean*/
BuildLineTable(ctx, position);
}
#ifdef SCROLLBAR
static void SetScrollBar(ctx)
TextSWContext *ctx;
{
float first, last;
int lastPos;
if (ctx->sbar) {
lastPos = (*(ctx->source->getLastPos))(ctx->source);
if (lastPos > 0) {
first = ctx->lt.top * 100.0 / lastPos; /* Just an approximation */
last = ctx->lt.entry[ctx->lt.lines].position * 100.0 / lastPos;
}
else {
first = 0.0;
last = 100.0;
}
TSetScrollBarPercentages(ctx->sbar, first, last - first);
}
}
static int ScrollUpDownProc (sbar, w, pix)
Window sbar, w;
int pix;
{
TextSWContextPtr ctx;
int apix, line, target;
TTextPosition pos;
if (FindEntry(w, myContext, &ctx) != ERRNONE)
return;
apix = abs(pix);
for (line = 1;
line < ctx->lt.lines && apix > ctx->lt.entry[line + 1].y;
line++);
if (pix >= 0) {
if (ctx->lt.entry[line].position > 0) {
BuildLineTable(ctx, ctx->lt.entry[line].position);
TMoveArea(ctx->w, ctx->leftmargin, ctx->lt.entry[line].y,
ctx->leftmargin, ctx->lt.entry[0].y, 9999, 9999);
SetScrollBar(ctx);
}
}
else {
target = ctx->lt.top;
while (ctx->lt.top > 0 && ctx->lt.entry[line].position > target) {
pos = ctx->lt.top - 1;
if (pos > 0)
pos--;
pos = (*(ctx->source->scan))(ctx->source, pos, lineSelection, left,
ctx->s.not_in_word);
BuildLineTable(ctx, pos);
}
if (ctx->lt.entry[line].position == target) {
TMoveArea(ctx->w, ctx->leftmargin,
ctx->lt.entry[0].y - ctx->lt.entry[line].y,
ctx->leftmargin, 0, 9999, 9999);
SetScrollBar(ctx);
}
else
DisplayTextSW(ctx);
}
}
static int ThumbProc (sbar, w, where)
Window sbar, w;
float where;
{
TextSWContextPtr ctx;
TTextPosition position, lastPos;
if (FindEntry(w, myContext, &ctx) != ERRNONE) return;
lastPos = (*(ctx->source->getLastPos))(ctx->source);
position = (where / 100.0) * lastPos;
if (position >= lastPos)
position = lastPos - 1;
position = (*(ctx->source->scan))(ctx->source, position, lineSelection, left,
ctx->s.not_in_word);
BuildLineTable(ctx, position);
DisplayTextSW(ctx);
}
#endif SCROLLBAR
/***
*** This routine will replace the text from pos1 to pos2 in a source.
*** It will return the values updateFrom and updateTo, which are the
*** bytes that need to be redisplayed.
***/
static ReplaceText (ctx, pos1, pos2, text, updateFrom, updateTo)
TextSWContext *ctx;
TTextPosition pos1, pos2; /* update from pos1 to pos2
/* NOTE: there values determine whether it is
/* text insertion or text replacement */
TTextBlock *text; /* new text to use */
TTextPosition *updateFrom, *updateTo; /* RETURNED: what to redisplay */
/* NOTE:
/* it is illegal to call this routine unless there is a valid line table!*/
{
int i, x, y, delta, realW, realH, line, width, visible;
TTextPosition startPos, endPos;
TTextBlock text2;
endPos = pos1;
line = LineForPosition(ctx, pos1);
delta = (*(ctx->source->replace))(ctx->source, pos1, pos2, text);
/*** fixup all line table entries and selection for edit */
for (i = line + 1; i < ctx->lt.lines + 1; i++) {
ctx->lt.entry[i].position = ctx->lt.entry[i].position + delta;
}
/*** want to update from the begining of the word to the left of the
/*** starting position. ***/
if (text->length != 0)
*updateFrom = (*(ctx->source->scan))(ctx->source, pos1,
wordSelection, left, ctx->s.not_in_word);
else
*updateFrom = pos1;
if (*updateFrom > ctx->lt.entry[0].position)
(*updateFrom)--;
/*** now that we know where to start from, check to see if it is in the
*** line table. (ie. visible) ***/
startPos = *updateFrom;
visible = LineAndXYForPosition(ctx, startPos, &line, &x, &y);
if (visible) {
for (i = line; i < ctx->lt.lines; i++) {/* fixup line table */
width = ctx->width - ctx->leftmargin - x;
(*(ctx->sink->findPosition)) (ctx->sink, ctx->source, startPos, x,
width, (ctx->options & wordBreak),
&endPos, &realW, &realH);
/** if not using workbreak -- find the \n **/
if (!(ctx->options & wordBreak)) {
(*(ctx->source->read))(ctx->source, startPos, &text2, 1);
if (text2.ptr[0] != '\n')
startPos = (*(ctx->source->scan))(ctx->source, startPos,
charSelection, right, ctx->s.not_in_word);
endPos = (*(ctx->source->scan))(ctx->source,
(*(ctx->source->scan))(ctx->source, startPos,
lineSelection, right, ctx->s.not_in_word),
charSelection, right, ctx->s.not_in_word);
}
ctx->lt.entry[i].endX = realW + x; /** ending x pixel in line */
ctx->lt.entry[i + 1].y = realH + ctx->lt.entry[i].y;
if ((endPos > pos1) && (endPos == ctx->lt.entry[i + 1].position)
&& (endPos == ctx->lt.entry[i + 2].position))
break;
ctx->lt.entry[i + 1].position = endPos;
startPos = endPos;
x = ctx->lt.entry[i + 1].x;
}
}
*updateTo = endPos;
return delta;
}
/***
*** change the text source.
***/
static void NewTextSource(ctx, source, startPos)
TextSWContext *ctx;
TTextSource *source;
TTextPosition startPos;
{
ctx->source = source;
ctx->lt.top = startPos;
ctx->s.left = ctx->s.right = 0;
ctx->i.position = startPos;
ForceBuildLineTable(ctx);
DisplayTextSW(ctx);
}
/***
*** This routine will Display text in the window assocated with ctx,
*** from pos1 to pos2 (byte offsets), and will highlight the text if
*** required.
***/
static void DisplayText(ctx, pos1, pos2, highlight)
TextSWContext *ctx;
TTextPosition pos1, pos2;
int highlight;
/* NOTE:
/* it is illegal to call this routine unless there is a valid line table!*/
{
int x, y, line, i, height, visible;
TTextPosition startPos, endPos;
if (pos1 < ctx->lt.top) pos1 = ctx->lt.top;
visible = LineAndXYForPosition(ctx, pos1, &line, &x, &y);
if (!visible)
return;
startPos = pos1;
for (i = line; i < ctx->lt.lines; i++) {
if (pos2 < ctx->lt.entry[i + 1].position)
endPos = pos2;
else
endPos = ctx->lt.entry[i + 1].position;
if (endPos > startPos)
(*(ctx->sink->display)) (
ctx->sink, ctx->source, ctx->w, x, y,
startPos, endPos, highlight);
startPos = endPos;
height = ctx->lt.entry[i + 1].y - ctx->lt.entry[i].y;
XPixSet(ctx->w, ctx->lt.entry[i].endX, y, 999, height, WhitePixel);
x = ctx->leftmargin;
y = ctx->lt.entry[i + 1].y;
if ((endPos == pos2) &&
(endPos != (*(ctx->source->getLastPos)) (ctx->source)))
break;
}
}
/***
*** If 2 or more windows may not have hightlighted text in more than 1 of
*** the windows, they have "mutually exclusive selection" (this is determined
*** at create time). When one window hightlights, the hightlighting in
*** the other windows must be turned off. This routine turns the other
*** highlighting off.
***/
static void mutual_exclusion_selection(ctx)
TextSWContext *ctx;
{
TextSWContext *previous_ctx;
if ((window_with_selection != NULL) && (window_with_selection != ctx->w))
/*** get the entry of the window that had the hightlighting ***/
if (FindEntry(window_with_selection, myContext, &previous_ctx)
== ERRNONE) {
/*** turn the hightlighting off ***/
DisplayText(previous_ctx, previous_ctx->s.left,
previous_ctx->s.right, FALSE);
previous_ctx->s.left = previous_ctx->s.right = 0;
}
/*** save the window with the new highlighting ***/
window_with_selection = ctx->w;
}
/***
*** This window performs the selection based upon hitting the
*** left mouse button (for right handers). It will hightlight
*** either by char, word, or eoln.
***/
static void DoSelection (ctx, position, time, motion)
TextSWContext *ctx;
TTextPosition position; /*** position where mouse was pressed ***/
unsigned short time;
int motion;
{
int delta, newLeft, newRight;
enum SelectionType newType;
if (ctx->i.type != none)
InsertCursor(ctx, off);
/**** mary commented this out. Currently not using double clicks ***/
/* delta = (time < ctx->s.time) ? ctx->s.time - time : time - ctx->s.time;
if (motion == TRUE)
newType = ctx->s.type;
else {
if ((delta < 50) && ((position >= ctx->s.left)
&& (position <= ctx->s.right)))/* multi-click event */
/* switch (ctx->s.type) {
case charSelection:
newType = wordSelection;
break;
case wordSelection:
newType = lineSelection;
break;
case lineSelection:
newType = allSelection;
break;
case allSelection:
newType = charSelection;
break;
}
else /* single-click event */
/* newType = charSelection;/* fool into Char selection */
/* } */
/*** end of commenting out ---- mary ***/
/** for now, newType is always what was passed in at create time - mary **/
newType = ctx->s.type;
/*** find the left and right positions. ***/
if (newType == charSelection) {
newLeft = position;
newRight = (*(ctx->source->scan))(ctx->source, position, newType,
right, ctx->s.not_in_word);
} else {
newLeft = (*(ctx->source->scan))(ctx->source, position, newType, left,
ctx->s.not_in_word);
newRight = (*(ctx->source->scan))(ctx->source, position, newType,
right, ctx->s.not_in_word);
}
/*** do the udpate
*** 1) if mouse clicked out of source range, make s.left = s.right
*** 2) only update insert position if insertion type is "edit"
*** 3) redisplay the old hightlighted text and new hightlighted text.
***/
if ((newLeft != ctx->s.left) || (newRight != ctx->s.right)
|| (newType != ctx->s.type)) {
DisplayText(ctx, ctx->s.left, ctx->s.right, FALSE);
ctx->s.type = newType;
ctx->s.left = newLeft;
if (newRight > (*(ctx->source->getLastPos))(ctx->source))
ctx->s.right = newLeft;
else
ctx->s.right = newRight;
DisplayText(ctx, ctx->s.left, ctx->s.right, TRUE);
if (ctx->i.type == edit)
ctx->i.position = ctx->s.right;
}
if (ctx->i.type != none)
InsertCursor(ctx, on);
/* ctx->s.time = time; */
}
static void ExtendSelection (ctx, position)
TextSWContext *ctx;
TTextPosition position;
{
TTextPosition newPos;
if (ctx->i.type != none)
InsertCursor(ctx, off);
if (position >= ctx->s.right) {
newPos = (*(ctx->source->scan))(ctx->source, position, ctx->s.type, right,
ctx->s.not_in_word);
DisplayText(ctx, ctx->s.right, newPos, TRUE);
ctx->s.right = newPos;
}
else if (position < ctx->s.left) {
newPos = (*(ctx->source->scan))(ctx->source, position, ctx->s.type, left,
ctx->s.not_in_word);
DisplayText(ctx, newPos, ctx->s.left, TRUE);
ctx->s.left = newPos;
}
else /* inside selection - determine which end */
if (position >= ctx->s.left+((ctx->s.right-ctx->s.left)/2)) {
newPos = (*(ctx->source->scan))(ctx->source, position, ctx->s.type,
right, ctx->s.not_in_word);
DisplayText(ctx, newPos, ctx->s.right, FALSE);
ctx->s.right = newPos;
}
else {
newPos = (*(ctx->source->scan))(ctx->source, position, ctx->s.type, left,
ctx->s.not_in_word);
DisplayText(ctx, ctx->s.left, newPos, FALSE);
ctx->s.left = newPos;
}
if (ctx->i.type != append)
ctx->i.position = ctx->s.right;
if (ctx->i.type != none)
InsertCursor(ctx, on);
}
#ifdef PASTESELECT
static PasteSelection(ctx, position)
TextSWContext *ctx;
TTextPosition position;
{
TTextPosition origpos, startPos, endPos, updateFrom, updateTo, f, t;
TTextBlock text;
int delta;
if (position > ctx->s.left && position < ctx->s.right)
return;
DisplayText(ctx, ctx->s.left, ctx->s.right, FALSE);
startPos = ctx->s.left;
updateFrom = 99999;
updateTo = 0;
origpos = position;
while (startPos < ctx->s.right) {
startPos = (*(ctx->source->read))(ctx->source, startPos, &text,
ctx->s.right - startPos);
/** paste in the new text **/
delta = ReplaceText(ctx, position, position, &text, &f, &t);
if (f < updateFrom)
updateFrom = f;
if (t > updateTo)
updateTo = t;
position += delta;
if (ctx->s.left >= origpos) {
startPos += delta;
ctx->s.right += delta;
}
}
ctx->i.position = position + 1;
DisplayText(ctx, updateFrom, updateTo, FALSE);
ctx->s.left = origpos;
ctx->s.right = position;
DisplayText(ctx, ctx->s.left, ctx->s.right, TRUE);
if (ctx->i.type != none)
InsertCursor(ctx, on);
}
#endif PASTESELECT
static KillSelection(ctx)
TextSWContext *ctx;
{
TTextBlock text;
TTextPosition updateFrom, updateTo;
int i;
if (ctx->i.position >= ctx->s.left && ctx->i.position <= ctx->s.right)
ctx->i.position = ctx->s.left;
text.length = 0;
i = ReplaceText(ctx, ctx->s.left, ctx->s.right, &text,
&updateFrom, &updateTo);
if (ctx->i.position > ctx->s.left)
ctx->i.position -= i;
ctx->s.left = ctx->s.right = 0;
DisplayText(ctx, updateFrom, updateTo, FALSE);
}
static void ClearWindow (ctx)
TextSWContext *ctx;
{
XPixSet(ctx->w, 0, 0, 9999, 9999, WhitePixel);
}
static DisplayTextSW (ctx)
TextSWContext *ctx;
{
ClearWindow(ctx);
BuildLineTable(ctx, ctx->lt.top);
DisplayText(ctx, ctx->lt.top, ctx->s.left, FALSE);
DisplayText(ctx, max(ctx->s.left, ctx->lt.top), ctx->s.right, TRUE);
DisplayText(ctx, max(ctx->s.right, ctx->lt.top),
(*(ctx->source->getLastPos))(ctx->source), FALSE);
if (ctx->i.type != none)
InsertCursor(ctx, on);
}
CheckResizeHeight(ctx)
TextSWContext *ctx;
{
TTextPosition endPos;
int visible,line;
WindowBox rbox, abox;
if (ctx->options & resizeHeight) {
endPos = (*(ctx->source->getLastPos))(ctx->source);
visible = IsPositionVisible(ctx, endPos);
line = LineForPosition(ctx, endPos);
if (visible)
line = LineForPosition(ctx, endPos);
else
line = ctx->lt.lines;
if (line + 1 != ctx->lt.lines) {
#ifdef SCROLLBAR
rbox.x = 0;
rbox.y = 0;
rbox.w = ctx->width;
rbox.h = (*(ctx->sink->maxHeight)) (ctx->sink, line + 1)
+ (2 * yMargin) + 2;
TMakeGeometryRequest(ctx->w, resize, &rbox, &abox);
#endif
}
}
}
/**
** This routine handles a text key (as opposed to a mouse button)
** being hit.
**/
static void ProcessTextKey (event, ctx)
XEvent *event;
TextSWContext *ctx;
{
int nbytes;
TTextPosition updateFrom, updateTo, endPos;
TTextBlock text;
text.ptr = XLookupMapping(event, &nbytes);
if (nbytes == 0) return;
text.length = nbytes;
if (!(ctx->options & editable)) {
XFeep(0);
return;
}
if (ctx->i.type != none)
InsertCursor(ctx, off);
DisplayText(ctx, ctx->s.left, ctx->s.right, FALSE);
switch (text.ptr[0]) {
case BS:
text.length = 0;
if (ctx->i.position > 0) {
endPos = ctx->i.position;
ctx->i.position = (*(ctx->source->scan))(ctx->source,
ctx->i.position - 1, charSelection, left,
ctx->s.not_in_word);
ReplaceText(ctx, ctx->i.position, endPos, &text,
&updateFrom, &updateTo);
}
break;
case DEL:
text.length = -1;
if (ctx->i.position > 0) {
endPos = ctx->i.position;
/** deleting the first character is a special case **/
if (ctx->i.position == 1)
ctx->i.position = 0;
else
ctx->i.position = (*(ctx->source->scan))(ctx->source,
ctx->i.position - 1, charSelection, left,
ctx->s.not_in_word) + 1;
ReplaceText(ctx, ctx->i.position, endPos, &text,
&updateFrom, &updateTo);
}
break;
case '\014': /* ^L */
ForceBuildLineTable(ctx);
DisplayTextSW(ctx);
return;
case CR:
text.ptr[0] = '\n';
ReplaceText(ctx, ctx->i.position, ctx->i.position, &text,
&updateFrom, &updateTo);
for (; text.length > 0; text.length--)
ctx->i.position =
(*(ctx->source->scan))(ctx->source, ctx->i.position,
charSelection, right, ctx->s.not_in_word);
break;
default:
ReplaceText(ctx, ctx->i.position, ctx->i.position, &text,
&updateFrom, &updateTo);
for (; text.length > 0; text.length--)
ctx->i.position =
(*(ctx->source->scan))(ctx->source, ctx->i.position,
charSelection, right, ctx->s.not_in_word);
break;
}
DisplayText(ctx, updateFrom, updateTo, FALSE);
DisplayText(ctx, ctx->s.left, ctx->s.right, TRUE);
if (ctx->i.type != none)
InsertCursor(ctx, on);
CheckResizeHeight(ctx);
/*** if the text is notify, call the user routine **/
if (index(ctx->notify.symbols, text.ptr[0]))
(*(ctx->notify.routine)) (ctx->notify.tag);
}
/**
** This routine handles a user hitting a mouse button
**/
static void ProcessTextButtons (event, ctx)
XEvent *event;
TextSWContext *ctx;
{
Window w, subW;
int x, y;
TTextPosition position;
XButtonEvent * buttonEvent;
int state;
Status status;
Cursor cursor;
w = event->window;
buttonEvent = (XButtonEvent *) event;
switch (event->type) {
case ButtonPressed:
case MouseMoved:
position = PositionForXY(ctx, buttonEvent->x, buttonEvent->y);
if ( (position > 0)
&& (position < (*(ctx->source->getLastPos))(ctx->source))
&& (buttonEvent->x > ctx->lt.entry[LineForPosition(ctx,
position-1)].endX))
position--;
if (event->type == ButtonPressed) {
switch (buttonEvent->detail & ValueMask) {
case LeftButton:
DoSelection(ctx, position, buttonEvent->time, FALSE);
if (ctx->s.mutual_exclusion)
mutual_exclusion_selection(ctx);
break;
case MiddleButton:
if (buttonEvent->detail & ShiftMask)
KillSelection(ctx);
#ifdef PASTESELECT
else
PasteSelection(ctx, position);
#endif
break;
case RightButton:
ExtendSelection(ctx, position);
break;
}
#ifdef CURSORS
cursor = GetCursor("left_ptr");
#else
cursor = XCreateCursor(left_ptr_width, left_ptr_height,
left_ptr_bits, left_ptr_mask_bits,
left_ptr_x_hot, left_ptr_y_hot,
BlackPixel, WhitePixel, GXcopy);
#endif
status = TGrabMouse(w, cursor, buttonMask);
}
else { /* must be mouse motion */
state = ((XMouseMovedEvent *) event)->detail;
if (state & LeftMask) {
DoSelection(ctx, position, buttonEvent->time, TRUE);
if (ctx->s.mutual_exclusion)
mutual_exclusion_selection(ctx);
} else
if (state & RightMask)
ExtendSelection(ctx, position);
}
break;
case ButtonReleased:
TUngrabMouse();
break;
}
}
/***
*** handles expose region event.
***/
static ProcessExposeRegion(event, ctx)
XExposeRegionEvent *event;
TextSWContextPtr ctx;
{
TTextPosition pos1, pos2, resultend;
int line, y;
LineTableEntryPtr entry;
/** figure out starting line that was exposed **/
line = LineForPosition(ctx, PositionForXY(ctx, event->x, event->y));
while (line < ctx->lt.lines && ctx->lt.entry[line + 1].y < event->y)
line++;
while (line < ctx->lt.lines) {
entry = &(ctx->lt.entry[line]);
if (entry->y >= event->y + event->height)
break;
(*(ctx->sink->resolve)) (ctx->sink, ctx->source, entry->position,
entry->x, event->x - entry->x, &pos1, &resultend);
(*(ctx->sink->resolve)) (ctx->sink, ctx->source, entry->position,
entry->x, event->x + event->width - entry->x, &pos2,
&resultend);
pos2++;
if (pos1 < ctx->s.right && pos2 > ctx->s.left) {
DisplayText(ctx, pos1, ctx->s.left, FALSE);
DisplayText(ctx, max(pos1, ctx->s.left), min(pos2, ctx->s.right),
TRUE);
DisplayText(ctx, ctx->s.right, pos2, FALSE);
}
else
DisplayText(ctx, pos1, pos2, FALSE);
line++;
}
if (ctx->i.type != none)
InsertCursor(ctx, on);
}
/**
** This routine handles all text sub window events
**/
static int ProcessTextSWEvent (event)
XEvent *event;
{
TextSWContext *ctx;
int err, returnCode;
WindowInfo info;
err = FindEntry(event->window, myContext, &ctx);
if (err != ERRNONE)
return(NOTHANDLED);
returnCode = PROCESSED;
switch (event->type) {
case ButtonPressed:
case ButtonReleased:
case MouseMoved:
ProcessTextButtons(event, ctx);
break;
case KeyPressed:
ProcessTextKey(event, ctx);
break;
case ResizeWindow:
ctx->width = ((XExposeWindowEvent *) event)->width;
ctx->height = ((XExposeWindowEvent *) event)->height;
ForceBuildLineTable(ctx);
break;
case ExposeWindow:
if (ctx->width != ((XExposeWindowEvent *) event)->width ||
ctx->height != ((XExposeWindowEvent *) event)->height) {
ctx->width = ((XExposeWindowEvent *) event)->width;
ctx->height = ((XExposeWindowEvent *) event)->height;
ForceBuildLineTable(ctx);
} else
if (event->subwindow == 0) DisplayTextSW(ctx);
break;
case ExposeRegion:
ProcessExposeRegion((XExposeRegionEvent *) event, ctx);
break;
case ExposeCopy:
break; /* work already done by ExposeRegion events */
default:
returnCode = 1;
}
return(returnCode);
}
/***
*** Given a window context and a byte offset into the source, this routine
*** will make the byte offset the starting position of the displayed text.
***/
static void TextReposition(ctx, startPos)
TextSWContext *ctx;
TTextPosition startPos;
{
TTextBlock text;
ctx->lt.top = (*(ctx->source->scan))(ctx->source, startPos,
lineSelection, left, ctx->s.not_in_word);
ctx->s.left = ctx->s.right = 0;
ForceBuildLineTable(ctx);
DisplayTextSW(ctx);
}
/***
*** highlight a region of text.
***/
static void HighlightText(ctx, pos)
TextSWContext *ctx;
TTextPosition *pos;
{
TTextPosition nleft, nright;
nleft = pos[0];
nright = pos[1] + 1;
if (nleft < ctx->s.left)
DisplayText(ctx, nleft, min(nright, ctx->s.left), TRUE);
if (nleft > ctx->s.left)
DisplayText(ctx, ctx->s.left, min(nleft, ctx->s.right), FALSE);
if (nright < ctx->s.right)
DisplayText(ctx, max(nright, ctx->s.left), ctx->s.right, FALSE);
if (nright > ctx->s.right)
DisplayText(ctx, max(ctx->s.right, nleft), nright, TRUE);
ctx->s.left = nleft;
ctx->s.right = nright;
}
/***
*** This routine passes back the string that is currently selected for
*** a given window. If the window passed in is part of a mutually exclusive
*** set of windows, the routine bassed back the string that is currently
*** selected for the set (ie. the selected string may be from a different
*** window)
***/
static char * GetHighlightText(ctx)
TextSWContext *ctx;
{
char *result;
TTextBlock text;
TTextPosition end, nend;
/*** find the ctx structure of window with text selection ***/
if (ctx->s.mutual_exclusion)
if (FindEntry(window_with_selection, myContext,&ctx) != ERRNONE)
return 0;
/*** get the text and put it into "result" ***/
result = (char *) Tmalloc(ctx->s.right - ctx->s.left +1);
end = (*(ctx->source->read))(ctx->source, ctx->s.left, &text,
ctx->s.right - ctx->s.left);
strncpy(result, text.ptr, ctx->s.right - ctx->s.left);
result[ ctx->s.right - ctx->s.left ] = '\0';
while (end < ctx->s.right) {
nend = (*(ctx->source->read)) (ctx->source, end, &text,
ctx->s.right - end);
strncat(result, text.ptr, ctx->s.right - end);
end = nend;
}
return result;
}
/***
*** This routine will replace text in within a source.
*** The starting and ending position will determine whether or not to
*** insert the text or to write over the older text.
*** NOTE: This does nothing on a regular DiskSource.
***/
static void ApplicationReplacesText(ctx, replace)
TextSWContext *ctx;
TTextReplace *replace;
{
TTextPosition updateFrom, updateTo;
if (ctx->i.type != none)
InsertCursor(ctx, off);
ReplaceText(ctx, replace->startPos, replace->endPos, &replace->text,
&updateFrom, &updateTo);
/*** set the insert position ***/
if (ctx->i.type == append)
ctx->i.position = (*(ctx->source->getLastPos))(ctx->source);
else {
ctx->i.position = replace->startPos;
for (; replace->text.length > 0; replace->text.length--)
ctx->i.position = (*(ctx->source->scan))(ctx->source,
ctx->i.position, charSelection, right,
ctx->s.not_in_word);
}
/*** display the text ****/
if (updateFrom < ctx->s.right && updateTo > ctx->s.left) {
DisplayText(ctx, updateFrom, ctx->s.left, FALSE);
DisplayText(ctx, max(updateFrom, ctx->s.left),
min(updateTo, ctx->s.right), TRUE);
DisplayText(ctx, ctx->s.right, updateTo, FALSE);
} else
DisplayText(ctx, updateFrom, updateTo, FALSE);
if (ctx->i.type != none)
InsertCursor(ctx, on);
}
/***
*** This routine will unhighlight the text for a given window. If the
*** window is part of a mutually exclusive set, then the hightlighted
*** text from the set will be unlighthighted (ie. It may be found in a
*** different window).
***/
static UnhighlightText(ctx)
TextSWContext *ctx;
{
/*** find the ctx structure with the selected text ***/
if (ctx->s.mutual_exclusion)
if (FindEntry(window_with_selection, myContext,&ctx) != ERRNONE)
return 0;
DisplayText(ctx, ctx->s.left, ctx->s.right, FALSE);
ctx->s.left = ctx->s.right = 0;
}
/***
*** This routine lets the application change the insertion position.
*** It turns off the old position, and turns on the new position.
***/
static setInsertPos(ctx, pos)
TextSWContext *ctx;
TTextPosition pos;
{
if (ctx->i.type != none)
InsertCursor(ctx, off);
ctx->i.position = pos;
if (ctx->i.type != none)
InsertCursor(ctx, on);
}
/***
*** routine to let the application change the options on the text window.
***/
ChangeTextOptions(ctx, newOptions)
TextSWContext *ctx;
short newOptions;
{
/*** this needs work ----- */
/*** for now, only let them change editting status ***/
if (newOptions & editable) {
ctx->i.type = (enum InsertionType) (*(ctx->source->getEditType))();
ctx->i.position = 0;
if (ctx->i.type != none)
InsertCursor(ctx, on);
ctx->options = ctx->options | editable;
}
}
/*
-------------------- Public routines ----------------------------
*/
/***
*** Given a window and an argument list, this routine will return the
*** corresponding values to each argument defined.
***/
Status TGetTextAttr(tw, arglist)
Window tw; /** tool window **/
Targ *arglist;
{
TextSWContext *ctx;
WindowInfo info;
int error;
error = FindEntry(tw, myContext, &ctx);
if (error != ERRNONE)
return(NOTHANDLED);
/***
*** Parse input parameters.
***/
while (arglist->name) {
switch (arglist->name) {
case T_TEXT_TOP:
arglist->data = (caddr_t) ctx->lt.top;
break;
case T_TEXT_SEL_TYPE:
arglist->data = (caddr_t) ctx->s.type;
break;
case T_TEXT_SEL_MUTUAL_EXCLUDE:
arglist->data = (caddr_t) ctx->s.mutual_exclusion;
break;
case T_TEXT_OPTIONS:
arglist->data = (caddr_t) ctx->options;
break;
case T_TEXT_LEFT_MARGIN:
arglist->data = (caddr_t) ctx->leftmargin;
break;
case T_TEXT_INSERT_POS:
arglist->data = (caddr_t) ctx->i.position;
break;
case T_TEXT_WORD_DELIM:
arglist->data = (caddr_t) ctx->s.not_in_word;
break;
case T_TEXT_NOTIFY_SYMBOLS:
arglist->data = (caddr_t) ctx->notify.symbols;
break;
case T_TEXT_NOTIFY_ROUTINE:
arglist->data = (caddr_t) ctx->notify.routine;
break;
case T_TEXT_NOTIFY_TAG:
arglist->data = (caddr_t) ctx->notify.tag;
break;
case T_TEXT_FONT_INFO:
arglist->data = (caddr_t) ctx->sink;
break;
case T_TEXT_SOURCE:
arglist->data = (caddr_t) ctx->source;
break;
case T_TEXT_HIGHLIGHT:
arglist->data = (caddr_t) GetHighlightText(ctx);
break;
case T_TEXT_WIDTH:
XQueryWindow(ctx->w, &info);
arglist->data = (caddr_t) info.width;
break;
case T_TEXT_HEIGHT:
XQueryWindow(ctx->w, &info);
arglist->data = (caddr_t) info.height;
break;
case T_TEXT_BRWIDTH:
XQueryWindow(ctx->w, &info);
arglist->data = (caddr_t) info.bdrwidth;
break;
default:
break;
}
arglist++;
}
}
/***
*** Given a window and an argument list, this routine performs the necessary
*** operations to set the values of the defined arguments.
*** NOTE: the operations are performed in the order that the arguments
*** appear in the argument array.
***/
Status TSetTextAttr(tw, arglist)
Window tw; /** tool window **/
Targ *arglist;
{
TextSWContext *ctx;
WindowInfo info;
int error;
/***
*** Get the window context.
***/
error = FindEntry(tw, myContext, &ctx);
if (error != ERRNONE)
return(NOTHANDLED);
/***
*** Parse input parameters.
***/
while (arglist->name) {
switch (arglist->name) {
case T_TEXT_TOP:
TextReposition(ctx, (TTextPosition) arglist->data);
break;
case T_TEXT_SEL_TYPE:
ctx->s.type = (enum SelectionType) arglist->data;
break;
case T_TEXT_SEL_MUTUAL_EXCLUDE:
ctx->s.mutual_exclusion = (int) arglist->data;
break;
case T_TEXT_OPTIONS:
ChangeTextOptions(ctx, (short) arglist->data);
break;
case T_TEXT_INSERT_POS:
setInsertPos(ctx, (TTextPosition) arglist->data + 1);
break;
case T_TEXT_WORD_DELIM:
ctx->s.not_in_word = (char *) arglist->data;
break;
case T_TEXT_NOTIFY_SYMBOLS:
ctx->notify.symbols = (char *) arglist->data;
break;
case T_TEXT_NOTIFY_ROUTINE:
ctx->notify.routine = (int(*)()) arglist->data;
break;
case T_TEXT_NOTIFY_TAG:
ctx->notify.tag = (caddr_t) arglist->data;
break;
case T_TEXT_SOURCE:
NewTextSource(ctx, (TTextSource *) arglist->data, 0);
break;
case T_TEXT_HIGHLIGHT:
HighlightText(ctx, (int *) arglist->data);
break;
case T_TEXT_UNHIGHLIGHT:
UnhighlightText(ctx);
break;
case T_TEXT_REPLACE:
ApplicationReplacesText(ctx, (TTextReplace *) arglist->data);
break;
case T_TEXT_LEFT_MARGIN:
ctx->leftmargin = abs((short)arglist->data);
ForceBuildLineTable(ctx);
DisplayTextSW(ctx);
break;
case T_TEXT_WIDTH:
if ((int)arglist->data == 0) break;
XQueryWindow(ctx->w, &info);
XChangeWindow(ctx->w, abs((int)arglist->data), info.height);
break;
case T_TEXT_HEIGHT:
if ((int)arglist->data == 0) break;
XQueryWindow(ctx->w, &info);
XChangeWindow(ctx->w, info.width, abs((int)arglist->data));
break;
case T_TEXT_BRWIDTH:
break;
case T_TEXT_FONT_INFO:
break;
default:
break;
}
arglist++;
}
}
/***
*** Routine to set up the window context record, save the entry, and
*** set xevents that need to be caught.
***/
Window TCreateTextSW (pw, arglist)
Window pw; /** parent window **/
Targ *arglist;
{
TextSWContext *ctx;
int err;
int x, y, width, height, br_width;
if (initialized == 0) initialize();
ctx = (TextSWContext *) Tmalloc(sizeof(TextSWContext));
/***
*** set defaults
***/
ctx->i.position = 0;
ctx->lt.top = 0;
ctx->lt.entry = NULL;
ctx->s.left = 0;
ctx->s.right = 0;
ctx->s.type = charSelection;
ctx->s.not_in_word = "";
ctx->s.mutual_exclusion = 0;
ctx->i.type = none;
ctx->notify.symbols = "";
ctx->notify.routine = NULL;
ctx->notify.tag = NULL;
ctx->options = 0;
ctx->leftmargin = xMargin;
ctx->sbar = 0;
ctx->sink = defaultSink;
x = y = 0;
height = width = 200;
br_width = 2;
/***
*** Parse input parameters.
***/
while (arglist->name) {
switch (arglist->name) {
case T_TEXT_TOP:
ctx->lt.top = (TTextPosition) arglist->data;
break;
case T_TEXT_SEL_TYPE:
ctx->s.type = (enum SelectionType) arglist->data;
break;
case T_TEXT_SEL_MUTUAL_EXCLUDE:
ctx->s.mutual_exclusion = (int) arglist->data;
break;
case T_TEXT_OPTIONS:
ctx->options = (short) arglist->data;
ctx->i.type = (ctx->options & editable)
? (*(ctx->source->getEditType)) ()
: none;
break;
case T_TEXT_LEFT_MARGIN:
ctx->leftmargin = abs((short) arglist->data);
break;
case T_TEXT_INSERT_POS:
ctx->i.position = (TTextPosition) arglist->data;
break;
case T_TEXT_WORD_DELIM:
ctx->s.not_in_word = (char *) arglist->data;
break;
case T_TEXT_NOTIFY_SYMBOLS:
ctx->notify.symbols = (char *) arglist->data;
break;
case T_TEXT_NOTIFY_ROUTINE:
ctx->notify.routine = (int(*)()) arglist->data;
break;
case T_TEXT_NOTIFY_TAG:
ctx->notify.tag = (caddr_t) arglist->data;
break;
case T_TEXT_FONT_INFO:
ctx->sink = (TTextSink *)
TCreateAsciiSink((FontInfo *) arglist->data);
break;
case T_TEXT_SOURCE:
ctx->source = (TTextSource *) arglist->data;
break;
case T_TEXT_WIDTH:
width = abs((int)arglist->data);
break;
case T_TEXT_HEIGHT:
height = abs((int)arglist->data);
break;
case T_TEXT_BRWIDTH:
br_width = abs((int) arglist->data);
break;
case T_TEXT_HIGHLIGHT:
break;
default:
break;
}
arglist++;
}
if (ctx->source == NULL)
ctx->source = (TTextSource *) TCreateStringSource(" ", 1);
/*** create the window ***/
ctx->w = XCreateWindow(pw, x, y, width, height, br_width,
BlackPixmap, WhitePixmap);
err = SaveEntry(ctx->w, myContext, ctx);
TSetXEventDispatch(ctx->w, ProcessTextSWEvent, TEXT_EVENTS, 0);
return ctx->w;
}
/***
*** get rid of text sub window
***/
void TDestroyTextSW (w)
Window w;
{
TextSWContext *ctx;
int err;
err = FindEntry(w, myContext, &ctx);
if (err == ERRNONE) {
DeleteEntry(w, myContext);
if (w != ctx->w) {
DeleteEntry(ctx->w, myContext);
#ifdef SCROLLBAR
TUnarrangeWithScrollBars(w);
#endif
}
TDestroyWindow(w);
free(ctx);
}
}