OSDN Git Service

Please enter the commit message for your changes. Lines starting
[eos/base.git] / util / src / TclTk / blt2.5 / generic / bltTed.c
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
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
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
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
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
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
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
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
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
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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     interp->result = Tk_PathName(tedPtr->tkwin);
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
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
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
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             interp->result = Tk_PathName(entryPtr->tkwin);
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
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     interp->result = Tk_PathName(tedPtr->tkwin);
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
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 *
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
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 }