📄 tktexttag.c
字号:
} if (tagPtr->spacing1String != NULL) { ckfree(tagPtr->spacing1String); } if (tagPtr->spacing2String != NULL) { ckfree(tagPtr->spacing2String); } if (tagPtr->spacing3String != NULL) { ckfree(tagPtr->spacing3String); } if (tagPtr->tabString != NULL) { ckfree(tagPtr->tabString); } if (tagPtr->tabArrayPtr != NULL) { ckfree((char *) tagPtr->tabArrayPtr); } if (tagPtr->underlineString != NULL) { ckfree(tagPtr->underlineString); } ckfree((char *) tagPtr);}/* *---------------------------------------------------------------------- * * SortTags -- * * This procedure sorts an array of tag pointers in increasing * order of priority, optimizing for the common case where the * array is small. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */static voidSortTags(numTags, tagArrayPtr) int numTags; /* Number of tag pointers at *tagArrayPtr. */ TkTextTag **tagArrayPtr; /* Pointer to array of pointers. */{ int i, j, prio; register TkTextTag **tagPtrPtr; TkTextTag **maxPtrPtr, *tmp; if (numTags < 2) { return; } if (numTags < 20) { for (i = numTags-1; i > 0; i--, tagArrayPtr++) { maxPtrPtr = tagPtrPtr = tagArrayPtr; prio = tagPtrPtr[0]->priority; for (j = i, tagPtrPtr++; j > 0; j--, tagPtrPtr++) { if (tagPtrPtr[0]->priority < prio) { prio = tagPtrPtr[0]->priority; maxPtrPtr = tagPtrPtr; } } tmp = *maxPtrPtr; *maxPtrPtr = *tagArrayPtr; *tagArrayPtr = tmp; } } else { qsort((VOID *) tagArrayPtr, (unsigned) numTags, sizeof (TkTextTag *), TagSortProc); }}/* *---------------------------------------------------------------------- * * TagSortProc -- * * This procedure is called by qsort when sorting an array of * tags in priority order. * * Results: * The return value is -1 if the first argument should be before * the second element (i.e. it has lower priority), 0 if it's * equivalent (this should never happen!), and 1 if it should be * after the second element. * * Side effects: * None. * *---------------------------------------------------------------------- */static intTagSortProc(first, second) CONST VOID *first, *second; /* Elements to be compared. */{ TkTextTag *tagPtr1, *tagPtr2; tagPtr1 = * (TkTextTag **) first; tagPtr2 = * (TkTextTag **) second; return tagPtr1->priority - tagPtr2->priority;}/* *---------------------------------------------------------------------- * * ChangeTagPriority -- * * This procedure changes the priority of a tag by modifying * its priority and the priorities of other tags that are affected * by the change. * * Results: * None. * * Side effects: * Priorities may be changed for some or all of the tags in * textPtr. The tags will be arranged so that there is exactly * one tag at each priority level between 0 and textPtr->numTags-1, * with tagPtr at priority "prio". * *---------------------------------------------------------------------- */static voidChangeTagPriority(textPtr, tagPtr, prio) TkText *textPtr; /* Information about text widget. */ TkTextTag *tagPtr; /* Tag whose priority is to be * changed. */ int prio; /* New priority for tag. */{ int low, high, delta; register TkTextTag *tagPtr2; Tcl_HashEntry *hPtr; Tcl_HashSearch search; if (prio < 0) { prio = 0; } if (prio >= textPtr->numTags) { prio = textPtr->numTags-1; } if (prio == tagPtr->priority) { return; } else if (prio < tagPtr->priority) { low = prio; high = tagPtr->priority-1; delta = 1; } else { low = tagPtr->priority+1; high = prio; delta = -1; } for (hPtr = Tcl_FirstHashEntry(&textPtr->tagTable, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { tagPtr2 = (TkTextTag *) Tcl_GetHashValue(hPtr); if ((tagPtr2->priority >= low) && (tagPtr2->priority <= high)) { tagPtr2->priority += delta; } } tagPtr->priority = prio;}/* *-------------------------------------------------------------- * * TkTextBindProc -- * * This procedure is invoked by the Tk dispatcher to handle * events associated with bindings on items. * * Results: * None. * * Side effects: * Depends on the command invoked as part of the binding * (if there was any). * *-------------------------------------------------------------- */voidTkTextBindProc(clientData, eventPtr) ClientData clientData; /* Pointer to canvas structure. */ XEvent *eventPtr; /* Pointer to X event that just * happened. */{ TkText *textPtr = (TkText *) clientData; int repick = 0;# define AnyButtonMask (Button1Mask|Button2Mask|Button3Mask\ |Button4Mask|Button5Mask) Tcl_Preserve((ClientData) textPtr); /* * This code simulates grabs for mouse buttons by keeping track * of whether a button is pressed and refusing to pick a new current * character while a button is pressed. */ if (eventPtr->type == ButtonPress) { textPtr->flags |= BUTTON_DOWN; } else if (eventPtr->type == ButtonRelease) { int mask; switch (eventPtr->xbutton.button) { case Button1: mask = Button1Mask; break; case Button2: mask = Button2Mask; break; case Button3: mask = Button3Mask; break; case Button4: mask = Button4Mask; break; case Button5: mask = Button5Mask; break; default: mask = 0; break; } if ((eventPtr->xbutton.state & AnyButtonMask) == (unsigned) mask) { textPtr->flags &= ~BUTTON_DOWN; repick = 1; } } else if ((eventPtr->type == EnterNotify) || (eventPtr->type == LeaveNotify)) { if (eventPtr->xcrossing.state & AnyButtonMask) { textPtr->flags |= BUTTON_DOWN; } else { textPtr->flags &= ~BUTTON_DOWN; } TkTextPickCurrent(textPtr, eventPtr); goto done; } else if (eventPtr->type == MotionNotify) { if (eventPtr->xmotion.state & AnyButtonMask) { textPtr->flags |= BUTTON_DOWN; } else { textPtr->flags &= ~BUTTON_DOWN; } TkTextPickCurrent(textPtr, eventPtr); } if ((textPtr->numCurTags > 0) && (textPtr->bindingTable != NULL) && (textPtr->tkwin != NULL)) { Tk_BindEvent(textPtr->bindingTable, eventPtr, textPtr->tkwin, textPtr->numCurTags, (ClientData *) textPtr->curTagArrayPtr); } if (repick) { unsigned int oldState; oldState = eventPtr->xbutton.state; eventPtr->xbutton.state &= ~(Button1Mask|Button2Mask |Button3Mask|Button4Mask|Button5Mask); TkTextPickCurrent(textPtr, eventPtr); eventPtr->xbutton.state = oldState; } done: Tcl_Release((ClientData) textPtr);}/* *-------------------------------------------------------------- * * TkTextPickCurrent -- * * Find the character containing the coordinates in an event * and place the "current" mark on that character. If the * "current" mark has moved then generate a fake leave event * on the old current character and a fake enter event on the new * current character. * * Results: * None. * * Side effects: * The current mark for textPtr may change. If it does, * then the commands associated with character entry and leave * could do just about anything. For example, the text widget * might be deleted. It is up to the caller to protect itself * with calls to Tcl_Preserve and Tcl_Release. * *-------------------------------------------------------------- */voidTkTextPickCurrent(textPtr, eventPtr) register TkText *textPtr; /* Text widget in which to select * current character. */ XEvent *eventPtr; /* Event describing location of * mouse cursor. Must be EnterWindow, * LeaveWindow, ButtonRelease, or * MotionNotify. */{ TkTextIndex index; TkTextTag **oldArrayPtr, **newArrayPtr; TkTextTag **copyArrayPtr = NULL; /* Initialization needed to prevent * compiler warning. */ int numOldTags, numNewTags, i, j, size; XEvent event; /* * If a button is down, then don't do anything at all; we'll be * called again when all buttons are up, and we can repick then. * This implements a form of mouse grabbing. */ if (textPtr->flags & BUTTON_DOWN) { if (((eventPtr->type == EnterNotify) || (eventPtr->type == LeaveNotify)) && ((eventPtr->xcrossing.mode == NotifyGrab) || (eventPtr->xcrossing.mode == NotifyUngrab))) { /* * Special case: the window is being entered or left because * of a grab or ungrab. In this case, repick after all. * Furthermore, clear BUTTON_DOWN to release the simulated * grab. */ textPtr->flags &= ~BUTTON_DOWN; } else { return; } } /* * Save information about this event in the widget in case we have * to synthesize more enter and leave events later (e.g. because a * character was deleted, causing a new character to be underneath * the mouse cursor). Also translate MotionNotify events into * EnterNotify events, since that's what gets reported to event * handlers when the current character changes. */ if (eventPtr != &textPtr->pickEvent) { if ((eventPtr->type == MotionNotify) || (eventPtr->type == ButtonRelease)) { textPtr->pickEvent.xcrossing.type = EnterNotify; textPtr->pickEvent.xcrossing.serial = eventPtr->xmotion.serial; textPtr->pickEvent.xcrossing.send_event = eventPtr->xmotion.send_event; textPtr->pickEvent.xcrossing.display = eventPtr->xmotion.display; textPtr->pickEvent.xcrossing.window = eventPtr->xmotion.window; textPtr->pickEvent.xcrossing.root = eventPtr->xmotion.root; textPtr->pickEvent.xcrossing.subwindow = None; textPtr->pickEvent.xcrossing.time = eventPtr->xmotion.time; textPtr->pickEvent.xcrossing.x = eventPtr->xmotion.x; textPtr->pickEvent.xcrossing.y = eventPtr->xmotion.y; textPtr->pickEvent.xcrossing.x_root = eventPtr->xmotion.x_root; textPtr->pickEvent.xcrossing.y_root = eventPtr->xmotion.y_root; textPtr->pickEvent.xcrossing.mode = NotifyNormal; textPtr->pickEvent.xcrossing.detail = NotifyNonlinear; textPtr->pickEvent.xcrossing.same_screen = eventPtr->xmotion.same_screen; textPtr->pickEvent.xcrossing.focus = False; textPtr->pickEvent.xcrossing.state = eventPtr->xmotion.state; } else { textPtr->pickEvent = *eventPtr; } } /* * Find the new current character, then find and sort all of the * tags associated with it. */ if (textPtr->pickEvent.type != LeaveNotify) { TkTextPixelIndex(textPtr, textPtr->pickEvent.xcrossing.x, textPtr->pickEvent.xcrossing.y, &index); newArrayPtr = TkBTreeGetTags(&index, &numNewTags); SortTags(numNewTags, newArrayPtr); } else { newArrayPtr = NULL; numNewTags = 0; } /* * Resort the tags associated with the previous marked character * (the priorities might have changed), then make a copy of the * new tags, and compare the old tags to the copy, nullifying * any tags that are present in both groups (i.e. the tags that * haven't changed). */ SortTags(textPtr->numCurTags, textPtr->curTagArrayPtr); if (numNewTags > 0) { size = numNewTags * sizeof(TkTextTag *); copyArrayPtr = (TkTextTag **) ckalloc((unsigned) size); memcpy((VOID *) copyArrayPtr, (VOID *) newArrayPtr, (size_t) size); for (i = 0; i < textPtr->numCurTags; i++) { for (j = 0; j < numNewTags; j++) { if (textPtr->curTagArrayPtr[i] == copyArrayPtr[j]) { textPtr->curTagArrayPtr[i] = NULL; copyArrayPtr[j] = NULL; break; } } } } /* * Invoke the binding system with a LeaveNotify event for all of * the tags that have gone away. We have to be careful here, * because it's possible that the binding could do something * (like calling tkwait) that eventually modifies * textPtr->curTagArrayPtr. To avoid problems in situations like * this, update curTagArrayPtr to its new value before invoking * any bindings, and don't use it any more here. */ numOldTags = textPtr->numCurTags; textPtr->numCurTags = numNewTags; oldArrayPtr = textPtr->curTagArrayPtr; textPtr->curTagArrayPtr = newArrayPtr; if (numOldTags != 0) { if ((textPtr->bindingTable != NULL) && (textPtr->tkwin != NULL)) { event = textPtr->pickEvent; event.type = LeaveNotify; /* * Always use a detail of NotifyAncestor. Besides being * consistent, this avoids problems where the binding code * will discard NotifyInferior events. */ event.xcrossing.detail = NotifyAncestor; Tk_BindEvent(textPtr->bindingTable, &event, textPtr->tkwin, numOldTags, (ClientData *) oldArrayPtr); } ckfree((char *) oldArrayPtr); } /* * Reset the "current" mark (be careful to recompute its location, * since it might have changed during an event binding). Then * invoke the binding system with an EnterNotify event for all of * the tags that have just appeared. */ TkTextPixelIndex(textPtr, textPtr->pickEvent.xcrossing.x, textPtr->pickEvent.xcrossing.y, &index); TkTextSetMark(textPtr, "current", &index); if (numNewTags != 0) { if ((textPtr->bindingTable != NULL) && (textPtr->tkwin != NULL)) { event = textPtr->pickEvent; event.type = EnterNotify; event.xcrossing.detail = NotifyAncestor; Tk_BindEvent(textPtr->bindingTable, &event, textPtr->tkwin, numNewTags, (ClientData *) copyArrayPtr); } ckfree((char *) copyArrayPtr); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -