📄 tkentry.c
字号:
ckfree((char *) entryPtr);}/* *---------------------------------------------------------------------- * * ConfigureEntry -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * an entry widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then interp->result contains an error message. * * Side effects: * Configuration information, such as colors, border width, * etc. get set for entryPtr; old resources get freed, * if there were any. * *---------------------------------------------------------------------- */static intConfigureEntry(interp, entryPtr, argc, argv, flags) Tcl_Interp *interp; /* Used for error reporting. */ register Entry *entryPtr; /* Information about widget; may or may * not already have values for some fields. */ int argc; /* Number of valid entries in argv. */ char **argv; /* Arguments. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */{ int oldExport; /* * Eliminate any existing trace on a variable monitored by the entry. */ if (entryPtr->textVarName != NULL) { Tcl_UntraceVar(interp, entryPtr->textVarName, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, EntryTextVarProc, (ClientData) entryPtr); } oldExport = entryPtr->exportSelection; if (Tk_ConfigureWidget(interp, entryPtr->tkwin, configSpecs, argc, argv, (char *) entryPtr, flags) != TCL_OK) { return TCL_ERROR; } /* * If the entry is tied to the value of a variable, then set up * a trace on the variable's value, create the variable if it doesn't * exist, and set the entry's value from the variable's value. */ if (entryPtr->textVarName != NULL) { char *value; value = Tcl_GetVar(interp, entryPtr->textVarName, TCL_GLOBAL_ONLY); if (value == NULL) { EntryValueChanged(entryPtr); } else { EntrySetValue(entryPtr, value); } Tcl_TraceVar(interp, entryPtr->textVarName, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, EntryTextVarProc, (ClientData) entryPtr); } /* * A few other options also need special processing, such as parsing * the geometry and setting the background from a 3-D border. */ if ((entryPtr->state != tkNormalUid) && (entryPtr->state != tkDisabledUid)) { Tcl_AppendResult(interp, "bad state value \"", entryPtr->state, "\": must be normal or disabled", (char *) NULL); entryPtr->state = tkNormalUid; return TCL_ERROR; } Tk_SetBackgroundFromBorder(entryPtr->tkwin, entryPtr->normalBorder); if (entryPtr->insertWidth <= 0) { entryPtr->insertWidth = 2; } if (entryPtr->insertBorderWidth > entryPtr->insertWidth/2) { entryPtr->insertBorderWidth = entryPtr->insertWidth/2; } /* * Restart the cursor timing sequence in case the on-time or off-time * just changed. */ if (entryPtr->flags & GOT_FOCUS) { EntryFocusProc(entryPtr, 1); } /* * Claim the selection if we've suddenly started exporting it. */ if (entryPtr->exportSelection && (!oldExport) && (entryPtr->selectFirst != -1) && !(entryPtr->flags & GOT_SELECTION)) { Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, EntryLostSelection, (ClientData) entryPtr); entryPtr->flags |= GOT_SELECTION; } /* * Recompute the window's geometry and arrange for it to be * redisplayed. */ Tk_SetInternalBorder(entryPtr->tkwin, entryPtr->borderWidth + entryPtr->highlightWidth); if (entryPtr->highlightWidth <= 0) { entryPtr->highlightWidth = 0; } entryPtr->inset = entryPtr->highlightWidth + entryPtr->borderWidth + XPAD; EntryWorldChanged((ClientData) entryPtr); return TCL_OK;}/* *--------------------------------------------------------------------------- * * EntryWorldChanged -- * * This procedure is called when the world has changed in some * way and the widget needs to recompute all its graphics contexts * and determine its new geometry. * * Results: * None. * * Side effects: * Entry will be relayed out and redisplayed. * *--------------------------------------------------------------------------- */ static voidEntryWorldChanged(instanceData) ClientData instanceData; /* Information about widget. */{ XGCValues gcValues; GC gc; unsigned long mask; Entry *entryPtr; entryPtr = (Entry *) instanceData; entryPtr->avgWidth = Tk_TextWidth(entryPtr->tkfont, "0", 1); if (entryPtr->avgWidth == 0) { entryPtr->avgWidth = 1; } gcValues.foreground = entryPtr->fgColorPtr->pixel; gcValues.font = Tk_FontId(entryPtr->tkfont); gcValues.graphics_exposures = False; mask = GCForeground | GCFont | GCGraphicsExposures; gc = Tk_GetGC(entryPtr->tkwin, mask, &gcValues); if (entryPtr->textGC != None) { Tk_FreeGC(entryPtr->display, entryPtr->textGC); } entryPtr->textGC = gc; gcValues.foreground = entryPtr->selFgColorPtr->pixel; gcValues.font = Tk_FontId(entryPtr->tkfont); mask = GCForeground | GCFont; gc = Tk_GetGC(entryPtr->tkwin, mask, &gcValues); if (entryPtr->selTextGC != None) { Tk_FreeGC(entryPtr->display, entryPtr->selTextGC); } entryPtr->selTextGC = gc; /* * Recompute the window's geometry and arrange for it to be * redisplayed. */ EntryComputeGeometry(entryPtr); entryPtr->flags |= UPDATE_SCROLLBAR; EventuallyRedraw(entryPtr);}/* *-------------------------------------------------------------- * * DisplayEntry -- * * This procedure redraws the contents of an entry window. * * Results: * None. * * Side effects: * Information appears on the screen. * *-------------------------------------------------------------- */static voidDisplayEntry(clientData) ClientData clientData; /* Information about window. */{ register Entry *entryPtr = (Entry *) clientData; register Tk_Window tkwin = entryPtr->tkwin; int baseY, selStartX, selEndX, cursorX, x, w; int xBound; Tk_FontMetrics fm; Pixmap pixmap; int showSelection; entryPtr->flags &= ~REDRAW_PENDING; if ((entryPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { return; } Tk_GetFontMetrics(entryPtr->tkfont, &fm); /* * Update the scrollbar if that's needed. */ if (entryPtr->flags & UPDATE_SCROLLBAR) { entryPtr->flags &= ~UPDATE_SCROLLBAR; EntryUpdateScrollbar(entryPtr); } /* * In order to avoid screen flashes, this procedure redraws the * textual area of the entry into off-screen memory, then copies * it back on-screen in a single operation. This means there's * no point in time where the on-screen image has been cleared. */ pixmap = Tk_GetPixmap(entryPtr->display, Tk_WindowId(tkwin), Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); /* * Compute x-coordinate of the pixel just after last visible * one, plus vertical position of baseline of text. */ xBound = Tk_Width(tkwin) - entryPtr->inset; baseY = (Tk_Height(tkwin) + fm.ascent - fm.descent) / 2; /* * On Windows and Mac, we need to hide the selection whenever we * don't have the focus. */#ifdef ALWAYS_SHOW_SELECTION showSelection = 1;#else showSelection = (entryPtr->flags & GOT_FOCUS);#endif /* * Draw the background in three layers. From bottom to top the * layers are: normal background, selection background, and * insertion cursor background. */ Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->normalBorder, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); if (showSelection && (entryPtr->selectLast > entryPtr->leftIndex)) { if (entryPtr->selectFirst <= entryPtr->leftIndex) { selStartX = entryPtr->leftX; } else { Tk_CharBbox(entryPtr->textLayout, entryPtr->selectFirst, &x, NULL, NULL, NULL); selStartX = x + entryPtr->layoutX; } if ((selStartX - entryPtr->selBorderWidth) < xBound) { Tk_CharBbox(entryPtr->textLayout, entryPtr->selectLast - 1, &x, NULL, &w, NULL); selEndX = x + w + entryPtr->layoutX; Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->selBorder, selStartX - entryPtr->selBorderWidth, baseY - fm.ascent - entryPtr->selBorderWidth, (selEndX - selStartX) + 2*entryPtr->selBorderWidth, (fm.ascent + fm.descent) + 2*entryPtr->selBorderWidth, entryPtr->selBorderWidth, TK_RELIEF_RAISED); } } /* * Draw a special background for the insertion cursor, overriding * even the selection background. As a special hack to keep the * cursor visible when the insertion cursor color is the same as * the color for selected text (e.g., on mono displays), write * background in the cursor area (instead of nothing) when the * cursor isn't on. Otherwise the selection would hide the cursor. */ if ((entryPtr->insertPos >= entryPtr->leftIndex) && (entryPtr->state == tkNormalUid) && (entryPtr->flags & GOT_FOCUS)) { if (entryPtr->insertPos == 0) { cursorX = 0; } else if (entryPtr->insertPos >= entryPtr->numChars) { Tk_CharBbox(entryPtr->textLayout, entryPtr->numChars - 1, &x, NULL, &w, NULL); cursorX = x + w; } else { Tk_CharBbox(entryPtr->textLayout, entryPtr->insertPos, &x, NULL, NULL, NULL); cursorX = x; } cursorX += entryPtr->layoutX; cursorX -= (entryPtr->insertWidth)/2; if (cursorX < xBound) { if (entryPtr->flags & CURSOR_ON) { Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->insertBorder, cursorX, baseY - fm.ascent, entryPtr->insertWidth, fm.ascent + fm.descent, entryPtr->insertBorderWidth, TK_RELIEF_RAISED); } else if (entryPtr->insertBorder == entryPtr->selBorder) { Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->normalBorder, cursorX, baseY - fm.ascent, entryPtr->insertWidth, fm.ascent + fm.descent, 0, TK_RELIEF_FLAT); } } } /* * Draw the text in two pieces: first the unselected portion, then the * selected portion on top of it. */ Tk_DrawTextLayout(entryPtr->display, pixmap, entryPtr->textGC, entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY, entryPtr->leftIndex, entryPtr->numChars); if (showSelection && (entryPtr->selTextGC != entryPtr->textGC) && (entryPtr->selectFirst < entryPtr->selectLast)) { int first; if (entryPtr->selectFirst - entryPtr->leftIndex < 0) { first = entryPtr->leftIndex; } else { first = entryPtr->selectFirst; } Tk_DrawTextLayout(entryPtr->display, pixmap, entryPtr->selTextGC, entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY, first, entryPtr->selectLast); } /* * Draw the border and focus highlight last, so they will overwrite * any text that extends past the viewable part of the window. */ if (entryPtr->relief != TK_RELIEF_FLAT) { Tk_Draw3DRectangle(tkwin, pixmap, entryPtr->normalBorder, entryPtr->highlightWidth, entryPtr->highlightWidth, Tk_Width(tkwin) - 2*entryPtr->highlightWidth, Tk_Height(tkwin) - 2*entryPtr->highlightWidth, entryPtr->borderWidth, entryPtr->relief); } if (entryPtr->highlightWidth != 0) { GC gc; if (entryPtr->flags & GOT_FOCUS) { gc = Tk_GCForColor(entryPtr->highlightColorPtr, pixmap); } else { gc = Tk_GCForColor(entryPtr->highlightBgColorPtr, pixmap); } Tk_DrawFocusHighlight(tkwin, gc, entryPtr->highlightWidth, pixmap); } /* * Everything's been redisplayed; now copy the pixmap onto the screen * and free up the pixmap. */ XCopyArea(entryPtr->display, pixmap, Tk_WindowId(tkwin), entryPtr->textGC, 0, 0, (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin), 0, 0); Tk_FreePixmap(entryPtr->display, pixmap); entryPtr->flags &= ~BORDER_NEEDED;}/* *---------------------------------------------------------------------- * * EntryComputeGeometry -- * * This procedure is invoked to recompute information about where * in its window an entry's string will be displayed. It also * computes the requested size for the window. * * Results: * None. * * Side effects: * The leftX and tabOrigin fields are recomputed for entryPtr, * and leftIndex may be adjusted. Tk_GeometryRequest is called * to register the desired dimensions for the window. * *---------------------------------------------------------------------- */static voidEntryComputeGeometry(entryPtr) Entry *entryPtr; /* Widget record for entry. */{ int totalLength, overflow, maxOffScreen, rightX; int height, width, i; Tk_FontMetrics fm; char *p, *displayString; /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -