1 /*
2  * bltTed.c --
3  *
4  *	This module implements an editor for the  table geometry
5  *	manager in the BLT toolkit.
6  *
7  * Copyright 1995 by AT&T Bell Laboratories.
8  * Permission to use, copy, modify, and distribute this software
9  * and its documentation for any purpose and without fee is hereby
10  * granted, provided that the above copyright notice appear in all
11  * copies and that both that the copyright notice and warranty
12  * disclaimer appear in supporting documentation, and that the
13  * names of AT&T Bell Laboratories any of their entities not be used
14  * in advertising or publicity pertaining to distribution of the
15  * software without specific, written prior permission.
16  *
17  * AT&T disclaims all warranties with regard to this software, including
18  * all implied warranties of merchantability and fitness.  In no event
19  * shall AT&T be liable for any special, indirect or consequential
20  * damages or any damages whatsoever resulting from loss of use, data
21  * or profits, whether in an action of contract, negligence or other
22  * tortuous action, arising out of or in connection with the use or
23  * performance of this software.
24  *
25  * Table editor was created by George Howlett.
26  */
27 
28 #include "bltInt.h"
29 
30 #include "bltTable.h"
31 
32 extern Tk_CustomOption bltDistanceOption;
33 extern Tk_CustomOption bltDashesOption;
34 
35 typedef struct TedStruct Ted;
36 
37 #define TABLE_THREAD_KEY	"BLT Table Data"
38 
39 typedef struct {
40     Blt_HashTable tableTable;	/* Hash table of table structures keyed by
41 				 * the address of the reference Tk window */
42 } TableData;
43 
44 
45 typedef struct {
46     int flags;
47     Tcl_Interp *interp;
48     Tk_Window tkwin;		/* Entry window */
49     Entry *entryPtr;		/* Entry it represents */
50     Table *tablePtr;		/* Table where it can be found */
51     Ted *tedPtr;		/* Table editor */
52     int mapped;			/* Indicates if the debugging windows are
53 				 * mapped */
54 } EntryRep;
55 
56 
57 typedef struct {
58     Tk_Font font;
59     XColor *widgetColor;
60     XColor *cntlColor;
61     XColor *normalFg, *normalBg;
62     XColor *activeFg, *activeBg;
63 
64     Tk_Cursor cursor;		/* Cursor to display inside of this window */
65     Pixmap stipple;
66 
67     GC drawGC;			/* GC to draw grid, outlines */
68     GC fillGC;			/* GC to fill entry area */
69     GC widgetFillGC;		/* GC to fill widget area */
70     GC cntlGC;			/* GC to fill rectangles */
71 
72 } EntryAttributes;
73 
74 typedef struct {
75     int count;
76     XRectangle *array;
77 } Rectangles;
78 
79 struct TedStruct {
80     int gridLineWidth;		/* Width of grid lines */
81     int buttonHeight;		/* Height of row/column buttons */
82     int cavityPad;		/* Extra padding to add to entry cavity */
83     int minSize;		/* Minimum size for partitions */
84 
85     EditorDrawProc *drawProc;
86     EditorDestroyProc *destroyProc;
87 
88     Display *display;
89     Tk_Font font;
90     Table *tablePtr;		/* Pointer to table being debugged */
91     Tcl_Interp *interp;
92     int flags;
93     Tk_Window tkwin;		/* Grid window */
94     Tk_Window input;		/* InputOnly window to receive events */
95     int inputIsSibling;
96 
97     /* Form the grid */
98     XSegment *segArr;
99     int nSegs;
100     XRectangle *padRectArr;
101     int nPadRects;
102     XRectangle *widgetPadRectArr;
103     int nWidgetPadRects;
104 
105     XRectangle *cntlRectArr;
106     int nCntlRects;
107 
108     XRectangle *rectArr;
109     int nRects;
110 
111     XRectangle activeRectArr[5];
112     int spanActive;
113 
114     GC rectGC;			/* GC to fill rectangles */
115     GC drawGC;			/* GC to draw grid, outlines */
116     GC fillGC;			/* GC to fill window */
117     GC spanGC;			/* GC to fill spans */
118     GC padRectGC;		/* GC to draw padding  */
119 
120     Tk_3DBorder border;		/* Border to use with buttons */
121     int relief;
122     int borderWidth;		/* Border width of buttons */
123     XColor *normalBg;
124     XColor *padColor;
125     XColor *gridColor;
126     XColor *buttonColor;
127     XColor *spanColor;
128 
129     Pixmap padStipple;
130     Pixmap spanStipple;
131     Blt_Dashes dashes;
132     char *fileName;		/* If non-NULL, indicates name of file
133 				 * to write final table output to */
134     int mapped;			/* Indicates if the debugging windows are
135 				 * mapped */
136     int gripSize;
137     int doubleBuffer;
138     Tk_Cursor cursor;
139     Blt_Chain *chainPtr;
140     int nextWindowId;
141 
142     EntryAttributes attributes;	/* Entry attributes */
143 };
144 
145 #define REDRAW_PENDING	(1<<0)	/* A DoWhenIdle handler has already
146 				 * been queued to redraw the window */
147 #define LAYOUT_PENDING	(1<<1)
148 
149 /*
150  *
151  *
152  *	|Cavity|1|2|
153  *
154  *
155  */
156 #define DEF_ENTRY_ACTIVE_BG_MONO	RGB_BLACK
157 #define DEF_ENTRY_ACTIVE_FG_MONO	RGB_WHITE
158 #define DEF_ENTRY_ACTIVE_BACKGROUND	RGB_BLACK
159 #define DEF_ENTRY_ACTIVE_FOREGROUND	RGB_WHITE
160 #define DEF_ENTRY_CURSOR		(char *)NULL
161 #define DEF_ENTRY_FONT	 	"*-Courier-Bold-R-Normal-*-100-*"
162 #define DEF_ENTRY_NORMAL_BACKGROUND	RGB_BLUE
163 #define DEF_ENTRY_NORMAL_BG_MONO	RGB_BLACK
164 #define DEF_ENTRY_NORMAL_FOREGROUND	RGB_WHITE
165 #define DEF_ENTRY_NORMAL_FG_MONO	RGB_WHITE
166 #define DEF_ENTRY_WIDGET_BACKGROUND	RGB_GREEN
167 #define DEF_ENTRY_CONTROL_BACKGROUND	RGB_YELLOW
168 #define DEF_ENTRY_WIDGET_BG_MONO	RGB_BLACK
169 #define DEF_ENTRY_STIPPLE		"gray50"
170 #define DEF_GRID_BACKGROUND		RGB_WHITE
171 #define DEF_GRID_BG_MONO		RGB_WHITE
172 #define DEF_GRID_CURSOR			"crosshair"
173 #define DEF_GRID_DASHES			(char *)NULL
174 #define DEF_GRID_FOREGROUND		RGB_BLACK
175 #define DEF_GRID_FG_MONO		RGB_BLACK
176 #define DEF_GRID_FONT			"*-Courier-Bold-R-Normal-*-100-*"
177 #define DEF_GRID_LINE_WIDTH		"1"
178 #define DEF_GRID_PAD_COLOR		RGB_RED
179 #define DEF_GRID_PAD_MONO		RGB_BLACK
180 #define DEF_GRID_PAD_STIPPLE		"gray25"
181 #define DEF_GRID_PAD_CAVITY		"0"
182 #define DEF_GRID_PAD_MIN		"8"
183 #define DEF_ROWCOL_BACKGROUND		RGB_RED
184 #define DEF_ROWCOL_BG_MONO		RGB_BLACK
185 #define DEF_ROWCOL_BORDER_COLOR		RGB_RED
186 #define DEF_ROWCOL_BORDER_MONO		RGB_BLACK
187 #define DEF_ROWCOL_BORDERWIDTH		"2"
188 #define DEF_ROWCOL_HEIGHT		"8"
189 #define DEF_ROWCOL_RELIEF		"raised"
190 #define DEF_SPAN_STIPPLE		"gray50"
191 #define DEF_SPAN_COLOR			RGB_BLACK
192 #define DEF_SPAN_MONO			RGB_BLACK
193 #define DEF_SPAN_GRIP_SIZE		"5"
194 #define DEF_GRID_DOUBLE_BUFFER		"1"
195 
196 static Tk_ConfigSpec configSpecs[] =
197 {
198     {TK_CONFIG_BORDER, "-bg", "tedBorder", (char *)NULL,
199 	DEF_ROWCOL_BORDER_COLOR, Tk_Offset(Ted, border), TK_CONFIG_COLOR_ONLY},
200     {TK_CONFIG_BORDER, "-bg", "tedBorder", (char *)NULL,
201 	DEF_ROWCOL_BORDER_MONO, Tk_Offset(Ted, border), TK_CONFIG_MONO_ONLY},
202     {TK_CONFIG_COLOR, "-background", "tedBackground", (char *)NULL,
203 	DEF_GRID_BACKGROUND, Tk_Offset(Ted, normalBg), TK_CONFIG_COLOR_ONLY},
204     {TK_CONFIG_COLOR, "-background", "tedBackground", (char *)NULL,
205 	DEF_GRID_BG_MONO, Tk_Offset(Ted, normalBg), TK_CONFIG_MONO_ONLY},
206     {TK_CONFIG_CURSOR, "-cursor", "cursor", (char *)NULL,
207 	DEF_GRID_CURSOR, Tk_Offset(Ted, cursor), TK_CONFIG_NULL_OK},
208     {TK_CONFIG_COLOR, "-gridcolor", "gridColor", (char *)NULL,
209 	DEF_GRID_FOREGROUND, Tk_Offset(Ted, gridColor), TK_CONFIG_COLOR_ONLY},
210     {TK_CONFIG_COLOR, "-gridcolor", "gridColor", (char *)NULL,
211 	DEF_GRID_FG_MONO, Tk_Offset(Ted, gridColor), TK_CONFIG_MONO_ONLY},
212     {TK_CONFIG_COLOR, "-buttoncolor", "buttonColor", (char *)NULL,
213 	DEF_ROWCOL_BACKGROUND, Tk_Offset(Ted, buttonColor), TK_CONFIG_COLOR_ONLY},
214     {TK_CONFIG_COLOR, "-buttoncolor", "buttonColor", (char *)NULL,
215 	DEF_ROWCOL_BG_MONO, Tk_Offset(Ted, buttonColor), TK_CONFIG_MONO_ONLY},
216     {TK_CONFIG_COLOR, "-padcolor", "padColor", (char *)NULL,
217 	DEF_GRID_PAD_COLOR, Tk_Offset(Ted, padColor), TK_CONFIG_COLOR_ONLY},
218     {TK_CONFIG_COLOR, "-padcolor", "padColor", (char *)NULL,
219 	DEF_GRID_PAD_MONO, Tk_Offset(Ted, padColor), TK_CONFIG_MONO_ONLY},
220     {TK_CONFIG_BITMAP, "-padstipple", "padStipple", (char *)NULL,
221 	DEF_GRID_PAD_STIPPLE, Tk_Offset(Ted, padStipple), TK_CONFIG_NULL_OK},
222     {TK_CONFIG_FONT, "-font", "font", (char *)NULL,
223 	DEF_GRID_FONT, Tk_Offset(Ted, font), 0},
224     {TK_CONFIG_CUSTOM, "-gridlinewidth", "gridLineWidth", (char *)NULL,
225 	DEF_GRID_LINE_WIDTH, Tk_Offset(Ted, gridLineWidth),
226 	TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
227     {TK_CONFIG_CUSTOM, "-buttonheight", "buttonHeight", (char *)NULL,
228 	DEF_ROWCOL_HEIGHT, Tk_Offset(Ted, buttonHeight),
229 	TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
230     {TK_CONFIG_CUSTOM, "-cavitypad", "cavityPad", (char *)NULL,
231 	DEF_GRID_PAD_CAVITY, Tk_Offset(Ted, cavityPad),
232 	TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
233     {TK_CONFIG_CUSTOM, "-minsize", "minSize", (char *)NULL,
234 	DEF_GRID_PAD_MIN, Tk_Offset(Ted, minSize),
235 	TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
236     {TK_CONFIG_CUSTOM, "-dashes", "dashes", (char *)NULL,
237 	DEF_GRID_DASHES, Tk_Offset(Ted, dashes),
238 	TK_CONFIG_NULL_OK, &bltDashesOption},
239     {TK_CONFIG_RELIEF, "-relief", "relief", (char *)NULL,
240 	DEF_ROWCOL_RELIEF, Tk_Offset(Ted, relief), TK_CONFIG_DONT_SET_DEFAULT},
241     {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", (char *)NULL,
242 	DEF_ROWCOL_BORDERWIDTH, Tk_Offset(Ted, borderWidth),
243 	TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
244     {TK_CONFIG_CURSOR, "-entrycursor", "entryCursor", (char *)NULL,
245 	DEF_ENTRY_CURSOR, Tk_Offset(Ted, attributes.cursor),
246 	TK_CONFIG_NULL_OK},
247     {TK_CONFIG_FONT, "-entryfont", "entryFont", (char *)NULL,
248 	DEF_ENTRY_FONT, Tk_Offset(Ted, attributes.font), 0},
249     {TK_CONFIG_BITMAP, "-entrystipple", "entryStipple", (char *)NULL,
250 	DEF_ENTRY_STIPPLE, Tk_Offset(Ted, attributes.stipple),
251 	TK_CONFIG_NULL_OK},
252     {TK_CONFIG_COLOR, "-widgetbackground", "widgetBackground", (char *)NULL,
253 	DEF_ENTRY_WIDGET_BACKGROUND, Tk_Offset(Ted, attributes.widgetColor),
254 	TK_CONFIG_COLOR_ONLY},
255     {TK_CONFIG_COLOR, "-widgetbackground", "widgetBackground", (char *)NULL,
256 	DEF_ENTRY_WIDGET_BG_MONO, Tk_Offset(Ted, attributes.widgetColor),
257 	TK_CONFIG_MONO_ONLY},
258     {TK_CONFIG_COLOR, "-controlbackground", "controlBackground", (char *)NULL,
259 	DEF_ENTRY_CONTROL_BACKGROUND, Tk_Offset(Ted, attributes.cntlColor),
260 	TK_CONFIG_COLOR_ONLY},
261     {TK_CONFIG_COLOR, "-controlbackground", "controlBackground", (char *)NULL,
262 	DEF_ENTRY_WIDGET_BG_MONO, Tk_Offset(Ted, attributes.cntlColor),
263 	TK_CONFIG_MONO_ONLY},
264     {TK_CONFIG_COLOR, "-entrybackground", "entryBackground", (char *)NULL,
265 	DEF_ENTRY_NORMAL_BACKGROUND, Tk_Offset(Ted, attributes.normalBg),
266 	TK_CONFIG_COLOR_ONLY},
267     {TK_CONFIG_COLOR, "-entrybackground", "entryBackground", (char *)NULL,
268 	DEF_ENTRY_NORMAL_BG_MONO, Tk_Offset(Ted, attributes.normalBg),
269 	TK_CONFIG_MONO_ONLY},
270     {TK_CONFIG_COLOR, "-entryactivebackground", "entryActiveBackground", (char *)NULL,
271 	DEF_ENTRY_ACTIVE_BACKGROUND, Tk_Offset(Ted, attributes.activeBg),
272 	TK_CONFIG_COLOR_ONLY},
273     {TK_CONFIG_COLOR, "-entryactivebackground", "entryActiveBackground", (char *)NULL,
274 	DEF_ENTRY_ACTIVE_BG_MONO, Tk_Offset(Ted, attributes.activeBg),
275 	TK_CONFIG_MONO_ONLY},
276     {TK_CONFIG_COLOR, "-entryactiveforeground", "entryActiveForeground", (char *)NULL,
277 	DEF_ENTRY_ACTIVE_FOREGROUND, Tk_Offset(Ted, attributes.activeFg),
278 	TK_CONFIG_COLOR_ONLY},
279     {TK_CONFIG_COLOR, "-entryactiveforeground", "entryActiveForeground", (char *)NULL,
280 	DEF_ENTRY_ACTIVE_FG_MONO, Tk_Offset(Ted, attributes.activeFg),
281 	TK_CONFIG_MONO_ONLY},
282     {TK_CONFIG_COLOR, "-entryforeground", "entryForeground", (char *)NULL,
283 	DEF_ENTRY_NORMAL_FOREGROUND, Tk_Offset(Ted, attributes.normalFg),
284 	TK_CONFIG_COLOR_ONLY},
285     {TK_CONFIG_COLOR, "-entryforeground", "entryForeground", (char *)NULL,
286 	DEF_ENTRY_NORMAL_FG_MONO, Tk_Offset(Ted, attributes.normalFg),
287 	TK_CONFIG_MONO_ONLY},
288     {TK_CONFIG_COLOR, "-spancolor", "spanColor", (char *)NULL,
289 	DEF_SPAN_COLOR, Tk_Offset(Ted, spanColor), TK_CONFIG_COLOR_ONLY},
290     {TK_CONFIG_COLOR, "-spancolor", "spanColor", (char *)NULL,
291 	DEF_SPAN_MONO, Tk_Offset(Ted, spanColor), TK_CONFIG_MONO_ONLY},
292     {TK_CONFIG_BITMAP, "-spanstipple", "spanStipple", (char *)NULL,
293 	DEF_SPAN_STIPPLE, Tk_Offset(Ted, spanStipple), TK_CONFIG_NULL_OK},
294     {TK_CONFIG_CUSTOM, "-gripsize", "gripSize", (char *)NULL,
295 	DEF_SPAN_GRIP_SIZE, Tk_Offset(Ted, gripSize),
296 	TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
297     {TK_CONFIG_BOOLEAN, "-dbl", "doubleBuffer", (char *)NULL,
298 	DEF_GRID_DOUBLE_BUFFER, Tk_Offset(Ted, doubleBuffer),
299 	TK_CONFIG_DONT_SET_DEFAULT},
300     {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
301 };
302 
303 
304 static void DrawEditor _ANSI_ARGS_((Editor *editor));
305 static void DestroyEditor _ANSI_ARGS_((DestroyData destroyData));
306 static void DisplayTed _ANSI_ARGS_((ClientData clientData));
307 static void DestroyTed _ANSI_ARGS_((DestroyData destroyData));
308 static void DisplayEntry _ANSI_ARGS_((ClientData clientData));
309 static void DestroyEntry _ANSI_ARGS_((DestroyData destoryData));
310 
311 static Tcl_CmdProc TedCmd;
312 static Tk_EventProc EntryEventProc;
313 static Tk_EventProc TedEventProc;
314 
315 /*
316  *----------------------------------------------------------------------
317  *
318  * EventuallyRedraw --
319  *
320  *	Queues a request to redraw the text window at the next idle
321  *	point.
322  *
323  * Results:
324  *	None.
325  *
326  * Side effects:
327  *	Information gets redisplayed.  Right now we don't do selective
328  *	redisplays:  the whole window will be redrawn.  This doesn't
329  *	seem to hurt performance noticeably, but if it does then this
330  *	could be changed.
331  *
332  *----------------------------------------------------------------------
333  */
334 static void
EventuallyRedraw(tedPtr)335 EventuallyRedraw(tedPtr)
336     Ted *tedPtr;		/* Information about editor. */
337 {
338     if ((tedPtr->tkwin != NULL) && !(tedPtr->flags & REDRAW_PENDING)) {
339 	tedPtr->flags |= REDRAW_PENDING;
340 	Tcl_DoWhenIdle(DisplayTed, tedPtr);
341     }
342 }
343 
344 /*
345  *----------------------------------------------------------------------
346  *
347  * EventuallyRedraw --
348  *
349  *	Queues a request to redraw the text window at the next idle
350  *	point.
351  *
352  * Results:
353  *	None.
354  *
355  * Side effects:
356  *	Information gets redisplayed.  Right now we don't do selective
357  *	redisplays:  the whole window will be redrawn.  This doesn't
358  *	seem to hurt performance noticeably, but if it does then this
359  *	could be changed.
360  *
361  *----------------------------------------------------------------------
362  */
363 static void
EventuallyRedrawEntry(repPtr)364 EventuallyRedrawEntry(repPtr)
365     EntryRep *repPtr;		/* Information about editor. */
366 {
367     if ((repPtr->tkwin != NULL) && !(repPtr->flags & REDRAW_PENDING)) {
368 	repPtr->flags |= REDRAW_PENDING;
369 	Tcl_DoWhenIdle(DisplayEntry, repPtr);
370     }
371 }
372 
373 /*
374  * --------------------------------------------------------------
375  *
376  * EntryEventProc --
377  *
378  * 	This procedure is invoked by the Tk dispatcher for various
379  * 	events on the editing grid for the table.
380  *
381  * Results:
382  *	None.
383  *
384  * Side effects:
385  *	When the window gets deleted, internal structures get
386  *	cleaned up.  When it gets exposed, it is redisplayed.
387  *
388  * --------------------------------------------------------------
389  */
390 static void
EntryEventProc(clientData,eventPtr)391 EntryEventProc(clientData, eventPtr)
392     ClientData clientData;	/* Information about window. */
393     XEvent *eventPtr;		/* Information about event. */
394 {
395     EntryRep *repPtr = (EntryRep *) clientData;
396 
397     if (eventPtr->type == ConfigureNotify) {
398 	EventuallyRedrawEntry(repPtr);
399     } else if (eventPtr->type == Expose) {
400 	if (eventPtr->xexpose.count == 0) {
401 	    EventuallyRedrawEntry(repPtr);
402 	}
403     } else if (eventPtr->type == DestroyNotify) {
404 	repPtr->tkwin = NULL;
405 	if (repPtr->flags & REDRAW_PENDING) {
406 	    Tcl_CancelIdleCall(DisplayEntry, repPtr);
407 	}
408 	Tcl_EventuallyFree(repPtr, DestroyEntry);
409     }
410 }
411 
412 /*
413  * --------------------------------------------------------------
414  *
415  * TedEventProc --
416  *
417  * 	This procedure is invoked by the Tk dispatcher for various
418  * 	events on the editing grid for the table.
419  *
420  * Results:
421  *	None.
422  *
423  * Side effects:
424  *	When the window gets deleted, internal structures get
425  *	cleaned up.  When it gets exposed, it is redisplayed.
426  *
427  * --------------------------------------------------------------
428  */
429 static void
TedEventProc(clientData,eventPtr)430 TedEventProc(clientData, eventPtr)
431     ClientData clientData;	/* Information about window. */
432     XEvent *eventPtr;		/* Information about event. */
433 {
434     Ted *tedPtr = (Ted *) clientData;
435 
436     if (eventPtr->type == ConfigureNotify) {
437 	EventuallyRedraw(tedPtr);
438     } else if (eventPtr->type == Expose) {
439 	if (eventPtr->xexpose.count == 0) {
440 	    EventuallyRedraw(tedPtr);
441 	}
442     } else if (eventPtr->type == DestroyNotify) {
443 	tedPtr->tkwin = NULL;
444 	if (tedPtr->flags & REDRAW_PENDING) {
445 	    Tcl_CancelIdleCall(DisplayTed, tedPtr);
446 	}
447 	Tcl_EventuallyFree(tedPtr, DestroyTed);
448     }
449 }
450 
451 /*
452  * ----------------------------------------------------------------------------
453  *
454  * CreateGrid --
455  *
456  * ----------------------------------------------------------------------------
457  */
458 static int
CreateGrid(tedPtr)459 CreateGrid(tedPtr)
460     Ted *tedPtr;
461 {
462     Tcl_Interp *interp;
463     Tk_Window tkwin;
464     Tk_Window master;
465     /*
466      * Create a sibling window to cover the master window. It will
467      * be stacked just above the master window.
468      */
469     interp = tedPtr->tablePtr->interp;
470     master = tedPtr->tablePtr->tkwin;
471     tkwin = Tk_CreateWindow(interp, master, "ted_%output%", (char *)NULL);
472     if (tkwin == NULL) {
473 	return TCL_ERROR;
474     }
475     Tk_SetClass(tkwin, "BltTed");
476     Tk_CreateEventHandler(tkwin, ExposureMask | StructureNotifyMask,
477 	TedEventProc, tedPtr);
478     Tk_MoveResizeWindow(tkwin, 0, 0, Tk_Width(master), Tk_Height(master));
479     Tk_RestackWindow(tkwin, Below, (Tk_Window)NULL);
480     Tk_MapWindow(tkwin);
481     tedPtr->tkwin = tkwin;
482     return TCL_OK;
483 }
484 
485 /*
486  * ----------------------------------------------------------------------------
487  *
488  * CreateEventWindow --
489  *
490  * ----------------------------------------------------------------------------
491  */
492 static int
CreateEventWindow(tedPtr)493 CreateEventWindow(tedPtr)
494     Ted *tedPtr;
495 {
496     Tcl_Interp *interp;
497     Tk_Window tkwin;
498     Tk_Window master;
499     Tk_Window parent;
500 
501     interp = tedPtr->tablePtr->interp;
502     master = tedPtr->tablePtr->tkwin;
503     /*
504      * Create an InputOnly window which sits above the table to
505      * collect and dispatch user events.
506      */
507     if (Tk_IsTopLevel(master)) {
508 	/*
509 	 * If master is a top-level window, it's also the parent of
510 	 * the widgets (it can't have a sibling).
511 	 * In this case, the InputOnly window is a child of the
512 	 * master instead of a sibling.
513 	 */
514 	parent = master;
515 	tkwin = Tk_CreateWindow(interp, parent, "ted_%input%", (char *)NULL);
516 	if (tkwin != NULL) {
517 	    Tk_ResizeWindow(tkwin, Tk_Width(parent), Tk_Height(parent));
518 	}
519 	tedPtr->inputIsSibling = 0;
520     } else {
521 	char *namePtr;		/* Name of InputOnly window. */
522 
523 	parent = Tk_Parent(master);
524 	namePtr = Blt_Malloc(strlen(Tk_Name(master)) + 5);
525 	sprintf(namePtr, "ted_%s", Tk_Name(master));
526 	tkwin = Tk_CreateWindow(interp, parent, namePtr, (char *)NULL);
527 	Blt_Free(namePtr);
528 	if (tkwin != NULL) {
529 	    Tk_MoveResizeWindow(tkwin, Tk_X(master), Tk_Y(master),
530 		Tk_Width(master), Tk_Height(master));
531 	}
532 	tedPtr->inputIsSibling = 1;
533     }
534     if (tkwin == NULL) {
535 	return TCL_ERROR;
536     }
537     Blt_MakeTransparentWindowExist(tkwin, Tk_WindowId(parent), TRUE);
538     Tk_RestackWindow(tkwin, Above, (Tk_Window)NULL);
539     Tk_MapWindow(tkwin);
540     tedPtr->input = tkwin;
541     return TCL_OK;
542 }
543 
544 /*
545  * ----------------------------------------------------------------------------
546  *
547  * CreateEntry --
548  *
549  * ----------------------------------------------------------------------------
550  */
551 static int
CreateEntry(tedPtr,entryPtr)552 CreateEntry(tedPtr, entryPtr)
553     Ted *tedPtr;
554     Entry *entryPtr;
555 {
556     Tk_Window tkwin, master;
557     char string[200];
558     EntryRep *repPtr;
559     Blt_ChainLink *linkPtr;
560 
561     repPtr = Blt_Calloc(1, sizeof(EntryRep));
562     assert(repPtr);
563     repPtr->tablePtr = tedPtr->tablePtr;
564     repPtr->tedPtr = tedPtr;
565     repPtr->interp = tedPtr->interp;
566     repPtr->entryPtr = entryPtr;
567     repPtr->mapped = 0;
568 
569     /*
570      * Create a sibling window to cover the master window. It will
571      * be stacked just above the master window.
572      */
573 
574     master = tedPtr->tablePtr->tkwin;
575     sprintf(string, "bltTed%d", tedPtr->nextWindowId);
576     tedPtr->nextWindowId++;
577     tkwin = Tk_CreateWindow(tedPtr->interp, master, string, (char *)NULL);
578     if (tkwin == NULL) {
579 	Blt_Free(repPtr);
580 	return TCL_ERROR;
581     }
582     Tk_SetClass(tkwin, "BltTed");
583     Tk_CreateEventHandler(tkwin, ExposureMask | StructureNotifyMask,
584 	EntryEventProc, repPtr);
585     repPtr->tkwin = tkwin;
586     linkPtr = Blt_ChainNewLink();
587     Blt_ChainSetValue(linkPtr, repPtr);
588     Blt_ChainLinkAfter(tedPtr->chainPtr, linkPtr, (Blt_ChainLink *)NULL);
589     return TCL_OK;
590 }
591 
592 /*
593  * ----------------------------------------------------------------------------
594  *
595  * DestroyEntry --
596  *
597  * ----------------------------------------------------------------------------
598  */
599 static void
DestroyEntry(data)600 DestroyEntry(data)
601     DestroyData data;
602 {
603     EntryRep *repPtr = (EntryRep *)data;
604     Blt_ChainLink *linkPtr;
605     Entry *entryPtr;
606 
607     for (linkPtr = Blt_ChainFirstLink(repPtr->tedPtr->chainPtr);
608 	linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
609 	entryPtr = Blt_ChainGetValue(linkPtr);
610 	if (entryPtr == repPtr->entryPtr) {
611 	    Blt_ChainDeleteLink(repPtr->tedPtr->chainPtr, linkPtr);
612 	    Blt_Free(repPtr);
613 	    return;
614 	}
615     }
616 }
617 
618 /*
619  * ----------------------------------------------------------------------------
620  *
621  * DisplayEntry --
622  *
623  * ----------------------------------------------------------------------------
624  */
625 static void
DisplayEntry(clientData)626 DisplayEntry(clientData)
627     ClientData clientData;
628 {
629     EntryRep *repPtr = (EntryRep *) clientData;
630     Ted *tedPtr;
631     Entry *entryPtr;
632     Tk_Window tkwin;
633     int x, y, width, height;
634 
635     repPtr->flags &= ~REDRAW_PENDING;
636     if ((repPtr->tkwin == NULL) || (repPtr->entryPtr == NULL)) {
637 	return;
638     }
639     if (!Tk_IsMapped(repPtr->tkwin)) {
640 	return;
641     }
642     tedPtr = repPtr->tedPtr;
643     entryPtr = repPtr->entryPtr;
644     tkwin = repPtr->tkwin;
645 
646     /*
647      * Check if the entry size and position.
648      * Move and resize the window accordingly.
649      */
650     x = Tk_X(entryPtr->tkwin) - (entryPtr->padLeft + tedPtr->cavityPad);
651     y = Tk_Y(entryPtr->tkwin) - (entryPtr->padTop + tedPtr->cavityPad);
652     width = Tk_Width(entryPtr->tkwin) + PADDING(entryPtr->padX) +
653 	(2 * tedPtr->cavityPad);
654     height = Tk_Height(entryPtr->tkwin) + PADDING(entryPtr->padY) +
655 	(2 * tedPtr->cavityPad);
656 
657 
658     if ((Tk_X(tkwin) != x) || (Tk_Y(tkwin) != y) ||
659 	(Tk_Width(tkwin) != width) || (Tk_Height(tkwin) != height)) {
660 	Tk_MoveResizeWindow(tkwin, x, y, width, height);
661 	Tk_RestackWindow(tkwin, Above, (Tk_Window)NULL);
662     }
663     /* Clear the background of the entry */
664 
665     XFillRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin),
666 	tedPtr->attributes.fillGC, 0, 0, width, height);
667 
668     /* Draw the window */
669 
670     x = entryPtr->padLeft + tedPtr->cavityPad;
671     y = entryPtr->padTop + tedPtr->cavityPad;
672 
673     XFillRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin),
674 	tedPtr->attributes.widgetFillGC, x, y, Tk_Width(entryPtr->tkwin),
675 	Tk_Height(entryPtr->tkwin));
676     XDrawRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin),
677 	tedPtr->attributes.drawGC, x, y, Tk_Width(entryPtr->tkwin),
678 	Tk_Height(entryPtr->tkwin));
679 }
680 
681 /*
682  * ----------------------------------------------------------------------------
683  *
684  * FindEditor --
685  *
686  *	Searches for a table associated with the window given by its
687  *	pathname.  This window represents the master window of the table.
688  *
689  *	Errors may occur because
690  *	  1) pathName does not represent a valid Tk window or
691  *	  2) the window is not associated with any table as its master.
692  *
693  * Results:
694  *	If a table entry exists, a pointer to the Table structure is
695  *	returned. Otherwise NULL is returned.
696  *
697  * ----------------------------------------------------------------------------
698  */
699 static Ted *
FindEditor(clientData,interp,pathName)700 FindEditor(clientData, interp, pathName)
701     ClientData clientData;	/* Thread-specific data. */
702     Tcl_Interp *interp;		/* Interpreter to report errors back to */
703     char *pathName;		/* Path name of the master window */
704 {
705     Table *tablePtr;
706 
707     if (Blt_GetTable(clientData, interp, pathName, &tablePtr) != TCL_OK) {
708 	return NULL;
709     }
710     if (tablePtr->editPtr == NULL) {
711 	Tcl_AppendResult(interp, "no editor exists for table \"",
712 	    Tk_PathName(tablePtr->tkwin), "\"", (char *)NULL);
713 	return NULL;
714     }
715     return (Ted *) tablePtr->editPtr;
716 }
717 
718 /*
719  * ----------------------------------------------------------------------------
720  *
721  * CreateTed --
722  *
723  * ----------------------------------------------------------------------------
724  */
725 static Ted *
CreateTed(tablePtr,interp)726 CreateTed(tablePtr, interp)
727     Table *tablePtr;
728     Tcl_Interp *interp;
729 {
730     Ted *tedPtr;
731 
732     tedPtr = Blt_Calloc(1, sizeof(Ted));
733     assert(tedPtr);
734     tedPtr->nextWindowId = 0;
735     tedPtr->interp = interp;
736     tedPtr->tablePtr = tablePtr;
737     tedPtr->gridLineWidth = 1;
738     tedPtr->buttonHeight = 0;
739     tedPtr->cavityPad = 0;
740     tedPtr->minSize = 3;
741     tedPtr->gripSize = 5;
742     tedPtr->drawProc = DrawEditor;
743     tedPtr->destroyProc = DestroyEditor;
744     tedPtr->display = Tk_Display(tablePtr->tkwin);
745     tedPtr->relief = TK_RELIEF_RAISED;
746     tedPtr->borderWidth = 2;
747     tedPtr->doubleBuffer = 1;
748     tedPtr->chainPtr = Blt_ChainCreate();
749     /* Create the grid window */
750 
751     if (CreateGrid(tedPtr) != TCL_OK) {
752 	return NULL;
753     }
754     /* Create an InputOnly window to collect user events */
755     if (CreateEventWindow(tedPtr) != TCL_OK) {
756 	return NULL;
757     }
758     tablePtr->editPtr = (Editor *)tedPtr;
759     return tedPtr;
760 }
761 
762 /*
763  * ----------------------------------------------------------------------------
764  *
765  * DestroyTed --
766  *
767  * ----------------------------------------------------------------------------
768  */
769 static void
DestroyTed(freeProcData)770 DestroyTed(freeProcData)
771     DestroyData freeProcData;
772 {
773     Ted *tedPtr = (Ted *) freeProcData;
774 
775     if (tedPtr->rectArr != NULL) {
776 	Blt_Free(tedPtr->rectArr);
777     }
778     if (tedPtr->segArr != NULL) {
779 	Blt_Free(tedPtr->segArr);
780     }
781     if (tedPtr->fillGC != NULL) {
782 	Tk_FreeGC(tedPtr->display, tedPtr->fillGC);
783     }
784     if (tedPtr->drawGC != NULL) {
785 	Tk_FreeGC(tedPtr->display, tedPtr->drawGC);
786     }
787     if (tedPtr->rectGC != NULL) {
788 	Tk_FreeGC(tedPtr->display, tedPtr->rectGC);
789     }
790     if (tedPtr->padRectGC != NULL) {
791 	Tk_FreeGC(tedPtr->display, tedPtr->padRectGC);
792     }
793     /* Is this save ? */
794     tedPtr->tablePtr->editPtr = NULL;
795     Blt_Free(tedPtr);
796 
797 }
798 
799 /*
800  * ----------------------------------------------------------------------------
801  *
802  * ConfigureTed --
803  *
804  *	This procedure is called to process an argv/argc list in order to
805  *	configure the table geometry manager.
806  *
807  * Results:
808  *	The return value is a standard Tcl result.  If TCL_ERROR is
809  *	returned, then interp->result contains an error message.
810  *
811  * Side effects:
812  *	Table configuration options (padx, pady, rows, columns, etc) get
813  *	set.   The table is recalculated and arranged at the next idle
814  *	point.
815  *
816  * ----------------------------------------------------------------------------
817  */
818 static int
ConfigureTed(tedPtr,argc,argv,flags)819 ConfigureTed(tedPtr, argc, argv, flags)
820     Ted *tedPtr;
821     int argc;
822     char **argv;		/* Option-value pairs */
823     int flags;
824 {
825     XGCValues gcValues;
826     GC newGC;
827     unsigned long gcMask;
828 
829     if (Tk_ConfigureWidget(tedPtr->interp, tedPtr->tkwin, configSpecs,
830 	    argc, argv, (char *)tedPtr, flags) != TCL_OK) {
831 	return TCL_ERROR;
832     }
833     /* GC for filling background of edit window */
834 
835     gcMask = GCForeground;
836     gcValues.foreground = tedPtr->normalBg->pixel;
837     newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues);
838     if (tedPtr->fillGC != NULL) {
839 	Tk_FreeGC(tedPtr->display, tedPtr->fillGC);
840     }
841     tedPtr->fillGC = newGC;
842 
843     /* GC for drawing grid lines */
844 
845     gcMask = (GCForeground | GCBackground | GCLineWidth | GCLineStyle |
846 	GCCapStyle | GCJoinStyle | GCFont);
847     gcValues.font = Tk_FontId(tedPtr->font);
848     gcValues.foreground = tedPtr->gridColor->pixel;
849     gcValues.background = tedPtr->normalBg->pixel;
850     gcValues.line_width = LineWidth(tedPtr->gridLineWidth);
851     gcValues.cap_style = CapRound;
852     gcValues.join_style = JoinRound;
853     gcValues.line_style = LineSolid;
854     if (LineIsDashed(tedPtr->dashes)) {
855 	gcValues.line_style = LineOnOffDash;
856     }
857     newGC = Blt_GetPrivateGC(tedPtr->tkwin, gcMask, &gcValues);
858     if (tedPtr->drawGC != NULL) {
859 	Blt_FreePrivateGC(tedPtr->display, tedPtr->drawGC);
860     }
861     if (LineIsDashed(tedPtr->dashes)) {
862 	XSetDashes(tedPtr->display, newGC, 0,
863 		   (CONST char *)tedPtr->dashes.values,
864 		   strlen((char *)tedPtr->dashes.values));
865     }
866     tedPtr->drawGC = newGC;
867 
868     /* GC for button rectangles */
869 
870     gcMask = GCForeground;
871     gcValues.foreground = tedPtr->buttonColor->pixel;
872     newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues);
873     if (tedPtr->rectGC != NULL) {
874 	Tk_FreeGC(tedPtr->display, tedPtr->rectGC);
875     }
876     tedPtr->rectGC = newGC;
877 
878     /* GC for button rectangles */
879 
880     gcMask = GCForeground;
881     gcValues.foreground = tedPtr->padColor->pixel;
882     if (tedPtr->padStipple != None) {
883 	gcMask |= GCStipple | GCFillStyle;
884 	gcValues.stipple = tedPtr->padStipple;
885 	gcValues.fill_style = FillStippled;
886     }
887     newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues);
888     if (tedPtr->padRectGC != NULL) {
889 	Tk_FreeGC(tedPtr->display, tedPtr->padRectGC);
890     }
891     tedPtr->padRectGC = newGC;
892 
893     /* GC for filling entrys */
894 
895     gcMask = GCForeground;
896     gcValues.foreground = tedPtr->attributes.normalBg->pixel;
897     if (tedPtr->attributes.stipple != None) {
898 	gcMask |= GCStipple | GCFillStyle;
899 	gcValues.stipple = tedPtr->attributes.stipple;
900 	gcValues.fill_style = FillStippled;
901     }
902     newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues);
903     if (tedPtr->attributes.fillGC != NULL) {
904 	Tk_FreeGC(tedPtr->display, tedPtr->attributes.fillGC);
905     }
906     tedPtr->attributes.fillGC = newGC;
907 
908     /* GC for drawing entrys */
909 
910     gcMask = GCForeground | GCBackground | GCFont;
911     gcValues.foreground = tedPtr->attributes.normalFg->pixel;
912     gcValues.background = tedPtr->attributes.normalBg->pixel;
913     gcValues.font = Tk_FontId(tedPtr->attributes.font);
914     newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues);
915     if (tedPtr->attributes.drawGC != NULL) {
916 	Blt_FreePrivateGC(tedPtr->display, tedPtr->attributes.drawGC);
917     }
918     tedPtr->attributes.drawGC = newGC;
919 
920     /* GC for filling widget rectangles */
921 
922     gcMask = GCForeground;
923     gcValues.foreground = tedPtr->attributes.widgetColor->pixel;
924     newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues);
925     if (tedPtr->attributes.widgetFillGC != NULL) {
926 	Tk_FreeGC(tedPtr->display, tedPtr->attributes.widgetFillGC);
927     }
928     tedPtr->attributes.widgetFillGC = newGC;
929 
930     gcMask = GCForeground;
931     gcValues.foreground = tedPtr->attributes.cntlColor->pixel;
932     newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues);
933     if (tedPtr->attributes.cntlGC != NULL) {
934 	Tk_FreeGC(tedPtr->display, tedPtr->attributes.cntlGC);
935     }
936     tedPtr->attributes.cntlGC = newGC;
937 
938     /* GC for filling span rectangle */
939 
940     gcMask = GCForeground;
941     gcValues.foreground = tedPtr->spanColor->pixel;
942     if (tedPtr->spanStipple != None) {
943 	gcMask |= GCStipple | GCFillStyle;
944 	gcValues.stipple = tedPtr->spanStipple;
945 	gcValues.fill_style = FillStippled;
946     }
947     newGC = Tk_GetGC(tedPtr->tkwin, gcMask, &gcValues);
948     if (tedPtr->spanGC != NULL) {
949 	Tk_FreeGC(tedPtr->display, tedPtr->spanGC);
950     }
951     tedPtr->spanGC = newGC;
952 
953     /* Define cursor for grid events */
954     if (tedPtr->cursor != None) {
955 	Tk_DefineCursor(tedPtr->input, tedPtr->cursor);
956     } else {
957 	Tk_UndefineCursor(tedPtr->input);
958     }
959     return TCL_OK;
960 }
961 
962 
963 static void
LayoutGrid(tedPtr)964 LayoutGrid(tedPtr)
965     Ted *tedPtr;
966 {
967     int needed;
968     XSegment *segArr;
969     Table *tablePtr;
970     Blt_ChainLink *linkPtr;
971     RowColumn *rcPtr;
972     int startX, endX;
973     int startY, endY;
974     int count;
975 
976     tablePtr = tedPtr->tablePtr;
977     if (tedPtr->segArr != NULL) {
978 	Blt_Free(tedPtr->segArr);
979 	tedPtr->segArr = NULL;
980     }
981     tedPtr->nSegs = 0;
982     if ((tablePtr->nRows == 0) || (tablePtr->nColumns == 0)) {
983 	return;
984     }
985     needed = tablePtr->nRows + tablePtr->nColumns + 2;
986     segArr = Blt_Calloc(needed, sizeof(XSegment));
987     if (segArr == NULL) {
988 	return;
989     }
990     linkPtr = Blt_ChainFirstLink(tablePtr->columnInfo.chainPtr);
991     rcPtr = Blt_ChainGetValue(linkPtr);
992     startX = rcPtr->offset - tedPtr->gridLineWidth;
993 
994     linkPtr = Blt_ChainLastLink(tablePtr->columnInfo.chainPtr);
995     rcPtr = Blt_ChainGetValue(linkPtr);
996     endX = rcPtr->offset + rcPtr->size - 1;
997 
998     linkPtr = Blt_ChainFirstLink(tablePtr->rowInfo.chainPtr);
999     rcPtr = Blt_ChainGetValue(linkPtr);
1000     startY = rcPtr->offset - tedPtr->gridLineWidth;
1001 
1002     linkPtr = Blt_ChainLastLink(tablePtr->rowInfo.chainPtr);
1003     rcPtr = Blt_ChainGetValue(linkPtr);
1004     endY = rcPtr->offset + rcPtr->size - 1;
1005 
1006     count = 0;			/* Reset segment counter */
1007 
1008     for (linkPtr = Blt_ChainFirstLink(tablePtr->rowInfo.chainPtr);
1009 	linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1010 	rcPtr = Blt_ChainGetValue(linkPtr);
1011 	segArr[count].x1 = startX;
1012 	segArr[count].x2 = endX;
1013 	segArr[count].y1 = segArr[count].y2 = rcPtr->offset -
1014 	    tedPtr->gridLineWidth;
1015 	count++;
1016     }
1017     segArr[count].x1 = startX;
1018     segArr[count].x2 = endX;
1019     segArr[count].y1 = segArr[count].y2 = endY;
1020     count++;
1021 
1022     for (linkPtr = Blt_ChainFirstLink(tablePtr->columnInfo.chainPtr);
1023 	linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1024 	rcPtr = Blt_ChainGetValue(linkPtr);
1025 	segArr[count].y1 = startY;
1026 	segArr[count].y2 = endY;
1027 	segArr[count].x1 = segArr[count].x2 = rcPtr->offset -
1028 	    tedPtr->gridLineWidth;
1029 	count++;
1030     }
1031     segArr[count].x1 = segArr[count].x2 = endX;
1032     segArr[count].y1 = startY;
1033     segArr[count].y2 = endY;
1034     count++;
1035     assert(count == needed);
1036     if (tedPtr->segArr != NULL) {
1037 	Blt_Free(tedPtr->segArr);
1038     }
1039     tedPtr->segArr = segArr;
1040     tedPtr->nSegs = count;
1041 }
1042 
1043 
1044 static void
LayoutPads(tedPtr)1045 LayoutPads(tedPtr)
1046     Ted *tedPtr;
1047 {
1048     int needed;
1049     XRectangle *rectArr, *rectPtr;
1050     Table *tablePtr;
1051     Blt_ChainLink *linkPtr;
1052     RowColumn *rcPtr;
1053     int startX, endX;
1054     int startY, endY;
1055     int count;
1056 
1057     tablePtr = tedPtr->tablePtr;
1058     if (tedPtr->padRectArr != NULL) {
1059 	Blt_Free(tedPtr->padRectArr);
1060 	tedPtr->padRectArr = NULL;
1061     }
1062     tedPtr->nPadRects = 0;
1063     if ((tablePtr->nRows == 0) || (tablePtr->nColumns == 0)) {
1064 	return;
1065     }
1066     needed = 2 * (tablePtr->nRows + tablePtr->nColumns);
1067     rectArr = Blt_Calloc(needed, sizeof(XRectangle));
1068     if (rectArr == NULL) {
1069 	return;
1070     }
1071     linkPtr = Blt_ChainFirstLink(tablePtr->columnInfo.chainPtr);
1072     rcPtr = Blt_ChainGetValue(linkPtr);
1073     startX = rcPtr->offset;
1074 
1075     linkPtr = Blt_ChainLastLink(tablePtr->columnInfo.chainPtr);
1076     rcPtr = Blt_ChainGetValue(linkPtr);
1077     endX = (rcPtr->offset + rcPtr->size);
1078 
1079     linkPtr = Blt_ChainFirstLink(tablePtr->rowInfo.chainPtr);
1080     rcPtr = Blt_ChainGetValue(linkPtr);
1081     startY = rcPtr->offset;
1082 
1083     linkPtr = Blt_ChainLastLink(tablePtr->rowInfo.chainPtr);
1084     rcPtr = Blt_ChainGetValue(linkPtr);
1085     endY = (rcPtr->offset + rcPtr->size);
1086 
1087     count = 0;			/* Reset segment counter */
1088     rectPtr = rectArr;
1089     for (linkPtr = Blt_ChainFirstLink(tablePtr->rowInfo.chainPtr);
1090 	linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1091 	rcPtr = Blt_ChainGetValue(linkPtr);
1092 	if (rcPtr->pad.side1 > 0) {
1093 	    rectPtr->x = startX;
1094 	    rectPtr->y = rcPtr->offset;
1095 	    rectPtr->height = rcPtr->pad.side1;
1096 	    rectPtr->width = endX - startX - 1;
1097 	    rectPtr++, count++;
1098 	}
1099 	if (rcPtr->pad.side2 > 0) {
1100 	    rectPtr->x = startX;
1101 	    rectPtr->y = rcPtr->offset + rcPtr->size - rcPtr->pad.side2 - 1;
1102 	    rectPtr->height = rcPtr->pad.side2;
1103 	    rectPtr->width = endX - startX - 1;
1104 	    rectPtr++, count++;
1105 	}
1106     }
1107     for (linkPtr = Blt_ChainFirstLink(tablePtr->columnInfo.chainPtr);
1108 	linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1109 	rcPtr = Blt_ChainGetValue(linkPtr);
1110 	if (rcPtr->pad.side1 > 0) {
1111 	    rectPtr->x = rcPtr->offset;
1112 	    rectPtr->y = startY;
1113 	    rectPtr->height = endY - startY - 1;
1114 	    rectPtr->width = rcPtr->pad.side1;
1115 	    rectPtr++, count++;
1116 	}
1117 	if (rcPtr->pad.side2 > 0) {
1118 	    rectPtr->x = rcPtr->offset + rcPtr->size - rcPtr->pad.side2;
1119 	    rectPtr->y = startY;
1120 	    rectPtr->height = endY - startY - 1;
1121 	    rectPtr->width = rcPtr->pad.side2;
1122 	    rectPtr++, count++;
1123 	}
1124     }
1125     if (count == 0) {
1126 	Blt_Free(rectArr);
1127 	return;
1128     }
1129     tedPtr->padRectArr = rectArr;
1130     tedPtr->nPadRects = count;
1131 }
1132 
1133 static void
LayoutEntries(tedPtr)1134 LayoutEntries(tedPtr)
1135     Ted *tedPtr;
1136 {
1137     Entry *entryPtr;
1138     XRectangle *rectArr;
1139     int needed;
1140     int count;
1141     Blt_ChainLink *linkPtr;
1142 
1143     if (tedPtr->widgetPadRectArr != NULL) {
1144 	Blt_Free(tedPtr->widgetPadRectArr);
1145 	tedPtr->widgetPadRectArr = NULL;
1146     }
1147     tedPtr->nWidgetPadRects = 0;
1148 
1149     needed = Blt_ChainGetLength(tedPtr->tablePtr->chainPtr);
1150     rectArr = Blt_Calloc(needed, sizeof(XRectangle));
1151     if (rectArr == NULL) {
1152 	return;
1153     }
1154     /* Draw any entry windows */
1155     count = 0;
1156     for (linkPtr = Blt_ChainFirstLink(tedPtr->tablePtr->chainPtr);
1157 	linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1158 	entryPtr = Blt_ChainGetValue(linkPtr);
1159 	if ((PADDING(entryPtr->padX) + PADDING(entryPtr->padY)) == 0) {
1160 	    continue;
1161 	}
1162 	rectArr[count].x = Tk_X(entryPtr->tkwin) - entryPtr->padLeft;
1163 	rectArr[count].y = Tk_Y(entryPtr->tkwin) - entryPtr->padTop;
1164 	rectArr[count].width = Tk_Width(entryPtr->tkwin) +
1165 	    PADDING(entryPtr->padX);
1166 	rectArr[count].height = Tk_Height(entryPtr->tkwin) +
1167 	    PADDING(entryPtr->padY);
1168 	count++;
1169     }
1170     if (count == 0) {
1171 	Blt_Free(rectArr);
1172 	return;
1173     }
1174     tedPtr->widgetPadRectArr = rectArr;
1175     tedPtr->nWidgetPadRects = count;
1176 }
1177 
1178 static void
LayoutControlEntries(tedPtr)1179 LayoutControlEntries(tedPtr)
1180     Ted *tedPtr;
1181 {
1182     Entry *entryPtr;
1183     XRectangle *rectArr;
1184     int needed;
1185     int count;
1186     Table *tablePtr = tedPtr->tablePtr;
1187     Blt_ChainLink *linkPtr;
1188     RowColumn *rcPtr;
1189 
1190     if (tedPtr->cntlRectArr != NULL) {
1191 	Blt_Free(tedPtr->cntlRectArr);
1192 	tedPtr->cntlRectArr = NULL;
1193     }
1194     tedPtr->nCntlRects = 0;
1195 
1196     needed = (tablePtr->nRows + tablePtr->nColumns);
1197     rectArr = Blt_Calloc(needed, sizeof(XRectangle));
1198     if (rectArr == NULL) {
1199 	return;
1200     }
1201     /* Draw any entry windows */
1202     count = 0;
1203     for (linkPtr = Blt_ChainFirstLink(tablePtr->columnInfo.chainPtr);
1204 	linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1205 	rcPtr = Blt_ChainGetValue(linkPtr);
1206 	entryPtr = rcPtr->control;
1207 	if (entryPtr != NULL) {
1208 	    rectArr[count].x = Tk_X(entryPtr->tkwin) - entryPtr->padLeft;
1209 	    rectArr[count].y = Tk_Y(entryPtr->tkwin) - entryPtr->padTop;
1210 	    rectArr[count].width = Tk_Width(entryPtr->tkwin) +
1211 		PADDING(entryPtr->padX);
1212 	    rectArr[count].height = Tk_Height(entryPtr->tkwin) +
1213 		PADDING(entryPtr->padY);
1214 	    count++;
1215 	}
1216     }
1217     for (linkPtr = Blt_ChainFirstLink(tablePtr->rowInfo.chainPtr);
1218 	linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1219 	rcPtr = Blt_ChainGetValue(linkPtr);
1220 	entryPtr = rcPtr->control;
1221 	if (entryPtr != NULL) {
1222 	    rectArr[count].x = Tk_X(entryPtr->tkwin) - entryPtr->padLeft;
1223 	    rectArr[count].y = Tk_Y(entryPtr->tkwin) - entryPtr->padTop;
1224 	    rectArr[count].width = Tk_Width(entryPtr->tkwin) +
1225 		PADDING(entryPtr->padX);
1226 	    rectArr[count].height = Tk_Height(entryPtr->tkwin) +
1227 		PADDING(entryPtr->padY);
1228 	    count++;
1229 	}
1230     }
1231     if (count == 0) {
1232 	Blt_Free(rectArr);
1233 	return;
1234     }
1235     tedPtr->cntlRectArr = rectArr;
1236     tedPtr->nCntlRects = count;
1237 }
1238 
1239 static void
LayoutButtons(tedPtr)1240 LayoutButtons(tedPtr)
1241     Ted *tedPtr;
1242 {
1243     int needed;
1244     XRectangle *rectArr;
1245     Table *tablePtr;
1246     Blt_ChainLink *linkPtr;
1247     RowColumn *rcPtr;
1248     int count;
1249 
1250     tablePtr = tedPtr->tablePtr;
1251     if ((tablePtr->nRows == 0) || (tablePtr->nColumns == 0)) {
1252 	if (tedPtr->rectArr != NULL) {
1253 	    Blt_Free(tedPtr->rectArr);
1254 	}
1255 	tedPtr->rectArr = NULL;
1256 	tedPtr->nRects = 0;
1257 	return;			/* Nothing to display, empty table */
1258     }
1259     needed = 2 * (tablePtr->nRows + tablePtr->nColumns);
1260     rectArr = Blt_Calloc(needed, sizeof(XRectangle));
1261     if (rectArr == NULL) {
1262 	return;			/* Can't allocate rectangles */
1263     }
1264     count = 0;
1265     for (linkPtr = Blt_ChainFirstLink(tablePtr->rowInfo.chainPtr);
1266 	linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1267 	rcPtr = Blt_ChainGetValue(linkPtr);
1268 	rectArr[count].x = 0;
1269 	rectArr[count].y = rcPtr->offset - rcPtr->pad.side1;
1270 	rectArr[count].width = tedPtr->buttonHeight;
1271 	rectArr[count].height = rcPtr->size - 2;
1272 	count++;
1273 	rectArr[count].x = Tk_Width(tedPtr->tkwin) - tedPtr->buttonHeight;
1274 	rectArr[count].y = rcPtr->offset - rcPtr->pad.side1;
1275 	rectArr[count].width = tedPtr->buttonHeight;
1276 	rectArr[count].height = rcPtr->size - 2;
1277 	count++;
1278     }
1279     for (linkPtr = Blt_ChainFirstLink(tablePtr->columnInfo.chainPtr);
1280 	linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1281 	rcPtr = Blt_ChainGetValue(linkPtr);
1282 	rectArr[count].x = rcPtr->offset - rcPtr->pad.side1;
1283 	rectArr[count].y = 0;
1284 	rectArr[count].width = rcPtr->size - 2;
1285 	rectArr[count].height = tedPtr->buttonHeight;
1286 	count++;
1287 	rectArr[count].x = rcPtr->offset - rcPtr->pad.side1;
1288 	rectArr[count].y = Tk_Height(tedPtr->tkwin) - tedPtr->buttonHeight;
1289 	rectArr[count].width = rcPtr->size - 2;
1290 	rectArr[count].height = tedPtr->buttonHeight;
1291 	count++;
1292     }
1293     assert(count == needed);
1294     if (tedPtr->rectArr != NULL) {
1295 	Blt_Free(tedPtr->rectArr);
1296     }
1297     tedPtr->rectArr = rectArr;
1298     tedPtr->nRects = count;
1299 }
1300 
1301 
1302 static void
DisplayTed(clientData)1303 DisplayTed(clientData)
1304     ClientData clientData;
1305 {
1306     Ted *tedPtr = (Ted *) clientData;
1307     Tk_Window master;
1308     Tk_Window tkwin;
1309     Blt_ChainLink *linkPtr;
1310     EntryRep *repPtr;
1311     Drawable drawable;
1312     Pixmap pixmap;
1313 
1314 #ifdef notdef
1315     fprintf(stderr, "display grid\n");
1316 #endif
1317     tedPtr->flags &= ~REDRAW_PENDING;
1318     if (!Tk_IsMapped(tedPtr->tkwin)) {
1319 	return;
1320     }
1321     /*
1322      * Check if the master window has changed size and resize the
1323      * grid and input windows accordingly.
1324      */
1325     master = tedPtr->tablePtr->tkwin;
1326     if ((Tk_Width(master) != Tk_Width(tedPtr->tkwin)) ||
1327 	(Tk_Height(master) != Tk_Height(tedPtr->tkwin))) {
1328 #ifdef notdef
1329 	fprintf(stderr, "resizing windows\n");
1330 #endif
1331 	Tk_ResizeWindow(tedPtr->tkwin, Tk_Width(master), Tk_Height(master));
1332 	Tk_ResizeWindow(tedPtr->input, Tk_Width(master), Tk_Height(master));
1333 	if (tedPtr->inputIsSibling) {
1334 	    Tk_MoveWindow(tedPtr->input, Tk_X(master), Tk_X(master));
1335 	}
1336 	tedPtr->flags |= LAYOUT_PENDING;
1337     }
1338     if (tedPtr->flags & LAYOUT_PENDING) {
1339 #ifdef notdef
1340 	fprintf(stderr, "layout of grid\n");
1341 #endif
1342 	LayoutPads(tedPtr);
1343 	LayoutEntries(tedPtr);
1344 	LayoutControlEntries(tedPtr);
1345 	LayoutGrid(tedPtr);
1346 	LayoutButtons(tedPtr);
1347 	tedPtr->flags &= ~LAYOUT_PENDING;
1348     }
1349     tkwin = tedPtr->tkwin;
1350 
1351     pixmap = None;		/* Suppress compiler warning. */
1352     drawable = Tk_WindowId(tkwin);
1353     if (tedPtr->doubleBuffer) {
1354 	/* Create an off-screen pixmap for semi-smooth scrolling. */
1355 	pixmap = Tk_GetPixmap(tedPtr->display, Tk_WindowId(tkwin),
1356 	    Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
1357 	drawable = pixmap;
1358     }
1359     /* Clear the background of the grid */
1360 
1361     XFillRectangle(Tk_Display(tkwin), drawable, tedPtr->fillGC, 0, 0,
1362 	Tk_Width(tkwin), Tk_Height(tkwin));
1363 
1364     /* Draw the row and column buttons */
1365 
1366     if (tedPtr->nRects > 0) {
1367 	int i;
1368 
1369 	for (i = 0; i < tedPtr->nRects; i++) {
1370 	    Blt_Fill3DRectangle(tkwin, drawable, tedPtr->border,
1371 		tedPtr->rectArr[i].x, tedPtr->rectArr[i].y,
1372 		tedPtr->rectArr[i].width, tedPtr->rectArr[i].height,
1373 		tedPtr->borderWidth, tedPtr->relief);
1374 	}
1375 #ifdef notdef
1376 	XFillRectangles(tedPtr->display, drawable, tedPtr->rectGC,
1377 	    tedPtr->rectArr, tedPtr->nRects);
1378 	XDrawRectangles(tedPtr->display, drawable, tedPtr->drawGC,
1379 	    tedPtr->rectArr, tedPtr->nRects);
1380 #endif
1381     }
1382     if (tedPtr->nPadRects > 0) {
1383 	XFillRectangles(tedPtr->display, drawable, tedPtr->padRectGC,
1384 	    tedPtr->padRectArr, tedPtr->nPadRects);
1385     }
1386     if (tedPtr->spanActive) {
1387 	XFillRectangles(tedPtr->display, drawable, tedPtr->spanGC,
1388 	    tedPtr->activeRectArr, 1);
1389 	XFillRectangles(tedPtr->display, drawable, tedPtr->drawGC,
1390 	    tedPtr->activeRectArr + 1, 4);
1391     }
1392     if (tedPtr->nWidgetPadRects > 0) {
1393 	XFillRectangles(tedPtr->display, drawable, tedPtr->attributes.fillGC,
1394 	    tedPtr->widgetPadRectArr, tedPtr->nWidgetPadRects);
1395     }
1396     if (tedPtr->nCntlRects > 0) {
1397 	XFillRectangles(tedPtr->display, drawable, tedPtr->attributes.cntlGC,
1398 	    tedPtr->cntlRectArr, tedPtr->nCntlRects);
1399     }
1400     /* Draw the grid lines */
1401     if (tedPtr->nSegs > 0) {
1402 	XDrawSegments(tedPtr->display, drawable, tedPtr->drawGC,
1403 	    tedPtr->segArr, tedPtr->nSegs);
1404     }
1405 #ifndef notdef
1406     /* Draw any entry windows */
1407     for (linkPtr = Blt_ChainFirstLink(tedPtr->chainPtr); linkPtr != NULL;
1408 	linkPtr = Blt_ChainNextLink(linkPtr)) {
1409 	repPtr = Blt_ChainGetValue(linkPtr);
1410 	if (repPtr->mapped) {
1411 	    DisplayEntry(repPtr);
1412 	}
1413     }
1414 #endif
1415     if (tedPtr->doubleBuffer) {
1416 	XCopyArea(tedPtr->display, drawable, Tk_WindowId(tkwin), tedPtr->fillGC,
1417 	    0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, 0);
1418 	Tk_FreePixmap(tedPtr->display, pixmap);
1419     }
1420 }
1421 
1422 
1423 static void
DrawEditor(editPtr)1424 DrawEditor(editPtr)
1425     Editor *editPtr;
1426 {
1427     Ted *tedPtr = (Ted *) editPtr;
1428 
1429     tedPtr->flags |= LAYOUT_PENDING;
1430     if ((tedPtr->tkwin != NULL) && !(tedPtr->flags & REDRAW_PENDING)) {
1431 	tedPtr->flags |= REDRAW_PENDING;
1432 #ifdef notdef
1433 	fprintf(stderr, "from draw editor\n");
1434 #endif
1435 	Tcl_DoWhenIdle(DisplayTed, tedPtr);
1436     }
1437 }
1438 
1439 static void
DestroyEditor(destroyData)1440 DestroyEditor(destroyData)
1441     DestroyData destroyData;
1442 {
1443     Ted *tedPtr = (Ted *) destroyData;
1444 
1445     tedPtr->tkwin = NULL;
1446     if (tedPtr->flags & REDRAW_PENDING) {
1447 	Tcl_CancelIdleCall(DisplayTed, tedPtr);
1448     }
1449     Tcl_EventuallyFree(tedPtr, DestroyTed);
1450 }
1451 
1452 /*
1453  * ----------------------------------------------------------------------------
1454  *
1455  * EditOp --
1456  *
1457  *	Processes an argv/argc list of table entries to add and configure
1458  *	new widgets into the table.  A table entry consists of the
1459  *	window path name, table index, and optional configuration options.
1460  *	The first argument in the argv list is the name of the table.  If
1461  *	no table exists for the given window, a new one is created.
1462  *
1463  * Results:
1464  *	Returns a standard Tcl result.  If an error occurred, TCL_ERROR is
1465  *	returned and an error message is left in interp->result.
1466  *
1467  * Side Effects:
1468  *	Memory is allocated, a new master table is possibly created, etc.
1469  *	The table is re-computed and arranged at the next idle point.
1470  *
1471  * ----------------------------------------------------------------------------
1472  */
1473 static int
EditOp(dataPtr,interp,argc,argv)1474 EditOp(dataPtr, interp, argc, argv)
1475     TableInterpData *dataPtr;	/* Interpreter-specific data. */
1476     Tcl_Interp *interp;		/* Interpreter to return list of names to */
1477     int argc;			/* Number of arguments */
1478     char **argv;
1479 {
1480     Table *tablePtr;
1481     Ted *tedPtr;
1482 
1483     if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) {
1484 	return TCL_ERROR;
1485     }
1486     if (tablePtr->editPtr != NULL) {	/* Already editing this table */
1487 	tedPtr = (Ted *) tablePtr->editPtr;
1488     } else {
1489 	tedPtr = CreateTed(tablePtr, interp);
1490 	if (tedPtr == NULL) {
1491 	    return TCL_ERROR;
1492 	}
1493     }
1494     if (ConfigureTed(tedPtr, argc - 3, argv + 3, 0) != TCL_OK) {
1495 	tedPtr->tkwin = NULL;
1496 	if (tedPtr->flags & REDRAW_PENDING) {
1497 	    Tcl_CancelIdleCall(DisplayTed, tedPtr);
1498 	}
1499 	Tcl_EventuallyFree(tedPtr, DestroyTed);
1500 	return TCL_ERROR;
1501     }
1502     /* Rearrange the table */
1503     if (!(tablePtr->flags & ARRANGE_PENDING)) {
1504 	tablePtr->flags |= ARRANGE_PENDING;
1505 	Tcl_DoWhenIdle(tablePtr->arrangeProc, tablePtr);
1506     }
1507     Tcl_SetObjResult(interp, Tcl_NewStringObj(Tk_PathName(tedPtr->tkwin), -1));
1508     tedPtr->flags |= LAYOUT_PENDING;
1509     EventuallyRedraw(tedPtr);
1510     return TCL_OK;
1511 }
1512 
1513 /*
1514  * ----------------------------------------------------------------------------
1515  *
1516  * CgetCmd --
1517  *
1518  * Results:
1519  *	The return value is a standard Tcl result.  If TCL_ERROR is
1520  *	returned, then interp->result contains an error message.
1521  *
1522  * ----------------------------------------------------------------------------
1523  */
1524 /*ARGSUSED*/
1525 static int
CgetOp(dataPtr,interp,argc,argv)1526 CgetOp(dataPtr, interp, argc, argv)
1527     TableInterpData *dataPtr;	/* Interpreter-specific data. */
1528     Tcl_Interp *interp;		/* Interpreter to report results back to */
1529     int argc;			/* Not used. */
1530     char **argv;		/* Option-value pairs */
1531 {
1532     Ted *tedPtr;
1533 
1534     tedPtr = FindEditor(dataPtr, interp, argv[2]);
1535     if (tedPtr == NULL) {
1536 	return TCL_ERROR;
1537     }
1538     return Tk_ConfigureValue(interp, tedPtr->tkwin, configSpecs,
1539 	    (char *)tedPtr, argv[3], 0);
1540 }
1541 
1542 /*
1543  * ----------------------------------------------------------------------------
1544  *
1545  * ConfigureCmd --
1546  *
1547  *	This procedure is called to process an argv/argc list in order to
1548  *	configure the table geometry manager.
1549  *
1550  * Results:
1551  *	The return value is a standard Tcl result.  If TCL_ERROR is
1552  *	returned, then interp->result contains an error message.
1553  *
1554  * Side effects:
1555  *	Table configuration options (padx, pady, rows, columns, etc) get
1556  *	set.   The table is recalculated and arranged at the next idle
1557  *	point.
1558  *
1559  * ----------------------------------------------------------------------------
1560  */
1561 static int
ConfigureOp(dataPtr,interp,argc,argv)1562 ConfigureOp(dataPtr, interp, argc, argv)
1563     TableInterpData *dataPtr;	/* Interpreter-specific data. */
1564     Tcl_Interp *interp;		/* Interpreter to report results back to */
1565     int argc;
1566     char **argv;		/* Option-value pairs */
1567 {
1568     Ted *tedPtr;
1569 
1570     tedPtr = FindEditor(dataPtr, interp, argv[2]);
1571     if (tedPtr == NULL) {
1572 	return TCL_ERROR;
1573     }
1574     if (argc == 3) {
1575 	return Tk_ConfigureInfo(interp, tedPtr->tkwin, configSpecs,
1576 		(char *)tedPtr, (char *)NULL, 0);
1577     } else if (argc == 4) {
1578 	return Tk_ConfigureInfo(interp, tedPtr->tkwin, configSpecs,
1579 		(char *)tedPtr, argv[3], 0);
1580     }
1581     if (ConfigureTed(tedPtr, argc - 3, argv + 3,
1582 	    TK_CONFIG_ARGV_ONLY) != TCL_OK) {
1583 	return TCL_ERROR;
1584     }
1585     EventuallyRedraw(tedPtr);
1586     return TCL_OK;
1587 }
1588 
1589 /*
1590  * ----------------------------------------------------------------------------
1591  *
1592  * SelectOp --
1593  *
1594  * ----------------------------------------------------------------------------
1595  */
1596 /*ARGSUSED*/
1597 static int
SelectOp(dataPtr,interp,argc,argv)1598 SelectOp(dataPtr, interp, argc, argv)
1599     TableInterpData *dataPtr;	/* Interpreter-specific data. */
1600     Tcl_Interp *interp;		/* Interpreter to return list of names to */
1601     int argc;			/* Not used. */
1602     char **argv;
1603 {
1604     Table *tablePtr;
1605     Ted *tedPtr;
1606     Entry *entryPtr;
1607     int active;
1608     int x, y, width, height;
1609     int ix, iy;
1610     Blt_ChainLink *linkPtr;
1611     Tk_Window tkwin;
1612 
1613     /* ted select master @x,y */
1614     tkwin = Tk_MainWindow(interp);
1615     tedPtr = FindEditor(dataPtr, interp, argv[2]);
1616     if (tedPtr == NULL) {
1617 	return TCL_ERROR;
1618     }
1619     if (Blt_GetXY(interp, tkwin, argv[3], &ix, &iy) != TCL_OK) {
1620 	return TCL_ERROR;
1621     }
1622     tablePtr = tedPtr->tablePtr;
1623     active = 0;
1624     for (linkPtr = Blt_ChainFirstLink(tablePtr->chainPtr);
1625 	linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1626 	entryPtr = Blt_ChainGetValue(linkPtr);
1627 	x = entryPtr->x - entryPtr->padX.side1;
1628 	y = entryPtr->y - entryPtr->padY.side1;
1629 	width = Tk_Width(entryPtr->tkwin) + PADDING(entryPtr->padX);
1630 	height = Tk_Height(entryPtr->tkwin) + PADDING(entryPtr->padY);
1631 	if ((ix >= x) && (ix <= (x + width)) &&
1632 	    (iy >= y) && (iy <= (y + height))) {
1633 	    int left, right, top, bottom;
1634 	    int last;
1635 	    int grip;
1636 	    RowColumn *rcPtr;
1637 
1638 	    last = entryPtr->column.rcPtr->index + entryPtr->column.span - 1;
1639 	    linkPtr = Blt_ChainGetNthLink(tablePtr->columnInfo.chainPtr, last);
1640 	    rcPtr = Blt_ChainGetValue(linkPtr);
1641 
1642 	    /* Calculate the span rectangle */
1643 	    left = (entryPtr->column.rcPtr->offset -
1644 		entryPtr->column.rcPtr->pad.side1);
1645 	    right = (rcPtr->offset - rcPtr->pad.side1) + rcPtr->size;
1646 
1647 	    top = (entryPtr->row.rcPtr->offset -
1648 		entryPtr->row.rcPtr->pad.side1);
1649 
1650 	    last = entryPtr->row.rcPtr->index + entryPtr->row.span - 1;
1651 	    linkPtr = Blt_ChainGetNthLink(tablePtr->rowInfo.chainPtr, last);
1652 	    rcPtr = Blt_ChainGetValue(linkPtr);
1653 	    bottom = (rcPtr->offset - rcPtr->pad.side1) + rcPtr->size;
1654 
1655 	    tedPtr->activeRectArr[0].x = left;
1656 	    tedPtr->activeRectArr[0].y = top;
1657 	    tedPtr->activeRectArr[0].width = (right - left);
1658 	    tedPtr->activeRectArr[0].height = (bottom - top);
1659 
1660 	    grip = tedPtr->gripSize;
1661 	    tedPtr->activeRectArr[1].x = (left + right - grip) / 2;
1662 	    tedPtr->activeRectArr[1].y = top;
1663 	    tedPtr->activeRectArr[1].width = grip - 1;
1664 	    tedPtr->activeRectArr[1].height = grip - 1;
1665 
1666 	    tedPtr->activeRectArr[2].x = left;
1667 	    tedPtr->activeRectArr[2].y = (top + bottom - grip) / 2;
1668 	    tedPtr->activeRectArr[2].width = grip - 1;
1669 	    tedPtr->activeRectArr[2].height = grip - 1;
1670 
1671 	    tedPtr->activeRectArr[3].x = (left + right - grip) / 2;
1672 	    tedPtr->activeRectArr[3].y = bottom - grip;
1673 	    tedPtr->activeRectArr[3].width = grip - 1;
1674 	    tedPtr->activeRectArr[3].height = grip - 1;
1675 
1676 	    tedPtr->activeRectArr[4].x = right - grip;
1677 	    tedPtr->activeRectArr[4].y = (top + bottom - grip) / 2;
1678 	    tedPtr->activeRectArr[4].width = grip - 1;
1679 	    tedPtr->activeRectArr[4].height = grip - 1;
1680 
1681         Tcl_SetObjResult(interp, Tcl_NewStringObj(Tk_PathName(entryPtr->tkwin), -1));
1682 	    active = 1;
1683 	    break;
1684 	}
1685     }
1686     if ((active) || (active != tedPtr->spanActive)) {
1687 	tedPtr->spanActive = active;
1688 	EventuallyRedraw(tedPtr);
1689     }
1690     return TCL_OK;
1691 }
1692 
1693 /*
1694  * ----------------------------------------------------------------------------
1695  *
1696  * EditOp --
1697  *
1698  *	Processes an argv/argc list of table entries to add and configure
1699  *	new widgets into the table.  A table entry consists of the
1700  *	window path name, table index, and optional configuration options.
1701  *	The first argument in the argv list is the name of the table.  If
1702  *	no table exists for the given window, a new one is created.
1703  *
1704  * Results:
1705  *	Returns a standard Tcl result.  If an error occurred, TCL_ERROR is
1706  *	returned and an error message is left in interp->result.
1707  *
1708  * Side Effects:
1709  *	Memory is allocated, a new master table is possibly created, etc.
1710  *	The table is re-computed and arranged at the next idle point.
1711  *
1712  * ----------------------------------------------------------------------------
1713  */
1714 static int
RepOp(dataPtr,interp,argc,argv)1715 RepOp(dataPtr, interp, argc, argv)
1716     TableInterpData *dataPtr;	/* Interpreter-specific data. */
1717     Tcl_Interp *interp;		/* Interpreter to return list of names to */
1718     int argc;			/* Number of arguments */
1719     char **argv;
1720 {
1721     Tk_Window tkwin;
1722     Table *tablePtr;
1723     Ted *tedPtr;
1724 
1725     /* ted rep master index */
1726     tkwin = Tk_NameToWindow(interp, argv[3], Tk_MainWindow(interp));
1727     if (tkwin == NULL) {
1728 	return TCL_ERROR;
1729     }
1730     if (Blt_GetTable(dataPtr, interp, argv[2], &tablePtr) != TCL_OK) {
1731 	return TCL_ERROR;
1732     }
1733     if (tablePtr->editPtr != NULL) {	/* Already editing this table */
1734 	tedPtr = (Ted *) tablePtr->editPtr;
1735     } else {
1736 	tedPtr = CreateTed(tablePtr, interp);
1737 	if (tedPtr == NULL) {
1738 	    return TCL_ERROR;
1739 	}
1740     }
1741     if (ConfigureTed(tedPtr, argc - 3, argv + 3, 0) != TCL_OK) {
1742 	tedPtr->tkwin = NULL;
1743 	if (tedPtr->flags & REDRAW_PENDING) {
1744 	    Tcl_CancelIdleCall(DisplayTed, tedPtr);
1745 	}
1746 	Tcl_EventuallyFree(tedPtr, DestroyTed);
1747 	return TCL_ERROR;
1748     }
1749     /* Rearrange the table */
1750     if (!(tablePtr->flags & ARRANGE_PENDING)) {
1751 	tablePtr->flags |= ARRANGE_PENDING;
1752 	Tcl_DoWhenIdle(tablePtr->arrangeProc, tablePtr);
1753     }
1754     Tcl_SetObjResult(interp, Tcl_NewStringObj(Tk_PathName(tedPtr->tkwin), -1));
1755     tedPtr->flags |= LAYOUT_PENDING;
1756     EventuallyRedraw(tedPtr);
1757     return TCL_OK;
1758 }
1759 
1760 /*
1761  * ----------------------------------------------------------------------------
1762  *
1763  * Command options for the table editor.
1764  *
1765  * The fields for Blt_OperSpec are as follows:
1766  *
1767  *   - option name
1768  *   - minimum number of characters required to disambiguate the option name.
1769  *   - function associated with command option.
1770  *   - minimum number of arguments required.
1771  *   - maximum number of arguments allowed (0 indicates no limit).
1772  *   - usage string
1773  *
1774  * ----------------------------------------------------------------------------
1775  */
1776 static Blt_OpSpec opSpecs[] =
1777 {
1778     {"cget", 2, (Blt_Op)CgetOp, 4, 4, "master option",},
1779     {"configure", 2, (Blt_Op)ConfigureOp, 3, 0,
1780 	"master ?option...?",},
1781     {"edit", 1, (Blt_Op)EditOp, 3, 0, "master ?options...?",},
1782     {"rep", 1, (Blt_Op)RepOp, 2, 0, "master index ?options...?",},
1783     {"select", 1, (Blt_Op)SelectOp, 4, 0, "master @x,y",},
1784  /* {"forget", 1, (Blt_Op)ForgetOp, 3, 0, "master ?master...?",},
1785     {"index", 1, (Blt_Op)IndexOp, 3, 0, "master ?item...?",}, */
1786 };
1787 static int nSpecs = sizeof(opSpecs) / sizeof(Blt_OpSpec);
1788 
1789 /*
1790  * ----------------------------------------------------------------------------
1791  *
1792  * TedCmd --
1793  *
1794  *	This procedure is invoked to process the Tcl command that
1795  *	corresponds to the table geometry manager.  See the user
1796  *	documentation for details on what it does.
1797  *
1798  * Results:
1799  *	A standard Tcl result.
1800  *
1801  * Side effects:
1802  *	See the user documentation.
1803  *
1804  * ----------------------------------------------------------------------------
1805  */
1806 static int
TedCmd(clientData,interp,argc,argv)1807 TedCmd(clientData, interp, argc, argv)
1808     ClientData clientData;	/* Thread-specific data. */
1809     Tcl_Interp *interp;
1810     int argc;
1811     char **argv;
1812 {
1813     Blt_Op proc;
1814     int result;
1815 
1816     proc = Blt_GetOp(interp, nSpecs, opSpecs, BLT_OP_ARG1, argc, argv, 0);
1817     if (proc == NULL) {
1818 	return TCL_ERROR;
1819     }
1820     result = (*proc) (clientData, interp, argc, argv);
1821     return result;
1822 }
1823 
1824 static TableData *
GetTableInterpData(interp)1825 GetTableInterpData(interp)
1826      Tcl_Interp *interp;
1827 {
1828     TableData *dataPtr;
1829     Tcl_InterpDeleteProc *proc;
1830 
1831     dataPtr = (TableData *)Tcl_GetAssocData(interp, TABLE_THREAD_KEY, &proc);
1832     assert(dataPtr);
1833     return dataPtr;
1834 }
1835 
1836 /*
1837  * ----------------------------------------------------------------------------
1838  *
1839  * Blt_TedInit --
1840  *
1841  *	This procedure is invoked to initialize the Tcl command that
1842  *	corresponds to the table geometry manager.
1843  *
1844  * Results:
1845  *	None.
1846  *
1847  * Side effects:
1848  *	Creates the new command and adds an entry into a global Tcl
1849  *	associative array.
1850  *
1851  * ---------------------------------------------------------------------------
1852  */
1853 int
Blt_TedInit(interp)1854 Blt_TedInit(interp)
1855     Tcl_Interp *interp;
1856 {
1857     static Blt_CmdSpec cmdSpec = {"ted", TedCmd, };
1858     TableData *dataPtr;
1859 
1860     dataPtr = GetTableInterpData(interp);
1861     cmdSpec.clientData = dataPtr;
1862     if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) {
1863 	return TCL_ERROR;
1864     }
1865     return TCL_OK;
1866 }
1867