/*
* tkTextDisp.c --
*
* This module provides facilities to display text widgets. It is
* the only place where information is kept about the screen layout
* of text widgets.
*
* Copyright (c) 1992-1994 The Regents of the University of California.
* Copyright (c) 1994-1995 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* SCCS: @(#) tkTextDisp.c 1.114 96/09/05 09:59:43
*/
#include "tkInt.h"
#include "tkText.h"
/*
* The following structure describes how to display a range of characters.
* The information is generated by scanning all of the tags associated
* with the characters and combining that with default information for
* the overall widget. These structures form the hash keys for
* dInfoPtr->styleTable.
*/
typedef struct StyleValues {
* NULL means use widget background. */
* means draw solid. */
* foreground stuff. None means draw
* solid.*/
* line of each text line. */
* later display lines of each text line. */
* baseline of line. */
* text. */
* be NULL). */
* text. */
* One of tkTextCharUid, tkTextNoneUid,
* or tkTextWordUid. */
} StyleValues;
/*
* The following structure extends the StyleValues structure above with
* graphics contexts used to actually draw the characters. The entries
* in dInfoPtr->styleTable point to structures of this type.
*/
typedef struct TextStyle {
* referenced in Chunks. */
* means use widget background. */
* derived. */
* to delete entry. */
} TextStyle;
/*
* The following macro determines whether two styles have the same
* background so that, for example, no beveled border should be drawn
* between them.
*/
/*
* The following structure describes one line of the display, which may
* be either part or all of one line of the text.
*/
typedef struct DLine {
* that is displayed on this line. */
* display line, including a trailing space
* or newline that isn't actually displayed. */
int y; /* Y-position at which line is supposed to
* be drawn (topmost pixel of rectangular
* area occupied by line). */
* appears on display. -1 means line isn't
* currently visible on display and must be
* redrawn. This is used to move lines by
* scrolling rather than re-drawing. */
* pixels. */
* top of the line because of spacing
* options. This is included in height
* and baseline. */
* bottom of the line because of spacing
* options. This is included in height. */
* of those that are displayed on this
* line of the screen. */
* this window. The list is sorted in
* order from top to bottom. Note: the
* next DLine doesn't always correspond
* to the next line of text: (a) can have
* multiple DLines for one text line, and
* (b) can have gaps where DLine's have been
* deleted because they're out of date. */
} DLine;
/*
* Flag bits for DLine structures:
*
* HAS_3D_BORDER - Non-zero means that at least one of the
* chunks in this line has a 3D border, so
* it potentially interacts with 3D borders
* in neighboring lines (see
* DisplayLineBackground).
* NEW_LAYOUT - Non-zero means that the line has been
* re-layed out since the last time the
* display was updated.
* TOP_LINE - Non-zero means that this was the top line
* in the window the last time that the window
* was laid out. This is important because
* a line may be displayed differently if its
* at the top or bottom than if it's in the
* middle (e.g. beveled edges aren't displayed
* for middle lines if the adjacent line has
* a similar background).
* BOTTOM_LINE - Non-zero means that this was the bottom line
* in the window the last time that the window
* was laid out.
*/
/*
* Overall display information for a text widget:
*/
typedef struct TextDInfo {
* to TextStyles for this widget. */
* this widget, in order from top to bottom. */
* screen pixmaps onto screen. */
* in the window to another (scrolling):
* differs from copyGC in that we need to get
* GraphicsExpose events. */
int x; /* First x-coordinate that may be used for
* actually displaying line information.
* Leaves space for border, etc. */
int y; /* First y-coordinate that may be used for
* actually displaying line information.
* Leaves space for border, etc. */
* space for displaying lines. */
* space for displaying lines. */
* been drawn in the appropriate fashion for
* the portion of the window after the last
* line of the text. This field is used to
* figure out when to redraw part or all of
* the eof field. */
/*
* Information used for scrolling:
*/
* number of average-size characters off-screen
* to the left for a line with no left
* margin. */
* number of pixels off-screen to the left. */
* visible in window (length may exceed window
* size). If there's no wrapping, this will
* be zero. */
/* Most recent values reported to horizontal
* scrollbar; used to eliminate unnecessary
* reports. */
/* Most recent values reported to vertical
* scrollbar; used to eliminate unnecessary
* reports. */
/*
* The following information is used to implement scanning:
*/
* the window when the scan started. */
* occurred since scanMarkY was set. */
/*
* Miscellaneous information:
*/
* happens that invalidates information in
* DLine structures; if a redisplay
* is in progress, it will see this and
* abort the redisplay. This is needed
* because, for example, an embedded window
* could change its size when it is first
* displayed, invalidating the DLine that
* is currently being displayed. If redisplay
* continues, it will use freed memory and
* could dump core. */
* definitions. */
} TextDInfo;
/*
* In TkTextDispChunk structures for character segments, the clientData
* field points to one of the following structures:
*/
typedef struct CharInfo {
* will be numChars, not 4. THIS MUST BE
* THE LAST FIELD IN THE STRUCTURE. */
} CharInfo;
/*
* Flag values for TextDInfo structures:
*
* DINFO_OUT_OF_DATE: Non-zero means that the DLine structures
* for this window are partially or completely
* out of date and need to be recomputed.
* REDRAW_PENDING: Means that a when-idle handler has been
* scheduled to update the display.
* REDRAW_BORDERS: Means window border or pad area has
* potentially been damaged and must be redrawn.
* REPICK_NEEDED: 1 means that the widget has been modified
* in a way that could change the current
* character (a different character might be
* under the mouse cursor now). Need to
* recompute the current character before
* the next redisplay.
*/
/*
* The following counters keep statistics about redisplay that can be
* checked to see how clever this code is at reducing redisplays.
*/
* of the screen. */
/*
* Forward declarations for procedures defined later in this file:
*/
int *heightPtr));
int x));
TkTextIndex *indexPtr));
TkTextIndex *indexPtr));
TkTextIndex *indexPtr));
TkTextIndex *dstPtr));
int offset));
int maxX));
/*
*----------------------------------------------------------------------
*
* TkTextCreateDInfo --
*
* This procedure is called when a new text widget is created.
* Its job is to set up display-related information for the widget.
*
* Results:
* None.
*
* Side effects:
* A TextDInfo data structure is allocated and initialized and attached
* to textPtr.
*
*----------------------------------------------------------------------
*/
void
{
&gcValues);
dInfoPtr->newCharOffset = 0;
dInfoPtr->curPixelOffset = 0;
dInfoPtr->scanMarkChar = 0;
dInfoPtr->scanTotalScroll = 0;
dInfoPtr->dLinesInvalidated = 0;
}
/*
*----------------------------------------------------------------------
*
* TkTextFreeDInfo --
*
* This procedure is called to free up all of the private display
* information kept by this file for a text widget.
*
* Results:
* None.
*
* Side effects:
* Lots of resources get freed.
*
*----------------------------------------------------------------------
*/
void
{
/*
* Be careful to free up styleTable *after* freeing up all the
* DLines, so that the hash table is still intact to free up the
* style-related information from the lines. Once the lines are
* all free then styleTable will be empty.
*/
}
}
}
/*
*----------------------------------------------------------------------
*
* GetStyle --
*
* This procedure creates all the information needed to display
* text at a particular location.
*
* Results:
* The return value is a pointer to a TextStyle structure that
* corresponds to *sValuePtr.
*
* Side effects:
* A new entry may be created in the style table for the widget.
*
*----------------------------------------------------------------------
*/
static TextStyle *
* display information is wanted. */
{
unsigned long mask;
/*
* The variables below keep track of the highest-priority specification
* that has occurred for each of the various fields of the StyleValues.
*/
/*
* Find out what tags are present for the character, then compute
* a StyleValues structure corresponding to those tags (scan
* through all of the tags, saving information for the highest-
* priority tag).
*/
for (i = 0 ; i < numTags; i++) {
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
/*
* Use an existing style if there's one around that matches.
*/
(char *) &styleValues, &new);
if (!new) {
return stylePtr;
}
/*
* No existing style matched. Make a new one.
*/
mask = GCForeground;
}
} else {
}
}
return stylePtr;
}
/*
*----------------------------------------------------------------------
*
* FreeStyle --
*
* This procedure is called when a TextStyle structure is no longer
* needed. It decrements the reference count and frees up the
* space for the style structure if the reference count is 0.
*
* Results:
* None.
*
* Side effects:
* The storage and other resources associated with the style
* are freed up if no-one's still using it.
*
*----------------------------------------------------------------------
*/
static void
{
}
}
}
/*
*----------------------------------------------------------------------
*
* LayoutDLine --
*
* This procedure generates a single DLine structure for a display
* line whose leftmost character is given by indexPtr.
*
* Results:
* The return value is a pointer to a DLine structure desribing the
* display line. All fields are filled in and correct except for
* y and nextPtr.
*
* Side effects:
* Storage is allocated for the new DLine.
*
*----------------------------------------------------------------------
*/
static DLine *
* necessarily point to a character segment. */
{
* for line. */
* point, if any. */
* breakChunkPtr. */
* to right of best break point. */
* have been placed on the line yet. */
* style for first character in line. */
* margins) due to justification. */
* stop compiler warnings. */
* runs to the end of the text line. */
* contains a tab. */
* the previous tab stop. */
* include in this chunk. */
* style for first character on line. */
* tab stop. */
* lines with numChars > 0. Used to
* drop 0-sized chunks from the end
* of the line. */
/*
* Create and initialize a new DLine structure.
*/
dlPtr->y = 0;
/*
* Each iteration of the loop below creates one TkTextDispChunk for
* the new display line. The line will always have at least one
* chunk (for the newline character at the end, if there's nothing
* else available).
*/
lastChunkPtr = NULL;
noCharsYet = 1;
breakCharOffset = 0;
tabIndex = -1;
tabChunkPtr = NULL;
tabArrayPtr = NULL;
rMargin = 0;
tabSize = 0;
/*
* Find the first segment to consider for the line. Can't call
* TkTextIndexToSeg for this because it won't return a segment
* with zero size (such as the insertion cursor's mark).
*/
/* Empty loop body. */
}
offset = 0;
continue;
}
}
/*
* Save style information such as justification and indentation,
* up until the first character is encountered, then retain that
* information for the rest of the line.
*/
if (noCharsYet) {
if (wrapMode == tkTextNoneUid) {
} else {
- rMargin;
if (maxX < x) {
maxX = x;
}
}
}
/*
* See if there is a tab in the current chunk; if so, only
* layout characters up to (and including) the tab.
*/
gotTab = 0;
if (justify == TK_JUSTIFY_LEFT) {
char *p;
if (*p == '\t') {
gotTab = 1;
break;
}
}
}
}
chunkPtr->x = x;
chunkPtr);
if (code <= 0) {
if (code < 0) {
/*
* This segment doesn't wish to display itself (e.g. most
* marks).
*/
offset = 0;
continue;
}
/*
* No characters from this segment fit in the window: this
* means we're at the end of the display line.
*/
}
break;
}
noCharsYet = 0;
}
if (lastChunkPtr == NULL) {
} else {
}
if (chunkPtr->breakIndex > 0) {
}
break;
}
/*
* If we're at a new tab, adjust the layout for all the chunks
* pertaining to the previous tab. Also adjust the amount of
* space left in the line to account for space that will be eaten
* up by the tab.
*/
if (gotTab) {
if (tabIndex >= 0) {
}
tabIndex++;
break;
}
}
offset = 0;
}
}
if (noCharsYet) {
panic("LayoutDLine couldn't place any characters on a line");
}
/*
* We're at the end of the display line. Throw away everything
* after the most recent word break, if there is one; this may
* potentially require the last chunk to be layed out again.
*/
if (breakChunkPtr == NULL) {
/*
* This code makes sure that we don't accidentally display
* chunks with no characters at the end of the line (such as
* the insertion cursor). These chunks belong on the next
* line. So, throw away everything after the last chunk that
* has characters in it.
*/
}
while (1) {
break;
}
}
}
wholeLine = 0;
}
/*
* Make tab adjustments for the last tab stop, if there is one.
*/
}
/*
* Make one more pass over the line to recompute various things
* like its height, length, and total number of characters. Also
* modify the x-locations of chunks to reflect justification.
* If we're not wrapping, I'm not sure what is the best way to
* handle left and center justification: should the total length,
* for purposes of justification, be (a) the window width, (b)
* the length of the longest line in the window, or (c) the length
* of the longest line in the text? (c) isn't available, (b) seems
* weird, since it can change with vertical scrolling, so (a) is
* what is implemented below.
*/
if (wrapMode == tkTextNoneUid) {
}
if (justify == TK_JUSTIFY_LEFT) {
jIndent = 0;
} else if (justify == TK_JUSTIFY_RIGHT) {
} else {
}
}
}
}
if ((sValuePtr->borderWidth > 0)
}
}
} else {
}
} else {
}
if (wholeLine) {
} else {
}
/*
* Recompute line length: may have changed because of justification.
*/
return dlPtr;
}
/*
*----------------------------------------------------------------------
*
* UpdateDisplayInfo --
*
* This procedure is invoked to recompute some or all of the
* DLine structures for a text widget. At the time it is called
* the DLine structures still left in the widget are guaranteed
* to be correct except that (a) the y-coordinates aren't
* necessarily correct, (b) there may be missing structures
* (the DLine structures get removed as soon as they are potentially
* out-of-date), and (c) DLine structures that don't start at the
* beginning of a line may be incorrect if previous information in
* the same line changed size in a way that moved a line boundary
* (DLines for any info that changed will have been deleted, but
* not DLines for unchanged info in the same text line).
*
* Results:
* None.
*
* Side effects:
* Upon return, the DLine information for textPtr correctly reflects
* the positions where characters will be displayed. However, this
* procedure doesn't actually bring the display up-to-date.
*
*----------------------------------------------------------------------
*/
static void
{
return;
}
/*
* Delete any DLines that are now above the top of the window.
*/
}
/*
*--------------------------------------------------------------
* Scan through the contents of the window from top to bottom,
* recomputing information for lines that are missing.
*--------------------------------------------------------------
*/
y = dInfoPtr->y;
while (1) {
break;
}
/*
* There are three possibilities right now:
* (a) the next DLine (dlPtr) corresponds exactly to the next
* information we want to display: just use it as-is.
* (b) the next DLine corresponds to a different line, or to
* a segment that will be coming later in the same line:
* leave this DLine alone in the hopes that we'll be able
* to use it later, then create a new DLine in front of
* it.
* (c) the next DLine corresponds to a segment in the line we
* want, but it's a segment that has already been processed
* or will never be processed. Delete the DLine and try
* again.
*
* One other twist on all this. It's possible for 3D borders
* to interact between lines (see DisplayLineBackground) so if
* a line is relayed out and has styles with 3D borders, its
* neighbors have to be redrawn if they have 3D borders too,
* since the interactions could have changed (the neighbors
* don't have to be relayed out, just redrawn).
*/
/*
* Case (b) -- must make new DLine.
*/
if (tkTextDebug) {
/*
* Debugging is enabled, so keep a log of all the lines
* that were re-layed out. The test suite uses this
* information.
*/
}
} else {
}
}
} else {
/*
* DlPtr refers to the line we want. Next check the
* index within the line.
*/
/*
* Case (a) -- can use existing display line as-is.
*/
}
goto lineOK;
}
goto makeNewDLine;
}
/*
* Case (c) -- dlPtr is useless. Discard it and start
* again with the next display line.
*/
} else {
}
continue;
}
/*
* Advance to the start of the next line.
*/
dlPtr->y = y;
/*
* If we switched text lines, delete any DLines left for the
* old text line.
*/
}
}
}
/*
* It's important to have the following check here rather than in
* the while statement for the loop, so that there's always at least
* one DLine generated, regardless of how small the window is. This
* keeps a lot of other code from breaking.
*/
if (y >= maxY) {
break;
}
}
/*
* Delete any DLine structures that don't fit on the screen.
*/
/*
*--------------------------------------------------------------
* If there is extra space at the bottom of the window (because
* we've hit the end of the text), then bring in more lines at
* the top of the window, if there are any, to fill in the view.
*--------------------------------------------------------------
*/
if (y < maxY) {
/*
* Layout an entire text line (potentially > 1 display line),
* then link in as many display lines as fit without moving
* the bottom line out of the window. Repeat this until
* all the extra space has been used up or we've reached the
* beginning of the text.
*/
if (charsToCount == 0) {
lineNum--;
}
do {
} while ((charsToCount > 0)
/*
* Scan through the display lines from the bottom one up to
* the top one.
*/
if (spaceLeft < 0) {
break;
}
if (tkTextDebug) {
}
}
}
/*
* Now we're all done except that the y-coordinates in all the
* DLines are wrong and the top index for the text is wrong.
* Update them.
*/
y = dInfoPtr->y;
panic("Added too many new lines in UpdateDisplayInfo");
}
dlPtr->y = y;
}
}
/*
*--------------------------------------------------------------
* If the old top or bottom line has scrolled elsewhere on the
* screen, we may not be able to re-use its old contents by
* copying bits (e.g., a beveled edge that was drawn when it was
* at the top or bottom won't be drawn when the line is in the
* middle and its neighbor has a matching background). Similarly,
* if the new top or bottom line came from somewhere else on the
* screen, we may not be able to copy the old bits.
*--------------------------------------------------------------
*/
}
while (1) {
}
}
}
break;
}
}
/*
* Arrange for scrollbars to be updated.
*/
/*
*--------------------------------------------------------------
* Deal with horizontal scrolling:
* 1. If there's empty space to the right of the longest line,
* shift the screen to the right to fill in the empty space.
* 2. If the desired horizontal scroll position has changed,
* force a full redisplay of all the lines in the widget.
* 3. If the wrap mode isn't "none" then re-scroll to the base
* position.
*--------------------------------------------------------------
*/
}
}
}
if (dInfoPtr->newCharOffset < 0) {
dInfoPtr->newCharOffset = 0;
}
}
}
}
/*
*----------------------------------------------------------------------
*
* FreeDLines --
*
* This procedure is called to free up all of the resources
* associated with one or more DLine structures.
*
* Results:
* None.
*
* Side effects:
* Memory gets freed and various other resources are released.
*
*----------------------------------------------------------------------
*/
static void
* widget. */
* one to free (NULL means everything
* starting with firstPtr). */
int unlink; /* 1 means DLines are currently linked
* into the list rooted at
* textPtr->dInfoPtr->dLinePtr and
* they have to be unlinked. 0 means
* just free without unlinking. */
{
if (unlink) {
} else {
/* Empty loop body. */
}
}
}
chunkPtr = nextChunkPtr) {
}
}
}
}
/*
*----------------------------------------------------------------------
*
* DisplayDLine --
*
* This procedure is invoked to draw a single line on the
* screen.
*
* Results:
* None.
*
* Side effects:
* The line given by dlPtr is drawn at its correct position in
* textPtr's window. Note that this is one *display* line, not
* one *text* line.
*
*----------------------------------------------------------------------
*/
static void
* if dlPtr is the top line. */
* Caller must make sure it's large enough
* to hold line. */
{
int height, x;
/*
* First, clear the area of the line to the background color for the
* text widget.
*/
/*
* Next, draw background information for the whole line.
*/
/*
* Make another pass through all of the chunks to redraw the
* insertion cursor, if it is visible on this line. Must do
* it here rather than in the foreground pass below because
* otherwise a wide insertion cursor will obscure the character
* to its left.
*/
}
}
}
/*
* Make yet another pass through all of the chunks to redraw all of
* foreground information. Note: we have to call the displayProc
* even for chunks that are off-screen. This is needed, for
* example, so that embedded windows can be unmapped in this case.
* Conve
*/
/*
* Already displayed the insertion cursor above. Don't
* do it again here.
*/
continue;
}
/*
* Note: we have to call the displayProc even for chunks
* that are off-screen. This is needed, for example, so
* that embedded windows can be unmapped in this case.
* Display the chunk at a coordinate that can be clearly
* identified by the displayProc as being off-screen to
* the left (the displayProc may not be able to tell if
* something is off to the right).
*/
} else {
}
if (dInfoPtr->dLinesInvalidated) {
return;
}
}
/*
* Copy the pixmap onto the screen. If this is the last line on
* the screen then copy a piece of the line, so that it doesn't
* overflow into the border area. Another special trick: copy the
* padding area to the left of the line; this is because the
* insertion cursor sometimes overflows onto that area and we want
* to get as much of the cursor as possible.
*/
}
linesRedrawn++;
}
/*
*--------------------------------------------------------------
*
* DisplayLineBackground --
*
* This procedure is called to fill in the background for
* a display line. It draws 3D borders cleverly so that
* adjacent chunks with the same style (whether on the same
* line or different lines) have a single 3D border around
* the whole region.
*
* Results:
* There is no return value. Pixmap is filled in with background
* information for dlPtr.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static void
* is the top-most line in the window. */
* Caller must make sure it's large enough
* to hold line. Caller must also have
* filled it with the background color for
* the widget. */
{
* below the current one. NULL if we're to
* the left of or to the right of the chunks
* in the line. */
* same as chunkPtr2->nextPtr in the case
* where chunkPtr2 is NULL because the line
* is indented). */
* currently working on. */
* as it goes down, 0 means it slopes left
* as it goes down. */
* of its neighbor just to the left of
* the current x coordinate? */
* just to the right of the current x-coord? */
/*
* Pass 1: scan through dlPtr from left to right. For each range of
* chunks with the same style, draw the main background for the style
* plus the vertical parts of the 3D borders (the left and right
* edges).
*/
continue;
}
}
}
}
}
/*
* Pass 2: draw the horizontal bevels along the top of the line. To
* do this, scan through dlPtr from left to right while simultaneously
* scanning through the line just above dlPtr. ChunkPtr2 and nextPtr2
* refer to two adjacent chunks in the line above.
*/
leftXIn = 1;
}
/*
* Find the chunk in the previous line that covers leftX.
*/
break;
}
}
}
} else {
}
/*
* The chunk in our line is about to end. If its style
* changes then draw the bevel for the current style.
*/
}
leftXIn = 1;
/*
* If the chunk in the line above is also ending at
* the same point then advance to the next chunk in
* that line.
*/
goto nextChunk2;
}
}
break;
}
}
continue;
}
/*
* The chunk in the line above is ending at an x-position where
* there is no change in the style of the current line. If the
* style above matches the current line on one side of the change
* but not on the other, we have to draw an L-shaped piece of
* bevel.
*/
if (matchLeft && !matchRight) {
}
leftXIn = 0;
} else if (!matchLeft && matchRight
}
} else {
}
}
}
/*
* Pass 3: draw the horizontal bevels along the bottom of the line.
* This uses the same approach as pass 2.
*/
leftXIn = 0;
}
/*
* Find the chunk in the previous line that covers leftX.
*/
break;
}
}
}
} else {
}
}
leftXIn = 0;
goto nextChunk2b;
}
}
break;
}
}
continue;
}
if (matchLeft && !matchRight) {
}
leftXIn = 1;
} else if (!matchLeft && matchRight
}
} else {
}
}
}
}
/*
*----------------------------------------------------------------------
*
* DisplayText --
*
* This procedure is invoked as a when-idle handler to update the
* display. It only redisplays the parts of the text widget that
* are out of date.
*
* Results:
* None.
*
* Side effects:
* Information is redrawn on the screen.
*
*----------------------------------------------------------------------
*/
static void
{
* compiler warnings. */
/*
* The widget has been deleted. Don't do anything.
*/
return;
}
if (tkTextDebug) {
}
/*
* The widget has been deleted. Don't do anything.
*/
goto end;
}
goto doScrollbars;
}
if (tkTextDebug) {
}
/*
* The widget has been deleted. Don't do anything.
*/
goto end;
}
/*
* Choose a new current item if that is needed (this could cause
* and the loop, since the handlers could conceivably necessitate
* yet another current item calculation). The tkwin check is because
* the whole window could go away in the Tcl_Release call.
*/
goto end;
}
}
/*
* First recompute what's supposed to be displayed.
*/
dInfoPtr->dLinesInvalidated = 0;
/*
* See if it's possible to bring some parts of the screen up-to-date
* by scrolling (copying from other parts of the screen).
*/
continue;
}
/*
* This line is already drawn somewhere in the window so it only
* needs to be copied to its new location. See if there's a group
* of lines that can all be copied together.
*/
y = dlPtr->y;
break;
}
}
/*
* Reduce the height of the area being copied if necessary to
* avoid overwriting the border area.
*/
}
/*
* Update the lines we are going to scroll to show that they
* have been copied.
*/
while (1) {
break;
}
}
/*
* Scan through the lines following the copied ones to see if
* we are going to overwrite them with the copy operation.
* If so, mark them for redisplay.
*/
}
}
/*
* Now scroll the lines. This may generate damage which we
* handle by calling TextInvalidateRegion to mark the display
* blocks as stale.
*/
damageRgn = TkCreateRegion();
}
numCopies++;
}
/*
* Clear the REDRAW_PENDING flag here. This is actually pretty
* tricky. We want to wait until *after* doing the scrolling,
* since that could generate more areas to redraw and don't
* want to reschedule a redisplay for them. On the other hand,
* we can't wait until after all the redisplaying, because the
* act of redisplaying could actually generate more redisplays
* (e.g. in the case of a nested window with event bindings triggered
* by redisplay).
*/
/*
* Redraw the borders if that's needed.
*/
if (tkTextDebug) {
}
/*
* The widget has been deleted. Don't do anything.
*/
goto end;
}
if (textPtr->highlightWidth != 0) {
} else {
}
}
0, TK_RELIEF_FLAT);
}
0, TK_RELIEF_FLAT);
0, TK_RELIEF_FLAT);
}
}
/*
* Now we have to redraw the lines that couldn't be updated by
* scrolling. First, compute the height of the largest line and
* allocate an off-screen pixmap to use for double-buffered
* displays.
*/
maxHeight = -1;
}
}
}
if (maxHeight > 0) {
if (tkTextDebug) {
}
if (dInfoPtr->dLinesInvalidated) {
return;
}
}
}
}
/*
* See if we need to refresh the part of the window below the
* last line of text (if there is any such area). Refresh the
* padding area on the left too, since the insertion cursor might
* have been displayed there previously).
*/
}
if (tkTextDebug) {
(char *) NULL, "eof",
}
/*
* The widget has been deleted. Don't do anything.
*/
goto end;
}
}
/*
* Update the vertical scrollbar, if there is one. Note: it's
* important to clear REDRAW_PENDING here, just in case the
* scroll procedure does something that requires redisplay.
*/
}
/*
* The widget has been deleted. Don't do anything.
*/
goto end;
}
/*
* Update the horizontal scrollbar, if any.
*/
}
}
end:
}
/*
*----------------------------------------------------------------------
*
* TkTextEventuallyRepick --
*
* This procedure is invoked whenever something happens that
* could change the current character or the tags associated
* with it.
*
* Results:
* None.
*
* Side effects:
* A repick is scheduled as an idle handler.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
void
{
}
}
/*
*----------------------------------------------------------------------
*
* TkTextRedrawRegion --
*
* This procedure is invoked to schedule a redisplay for a given
* region of a text widget. The redisplay itself may not occur
* immediately: it's scheduled as a when-idle handler.
*
* Results:
* None.
*
* Side effects:
* Information will eventually be redrawn on the screen.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
void
int x, y; /* Coordinates of upper-left corner of area
* to be redrawn, in pixels relative to
* textPtr's window. */
{
rect.x = x;
rect.y = y;
}
}
/*
*----------------------------------------------------------------------
*
* TextInvalidateRegion --
*
* Mark a region of text as invalid.
*
* Results:
* None.
*
* Side effects:
* Updates the display information for the text widget.
*
*----------------------------------------------------------------------
*/
static void
{
/*
* Find all lines that overlap the given region and mark them for
* redisplay.
*/
}
}
}
/*
* Schedule the redisplay operation if there isn't one already
* scheduled.
*/
}
}
/*
*----------------------------------------------------------------------
*
* TkTextChanged --
*
* This procedure is invoked when info in a text widget is about
* to be modified in a way that changes how it is displayed (e.g.
* characters were inserted or deleted, or tag information was
* changed). This procedure must be called *before* a change is
* made, so that indexes in the display information are still
* valid.
*
* Results:
* None.
*
* Side effects:
* The range of character between index1Ptr (inclusive) and
* index2Ptr (exclusive) will be redisplayed at some point in the
* future (the actual redisplay is scheduled as a when-idle handler).
*
*----------------------------------------------------------------------
*/
void
* to redisplay. */
{
/*
* Schedule both a redisplay and a recomputation of display information.
* It's done here rather than the end of the procedure for two reasons:
*
* 1. If there are no display lines to update we'll want to return
* immediately, well before the end of the procedure.
* 2. It's important to arrange for the redisplay BEFORE calling
* FreeDLines. The reason for this is subtle and has to do with
* embedded windows. The chunk delete procedure for an embedded
* window will schedule an idle handler to unmap the window.
* However, we want the idle handler for redisplay to be called
* first, so that it can put the embedded window back on the screen
* again (if appropriate). This will prevent the window from ever
* being unmapped, and thereby avoid flashing.
*/
}
/*
* Find the DLines corresponding to index1Ptr and index2Ptr. There
* is one tricky thing here, which is that we have to relayout in
* units of whole text lines: round index1Ptr back to the beginning
* of its text line, and include all the display lines after index2,
* up to the end of its text line. This is necessary because the
* indices stored in the display lines will no longer be valid. It's
* also needed because any edit could change the way lines wrap.
*/
return;
}
}
/*
* Delete all the DLines from firstPtr up to but not including lastPtr.
*/
}
/*
*----------------------------------------------------------------------
*
* TkTextRedrawTag --
*
* This procedure is invoked to request a redraw of all characters
* in a given range that have a particular tag on or off. It's
* called, for example, when tag options change.
*
* Results:
* None.
*
* Side effects:
* Information on the screen may be redrawn, and the layout of
* the screen may change.
*
*----------------------------------------------------------------------
*/
void
* for redisplay. NULL means start at
* beginning of text. */
* for redisplay. NULL means process all
* the characters in the text. */
int withTag; /* 1 means redraw characters that have the
* tag, 0 means redraw those without. */
{
int tagOn;
/*
* Round up the starting position if it's before the first line
* visible on the screen (we only care about what's on the screen).
*/
return;
}
}
/*
* Set the stopping position if it wasn't specified.
*/
}
/*
* Initialize a search through all transitions on the tag, starting
* with the first transition where the tag's current state is different
* from what it will eventually be.
*/
/*
* Make our own curIndex because at this point search.curIndex
* may not equal index1Ptr->curIndex in the case the first tag toggle
* comes after index1Ptr (See the use of FindTagStart in TkBTreeStartSearch)
*/
if (!TkBTreeNextTag(&search)) {
return;
}
}
/*
* Schedule a redisplay and layout recalculation if they aren't
* already pending. This has to be done before calling FreeDLines,
* for the reason given in TkTextChanged.
*/
}
/*
* Each loop through the loop below is for one range of characters
* where the tag's current state is different than its eventual
* state. At the top of the loop, search contains information about
* the first character in the range.
*/
while (1) {
/*
* Find the first DLine structure in the range. Note: if the
* desired character isn't the first in its text line, then look
* for the character just before it instead. This is needed to
* handle the case where the first character of a wrapped
* display line just got smaller, so that it now fits on the
* line before: need to relayout the line containing the
* previous character.
*/
if (curIndexPtr->charIndex == 0) {
} else {
tmp = *curIndexPtr;
}
break;
}
/*
* Find the first DLine structure that's past the end of the range.
*/
if (!TkBTreeNextTag(&search)) {
} else {
}
}
/*
* Delete all of the display lines in the range, so that they'll
* be re-layed out and redrawn.
*/
/*
* Find the first text line in the next range.
*/
if (!TkBTreeNextTag(&search)) {
break;
}
}
}
/*
*----------------------------------------------------------------------
*
* TkTextRelayoutWindow --
*
* This procedure is called when something has happened that
* invalidates the whole layout of characters on the screen, such
* as a change in a configuration option for the overall text
* widget or a change in the window size. It causes all display
* information to be recomputed and the window to be redrawn.
*
* Results:
* None.
*
* Side effects:
* All the display information will be recomputed for the window
* and the window will be redrawn.
*
*----------------------------------------------------------------------
*/
void
{
/*
* Schedule the window redisplay. See TkTextChanged for the
* reason why this has to be done before any calls to FreeDLines.
*/
}
/*
* (Re-)create the graphics context for drawing the traversal
* highlight.
*/
}
/*
* Throw away all the current layout information.
*/
/*
* Recompute some overall things for the layout. Even if the
* window gets very small, pretend that there's at least one
* pixel of drawing space in it.
*/
if (textPtr->highlightWidth < 0) {
textPtr->highlightWidth = 0;
}
}
}
/*
* If the upper-left character isn't the first in a line, recompute
* it. This is necessary because a change in the window's size
* or options could change the way lines wrap.
*/
}
/*
* Invalidate cached scrollbar positions, so that scrollbars
* sliders will be udpated.
*/
}
/*
*----------------------------------------------------------------------
*
* TkTextSetYView --
*
* This procedure is called to specify what lines are to be
* displayed in a text widget.
*
* Results:
* None.
*
* Side effects:
* The display will (eventually) be updated so that the position
* given by "indexPtr" is visible on the screen at the position
* determined by "pickPlace".
*
*----------------------------------------------------------------------
*/
void
* in the view. */
int pickPlace; /* 0 means topLine must appear at top of
* screen. 1 means we get to pick where it
* appears: minimize screen motion or else
* display line at center of screen. */
{
/*
* If the specified position is the extra line at the end of the
* text, round it back to the last real line.
*/
}
if (!pickPlace) {
/*
* The specified position must go at the top of the screen.
* Just leave all the DLine's alone: we may be able to reuse
* some of the information that's currently on the screen
* without redisplaying it all.
*/
} else {
}
goto scheduleUpdate;
}
/*
* We have to pick where to display the index. First, bring
* the display information up to date and see if the index will be
* completely visible in the current screen configuration. If so
* then there's nothing to do.
*/
}
/*
* Part of the line hangs off the bottom of the screen;
* pretend the whole line is off-screen.
*/
return;
}
}
/*
* The desired line isn't already on-screen. Figure out what
* it means to be "close" to the top or bottom of the screen.
* Close means within 1/3 of the screen height or within three
* lines, whichever is greater. Add one extra line also, to
* account for the way MeasureUp rounds.
*/
}
close += lineHeight;
/*
* The desired line is above the top of screen. If it is
* "close" to the top of the window then make it the top
* line on the screen.
*/
goto scheduleUpdate;
}
} else {
/*
* The desired line is below the bottom of the screen. If it is
* "close" to the bottom of the screen then position it at the
* bottom of the screen.
*/
}
}
/*
* Our job now is to arrange the display so that indexPtr appears
* as low on the screen as possible but with its bottom no lower
* than bottomY. BottomY is the bottom of the window if the
* desired line is just below the current screen, otherwise it
* is a half-line lower than the center of the window.
*/
}
}
/*
*--------------------------------------------------------------
*
* MeasureUp --
*
* Given one index, find the index of the first character
* on the highest display line that would be displayed no more
* than "distance" pixels above the given index.
*
* Results:
* *dstPtr is filled in with the index of the first character
* on a display line. The display line is found by measuring
* up "distance" pixels above the pixel just below an imaginary
* display line that contains srcPtr. If the display line
* that covers this coordinate actually extends above the
* coordinate, then return the index of the next lower line
* instead (i.e. the returned index will be completely visible
* at or below the given y-coordinate).
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static void
* measuring. */
int distance; /* Vertical distance in pixels measured
* from the pixel just below the lowest
* one in srcPtr's line. */
{
* in current line. */
noBestYet = 1;
lineNum--) {
/*
* Layout an entire text line (potentially > 1 display line).
* For the first line, which contains srcPtr, only layout the
* part up through srcPtr (charsToCount is non-infinite to
* accomplish this). Make a list of all the display lines
* in backwards order (the lowest DLine on the screen is first
* in the list).
*/
do {
/*
* Scan through the display lines to see if we've covered enough
* vertical distance. If so, save the starting index for the
* line at the desired location.
*/
if (distance < 0) {
break;
}
noBestYet = 0;
}
/*
* Discard the display lines, then either return or prepare
* for the next display line to lay out.
*/
if (distance < 0) {
return;
}
}
/*
* Ran off the beginning of the text. Return the first character
* in the text.
*/
}
/*
*--------------------------------------------------------------
*
* TkTextSeeCmd --
*
* This procedure is invoked to process the "see" option for
* the widget command for text widgets. See the user documentation
* for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*--------------------------------------------------------------
*/
int
int argc; /* Number of arguments. */
char **argv; /* Argument strings. Someone else has already
* parsed this command enough to know that
* argv[1] is "see". */
{
if (argc != 3) {
return TCL_ERROR;
}
return TCL_ERROR;
}
/*
* If the specified position is the extra line at the end of the
* text, round it back to the last real line.
*/
}
/*
* First get the desired position into the vertical range of the window.
*/
/*
* Now make sure that the character is in view horizontally.
*/
}
return TCL_OK;
}
/*
* Find the chunk that contains the desired index.
*/
break;
}
}
/*
* Call a chunk-specific procedure to find the horizontal range of
* the character within the chunk.
*/
&height);
if (delta < 0) {
} else {
}
} else {
if (delta > 0) {
} else {
}
} else {
return TCL_OK;
}
}
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* TkTextXviewCmd --
*
* This procedure is invoked to process the "xview" option for
* the widget command for text widgets. See the user documentation
* for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*--------------------------------------------------------------
*/
int
int argc; /* Number of arguments. */
char **argv; /* Argument strings. Someone else has already
* parsed this command enough to know that
* argv[1] is "xview". */
{
double fraction;
}
if (argc == 2) {
return TCL_OK;
}
switch (type) {
case TK_SCROLL_ERROR:
return TCL_ERROR;
case TK_SCROLL_MOVETO:
if (fraction > 1.0) {
fraction = 1.0;
}
if (fraction < 0) {
fraction = 0;
}
+ 0.5;
break;
case TK_SCROLL_PAGES:
- 2;
if (charsPerPage < 1) {
charsPerPage = 1;
}
break;
case TK_SCROLL_UNITS:
break;
}
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* ScrollByLines --
*
* This procedure is called to scroll a text widget up or down
* by a given number of lines.
*
* Results:
* None.
*
* Side effects:
* The view in textPtr's window changes to reflect the value
* of "offset".
*
*----------------------------------------------------------------------
*/
static void
int offset; /* Amount by which to scroll, in *screen*
* lines. Positive means that information
* later in text becomes visible, negative
* means that information earlier in the
* text becomes visible. */
{
if (offset < 0) {
/*
* Must scroll up (to show earlier information in the text).
* The code below is similar to that in MeasureUp, except that
* it counts lines instead of pixels.
*/
offset--; /* Skip line containing topIndex. */
do {
} while ((charsToCount > 0)
offset++;
if (offset == 0) {
break;
}
}
/*
* Discard the display lines, then either return or prepare
* for the next display line to lay out.
*/
if (offset >= 0) {
goto scheduleUpdate;
}
}
/*
* Ran off the beginning of the text. Return the first character
* in the text.
*/
} else {
/*
* Scrolling down, to show later information in the text.
* Just count lines from the current top of the window.
*/
for (i = 0; i < offset; i++) {
break;
}
}
}
}
}
/*
*--------------------------------------------------------------
*
* TkTextYviewCmd --
*
* This procedure is invoked to process the "yview" option for
* the widget command for text widgets. See the user documentation
* for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*--------------------------------------------------------------
*/
int
int argc; /* Number of arguments. */
char **argv; /* Argument strings. Someone else has already
* parsed this command enough to know that
* argv[1] is "yview". */
{
double fraction;
}
if (argc == 2) {
return TCL_OK;
}
/*
* Next, handle the old syntax: "pathName yview ?-pickplace? where"
*/
pickPlace = 0;
if ((switchLength >= 2)
pickPlace = 1;
if (argc != 4) {
argv[0], " yview -pickplace lineNum|index\"",
(char *) NULL);
return TCL_ERROR;
}
}
}
return TCL_OK;
}
/*
* The argument must be a regular text index.
*/
return TCL_ERROR;
}
return TCL_OK;
}
/*
* New syntax: dispatch based on argv[2].
*/
switch (type) {
case TK_SCROLL_ERROR:
return TCL_ERROR;
case TK_SCROLL_MOVETO:
if (fraction > 1.0) {
fraction = 1.0;
}
if (fraction < 0) {
fraction = 0;
}
}
break;
case TK_SCROLL_PAGES:
/*
* Scroll up or down by screenfuls. Actually, use the
* window height minus two lines, so that there's some
* overlap between adjacent pages.
*/
if (count < 0) {
+ lineHeight;
/*
* A page of scrolling ended up being less than one line.
* Scroll one line anyway.
*/
count = -1;
goto scrollByLines;
}
} else {
/*
* Scrolling down by pages. Layout lines starting at the
* top index and count through the desired vertical distance.
*/
do {
&new);
break;
}
} while (pixels > 0);
}
}
break;
case TK_SCROLL_UNITS:
break;
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* TkTextScanCmd --
*
* This procedure is invoked to process the "scan" option for
* the widget command for text widgets. See the user documentation
* for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*--------------------------------------------------------------
*/
int
int argc; /* Number of arguments. */
char **argv; /* Argument strings. Someone else has already
* parsed this command enough to know that
* argv[1] is "scan". */
{
if (argc != 5) {
return TCL_ERROR;
}
return TCL_ERROR;
}
return TCL_ERROR;
}
c = argv[2][0];
/*
* Amplify the difference between the current position and the
* mark position to compute how much the view should shift, then
* update the mark position to correspond to the new view. If we
* run off the edge of the text, reset the mark point so that the
* current position continues to correspond to the edge of the
* window. This means that the picture will start dragging as
* soon as the mouse reverses direction (without this reset, might
* have to slide mouse a long ways back before the picture starts
* moving again).
*/
if (newChar < 0) {
}
dInfoPtr->scanTotalScroll = 0;
}
}
dInfoPtr->scanTotalScroll = 0;
} else {
"\": must be mark or dragto", (char *) NULL);
return TCL_ERROR;
}
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* GetXView --
*
* This procedure computes the fractions that indicate what's
* visible in a text window and, optionally, evaluates a
* Tcl script to report them to the text's associated scrollbar.
*
* Results:
* If report is zero, then interp->result is filled in with
* two real numbers separated by a space, giving the position of
* the left and right edges of the window as fractions from 0 to
* 1, where 0 means the left edge of the text and 1 means the right
* edge. If report is non-zero, then interp->result isn't modified
* directly, but instead a script is evaluated in interp to report
* the new horizontal scroll position to the scrollbar (if the scroll
* position hasn't changed then no script is invoked).
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
* describing visible range gets
* stored in interp->result. */
int report; /* Non-zero means report info to
* scrollbar if it has changed. */
{
int code;
if (last > 1.0) {
last = 1.0;
}
} else {
first = 0;
last = 1.0;
}
if (!report) {
return;
}
return;
}
"\n (horizontal scrolling command executed by text)");
}
}
/*
*----------------------------------------------------------------------
*
* GetYView --
*
* This procedure computes the fractions that indicate what's
* visible in a text window and, optionally, evaluates a
* Tcl script to report them to the text's associated scrollbar.
*
* Results:
* If report is zero, then interp->result is filled in with
* two real numbers separated by a space, giving the position of
* the top and bottom of the window as fractions from 0 to 1, where
* 0 means the beginning of the text and 1 means the end. If
* report is non-zero, then interp->result isn't modified directly,
* but a script is evaluated in interp to report the new scroll
* position to the scrollbar (if the scroll position hasn't changed
* then no script is invoked).
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
* describing visible range gets
* stored in interp->result. */
int report; /* Non-zero means report info to
* scrollbar if it has changed. */
{
first /= totalLines;
while (1) {
/*
* The last line is only partially visible, so don't
* count its characters in what's visible.
*/
count = 0;
break;
}
break;
}
}
last /= totalLines;
if (!report) {
return;
}
return;
}
"\n (vertical scrolling command executed by text)");
}
}
/*
*----------------------------------------------------------------------
*
* FindDLine --
*
* This procedure is called to find the DLine corresponding to a
* given text index.
*
* Results:
* The return value is a pointer to the first DLine found in the
* list headed by dlPtr that displays information at or after the
* specified position. If there is no such line in the list then
* NULL is returned.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static DLine *
* to search. */
{
return NULL;
}
/*
* The first display line is already past the desired line.
*/
return dlPtr;
}
/*
* Find the first display line that covers the desired text line.
*/
return NULL;
}
}
panic("FindDLine reached end of text");
}
}
return dlPtr;
}
/*
* Now get to the right position within the text line.
*/
break;
}
}
return dlPtr;
}
/*
*----------------------------------------------------------------------
*
* TkTextPixelIndex --
*
* Given an (x,y) coordinate on the screen, find the location of
* the character closest to that location.
*
* Results:
* The index at *indexPtr is modified to refer to the character
* on the display that is closest to (x,y).
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
int x, y; /* Pixel coordinates of point in widget's
* window. */
* index of the character nearest to (x,y). */
{
/*
* Make sure that all of the layout information about what's
* displayed where on the screen is up-to-date.
*/
}
/*
* If the coordinates are above the top of the window, then adjust
* them to refer to the upper-right corner of the window. If they're
* off to one side or the other, then adjust to the closest side.
*/
if (y < dInfoPtr->y) {
y = dInfoPtr->y;
x = dInfoPtr->x;
}
}
if (x < dInfoPtr->x) {
x = dInfoPtr->x;
}
/*
* Find the display line containing the desired y-coordinate.
*/
/*
* Y-coordinate is off the bottom of the displayed text.
* Use the last character on the last line.
*/
break;
}
}
/*
* Scan through the line's chunks to find the one that contains
* the desired x-coordinate. Before doing this, translate the
* x-coordinate from the coordinate system of the window to the
* coordinate system of the line (to take account of x-scrolling).
*/
return;
}
}
/*
* If the chunk has more than one character in it, ask it which
* character is at the desired location.
*/
}
}
/*
*----------------------------------------------------------------------
*
* TkTextCharBbox --
*
* Given an index, find the bounding box of the screen area
* occupied by that character.
*
* Results:
* Zero is returned if the character is on the screen. -1
* means the character isn't on the screen. If the return value
* is 0, then the bounding box of the part of the character that's
* visible on the screen is returned to *xPtr, *yPtr, *widthPtr,
* and *heightPtr.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
* box is desired. */
* coordinate. */
{
int index;
/*
* Make sure that all of the screen layout information is up to date.
*/
}
/*
* Find the display line containing the desired index.
*/
return -1;
}
/*
* Find the chunk within the line that contains the desired
* index.
*/
return -1;
}
break;
}
}
/*
* Call a chunk-specific procedure to find the horizontal range of
* the character within the chunk, then fill in the vertical range.
* The x-coordinate returned by bboxProc is a coordinate within a
* line, not a coordinate on the screen. Translate it to reflect
* horizontal scrolling.
*/
/*
* Last character in display line. Give it all the space up to
* the line.
*/
}
}
return -1;
}
if (*widthPtr <= 0) {
return -1;
}
}
if (*heightPtr <= 0) {
return -1;
}
}
return 0;
}
/*
*----------------------------------------------------------------------
*
* TkTextDLineInfo --
*
* Given an index, return information about the display line
* containing that character.
*
* Results:
* Zero is returned if the character is on the screen. -1
* means the character isn't on the screen. If the return value
* is 0, then information is returned in the variables pointed
* to by xPtr, yPtr, widthPtr, heightPtr, and basePtr.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
* box is desired. */
* coordinate. */
int *basePtr; /* Filled in with the baseline position,
* measured as an offset down from *yPtr. */
{
/*
* Make sure that all of the screen layout information is up to date.
*/
}
/*
* Find the display line containing the desired index.
*/
return -1;
}
} else {
}
return 0;
}
/*
*--------------------------------------------------------------
*
* TkTextCharLayoutProc --
*
* This procedure is the "layoutProc" for character segments.
*
* Results:
* If there is something to display for the chunk then a
* non-zero value is returned and the fields of chunkPtr
* will be filled in (see the declaration of TkTextDispChunk
* in tkText.h for details). If zero is returned it means
* that no characters from this chunk fit in the window.
* If -1 is returned it means that this segment just doesn't
* need to be displayed (never happens for text).
*
* Side effects:
* Memory is allocated to hold additional information about
* the chunk.
*
*--------------------------------------------------------------
*/
int
* (corresponds to segPtr and offset). */
int offset; /* Offset within segment of first character
* to consider. */
int maxX; /* Chunk must not occupy pixels at this
* position or higher. */
int maxChars; /* Chunk must not include more than this
* many characters. */
int noCharsYet; /* Non-zero means no characters have been
* assigned to this display line yet. */
* tkTextNoneUid, or tkTextWordUid. */
register TkTextDispChunk *chunkPtr;
/* Structure to fill in with information
* about this chunk. The x field has already
* been set by the caller. */
{
char *p;
/*
* Figure out how many characters will fit in the space we've got.
* Include the next character, even though it won't fit completely,
* if any of the following is true:
* (a) the chunk contains no characters and the display line contains
* no characters yet (i.e. the line isn't wide enough to hold
* even a single character).
* (b) at least one pixel of the character is visible, we haven't
* already exceeded the character limit, and the next character
* is a white space character.
*/
if (charsThatFit < maxChars) {
if ((charsThatFit == 0) && noCharsYet) {
charsThatFit = 1;
TK_IGNORE_TABS, &nextX);
}
|| (p[charsThatFit] == '\t'))) {
/*
* Space characters are funny, in that they are considered
* to fit if there is at least one pixel of space left on the
* line. Just give the space character whatever space is left.
*/
charsThatFit++;
}
if (p[charsThatFit] == '\n') {
/*
* A newline character takes up no space, so if the previous
* character fits then so does the newline.
*/
charsThatFit++;
}
if (charsThatFit == 0) {
return 0;
}
}
/*
* Fill in the chunk structure and allocate and initialize a
* CharInfo structure. If the last character is a newline
* then don't bother to display it.
*/
}
/*
* Compute a break location. If we're in word wrap mode, a
* break can occur after any space character, or at the end of
* the chunk if the next segment (ignoring those with zero size)
* is not a character segment.
*/
if (wrapMode != tkTextWordUid) {
} else {
count--, p--) {
break;
}
}
}
break;
}
}
}
}
return 1;
}
/*
*--------------------------------------------------------------
*
* CharDisplayProc --
*
* This procedure is called to display a character chunk on
* the screen or in an off-screen pixmap.
*
* Results:
* None.
*
* Side effects:
* Graphics are drawn.
*
*--------------------------------------------------------------
*/
static void
int x; /* X-position in dst at which to
* draw this chunk (may differ from
* the x-position in the chunk because
* of scrolling). */
int y; /* Y-position at which to draw this
* chunk in dst. */
int height; /* Total height of line. */
int baseline; /* Offset of baseline from y. */
* chunk. */
int screenY; /* Y-coordinate in text window that
* corresponds to y. */
{
/*
* The chunk is off-screen.
*/
return;
}
/*
* If the text sticks out way to the left of the window, skip
* over the characters that aren't in the visible part of the
* window. This is essential if x is very negative (such as
* less than 32K); otherwise overflow problems will occur
* in servers that use 16-bit arithmetic, like X.
*/
offsetX = x;
offsetChars = 0;
if (x < 0) {
}
/*
* Draw the text, underline, and overstrike for this chunk.
*/
}
if (sValuePtr->overstrike) {
x - chunkPtr->x, TK_IGNORE_TABS, 0,
}
}
}
/*
*--------------------------------------------------------------
*
* CharUndisplayProc --
*
* This procedure is called when a character chunk is no
* longer going to be displayed. It frees up resources
* that were allocated to display the chunk.
*
* Results:
* None.
*
* Side effects:
* Memory and other resources get freed.
*
*--------------------------------------------------------------
*/
static void
* widget. */
{
}
/*
*--------------------------------------------------------------
*
* CharMeasureProc --
*
* This procedure is called to determine which character in
* a character chunk lies over a given x-coordinate.
*
* Results:
* The return value is the index *within the chunk* of the
* character that covers the position given by "x".
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static int
int x; /* X-coordinate, in same coordinate
* system as chunkPtr->x. */
{
int endX;
TK_IGNORE_TABS, &endX);
}
/*
*--------------------------------------------------------------
*
* CharBboxProc --
*
* This procedure is called to compute the bounding box of
* the area occupied by a single character.
*
* Results:
* There is no return value. *xPtr and *yPtr are filled in
* with the coordinates of the upper left corner of the
* character, and *widthPtr and *heightPtr are filled in with
* the dimensions of the character in pixels. Note: not all
* of the returned bbox is necessarily visible on the screen
* (the rightmost part might be off-screen to the right,
* and the bottommost part might be off-screen to the bottom).
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static void
int index; /* Index of desired character within
* the chunk. */
int y; /* Topmost pixel in area allocated
* for this line. */
int lineHeight; /* Height of line, in pixels. */
int baseline; /* Location of line's baseline, in
* pixels measured down from y. */
* character's upper-left pixel.
* X-coord is in same coordinate
* system as chunkPtr->x. */
int *widthPtr; /* Gets filled in with width of
* character, in pixels. */
int *heightPtr; /* Gets filled in with height of
* character, in pixels. */
{
int maxX;
xPtr);
/*
* This situation only happens if the last character in a line
* is a space character, in which case it absorbs all of the
* extra space in the line (see TkTextCharLayoutProc).
*/
/*
* The desired character is a tab character that terminates a
* chunk; give it all the space left in the chunk.
*/
} else {
widthPtr);
} else {
}
}
}
/*
*----------------------------------------------------------------------
*
* AdjustForTab --
*
* This procedure is called to move a series of chunks right
* in order to align them with a tab stop.
*
* Results:
* None.
*
* Side effects:
* The width of chunkPtr gets adjusted so that it absorbs the
* extra space due to the tab. The x locations in all the chunks
* after chunkPtr are adjusted rightward to align with the tab
* stop given by tabArrayPtr and index.
*
*----------------------------------------------------------------------
*/
static void
* a whole. */
* that apply to this line. May be
* NULL to indicate default tabbing
* (every 8 chars). */
int index; /* Index of current tab stop. */
* the tab; the following chunks
* contain information to be shifted
* right. */
{
* prevent compiler warnings. */
char *p;
/*
* Nothing after the actual tab; just return.
*/
return;
}
/*
* If no tab information has been given, do the usual thing:
* round up to the next boundary of 8 average-sized characters.
*/
/*
* No tab information has been given, so use the default
* interpretation of tabs.
*/
goto update;
}
} else {
/*
* Ran out of tab stops; compute a tab position by extrapolating
* from the last two tab positions.
*/
} else {
prev = 0;
}
}
goto update;
}
/*
* Compute the width of all the information in the tab group,
* then use it to pick a desired location.
*/
width = 0;
}
} else {
}
goto update;
}
/*
* Must be numeric alignment. Search through the text to be
* tabbed, looking for the last , or . before the first character
* that isn't a number, comma, period, or sign.
*/
continue;
}
gotDigit = 1;
} else if ((*p == '.') || (*p == ',')) {
} else if (gotDigit) {
if (decimalChunkPtr == NULL) {
}
goto endOfNumber;
}
}
}
if (decimalChunkPtr != NULL) {
int curX;
TK_IGNORE_TABS, &curX);
goto update;
} else {
/*
* There wasn't a decimal point. Right justify the text.
*/
width = 0;
}
}
/*
* Shift all of the chunks to the right so that the left edge is
* at the desired location, then expand the chunk containing the
* tab. Be sure that the tab occupies at least the width of a
* space character.
*/
if (delta < spaceWidth) {
delta = spaceWidth;
}
}
}
/*
*----------------------------------------------------------------------
*
* SizeOfTab --
*
* This returns an estimate of the amount of white space that will
* be consumed by a tab.
*
* Results:
* The return value is the minimum number of pixels that will
* be occupied by the index'th tab of tabArrayPtr, assuming that
* the current position on the line is x and the end of the
* line is maxX. For numeric tabs, this is a conservative
* estimate. The return value is always >= 0.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
* a whole. */
* that apply to this line. NULL
* means use default tabbing (every
* 8 chars.) */
int index; /* Index of current tab stop. */
int x; /* Current x-location in line. Only
* used if tabArrayPtr == NULL. */
int maxX; /* X-location of pixel just past the
* right edge of the line. */
{
return tabX - x;
}
} else {
/*
* Ran out of tab stops; compute a tab position by extrapolating
* from the last two tab positions.
*/
} else {
prev = 0;
}
}
/*
* Be very careful in the arithmetic below, because maxX may
* be the largest positive number: watch out for integer
* overflow.
*/
} else {
result = 0;
}
goto done;
}
result = 0;
goto done;
}
/*
* Note: this treats NUMERIC alignment the same as LEFT
* alignment, which is somewhat conservative. However, it's
* pretty tricky at this point to figure out exactly where
* the damn decimal point will be.
*/
if (tabX > x) {
} else {
result = 0;
}
done:
if (result < spaceWidth) {
result = spaceWidth;
}
return result;
}