1 | /*
|
---|
2 | Remember row,column where string was acquired.
|
---|
3 | postcombobox x y
|
---|
4 | icon?, text, row, column position, fg, bg button?
|
---|
5 | based upon style.
|
---|
6 | grab set
|
---|
7 | SetIcon
|
---|
8 | SetText
|
---|
9 | SetBg
|
---|
10 | SetFg
|
---|
11 | SetFont
|
---|
12 | SetButton
|
---|
13 | */
|
---|
14 |
|
---|
15 | /*
|
---|
16 | * bltTreeViewEdit.c --
|
---|
17 | *
|
---|
18 | * This module implements an hierarchy widget for the BLT toolkit.
|
---|
19 | *
|
---|
20 | * Copyright 1998-1999 Lucent Technologies, Inc.
|
---|
21 | *
|
---|
22 | * Permission to use, copy, modify, and distribute this software and
|
---|
23 | * its documentation for any purpose and without fee is hereby
|
---|
24 | * granted, provided that the above copyright notice appear in all
|
---|
25 | * copies and that both that the copyright notice and warranty
|
---|
26 | * disclaimer appear in supporting documentation, and that the names
|
---|
27 | * of Lucent Technologies or any of their entities not be used in
|
---|
28 | * advertising or publicity pertaining to distribution of the software
|
---|
29 | * without specific, written prior permission.
|
---|
30 | *
|
---|
31 | * Lucent Technologies disclaims all warranties with regard to this
|
---|
32 | * software, including all implied warranties of merchantability and
|
---|
33 | * fitness. In no event shall Lucent Technologies be liable for any
|
---|
34 | * special, indirect or consequential damages or any damages
|
---|
35 | * whatsoever resulting from loss of use, data or profits, whether in
|
---|
36 | * an action of contract, negligence or other tortuous action, arising
|
---|
37 | * out of or in connection with the use or performance of this
|
---|
38 | * software.
|
---|
39 | *
|
---|
40 | * The "treeview" widget was created by George A. Howlett.
|
---|
41 | */
|
---|
42 |
|
---|
43 | #include "bltInt.h"
|
---|
44 |
|
---|
45 | #ifndef NO_TREEVIEW
|
---|
46 |
|
---|
47 | #include "bltTreeView.h"
|
---|
48 | #include <X11/Xutil.h>
|
---|
49 | #include <X11/Xatom.h>
|
---|
50 |
|
---|
51 | #define TEXTBOX_FOCUS (1<<0)
|
---|
52 | #define TEXTBOX_REDRAW (1<<1)
|
---|
53 |
|
---|
54 | static Tcl_IdleProc DisplayTextbox;
|
---|
55 | static Tcl_FreeProc DestroyTextbox;
|
---|
56 | static Tcl_TimerProc BlinkCursorProc;
|
---|
57 | static Tcl_ObjCmdProc TextboxCmd;
|
---|
58 |
|
---|
59 | /*
|
---|
60 | * Textbox --
|
---|
61 | *
|
---|
62 | * This structure is shared by entries when their labels are
|
---|
63 | * edited via the keyboard. It maintains the location of the
|
---|
64 | * insertion cursor and the text selection for the editted entry.
|
---|
65 | * The structure is shared since we need only one. The "focus"
|
---|
66 | * entry should be the only entry receiving KeyPress/KeyRelease
|
---|
67 | * events at any time. Information from the previously editted
|
---|
68 | * entry is overwritten.
|
---|
69 | *
|
---|
70 | * Note that all the indices internally are in terms of bytes,
|
---|
71 | * not characters. This is because UTF-8 strings may encode a
|
---|
72 | * single character into a multi-byte sequence. To find the
|
---|
73 | * respective character position
|
---|
74 | *
|
---|
75 | * n = Tcl_NumUtfChars(string, index);
|
---|
76 | *
|
---|
77 | * where n is the resulting character number.
|
---|
78 | */
|
---|
79 | typedef struct {
|
---|
80 |
|
---|
81 | /*
|
---|
82 | * This is a SNAFU in the Tk API. It assumes that only an official
|
---|
83 | * Tk "toplevel" widget will ever become a toplevel window (i.e. a
|
---|
84 | * window whose parent is the root window). Because under Win32,
|
---|
85 | * Tk tries to use the widget record associated with the TopLevel
|
---|
86 | * as a Tk frame widget, to read its menu name. What this means
|
---|
87 | * is that any widget that's going to be a toplevel, must also look
|
---|
88 | * like a frame. Therefore we've copied the frame widget structure
|
---|
89 | * fields into the token.
|
---|
90 | */
|
---|
91 |
|
---|
92 | Tk_Window tkwin; /* Window that embodies the frame. NULL
|
---|
93 | * means that the window has been destroyed
|
---|
94 | * but the data structures haven't yet been
|
---|
95 | * cleaned up. */
|
---|
96 | Display *display; /* Display containing widget. Used, among
|
---|
97 | * other things, so that resources can be
|
---|
98 | * freed even after tkwin has gone away. */
|
---|
99 | Tcl_Interp *interp; /* Interpreter associated with widget. Used
|
---|
100 | * to delete widget command. */
|
---|
101 | Tcl_Command widgetCmd; /* Token for frame's widget command. */
|
---|
102 | char *className; /* Class name for widget (from configuration
|
---|
103 | * option). Malloc-ed. */
|
---|
104 | int mask; /* Either FRAME or TOPLEVEL; used to select
|
---|
105 | * which configuration options are valid for
|
---|
106 | * widget. */
|
---|
107 | char *screenName; /* Screen on which widget is created. Non-null
|
---|
108 | * only for top-levels. Malloc-ed, may be
|
---|
109 | * NULL. */
|
---|
110 | char *visualName; /* Textual description of visual for window,
|
---|
111 | * from -visual option. Malloc-ed, may be
|
---|
112 | * NULL. */
|
---|
113 | char *colormapName; /* Textual description of colormap for window,
|
---|
114 | * from -colormap option. Malloc-ed, may be
|
---|
115 | * NULL. */
|
---|
116 | char *menuName; /* Textual description of menu to use for
|
---|
117 | * menubar. Malloc-ed, may be NULL. */
|
---|
118 | Colormap colormap; /* If not None, identifies a colormap
|
---|
119 | * allocated for this window, which must be
|
---|
120 | * freed when the window is deleted. */
|
---|
121 | Tk_3DBorder border; /* Structure used to draw 3-D border and
|
---|
122 | * background. NULL means no background
|
---|
123 | * or border. */
|
---|
124 | int borderWidth; /* Width of 3-D border (if any). */
|
---|
125 | int relief; /* 3-d effect: TK_RELIEF_RAISED etc. */
|
---|
126 | int highlightWidth; /* Width in pixels of highlight to draw
|
---|
127 | * around widget when it has the focus.
|
---|
128 | * 0 means don't draw a highlight. */
|
---|
129 | XColor *highlightBgColorPtr;
|
---|
130 | /* Color for drawing traversal highlight
|
---|
131 | * area when highlight is off. */
|
---|
132 | XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
|
---|
133 | int width; /* Width to request for window. <= 0 means
|
---|
134 | * don't request any size. */
|
---|
135 | int height; /* Height to request for window. <= 0 means
|
---|
136 | * don't request any size. */
|
---|
137 | Tk_Cursor cursor; /* Current cursor for window, or None. */
|
---|
138 | char *takeFocus; /* Value of -takefocus option; not used in
|
---|
139 | * the C code, but used by keyboard traversal
|
---|
140 | * scripts. Malloc'ed, but may be NULL. */
|
---|
141 | int isContainer; /* 1 means this window is a container, 0 means
|
---|
142 | * that it isn't. */
|
---|
143 | char *useThis; /* If the window is embedded, this points to
|
---|
144 | * the name of the window in which it is
|
---|
145 | * embedded (malloc'ed). For non-embedded
|
---|
146 | * windows this is NULL. */
|
---|
147 | int flags; /* Various flags; see below for
|
---|
148 | * definitions. */
|
---|
149 |
|
---|
150 | /* Textbox-specific fields */
|
---|
151 | TreeView *tvPtr;
|
---|
152 | int x, y; /* Position of window. */
|
---|
153 |
|
---|
154 | int active; /* Indicates that the frame is active. */
|
---|
155 | int exportSelection;
|
---|
156 |
|
---|
157 | int insertPos; /* Position of the cursor within the
|
---|
158 | * array of bytes of the entry's label. */
|
---|
159 |
|
---|
160 | int cursorX, cursorY; /* Position of the insertion cursor in the
|
---|
161 | * textbox window. */
|
---|
162 | short int cursorWidth; /* Size of the insertion cursor symbol. */
|
---|
163 | short int cursorHeight;
|
---|
164 |
|
---|
165 | int selAnchor; /* Fixed end of selection. Used to extend
|
---|
166 | * the selection while maintaining the
|
---|
167 | * other end of the selection. */
|
---|
168 | int selFirst; /* Position of the first character in the
|
---|
169 | * selection. */
|
---|
170 | int selLast; /* Position of the last character in the
|
---|
171 | * selection. */
|
---|
172 |
|
---|
173 | int cursorOn; /* Indicates if the cursor is displayed. */
|
---|
174 | int onTime, offTime; /* Time in milliseconds to wait before
|
---|
175 | * changing the cursor from off-to-on
|
---|
176 | * and on-to-off. Setting offTime to 0 makes
|
---|
177 | * the cursor steady. */
|
---|
178 | Tcl_TimerToken timerToken; /* Handle for a timer event called periodically
|
---|
179 | * to blink the cursor. */
|
---|
180 | /* Data-specific fields. */
|
---|
181 | TreeViewEntry *entryPtr; /* Selected entry */
|
---|
182 | TreeViewColumn *columnPtr; /* Column of entry to be edited */
|
---|
183 | TreeViewStyle *stylePtr;
|
---|
184 | TreeViewIcon icon;
|
---|
185 | int gap;
|
---|
186 | char *string;
|
---|
187 | TextLayout *textPtr;
|
---|
188 | Tk_Font font;
|
---|
189 | GC gc;
|
---|
190 |
|
---|
191 | Tk_3DBorder selBorder;
|
---|
192 | int selRelief;
|
---|
193 | int selBorderWidth;
|
---|
194 | XColor *selFgColor; /* Text color of a selected entry. */
|
---|
195 | int buttonBorderWidth;
|
---|
196 | Tk_3DBorder buttonBorder;
|
---|
197 | int buttonRelief;
|
---|
198 | } Textbox;
|
---|
199 |
|
---|
200 | #define DEF_TEXTBOX_BACKGROUND RGB_WHITE
|
---|
201 | #define DEF_TEXTBOX_BORDERWIDTH STD_BORDERWIDTH
|
---|
202 | #ifdef WIN32
|
---|
203 | #define DEF_TEXTBOX_BUTTON_BACKGROUND RGB_GREY85
|
---|
204 | #else
|
---|
205 | #define DEF_TEXTBOX_BUTTON_BACKGROUND RGB_GREY90
|
---|
206 | #endif
|
---|
207 | #define DEF_TEXTBOX_BUTTON_BORDERWIDTH "2"
|
---|
208 | #define DEF_TEXTBOX_BUTTON_RELIEF "raised"
|
---|
209 | #define DEF_TEXTBOX_CURSOR (char *)NULL
|
---|
210 | #define DEF_TEXTBOX_EXPORT_SELECTION "no"
|
---|
211 | #define DEF_TEXTBOX_NORMAL_BACKGROUND STD_NORMAL_BACKGROUND
|
---|
212 | #define DEF_TEXTBOX_NORMAL_FG_MONO STD_ACTIVE_FG_MONO
|
---|
213 | #define DEF_TEXTBOX_RELIEF "sunken"
|
---|
214 | #define DEF_TEXTBOX_SELECT_BACKGROUND RGB_LIGHTBLUE0
|
---|
215 | #define DEF_TEXTBOX_SELECT_BG_MONO STD_SELECT_BG_MONO
|
---|
216 | #define DEF_TEXTBOX_SELECT_BORDERWIDTH "1"
|
---|
217 | #define DEF_TEXTBOX_SELECT_FOREGROUND STD_SELECT_FOREGROUND
|
---|
218 | #define DEF_TEXTBOX_SELECT_FG_MONO STD_SELECT_FG_MONO
|
---|
219 | #define DEF_TEXTBOX_SELECT_RELIEF "flat"
|
---|
220 |
|
---|
221 | /* Textbox Procedures */
|
---|
222 | static Blt_ConfigSpec textboxConfigSpecs[] =
|
---|
223 | {
|
---|
224 | {BLT_CONFIG_BORDER, "-background", "background", "Background",
|
---|
225 | DEF_TEXTBOX_BACKGROUND, Blt_Offset(Textbox, border), 0},
|
---|
226 | {BLT_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0,0},
|
---|
227 | {BLT_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0,0},
|
---|
228 | {BLT_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
|
---|
229 | DEF_TEXTBOX_CURSOR, Blt_Offset(Textbox, cursor),
|
---|
230 | BLT_CONFIG_NULL_OK},
|
---|
231 | {BLT_CONFIG_DISTANCE, "-borderwidth", "borderWidth", "BorderWidth",
|
---|
232 | DEF_TEXTBOX_BORDERWIDTH, Blt_Offset(Textbox, borderWidth),
|
---|
233 | BLT_CONFIG_DONT_SET_DEFAULT},
|
---|
234 | {BLT_CONFIG_BORDER, "-buttonbackground", "buttonBackground",
|
---|
235 | "ButtonBackground", DEF_TEXTBOX_BUTTON_BACKGROUND,
|
---|
236 | Blt_Offset(Textbox, buttonBorder), 0},
|
---|
237 | {BLT_CONFIG_RELIEF, "-buttonrelief", "buttonRelief", "ButtonRelief",
|
---|
238 | DEF_TEXTBOX_BUTTON_RELIEF, Blt_Offset(Textbox, buttonRelief),
|
---|
239 | BLT_CONFIG_DONT_SET_DEFAULT},
|
---|
240 | {BLT_CONFIG_DISTANCE, "-buttonborderwidth", "buttonBorderWidth",
|
---|
241 | "ButtonBorderWidth", DEF_TEXTBOX_BUTTON_BORDERWIDTH,
|
---|
242 | Blt_Offset(Textbox, buttonBorderWidth),
|
---|
243 | BLT_CONFIG_DONT_SET_DEFAULT},
|
---|
244 | {BLT_CONFIG_BOOLEAN, "-exportselection", "exportSelection",
|
---|
245 | "ExportSelection", DEF_TEXTBOX_EXPORT_SELECTION,
|
---|
246 | Blt_Offset(Textbox, exportSelection),
|
---|
247 | BLT_CONFIG_DONT_SET_DEFAULT},
|
---|
248 | {BLT_CONFIG_RELIEF, "-relief", "relief", "Relief",
|
---|
249 | DEF_TEXTBOX_RELIEF, Blt_Offset(Textbox, relief), 0},
|
---|
250 | {BLT_CONFIG_BORDER, "-selectbackground", "selectBackground", "Background",
|
---|
251 | DEF_TEXTBOX_SELECT_BG_MONO, Blt_Offset(Textbox, selBorder),
|
---|
252 | BLT_CONFIG_MONO_ONLY},
|
---|
253 | {BLT_CONFIG_BORDER, "-selectbackground", "selectBackground", "Background",
|
---|
254 | DEF_TEXTBOX_SELECT_BACKGROUND, Blt_Offset(Textbox, selBorder),
|
---|
255 | BLT_CONFIG_COLOR_ONLY},
|
---|
256 | {BLT_CONFIG_DISTANCE, "-selectborderwidth", "selectBorderWidth",
|
---|
257 | "BorderWidth", DEF_TEXTBOX_SELECT_BORDERWIDTH,
|
---|
258 | Blt_Offset(Textbox, selBorderWidth),
|
---|
259 | BLT_CONFIG_DONT_SET_DEFAULT},
|
---|
260 | {BLT_CONFIG_COLOR, "-selectforeground", "selectForeground", "Foreground",
|
---|
261 |
|
---|
262 | DEF_TEXTBOX_SELECT_FG_MONO, Blt_Offset(Textbox, selFgColor),
|
---|
263 | BLT_CONFIG_MONO_ONLY},
|
---|
264 | {BLT_CONFIG_COLOR, "-selectforeground", "selectForeground", "Foreground",
|
---|
265 | DEF_TEXTBOX_SELECT_FOREGROUND, Blt_Offset(Textbox, selFgColor),
|
---|
266 | BLT_CONFIG_COLOR_ONLY},
|
---|
267 | {BLT_CONFIG_RELIEF, "-selectrelief", "selectRelief", "Relief",
|
---|
268 | DEF_TEXTBOX_SELECT_RELIEF, Blt_Offset(Textbox, selRelief),
|
---|
269 | BLT_CONFIG_DONT_SET_DEFAULT},
|
---|
270 | {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL,
|
---|
271 | 0, 0}
|
---|
272 | };
|
---|
273 |
|
---|
274 | static Tk_LostSelProc TextboxLostSelectionProc;
|
---|
275 | static Tk_SelectionProc TextboxSelectionProc;
|
---|
276 | static Tk_EventProc TextboxEventProc;
|
---|
277 |
|
---|
278 | /*
|
---|
279 | *----------------------------------------------------------------------
|
---|
280 | *
|
---|
281 | * EventuallyRedraw --
|
---|
282 | *
|
---|
283 | * Queues a request to redraw the widget at the next idle point.
|
---|
284 | *
|
---|
285 | * Results:
|
---|
286 | * None.
|
---|
287 | *
|
---|
288 | * Side effects:
|
---|
289 | * Information gets redisplayed. Right now we don't do selective
|
---|
290 | * redisplays: the whole window will be redrawn.
|
---|
291 | *
|
---|
292 | *----------------------------------------------------------------------
|
---|
293 | */
|
---|
294 | static void
|
---|
295 | EventuallyRedraw(tbPtr)
|
---|
296 | Textbox *tbPtr;
|
---|
297 | {
|
---|
298 | if ((tbPtr->tkwin != NULL) &&
|
---|
299 | ((tbPtr->flags & TEXTBOX_REDRAW) == 0)) {
|
---|
300 | tbPtr->flags |= TEXTBOX_REDRAW;
|
---|
301 | Tcl_DoWhenIdle(DisplayTextbox, tbPtr);
|
---|
302 | }
|
---|
303 | }
|
---|
304 |
|
---|
305 | /*
|
---|
306 | *----------------------------------------------------------------------
|
---|
307 | *
|
---|
308 | * BlinkCursorProc --
|
---|
309 | *
|
---|
310 | * This procedure is called as a timer handler to blink the
|
---|
311 | * insertion cursor off and on.
|
---|
312 | *
|
---|
313 | * Results:
|
---|
314 | * None.
|
---|
315 | *
|
---|
316 | * Side effects:
|
---|
317 | * The cursor gets turned on or off, redisplay gets invoked,
|
---|
318 | * and this procedure reschedules itself.
|
---|
319 | *
|
---|
320 | *----------------------------------------------------------------------
|
---|
321 | */
|
---|
322 | static void
|
---|
323 | BlinkCursorProc(clientData)
|
---|
324 | ClientData clientData; /* Pointer to record describing entry. */
|
---|
325 | {
|
---|
326 | Textbox *tbPtr = clientData;
|
---|
327 | int interval;
|
---|
328 |
|
---|
329 | if (!(tbPtr->flags & TEXTBOX_FOCUS) || (tbPtr->offTime == 0)) {
|
---|
330 | return;
|
---|
331 | }
|
---|
332 | if (tbPtr->active) {
|
---|
333 | tbPtr->cursorOn ^= 1;
|
---|
334 | interval = (tbPtr->cursorOn) ? tbPtr->onTime : tbPtr->offTime;
|
---|
335 | tbPtr->timerToken =
|
---|
336 | Tcl_CreateTimerHandler(interval, BlinkCursorProc, tbPtr);
|
---|
337 | EventuallyRedraw(tbPtr);
|
---|
338 | }
|
---|
339 | }
|
---|
340 |
|
---|
341 | /*
|
---|
342 | * --------------------------------------------------------------
|
---|
343 | *
|
---|
344 | * TextboxEventProc --
|
---|
345 | *
|
---|
346 | * This procedure is invoked by the Tk dispatcher for various
|
---|
347 | * events on treeview widgets.
|
---|
348 | *
|
---|
349 | * Results:
|
---|
350 | * None.
|
---|
351 | *
|
---|
352 | * Side effects:
|
---|
353 | * When the window gets deleted, internal structures get
|
---|
354 | * cleaned up. When it gets exposed, it is redisplayed.
|
---|
355 | *
|
---|
356 | * --------------------------------------------------------------
|
---|
357 | */
|
---|
358 | static void
|
---|
359 | TextboxEventProc(clientData, eventPtr)
|
---|
360 | ClientData clientData; /* Information about window. */
|
---|
361 | XEvent *eventPtr; /* Information about event. */
|
---|
362 | {
|
---|
363 | Textbox *tbPtr = clientData;
|
---|
364 |
|
---|
365 | if (eventPtr->type == Expose) {
|
---|
366 | if (eventPtr->xexpose.count == 0) {
|
---|
367 | EventuallyRedraw(tbPtr);
|
---|
368 | }
|
---|
369 | } else if (eventPtr->type == ConfigureNotify) {
|
---|
370 | EventuallyRedraw(tbPtr);
|
---|
371 | } else if ((eventPtr->type == FocusIn) || (eventPtr->type == FocusOut)) {
|
---|
372 | if (eventPtr->xfocus.detail == NotifyInferior) {
|
---|
373 | return;
|
---|
374 | }
|
---|
375 | if (eventPtr->type == FocusIn) {
|
---|
376 | tbPtr->flags |= TEXTBOX_FOCUS;
|
---|
377 | } else {
|
---|
378 | tbPtr->flags &= ~TEXTBOX_FOCUS;
|
---|
379 | }
|
---|
380 | Tcl_DeleteTimerHandler(tbPtr->timerToken);
|
---|
381 | if ((tbPtr->active) && (tbPtr->flags & TEXTBOX_FOCUS)) {
|
---|
382 | tbPtr->cursorOn = TRUE;
|
---|
383 | if (tbPtr->offTime != 0) {
|
---|
384 | tbPtr->timerToken = Tcl_CreateTimerHandler(tbPtr->onTime,
|
---|
385 | BlinkCursorProc, tbPtr);
|
---|
386 | }
|
---|
387 | } else {
|
---|
388 | tbPtr->cursorOn = FALSE;
|
---|
389 | tbPtr->timerToken = (Tcl_TimerToken) NULL;
|
---|
390 | }
|
---|
391 | EventuallyRedraw(tbPtr);
|
---|
392 | } else if (eventPtr->type == DestroyNotify) {
|
---|
393 | if (tbPtr->tkwin != NULL) {
|
---|
394 | tbPtr->tkwin = NULL;
|
---|
395 | }
|
---|
396 | if (tbPtr->flags & TEXTBOX_REDRAW) {
|
---|
397 | Tcl_CancelIdleCall(DisplayTextbox, tbPtr);
|
---|
398 | }
|
---|
399 | if (tbPtr->timerToken != NULL) {
|
---|
400 | Tcl_DeleteTimerHandler(tbPtr->timerToken);
|
---|
401 | }
|
---|
402 | tbPtr->tvPtr->comboWin = NULL;
|
---|
403 | Tcl_EventuallyFree(tbPtr, DestroyTextbox);
|
---|
404 | }
|
---|
405 | }
|
---|
406 |
|
---|
407 | /*
|
---|
408 | *----------------------------------------------------------------------
|
---|
409 | *
|
---|
410 | * TextboxLostSelectionProc --
|
---|
411 | *
|
---|
412 | * This procedure is called back by Tk when the selection is
|
---|
413 | * grabbed away from a Text widget.
|
---|
414 | *
|
---|
415 | * Results:
|
---|
416 | * None.
|
---|
417 | *
|
---|
418 | * Side effects:
|
---|
419 | * The existing selection is unhighlighted, and the window is
|
---|
420 | * marked as not containing a selection.
|
---|
421 | *
|
---|
422 | *----------------------------------------------------------------------
|
---|
423 | */
|
---|
424 | static void
|
---|
425 | TextboxLostSelectionProc(clientData)
|
---|
426 | ClientData clientData; /* Information about Text widget. */
|
---|
427 | {
|
---|
428 | Textbox *tbPtr = clientData;
|
---|
429 |
|
---|
430 | if ((tbPtr->selFirst >= 0) && (tbPtr->exportSelection)) {
|
---|
431 | tbPtr->selFirst = tbPtr->selLast = -1;
|
---|
432 | EventuallyRedraw(tbPtr);
|
---|
433 | }
|
---|
434 | }
|
---|
435 |
|
---|
436 | static int
|
---|
437 | PointerToIndex(tbPtr, x, y)
|
---|
438 | Textbox *tbPtr;
|
---|
439 | int x, y;
|
---|
440 | {
|
---|
441 | TextLayout *textPtr;
|
---|
442 | Tk_FontMetrics fontMetrics;
|
---|
443 | TextFragment *fragPtr;
|
---|
444 | int nBytes;
|
---|
445 | register int i;
|
---|
446 | int total;
|
---|
447 |
|
---|
448 | if ((tbPtr->string == NULL) || (tbPtr->string[0] == '\0')) {
|
---|
449 | return 0;
|
---|
450 | }
|
---|
451 | x -= tbPtr->selBorderWidth;
|
---|
452 | y -= tbPtr->selBorderWidth;
|
---|
453 |
|
---|
454 | textPtr = tbPtr->textPtr;
|
---|
455 |
|
---|
456 | /* Bound the y-coordinate within the window. */
|
---|
457 | if (y < 0) {
|
---|
458 | y = 0;
|
---|
459 | } else if (y >= textPtr->height) {
|
---|
460 | y = textPtr->height - 1;
|
---|
461 | }
|
---|
462 | /*
|
---|
463 | * Compute the line that contains the y-coordinate.
|
---|
464 | *
|
---|
465 | * FIXME: This assumes that segments are distributed
|
---|
466 | * line-by-line. This may change in the future.
|
---|
467 | */
|
---|
468 | Tk_GetFontMetrics(tbPtr->font, &fontMetrics);
|
---|
469 | fragPtr = textPtr->fragArr;
|
---|
470 | total = 0;
|
---|
471 | for (i = (y / fontMetrics.linespace); i > 0; i--) {
|
---|
472 | total += fragPtr->count;
|
---|
473 | fragPtr++;
|
---|
474 | }
|
---|
475 | if (x < 0) {
|
---|
476 | nBytes = 0;
|
---|
477 | } else if (x >= textPtr->width) {
|
---|
478 | nBytes = fragPtr->count;
|
---|
479 | } else {
|
---|
480 | int newX;
|
---|
481 |
|
---|
482 | /* Find the character underneath the pointer. */
|
---|
483 | nBytes = Tk_MeasureChars(tbPtr->font, fragPtr->text, fragPtr->count,
|
---|
484 | x, 0, &newX);
|
---|
485 | if ((newX < x) && (nBytes < fragPtr->count)) {
|
---|
486 | double fract;
|
---|
487 | int length, charSize;
|
---|
488 | char *next;
|
---|
489 |
|
---|
490 | next = fragPtr->text + nBytes;
|
---|
491 | #if HAVE_UTF
|
---|
492 | {
|
---|
493 | Tcl_UniChar dummy;
|
---|
494 |
|
---|
495 | length = Tcl_UtfToUniChar(next, &dummy);
|
---|
496 | }
|
---|
497 | #else
|
---|
498 | length = 1;
|
---|
499 | #endif
|
---|
500 | charSize = Tk_TextWidth(tbPtr->font, next, length);
|
---|
501 | fract = ((double)(x - newX) / (double)charSize);
|
---|
502 | if (ROUND(fract)) {
|
---|
503 | nBytes += length;
|
---|
504 | }
|
---|
505 | }
|
---|
506 | }
|
---|
507 | return nBytes + total;
|
---|
508 | }
|
---|
509 |
|
---|
510 | static int
|
---|
511 | IndexToPointer(tbPtr)
|
---|
512 | Textbox *tbPtr;
|
---|
513 | {
|
---|
514 | int x, y;
|
---|
515 | int maxLines;
|
---|
516 | TextLayout *textPtr;
|
---|
517 | Tk_FontMetrics fontMetrics;
|
---|
518 | int nBytes;
|
---|
519 | int sum;
|
---|
520 | TextFragment *fragPtr;
|
---|
521 | register int i;
|
---|
522 |
|
---|
523 | textPtr = tbPtr->textPtr;
|
---|
524 | Tk_GetFontMetrics(tbPtr->font, &fontMetrics);
|
---|
525 | maxLines = (textPtr->height / fontMetrics.linespace) - 1;
|
---|
526 |
|
---|
527 | sum = 0;
|
---|
528 | x = y = tbPtr->borderWidth;
|
---|
529 | if (tbPtr->icon != NULL) {
|
---|
530 | x += TreeViewIconWidth(tbPtr->icon) + 2 * tbPtr->gap;
|
---|
531 | }
|
---|
532 | fragPtr = textPtr->fragArr;
|
---|
533 | for (i = 0; i <= maxLines; i++) {
|
---|
534 | /* Total the number of bytes on each line. Include newlines. */
|
---|
535 | nBytes = fragPtr->count + 1;
|
---|
536 | if ((sum + nBytes) > tbPtr->insertPos) {
|
---|
537 | x += Tk_TextWidth(tbPtr->font, fragPtr->text,
|
---|
538 | tbPtr->insertPos - sum);
|
---|
539 | break;
|
---|
540 | }
|
---|
541 | y += fontMetrics.linespace;
|
---|
542 | sum += nBytes;
|
---|
543 | fragPtr++;
|
---|
544 | }
|
---|
545 | tbPtr->cursorX = x;
|
---|
546 | tbPtr->cursorY = y;
|
---|
547 | tbPtr->cursorHeight = fontMetrics.linespace;
|
---|
548 | tbPtr->cursorWidth = 3;
|
---|
549 | return TCL_OK;
|
---|
550 | }
|
---|
551 |
|
---|
552 | static void
|
---|
553 | UpdateLayout(tbPtr)
|
---|
554 | Textbox *tbPtr;
|
---|
555 | {
|
---|
556 | TextStyle ts;
|
---|
557 | int width, height;
|
---|
558 | TextLayout *textPtr;
|
---|
559 | int gap;
|
---|
560 | int iconWidth, iconHeight;
|
---|
561 |
|
---|
562 | gap = iconWidth = iconHeight = 0;
|
---|
563 | if (tbPtr->icon != NULL) {
|
---|
564 | iconWidth = TreeViewIconWidth(tbPtr->icon) + 4;
|
---|
565 | iconHeight = TreeViewIconHeight(tbPtr->icon);
|
---|
566 | gap = tbPtr->gap;
|
---|
567 | }
|
---|
568 |
|
---|
569 | /* The layout is based upon the current font. */
|
---|
570 | Blt_InitTextStyle(&ts);
|
---|
571 | ts.anchor = TK_ANCHOR_NW;
|
---|
572 | ts.justify = TK_JUSTIFY_LEFT;
|
---|
573 | ts.font = tbPtr->font;
|
---|
574 | textPtr = Blt_GetTextLayout(tbPtr->string, &ts);
|
---|
575 | if (tbPtr->textPtr != NULL) {
|
---|
576 | Blt_Free(tbPtr->textPtr);
|
---|
577 | }
|
---|
578 | tbPtr->textPtr = textPtr;
|
---|
579 |
|
---|
580 | width = iconWidth + textPtr->width + gap * 2;
|
---|
581 | height = MAX(iconHeight, textPtr->height);
|
---|
582 |
|
---|
583 | if (width <= tbPtr->columnPtr->width) {
|
---|
584 | width = tbPtr->columnPtr->width;
|
---|
585 | }
|
---|
586 | if (height < tbPtr->entryPtr->height) {
|
---|
587 | height = tbPtr->entryPtr->height;
|
---|
588 | }
|
---|
589 | tbPtr->width = width + (2 * tbPtr->borderWidth);
|
---|
590 | tbPtr->height = height + (2 * tbPtr->borderWidth);
|
---|
591 | IndexToPointer(tbPtr);
|
---|
592 | Tk_MoveResizeWindow(tbPtr->tkwin, tbPtr->x, tbPtr->y,
|
---|
593 | tbPtr->width, tbPtr->height);
|
---|
594 | Tk_MapWindow(tbPtr->tkwin);
|
---|
595 | XRaiseWindow(tbPtr->display, Tk_WindowId(tbPtr->tkwin));
|
---|
596 | }
|
---|
597 |
|
---|
598 | static void
|
---|
599 | InsertText(tbPtr, insertText, insertPos, nBytes)
|
---|
600 | Textbox *tbPtr;
|
---|
601 | char *insertText;
|
---|
602 | int insertPos;
|
---|
603 | int nBytes;
|
---|
604 | {
|
---|
605 | int oldSize, newSize;
|
---|
606 | char *oldText, *newText;
|
---|
607 |
|
---|
608 | oldText = tbPtr->string;
|
---|
609 | oldSize = strlen(oldText);
|
---|
610 | newSize = oldSize + nBytes;
|
---|
611 | newText = Blt_Malloc(sizeof(char) * (newSize + 1));
|
---|
612 | if (insertPos == oldSize) { /* Append */
|
---|
613 | strcpy(newText, oldText);
|
---|
614 | strcat(newText, insertText);
|
---|
615 | } else if (insertPos == 0) {/* Prepend */
|
---|
616 | strcpy(newText, insertText);
|
---|
617 | strcat(newText, oldText);
|
---|
618 | } else { /* Insert into existing. */
|
---|
619 | char *p;
|
---|
620 |
|
---|
621 | p = newText;
|
---|
622 | strncpy(p, oldText, insertPos);
|
---|
623 | p += insertPos;
|
---|
624 | strcpy(p, insertText);
|
---|
625 | p += nBytes;
|
---|
626 | strcpy(p, oldText + insertPos);
|
---|
627 | }
|
---|
628 |
|
---|
629 | /*
|
---|
630 | * All indices from the start of the insertion to the end of the
|
---|
631 | * string need to be updated. Simply move the indices down by the
|
---|
632 | * number of characters added.
|
---|
633 | */
|
---|
634 | if (tbPtr->selFirst >= insertPos) {
|
---|
635 | tbPtr->selFirst += nBytes;
|
---|
636 | }
|
---|
637 | if (tbPtr->selLast > insertPos) {
|
---|
638 | tbPtr->selLast += nBytes;
|
---|
639 | }
|
---|
640 | if ((tbPtr->selAnchor > insertPos) || (tbPtr->selFirst >= insertPos)) {
|
---|
641 | tbPtr->selAnchor += nBytes;
|
---|
642 | }
|
---|
643 | if (tbPtr->string != NULL) {
|
---|
644 | Blt_Free(tbPtr->string);
|
---|
645 | }
|
---|
646 | tbPtr->string = newText;
|
---|
647 | tbPtr->insertPos = insertPos + nBytes;
|
---|
648 | UpdateLayout(tbPtr);
|
---|
649 | }
|
---|
650 |
|
---|
651 | static int
|
---|
652 | DeleteText(tbPtr, firstPos, lastPos)
|
---|
653 | Textbox *tbPtr;
|
---|
654 | int firstPos, lastPos;
|
---|
655 | {
|
---|
656 | char *oldText, *newText;
|
---|
657 | int oldSize, newSize;
|
---|
658 | int nBytes;
|
---|
659 | char *p;
|
---|
660 |
|
---|
661 | oldText = tbPtr->string;
|
---|
662 | if (firstPos > lastPos) {
|
---|
663 | return TCL_OK;
|
---|
664 | }
|
---|
665 | lastPos++; /* Now is the position after the last
|
---|
666 | * character. */
|
---|
667 |
|
---|
668 | nBytes = lastPos - firstPos;
|
---|
669 |
|
---|
670 | oldSize = strlen(oldText) + 1;
|
---|
671 | newSize = oldSize - nBytes + 1;
|
---|
672 | newText = Blt_Malloc(sizeof(char) * newSize);
|
---|
673 | p = newText;
|
---|
674 | if (firstPos > 0) {
|
---|
675 | strncpy(p, oldText, firstPos);
|
---|
676 | p += firstPos;
|
---|
677 | }
|
---|
678 | *p = '\0';
|
---|
679 | if (lastPos < oldSize) {
|
---|
680 | strcpy(p, oldText + lastPos);
|
---|
681 | }
|
---|
682 | Blt_Free(oldText);
|
---|
683 |
|
---|
684 | /*
|
---|
685 | * Since deleting characters compacts the character array, we need to
|
---|
686 | * update the various character indices according. It depends where
|
---|
687 | * the index occurs in relation to range of deleted characters:
|
---|
688 | *
|
---|
689 | * before Ignore.
|
---|
690 | * within Move the index back to the start of the deletion.
|
---|
691 | * after Subtract off the deleted number of characters,
|
---|
692 | * since the array has been compressed by that
|
---|
693 | * many characters.
|
---|
694 | *
|
---|
695 | */
|
---|
696 | if (tbPtr->selFirst >= firstPos) {
|
---|
697 | if (tbPtr->selFirst >= lastPos) {
|
---|
698 | tbPtr->selFirst -= nBytes;
|
---|
699 | } else {
|
---|
700 | tbPtr->selFirst = firstPos;
|
---|
701 | }
|
---|
702 | }
|
---|
703 | if (tbPtr->selLast >= firstPos) {
|
---|
704 | if (tbPtr->selLast >= lastPos) {
|
---|
705 | tbPtr->selLast -= nBytes;
|
---|
706 | } else {
|
---|
707 | tbPtr->selLast = firstPos;
|
---|
708 | }
|
---|
709 | }
|
---|
710 | if (tbPtr->selLast <= tbPtr->selFirst) {
|
---|
711 | tbPtr->selFirst = tbPtr->selLast = -1; /* Cut away the entire
|
---|
712 | * selection. */
|
---|
713 | }
|
---|
714 | if (tbPtr->selAnchor >= firstPos) {
|
---|
715 | if (tbPtr->selAnchor >= lastPos) {
|
---|
716 | tbPtr->selAnchor -= nBytes;
|
---|
717 | } else {
|
---|
718 | tbPtr->selAnchor = firstPos;
|
---|
719 | }
|
---|
720 | }
|
---|
721 | if (tbPtr->insertPos >= firstPos) {
|
---|
722 | if (tbPtr->insertPos >= lastPos) {
|
---|
723 | tbPtr->insertPos -= nBytes;
|
---|
724 | } else {
|
---|
725 | tbPtr->insertPos = firstPos;
|
---|
726 | }
|
---|
727 | }
|
---|
728 | tbPtr->string = newText;
|
---|
729 | UpdateLayout(tbPtr);
|
---|
730 | EventuallyRedraw(tbPtr);
|
---|
731 | return TCL_OK;
|
---|
732 | }
|
---|
733 |
|
---|
734 | static int
|
---|
735 | AcquireText(tvPtr, tbPtr, entryPtr, columnPtr)
|
---|
736 | TreeView *tvPtr;
|
---|
737 | Textbox *tbPtr;
|
---|
738 | TreeViewEntry *entryPtr;
|
---|
739 | TreeViewColumn *columnPtr;
|
---|
740 | {
|
---|
741 | TreeViewStyle *stylePtr;
|
---|
742 | int x, y;
|
---|
743 | char *string;
|
---|
744 | TreeViewIcon icon;
|
---|
745 |
|
---|
746 | if (columnPtr == &tvPtr->treeColumn) {
|
---|
747 | int level;
|
---|
748 |
|
---|
749 | level = DEPTH(tvPtr, entryPtr->node);
|
---|
750 | x = SCREENX(tvPtr, entryPtr->worldX);
|
---|
751 | y = SCREENY(tvPtr, entryPtr->worldY);
|
---|
752 | x += ICONWIDTH(level) + ICONWIDTH(level + 1) + 4;
|
---|
753 | string = GETLABEL(entryPtr);
|
---|
754 | stylePtr = columnPtr->stylePtr;
|
---|
755 | icon = Blt_TreeViewGetEntryIcon(tvPtr, entryPtr);
|
---|
756 | } else {
|
---|
757 | TreeViewValue *valuePtr;
|
---|
758 |
|
---|
759 | x = SCREENX(tvPtr, columnPtr->worldX);
|
---|
760 | y = SCREENY(tvPtr, entryPtr->worldY);
|
---|
761 | stylePtr = columnPtr->stylePtr;
|
---|
762 | valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr);
|
---|
763 | string = valuePtr->string;
|
---|
764 | if (valuePtr->stylePtr != NULL) {
|
---|
765 | stylePtr = valuePtr->stylePtr;
|
---|
766 | }
|
---|
767 | icon = stylePtr->icon;
|
---|
768 | }
|
---|
769 | if (tbPtr->textPtr != NULL) {
|
---|
770 | Blt_Free(tbPtr->textPtr);
|
---|
771 | tbPtr->textPtr = NULL;
|
---|
772 | }
|
---|
773 | if (tbPtr->string != NULL) {
|
---|
774 | Blt_Free(tbPtr->string);
|
---|
775 | }
|
---|
776 | if (string == NULL) {
|
---|
777 | string = "";
|
---|
778 | }
|
---|
779 | tbPtr->icon = icon;
|
---|
780 | tbPtr->entryPtr = entryPtr;
|
---|
781 | tbPtr->columnPtr = columnPtr;
|
---|
782 | tbPtr->x = x - tbPtr->borderWidth;
|
---|
783 | tbPtr->y = y - tbPtr->borderWidth;
|
---|
784 |
|
---|
785 | tbPtr->gap = stylePtr->gap;
|
---|
786 | tbPtr->string = Blt_Strdup(string);
|
---|
787 | tbPtr->gc = Blt_TreeViewGetStyleGC(stylePtr);
|
---|
788 | tbPtr->font = Blt_TreeViewGetStyleFont(tvPtr, stylePtr);
|
---|
789 | tbPtr->selFirst = tbPtr->selLast = -1;
|
---|
790 | UpdateLayout(tbPtr);
|
---|
791 | Tk_MapWindow(tbPtr->tkwin);
|
---|
792 | EventuallyRedraw(tbPtr);
|
---|
793 | return TCL_OK;
|
---|
794 | }
|
---|
795 |
|
---|
796 |
|
---|
797 | /*
|
---|
798 | *---------------------------------------------------------------------------
|
---|
799 | *
|
---|
800 | * GetIndexFromObj --
|
---|
801 | *
|
---|
802 | * Parse an index into an entry and return either its value
|
---|
803 | * or an error.
|
---|
804 | *
|
---|
805 | * Results:
|
---|
806 | * A standard Tcl result. If all went well, then *indexPtr is
|
---|
807 | * filled in with the character index (into entryPtr) corresponding to
|
---|
808 | * string. The index value is guaranteed to lie between 0 and
|
---|
809 | * the number of characters in the string, inclusive. If an
|
---|
810 | * error occurs then an error message is left in the interp's result.
|
---|
811 | *
|
---|
812 | * Side effects:
|
---|
813 | * None.
|
---|
814 | *
|
---|
815 | *---------------------------------------------------------------------------
|
---|
816 | */
|
---|
817 | static int
|
---|
818 | GetIndexFromObj(interp, tbPtr, objPtr, indexPtr)
|
---|
819 | Tcl_Interp *interp;
|
---|
820 | Textbox *tbPtr;
|
---|
821 | Tcl_Obj *objPtr;
|
---|
822 | int *indexPtr;
|
---|
823 | {
|
---|
824 | int textPos;
|
---|
825 | char c;
|
---|
826 | char *string;
|
---|
827 |
|
---|
828 | string = Tcl_GetString(objPtr);
|
---|
829 | if ((tbPtr->string == NULL) || (tbPtr->string[0] == '\0')) {
|
---|
830 | *indexPtr = 0;
|
---|
831 | return TCL_OK;
|
---|
832 | }
|
---|
833 | c = string[0];
|
---|
834 | if ((c == 'a') && (strcmp(string, "anchor") == 0)) {
|
---|
835 | textPos = tbPtr->selAnchor;
|
---|
836 | } else if ((c == 'e') && (strcmp(string, "end") == 0)) {
|
---|
837 | textPos = strlen(tbPtr->string);
|
---|
838 | } else if ((c == 'i') && (strcmp(string, "insert") == 0)) {
|
---|
839 | textPos = tbPtr->insertPos;
|
---|
840 | } else if ((c == 'n') && (strcmp(string, "next") == 0)) {
|
---|
841 | textPos = tbPtr->insertPos;
|
---|
842 | if (textPos < (int)strlen(tbPtr->string)) {
|
---|
843 | textPos++;
|
---|
844 | }
|
---|
845 | } else if ((c == 'l') && (strcmp(string, "last") == 0)) {
|
---|
846 | textPos = tbPtr->insertPos;
|
---|
847 | if (textPos > 0) {
|
---|
848 | textPos--;
|
---|
849 | }
|
---|
850 | } else if ((c == 's') && (strcmp(string, "sel.first") == 0)) {
|
---|
851 | if (tbPtr->selFirst < 0) {
|
---|
852 | textPos = -1;
|
---|
853 | } else {
|
---|
854 | textPos = tbPtr->selFirst;
|
---|
855 | }
|
---|
856 | } else if ((c == 's') && (strcmp(string, "sel.last") == 0)) {
|
---|
857 | if (tbPtr->selLast < 0) {
|
---|
858 | textPos = -1;
|
---|
859 | } else {
|
---|
860 | textPos = tbPtr->selLast;
|
---|
861 | }
|
---|
862 | } else if (c == '@') {
|
---|
863 | int x, y;
|
---|
864 |
|
---|
865 | if (Blt_GetXY(interp, tbPtr->tkwin, string, &x, &y) != TCL_OK) {
|
---|
866 | return TCL_ERROR;
|
---|
867 | }
|
---|
868 | textPos = PointerToIndex(tbPtr, x, y);
|
---|
869 | } else if (isdigit((int)c)) {
|
---|
870 | int number;
|
---|
871 | int maxChars;
|
---|
872 |
|
---|
873 | if (Tcl_GetIntFromObj(interp, objPtr, &number) != TCL_OK) {
|
---|
874 | return TCL_ERROR;
|
---|
875 | }
|
---|
876 | /* Don't allow the index to point outside the label. */
|
---|
877 | maxChars = Tcl_NumUtfChars(tbPtr->string, -1);
|
---|
878 | if (number < 0) {
|
---|
879 | textPos = 0;
|
---|
880 | } else if (number > maxChars) {
|
---|
881 | textPos = strlen(tbPtr->string);
|
---|
882 | } else {
|
---|
883 | textPos = Tcl_UtfAtIndex(tbPtr->string, number) -
|
---|
884 | tbPtr->string;
|
---|
885 | }
|
---|
886 | } else {
|
---|
887 | if (interp != NULL) {
|
---|
888 | Tcl_AppendResult(interp, "bad label index \"", string, "\"",
|
---|
889 | (char *)NULL);
|
---|
890 | }
|
---|
891 | return TCL_ERROR;
|
---|
892 | }
|
---|
893 | *indexPtr = textPos;
|
---|
894 | return TCL_OK;
|
---|
895 | }
|
---|
896 |
|
---|
897 | /*
|
---|
898 | *----------------------------------------------------------------------
|
---|
899 | *
|
---|
900 | * SelectText --
|
---|
901 | *
|
---|
902 | * Modify the selection by moving its un-anchored end. This
|
---|
903 | * could make the selection either larger or smaller.
|
---|
904 | *
|
---|
905 | * Results:
|
---|
906 | * None.
|
---|
907 | *
|
---|
908 | * Side effects:
|
---|
909 | * The selection changes.
|
---|
910 | *
|
---|
911 | *----------------------------------------------------------------------
|
---|
912 | */
|
---|
913 | static int
|
---|
914 | SelectText(tbPtr, textPos)
|
---|
915 | Textbox *tbPtr; /* Information about textbox. */
|
---|
916 | int textPos; /* Index of element that is to
|
---|
917 | * become the "other" end of the
|
---|
918 | * selection. */
|
---|
919 | {
|
---|
920 | int selFirst, selLast;
|
---|
921 |
|
---|
922 | /*
|
---|
923 | * Grab the selection if we don't own it already.
|
---|
924 | */
|
---|
925 | if ((tbPtr->exportSelection) && (tbPtr->selFirst == -1)) {
|
---|
926 | Tk_OwnSelection(tbPtr->tkwin, XA_PRIMARY,
|
---|
927 | TextboxLostSelectionProc, tbPtr);
|
---|
928 | }
|
---|
929 | /* If the anchor hasn't been set yet, assume the beginning of the text*/
|
---|
930 | if (tbPtr->selAnchor < 0) {
|
---|
931 | tbPtr->selAnchor = 0;
|
---|
932 | }
|
---|
933 | if (tbPtr->selAnchor <= textPos) {
|
---|
934 | selFirst = tbPtr->selAnchor;
|
---|
935 | selLast = textPos;
|
---|
936 | } else {
|
---|
937 | selFirst = textPos;
|
---|
938 | selLast = tbPtr->selAnchor;
|
---|
939 | }
|
---|
940 | if ((tbPtr->selFirst != selFirst) || (tbPtr->selLast != selLast)) {
|
---|
941 | tbPtr->selFirst = selFirst;
|
---|
942 | tbPtr->selLast = selLast;
|
---|
943 | EventuallyRedraw(tbPtr);
|
---|
944 | }
|
---|
945 | return TCL_OK;
|
---|
946 | }
|
---|
947 |
|
---|
948 | /*
|
---|
949 | *----------------------------------------------------------------------
|
---|
950 | *
|
---|
951 | * TextboxSelectionProc --
|
---|
952 | *
|
---|
953 | * This procedure is called back by Tk when the selection is
|
---|
954 | * requested by someone. It returns part or all of the selection
|
---|
955 | * in a buffer provided by the caller.
|
---|
956 | *
|
---|
957 | * Results:
|
---|
958 | * The return value is the number of non-NULL bytes stored at
|
---|
959 | * buffer. Buffer is filled (or partially filled) with a
|
---|
960 | * NUL-terminated string containing part or all of the
|
---|
961 | * selection, as given by offset and maxBytes.
|
---|
962 | *
|
---|
963 | * Side effects:
|
---|
964 | * None.
|
---|
965 | *
|
---|
966 | *----------------------------------------------------------------------
|
---|
967 | */
|
---|
968 | static int
|
---|
969 | TextboxSelectionProc(clientData, offset, buffer, maxBytes)
|
---|
970 | ClientData clientData; /* Information about the widget. */
|
---|
971 | int offset; /* Offset within selection of first
|
---|
972 | * character to be returned. */
|
---|
973 | char *buffer; /* Location in which to place
|
---|
974 | * selection. */
|
---|
975 | int maxBytes; /* Maximum number of bytes to place
|
---|
976 | * at buffer, not including terminating
|
---|
977 | * NULL character. */
|
---|
978 | {
|
---|
979 | Textbox *tbPtr = clientData;
|
---|
980 | int size;
|
---|
981 |
|
---|
982 | size = strlen(tbPtr->string + offset);
|
---|
983 | /*
|
---|
984 | * Return the string currently in the textbox.
|
---|
985 | */
|
---|
986 | strncpy(buffer, tbPtr->string + offset, maxBytes);
|
---|
987 | buffer[maxBytes] = '\0';
|
---|
988 | return (size > maxBytes) ? maxBytes : size;
|
---|
989 | }
|
---|
990 |
|
---|
991 |
|
---|
992 | static void
|
---|
993 | DestroyTextbox(data)
|
---|
994 | DestroyData data;
|
---|
995 | {
|
---|
996 | Textbox *tbPtr = (Textbox *)data;
|
---|
997 |
|
---|
998 | Blt_FreeObjOptions(textboxConfigSpecs, (char *)tbPtr,
|
---|
999 | tbPtr->display, 0);
|
---|
1000 |
|
---|
1001 | if (tbPtr->string != NULL) {
|
---|
1002 | Blt_Free(tbPtr->string);
|
---|
1003 | }
|
---|
1004 | if (tbPtr->textPtr != NULL) {
|
---|
1005 | Blt_Free(tbPtr->textPtr);
|
---|
1006 | }
|
---|
1007 | if (tbPtr->timerToken != NULL) {
|
---|
1008 | Tcl_DeleteTimerHandler(tbPtr->timerToken);
|
---|
1009 | }
|
---|
1010 | if (tbPtr->tkwin != NULL) {
|
---|
1011 | Tk_DeleteSelHandler(tbPtr->tkwin, XA_PRIMARY, XA_STRING);
|
---|
1012 | }
|
---|
1013 | Blt_Free(tbPtr);
|
---|
1014 | }
|
---|
1015 |
|
---|
1016 | static void
|
---|
1017 | ConfigureTextbox(tbPtr)
|
---|
1018 | Textbox *tbPtr;
|
---|
1019 | {
|
---|
1020 | #ifdef notdef
|
---|
1021 | GC newGC;
|
---|
1022 | Textbox *tbPtr = tvPtr->tbPtr;
|
---|
1023 | XGCValues gcValues;
|
---|
1024 | unsigned long gcMask;
|
---|
1025 |
|
---|
1026 | /*
|
---|
1027 | * GC for edit window.
|
---|
1028 | */
|
---|
1029 | gcMask = 0;
|
---|
1030 | newGC = Tk_GetGC(tbPtr->tkwin, gcMask, &gcValues);
|
---|
1031 | if (tbPtr->gc != NULL) {
|
---|
1032 | Tk_FreeGC(tbPtr->display, tbPtr->gc);
|
---|
1033 | }
|
---|
1034 | tbPtr->gc = newGC;
|
---|
1035 | tbPtr->width = tbPtr->textPtr->width +
|
---|
1036 | 2 * (tbPtr->borderWidth + tbPtr->highlightWidth);
|
---|
1037 | tbPtr->height = tbPtr->textPtr->height +
|
---|
1038 | 2 * (tbPtr->borderWidth + tbPtr->highlightWidth);
|
---|
1039 |
|
---|
1040 | if (Tk_IsMapped(tbPtr->tkwin)) {
|
---|
1041 | if ((tbPtr->height != Tk_Height(tbPtr->tkwin)) ||
|
---|
1042 | (tbPtr->width != Tk_Width(tbPtr->tkwin))) {
|
---|
1043 | Tk_ResizeWindow(tbPtr->tkwin, tbPtr->width, tbPtr->height);
|
---|
1044 | }
|
---|
1045 | }
|
---|
1046 | #endif
|
---|
1047 | }
|
---|
1048 |
|
---|
1049 | int
|
---|
1050 | Blt_TreeViewTextbox(tvPtr, entryPtr, columnPtr)
|
---|
1051 | TreeView *tvPtr;
|
---|
1052 | TreeViewEntry *entryPtr;
|
---|
1053 | TreeViewColumn *columnPtr;
|
---|
1054 | {
|
---|
1055 | Tk_Window tkwin;
|
---|
1056 | Textbox *tbPtr;
|
---|
1057 | char editClass[20];
|
---|
1058 |
|
---|
1059 | if (tvPtr->comboWin != NULL) {
|
---|
1060 | Tk_DestroyWindow(tvPtr->comboWin);
|
---|
1061 | }
|
---|
1062 | tkwin = Tk_CreateWindow(tvPtr->interp, tvPtr->tkwin, "edit", (char *)NULL);
|
---|
1063 | if (tkwin == NULL) {
|
---|
1064 | return TCL_ERROR;
|
---|
1065 | }
|
---|
1066 |
|
---|
1067 | Tk_MakeWindowExist(tkwin);
|
---|
1068 |
|
---|
1069 | sprintf(editClass, "%sEditor", Tk_Class(tvPtr->tkwin));
|
---|
1070 | Tk_SetClass(tkwin, editClass);
|
---|
1071 |
|
---|
1072 | tbPtr = Blt_Calloc(1, sizeof(Textbox));
|
---|
1073 | assert(tbPtr);
|
---|
1074 |
|
---|
1075 | tbPtr->interp = tvPtr->interp;
|
---|
1076 | tbPtr->display = Tk_Display(tkwin);
|
---|
1077 | tbPtr->tkwin = tkwin;
|
---|
1078 | tbPtr->borderWidth = 1;
|
---|
1079 | tbPtr->relief = TK_RELIEF_SOLID;
|
---|
1080 | tbPtr->selRelief = TK_RELIEF_FLAT;
|
---|
1081 | tbPtr->selBorderWidth = 1;
|
---|
1082 | tbPtr->selAnchor = -1;
|
---|
1083 | tbPtr->selFirst = tbPtr->selLast = -1;
|
---|
1084 | tbPtr->onTime = 600;
|
---|
1085 | tbPtr->active = TRUE;
|
---|
1086 | tbPtr->offTime = 300;
|
---|
1087 | tbPtr->tvPtr = tvPtr;
|
---|
1088 | tbPtr->buttonRelief = TK_RELIEF_SUNKEN;
|
---|
1089 | tbPtr->buttonBorderWidth = 1;
|
---|
1090 | tvPtr->comboWin = tkwin;
|
---|
1091 | #if (TK_MAJOR_VERSION > 4)
|
---|
1092 | Blt_SetWindowInstanceData(tkwin, tbPtr);
|
---|
1093 | #endif
|
---|
1094 | Tk_CreateSelHandler(tkwin, XA_PRIMARY, XA_STRING,
|
---|
1095 | TextboxSelectionProc, tbPtr, XA_STRING);
|
---|
1096 | Tk_CreateEventHandler(tkwin, ExposureMask | StructureNotifyMask |
|
---|
1097 | FocusChangeMask, TextboxEventProc, tbPtr);
|
---|
1098 | Tcl_CreateObjCommand(tvPtr->interp, Tk_PathName(tkwin),
|
---|
1099 | TextboxCmd, tbPtr, NULL);
|
---|
1100 | if (Blt_ConfigureWidgetFromObj(tvPtr->interp, tkwin, textboxConfigSpecs, 0,
|
---|
1101 | (Tcl_Obj **)NULL, (char *)tbPtr, 0) != TCL_OK) {
|
---|
1102 | Tk_DestroyWindow(tkwin);
|
---|
1103 | return TCL_ERROR;
|
---|
1104 | }
|
---|
1105 | AcquireText(tvPtr, tbPtr, entryPtr, columnPtr);
|
---|
1106 | tbPtr->insertPos = strlen(tbPtr->string);
|
---|
1107 |
|
---|
1108 | Tk_MoveResizeWindow(tkwin, tbPtr->x, tbPtr->y, tbPtr->width,
|
---|
1109 | tbPtr->height);
|
---|
1110 | Tk_MapWindow(tkwin);
|
---|
1111 | Tk_MakeWindowExist(tkwin);
|
---|
1112 | XRaiseWindow(tbPtr->display, Tk_WindowId(tkwin));
|
---|
1113 | EventuallyRedraw(tbPtr);
|
---|
1114 | return TCL_OK;
|
---|
1115 | }
|
---|
1116 |
|
---|
1117 | static void
|
---|
1118 | DisplayTextbox(clientData)
|
---|
1119 | ClientData clientData;
|
---|
1120 | {
|
---|
1121 | Textbox *tbPtr = clientData;
|
---|
1122 | Pixmap drawable;
|
---|
1123 | register int i;
|
---|
1124 | int x1, x2;
|
---|
1125 | int count, nChars;
|
---|
1126 | int leftPos, rightPos;
|
---|
1127 | int selStart, selEnd, selLength;
|
---|
1128 | int x, y;
|
---|
1129 | TextFragment *fragPtr;
|
---|
1130 | Tk_FontMetrics fontMetrics;
|
---|
1131 | #ifdef notdef
|
---|
1132 | int buttonX, buttonY, buttonWidth, buttonHeight;
|
---|
1133 | #endif
|
---|
1134 | tbPtr->flags &= ~TEXTBOX_REDRAW;
|
---|
1135 | if (!Tk_IsMapped(tbPtr->tkwin)) {
|
---|
1136 | return;
|
---|
1137 | }
|
---|
1138 | if (tbPtr->columnPtr == NULL) {
|
---|
1139 | return;
|
---|
1140 | }
|
---|
1141 | drawable = Tk_GetPixmap(tbPtr->display, Tk_WindowId(tbPtr->tkwin),
|
---|
1142 | Tk_Width(tbPtr->tkwin), Tk_Height(tbPtr->tkwin),
|
---|
1143 | Tk_Depth(tbPtr->tkwin));
|
---|
1144 |
|
---|
1145 | Blt_Fill3DRectangle(tbPtr->tkwin, drawable, tbPtr->border, 0, 0,
|
---|
1146 | Tk_Width(tbPtr->tkwin), Tk_Height(tbPtr->tkwin),
|
---|
1147 | tbPtr->borderWidth, tbPtr->relief);
|
---|
1148 |
|
---|
1149 | x = tbPtr->borderWidth + tbPtr->gap;
|
---|
1150 | y = tbPtr->borderWidth;
|
---|
1151 |
|
---|
1152 | #ifdef notdef
|
---|
1153 | buttonX = Tk_Width(tbPtr->tkwin) -
|
---|
1154 | (tbPtr->borderWidth + tbPtr->gap + 1);
|
---|
1155 | buttonY = tbPtr->borderWidth + 1;
|
---|
1156 | #endif
|
---|
1157 |
|
---|
1158 | if (tbPtr->icon != NULL) {
|
---|
1159 | y += (tbPtr->height - TreeViewIconHeight(tbPtr->icon)) / 2;
|
---|
1160 | Tk_RedrawImage(TreeViewIconBits(tbPtr->icon), 0, 0,
|
---|
1161 | TreeViewIconWidth(tbPtr->icon),
|
---|
1162 | TreeViewIconHeight(tbPtr->icon),
|
---|
1163 | drawable, x, y);
|
---|
1164 | x += TreeViewIconWidth(tbPtr->icon) + tbPtr->gap;
|
---|
1165 | }
|
---|
1166 |
|
---|
1167 | Tk_GetFontMetrics(tbPtr->font, &fontMetrics);
|
---|
1168 | fragPtr = tbPtr->textPtr->fragArr;
|
---|
1169 | count = 0;
|
---|
1170 | y = tbPtr->borderWidth;
|
---|
1171 | if (tbPtr->height > fontMetrics.linespace) {
|
---|
1172 | y += (tbPtr->height - fontMetrics.linespace) / 2;
|
---|
1173 | }
|
---|
1174 | for (i = 0; i < tbPtr->textPtr->nFrags; i++, fragPtr++) {
|
---|
1175 | leftPos = count;
|
---|
1176 | count += fragPtr->count;
|
---|
1177 | rightPos = count;
|
---|
1178 | if ((rightPos < tbPtr->selFirst) || (leftPos > tbPtr->selLast)) {
|
---|
1179 | /* No part of the text fragment is selected. */
|
---|
1180 | Tk_DrawChars(tbPtr->display, drawable, tbPtr->gc,
|
---|
1181 | tbPtr->font, fragPtr->text, fragPtr->count,
|
---|
1182 | x + fragPtr->x, y + fragPtr->y);
|
---|
1183 | continue;
|
---|
1184 | }
|
---|
1185 |
|
---|
1186 | /*
|
---|
1187 | * A text fragment can have up to 3 regions:
|
---|
1188 | *
|
---|
1189 | * 1. Text before the start the selection
|
---|
1190 | * 2. Selected text itself (drawn in a raised border)
|
---|
1191 | * 3. Text following the selection.
|
---|
1192 | */
|
---|
1193 |
|
---|
1194 | selStart = leftPos;
|
---|
1195 | selEnd = rightPos;
|
---|
1196 | /* First adjust selected region for current line. */
|
---|
1197 | if (tbPtr->selFirst > leftPos) {
|
---|
1198 | selStart = tbPtr->selFirst;
|
---|
1199 | }
|
---|
1200 | if (tbPtr->selLast < rightPos) {
|
---|
1201 | selEnd = tbPtr->selLast;
|
---|
1202 | }
|
---|
1203 | selLength = (selEnd - selStart);
|
---|
1204 | x1 = x;
|
---|
1205 |
|
---|
1206 | if (selStart > leftPos) { /* Normal text preceding the selection */
|
---|
1207 | nChars = (selStart - leftPos);
|
---|
1208 | Tk_MeasureChars(tbPtr->font, tbPtr->string + leftPos,
|
---|
1209 | nChars, 10000, DEF_TEXT_FLAGS, &x1);
|
---|
1210 | x1 += x;
|
---|
1211 | }
|
---|
1212 | if (selLength > 0) { /* The selection itself */
|
---|
1213 | int width;
|
---|
1214 |
|
---|
1215 | Tk_MeasureChars(tbPtr->font, fragPtr->text + selStart, selLength,
|
---|
1216 | 10000, DEF_TEXT_FLAGS, &x2);
|
---|
1217 | x2 += x;
|
---|
1218 | width = (x2 - x1) + 1;
|
---|
1219 | Blt_Fill3DRectangle(tbPtr->tkwin, drawable, tbPtr->selBorder,
|
---|
1220 | x1, y + fragPtr->y - fontMetrics.ascent,
|
---|
1221 | width, fontMetrics.linespace,
|
---|
1222 | tbPtr->selBorderWidth, tbPtr->selRelief);
|
---|
1223 | }
|
---|
1224 | Tk_DrawChars(Tk_Display(tbPtr->tkwin), drawable, tbPtr->gc,
|
---|
1225 | tbPtr->font, fragPtr->text, fragPtr->count,
|
---|
1226 | fragPtr->x + x, fragPtr->y + y);
|
---|
1227 | }
|
---|
1228 | if ((tbPtr->flags & TEXTBOX_FOCUS) && (tbPtr->cursorOn)) {
|
---|
1229 | int left, top, right, bottom;
|
---|
1230 |
|
---|
1231 | IndexToPointer(tbPtr);
|
---|
1232 | left = tbPtr->cursorX + 1;
|
---|
1233 | right = left + 1;
|
---|
1234 | top = tbPtr->cursorY;
|
---|
1235 | if (tbPtr->height > fontMetrics.linespace) {
|
---|
1236 | top += (tbPtr->height - fontMetrics.linespace) / 2;
|
---|
1237 | }
|
---|
1238 | bottom = top + tbPtr->cursorHeight - 1;
|
---|
1239 | XDrawLine(tbPtr->display, drawable, tbPtr->gc, left, top, left,
|
---|
1240 | bottom);
|
---|
1241 | XDrawLine(tbPtr->display, drawable, tbPtr->gc, left - 1, top, right,
|
---|
1242 | top);
|
---|
1243 | XDrawLine(tbPtr->display, drawable, tbPtr->gc, left - 1, bottom,
|
---|
1244 | right, bottom);
|
---|
1245 | }
|
---|
1246 | #ifdef notdef
|
---|
1247 | buttonWidth = STD_ARROW_WIDTH + 6 + 2 * tbPtr->buttonBorderWidth;
|
---|
1248 | buttonX -= buttonWidth;
|
---|
1249 | buttonHeight = Tk_Height(tbPtr->tkwin) - 4;
|
---|
1250 | Blt_Fill3DRectangle(tbPtr->tkwin, drawable, tbPtr->buttonBorder,
|
---|
1251 | buttonX, buttonY, buttonWidth, buttonHeight,
|
---|
1252 | tbPtr->buttonBorderWidth, tbPtr->buttonRelief);
|
---|
1253 |
|
---|
1254 | buttonX += buttonWidth / 2;
|
---|
1255 | buttonY = tbPtr->height / 2;
|
---|
1256 | Blt_DrawArrow(tbPtr->display, drawable, tbPtr->gc, buttonX,
|
---|
1257 | buttonY, STD_ARROW_HEIGHT, ARROW_DOWN);
|
---|
1258 | #endif
|
---|
1259 | Blt_Draw3DRectangle(tbPtr->tkwin, drawable, tbPtr->border, 0, 0,
|
---|
1260 | Tk_Width(tbPtr->tkwin), Tk_Height(tbPtr->tkwin),
|
---|
1261 | tbPtr->borderWidth, tbPtr->relief);
|
---|
1262 | XCopyArea(tbPtr->display, drawable, Tk_WindowId(tbPtr->tkwin),
|
---|
1263 | tbPtr->gc, 0, 0, Tk_Width(tbPtr->tkwin),
|
---|
1264 | Tk_Height(tbPtr->tkwin), 0, 0);
|
---|
1265 | Tk_FreePixmap(tbPtr->display, drawable);
|
---|
1266 | }
|
---|
1267 |
|
---|
1268 | /*ARGSUSED*/
|
---|
1269 | static int
|
---|
1270 | ApplyOp(tbPtr, interp, objc, objv)
|
---|
1271 | Textbox *tbPtr;
|
---|
1272 | Tcl_Interp *interp;
|
---|
1273 | int objc; /* Not used. */
|
---|
1274 | Tcl_Obj *CONST *objv; /* Not used. */
|
---|
1275 | {
|
---|
1276 | TreeViewEntry *entryPtr;
|
---|
1277 | TreeView *tvPtr = tbPtr->tvPtr;
|
---|
1278 |
|
---|
1279 | entryPtr = tbPtr->entryPtr;
|
---|
1280 | if (tbPtr->columnPtr == &tvPtr->treeColumn) {
|
---|
1281 | if (entryPtr->labelUid != NULL) {
|
---|
1282 | Blt_TreeViewFreeUid(tvPtr, entryPtr->labelUid);
|
---|
1283 | }
|
---|
1284 | if (tbPtr->string == NULL) {
|
---|
1285 | entryPtr->labelUid = Blt_TreeViewGetUid(tvPtr, "");
|
---|
1286 | } else {
|
---|
1287 | entryPtr->labelUid = Blt_TreeViewGetUid(tvPtr, tbPtr->string);
|
---|
1288 | }
|
---|
1289 | } else {
|
---|
1290 | TreeViewColumn *columnPtr;
|
---|
1291 | Tcl_Obj *objPtr;
|
---|
1292 |
|
---|
1293 | columnPtr = tbPtr->columnPtr;
|
---|
1294 | objPtr = Tcl_NewStringObj(tbPtr->string, -1);
|
---|
1295 | if (Blt_TreeSetValueByKey(interp, tvPtr->tree, entryPtr->node,
|
---|
1296 | columnPtr->key, objPtr) != TCL_OK) {
|
---|
1297 | Tcl_DecrRefCount(objPtr);
|
---|
1298 | return TCL_ERROR;
|
---|
1299 | }
|
---|
1300 | entryPtr->flags |= ENTRY_DIRTY;
|
---|
1301 | }
|
---|
1302 | if (tvPtr != NULL) {
|
---|
1303 | Blt_TreeViewConfigureEntry(tvPtr, entryPtr, 0, NULL,
|
---|
1304 | BLT_CONFIG_OBJV_ONLY);
|
---|
1305 | tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
|
---|
1306 | Blt_TreeViewEventuallyRedraw(tvPtr);
|
---|
1307 | }
|
---|
1308 | Tk_DestroyWindow(tbPtr->tkwin);
|
---|
1309 | return TCL_OK;
|
---|
1310 | }
|
---|
1311 |
|
---|
1312 | /*ARGSUSED*/
|
---|
1313 | static int
|
---|
1314 | CancelOp(tbPtr, interp, objc, objv)
|
---|
1315 | Textbox *tbPtr;
|
---|
1316 | Tcl_Interp *interp; /* Not used. */
|
---|
1317 | int objc; /* Not used. */
|
---|
1318 | Tcl_Obj *CONST *objv; /* Not used. */
|
---|
1319 | {
|
---|
1320 | Tk_DestroyWindow(tbPtr->tkwin);
|
---|
1321 | return TCL_OK;
|
---|
1322 | }
|
---|
1323 |
|
---|
1324 | /*
|
---|
1325 | *----------------------------------------------------------------------
|
---|
1326 | *
|
---|
1327 | * CgetOp --
|
---|
1328 | *
|
---|
1329 | *----------------------------------------------------------------------
|
---|
1330 | */
|
---|
1331 | /*ARGSUSED*/
|
---|
1332 | static int
|
---|
1333 | CgetOp(tbPtr, interp, objc, objv)
|
---|
1334 | Textbox *tbPtr;
|
---|
1335 | Tcl_Interp *interp;
|
---|
1336 | int objc; /* Not used. */
|
---|
1337 | Tcl_Obj *CONST *objv;
|
---|
1338 | {
|
---|
1339 | return Blt_ConfigureValueFromObj(interp, tbPtr->tkwin,
|
---|
1340 | textboxConfigSpecs, (char *)tbPtr, objv[2], 0);
|
---|
1341 | }
|
---|
1342 |
|
---|
1343 | /*
|
---|
1344 | *----------------------------------------------------------------------
|
---|
1345 | *
|
---|
1346 | * ConfigureOp --
|
---|
1347 | *
|
---|
1348 | * This procedure is called to process a list of configuration
|
---|
1349 | * options database, in order to reconfigure the one of more
|
---|
1350 | * entries in the widget.
|
---|
1351 | *
|
---|
1352 | * .c configure option value
|
---|
1353 | *
|
---|
1354 | * Results:
|
---|
1355 | * A standard Tcl result. If TCL_ERROR is returned, then
|
---|
1356 | * interp->result contains an error message.
|
---|
1357 | *
|
---|
1358 | * Side effects:
|
---|
1359 | * Configuration information, such as text string, colors, font,
|
---|
1360 | * etc. get set for tvPtr; old resources get freed, if there
|
---|
1361 | * were any. The hypertext is redisplayed.
|
---|
1362 | *
|
---|
1363 | *----------------------------------------------------------------------
|
---|
1364 | */
|
---|
1365 | static int
|
---|
1366 | ConfigureOp(tbPtr, interp, objc, objv)
|
---|
1367 | Textbox *tbPtr;
|
---|
1368 | Tcl_Interp *interp;
|
---|
1369 | int objc;
|
---|
1370 | Tcl_Obj *CONST *objv;
|
---|
1371 | {
|
---|
1372 | if (objc == 2) {
|
---|
1373 | return Blt_ConfigureInfoFromObj(interp, tbPtr->tkwin,
|
---|
1374 | textboxConfigSpecs, (char *)tbPtr, (Tcl_Obj *)NULL, 0);
|
---|
1375 | } else if (objc == 3) {
|
---|
1376 | return Blt_ConfigureInfoFromObj(interp, tbPtr->tkwin,
|
---|
1377 | textboxConfigSpecs, (char *)tbPtr, objv[3], 0);
|
---|
1378 | }
|
---|
1379 | if (Blt_ConfigureWidgetFromObj(interp, tbPtr->tkwin,
|
---|
1380 | textboxConfigSpecs, objc - 2, objv + 2, (char *)tbPtr,
|
---|
1381 | BLT_CONFIG_OBJV_ONLY) != TCL_OK) {
|
---|
1382 | return TCL_ERROR;
|
---|
1383 | }
|
---|
1384 | ConfigureTextbox(tbPtr);
|
---|
1385 | EventuallyRedraw(tbPtr);
|
---|
1386 | return TCL_OK;
|
---|
1387 | }
|
---|
1388 |
|
---|
1389 | /*
|
---|
1390 | *----------------------------------------------------------------------
|
---|
1391 | *
|
---|
1392 | * DeleteOp --
|
---|
1393 | *
|
---|
1394 | * Remove one or more characters from the label of an entry.
|
---|
1395 | *
|
---|
1396 | * Results:
|
---|
1397 | * None.
|
---|
1398 | *
|
---|
1399 | * Side effects:
|
---|
1400 | * Memory gets freed, the entry gets modified and (eventually)
|
---|
1401 | * redisplayed.
|
---|
1402 | *
|
---|
1403 | *----------------------------------------------------------------------
|
---|
1404 | */
|
---|
1405 | /*ARGSUSED*/
|
---|
1406 | static int
|
---|
1407 | DeleteOp(tbPtr, interp, objc, objv)
|
---|
1408 | Textbox *tbPtr;
|
---|
1409 | Tcl_Interp *interp; /* Not used. */
|
---|
1410 | int objc;
|
---|
1411 | Tcl_Obj *CONST *objv;
|
---|
1412 | {
|
---|
1413 | int firstPos, lastPos;
|
---|
1414 |
|
---|
1415 | if (tbPtr->entryPtr == NULL) {
|
---|
1416 | return TCL_OK;
|
---|
1417 | }
|
---|
1418 | if (GetIndexFromObj(interp, tbPtr, objv[2], &firstPos) != TCL_OK) {
|
---|
1419 | return TCL_ERROR;
|
---|
1420 | }
|
---|
1421 | lastPos = firstPos;
|
---|
1422 | if ((objc == 4) &&
|
---|
1423 | (GetIndexFromObj(interp, tbPtr, objv[3], &lastPos) != TCL_OK)) {
|
---|
1424 | return TCL_ERROR;
|
---|
1425 | }
|
---|
1426 | if (firstPos > lastPos) {
|
---|
1427 | return TCL_OK;
|
---|
1428 | }
|
---|
1429 | return DeleteText(tbPtr, firstPos, lastPos);
|
---|
1430 | }
|
---|
1431 |
|
---|
1432 |
|
---|
1433 | /*
|
---|
1434 | *----------------------------------------------------------------------
|
---|
1435 | *
|
---|
1436 | * IcursorOp --
|
---|
1437 | *
|
---|
1438 | * Returns the numeric index of the given string. Indices can be
|
---|
1439 | * one of the following:
|
---|
1440 | *
|
---|
1441 | * "anchor" Selection anchor.
|
---|
1442 | * "end" End of the label.
|
---|
1443 | * "insert" Insertion cursor.
|
---|
1444 | * "sel.first" First character selected.
|
---|
1445 | * "sel.last" Last character selected.
|
---|
1446 | * @x,y Index at X-Y screen coordinate.
|
---|
1447 | * number Returns the same number.
|
---|
1448 | *
|
---|
1449 | * Results:
|
---|
1450 | * A standard Tcl result. If the argument does not represent a
|
---|
1451 | * valid label index, then TCL_ERROR is returned and the interpreter
|
---|
1452 | * result will contain an error message.
|
---|
1453 | *
|
---|
1454 | *----------------------------------------------------------------------
|
---|
1455 | */
|
---|
1456 | /*ARGSUSED*/
|
---|
1457 | static int
|
---|
1458 | IcursorOp(tbPtr, interp, objc, objv)
|
---|
1459 | Textbox *tbPtr;
|
---|
1460 | Tcl_Interp *interp;
|
---|
1461 | int objc; /* Not used. */
|
---|
1462 | Tcl_Obj *CONST *objv;
|
---|
1463 | {
|
---|
1464 | int textPos;
|
---|
1465 |
|
---|
1466 | if (GetIndexFromObj(interp, tbPtr, objv[2], &textPos) != TCL_OK) {
|
---|
1467 | return TCL_ERROR;
|
---|
1468 | }
|
---|
1469 | if (tbPtr->columnPtr != NULL) {
|
---|
1470 | tbPtr->insertPos = textPos;
|
---|
1471 | IndexToPointer(tbPtr);
|
---|
1472 | EventuallyRedraw(tbPtr);
|
---|
1473 | }
|
---|
1474 | return TCL_OK;
|
---|
1475 | }
|
---|
1476 |
|
---|
1477 |
|
---|
1478 | /*
|
---|
1479 | *----------------------------------------------------------------------
|
---|
1480 | *
|
---|
1481 | * IndexOp --
|
---|
1482 | *
|
---|
1483 | * Returns the numeric index of the given string. Indices can be
|
---|
1484 | * one of the following:
|
---|
1485 | *
|
---|
1486 | * "anchor" Selection anchor.
|
---|
1487 | * "end" End of the label.
|
---|
1488 | * "insert" Insertion cursor.
|
---|
1489 | * "sel.first" First character selected.
|
---|
1490 | * "sel.last" Last character selected.
|
---|
1491 | * @x,y Index at X-Y screen coordinate.
|
---|
1492 | * number Returns the same number.
|
---|
1493 | *
|
---|
1494 | * Results:
|
---|
1495 | * A standard Tcl result. If the argument does not represent a
|
---|
1496 | * valid label index, then TCL_ERROR is returned and the interpreter
|
---|
1497 | * result will contain an error message.
|
---|
1498 | *
|
---|
1499 | *----------------------------------------------------------------------
|
---|
1500 | */
|
---|
1501 | /*ARGSUSED*/
|
---|
1502 | static int
|
---|
1503 | IndexOp(tbPtr, interp, objc, objv)
|
---|
1504 | Textbox *tbPtr;
|
---|
1505 | Tcl_Interp *interp;
|
---|
1506 | int objc; /* Not used. */
|
---|
1507 | Tcl_Obj *CONST *objv;
|
---|
1508 | {
|
---|
1509 | int textPos;
|
---|
1510 |
|
---|
1511 | if (GetIndexFromObj(interp, tbPtr, objv[2], &textPos) != TCL_OK) {
|
---|
1512 | return TCL_ERROR;
|
---|
1513 | }
|
---|
1514 | if ((tbPtr->columnPtr != NULL) && (tbPtr->string != NULL)) {
|
---|
1515 | int nChars;
|
---|
1516 |
|
---|
1517 | nChars = Tcl_NumUtfChars(tbPtr->string, textPos);
|
---|
1518 | Tcl_SetObjResult(interp, Tcl_NewIntObj(nChars));
|
---|
1519 | }
|
---|
1520 | return TCL_OK;
|
---|
1521 | }
|
---|
1522 |
|
---|
1523 | /*
|
---|
1524 | *----------------------------------------------------------------------
|
---|
1525 | *
|
---|
1526 | * InsertOp --
|
---|
1527 | *
|
---|
1528 | * Add new characters to the label of an entry.
|
---|
1529 | *
|
---|
1530 | * Results:
|
---|
1531 | * None.
|
---|
1532 | *
|
---|
1533 | * Side effects:
|
---|
1534 | * New information gets added to tbPtr; it will be redisplayed
|
---|
1535 | * soon, but not necessarily immediately.
|
---|
1536 | *
|
---|
1537 | *----------------------------------------------------------------------
|
---|
1538 | */
|
---|
1539 | /*ARGSUSED*/
|
---|
1540 | static int
|
---|
1541 | InsertOp(tbPtr, interp, objc, objv)
|
---|
1542 | Textbox *tbPtr;
|
---|
1543 | Tcl_Interp *interp; /* Not used. */
|
---|
1544 | int objc;
|
---|
1545 | Tcl_Obj *CONST *objv;
|
---|
1546 | {
|
---|
1547 | int extra;
|
---|
1548 | int insertPos;
|
---|
1549 | char *string;
|
---|
1550 |
|
---|
1551 | if (tbPtr->entryPtr == NULL) {
|
---|
1552 | return TCL_ERROR;
|
---|
1553 | }
|
---|
1554 | if (GetIndexFromObj(interp, tbPtr, objv[2], &insertPos) != TCL_OK) {
|
---|
1555 | return TCL_ERROR;
|
---|
1556 | }
|
---|
1557 | string = Tcl_GetStringFromObj(objv[3], &extra);
|
---|
1558 | if (extra == 0) { /* Nothing to insert. Move the cursor anyways. */
|
---|
1559 | tbPtr->insertPos = insertPos;
|
---|
1560 | } else {
|
---|
1561 | InsertText(tbPtr, string, insertPos, extra);
|
---|
1562 | }
|
---|
1563 | return TCL_OK;
|
---|
1564 | }
|
---|
1565 |
|
---|
1566 | /*ARGSUSED*/
|
---|
1567 | static int
|
---|
1568 | SelectionAdjustOp(tbPtr, interp, objc, objv)
|
---|
1569 | Textbox *tbPtr;
|
---|
1570 | Tcl_Interp *interp; /* Not used. */
|
---|
1571 | int objc;
|
---|
1572 | Tcl_Obj *CONST *objv;
|
---|
1573 | {
|
---|
1574 | int textPos;
|
---|
1575 | int half1, half2;
|
---|
1576 |
|
---|
1577 | if (GetIndexFromObj(interp, tbPtr, objv[3], &textPos) != TCL_OK) {
|
---|
1578 | return TCL_ERROR;
|
---|
1579 | }
|
---|
1580 | half1 = (tbPtr->selFirst + tbPtr->selLast) / 2;
|
---|
1581 | half2 = (tbPtr->selFirst + tbPtr->selLast + 1) / 2;
|
---|
1582 | if (textPos < half1) {
|
---|
1583 | tbPtr->selAnchor = tbPtr->selLast;
|
---|
1584 | } else if (textPos > half2) {
|
---|
1585 | tbPtr->selAnchor = tbPtr->selFirst;
|
---|
1586 | }
|
---|
1587 | return SelectText(tbPtr, textPos);
|
---|
1588 | }
|
---|
1589 |
|
---|
1590 | /*ARGSUSED*/
|
---|
1591 | static int
|
---|
1592 | SelectionClearOp(tbPtr, interp, objc, objv)
|
---|
1593 | Textbox *tbPtr;
|
---|
1594 | Tcl_Interp *interp; /* Not used. */
|
---|
1595 | int objc; /* Not used. */
|
---|
1596 | Tcl_Obj *CONST *objv; /* Not used. */
|
---|
1597 | {
|
---|
1598 | if (tbPtr->selFirst != -1) {
|
---|
1599 | tbPtr->selFirst = tbPtr->selLast = -1;
|
---|
1600 | EventuallyRedraw(tbPtr);
|
---|
1601 | }
|
---|
1602 | return TCL_OK;
|
---|
1603 | }
|
---|
1604 |
|
---|
1605 | /*ARGSUSED*/
|
---|
1606 | static int
|
---|
1607 | SelectionFromOp(tbPtr, interp, objc, objv)
|
---|
1608 | Textbox *tbPtr;
|
---|
1609 | Tcl_Interp *interp; /* Not used. */
|
---|
1610 | int objc;
|
---|
1611 | Tcl_Obj *CONST *objv;
|
---|
1612 | {
|
---|
1613 | int textPos;
|
---|
1614 |
|
---|
1615 | if (GetIndexFromObj(interp, tbPtr, objv[3], &textPos) != TCL_OK) {
|
---|
1616 | return TCL_ERROR;
|
---|
1617 | }
|
---|
1618 | tbPtr->selAnchor = textPos;
|
---|
1619 | return TCL_OK;
|
---|
1620 | }
|
---|
1621 |
|
---|
1622 | /*ARGSUSED*/
|
---|
1623 | static int
|
---|
1624 | SelectionPresentOp(tbPtr, interp, objc, objv)
|
---|
1625 | Textbox *tbPtr;
|
---|
1626 | Tcl_Interp *interp;
|
---|
1627 | int objc; /* Not used. */
|
---|
1628 | Tcl_Obj *CONST *objv; /* Not used. */
|
---|
1629 | {
|
---|
1630 | int bool;
|
---|
1631 |
|
---|
1632 | bool = (tbPtr->selFirst != -1);
|
---|
1633 | Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool));
|
---|
1634 | return TCL_OK;
|
---|
1635 | }
|
---|
1636 |
|
---|
1637 | /*ARGSUSED*/
|
---|
1638 | static int
|
---|
1639 | SelectionRangeOp(tbPtr, interp, objc, objv)
|
---|
1640 | Textbox *tbPtr;
|
---|
1641 | Tcl_Interp *interp; /* Not used. */
|
---|
1642 | int objc;
|
---|
1643 | Tcl_Obj *CONST *objv;
|
---|
1644 | {
|
---|
1645 | int selFirst, selLast;
|
---|
1646 |
|
---|
1647 | if (GetIndexFromObj(interp, tbPtr, objv[3], &selFirst) != TCL_OK) {
|
---|
1648 | return TCL_ERROR;
|
---|
1649 | }
|
---|
1650 | if (GetIndexFromObj(interp, tbPtr, objv[4], &selLast) != TCL_OK) {
|
---|
1651 | return TCL_ERROR;
|
---|
1652 | }
|
---|
1653 | tbPtr->selAnchor = selFirst;
|
---|
1654 | return SelectText(tbPtr, selLast);
|
---|
1655 | }
|
---|
1656 |
|
---|
1657 | /*ARGSUSED*/
|
---|
1658 | static int
|
---|
1659 | SelectionToOp(tbPtr, interp, objc, objv)
|
---|
1660 | Textbox *tbPtr;
|
---|
1661 | Tcl_Interp *interp; /* Not used. */
|
---|
1662 | int objc;
|
---|
1663 | Tcl_Obj *CONST *objv;
|
---|
1664 | {
|
---|
1665 | int textPos;
|
---|
1666 |
|
---|
1667 | if (GetIndexFromObj(interp, tbPtr, objv[3], &textPos) != TCL_OK) {
|
---|
1668 | return TCL_ERROR;
|
---|
1669 | }
|
---|
1670 | return SelectText(tbPtr, textPos);
|
---|
1671 | }
|
---|
1672 |
|
---|
1673 |
|
---|
1674 | static Blt_OpSpec selectionOps[] =
|
---|
1675 | {
|
---|
1676 | {"adjust", 1, (Blt_Op)SelectionAdjustOp, 4, 4, "index",},
|
---|
1677 | {"clear", 1, (Blt_Op)SelectionClearOp, 3, 3, "",},
|
---|
1678 | {"from", 1, (Blt_Op)SelectionFromOp, 4, 4, "index"},
|
---|
1679 | {"present", 1, (Blt_Op)SelectionPresentOp, 3, 3, ""},
|
---|
1680 | {"range", 1, (Blt_Op)SelectionRangeOp, 5, 5, "start end",},
|
---|
1681 | {"to", 1, (Blt_Op)SelectionToOp, 4, 4, "index"},
|
---|
1682 | };
|
---|
1683 |
|
---|
1684 | static int nSelectionOps = sizeof(selectionOps) / sizeof(Blt_OpSpec);
|
---|
1685 |
|
---|
1686 | /*
|
---|
1687 | * This procedure handles the individual options for text
|
---|
1688 | * selections. The selected text is designated by start and end
|
---|
1689 | * indices into the text pool. The selected segment has both a
|
---|
1690 | * anchored and unanchored ends. The following selection
|
---|
1691 | * operations are implemented:
|
---|
1692 | *
|
---|
1693 | * "adjust" - resets either the first or last index
|
---|
1694 | * of the selection.
|
---|
1695 | * "clear" - clears the selection. Sets first/last
|
---|
1696 | * indices to -1.
|
---|
1697 | * "from" - sets the index of the selection anchor.
|
---|
1698 | * "present" - return "1" if a selection is available,
|
---|
1699 | * "0" otherwise.
|
---|
1700 | * "range" - sets the first and last indices.
|
---|
1701 | * "to" - sets the index of the un-anchored end.
|
---|
1702 | */
|
---|
1703 | static int
|
---|
1704 | SelectionOp(tbPtr, interp, objc, objv)
|
---|
1705 | Textbox *tbPtr;
|
---|
1706 | Tcl_Interp *interp;
|
---|
1707 | int objc;
|
---|
1708 | Tcl_Obj *CONST *objv;
|
---|
1709 | {
|
---|
1710 | Blt_Op proc;
|
---|
1711 | int result;
|
---|
1712 |
|
---|
1713 | proc = Blt_GetOpFromObj(interp, nSelectionOps, selectionOps, BLT_OP_ARG2,
|
---|
1714 | objc, objv, 0);
|
---|
1715 | if (proc == NULL) {
|
---|
1716 | return TCL_ERROR;
|
---|
1717 | }
|
---|
1718 | result = (*proc) (tbPtr, interp, objc, objv);
|
---|
1719 | return result;
|
---|
1720 | }
|
---|
1721 |
|
---|
1722 | /*
|
---|
1723 | *----------------------------------------------------------------------
|
---|
1724 | *
|
---|
1725 | * TextboxCmd --
|
---|
1726 | *
|
---|
1727 | * This procedure handles entry operations.
|
---|
1728 | *
|
---|
1729 | * Results:
|
---|
1730 | * A standard Tcl result.
|
---|
1731 | *
|
---|
1732 | *----------------------------------------------------------------------
|
---|
1733 | */
|
---|
1734 | static Blt_OpSpec comboOps[] =
|
---|
1735 | {
|
---|
1736 | {"apply", 1, (Blt_Op)ApplyOp, 2, 2, "",},
|
---|
1737 | {"cancel", 2, (Blt_Op)CancelOp, 2, 2, "",},
|
---|
1738 | {"cget", 2, (Blt_Op)CgetOp, 3, 3, "value",},
|
---|
1739 | {"configure", 2, (Blt_Op)ConfigureOp, 2, 0, "?option value...?",},
|
---|
1740 | {"delete", 1, (Blt_Op)DeleteOp, 3, 4, "first ?last?"},
|
---|
1741 | {"icursor", 2, (Blt_Op)IcursorOp, 3, 3, "index"},
|
---|
1742 | {"index", 3, (Blt_Op)IndexOp, 3, 3, "index"},
|
---|
1743 | {"insert", 3, (Blt_Op)InsertOp, 4, 4, "index string"},
|
---|
1744 | {"selection", 1, (Blt_Op)SelectionOp, 2, 0, "args"},
|
---|
1745 | };
|
---|
1746 | static int nComboOps = sizeof(comboOps) / sizeof(Blt_OpSpec);
|
---|
1747 |
|
---|
1748 | static int
|
---|
1749 | TextboxCmd(clientData, interp, objc, objv)
|
---|
1750 | ClientData clientData;
|
---|
1751 | Tcl_Interp *interp;
|
---|
1752 | int objc;
|
---|
1753 | Tcl_Obj *CONST *objv;
|
---|
1754 | {
|
---|
1755 | Textbox *tbPtr = clientData;
|
---|
1756 | Blt_Op proc;
|
---|
1757 | int result;
|
---|
1758 |
|
---|
1759 | proc = Blt_GetOpFromObj(interp, nComboOps, comboOps, BLT_OP_ARG1, objc,
|
---|
1760 | objv, 0);
|
---|
1761 | if (proc == NULL) {
|
---|
1762 | return TCL_ERROR;
|
---|
1763 | }
|
---|
1764 | result = (*proc) (tbPtr, interp, objc, objv);
|
---|
1765 | return result;
|
---|
1766 | }
|
---|
1767 |
|
---|
1768 | #endif
|
---|
1769 |
|
---|