|
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 - 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); } }