📄 tktextdisp.c
字号:
if (index.charIndex == dlPtr->index.charIndex) { /* * Case (a) -- can use existing display line as-is. */ if ((dlPtr->flags & HAS_3D_BORDER) && (prevPtr != NULL) && (prevPtr->flags & (NEW_LAYOUT))) { dlPtr->oldY = -1; } goto lineOK; } if (index.charIndex < dlPtr->index.charIndex) { goto makeNewDLine; } /* * Case (c) -- dlPtr is useless. Discard it and start * again with the next display line. */ newPtr = dlPtr->nextPtr; FreeDLines(textPtr, dlPtr, newPtr, 0); dlPtr = newPtr; if (prevPtr != NULL) { prevPtr->nextPtr = newPtr; } else { dInfoPtr->dLinePtr = newPtr; } continue; } /* * Advance to the start of the next line. */ lineOK: dlPtr->y = y; y += dlPtr->height; TkTextIndexForwChars(&index, dlPtr->count, &index); prevPtr = dlPtr; dlPtr = dlPtr->nextPtr; /* * If we switched text lines, delete any DLines left for the * old text line. */ if (index.linePtr != prevPtr->index.linePtr) { register DLine *nextPtr; nextPtr = dlPtr; while ((nextPtr != NULL) && (nextPtr->index.linePtr == prevPtr->index.linePtr)) { nextPtr = nextPtr->nextPtr; } if (nextPtr != dlPtr) { FreeDLines(textPtr, dlPtr, nextPtr, 0); prevPtr->nextPtr = nextPtr; dlPtr = nextPtr; } } /* * 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. */ FreeDLines(textPtr, dlPtr, (DLine *) NULL, 1); /* *-------------------------------------------------------------- * 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) { int lineNum, spaceLeft, charsToCount; DLine *lowestPtr; /* * 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. */ spaceLeft = maxY - y; lineNum = TkBTreeLineIndex(dInfoPtr->dLinePtr->index.linePtr); charsToCount = dInfoPtr->dLinePtr->index.charIndex; if (charsToCount == 0) { charsToCount = INT_MAX; lineNum--; } for ( ; (lineNum >= 0) && (spaceLeft > 0); lineNum--) { index.linePtr = TkBTreeFindLine(textPtr->tree, lineNum); index.charIndex = 0; lowestPtr = NULL; do { dlPtr = LayoutDLine(textPtr, &index); dlPtr->nextPtr = lowestPtr; lowestPtr = dlPtr; TkTextIndexForwChars(&index, dlPtr->count, &index); charsToCount -= dlPtr->count; } while ((charsToCount > 0) && (index.linePtr == lowestPtr->index.linePtr)); /* * Scan through the display lines from the bottom one up to * the top one. */ while (lowestPtr != NULL) { dlPtr = lowestPtr; spaceLeft -= dlPtr->height; if (spaceLeft < 0) { break; } lowestPtr = dlPtr->nextPtr; dlPtr->nextPtr = dInfoPtr->dLinePtr; dInfoPtr->dLinePtr = dlPtr; if (tkTextDebug) { char string[TK_POS_CHARS]; TkTextPrintIndex(&dlPtr->index, string); Tcl_SetVar2(textPtr->interp, "tk_textRelayout", (char *) NULL, string, TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT); } } FreeDLines(textPtr, lowestPtr, (DLine *) NULL, 0); charsToCount = INT_MAX; } /* * 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. */ textPtr->topIndex = dInfoPtr->dLinePtr->index; y = dInfoPtr->y; for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL; dlPtr = dlPtr->nextPtr) { if (y > dInfoPtr->maxY) { panic("Added too many new lines in UpdateDisplayInfo"); } dlPtr->y = y; y += dlPtr->height; } } /* *-------------------------------------------------------------- * 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. *-------------------------------------------------------------- */ dlPtr = dInfoPtr->dLinePtr; if ((dlPtr->flags & HAS_3D_BORDER) && !(dlPtr->flags & TOP_LINE)) { dlPtr->oldY = -1; } while (1) { if ((dlPtr->flags & TOP_LINE) && (dlPtr != dInfoPtr->dLinePtr) && (dlPtr->flags & HAS_3D_BORDER)) { dlPtr->oldY = -1; } if ((dlPtr->flags & BOTTOM_LINE) && (dlPtr->nextPtr != NULL) && (dlPtr->flags & HAS_3D_BORDER)) { dlPtr->oldY = -1; } if (dlPtr->nextPtr == NULL) { if ((dlPtr->flags & HAS_3D_BORDER) && !(dlPtr->flags & BOTTOM_LINE)) { dlPtr->oldY = -1; } dlPtr->flags &= ~TOP_LINE; dlPtr->flags |= BOTTOM_LINE; break; } dlPtr->flags &= ~(TOP_LINE|BOTTOM_LINE); dlPtr = dlPtr->nextPtr; } dInfoPtr->dLinePtr->flags |= TOP_LINE; /* * Arrange for scrollbars to be updated. */ textPtr->flags |= UPDATE_SCROLLBARS; /* *-------------------------------------------------------------- * 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. *-------------------------------------------------------------- */ dInfoPtr->maxLength = 0; for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL; dlPtr = dlPtr->nextPtr) { if (dlPtr->length > dInfoPtr->maxLength) { dInfoPtr->maxLength = dlPtr->length; } } maxOffset = (dInfoPtr->maxLength - (dInfoPtr->maxX - dInfoPtr->x) + textPtr->charWidth - 1)/textPtr->charWidth; if (dInfoPtr->newCharOffset > maxOffset) { dInfoPtr->newCharOffset = maxOffset; } if (dInfoPtr->newCharOffset < 0) { dInfoPtr->newCharOffset = 0; } pixelOffset = dInfoPtr->newCharOffset * textPtr->charWidth; if (pixelOffset != dInfoPtr->curPixelOffset) { dInfoPtr->curPixelOffset = pixelOffset; for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL; dlPtr = dlPtr->nextPtr) { dlPtr->oldY = -1; } }}/* *---------------------------------------------------------------------- * * 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 voidFreeDLines(textPtr, firstPtr, lastPtr, unlink) TkText *textPtr; /* Information about overall text * widget. */ register DLine *firstPtr; /* Pointer to first DLine to free up. */ DLine *lastPtr; /* Pointer to DLine just after last * 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. */{ register TkTextDispChunk *chunkPtr, *nextChunkPtr; register DLine *nextDLinePtr; if (unlink) { if (textPtr->dInfoPtr->dLinePtr == firstPtr) { textPtr->dInfoPtr->dLinePtr = lastPtr; } else { register DLine *prevPtr; for (prevPtr = textPtr->dInfoPtr->dLinePtr; prevPtr->nextPtr != firstPtr; prevPtr = prevPtr->nextPtr) { /* Empty loop body. */ } prevPtr->nextPtr = lastPtr; } } while (firstPtr != lastPtr) { nextDLinePtr = firstPtr->nextPtr; for (chunkPtr = firstPtr->chunkPtr; chunkPtr != NULL; chunkPtr = nextChunkPtr) { if (chunkPtr->undisplayProc != NULL) { (*chunkPtr->undisplayProc)(textPtr, chunkPtr); } FreeStyle(textPtr, chunkPtr->stylePtr); nextChunkPtr = chunkPtr->nextPtr; ckfree((char *) chunkPtr); } ckfree((char *) firstPtr); firstPtr = nextDLinePtr; } textPtr->dInfoPtr->dLinesInvalidated = 1;}/* *---------------------------------------------------------------------- * * 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 voidDisplayDLine(textPtr, dlPtr, prevPtr, pixmap) TkText *textPtr; /* Text widget in which to draw line. */ register DLine *dlPtr; /* Information about line to draw. */ DLine *prevPtr; /* Line just before one to draw, or NULL * if dlPtr is the top line. */ Pixmap pixmap; /* Pixmap to use for double-buffering. * Caller must make sure it's large enough * to hold line. */{ register TkTextDispChunk *chunkPtr; TextDInfo *dInfoPtr = textPtr->dInfoPtr; Display *display; int height, x; /* * First, clear the area of the line to the background color for the * text widget. */ display = Tk_Display(textPtr->tkwin); Tk_Fill3DRectangle(textPtr->tkwin, pixmap, textPtr->border, 0, 0, Tk_Width(textPtr->tkwin), dlPtr->height, 0, TK_RELIEF_FLAT); /* * Next, draw background information for the whole line. */ DisplayLineBackground(textPtr, dlPtr, prevPtr, pixmap); /* * 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. */ if (textPtr->state == tkNormalUid) { for (chunkPtr = dlPtr->chunkPtr; (chunkPtr != NULL); chunkPtr = chunkPtr->nextPtr) { x = chunkPtr->x + dInfoPtr->x - dInfoPtr->curPixelOffset; if (chunkPtr->displayProc == TkTextInsertDisplayProc) { (*chunkPtr->displayProc)(chunkPtr, x, dlPtr->spaceAbove, dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, dlPtr->baseline - dlPtr->spaceAbove, display, pixmap, dlPtr->y + dlPtr->spaceAbove); } } } /* * 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 */ for (chunkPtr = dlPtr->chunkPtr; (chunkPtr != NULL); chunkPtr = chunkPtr->nextPtr) { if (chunkPtr->displayProc == TkTextInsertDisplayProc) { /* * Already displayed the insertion cursor above. Don't * do it again here. */ continue; } x = chunkPtr->x + dInfoPtr->x - dInfoPtr->curPixelOffset; if ((x + chunkPtr->width <= 0) || (x >= dInfoPtr->maxX)) { /* * 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -