1 |
578 |
markom |
/*
|
2 |
|
|
* tkTable.c --
|
3 |
|
|
*
|
4 |
|
|
* This module implements table widgets for the Tk
|
5 |
|
|
* toolkit. An table displays a 2D array of strings
|
6 |
|
|
* and allows the strings to be edited.
|
7 |
|
|
*
|
8 |
|
|
* Based on Tk3 table widget written by Roland King
|
9 |
|
|
*
|
10 |
|
|
* Updates 1996 by:
|
11 |
|
|
* Jeffrey Hobbs jeff.hobbs@acm.org
|
12 |
|
|
* John Ellson ellson@lucent.com
|
13 |
|
|
* Peter Bruecker peter@bj-ig.de
|
14 |
|
|
* Tom Moore tmoore@spatial.ca
|
15 |
|
|
* Sebastian Wangnick wangnick@orthogon.de
|
16 |
|
|
*
|
17 |
|
|
* Copyright (c) 1997-1998 Jeffrey Hobbs
|
18 |
|
|
*
|
19 |
|
|
* See the file "license.terms" for information on usage and redistribution
|
20 |
|
|
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
21 |
|
|
*
|
22 |
|
|
*/
|
23 |
|
|
|
24 |
|
|
#include "tkTable.h"
|
25 |
|
|
#ifdef DEBUG
|
26 |
|
|
#include "../../dprint.h"
|
27 |
|
|
#endif
|
28 |
|
|
|
29 |
|
|
INLINE static void TableFlushCache _ANSI_ARGS_((Table *tablePtr));
|
30 |
|
|
static int TableClear _ANSI_ARGS_((register Table *tablePtr, int mode,
|
31 |
|
|
char *first, char *last));
|
32 |
|
|
INLINE static void TableGetGc _ANSI_ARGS_((Display *display, Drawable d,
|
33 |
|
|
TableTag *tagPtr, GC *tagGc));
|
34 |
|
|
static void TableRedrawHighlight _ANSI_ARGS_((Table *tablePtr));
|
35 |
|
|
static void TableDisplay _ANSI_ARGS_((ClientData clientdata));
|
36 |
|
|
static void TableFlashEvent _ANSI_ARGS_((ClientData clientdata));
|
37 |
|
|
static void TableAddFlash _ANSI_ARGS_((Table *tablePtr, int row, int col));
|
38 |
|
|
static void TableSetActiveIndex _ANSI_ARGS_((register Table *tablePtr));
|
39 |
|
|
static void TableGetActiveBuf _ANSI_ARGS_((register Table *tablePtr));
|
40 |
|
|
static char * TableVarProc _ANSI_ARGS_((ClientData clientData,
|
41 |
|
|
Tcl_Interp *interp, char *name, char *index,
|
42 |
|
|
int flags));
|
43 |
|
|
static void TableGeometryRequest _ANSI_ARGS_((Table *tablePtr));
|
44 |
|
|
static void TableAdjustActive _ANSI_ARGS_((register Table *tablePtr));
|
45 |
|
|
static void TableAdjustParams _ANSI_ARGS_((register Table *tablePtr));
|
46 |
|
|
static void TableCursorEvent _ANSI_ARGS_((ClientData clientData));
|
47 |
|
|
static void TableConfigCursor _ANSI_ARGS_((register Table *tablePtr));
|
48 |
|
|
static int TableFetchSelection _ANSI_ARGS_((ClientData clientData,
|
49 |
|
|
int offset, char *buffer, int maxBytes));
|
50 |
|
|
static void TableLostSelection _ANSI_ARGS_((ClientData clientData));
|
51 |
|
|
static Tk_RestrictAction TableRestrictProc _ANSI_ARGS_((ClientData arg,
|
52 |
|
|
XEvent *eventPtr));
|
53 |
|
|
static int TableValidateChange _ANSI_ARGS_((Table *tablePtr, int r,
|
54 |
|
|
int c, char *old, char *new, int index));
|
55 |
|
|
static void TableDeleteChars _ANSI_ARGS_((register Table *tablePtr,
|
56 |
|
|
int index, int count));
|
57 |
|
|
static void TableInsertChars _ANSI_ARGS_((register Table *tablePtr,
|
58 |
|
|
int index, char *string));
|
59 |
|
|
static int TableWidgetCmd _ANSI_ARGS_((ClientData clientData,
|
60 |
|
|
Tcl_Interp *interp, int argc, char **argv));
|
61 |
|
|
static void TableDestroy _ANSI_ARGS_((ClientData clientdata));
|
62 |
|
|
static void TableEventProc _ANSI_ARGS_((ClientData clientData,
|
63 |
|
|
XEvent *eventPtr));
|
64 |
|
|
static int TableConfigure _ANSI_ARGS_((Tcl_Interp *interp,
|
65 |
|
|
Table *tablePtr, int argc, char **argv,
|
66 |
|
|
int flags, int forceUpdate));
|
67 |
|
|
static void TableCmdDeletedProc _ANSI_ARGS_((ClientData clientData));
|
68 |
|
|
static int TableCmd _ANSI_ARGS_((ClientData clientData,
|
69 |
|
|
Tcl_Interp *interp, int argc, char **argv));
|
70 |
|
|
|
71 |
|
|
/*
|
72 |
|
|
* The list of command values for all the widget commands
|
73 |
|
|
* We could use enum for many of these #defines, but it adds
|
74 |
|
|
* just that much more code size...
|
75 |
|
|
*/
|
76 |
|
|
#define CMD_ACTIVATE 1 /* activate command a la listbox */
|
77 |
|
|
#define CMD_BBOX 3 /* bounding box of cell <index> */
|
78 |
|
|
#define CMD_BORDER 5 /* border movement function */
|
79 |
|
|
#define CMD_CGET 7 /* basic cget widget command */
|
80 |
|
|
#define CMD_CLEAR 8 /* clear state command */
|
81 |
|
|
#define CMD_CONFIGURE 9 /* general configure command */
|
82 |
|
|
#define CMD_CURSELECTION 11 /* get current selected cell(s) */
|
83 |
|
|
#define CMD_CURVALUE 13 /* get current selection buffer */
|
84 |
|
|
#define CMD_DELETE 15 /* delete text in the selection */
|
85 |
|
|
#define CMD_FLUSH 17 /* flush the table cache */
|
86 |
|
|
#define CMD_GET 19 /* get mode a la listbox */
|
87 |
|
|
#define CMD_HEIGHT 21 /* (re)set row heights */
|
88 |
|
|
#define CMD_ICURSOR 23 /* set the insertion cursor */
|
89 |
|
|
#define CMD_INDEX 25 /* get an index */
|
90 |
|
|
#define CMD_INSERT 27 /* insert text at any position */
|
91 |
|
|
#define CMD_REREAD 31 /* reread the current selection */
|
92 |
|
|
#define CMD_SCAN 33 /* scan command a la listbox */
|
93 |
|
|
#define CMD_SEE 35 /* see command a la listbox */
|
94 |
|
|
#define CMD_SELECTION 37 /* selection command a la listbox */
|
95 |
|
|
#define CMD_SET 39 /* set command, to set multiple items */
|
96 |
|
|
#define CMD_TAG 41 /* tag command menu */
|
97 |
|
|
#define CMD_VALIDATE 43 /* validate contents of active cell */
|
98 |
|
|
#define CMD_VERSION 45 /* hidden command to return version */
|
99 |
|
|
#define CMD_WIDTH 47 /* (re)set column widths */
|
100 |
|
|
#define CMD_WINDOW 49 /* manage embedded windows */
|
101 |
|
|
#define CMD_XVIEW 51 /* change x view of widget (for scrollbars) */
|
102 |
|
|
#define CMD_YVIEW 53 /* change y view of widget (for scrollbars) */
|
103 |
|
|
|
104 |
|
|
/* The list of commands for the command parser */
|
105 |
|
|
|
106 |
|
|
static Cmd_Struct main_cmds[] = {
|
107 |
|
|
{"activate", CMD_ACTIVATE},
|
108 |
|
|
{"bbox", CMD_BBOX},
|
109 |
|
|
{"border", CMD_BORDER},
|
110 |
|
|
{"cget", CMD_CGET},
|
111 |
|
|
{"clear", CMD_CLEAR},
|
112 |
|
|
{"configure", CMD_CONFIGURE},
|
113 |
|
|
{"curselection", CMD_CURSELECTION},
|
114 |
|
|
{"curvalue", CMD_CURVALUE},
|
115 |
|
|
{"delete", CMD_DELETE},
|
116 |
|
|
{"flush", CMD_FLUSH},
|
117 |
|
|
{"get", CMD_GET},
|
118 |
|
|
{"height", CMD_HEIGHT},
|
119 |
|
|
{"icursor", CMD_ICURSOR},
|
120 |
|
|
{"index", CMD_INDEX},
|
121 |
|
|
{"insert", CMD_INSERT},
|
122 |
|
|
{"reread", CMD_REREAD},
|
123 |
|
|
{"scan", CMD_SCAN},
|
124 |
|
|
{"see", CMD_SEE},
|
125 |
|
|
{"selection", CMD_SELECTION},
|
126 |
|
|
{"set", CMD_SET},
|
127 |
|
|
{"tag", CMD_TAG},
|
128 |
|
|
{"validate", CMD_VALIDATE},
|
129 |
|
|
{"version", CMD_VERSION},
|
130 |
|
|
{"window", CMD_WINDOW},
|
131 |
|
|
{"width", CMD_WIDTH},
|
132 |
|
|
{"xview", CMD_XVIEW},
|
133 |
|
|
{"yview", CMD_YVIEW},
|
134 |
|
|
{"", 0}
|
135 |
|
|
};
|
136 |
|
|
|
137 |
|
|
/* selection subcommands */
|
138 |
|
|
#define SEL_ANCHOR 1 /* set selection anchor */
|
139 |
|
|
#define SEL_CLEAR 2 /* clear list from selection */
|
140 |
|
|
#define SEL_INCLUDES 3 /* query items inclusion in selection */
|
141 |
|
|
#define SEL_SET 4 /* include items in selection */
|
142 |
|
|
|
143 |
|
|
static Cmd_Struct sel_cmds[]= {
|
144 |
|
|
{"anchor", SEL_ANCHOR},
|
145 |
|
|
{"clear", SEL_CLEAR},
|
146 |
|
|
{"includes", SEL_INCLUDES},
|
147 |
|
|
{"set", SEL_SET},
|
148 |
|
|
{"", 0 }
|
149 |
|
|
};
|
150 |
|
|
|
151 |
|
|
/* -selecttype selection type options */
|
152 |
|
|
/* These alter how the selection set/clear commands behave */
|
153 |
|
|
#define SEL_ROW (1<<0)
|
154 |
|
|
#define SEL_COL (1<<1)
|
155 |
|
|
#define SEL_BOTH (1<<2)
|
156 |
|
|
#define SEL_CELL (1<<3)
|
157 |
|
|
#define SEL_NONE (1<<4)
|
158 |
|
|
|
159 |
|
|
static Cmd_Struct sel_vals[]= {
|
160 |
|
|
{"row", SEL_ROW},
|
161 |
|
|
{"col", SEL_COL},
|
162 |
|
|
{"both", SEL_BOTH},
|
163 |
|
|
{"cell", SEL_CELL},
|
164 |
|
|
{"", 0 }
|
165 |
|
|
};
|
166 |
|
|
|
167 |
|
|
/* clear subcommands */
|
168 |
|
|
#define CLEAR_TAGS (1<<0)
|
169 |
|
|
#define CLEAR_SIZES (1<<1)
|
170 |
|
|
#define CLEAR_CACHE (1<<2)
|
171 |
|
|
static Cmd_Struct clear_cmds[] = {
|
172 |
|
|
{"tags", CLEAR_TAGS},
|
173 |
|
|
{"sizes", CLEAR_SIZES},
|
174 |
|
|
{"cache", CLEAR_CACHE},
|
175 |
|
|
{"all", CLEAR_TAGS | CLEAR_SIZES | CLEAR_CACHE},
|
176 |
|
|
{"", 0}
|
177 |
|
|
};
|
178 |
|
|
|
179 |
|
|
/* -resizeborders options */
|
180 |
|
|
static Cmd_Struct resize_vals[]= {
|
181 |
|
|
{"row", SEL_ROW}, /* allow rows to be dragged */
|
182 |
|
|
{"col", SEL_COL}, /* allow cols to be dragged */
|
183 |
|
|
{"both", SEL_ROW|SEL_COL}, /* allow either to be dragged */
|
184 |
|
|
{"none", SEL_NONE}, /* allow nothing to be dragged */
|
185 |
|
|
{"", 0 }
|
186 |
|
|
};
|
187 |
|
|
|
188 |
|
|
/* insert/delete subcommands */
|
189 |
|
|
#define MOD_ACTIVE 1
|
190 |
|
|
#define MOD_COLS 2
|
191 |
|
|
#define MOD_ROWS 3
|
192 |
|
|
static Cmd_Struct mod_cmds[] = {
|
193 |
|
|
{"active", MOD_ACTIVE},
|
194 |
|
|
{"cols", MOD_COLS},
|
195 |
|
|
{"rows", MOD_ROWS},
|
196 |
|
|
{"", 0}
|
197 |
|
|
};
|
198 |
|
|
|
199 |
|
|
/* border subcommands */
|
200 |
|
|
#define BD_MARK 1
|
201 |
|
|
#define BD_DRAGTO 2
|
202 |
|
|
static Cmd_Struct bd_cmds[] = {
|
203 |
|
|
{"mark", BD_MARK},
|
204 |
|
|
{"dragto", BD_DRAGTO},
|
205 |
|
|
{"", 0}
|
206 |
|
|
};
|
207 |
|
|
|
208 |
|
|
/* drawmode values */
|
209 |
|
|
/* The display redraws with a pixmap using TK function calls */
|
210 |
|
|
#define DRAW_MODE_SLOW (1<<0)
|
211 |
|
|
/* The redisplay is direct to the screen, but TK function calls are still
|
212 |
|
|
* used to give correct 3-d border appearance and thus remain compatible
|
213 |
|
|
* with other TK apps */
|
214 |
|
|
#define DRAW_MODE_TK_COMPAT (1<<1)
|
215 |
|
|
/* the redisplay goes straight to the screen and the 3d borders are rendered
|
216 |
|
|
* with a single pixel wide line only. It cheats and uses the internal
|
217 |
|
|
* border structure to do the borders */
|
218 |
|
|
#define DRAW_MODE_FAST (1<<2)
|
219 |
|
|
#define DRAW_MODE_SINGLE (1<<3)
|
220 |
|
|
|
221 |
|
|
static Cmd_Struct drawmode_vals[] = {
|
222 |
|
|
{"fast", DRAW_MODE_FAST},
|
223 |
|
|
{"compatible", DRAW_MODE_TK_COMPAT},
|
224 |
|
|
{"slow", DRAW_MODE_SLOW},
|
225 |
|
|
{"single", DRAW_MODE_SINGLE},
|
226 |
|
|
{"", 0}
|
227 |
|
|
};
|
228 |
|
|
|
229 |
|
|
/* stretchmode values */
|
230 |
|
|
#define STRETCH_MODE_NONE (1<<0) /* No additional pixels will be
|
231 |
|
|
added to rows or cols */
|
232 |
|
|
#define STRETCH_MODE_UNSET (1<<1) /* All default rows or columns will
|
233 |
|
|
be stretched to fill the screen */
|
234 |
|
|
#define STRETCH_MODE_ALL (1<<2) /* All rows/columns will be padded
|
235 |
|
|
to fill the window */
|
236 |
|
|
#define STRETCH_MODE_LAST (1<<3) /* Stretch last elememt to fill
|
237 |
|
|
window */
|
238 |
|
|
#define STRETCH_MODE_FILL (1<<4) /* More ROWS in Window */
|
239 |
|
|
|
240 |
|
|
static Cmd_Struct stretch_vals[] = {
|
241 |
|
|
{"none", STRETCH_MODE_NONE},
|
242 |
|
|
{"unset", STRETCH_MODE_UNSET},
|
243 |
|
|
{"all", STRETCH_MODE_ALL},
|
244 |
|
|
{"last", STRETCH_MODE_LAST},
|
245 |
|
|
{"fill", STRETCH_MODE_FILL},
|
246 |
|
|
{"", 0}
|
247 |
|
|
};
|
248 |
|
|
|
249 |
|
|
static Cmd_Struct state_vals[]= {
|
250 |
|
|
{"normal", STATE_NORMAL},
|
251 |
|
|
{"disabled", STATE_DISABLED},
|
252 |
|
|
{"", 0 }
|
253 |
|
|
};
|
254 |
|
|
|
255 |
|
|
/* The widget configuration table */
|
256 |
|
|
static Tk_CustomOption drawOpt = { Cmd_OptionSet, Cmd_OptionGet,
|
257 |
|
|
(ClientData)(&drawmode_vals) };
|
258 |
|
|
static Tk_CustomOption resizeTypeOpt = { Cmd_OptionSet, Cmd_OptionGet,
|
259 |
|
|
(ClientData)(&resize_vals) };
|
260 |
|
|
static Tk_CustomOption stretchOpt = { Cmd_OptionSet, Cmd_OptionGet,
|
261 |
|
|
(ClientData)(&stretch_vals) };
|
262 |
|
|
static Tk_CustomOption selTypeOpt = { Cmd_OptionSet, Cmd_OptionGet,
|
263 |
|
|
(ClientData)(&sel_vals) };
|
264 |
|
|
static Tk_CustomOption stateTypeOpt = { Cmd_OptionSet, Cmd_OptionGet,
|
265 |
|
|
(ClientData)(&state_vals) };
|
266 |
|
|
|
267 |
|
|
static Tk_ConfigSpec TableConfig[] = {
|
268 |
|
|
{TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", "center",
|
269 |
|
|
Tk_Offset(Table, defaultTag.anchor), 0 },
|
270 |
|
|
{TK_CONFIG_BOOLEAN, "-autoclear", "autoClear", "AutoClear", "0",
|
271 |
|
|
Tk_Offset(Table, autoClear), 0 },
|
272 |
|
|
{TK_CONFIG_BORDER, "-background", "background", "Background", NORMAL_BG,
|
273 |
|
|
Tk_Offset(Table, defaultTag.bg), 0 },
|
274 |
|
|
{TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, (char *) NULL, 0, 0},
|
275 |
|
|
{TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *) NULL, 0, 0},
|
276 |
|
|
{TK_CONFIG_CURSOR, "-bordercursor", "borderCursor", "Cursor", "crosshair",
|
277 |
|
|
Tk_Offset(Table, bdcursor), TK_CONFIG_NULL_OK },
|
278 |
|
|
{TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", "1",
|
279 |
|
|
Tk_Offset(Table, borderWidth), 0 },
|
280 |
|
|
{TK_CONFIG_STRING, "-browsecommand", "browseCommand", "BrowseCommand", "",
|
281 |
|
|
Tk_Offset(Table, browseCmd), TK_CONFIG_NULL_OK},
|
282 |
|
|
{TK_CONFIG_SYNONYM, "-browsecmd", "browseCommand", (char *) NULL,
|
283 |
|
|
(char *) NULL, 0, TK_CONFIG_NULL_OK},
|
284 |
|
|
{TK_CONFIG_BOOLEAN, "-cache", "cache", "Cache", "0",
|
285 |
|
|
Tk_Offset(Table, caching), 0},
|
286 |
|
|
{TK_CONFIG_INT, "-colorigin", "colOrigin", "Origin", "0",
|
287 |
|
|
Tk_Offset(Table, colOffset), 0 },
|
288 |
|
|
{TK_CONFIG_INT, "-cols", "cols", "Cols", "10",
|
289 |
|
|
Tk_Offset(Table, cols), 0 },
|
290 |
|
|
{TK_CONFIG_STRING, "-colseparator", "colSeparator", "Separator", NULL,
|
291 |
|
|
Tk_Offset(Table, colSep), TK_CONFIG_NULL_OK },
|
292 |
|
|
{TK_CONFIG_CUSTOM, "-colstretchmode", "colStretch", "StretchMode", "none",
|
293 |
|
|
Tk_Offset (Table, colStretch), 0 , &stretchOpt },
|
294 |
|
|
{TK_CONFIG_STRING, "-coltagcommand", "colTagCommand", "TagCommand", NULL,
|
295 |
|
|
Tk_Offset(Table, colTagCmd), TK_CONFIG_NULL_OK },
|
296 |
|
|
{TK_CONFIG_INT, "-colwidth", "colWidth", "ColWidth", "10",
|
297 |
|
|
Tk_Offset(Table, defColWidth), 0 },
|
298 |
|
|
{TK_CONFIG_STRING, "-command", "command", "Command", "",
|
299 |
|
|
Tk_Offset(Table, command), TK_CONFIG_NULL_OK},
|
300 |
|
|
{TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", "xterm",
|
301 |
|
|
Tk_Offset(Table, cursor), TK_CONFIG_NULL_OK },
|
302 |
|
|
{TK_CONFIG_CUSTOM, "-drawmode", "drawMode", "DrawMode", "compatible",
|
303 |
|
|
Tk_Offset(Table, drawMode), 0, &drawOpt },
|
304 |
|
|
{TK_CONFIG_BOOLEAN, "-exportselection", "exportSelection",
|
305 |
|
|
"ExportSelection", "1", Tk_Offset(Table, exportSelection), 0},
|
306 |
|
|
{TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, (char *) NULL, 0, 0},
|
307 |
|
|
{TK_CONFIG_BOOLEAN, "-flashmode", "flashMode", "FlashMode", "0",
|
308 |
|
|
Tk_Offset(Table, flashMode), 0 },
|
309 |
|
|
{TK_CONFIG_INT, "-flashtime", "flashTime", "FlashTime", "2",
|
310 |
|
|
Tk_Offset(Table, flashTime), 0 },
|
311 |
|
|
{TK_CONFIG_FONT, "-font", "font", "Font", DEF_TABLE_FONT,
|
312 |
|
|
Tk_Offset(Table, defaultTag.tkfont), 0 },
|
313 |
|
|
{TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground", "black",
|
314 |
|
|
Tk_Offset(Table, defaultTag.fg), 0 },
|
315 |
|
|
{TK_CONFIG_INT, "-height", "height", "Height", "0",
|
316 |
|
|
Tk_Offset(Table, maxReqRows), 0 },
|
317 |
|
|
{TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
|
318 |
|
|
"HighlightBackground", NORMAL_BG, Tk_Offset(Table, highlightBgColorPtr), 0},
|
319 |
|
|
{TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
|
320 |
|
|
HIGHLIGHT, Tk_Offset(Table, highlightColorPtr), 0 },
|
321 |
|
|
{TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
|
322 |
|
|
"HighlightThickness", "2", Tk_Offset(Table, highlightWidth), 0 },
|
323 |
|
|
{TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground",
|
324 |
|
|
"Black", Tk_Offset(Table, insertBg), 0 },
|
325 |
|
|
{TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
|
326 |
|
|
"0", Tk_Offset(Table, insertBorderWidth), TK_CONFIG_COLOR_ONLY},
|
327 |
|
|
{TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
|
328 |
|
|
"0", Tk_Offset(Table, insertBorderWidth), TK_CONFIG_MONO_ONLY},
|
329 |
|
|
{TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime", "300",
|
330 |
|
|
Tk_Offset(Table, insertOffTime), 0},
|
331 |
|
|
{TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime", "600",
|
332 |
|
|
Tk_Offset(Table, insertOnTime), 0},
|
333 |
|
|
{TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth", "2",
|
334 |
|
|
Tk_Offset(Table, insertWidth), 0},
|
335 |
|
|
{TK_CONFIG_BOOLEAN, "-invertselected", "invertSelected", "InvertSelected",
|
336 |
|
|
"0", Tk_Offset(Table, invertSelected), 0},
|
337 |
|
|
{TK_CONFIG_PIXELS, "-maxheight", "maxHeight", "MaxHeight", "600",
|
338 |
|
|
Tk_Offset(Table, maxReqHeight), 0 },
|
339 |
|
|
{TK_CONFIG_PIXELS, "-maxwidth", "maxWidth", "MaxWidth", "800",
|
340 |
|
|
Tk_Offset(Table, maxReqWidth), 0 },
|
341 |
|
|
{TK_CONFIG_BOOLEAN, "-multiline", "multiline", "Multiline", "1",
|
342 |
|
|
Tk_Offset(Table, defaultTag.multiline), 0 },
|
343 |
|
|
{TK_CONFIG_PIXELS, "-padx", "padX", "Pad", "2", Tk_Offset(Table, padX), 0},
|
344 |
|
|
{TK_CONFIG_PIXELS, "-pady", "padY", "Pad", "1", Tk_Offset(Table, padY), 0},
|
345 |
|
|
{TK_CONFIG_RELIEF, "-relief", "relief", "Relief", "sunken",
|
346 |
|
|
Tk_Offset(Table, defaultTag.relief), 0 },
|
347 |
|
|
{TK_CONFIG_CUSTOM, "-resizeborders", "resizeBorders", "ResizeBorders",
|
348 |
|
|
"both", Tk_Offset(Table, resize), 0, &resizeTypeOpt },
|
349 |
|
|
{TK_CONFIG_PIXELS, "-rowheight", "rowHeight", "RowHeight", "1",
|
350 |
|
|
Tk_Offset(Table, defRowHeight), 0 },
|
351 |
|
|
{TK_CONFIG_INT, "-roworigin", "rowOrigin", "Origin", "0",
|
352 |
|
|
Tk_Offset(Table, rowOffset), 0 },
|
353 |
|
|
{TK_CONFIG_INT, "-rows", "rows", "Rows", "10", Tk_Offset(Table, rows), 0 },
|
354 |
|
|
{TK_CONFIG_STRING, "-rowseparator", "rowSeparator", "Separator", NULL,
|
355 |
|
|
Tk_Offset(Table, rowSep), TK_CONFIG_NULL_OK },
|
356 |
|
|
{TK_CONFIG_CUSTOM, "-rowstretchmode", "rowStretch", "StretchMode", "none",
|
357 |
|
|
Tk_Offset(Table, rowStretch), 0 , &stretchOpt },
|
358 |
|
|
{TK_CONFIG_STRING, "-rowtagcommand", "rowTagCommand", "TagCommand", NULL,
|
359 |
|
|
Tk_Offset(Table, rowTagCmd), TK_CONFIG_NULL_OK },
|
360 |
|
|
{TK_CONFIG_SYNONYM, "-selcmd", "selectionCommand", (char *) NULL,
|
361 |
|
|
(char *) NULL, 0, TK_CONFIG_NULL_OK},
|
362 |
|
|
{TK_CONFIG_STRING, "-selectioncommand", "selectionCommand",
|
363 |
|
|
"SelectionCommand", NULL, Tk_Offset(Table, selCmd), TK_CONFIG_NULL_OK },
|
364 |
|
|
{TK_CONFIG_STRING, "-selectmode", "selectMode", "SelectMode", "browse",
|
365 |
|
|
Tk_Offset(Table, selectMode), TK_CONFIG_NULL_OK },
|
366 |
|
|
{TK_CONFIG_BOOLEAN, "-selecttitles", "selectTitles", "SelectTitles", "0",
|
367 |
|
|
Tk_Offset(Table, selectTitles), 0 },
|
368 |
|
|
{TK_CONFIG_CUSTOM, "-selecttype", "selectType", "SelectType", "cell",
|
369 |
|
|
Tk_Offset(Table, selectType), 0, &selTypeOpt },
|
370 |
|
|
{TK_CONFIG_CUSTOM, "-state", "state", "State", "normal",
|
371 |
|
|
Tk_Offset(Table, state), 0, &stateTypeOpt},
|
372 |
|
|
{TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", (char *) NULL,
|
373 |
|
|
Tk_Offset(Table, takeFocus), TK_CONFIG_NULL_OK },
|
374 |
|
|
{TK_CONFIG_INT, "-titlecols", "titleCols", "TitleCols", "0",
|
375 |
|
|
Tk_Offset(Table, titleCols), TK_CONFIG_NULL_OK },
|
376 |
|
|
{TK_CONFIG_INT, "-titlerows", "titleRows", "TitleRows", "0",
|
377 |
|
|
Tk_Offset(Table, titleRows), TK_CONFIG_NULL_OK },
|
378 |
|
|
{TK_CONFIG_BOOLEAN, "-usecommand", "useCommand", "UseCommand", "1",
|
379 |
|
|
Tk_Offset(Table, useCmd), 0},
|
380 |
|
|
{TK_CONFIG_STRING, "-variable", "variable", "Variable", (char *) NULL,
|
381 |
|
|
Tk_Offset(Table, arrayVar), TK_CONFIG_NULL_OK },
|
382 |
|
|
{TK_CONFIG_BOOLEAN, "-validate", "validate", "Validate", "0",
|
383 |
|
|
Tk_Offset(Table, validate), 0 },
|
384 |
|
|
{TK_CONFIG_STRING, "-validatecommand", "validateCommand", "ValidateCommand",
|
385 |
|
|
"", Tk_Offset(Table, valCmd), TK_CONFIG_NULL_OK},
|
386 |
|
|
{TK_CONFIG_SYNONYM, "-vcmd", "validateCommand", (char *) NULL,
|
387 |
|
|
(char *) NULL, 0, TK_CONFIG_NULL_OK},
|
388 |
|
|
{TK_CONFIG_INT, "-width", "width", "Width", "0",
|
389 |
|
|
Tk_Offset(Table, maxReqCols), 0 },
|
390 |
|
|
{TK_CONFIG_BOOLEAN, "-wrap", "wrap", "Wrap", "0",
|
391 |
|
|
Tk_Offset(Table, defaultTag.wrap), 0 },
|
392 |
|
|
{TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
|
393 |
|
|
NULL, Tk_Offset(Table, xScrollCmd), TK_CONFIG_NULL_OK },
|
394 |
|
|
{TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
|
395 |
|
|
NULL, Tk_Offset(Table, yScrollCmd), TK_CONFIG_NULL_OK },
|
396 |
|
|
{TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
|
397 |
|
|
(char *) NULL, 0, 0 }
|
398 |
|
|
};
|
399 |
|
|
|
400 |
|
|
/*
|
401 |
|
|
* This specifies the configure options that will cause an update to
|
402 |
|
|
* occur, so we should have a quick lookup table for them.
|
403 |
|
|
* Keep this in sync with the above values.
|
404 |
|
|
*/
|
405 |
|
|
static Cmd_Struct update_config[] = {
|
406 |
|
|
{"-anchor", 1}, {"-background", 1},
|
407 |
|
|
{"-bg", 1}, {"-bd", 1},
|
408 |
|
|
{"-borderwidth", 1}, {"-cache", 1},
|
409 |
|
|
{"-command", 1}, {"-colorigin", 1},
|
410 |
|
|
{"-cols", 1}, {"-colstretchmode", 1},
|
411 |
|
|
{"-coltagcommand", 1}, {"-drawmode", 1},
|
412 |
|
|
{"-fg", 1}, {"-font", 1},
|
413 |
|
|
{"-foreground", 1},
|
414 |
|
|
{"-height", 1}, {"-highlightbackground", 1},
|
415 |
|
|
{"-highlightcolor", 1}, {"-highlightthickness", 1},
|
416 |
|
|
{"-insertbackground", 1}, {"-insertborderwidth", 1},
|
417 |
|
|
{"-insertwidth", 1}, {"-invertselected", 1},
|
418 |
|
|
{"-maxheight", 1}, {"-maxwidth", 1},
|
419 |
|
|
{"-multiline", 1},
|
420 |
|
|
{"-padx", 1}, {"-pady", 1},
|
421 |
|
|
{"-relief", 1}, {"-roworigin", 1},
|
422 |
|
|
{"-rows", 1}, {"-rowstretchmode", 1},
|
423 |
|
|
{"-rowtagcommand", 1}, {"-state", 1},
|
424 |
|
|
{"-titlecols", 1}, {"-titlerows", 1},
|
425 |
|
|
{"-usecommand", 1}, {"-variable", 1},
|
426 |
|
|
{"-width", 1}, {"-wrap", 1},
|
427 |
|
|
{"-xscrollcommand", 1}, {"-yscrollcommand", 1},
|
428 |
|
|
{"", 0},
|
429 |
|
|
};
|
430 |
|
|
|
431 |
|
|
/*
|
432 |
|
|
* END HEADER INFORMATION
|
433 |
|
|
*/
|
434 |
|
|
|
435 |
|
|
/*
|
436 |
|
|
*----------------------------------------------------------------------
|
437 |
|
|
*
|
438 |
|
|
* TableFlushCache --
|
439 |
|
|
* Flushes the internal cache of the table.
|
440 |
|
|
*
|
441 |
|
|
* Results:
|
442 |
|
|
* None.
|
443 |
|
|
*
|
444 |
|
|
* Side effects:
|
445 |
|
|
* None.
|
446 |
|
|
*
|
447 |
|
|
*----------------------------------------------------------------------
|
448 |
|
|
*/
|
449 |
|
|
INLINE static void
|
450 |
|
|
TableFlushCache(register Table *tablePtr)
|
451 |
|
|
{
|
452 |
|
|
/* Just get rid of it and reinit it */
|
453 |
|
|
Tcl_DeleteHashTable(tablePtr->cache);
|
454 |
|
|
ckfree((char *) (tablePtr->cache));
|
455 |
|
|
tablePtr->cache = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
|
456 |
|
|
Tcl_InitHashTable(tablePtr->cache, TCL_STRING_KEYS);
|
457 |
|
|
}
|
458 |
|
|
|
459 |
|
|
|
460 |
|
|
|
461 |
|
|
/*
|
462 |
|
|
*----------------------------------------------------------------------
|
463 |
|
|
*
|
464 |
|
|
* TableRefresh --
|
465 |
|
|
* Refreshes an area of the table based on the mode.
|
466 |
|
|
* row,col in real coords (0-based)
|
467 |
|
|
*
|
468 |
|
|
* Results:
|
469 |
|
|
* Will cause redraw for visible cells
|
470 |
|
|
*
|
471 |
|
|
* Side effects:
|
472 |
|
|
* None.
|
473 |
|
|
*
|
474 |
|
|
*----------------------------------------------------------------------
|
475 |
|
|
*/
|
476 |
|
|
void
|
477 |
|
|
TableRefresh(register Table *tablePtr, int row, int col, int mode)
|
478 |
|
|
{
|
479 |
|
|
int x, y, w, h;
|
480 |
|
|
|
481 |
|
|
if (mode & CELL) {
|
482 |
|
|
if (TableCellVCoords(tablePtr, row, col, &x, &y, &w, &h, 0)) {
|
483 |
|
|
TableInvalidate(tablePtr, x, y, w, h, mode);
|
484 |
|
|
}
|
485 |
|
|
} else if (mode & ROW) {
|
486 |
|
|
/* get the position of the leftmost cell in the row */
|
487 |
|
|
if ((mode & INV_FILL) && row < tablePtr->topRow) {
|
488 |
|
|
/* Invalidate whole table */
|
489 |
|
|
TableInvalidateAll(tablePtr, mode);
|
490 |
|
|
} else if (TableCellVCoords(tablePtr, row, tablePtr->leftCol,
|
491 |
|
|
&x, &y, &w, &h, 0)) {
|
492 |
|
|
/* Invalidate from this row, maybe to end */
|
493 |
|
|
TableInvalidate(tablePtr, 0, y, Tk_Width(tablePtr->tkwin),
|
494 |
|
|
(mode&INV_FILL)?Tk_Height(tablePtr->tkwin):h, mode);
|
495 |
|
|
}
|
496 |
|
|
} else if (mode & COL) {
|
497 |
|
|
/* get the position of the topmost cell on the column */
|
498 |
|
|
if ((mode & INV_FILL) && col < tablePtr->leftCol) {
|
499 |
|
|
/* Invalidate whole table */
|
500 |
|
|
TableInvalidateAll(tablePtr, mode);
|
501 |
|
|
} else if (TableCellVCoords(tablePtr, tablePtr->topRow, col,
|
502 |
|
|
&x, &y, &w, &h, 0)) {
|
503 |
|
|
/* Invalidate from this column, maybe to end */
|
504 |
|
|
TableInvalidate(tablePtr, x, 0,
|
505 |
|
|
(mode&INV_FILL)?Tk_Width(tablePtr->tkwin):w,
|
506 |
|
|
Tk_Height(tablePtr->tkwin), mode);
|
507 |
|
|
}
|
508 |
|
|
}
|
509 |
|
|
}
|
510 |
|
|
|
511 |
|
|
/*
|
512 |
|
|
*----------------------------------------------------------------------
|
513 |
|
|
*
|
514 |
|
|
* TableClear --
|
515 |
|
|
* Clears state information about the table.
|
516 |
|
|
*
|
517 |
|
|
* Results:
|
518 |
|
|
* Cached info can be lost. Returns valid Tcl result.
|
519 |
|
|
*
|
520 |
|
|
* Side effects:
|
521 |
|
|
* Can cause redraw.
|
522 |
|
|
*
|
523 |
|
|
*----------------------------------------------------------------------
|
524 |
|
|
*/
|
525 |
|
|
static int
|
526 |
|
|
TableClear(register Table *tablePtr, int mode, char *first, char *last)
|
527 |
|
|
{
|
528 |
|
|
int redraw = 0;
|
529 |
|
|
|
530 |
|
|
if (mode == 0) return TCL_ERROR;
|
531 |
|
|
|
532 |
|
|
if (first == NULL) {
|
533 |
|
|
if (mode & CLEAR_TAGS) {
|
534 |
|
|
Tcl_DeleteHashTable(tablePtr->rowStyles);
|
535 |
|
|
Tcl_DeleteHashTable(tablePtr->colStyles);
|
536 |
|
|
Tcl_DeleteHashTable(tablePtr->cellStyles);
|
537 |
|
|
Tcl_DeleteHashTable(tablePtr->flashCells);
|
538 |
|
|
Tcl_DeleteHashTable(tablePtr->selCells);
|
539 |
|
|
|
540 |
|
|
/* style hash tables */
|
541 |
|
|
Tcl_InitHashTable(tablePtr->rowStyles, TCL_ONE_WORD_KEYS);
|
542 |
|
|
Tcl_InitHashTable(tablePtr->colStyles, TCL_ONE_WORD_KEYS);
|
543 |
|
|
Tcl_InitHashTable(tablePtr->cellStyles, TCL_STRING_KEYS);
|
544 |
|
|
|
545 |
|
|
/* special style hash tables */
|
546 |
|
|
Tcl_InitHashTable(tablePtr->flashCells, TCL_STRING_KEYS);
|
547 |
|
|
Tcl_InitHashTable(tablePtr->selCells, TCL_STRING_KEYS);
|
548 |
|
|
}
|
549 |
|
|
|
550 |
|
|
if (mode & CLEAR_SIZES) {
|
551 |
|
|
Tcl_DeleteHashTable(tablePtr->colWidths);
|
552 |
|
|
Tcl_DeleteHashTable(tablePtr->rowHeights);
|
553 |
|
|
|
554 |
|
|
/* style hash tables */
|
555 |
|
|
Tcl_InitHashTable(tablePtr->colWidths, TCL_ONE_WORD_KEYS);
|
556 |
|
|
Tcl_InitHashTable(tablePtr->rowHeights, TCL_ONE_WORD_KEYS);
|
557 |
|
|
}
|
558 |
|
|
|
559 |
|
|
if (mode & CLEAR_CACHE) {
|
560 |
|
|
TableFlushCache(tablePtr);
|
561 |
|
|
/* If we were caching and we have no other data source,
|
562 |
|
|
* invalidate all the cells */
|
563 |
|
|
if (tablePtr->dataSource == DATA_CACHE) {
|
564 |
|
|
TableGetActiveBuf(tablePtr);
|
565 |
|
|
}
|
566 |
|
|
}
|
567 |
|
|
redraw = 1;
|
568 |
|
|
} else {
|
569 |
|
|
int row, col, r1, r2, c1, c2;
|
570 |
|
|
Tcl_HashEntry *entryPtr;
|
571 |
|
|
char buf[INDEX_BUFSIZE];
|
572 |
|
|
|
573 |
|
|
if (TableGetIndex(tablePtr, first, &row, &col) == TCL_ERROR ||
|
574 |
|
|
(last != NULL && TableGetIndex(tablePtr, last, &r2, &c2)==TCL_ERROR)) {
|
575 |
|
|
return TCL_ERROR;
|
576 |
|
|
}
|
577 |
|
|
if (last == NULL) {
|
578 |
|
|
r1 = r2 = row;
|
579 |
|
|
c1 = c2 = col;
|
580 |
|
|
} else {
|
581 |
|
|
r1 = MIN(row,r2); r2 = MAX(row,r2);
|
582 |
|
|
c1 = MIN(col,c2); c2 = MAX(col,c2);
|
583 |
|
|
}
|
584 |
|
|
for (row = r1; row <= r2; row++) {
|
585 |
|
|
/* Note that *Styles entries are user based (no offset)
|
586 |
|
|
* while size entries are 0-based (real) */
|
587 |
|
|
if ((mode & CLEAR_TAGS) &&
|
588 |
|
|
(entryPtr = Tcl_FindHashEntry(tablePtr->rowStyles, (char *) row))) {
|
589 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
590 |
|
|
redraw = 1;
|
591 |
|
|
}
|
592 |
|
|
|
593 |
|
|
if ((mode & CLEAR_SIZES) &&
|
594 |
|
|
(entryPtr = Tcl_FindHashEntry(tablePtr->rowHeights,
|
595 |
|
|
(char *) row-tablePtr->rowOffset))) {
|
596 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
597 |
|
|
redraw = 1;
|
598 |
|
|
}
|
599 |
|
|
|
600 |
|
|
for (col = c1; col <= c2; col++) {
|
601 |
|
|
TableMakeArrayIndex(row, col, buf);
|
602 |
|
|
|
603 |
|
|
if (mode & CLEAR_TAGS) {
|
604 |
|
|
if ((row == r1) && (entryPtr = Tcl_FindHashEntry(tablePtr->colStyles,
|
605 |
|
|
(char *) col))) {
|
606 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
607 |
|
|
redraw = 1;
|
608 |
|
|
}
|
609 |
|
|
if ((entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf))) {
|
610 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
611 |
|
|
redraw = 1;
|
612 |
|
|
}
|
613 |
|
|
if ((entryPtr = Tcl_FindHashEntry(tablePtr->flashCells, buf))) {
|
614 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
615 |
|
|
redraw = 1;
|
616 |
|
|
}
|
617 |
|
|
if ((entryPtr = Tcl_FindHashEntry(tablePtr->selCells, buf))) {
|
618 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
619 |
|
|
redraw = 1;
|
620 |
|
|
}
|
621 |
|
|
}
|
622 |
|
|
|
623 |
|
|
if ((mode & CLEAR_SIZES) && row == r1 &&
|
624 |
|
|
(entryPtr = Tcl_FindHashEntry(tablePtr->colWidths, (char *)
|
625 |
|
|
col-tablePtr->colOffset))) {
|
626 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
627 |
|
|
redraw = 1;
|
628 |
|
|
}
|
629 |
|
|
|
630 |
|
|
if ((mode & CLEAR_CACHE) &&
|
631 |
|
|
(entryPtr = Tcl_FindHashEntry(tablePtr->cache, buf))) {
|
632 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
633 |
|
|
/* if the cache is our data source,
|
634 |
|
|
* we need to invalidate the cells changed */
|
635 |
|
|
if ((tablePtr->dataSource == DATA_CACHE) &&
|
636 |
|
|
(row-tablePtr->rowOffset == tablePtr->activeRow &&
|
637 |
|
|
col-tablePtr->colOffset == tablePtr->activeCol))
|
638 |
|
|
TableGetActiveBuf(tablePtr);
|
639 |
|
|
redraw = 1;
|
640 |
|
|
}
|
641 |
|
|
}
|
642 |
|
|
}
|
643 |
|
|
}
|
644 |
|
|
/* This could be more sensitive about what it updates,
|
645 |
|
|
* but that can actually be a lot more costly in some cases */
|
646 |
|
|
if (redraw) {
|
647 |
|
|
if (mode & CLEAR_SIZES) {
|
648 |
|
|
TableAdjustParams(tablePtr);
|
649 |
|
|
/* rerequest geometry */
|
650 |
|
|
TableGeometryRequest(tablePtr);
|
651 |
|
|
}
|
652 |
|
|
TableInvalidateAll(tablePtr, 0);
|
653 |
|
|
}
|
654 |
|
|
return TCL_OK;
|
655 |
|
|
}
|
656 |
|
|
|
657 |
|
|
/*
|
658 |
|
|
*----------------------------------------------------------------------
|
659 |
|
|
*
|
660 |
|
|
* TableGetGc --
|
661 |
|
|
* Gets a GC corresponding to the tag structure passed.
|
662 |
|
|
*
|
663 |
|
|
* Results:
|
664 |
|
|
* Returns usable GC.
|
665 |
|
|
*
|
666 |
|
|
* Side effects:
|
667 |
|
|
* None
|
668 |
|
|
*
|
669 |
|
|
*----------------------------------------------------------------------
|
670 |
|
|
*/
|
671 |
|
|
INLINE static void
|
672 |
|
|
TableGetGc(Display *display, Drawable d, TableTag *tagPtr, GC *tagGc)
|
673 |
|
|
{
|
674 |
|
|
XGCValues gcValues;
|
675 |
|
|
gcValues.foreground = Tk_3DBorderColor(tagPtr->fg)->pixel;
|
676 |
|
|
gcValues.background = Tk_3DBorderColor(tagPtr->bg)->pixel;
|
677 |
|
|
gcValues.font = Tk_FontId(tagPtr->tkfont);
|
678 |
|
|
if (*tagGc == NULL) {
|
679 |
|
|
gcValues.graphics_exposures = False;
|
680 |
|
|
*tagGc = XCreateGC(display, d,
|
681 |
|
|
GCForeground|GCBackground|GCFont|GCGraphicsExposures,
|
682 |
|
|
&gcValues);
|
683 |
|
|
} else {
|
684 |
|
|
XChangeGC(display, *tagGc, GCForeground|GCBackground|GCFont, &gcValues);
|
685 |
|
|
}
|
686 |
|
|
}
|
687 |
|
|
|
688 |
|
|
#define TableFreeGc XFreeGC
|
689 |
|
|
|
690 |
|
|
/*
|
691 |
|
|
*----------------------------------------------------------------------
|
692 |
|
|
*
|
693 |
|
|
* TableRedrawHighlight --
|
694 |
|
|
* Redraws just the highlight for the window
|
695 |
|
|
*
|
696 |
|
|
* Results:
|
697 |
|
|
* None.
|
698 |
|
|
*
|
699 |
|
|
* Side effects:
|
700 |
|
|
* None
|
701 |
|
|
*
|
702 |
|
|
*----------------------------------------------------------------------
|
703 |
|
|
*/
|
704 |
|
|
INLINE static void
|
705 |
|
|
TableRedrawHighlight(Table *tablePtr)
|
706 |
|
|
{
|
707 |
|
|
if ((tablePtr->flags & REDRAW_BORDER) && tablePtr->highlightWidth > 0) {
|
708 |
|
|
GC gc = Tk_GCForColor((tablePtr->flags & HAS_FOCUS)
|
709 |
|
|
?(tablePtr->highlightColorPtr)
|
710 |
|
|
:(tablePtr->highlightBgColorPtr),
|
711 |
|
|
Tk_WindowId(tablePtr->tkwin));
|
712 |
|
|
Tk_DrawFocusHighlight(tablePtr->tkwin, gc, tablePtr->highlightWidth,
|
713 |
|
|
Tk_WindowId(tablePtr->tkwin));
|
714 |
|
|
}
|
715 |
|
|
tablePtr->flags &= ~REDRAW_BORDER;
|
716 |
|
|
}
|
717 |
|
|
|
718 |
|
|
/*
|
719 |
|
|
*--------------------------------------------------------------
|
720 |
|
|
*
|
721 |
|
|
* TableUndisplay --
|
722 |
|
|
* This procedure removes the contents of a table window
|
723 |
|
|
* that have been moved offscreen.
|
724 |
|
|
*
|
725 |
|
|
* Results:
|
726 |
|
|
* Embedded windows can be unmapped.
|
727 |
|
|
*
|
728 |
|
|
* Side effects:
|
729 |
|
|
* Information disappears from the screen.
|
730 |
|
|
*
|
731 |
|
|
*--------------------------------------------------------------
|
732 |
|
|
*/
|
733 |
|
|
static void
|
734 |
|
|
TableUndisplay(register Table *tablePtr)
|
735 |
|
|
{
|
736 |
|
|
register int *seen = tablePtr->seen;
|
737 |
|
|
int row, col;
|
738 |
|
|
|
739 |
|
|
TableGetLastCell(tablePtr, &row, &col);
|
740 |
|
|
if (seen[0] != -1) {
|
741 |
|
|
if (seen[0] < tablePtr->topRow) {
|
742 |
|
|
/* Remove now hidden rows */
|
743 |
|
|
EmbWinUnmap(tablePtr, seen[0], tablePtr->topRow-1, 0, seen[3]);
|
744 |
|
|
}
|
745 |
|
|
if (seen[1] < tablePtr->leftCol) {
|
746 |
|
|
/* Remove now hidden cols */
|
747 |
|
|
EmbWinUnmap(tablePtr, 0, seen[2], seen[1], tablePtr->leftCol-1);
|
748 |
|
|
}
|
749 |
|
|
if (seen[2] > row) {
|
750 |
|
|
/* Remove now off-screen rows */
|
751 |
|
|
EmbWinUnmap(tablePtr, row+1, seen[2], 0, seen[3]);
|
752 |
|
|
}
|
753 |
|
|
if (seen[3] > col) {
|
754 |
|
|
/* Remove now off-screen cols */
|
755 |
|
|
EmbWinUnmap(tablePtr, 0, seen[2], col+1, seen[3]);
|
756 |
|
|
}
|
757 |
|
|
}
|
758 |
|
|
seen[0] = tablePtr->topRow;
|
759 |
|
|
seen[1] = tablePtr->leftCol;
|
760 |
|
|
seen[2] = row;
|
761 |
|
|
seen[3] = col;
|
762 |
|
|
}
|
763 |
|
|
|
764 |
|
|
/*
|
765 |
|
|
*--------------------------------------------------------------
|
766 |
|
|
*
|
767 |
|
|
* TableDisplay --
|
768 |
|
|
* This procedure redraws the contents of a table window.
|
769 |
|
|
* The conditional code in this function is due to these factors:
|
770 |
|
|
* o Lack of XSetClipRectangles on Windows
|
771 |
|
|
*
|
772 |
|
|
* Results:
|
773 |
|
|
* None.
|
774 |
|
|
*
|
775 |
|
|
* Side effects:
|
776 |
|
|
* Information appears on the screen.
|
777 |
|
|
*
|
778 |
|
|
*--------------------------------------------------------------
|
779 |
|
|
*/
|
780 |
|
|
static void
|
781 |
|
|
TableDisplay(ClientData clientdata)
|
782 |
|
|
{
|
783 |
|
|
register Table *tablePtr = (Table *) clientdata;
|
784 |
|
|
Tk_Window tkwin = tablePtr->tkwin;
|
785 |
|
|
Display *display = tablePtr->display;
|
786 |
|
|
Drawable window;
|
787 |
|
|
#ifdef _WIN32
|
788 |
|
|
Drawable clipWind;
|
789 |
|
|
#else
|
790 |
|
|
XRectangle clipRect;
|
791 |
|
|
#endif
|
792 |
|
|
int rowFrom, rowTo, colFrom, colTo,
|
793 |
|
|
invalidX, invalidY, invalidWidth, invalidHeight,
|
794 |
|
|
x, y, width, height, itemX, itemY, itemW, itemH,
|
795 |
|
|
row, col, urow, ucol, cx, cy, cw, ch, bd,
|
796 |
|
|
numBytes, new, boundW, boundH, maxW, maxH,
|
797 |
|
|
originX, originY, activeCell, clipRectSet, shouldInvert;
|
798 |
|
|
GC tagGc = NULL, topGc, bottomGc;
|
799 |
|
|
char *string = NULL;
|
800 |
|
|
char buf[INDEX_BUFSIZE];
|
801 |
|
|
TableTag *tagPtr = NULL, *titlePtr, *selPtr, *activePtr, *flashPtr,
|
802 |
|
|
*rowPtr, *colPtr;
|
803 |
|
|
Tcl_HashEntry *entryPtr;
|
804 |
|
|
static XPoint rect[3] = { {0, 0}, {0, 0}, {0, 0} };
|
805 |
|
|
Tcl_HashTable *colTagsCache = NULL;
|
806 |
|
|
Tk_TextLayout textLayout = NULL;
|
807 |
|
|
TableEmbWindow *ewPtr;
|
808 |
|
|
|
809 |
|
|
if ((tablePtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
|
810 |
|
|
return;
|
811 |
|
|
}
|
812 |
|
|
tablePtr->flags &= ~REDRAW_PENDING;
|
813 |
|
|
|
814 |
|
|
bd = tablePtr->borderWidth;
|
815 |
|
|
boundW = Tk_Width(tkwin)-tablePtr->highlightWidth;
|
816 |
|
|
boundH = Tk_Height(tkwin)-tablePtr->highlightWidth;
|
817 |
|
|
|
818 |
|
|
/* Constrain drawable to not include highlight borders */
|
819 |
|
|
invalidX = MAX(tablePtr->highlightWidth, tablePtr->invalidX);
|
820 |
|
|
invalidY = MAX(tablePtr->highlightWidth, tablePtr->invalidY);
|
821 |
|
|
invalidWidth = MIN(tablePtr->invalidWidth, MAX(1, boundW-invalidX));
|
822 |
|
|
invalidHeight = MIN(tablePtr->invalidHeight, MAX(1, boundH-invalidY));
|
823 |
|
|
|
824 |
|
|
/*
|
825 |
|
|
* if we are using the slow drawing mode with a pixmap
|
826 |
|
|
* create the pixmap and adjust x && y for offset in pixmap
|
827 |
|
|
*/
|
828 |
|
|
if (tablePtr->drawMode == DRAW_MODE_SLOW) {
|
829 |
|
|
window = Tk_GetPixmap(display, Tk_WindowId(tkwin),
|
830 |
|
|
invalidWidth, invalidHeight, Tk_Depth(tkwin));
|
831 |
|
|
} else {
|
832 |
|
|
window = Tk_WindowId(tkwin);
|
833 |
|
|
}
|
834 |
|
|
#ifdef _WIN32
|
835 |
|
|
clipWind = Tk_GetPixmap(display, window,
|
836 |
|
|
invalidWidth, invalidHeight, Tk_Depth(tkwin));
|
837 |
|
|
#endif
|
838 |
|
|
|
839 |
|
|
/* set up the permanent tag styles */
|
840 |
|
|
entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, "title");
|
841 |
|
|
titlePtr = (TableTag *) Tcl_GetHashValue(entryPtr);
|
842 |
|
|
entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, "sel");
|
843 |
|
|
selPtr = (TableTag *) Tcl_GetHashValue(entryPtr);
|
844 |
|
|
entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, "active");
|
845 |
|
|
activePtr= (TableTag *) Tcl_GetHashValue(entryPtr);
|
846 |
|
|
entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, "flash");
|
847 |
|
|
flashPtr = (TableTag *) Tcl_GetHashValue(entryPtr);
|
848 |
|
|
|
849 |
|
|
/* find out the cells represented by the invalid region */
|
850 |
|
|
TableWhatCell(tablePtr, invalidX, invalidY, &rowFrom, &colFrom);
|
851 |
|
|
TableWhatCell(tablePtr, invalidX+invalidWidth-1,
|
852 |
|
|
invalidY+invalidHeight-1, &rowTo, &colTo);
|
853 |
|
|
|
854 |
|
|
#ifdef DEBUG
|
855 |
|
|
tcl_dprintf(tablePtr->interp, "display %d,%d => %d,%d",
|
856 |
|
|
rowFrom+tablePtr->rowOffset, colFrom+tablePtr->colOffset,
|
857 |
|
|
rowTo+tablePtr->rowOffset, colTo+tablePtr->colOffset);
|
858 |
|
|
#endif
|
859 |
|
|
|
860 |
|
|
/*
|
861 |
|
|
* Initialize colTagsCache hash table to cache column tag names.
|
862 |
|
|
*/
|
863 |
|
|
colTagsCache = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
|
864 |
|
|
Tcl_InitHashTable(colTagsCache, TCL_ONE_WORD_KEYS);
|
865 |
|
|
|
866 |
|
|
/* Cycle through the cells and display them */
|
867 |
|
|
for (row = rowFrom; row <= rowTo; row++) {
|
868 |
|
|
/*
|
869 |
|
|
* are we in the 'dead zone' between the
|
870 |
|
|
* title rows and the first displayed row
|
871 |
|
|
*/
|
872 |
|
|
if (row < tablePtr->topRow && row >= tablePtr->titleRows) {
|
873 |
|
|
row = tablePtr->topRow;
|
874 |
|
|
}
|
875 |
|
|
|
876 |
|
|
/* Cache the row in user terms */
|
877 |
|
|
urow = row+tablePtr->rowOffset;
|
878 |
|
|
|
879 |
|
|
/* Get the row tag once for all iterations of col */
|
880 |
|
|
rowPtr = FindRowColTag(tablePtr, urow, ROW);
|
881 |
|
|
|
882 |
|
|
for (col = colFrom; col <= colTo; col++) {
|
883 |
|
|
activeCell = 0;
|
884 |
|
|
/*
|
885 |
|
|
* are we in the 'dead zone' between the
|
886 |
|
|
* title cols and the first displayed col
|
887 |
|
|
*/
|
888 |
|
|
if (col < tablePtr->leftCol && col >= tablePtr->titleCols) {
|
889 |
|
|
col = tablePtr->leftCol;
|
890 |
|
|
}
|
891 |
|
|
|
892 |
|
|
/* Cache the col in user terms */
|
893 |
|
|
ucol = col+tablePtr->colOffset;
|
894 |
|
|
|
895 |
|
|
/* put the use cell ref into a buffer for the hash lookups */
|
896 |
|
|
TableMakeArrayIndex(urow, ucol, buf);
|
897 |
|
|
|
898 |
|
|
/* get the coordinates for the cell */
|
899 |
|
|
TableCellCoords(tablePtr, row, col, &x, &y, &width, &height);
|
900 |
|
|
|
901 |
|
|
/* Constrain drawn size to the visual boundaries */
|
902 |
|
|
if (width > boundW-x) {
|
903 |
|
|
width = boundW-x;
|
904 |
|
|
}
|
905 |
|
|
if (height > boundH-y) {
|
906 |
|
|
height = boundH-y;
|
907 |
|
|
}
|
908 |
|
|
|
909 |
|
|
/* Create the tag here */
|
910 |
|
|
tagPtr = TableNewTag();
|
911 |
|
|
/* First, merge in the default tag */
|
912 |
|
|
TableMergeTag(tagPtr, &(tablePtr->defaultTag));
|
913 |
|
|
|
914 |
|
|
if ((entryPtr = Tcl_FindHashEntry(tablePtr->winTable, buf)) != NULL) {
|
915 |
|
|
ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr);
|
916 |
|
|
|
917 |
|
|
if (ewPtr->tkwin != NULL) {
|
918 |
|
|
/* Display embedded window instead of text */
|
919 |
|
|
|
920 |
|
|
/* if active, make it disabled to avoid unnecessary editing */
|
921 |
|
|
if ((tablePtr->flags & HAS_ACTIVE)
|
922 |
|
|
&& row == tablePtr->activeRow && col == tablePtr->activeCol) {
|
923 |
|
|
tablePtr->flags |= ACTIVE_DISABLED;
|
924 |
|
|
}
|
925 |
|
|
|
926 |
|
|
EmbWinDisplay(tablePtr, window, ewPtr, tagPtr,
|
927 |
|
|
x, y, width, height);
|
928 |
|
|
|
929 |
|
|
if (tablePtr->drawMode == DRAW_MODE_SLOW) {
|
930 |
|
|
/* Correctly adjust x && y with the offset */
|
931 |
|
|
x -= invalidX;
|
932 |
|
|
y -= invalidY;
|
933 |
|
|
}
|
934 |
|
|
Tk_Fill3DRectangle(tkwin, window, tagPtr->bg,
|
935 |
|
|
x, y, width, height, bd, TK_RELIEF_FLAT);
|
936 |
|
|
|
937 |
|
|
goto ImageUsed;
|
938 |
|
|
}
|
939 |
|
|
}
|
940 |
|
|
|
941 |
|
|
if (tablePtr->drawMode == DRAW_MODE_SLOW) {
|
942 |
|
|
/* Correctly adjust x && y with the offset */
|
943 |
|
|
x -= invalidX;
|
944 |
|
|
y -= invalidY;
|
945 |
|
|
}
|
946 |
|
|
|
947 |
|
|
shouldInvert = 0;
|
948 |
|
|
/*
|
949 |
|
|
* get the combined tag structure for the cell
|
950 |
|
|
* first clear out a new tag structure that we will build in
|
951 |
|
|
* then add tags as we realize they belong.
|
952 |
|
|
* Tags with the highest priority are added first
|
953 |
|
|
*/
|
954 |
|
|
|
955 |
|
|
/*
|
956 |
|
|
* Merge colPtr if it exists
|
957 |
|
|
* let's see if we have the value cached already
|
958 |
|
|
* if not, run the findColTag routine and cache the value
|
959 |
|
|
*/
|
960 |
|
|
entryPtr = Tcl_CreateHashEntry(colTagsCache, (char *)ucol, &new);
|
961 |
|
|
if (new) {
|
962 |
|
|
colPtr = FindRowColTag(tablePtr, ucol, COL);
|
963 |
|
|
Tcl_SetHashValue(entryPtr, colPtr);
|
964 |
|
|
} else {
|
965 |
|
|
colPtr = (TableTag *) Tcl_GetHashValue(entryPtr);
|
966 |
|
|
}
|
967 |
|
|
if (colPtr != (TableTag *) NULL)
|
968 |
|
|
TableMergeTag(tagPtr, colPtr);
|
969 |
|
|
/* Merge rowPtr if it exists */
|
970 |
|
|
if (rowPtr != (TableTag *) NULL)
|
971 |
|
|
TableMergeTag(tagPtr, rowPtr);
|
972 |
|
|
/* Am I in the titles */
|
973 |
|
|
if (row < tablePtr->topRow || col < tablePtr->leftCol)
|
974 |
|
|
TableMergeTag(tagPtr, titlePtr);
|
975 |
|
|
/* Does this have a cell tag */
|
976 |
|
|
if ((entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf)) != NULL)
|
977 |
|
|
TableMergeTag(tagPtr, (TableTag *) Tcl_GetHashValue(entryPtr));
|
978 |
|
|
/* is this cell selected? */
|
979 |
|
|
if (Tcl_FindHashEntry(tablePtr->selCells, buf) != NULL) {
|
980 |
|
|
if (tablePtr->invertSelected && !activeCell) {
|
981 |
|
|
shouldInvert = 1;
|
982 |
|
|
} else {
|
983 |
|
|
TableMergeTag(tagPtr, selPtr);
|
984 |
|
|
}
|
985 |
|
|
}
|
986 |
|
|
/* is this cell active? */
|
987 |
|
|
if ((tablePtr->flags & HAS_ACTIVE) && tablePtr->state == STATE_NORMAL
|
988 |
|
|
&& row == tablePtr->activeRow && col == tablePtr->activeCol) {
|
989 |
|
|
if (tagPtr->state == STATE_DISABLED) {
|
990 |
|
|
tablePtr->flags |= ACTIVE_DISABLED;
|
991 |
|
|
} else {
|
992 |
|
|
TableMergeTag(tagPtr, activePtr);
|
993 |
|
|
activeCell = 1;
|
994 |
|
|
tablePtr->flags &= ~ACTIVE_DISABLED;
|
995 |
|
|
}
|
996 |
|
|
}
|
997 |
|
|
/* if flash mode is on, is this cell flashing */
|
998 |
|
|
if (tablePtr->flashMode &&
|
999 |
|
|
Tcl_FindHashEntry(tablePtr->flashCells, buf) != NULL)
|
1000 |
|
|
TableMergeTag(tagPtr, flashPtr);
|
1001 |
|
|
|
1002 |
|
|
if (shouldInvert) TableInvertTag(tagPtr);
|
1003 |
|
|
|
1004 |
|
|
/*
|
1005 |
|
|
* first fill in a blank rectangle. This is left as a Tk call instead
|
1006 |
|
|
* of a direct X call for Tk compatibilty. The TK_RELIEF_FLAT ensures
|
1007 |
|
|
* that only XFillRectangle is called anyway so the speed is the same
|
1008 |
|
|
*/
|
1009 |
|
|
Tk_Fill3DRectangle(tkwin, window, tagPtr->bg,
|
1010 |
|
|
x, y, width, height, bd, TK_RELIEF_FLAT);
|
1011 |
|
|
|
1012 |
|
|
/*
|
1013 |
|
|
* If an image is in the tag, draw it
|
1014 |
|
|
*/
|
1015 |
|
|
if (tagPtr->image != NULL) {
|
1016 |
|
|
Tk_SizeOfImage(tagPtr->image, &itemW, &itemH);
|
1017 |
|
|
/* Handle anchoring of image in cell space */
|
1018 |
|
|
switch (tagPtr->anchor) {
|
1019 |
|
|
case TK_ANCHOR_NW:
|
1020 |
|
|
case TK_ANCHOR_W:
|
1021 |
|
|
case TK_ANCHOR_SW: /* western position */
|
1022 |
|
|
originX = itemX = 0;
|
1023 |
|
|
break;
|
1024 |
|
|
case TK_ANCHOR_N:
|
1025 |
|
|
case TK_ANCHOR_S:
|
1026 |
|
|
case TK_ANCHOR_CENTER: /* centered position */
|
1027 |
|
|
itemX = MAX(0, (itemW-width)/2-bd);
|
1028 |
|
|
originX = MAX(0, (width-itemW)/2);
|
1029 |
|
|
break;
|
1030 |
|
|
default: /* eastern position */
|
1031 |
|
|
itemX = MAX(0, itemW-width-2*bd);
|
1032 |
|
|
originX = MAX(0, width-itemW);
|
1033 |
|
|
}
|
1034 |
|
|
switch (tagPtr->anchor) {
|
1035 |
|
|
case TK_ANCHOR_N:
|
1036 |
|
|
case TK_ANCHOR_NE:
|
1037 |
|
|
case TK_ANCHOR_NW: /* northern position */
|
1038 |
|
|
originY = itemY = 0;
|
1039 |
|
|
break;
|
1040 |
|
|
case TK_ANCHOR_W:
|
1041 |
|
|
case TK_ANCHOR_E:
|
1042 |
|
|
case TK_ANCHOR_CENTER: /* centered position */
|
1043 |
|
|
itemY = MAX(0, (itemH-height)/2-bd);
|
1044 |
|
|
originY = MAX(0, (height-itemH)/2);
|
1045 |
|
|
break;
|
1046 |
|
|
default: /* southern position */
|
1047 |
|
|
itemY = MAX(0, itemH-height-2*bd);
|
1048 |
|
|
originY = MAX(0, height-itemH);
|
1049 |
|
|
}
|
1050 |
|
|
Tk_RedrawImage(tagPtr->image, itemX, itemY,
|
1051 |
|
|
MIN(itemW, width-originX-2*bd),
|
1052 |
|
|
MIN(itemH, height-originY-2*bd), window,
|
1053 |
|
|
x+originX+bd, y+originY+bd);
|
1054 |
|
|
/* Jump to avoid display of the text value */
|
1055 |
|
|
if (tagPtr->showtext == 0)
|
1056 |
|
|
goto ImageUsed;
|
1057 |
|
|
}
|
1058 |
|
|
|
1059 |
|
|
/* get the GC for this particular blend of tags
|
1060 |
|
|
* this creates the GC if it never existed, otherwise it
|
1061 |
|
|
* modifies the one we have */
|
1062 |
|
|
TableGetGc(display, window, tagPtr, &tagGc);
|
1063 |
|
|
|
1064 |
|
|
/* if this is the active cell, use the buffer */
|
1065 |
|
|
if (activeCell) {
|
1066 |
|
|
string = tablePtr->activeBuf;
|
1067 |
|
|
} else {
|
1068 |
|
|
/* Is there a value in the cell? If so, draw it */
|
1069 |
|
|
string = TableGetCellValue(tablePtr, urow, ucol);
|
1070 |
|
|
}
|
1071 |
|
|
|
1072 |
|
|
numBytes = strlen(string);
|
1073 |
|
|
/* If there is a string, show it */
|
1074 |
|
|
if (activeCell || numBytes) {
|
1075 |
|
|
/* get the dimensions of the string */
|
1076 |
|
|
textLayout = Tk_ComputeTextLayout(tagPtr->tkfont, string, numBytes,
|
1077 |
|
|
(tagPtr->wrap>0) ? width : 0,
|
1078 |
|
|
tagPtr->justify,
|
1079 |
|
|
(tagPtr->multiline>0) ? 0 :
|
1080 |
|
|
TK_IGNORE_NEWLINES,
|
1081 |
|
|
&itemW, &itemH);
|
1082 |
|
|
|
1083 |
|
|
/*
|
1084 |
|
|
* Set the origin coordinates of the string to draw using the anchor.
|
1085 |
|
|
* origin represents the (x,y) coordinate of the lower left corner of
|
1086 |
|
|
* the text box, relative to the internal (inside the border) window
|
1087 |
|
|
*/
|
1088 |
|
|
|
1089 |
|
|
/* set the X origin first */
|
1090 |
|
|
switch (tagPtr->anchor) {
|
1091 |
|
|
case TK_ANCHOR_NW:
|
1092 |
|
|
case TK_ANCHOR_W:
|
1093 |
|
|
case TK_ANCHOR_SW: /* western position */
|
1094 |
|
|
originX = tablePtr->padX;
|
1095 |
|
|
break;
|
1096 |
|
|
case TK_ANCHOR_N:
|
1097 |
|
|
case TK_ANCHOR_S:
|
1098 |
|
|
case TK_ANCHOR_CENTER: /* centered position */
|
1099 |
|
|
originX = (width-itemW)/2 - bd;
|
1100 |
|
|
break;
|
1101 |
|
|
default: /* eastern position */
|
1102 |
|
|
originX = width-itemW-2*bd-tablePtr->padX;
|
1103 |
|
|
}
|
1104 |
|
|
|
1105 |
|
|
/* then set the Y origin */
|
1106 |
|
|
switch (tagPtr->anchor) {
|
1107 |
|
|
case TK_ANCHOR_N:
|
1108 |
|
|
case TK_ANCHOR_NE:
|
1109 |
|
|
case TK_ANCHOR_NW: /* northern position */
|
1110 |
|
|
originY = tablePtr->padY;
|
1111 |
|
|
break;
|
1112 |
|
|
case TK_ANCHOR_W:
|
1113 |
|
|
case TK_ANCHOR_E:
|
1114 |
|
|
case TK_ANCHOR_CENTER: /* centered position */
|
1115 |
|
|
originY = (height-itemH)/2 - bd;
|
1116 |
|
|
break;
|
1117 |
|
|
default: /* southern position */
|
1118 |
|
|
originY = height-itemH-2*bd-tablePtr->padY;
|
1119 |
|
|
}
|
1120 |
|
|
|
1121 |
|
|
/*
|
1122 |
|
|
* if this is the selected cell and we are editing
|
1123 |
|
|
* ensure that the cursor will be displayed
|
1124 |
|
|
*/
|
1125 |
|
|
if (activeCell) {
|
1126 |
|
|
#if (TK_MINOR_VERSION > 0)
|
1127 |
|
|
int insertByte;
|
1128 |
|
|
|
1129 |
|
|
insertByte = Tcl_UtfAtIndex(string, tablePtr->icursor) - string;
|
1130 |
|
|
Tk_CharBbox(textLayout, MIN(numBytes, insertByte),
|
1131 |
|
|
&cx, &cy, &cw, &ch);
|
1132 |
|
|
#else
|
1133 |
|
|
Tk_CharBbox(textLayout, MIN(numBytes, tablePtr->icursor),
|
1134 |
|
|
&cx, &cy, &cw, &ch);
|
1135 |
|
|
#endif
|
1136 |
|
|
/* we have to fudge with maxW because of odd width
|
1137 |
|
|
* determination for newlines at the end of a line */
|
1138 |
|
|
maxW = width-bd-tablePtr->padX-tablePtr->insertWidth
|
1139 |
|
|
-(cx+MIN(tablePtr->charWidth, cw));
|
1140 |
|
|
maxH = height-bd-tablePtr->padY-(cy+ch);
|
1141 |
|
|
if (originX < tablePtr->padX+bd-cx) {
|
1142 |
|
|
/* cursor off cell to the left */
|
1143 |
|
|
/* use western positioning to cet cursor at left edge
|
1144 |
|
|
* with slight variation to show some text */
|
1145 |
|
|
originX = tablePtr->padX+bd-cx
|
1146 |
|
|
+MIN(cx, width-2*bd-tablePtr->padX-tablePtr->insertWidth);
|
1147 |
|
|
} else if (originX > maxW) {
|
1148 |
|
|
/* cursor off cell to the right */
|
1149 |
|
|
/* use eastern positioning to cet cursor at right edge */
|
1150 |
|
|
originX = maxW;
|
1151 |
|
|
}
|
1152 |
|
|
if (originY < tablePtr->padY+bd-cy) {
|
1153 |
|
|
/* cursor before top of cell */
|
1154 |
|
|
/* use northern positioning to cet cursor at top edge */
|
1155 |
|
|
originY = tablePtr->padY+bd-cy;
|
1156 |
|
|
} else if (originY > maxH) {
|
1157 |
|
|
/* cursor beyond bottom of cell */
|
1158 |
|
|
/* use southern positioning to cet cursor at bottom edge */
|
1159 |
|
|
originY = maxH;
|
1160 |
|
|
}
|
1161 |
|
|
tablePtr->activeLayout = textLayout;
|
1162 |
|
|
tablePtr->activeX = originX;
|
1163 |
|
|
tablePtr->activeY = originY;
|
1164 |
|
|
}
|
1165 |
|
|
/*
|
1166 |
|
|
* use a clip rectangle only if necessary as it means
|
1167 |
|
|
* updating the GC in the server which slows everything down.
|
1168 |
|
|
* The bd offsets allow us to fudge a little more since the
|
1169 |
|
|
* borders are drawn after drawing the string.
|
1170 |
|
|
*/
|
1171 |
|
|
if ((clipRectSet = ((originX < bd) || (originY < bd)
|
1172 |
|
|
|| (originX+itemW > width-bd)
|
1173 |
|
|
|| (originY+itemH > height-bd)))) {
|
1174 |
|
|
#ifdef _WIN32
|
1175 |
|
|
/* We always draw in the upper-left corner of the clipWind */
|
1176 |
|
|
Tk_Fill3DRectangle(tkwin, clipWind, tagPtr->bg, 0, 0,
|
1177 |
|
|
width, height, bd, TK_RELIEF_FLAT);
|
1178 |
|
|
Tk_DrawTextLayout(display, clipWind, tagGc, textLayout,
|
1179 |
|
|
originX+bd, originY+bd, 0, -1);
|
1180 |
|
|
XCopyArea(display, clipWind, window, tagGc, 0, 0,
|
1181 |
|
|
width, height, x, y);
|
1182 |
|
|
#else
|
1183 |
|
|
/* set the clipping rectangle */
|
1184 |
|
|
clipRect.x = x;
|
1185 |
|
|
clipRect.y = y;
|
1186 |
|
|
clipRect.width = width;
|
1187 |
|
|
clipRect.height = height;
|
1188 |
|
|
XSetClipRectangles(display, tagGc, 0, 0, &clipRect, 1, Unsorted);
|
1189 |
|
|
#endif
|
1190 |
|
|
}
|
1191 |
|
|
|
1192 |
|
|
#ifdef _WIN32 /* no cliprect on windows */
|
1193 |
|
|
if (!clipRectSet)
|
1194 |
|
|
#endif
|
1195 |
|
|
Tk_DrawTextLayout(display, window, tagGc, textLayout,
|
1196 |
|
|
x+originX+bd, y+originY+bd, 0, -1);
|
1197 |
|
|
|
1198 |
|
|
#ifndef _WIN32 /* no cliprect on windows */
|
1199 |
|
|
/* reset the clip mask */
|
1200 |
|
|
if (clipRectSet) {
|
1201 |
|
|
XSetClipMask(display, tagGc, None);
|
1202 |
|
|
}
|
1203 |
|
|
#endif
|
1204 |
|
|
|
1205 |
|
|
/* if this is the active cell draw the cursor if it's on.
|
1206 |
|
|
* this ignores clip rectangles. */
|
1207 |
|
|
if (activeCell && (tablePtr->flags & CURSOR_ON) &&
|
1208 |
|
|
(originY+bd+cy < height) &&
|
1209 |
|
|
(originX+cx+bd-(tablePtr->insertWidth/2) >= 0)) {
|
1210 |
|
|
/* make sure it will fit in the box */
|
1211 |
|
|
maxW = MAX(0, originY+bd+cy);
|
1212 |
|
|
maxH = MIN(ch, height-maxW);
|
1213 |
|
|
Tk_Fill3DRectangle(tkwin, window, tablePtr->insertBg,
|
1214 |
|
|
x+originX+cx+bd-(tablePtr->insertWidth/2),
|
1215 |
|
|
y+maxW, tablePtr->insertWidth,
|
1216 |
|
|
maxH, 0, TK_RELIEF_FLAT);
|
1217 |
|
|
}
|
1218 |
|
|
}
|
1219 |
|
|
|
1220 |
|
|
ImageUsed:
|
1221 |
|
|
/* Draw the 3d border on the pixmap correctly offset */
|
1222 |
|
|
if (tablePtr->borderWidth) {
|
1223 |
|
|
switch (tablePtr->drawMode) {
|
1224 |
|
|
case DRAW_MODE_SLOW:
|
1225 |
|
|
case DRAW_MODE_TK_COMPAT:
|
1226 |
|
|
Tk_Draw3DRectangle(tkwin, window, tagPtr->bg,
|
1227 |
|
|
x, y, width, height, bd, tagPtr->relief);
|
1228 |
|
|
break;
|
1229 |
|
|
case DRAW_MODE_FAST:
|
1230 |
|
|
/*
|
1231 |
|
|
** choose the GCs to get the best approximation
|
1232 |
|
|
** to the desired drawing style
|
1233 |
|
|
*/
|
1234 |
|
|
switch(tagPtr->relief) {
|
1235 |
|
|
case TK_RELIEF_FLAT:
|
1236 |
|
|
topGc = bottomGc = Tk_3DBorderGC(tkwin, tagPtr->bg, TK_3D_FLAT_GC);
|
1237 |
|
|
break;
|
1238 |
|
|
case TK_RELIEF_RAISED:
|
1239 |
|
|
case TK_RELIEF_RIDGE:
|
1240 |
|
|
topGc = Tk_3DBorderGC(tkwin, tagPtr->bg, TK_3D_LIGHT_GC);
|
1241 |
|
|
bottomGc = Tk_3DBorderGC(tkwin, tagPtr->bg, TK_3D_DARK_GC);
|
1242 |
|
|
break;
|
1243 |
|
|
default: /* TK_RELIEF_SUNKEN TK_RELIEF_GROOVE */
|
1244 |
|
|
bottomGc = Tk_3DBorderGC(tkwin, tagPtr->bg, TK_3D_LIGHT_GC);
|
1245 |
|
|
topGc = Tk_3DBorderGC(tkwin, tagPtr->bg, TK_3D_DARK_GC);
|
1246 |
|
|
break;
|
1247 |
|
|
}
|
1248 |
|
|
|
1249 |
|
|
/* draw a line with single pixel width */
|
1250 |
|
|
rect[0].x = x + width - 1;
|
1251 |
|
|
rect[0].y = y;
|
1252 |
|
|
rect[1].y = height - 1;
|
1253 |
|
|
rect[2].x = -width + 1;
|
1254 |
|
|
XDrawLines(display, window, bottomGc, rect, 3, CoordModePrevious);
|
1255 |
|
|
rect[0].x = x;
|
1256 |
|
|
rect[0].y = y + height - 1;
|
1257 |
|
|
rect[1].y = -height + 1;
|
1258 |
|
|
rect[2].x = width - 1;
|
1259 |
|
|
XDrawLines(display, window, topGc, rect, 3, CoordModePrevious);
|
1260 |
|
|
break;
|
1261 |
|
|
case DRAW_MODE_SINGLE:
|
1262 |
|
|
topGc = Tk_3DBorderGC(tkwin, tagPtr->bg, TK_3D_DARK_GC);
|
1263 |
|
|
/* draw a line with single pixel width */
|
1264 |
|
|
rect[0].x = x;
|
1265 |
|
|
rect[0].y = y + height - 1;
|
1266 |
|
|
rect[1].y = -height + 1;
|
1267 |
|
|
rect[2].x = width - 1;
|
1268 |
|
|
XDrawLines(display, window, topGc, rect, 3, CoordModePrevious);
|
1269 |
|
|
break;
|
1270 |
|
|
}
|
1271 |
|
|
}
|
1272 |
|
|
|
1273 |
|
|
/* delete the tag structure */
|
1274 |
|
|
ckfree((char *) (tagPtr));
|
1275 |
|
|
if (textLayout && !activeCell) {
|
1276 |
|
|
Tk_FreeTextLayout(textLayout);
|
1277 |
|
|
textLayout = NULL;
|
1278 |
|
|
}
|
1279 |
|
|
}
|
1280 |
|
|
}
|
1281 |
|
|
#ifdef _WIN32
|
1282 |
|
|
Tk_FreePixmap(display, clipWind);
|
1283 |
|
|
#endif
|
1284 |
|
|
|
1285 |
|
|
/* Take care of removing embedded windows that are no longer in view */
|
1286 |
|
|
TableUndisplay(tablePtr);
|
1287 |
|
|
|
1288 |
|
|
/* copy over and delete the pixmap if we are in slow mode */
|
1289 |
|
|
if (tablePtr->drawMode == DRAW_MODE_SLOW) {
|
1290 |
|
|
/* Get a default valued GC */
|
1291 |
|
|
TableGetGc(display, window, &(tablePtr->defaultTag), &tagGc);
|
1292 |
|
|
XCopyArea(display, window, Tk_WindowId(tkwin), tagGc, 0, 0,
|
1293 |
|
|
invalidWidth, invalidHeight, invalidX, invalidY);
|
1294 |
|
|
Tk_FreePixmap(display, window);
|
1295 |
|
|
window = Tk_WindowId(tkwin);
|
1296 |
|
|
}
|
1297 |
|
|
|
1298 |
|
|
/*
|
1299 |
|
|
* if we have got to the end of the table,
|
1300 |
|
|
* clear the area after the last row/col
|
1301 |
|
|
*/
|
1302 |
|
|
TableCellCoords(tablePtr, tablePtr->rows-1, tablePtr->cols-1,
|
1303 |
|
|
&x, &y, &width, &height);
|
1304 |
|
|
|
1305 |
|
|
/* This should occur before moving pixmap, but this simplifies things
|
1306 |
|
|
*
|
1307 |
|
|
* Could use Tk_Fill3DRectangle instead of XFillRectangle
|
1308 |
|
|
* for best compatibility, and XClearArea could be used on Unix
|
1309 |
|
|
* for best speed, so this is the compromise w/o #ifdef's
|
1310 |
|
|
*/
|
1311 |
|
|
if (x+width < invalidX+invalidWidth) {
|
1312 |
|
|
XFillRectangle(display, window,
|
1313 |
|
|
Tk_3DBorderGC(tkwin, tablePtr->defaultTag.bg,
|
1314 |
|
|
TK_3D_FLAT_GC), x+width, invalidY,
|
1315 |
|
|
invalidX+invalidWidth-x-width, invalidHeight);
|
1316 |
|
|
}
|
1317 |
|
|
|
1318 |
|
|
if (y+height < invalidY+invalidHeight) {
|
1319 |
|
|
XFillRectangle(display, window,
|
1320 |
|
|
Tk_3DBorderGC(tkwin, tablePtr->defaultTag.bg,
|
1321 |
|
|
TK_3D_FLAT_GC), invalidX, y+height,
|
1322 |
|
|
invalidWidth, invalidY+invalidHeight-y-height);
|
1323 |
|
|
}
|
1324 |
|
|
|
1325 |
|
|
if (tagGc != NULL) {
|
1326 |
|
|
TableFreeGc(display, tagGc);
|
1327 |
|
|
}
|
1328 |
|
|
TableRedrawHighlight(tablePtr);
|
1329 |
|
|
/*
|
1330 |
|
|
* Free the hash table used to cache evaluations.
|
1331 |
|
|
*/
|
1332 |
|
|
Tcl_DeleteHashTable(colTagsCache);
|
1333 |
|
|
ckfree((char *) (colTagsCache));
|
1334 |
|
|
}
|
1335 |
|
|
|
1336 |
|
|
/*
|
1337 |
|
|
*----------------------------------------------------------------------
|
1338 |
|
|
*
|
1339 |
|
|
* TableInvalidate --
|
1340 |
|
|
* Invalidates a rectangle and adds it to the total invalid rectangle
|
1341 |
|
|
* waiting to be redrawn. If the INV_FORCE flag bit is set,
|
1342 |
|
|
* it does an update instantly else waits until Tk is idle.
|
1343 |
|
|
*
|
1344 |
|
|
* Results:
|
1345 |
|
|
* Will schedule table (re)display.
|
1346 |
|
|
*
|
1347 |
|
|
* Side effects:
|
1348 |
|
|
* None
|
1349 |
|
|
*
|
1350 |
|
|
*----------------------------------------------------------------------
|
1351 |
|
|
*/
|
1352 |
|
|
void
|
1353 |
|
|
TableInvalidate(Table * tablePtr, int x, int y,
|
1354 |
|
|
int width, int height, int flags)
|
1355 |
|
|
{
|
1356 |
|
|
register int hl = tablePtr->highlightWidth;
|
1357 |
|
|
register Tk_Window tkwin = tablePtr->tkwin;
|
1358 |
|
|
|
1359 |
|
|
/* make sure that the window hasn't been destroyed already */
|
1360 |
|
|
/* avoid allocating 0 sized pixmaps which would be fatal */
|
1361 |
|
|
/* and check if rectangle is even on the screen */
|
1362 |
|
|
if ((tkwin == NULL) || (width <= 0) || (height <= 0)
|
1363 |
|
|
|| (x > Tk_Width(tkwin)) || (y > Tk_Height(tkwin))) return;
|
1364 |
|
|
|
1365 |
|
|
/* If not even mapped, wait for the remap to redraw all */
|
1366 |
|
|
if (!Tk_IsMapped(tkwin)) {
|
1367 |
|
|
tablePtr->flags |= REDRAW_ON_MAP;
|
1368 |
|
|
return;
|
1369 |
|
|
}
|
1370 |
|
|
|
1371 |
|
|
/* if no pending updates then replace the rectangle,
|
1372 |
|
|
* otherwise find the bounding rectangle */
|
1373 |
|
|
if ((flags & INV_HIGHLIGHT) &&
|
1374 |
|
|
(x < hl || y < hl || x+width >= Tk_Width(tkwin)-hl ||
|
1375 |
|
|
y+height >= Tk_Height(tkwin)-hl)) {
|
1376 |
|
|
tablePtr->flags |= REDRAW_BORDER;
|
1377 |
|
|
}
|
1378 |
|
|
|
1379 |
|
|
if (tablePtr->flags & REDRAW_PENDING) {
|
1380 |
|
|
tablePtr->invalidWidth = MAX(tablePtr->invalidX+tablePtr->invalidWidth,
|
1381 |
|
|
x + width);
|
1382 |
|
|
tablePtr->invalidHeight = MAX(tablePtr->invalidY+tablePtr->invalidHeight,
|
1383 |
|
|
y + height);
|
1384 |
|
|
if (tablePtr->invalidX > x) tablePtr->invalidX = x;
|
1385 |
|
|
if (tablePtr->invalidY > y) tablePtr->invalidY = y;
|
1386 |
|
|
tablePtr->invalidWidth -= tablePtr->invalidX;
|
1387 |
|
|
tablePtr->invalidHeight -= tablePtr->invalidY;
|
1388 |
|
|
/* are we forcing this update out */
|
1389 |
|
|
if (flags & INV_FORCE) {
|
1390 |
|
|
Tcl_CancelIdleCall(TableDisplay, (ClientData) tablePtr);
|
1391 |
|
|
TableDisplay((ClientData) tablePtr);
|
1392 |
|
|
}
|
1393 |
|
|
} else {
|
1394 |
|
|
tablePtr->invalidX = x;
|
1395 |
|
|
tablePtr->invalidY = y;
|
1396 |
|
|
tablePtr->invalidWidth = width;
|
1397 |
|
|
tablePtr->invalidHeight = height;
|
1398 |
|
|
if (flags & INV_FORCE) {
|
1399 |
|
|
TableDisplay((ClientData) tablePtr);
|
1400 |
|
|
} else {
|
1401 |
|
|
tablePtr->flags |= REDRAW_PENDING;
|
1402 |
|
|
Tcl_DoWhenIdle(TableDisplay, (ClientData) tablePtr);
|
1403 |
|
|
}
|
1404 |
|
|
}
|
1405 |
|
|
}
|
1406 |
|
|
|
1407 |
|
|
/*
|
1408 |
|
|
*----------------------------------------------------------------------
|
1409 |
|
|
*
|
1410 |
|
|
* TableFlashEvent --
|
1411 |
|
|
* Called when the flash timer goes off.
|
1412 |
|
|
*
|
1413 |
|
|
* Results:
|
1414 |
|
|
* Decrements all the entries in the hash table and invalidates
|
1415 |
|
|
* any cells that expire, deleting them from the table. If the
|
1416 |
|
|
* table is now empty, stops the timer, else reenables it.
|
1417 |
|
|
*
|
1418 |
|
|
* Side effects:
|
1419 |
|
|
* None.
|
1420 |
|
|
*
|
1421 |
|
|
*----------------------------------------------------------------------
|
1422 |
|
|
*/
|
1423 |
|
|
static void
|
1424 |
|
|
TableFlashEvent(ClientData clientdata)
|
1425 |
|
|
{
|
1426 |
|
|
Table *tablePtr = (Table *) clientdata;
|
1427 |
|
|
Tcl_HashEntry *entryPtr;
|
1428 |
|
|
Tcl_HashSearch search;
|
1429 |
|
|
int entries, count, row, col;
|
1430 |
|
|
|
1431 |
|
|
entries = 0;
|
1432 |
|
|
for (entryPtr = Tcl_FirstHashEntry(tablePtr->flashCells, &search);
|
1433 |
|
|
entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
|
1434 |
|
|
count = (int) Tcl_GetHashValue(entryPtr);
|
1435 |
|
|
if (--count <= 0) {
|
1436 |
|
|
/* get the cell address and invalidate that region only */
|
1437 |
|
|
TableParseArrayIndex(&row, &col,
|
1438 |
|
|
Tcl_GetHashKey(tablePtr->flashCells, entryPtr));
|
1439 |
|
|
|
1440 |
|
|
/* delete the entry from the table */
|
1441 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
1442 |
|
|
|
1443 |
|
|
TableRefresh(tablePtr, row-tablePtr->rowOffset,
|
1444 |
|
|
col-tablePtr->colOffset, CELL|INV_FORCE);
|
1445 |
|
|
} else {
|
1446 |
|
|
Tcl_SetHashValue(entryPtr, (ClientData) count);
|
1447 |
|
|
entries++;
|
1448 |
|
|
}
|
1449 |
|
|
}
|
1450 |
|
|
|
1451 |
|
|
/* do I need to restart the timer */
|
1452 |
|
|
if (entries && tablePtr->flashMode)
|
1453 |
|
|
tablePtr->flashTimer = Tcl_CreateTimerHandler(250, TableFlashEvent,
|
1454 |
|
|
(ClientData) tablePtr);
|
1455 |
|
|
else
|
1456 |
|
|
tablePtr->flashTimer = 0;
|
1457 |
|
|
}
|
1458 |
|
|
|
1459 |
|
|
/*
|
1460 |
|
|
*----------------------------------------------------------------------
|
1461 |
|
|
*
|
1462 |
|
|
* TableAddFlash --
|
1463 |
|
|
* Adds a flash on cell row,col (real coords) with the default timeout
|
1464 |
|
|
* if flashing is enabled and flashtime > 0.
|
1465 |
|
|
*
|
1466 |
|
|
* Results:
|
1467 |
|
|
* Cell will flash.
|
1468 |
|
|
*
|
1469 |
|
|
* Side effects:
|
1470 |
|
|
* Will start flash timer if it didn't exist.
|
1471 |
|
|
*
|
1472 |
|
|
*----------------------------------------------------------------------
|
1473 |
|
|
*/
|
1474 |
|
|
static void
|
1475 |
|
|
TableAddFlash(Table *tablePtr, int row, int col)
|
1476 |
|
|
{
|
1477 |
|
|
char buf[INDEX_BUFSIZE];
|
1478 |
|
|
int dummy;
|
1479 |
|
|
Tcl_HashEntry *entryPtr;
|
1480 |
|
|
|
1481 |
|
|
if (!tablePtr->flashMode || tablePtr->flashTime < 1)
|
1482 |
|
|
return;
|
1483 |
|
|
|
1484 |
|
|
/* create the array index in user coords */
|
1485 |
|
|
TableMakeArrayIndex(row+tablePtr->rowOffset, col+tablePtr->colOffset, buf);
|
1486 |
|
|
|
1487 |
|
|
/* add the flash to the hash table */
|
1488 |
|
|
entryPtr = Tcl_CreateHashEntry(tablePtr->flashCells, buf, &dummy);
|
1489 |
|
|
Tcl_SetHashValue(entryPtr, tablePtr->flashTime);
|
1490 |
|
|
|
1491 |
|
|
/* now set the timer if it's not already going and invalidate the area */
|
1492 |
|
|
if (tablePtr->flashTimer == NULL)
|
1493 |
|
|
tablePtr->flashTimer = Tcl_CreateTimerHandler(250, TableFlashEvent,
|
1494 |
|
|
(ClientData) tablePtr);
|
1495 |
|
|
}
|
1496 |
|
|
|
1497 |
|
|
/*
|
1498 |
|
|
*----------------------------------------------------------------------
|
1499 |
|
|
*
|
1500 |
|
|
* TableSetActiveIndex --
|
1501 |
|
|
* Sets the "active" index of the associated array to the current
|
1502 |
|
|
* value of the active buffer.
|
1503 |
|
|
*
|
1504 |
|
|
* Results:
|
1505 |
|
|
* None.
|
1506 |
|
|
*
|
1507 |
|
|
* Side effects:
|
1508 |
|
|
* Traces on the array can cause side effects.
|
1509 |
|
|
*
|
1510 |
|
|
*----------------------------------------------------------------------
|
1511 |
|
|
*/
|
1512 |
|
|
static void
|
1513 |
|
|
TableSetActiveIndex(register Table *tablePtr)
|
1514 |
|
|
{
|
1515 |
|
|
if (tablePtr->arrayVar) {
|
1516 |
|
|
tablePtr->flags |= SET_ACTIVE;
|
1517 |
|
|
Tcl_SetVar2(tablePtr->interp, tablePtr->arrayVar, "active",
|
1518 |
|
|
tablePtr->activeBuf, TCL_GLOBAL_ONLY);
|
1519 |
|
|
tablePtr->flags &= ~SET_ACTIVE;
|
1520 |
|
|
}
|
1521 |
|
|
}
|
1522 |
|
|
|
1523 |
|
|
/*
|
1524 |
|
|
*----------------------------------------------------------------------
|
1525 |
|
|
*
|
1526 |
|
|
* TableGetActiveBuf --
|
1527 |
|
|
* Get the current selection into the buffer and mark it as unedited.
|
1528 |
|
|
* Set the position to the end of the string.
|
1529 |
|
|
*
|
1530 |
|
|
* Results:
|
1531 |
|
|
* None.
|
1532 |
|
|
*
|
1533 |
|
|
* Side effects:
|
1534 |
|
|
* tablePtr->activeBuf will change.
|
1535 |
|
|
*
|
1536 |
|
|
*----------------------------------------------------------------------
|
1537 |
|
|
*/
|
1538 |
|
|
static void
|
1539 |
|
|
TableGetActiveBuf(register Table *tablePtr)
|
1540 |
|
|
{
|
1541 |
|
|
char *data = "";
|
1542 |
|
|
|
1543 |
|
|
if (tablePtr->flags & HAS_ACTIVE)
|
1544 |
|
|
data = TableGetCellValue(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
|
1545 |
|
|
tablePtr->activeCol+tablePtr->colOffset);
|
1546 |
|
|
|
1547 |
|
|
if (strcmp(tablePtr->activeBuf, data) == 0) {
|
1548 |
|
|
/* this forced SetActiveIndex is necessary if we change array vars and
|
1549 |
|
|
* they happen to have these cells equal, we won't properly set the
|
1550 |
|
|
* active index for the new array var unless we do this here */
|
1551 |
|
|
TableSetActiveIndex(tablePtr);
|
1552 |
|
|
return;
|
1553 |
|
|
}
|
1554 |
|
|
/* is the buffer long enough */
|
1555 |
|
|
tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, strlen(data)+1);
|
1556 |
|
|
strcpy(tablePtr->activeBuf, data);
|
1557 |
|
|
TableGetIcursor(tablePtr, "end", (int *)0);
|
1558 |
|
|
tablePtr->flags &= ~TEXT_CHANGED;
|
1559 |
|
|
TableSetActiveIndex(tablePtr);
|
1560 |
|
|
}
|
1561 |
|
|
|
1562 |
|
|
/*
|
1563 |
|
|
*----------------------------------------------------------------------
|
1564 |
|
|
*
|
1565 |
|
|
* TableVarProc --
|
1566 |
|
|
* This is the trace procedure associated with the Tcl array. No
|
1567 |
|
|
* validation will occur here because this only triggers when the
|
1568 |
|
|
* array value is directly set, and we can't maintain the old value.
|
1569 |
|
|
*
|
1570 |
|
|
* Results:
|
1571 |
|
|
* Invalidates changed cell.
|
1572 |
|
|
*
|
1573 |
|
|
* Side effects:
|
1574 |
|
|
* Creates/Updates entry in the cache if we are caching.
|
1575 |
|
|
*
|
1576 |
|
|
*----------------------------------------------------------------------
|
1577 |
|
|
*/
|
1578 |
|
|
static char *
|
1579 |
|
|
TableVarProc(clientData, interp, name, index, flags)
|
1580 |
|
|
ClientData clientData; /* Information about table. */
|
1581 |
|
|
Tcl_Interp *interp; /* Interpreter containing variable. */
|
1582 |
|
|
char *name; /* Not used. */
|
1583 |
|
|
char *index; /* Not used. */
|
1584 |
|
|
int flags; /* Information about what happened. */
|
1585 |
|
|
{
|
1586 |
|
|
Table *tablePtr = (Table *) clientData;
|
1587 |
|
|
int dummy, row, col, update = 1;
|
1588 |
|
|
|
1589 |
|
|
/* This is redundant, as the name should always == arrayVar */
|
1590 |
|
|
name = tablePtr->arrayVar;
|
1591 |
|
|
|
1592 |
|
|
/* is this the whole var being destroyed or just one cell being deleted */
|
1593 |
|
|
if ((flags & TCL_TRACE_UNSETS) && index == NULL) {
|
1594 |
|
|
/* if this isn't the interpreter being destroyed reinstate the trace */
|
1595 |
|
|
if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
|
1596 |
|
|
Tcl_SetVar2(interp, name, TEST_KEY, "", TCL_GLOBAL_ONLY);
|
1597 |
|
|
Tcl_UnsetVar2(interp, name, TEST_KEY, TCL_GLOBAL_ONLY);
|
1598 |
|
|
Tcl_ResetResult(interp);
|
1599 |
|
|
|
1600 |
|
|
/* set a trace on the variable */
|
1601 |
|
|
Tcl_TraceVar(interp, name,
|
1602 |
|
|
TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_GLOBAL_ONLY,
|
1603 |
|
|
(Tcl_VarTraceProc *)TableVarProc, (ClientData) tablePtr);
|
1604 |
|
|
|
1605 |
|
|
/* only do the following if arrayVar is our data source */
|
1606 |
|
|
if (tablePtr->dataSource & DATA_ARRAY) {
|
1607 |
|
|
/* clear the selection buffer */
|
1608 |
|
|
TableGetActiveBuf(tablePtr);
|
1609 |
|
|
/* flush any cache */
|
1610 |
|
|
TableFlushCache(tablePtr);
|
1611 |
|
|
/* and invalidate the table */
|
1612 |
|
|
TableInvalidateAll(tablePtr, 0);
|
1613 |
|
|
}
|
1614 |
|
|
}
|
1615 |
|
|
return (char *) NULL;
|
1616 |
|
|
}
|
1617 |
|
|
/* only continue if arrayVar is our data source */
|
1618 |
|
|
if (!(tablePtr->dataSource & DATA_ARRAY)) {
|
1619 |
|
|
return (char *) NULL;
|
1620 |
|
|
}
|
1621 |
|
|
/* get the cell address and invalidate that region only.
|
1622 |
|
|
* Make sure that it is a valid cell address. */
|
1623 |
|
|
if (strcmp("active", index) == 0) {
|
1624 |
|
|
if (tablePtr->flags & SET_ACTIVE) {
|
1625 |
|
|
/* If we are already setting the active cell, the update
|
1626 |
|
|
* will occur in other code */
|
1627 |
|
|
update = 0;
|
1628 |
|
|
} else {
|
1629 |
|
|
/* modified TableGetActiveBuf */
|
1630 |
|
|
char *data = "";
|
1631 |
|
|
|
1632 |
|
|
row = tablePtr->activeRow;
|
1633 |
|
|
col = tablePtr->activeCol;
|
1634 |
|
|
if (tablePtr->flags & HAS_ACTIVE)
|
1635 |
|
|
data = Tcl_GetVar2(interp, name, index, TCL_GLOBAL_ONLY);
|
1636 |
|
|
if (!data) data = "";
|
1637 |
|
|
|
1638 |
|
|
if (strcmp(tablePtr->activeBuf, data) == 0) {
|
1639 |
|
|
return (char *) NULL;
|
1640 |
|
|
}
|
1641 |
|
|
tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf,
|
1642 |
|
|
strlen(data)+1);
|
1643 |
|
|
strcpy(tablePtr->activeBuf, data);
|
1644 |
|
|
/* set cursor to the last char */
|
1645 |
|
|
TableGetIcursor(tablePtr, "end", (int *)0);
|
1646 |
|
|
tablePtr->flags |= TEXT_CHANGED;
|
1647 |
|
|
}
|
1648 |
|
|
} else if (TableParseArrayIndex(&row, &col, index) == 2) {
|
1649 |
|
|
char buf[INDEX_BUFSIZE];
|
1650 |
|
|
/* Make sure it won't trigger on array(2,3extrastuff) */
|
1651 |
|
|
TableMakeArrayIndex(row, col, buf);
|
1652 |
|
|
if (strcmp(buf, index)) {
|
1653 |
|
|
return (char *) NULL;
|
1654 |
|
|
}
|
1655 |
|
|
if (tablePtr->caching) {
|
1656 |
|
|
Tcl_HashEntry *entryPtr;
|
1657 |
|
|
char *val, *data = NULL;
|
1658 |
|
|
|
1659 |
|
|
data = Tcl_GetVar2(interp, name, index, TCL_GLOBAL_ONLY);
|
1660 |
|
|
if (!data) data = "";
|
1661 |
|
|
val = (char *)ckalloc(strlen(data)+1);
|
1662 |
|
|
strcpy(val, data);
|
1663 |
|
|
entryPtr = Tcl_CreateHashEntry(tablePtr->cache, buf, &dummy);
|
1664 |
|
|
Tcl_SetHashValue(entryPtr, val);
|
1665 |
|
|
}
|
1666 |
|
|
/* convert index to real coords */
|
1667 |
|
|
row -= tablePtr->rowOffset;
|
1668 |
|
|
col -= tablePtr->colOffset;
|
1669 |
|
|
/* did the active cell just update */
|
1670 |
|
|
if (row == tablePtr->activeRow && col == tablePtr->activeCol)
|
1671 |
|
|
TableGetActiveBuf(tablePtr);
|
1672 |
|
|
/* Flash the cell */
|
1673 |
|
|
TableAddFlash(tablePtr, row, col);
|
1674 |
|
|
} else {
|
1675 |
|
|
return (char *) NULL;
|
1676 |
|
|
}
|
1677 |
|
|
|
1678 |
|
|
if (update) TableRefresh(tablePtr, row, col, CELL);
|
1679 |
|
|
|
1680 |
|
|
return (char *) NULL;
|
1681 |
|
|
}
|
1682 |
|
|
|
1683 |
|
|
/*
|
1684 |
|
|
*----------------------------------------------------------------------
|
1685 |
|
|
*
|
1686 |
|
|
* TableGeometryRequest --
|
1687 |
|
|
* This procedure is invoked to request a new geometry from Tk.
|
1688 |
|
|
*
|
1689 |
|
|
* Results:
|
1690 |
|
|
* None.
|
1691 |
|
|
*
|
1692 |
|
|
* Side effects:
|
1693 |
|
|
* Geometry information is updated and a new requested size is
|
1694 |
|
|
* registered for the widget. Internal border info is also set.
|
1695 |
|
|
*
|
1696 |
|
|
*----------------------------------------------------------------------
|
1697 |
|
|
*/
|
1698 |
|
|
static void
|
1699 |
|
|
TableGeometryRequest(tablePtr)
|
1700 |
|
|
register Table *tablePtr;
|
1701 |
|
|
{
|
1702 |
|
|
int x, y;
|
1703 |
|
|
|
1704 |
|
|
/* Do the geometry request
|
1705 |
|
|
* If -width #cols was not specified or it is greater than the real
|
1706 |
|
|
* number of cols, use maxWidth as a lower bound, with the other lower
|
1707 |
|
|
* bound being the upper bound of the window's user-set width and the
|
1708 |
|
|
* value of -maxwidth set by the programmer
|
1709 |
|
|
* Vice versa for rows/height
|
1710 |
|
|
*/
|
1711 |
|
|
x = MIN((tablePtr->maxReqCols==0 || tablePtr->maxReqCols > tablePtr->cols) ?
|
1712 |
|
|
tablePtr->maxWidth : tablePtr->colStarts[tablePtr->maxReqCols],
|
1713 |
|
|
tablePtr->maxReqWidth) + 2*tablePtr->highlightWidth;
|
1714 |
|
|
y = MIN((tablePtr->maxReqRows==0 || tablePtr->maxReqRows > tablePtr->rows) ?
|
1715 |
|
|
tablePtr->maxHeight : tablePtr->rowStarts[tablePtr->maxReqRows],
|
1716 |
|
|
tablePtr->maxReqHeight) + 2*tablePtr->highlightWidth;
|
1717 |
|
|
Tk_GeometryRequest(tablePtr->tkwin, x, y);
|
1718 |
|
|
}
|
1719 |
|
|
|
1720 |
|
|
/*
|
1721 |
|
|
*----------------------------------------------------------------------
|
1722 |
|
|
*
|
1723 |
|
|
* TableAdjustActive --
|
1724 |
|
|
* This procedure is called by AdjustParams and CMD_ACTIVATE to
|
1725 |
|
|
* move the active cell.
|
1726 |
|
|
*
|
1727 |
|
|
* Results:
|
1728 |
|
|
* Old and new active cell indices will be invalidated.
|
1729 |
|
|
*
|
1730 |
|
|
* Side effects:
|
1731 |
|
|
* If the old active cell index was edited, it will be saved.
|
1732 |
|
|
* The active buffer will be updated.
|
1733 |
|
|
*
|
1734 |
|
|
*----------------------------------------------------------------------
|
1735 |
|
|
*/
|
1736 |
|
|
static void
|
1737 |
|
|
TableAdjustActive(tablePtr)
|
1738 |
|
|
register Table *tablePtr; /* Widget record for table */
|
1739 |
|
|
{
|
1740 |
|
|
if (tablePtr->flags & HAS_ACTIVE) {
|
1741 |
|
|
/* make sure the active cell has a reasonable real index */
|
1742 |
|
|
tablePtr->activeRow = MAX(0, MIN(tablePtr->activeRow, tablePtr->rows-1));
|
1743 |
|
|
tablePtr->activeCol = MAX(0, MIN(tablePtr->activeCol, tablePtr->cols-1));
|
1744 |
|
|
}
|
1745 |
|
|
|
1746 |
|
|
/*
|
1747 |
|
|
* now check the new value of active cell against the original,
|
1748 |
|
|
* If it changed, invalidate the area, else leave it alone
|
1749 |
|
|
*/
|
1750 |
|
|
if (tablePtr->oldActRow != tablePtr->activeRow ||
|
1751 |
|
|
tablePtr->oldActCol != tablePtr->activeCol) {
|
1752 |
|
|
int x, y, width, height;
|
1753 |
|
|
/* put the value back in the cell */
|
1754 |
|
|
if (tablePtr->oldActRow >= 0 && tablePtr->oldActCol >= 0) {
|
1755 |
|
|
/*
|
1756 |
|
|
* Set the value of the old active cell to the active buffer
|
1757 |
|
|
* SetCellValue will check if the value actually changed
|
1758 |
|
|
*/
|
1759 |
|
|
if (tablePtr->flags & TEXT_CHANGED) {
|
1760 |
|
|
/* WARNING an outside trace will be triggered here and if it
|
1761 |
|
|
* calls something that causes TableAdjustParams to be called
|
1762 |
|
|
* again, we are in data consistency trouble */
|
1763 |
|
|
/* HACK - turn TEXT_CHANGED off now to possibly avoid the
|
1764 |
|
|
* above data inconsistency problem. */
|
1765 |
|
|
tablePtr->flags &= ~TEXT_CHANGED;
|
1766 |
|
|
TableSetCellValue(tablePtr, tablePtr->oldActRow+tablePtr->rowOffset,
|
1767 |
|
|
tablePtr->oldActCol+tablePtr->colOffset,
|
1768 |
|
|
tablePtr->activeBuf);
|
1769 |
|
|
}
|
1770 |
|
|
/* invalidate the old active cell */
|
1771 |
|
|
TableCellCoords(tablePtr, tablePtr->oldActRow, tablePtr->oldActCol,
|
1772 |
|
|
&x, &y, &width, &height);
|
1773 |
|
|
TableInvalidate(tablePtr, x, y, width, height, 0);
|
1774 |
|
|
}
|
1775 |
|
|
|
1776 |
|
|
/* get the new value of the active cell into buffer */
|
1777 |
|
|
TableGetActiveBuf(tablePtr);
|
1778 |
|
|
|
1779 |
|
|
/* invalidate the new active cell */
|
1780 |
|
|
TableCellCoords(tablePtr, tablePtr->activeRow, tablePtr->activeCol,
|
1781 |
|
|
&x, &y, &width, &height);
|
1782 |
|
|
TableInvalidate(tablePtr, x, y, width, height, 0);
|
1783 |
|
|
/* set the old active row/col for the next time this function is called */
|
1784 |
|
|
tablePtr->oldActRow = tablePtr->activeRow;
|
1785 |
|
|
tablePtr->oldActCol = tablePtr->activeCol;
|
1786 |
|
|
}
|
1787 |
|
|
}
|
1788 |
|
|
|
1789 |
|
|
/*
|
1790 |
|
|
*----------------------------------------------------------------------
|
1791 |
|
|
*
|
1792 |
|
|
* TableAdjustParams --
|
1793 |
|
|
* Calculate the row and column starts. Adjusts the topleft corner
|
1794 |
|
|
* variable to keep it within the screen range, out of the titles
|
1795 |
|
|
* and keep the screen full make sure the selected cell is in the
|
1796 |
|
|
* visible area checks to see if the top left cell has changed at
|
1797 |
|
|
* all and invalidates the table if it has.
|
1798 |
|
|
*
|
1799 |
|
|
* Results:
|
1800 |
|
|
* None.
|
1801 |
|
|
*
|
1802 |
|
|
* Side Effects:
|
1803 |
|
|
* Number of rows can change if -rowstretchmode == fill.
|
1804 |
|
|
* topRow && leftCol can change to fit display.
|
1805 |
|
|
* activeRow/Col can change to ensure it is a valid cell.
|
1806 |
|
|
*
|
1807 |
|
|
*----------------------------------------------------------------------
|
1808 |
|
|
*/
|
1809 |
|
|
static void
|
1810 |
|
|
TableAdjustParams(register Table *tablePtr)
|
1811 |
|
|
{
|
1812 |
|
|
int topRow, leftCol, row, col, total, i, value, x, y, width, height;
|
1813 |
|
|
int w, h, bd, hl, recalc = 0;
|
1814 |
|
|
int diff, unpreset, lastUnpreset, pad, lastPad, numPixels;
|
1815 |
|
|
int defColWidth, defRowHeight;
|
1816 |
|
|
Tcl_HashEntry *entryPtr;
|
1817 |
|
|
|
1818 |
|
|
/* cache the borderwidth (doubled) for many upcoming calculations */
|
1819 |
|
|
bd = 2*tablePtr->borderWidth;
|
1820 |
|
|
hl = tablePtr->highlightWidth;
|
1821 |
|
|
w = Tk_Width(tablePtr->tkwin)-2*hl;
|
1822 |
|
|
h = Tk_Height(tablePtr->tkwin)-2*hl;
|
1823 |
|
|
|
1824 |
|
|
/* account for whether defColWidth is in chars (>=0) or pixels (<0) */
|
1825 |
|
|
/* bd is added in here for convenience */
|
1826 |
|
|
if (tablePtr->defColWidth > 0)
|
1827 |
|
|
defColWidth = tablePtr->charWidth * tablePtr->defColWidth + bd;
|
1828 |
|
|
else
|
1829 |
|
|
defColWidth = -(tablePtr->defColWidth) + bd;
|
1830 |
|
|
if (tablePtr->defRowHeight > 0)
|
1831 |
|
|
defRowHeight = tablePtr->charHeight * tablePtr->defRowHeight + bd;
|
1832 |
|
|
else
|
1833 |
|
|
defRowHeight = -(tablePtr->defRowHeight) + bd;
|
1834 |
|
|
|
1835 |
|
|
/* Set up the arrays to hold the col pixels and starts */
|
1836 |
|
|
if (tablePtr->colPixels) ckfree((char *) tablePtr->colPixels);
|
1837 |
|
|
tablePtr->colPixels = (int *) ckalloc(tablePtr->cols * sizeof(int));
|
1838 |
|
|
if (tablePtr->colStarts) ckfree((char *) tablePtr->colStarts);
|
1839 |
|
|
tablePtr->colStarts = (int *) ckalloc((tablePtr->cols+1) * sizeof(int));
|
1840 |
|
|
|
1841 |
|
|
/* get all the preset columns and set their widths */
|
1842 |
|
|
lastUnpreset = 0;
|
1843 |
|
|
numPixels = 0;
|
1844 |
|
|
unpreset = 0;
|
1845 |
|
|
for (i = 0; i < tablePtr->cols; i++) {
|
1846 |
|
|
if ((entryPtr = Tcl_FindHashEntry(tablePtr->colWidths,
|
1847 |
|
|
(char *) i)) == NULL) {
|
1848 |
|
|
tablePtr->colPixels[i] = -1;
|
1849 |
|
|
unpreset++;
|
1850 |
|
|
lastUnpreset = i;
|
1851 |
|
|
} else {
|
1852 |
|
|
value = (int) Tcl_GetHashValue(entryPtr);
|
1853 |
|
|
if (value <= 0) {
|
1854 |
|
|
tablePtr->colPixels[i] = -value + bd;
|
1855 |
|
|
} else {
|
1856 |
|
|
tablePtr->colPixels[i] = value * tablePtr->charWidth + bd;
|
1857 |
|
|
}
|
1858 |
|
|
numPixels += tablePtr->colPixels[i];
|
1859 |
|
|
}
|
1860 |
|
|
}
|
1861 |
|
|
|
1862 |
|
|
/* work out how much to pad each col depending on the mode */
|
1863 |
|
|
diff = w-numPixels-(unpreset*defColWidth);
|
1864 |
|
|
total = 0;
|
1865 |
|
|
/* now do the padding and calculate the column starts */
|
1866 |
|
|
/* diff lower than 0 means we can't see the entire set of columns,
|
1867 |
|
|
* thus no special stretching will occur & we optimize the calculation */
|
1868 |
|
|
if (diff <= 0) {
|
1869 |
|
|
for (i = 0; i < tablePtr->cols; i++) {
|
1870 |
|
|
if (tablePtr->colPixels[i] == -1)
|
1871 |
|
|
tablePtr->colPixels[i] = defColWidth;
|
1872 |
|
|
tablePtr->colStarts[i] = total;
|
1873 |
|
|
total += tablePtr->colPixels[i];
|
1874 |
|
|
}
|
1875 |
|
|
} else {
|
1876 |
|
|
switch(tablePtr->colStretch) {
|
1877 |
|
|
case STRETCH_MODE_NONE:
|
1878 |
|
|
pad = 0;
|
1879 |
|
|
lastPad = 0;
|
1880 |
|
|
break;
|
1881 |
|
|
case STRETCH_MODE_UNSET:
|
1882 |
|
|
if (unpreset == 0) {
|
1883 |
|
|
pad = 0;
|
1884 |
|
|
lastPad = 0;
|
1885 |
|
|
} else {
|
1886 |
|
|
pad = diff / unpreset;
|
1887 |
|
|
lastPad = diff - pad * (unpreset - 1);
|
1888 |
|
|
}
|
1889 |
|
|
break;
|
1890 |
|
|
case STRETCH_MODE_LAST:
|
1891 |
|
|
pad = 0;
|
1892 |
|
|
lastPad = diff;
|
1893 |
|
|
lastUnpreset = tablePtr->cols - 1;
|
1894 |
|
|
break;
|
1895 |
|
|
default: /* STRETCH_MODE_ALL, but also FILL for cols */
|
1896 |
|
|
pad = diff / tablePtr->cols;
|
1897 |
|
|
/* force it to be applied to the last column too */
|
1898 |
|
|
lastUnpreset = tablePtr->cols - 1;
|
1899 |
|
|
lastPad = diff - pad * lastUnpreset;
|
1900 |
|
|
}
|
1901 |
|
|
|
1902 |
|
|
for (i = 0; i < tablePtr->cols; i++) {
|
1903 |
|
|
if (tablePtr->colPixels[i] == -1) {
|
1904 |
|
|
tablePtr->colPixels[i] = defColWidth
|
1905 |
|
|
+ ((i==lastUnpreset)?lastPad:pad);
|
1906 |
|
|
} else if (tablePtr->colStretch == STRETCH_MODE_ALL) {
|
1907 |
|
|
tablePtr->colPixels[i] += (i==lastUnpreset)?lastPad:pad;
|
1908 |
|
|
}
|
1909 |
|
|
tablePtr->colStarts[i] = total;
|
1910 |
|
|
total += tablePtr->colPixels[i];
|
1911 |
|
|
}
|
1912 |
|
|
}
|
1913 |
|
|
tablePtr->colStarts[i] = tablePtr->maxWidth = total;
|
1914 |
|
|
|
1915 |
|
|
/*
|
1916 |
|
|
* The 'do' loop is only necessary for rows because of FILL mode
|
1917 |
|
|
*/
|
1918 |
|
|
do {
|
1919 |
|
|
/* Set up the arrays to hold the row pixels and starts */
|
1920 |
|
|
/* FIX - this can be moved outside 'do' if you check >row size */
|
1921 |
|
|
if (tablePtr->rowPixels) ckfree((char *) tablePtr->rowPixels);
|
1922 |
|
|
tablePtr->rowPixels = (int *) ckalloc(tablePtr->rows * sizeof(int));
|
1923 |
|
|
|
1924 |
|
|
/* get all the preset rows and set their heights */
|
1925 |
|
|
lastUnpreset = 0;
|
1926 |
|
|
numPixels = 0;
|
1927 |
|
|
unpreset = 0;
|
1928 |
|
|
for (i = 0; i < tablePtr->rows; i++) {
|
1929 |
|
|
if ((entryPtr = Tcl_FindHashEntry(tablePtr->rowHeights,
|
1930 |
|
|
(char *) i)) == NULL) {
|
1931 |
|
|
tablePtr->rowPixels[i] = -1;
|
1932 |
|
|
unpreset++;
|
1933 |
|
|
lastUnpreset = i;
|
1934 |
|
|
} else {
|
1935 |
|
|
value = (int) Tcl_GetHashValue(entryPtr);
|
1936 |
|
|
if (value <= 0) {
|
1937 |
|
|
tablePtr->rowPixels[i] = -value + bd;
|
1938 |
|
|
} else {
|
1939 |
|
|
tablePtr->rowPixels[i] = value * tablePtr->charHeight + bd;
|
1940 |
|
|
}
|
1941 |
|
|
numPixels += tablePtr->rowPixels[i];
|
1942 |
|
|
}
|
1943 |
|
|
}
|
1944 |
|
|
|
1945 |
|
|
/* work out how much to pad each row depending on the mode */
|
1946 |
|
|
diff = h-numPixels-(unpreset*defRowHeight);
|
1947 |
|
|
switch(tablePtr->rowStretch) {
|
1948 |
|
|
case STRETCH_MODE_NONE:
|
1949 |
|
|
pad = 0;
|
1950 |
|
|
lastPad = 0;
|
1951 |
|
|
break;
|
1952 |
|
|
case STRETCH_MODE_UNSET:
|
1953 |
|
|
if (unpreset == 0) {
|
1954 |
|
|
pad = 0;
|
1955 |
|
|
lastPad = 0;
|
1956 |
|
|
} else {
|
1957 |
|
|
pad = MAX(0,diff) / unpreset;
|
1958 |
|
|
lastPad = MAX(0,diff) - pad * (unpreset - 1);
|
1959 |
|
|
}
|
1960 |
|
|
break;
|
1961 |
|
|
case STRETCH_MODE_LAST:
|
1962 |
|
|
pad = 0;
|
1963 |
|
|
lastPad = MAX(0,diff);
|
1964 |
|
|
/* force it to be applied to the last column too */
|
1965 |
|
|
lastUnpreset = tablePtr->rows - 1;
|
1966 |
|
|
break;
|
1967 |
|
|
case STRETCH_MODE_FILL:
|
1968 |
|
|
pad = 0;
|
1969 |
|
|
lastPad = diff;
|
1970 |
|
|
if (diff && !recalc) {
|
1971 |
|
|
tablePtr->rows += (diff/defRowHeight);
|
1972 |
|
|
if (diff < 0 && tablePtr->rows < 0)
|
1973 |
|
|
tablePtr->rows = 0;
|
1974 |
|
|
lastUnpreset = tablePtr->rows - 1;
|
1975 |
|
|
recalc = 1;
|
1976 |
|
|
continue;
|
1977 |
|
|
} else {
|
1978 |
|
|
lastUnpreset = tablePtr->rows - 1;
|
1979 |
|
|
recalc = 0;
|
1980 |
|
|
}
|
1981 |
|
|
break;
|
1982 |
|
|
default: /* STRETCH_MODE_ALL */
|
1983 |
|
|
pad = MAX(0,diff) / tablePtr->rows;
|
1984 |
|
|
/* force it to be applied to the last column too */
|
1985 |
|
|
lastUnpreset = tablePtr->rows - 1;
|
1986 |
|
|
lastPad = MAX(0,diff) - pad * lastUnpreset;
|
1987 |
|
|
}
|
1988 |
|
|
} while (recalc);
|
1989 |
|
|
|
1990 |
|
|
if (tablePtr->rowStarts) ckfree((char *) tablePtr->rowStarts);
|
1991 |
|
|
tablePtr->rowStarts = (int *) ckalloc((tablePtr->rows+1)*sizeof(int));
|
1992 |
|
|
/* now do the padding and calculate the row starts */
|
1993 |
|
|
total = 0;
|
1994 |
|
|
for (i = 0; i < tablePtr->rows; i++) {
|
1995 |
|
|
if (tablePtr->rowPixels[i] == -1) {
|
1996 |
|
|
tablePtr->rowPixels[i] = defRowHeight
|
1997 |
|
|
+ ((i==lastUnpreset)?lastPad:pad);
|
1998 |
|
|
} else if (tablePtr->rowStretch == STRETCH_MODE_ALL) {
|
1999 |
|
|
tablePtr->rowPixels[i] += (i==lastUnpreset)?lastPad:pad;
|
2000 |
|
|
}
|
2001 |
|
|
/* calculate the start of each row */
|
2002 |
|
|
tablePtr->rowStarts[i] = total;
|
2003 |
|
|
total += tablePtr->rowPixels[i];
|
2004 |
|
|
}
|
2005 |
|
|
tablePtr->rowStarts[i] = tablePtr->maxHeight = total;
|
2006 |
|
|
|
2007 |
|
|
/* make sure the top row and col have reasonable real indices */
|
2008 |
|
|
tablePtr->topRow = topRow =
|
2009 |
|
|
MAX(tablePtr->titleRows, MIN(tablePtr->topRow, tablePtr->rows-1));
|
2010 |
|
|
tablePtr->leftCol = leftCol =
|
2011 |
|
|
MAX(tablePtr->titleCols, MIN(tablePtr->leftCol, tablePtr->cols-1));
|
2012 |
|
|
|
2013 |
|
|
/* If we dont have the info, dont bother to fix up the other parameters */
|
2014 |
|
|
if (Tk_WindowId(tablePtr->tkwin) == None) {
|
2015 |
|
|
tablePtr->oldTopRow = tablePtr->oldLeftCol = -1;
|
2016 |
|
|
return;
|
2017 |
|
|
}
|
2018 |
|
|
|
2019 |
|
|
w += hl;
|
2020 |
|
|
h += hl;
|
2021 |
|
|
/*
|
2022 |
|
|
* If we use this value of topRow, will we fill the window?
|
2023 |
|
|
* if not, decrease it until we will, or until it gets to titleRows
|
2024 |
|
|
* make sure we don't cut off the bottom row
|
2025 |
|
|
*/
|
2026 |
|
|
for (; topRow > tablePtr->titleRows; topRow--)
|
2027 |
|
|
if ((tablePtr->maxHeight-(tablePtr->rowStarts[topRow-1] -
|
2028 |
|
|
tablePtr->rowStarts[tablePtr->titleRows])) > h)
|
2029 |
|
|
break;
|
2030 |
|
|
/*
|
2031 |
|
|
* If we use this value of topCol, will we fill the window?
|
2032 |
|
|
* if not, decrease it until we will, or until it gets to titleCols
|
2033 |
|
|
* make sure we don't cut off the left column
|
2034 |
|
|
*/
|
2035 |
|
|
for (; leftCol > tablePtr->titleCols; leftCol--)
|
2036 |
|
|
if ((tablePtr->maxWidth-(tablePtr->colStarts[leftCol-1] -
|
2037 |
|
|
tablePtr->colStarts[tablePtr->titleCols])) > w)
|
2038 |
|
|
break;
|
2039 |
|
|
|
2040 |
|
|
tablePtr->topRow = topRow;
|
2041 |
|
|
tablePtr->leftCol = leftCol;
|
2042 |
|
|
|
2043 |
|
|
/* Now work out where the bottom right for scrollbar update
|
2044 |
|
|
* and testing for one last stretch */
|
2045 |
|
|
TableGetLastCell(tablePtr, &row, &col);
|
2046 |
|
|
TableCellVCoords(tablePtr, row, col, &x, &y, &width, &height, 0);
|
2047 |
|
|
|
2048 |
|
|
/*
|
2049 |
|
|
* Do we have scrollbars, if so, calculate and call the TCL functions In
|
2050 |
|
|
* order to get the scrollbar to be completely full when the whole screen
|
2051 |
|
|
* is shown and there are titles, we have to arrange for the scrollbar
|
2052 |
|
|
* range to be 0 -> rows-titleRows etc. This leads to the position
|
2053 |
|
|
* setting methods, toprow and leftcol, being relative to the titles, not
|
2054 |
|
|
* absolute row and column numbers.
|
2055 |
|
|
*/
|
2056 |
|
|
if (tablePtr->yScrollCmd != NULL || tablePtr->xScrollCmd != NULL) {
|
2057 |
|
|
Tcl_Interp *interp = tablePtr->interp;
|
2058 |
|
|
char buf[INDEX_BUFSIZE];
|
2059 |
|
|
double first, last;
|
2060 |
|
|
|
2061 |
|
|
/*
|
2062 |
|
|
* We must hold onto the interpreter because the data referred to at
|
2063 |
|
|
* tablePtr might be freed as a result of the call to Tcl_VarEval.
|
2064 |
|
|
*/
|
2065 |
|
|
Tcl_Preserve((ClientData) interp);
|
2066 |
|
|
|
2067 |
|
|
/* Do we have a Y-scrollbar and rows to scroll? */
|
2068 |
|
|
if (tablePtr->yScrollCmd != NULL) {
|
2069 |
|
|
if (row < tablePtr->titleRows) {
|
2070 |
|
|
first = 0;
|
2071 |
|
|
last = 1;
|
2072 |
|
|
} else {
|
2073 |
|
|
diff = tablePtr->rowStarts[tablePtr->titleRows];
|
2074 |
|
|
last = (double) (tablePtr->rowStarts[tablePtr->rows]-diff);
|
2075 |
|
|
first = (tablePtr->rowStarts[topRow]-diff) / last;
|
2076 |
|
|
last = (height+tablePtr->rowStarts[row]-diff) / last;
|
2077 |
|
|
}
|
2078 |
|
|
sprintf(buf, " %g %g", first, last);
|
2079 |
|
|
if (Tcl_VarEval(interp, tablePtr->yScrollCmd,
|
2080 |
|
|
buf, (char *) NULL) != TCL_OK) {
|
2081 |
|
|
Tcl_AddErrorInfo(interp,
|
2082 |
|
|
"\n (vertical scrolling command executed by table)");
|
2083 |
|
|
Tcl_BackgroundError(interp);
|
2084 |
|
|
}
|
2085 |
|
|
}
|
2086 |
|
|
/* Do we have a X-scrollbar and cols to scroll? */
|
2087 |
|
|
if (tablePtr->xScrollCmd != NULL) {
|
2088 |
|
|
if (col < tablePtr->titleCols) {
|
2089 |
|
|
first = 0;
|
2090 |
|
|
last = 1;
|
2091 |
|
|
} else {
|
2092 |
|
|
diff = tablePtr->colStarts[tablePtr->titleCols];
|
2093 |
|
|
last = (double) (tablePtr->colStarts[tablePtr->cols]-diff);
|
2094 |
|
|
first = (tablePtr->colStarts[leftCol]-diff) / last;
|
2095 |
|
|
last = (width+tablePtr->colStarts[col]-diff) / last;
|
2096 |
|
|
}
|
2097 |
|
|
sprintf(buf, " %g %g", first, last);
|
2098 |
|
|
if (Tcl_VarEval(interp, tablePtr->xScrollCmd,
|
2099 |
|
|
buf, (char *) NULL) != TCL_OK) {
|
2100 |
|
|
Tcl_AddErrorInfo(interp,
|
2101 |
|
|
"\n (horizontal scrolling command executed by table)");
|
2102 |
|
|
Tcl_BackgroundError(interp);
|
2103 |
|
|
}
|
2104 |
|
|
}
|
2105 |
|
|
|
2106 |
|
|
Tcl_Release((ClientData) interp);
|
2107 |
|
|
}
|
2108 |
|
|
|
2109 |
|
|
/* Adjust the last row/col to fill empty space if it is visible */
|
2110 |
|
|
/* do this after setting the scrollbars to not upset its calculations */
|
2111 |
|
|
if (row == tablePtr->rows-1 && tablePtr->rowStretch != STRETCH_MODE_NONE) {
|
2112 |
|
|
diff = h-(y+height);
|
2113 |
|
|
if (diff > 0) {
|
2114 |
|
|
tablePtr->rowPixels[tablePtr->rows-1] += diff;
|
2115 |
|
|
tablePtr->rowStarts[tablePtr->rows] += diff;
|
2116 |
|
|
}
|
2117 |
|
|
}
|
2118 |
|
|
if (col == tablePtr->cols-1 && tablePtr->colStretch != STRETCH_MODE_NONE) {
|
2119 |
|
|
diff = w-(x+width);
|
2120 |
|
|
if (diff > 0) {
|
2121 |
|
|
tablePtr->colPixels[tablePtr->cols-1] += diff;
|
2122 |
|
|
tablePtr->colStarts[tablePtr->cols] += diff;
|
2123 |
|
|
}
|
2124 |
|
|
}
|
2125 |
|
|
|
2126 |
|
|
TableAdjustActive(tablePtr);
|
2127 |
|
|
|
2128 |
|
|
/*
|
2129 |
|
|
* now check the new value of topleft cell against the originals,
|
2130 |
|
|
* If they changed, invalidate the area, else leave it alone
|
2131 |
|
|
*/
|
2132 |
|
|
if (tablePtr->topRow != tablePtr->oldTopRow ||
|
2133 |
|
|
tablePtr->leftCol != tablePtr->oldLeftCol) {
|
2134 |
|
|
/* set the old top row/col for the next time this function is called */
|
2135 |
|
|
tablePtr->oldTopRow = tablePtr->topRow;
|
2136 |
|
|
tablePtr->oldLeftCol = tablePtr->leftCol;
|
2137 |
|
|
/* only the upper corner title cells wouldn't change */
|
2138 |
|
|
TableInvalidateAll(tablePtr, 0);
|
2139 |
|
|
}
|
2140 |
|
|
}
|
2141 |
|
|
|
2142 |
|
|
/*
|
2143 |
|
|
*----------------------------------------------------------------------
|
2144 |
|
|
*
|
2145 |
|
|
* TableCursorEvent --
|
2146 |
|
|
* Toggle the cursor status. Equivalent to EntryBlinkProc.
|
2147 |
|
|
*
|
2148 |
|
|
* Results:
|
2149 |
|
|
* None.
|
2150 |
|
|
*
|
2151 |
|
|
* Side effects:
|
2152 |
|
|
* The cursor will be switched off/on.
|
2153 |
|
|
*
|
2154 |
|
|
*----------------------------------------------------------------------
|
2155 |
|
|
*/
|
2156 |
|
|
static void
|
2157 |
|
|
TableCursorEvent(ClientData clientData)
|
2158 |
|
|
{
|
2159 |
|
|
register Table *tablePtr = (Table *) clientData;
|
2160 |
|
|
|
2161 |
|
|
if (!(tablePtr->flags & HAS_FOCUS) || (tablePtr->insertOffTime == 0)) {
|
2162 |
|
|
return;
|
2163 |
|
|
}
|
2164 |
|
|
|
2165 |
|
|
if (tablePtr->cursorTimer != NULL)
|
2166 |
|
|
Tcl_DeleteTimerHandler(tablePtr->cursorTimer);
|
2167 |
|
|
|
2168 |
|
|
tablePtr->cursorTimer =
|
2169 |
|
|
Tcl_CreateTimerHandler((tablePtr->flags & CURSOR_ON) ?
|
2170 |
|
|
tablePtr->insertOffTime : tablePtr->insertOnTime,
|
2171 |
|
|
TableCursorEvent, (ClientData) tablePtr);
|
2172 |
|
|
/* Toggle the cursor */
|
2173 |
|
|
tablePtr->flags ^= CURSOR_ON;
|
2174 |
|
|
|
2175 |
|
|
/* invalidate the cell */
|
2176 |
|
|
TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol,
|
2177 |
|
|
CELL|INV_FORCE);
|
2178 |
|
|
}
|
2179 |
|
|
|
2180 |
|
|
/*
|
2181 |
|
|
*----------------------------------------------------------------------
|
2182 |
|
|
*
|
2183 |
|
|
* TableConfigCursor --
|
2184 |
|
|
* Configures the timer depending on the state of the table.
|
2185 |
|
|
* Equivalent to EntryFocusProc.
|
2186 |
|
|
*
|
2187 |
|
|
* Results:
|
2188 |
|
|
* None.
|
2189 |
|
|
*
|
2190 |
|
|
* Side effects:
|
2191 |
|
|
* The cursor will be switched off/on.
|
2192 |
|
|
*
|
2193 |
|
|
*----------------------------------------------------------------------
|
2194 |
|
|
*/
|
2195 |
|
|
static void
|
2196 |
|
|
TableConfigCursor(register Table *tablePtr)
|
2197 |
|
|
{
|
2198 |
|
|
/* to get a cursor, we have to have focus and allow edits */
|
2199 |
|
|
if ((tablePtr->flags & HAS_FOCUS) && !(tablePtr->flags & ACTIVE_DISABLED) &&
|
2200 |
|
|
(tablePtr->state == STATE_NORMAL)) {
|
2201 |
|
|
/* turn the cursor on */
|
2202 |
|
|
if (!(tablePtr->flags & CURSOR_ON)) {
|
2203 |
|
|
tablePtr->flags |= CURSOR_ON;
|
2204 |
|
|
}
|
2205 |
|
|
|
2206 |
|
|
/* set up the first timer */
|
2207 |
|
|
if (tablePtr->insertOffTime != 0) {
|
2208 |
|
|
/* make sure nothing existed */
|
2209 |
|
|
Tcl_DeleteTimerHandler(tablePtr->cursorTimer);
|
2210 |
|
|
tablePtr->cursorTimer = Tcl_CreateTimerHandler(tablePtr->insertOnTime,
|
2211 |
|
|
TableCursorEvent,
|
2212 |
|
|
(ClientData) tablePtr);
|
2213 |
|
|
}
|
2214 |
|
|
|
2215 |
|
|
} else {
|
2216 |
|
|
/* turn the cursor off */
|
2217 |
|
|
if ((tablePtr->flags & CURSOR_ON)) {
|
2218 |
|
|
tablePtr->flags &= ~CURSOR_ON;
|
2219 |
|
|
}
|
2220 |
|
|
|
2221 |
|
|
/* and disable the timer */
|
2222 |
|
|
if (tablePtr->cursorTimer != NULL)
|
2223 |
|
|
Tcl_DeleteTimerHandler(tablePtr->cursorTimer);
|
2224 |
|
|
tablePtr->cursorTimer = NULL;
|
2225 |
|
|
}
|
2226 |
|
|
|
2227 |
|
|
/* Invalidate the selection window to show or hide the cursor */
|
2228 |
|
|
TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol,
|
2229 |
|
|
CELL|INV_FORCE);
|
2230 |
|
|
}
|
2231 |
|
|
|
2232 |
|
|
/*
|
2233 |
|
|
*----------------------------------------------------------------------
|
2234 |
|
|
*
|
2235 |
|
|
* TableFetchSelection --
|
2236 |
|
|
* This procedure is called back by Tk when the selection is
|
2237 |
|
|
* requested by someone. It returns part or all of the selection
|
2238 |
|
|
* in a buffer provided by the caller.
|
2239 |
|
|
*
|
2240 |
|
|
* Results:
|
2241 |
|
|
* The return value is the number of non-NULL bytes stored
|
2242 |
|
|
* at buffer. Buffer is filled (or partially filled) with a
|
2243 |
|
|
* NULL-terminated string containing part or all of the selection,
|
2244 |
|
|
* as given by offset and maxBytes.
|
2245 |
|
|
*
|
2246 |
|
|
* Side effects:
|
2247 |
|
|
* None.
|
2248 |
|
|
*
|
2249 |
|
|
*----------------------------------------------------------------------
|
2250 |
|
|
*/
|
2251 |
|
|
static int
|
2252 |
|
|
TableFetchSelection(clientData, offset, buffer, maxBytes)
|
2253 |
|
|
ClientData clientData; /* Information about table widget. */
|
2254 |
|
|
int offset; /* Offset within selection of first
|
2255 |
|
|
* character to be returned. */
|
2256 |
|
|
char *buffer; /* Location in which to place
|
2257 |
|
|
* selection. */
|
2258 |
|
|
int maxBytes; /* Maximum number of bytes to place
|
2259 |
|
|
* at buffer, not including terminating
|
2260 |
|
|
* NULL character. */
|
2261 |
|
|
{
|
2262 |
|
|
register Table *tablePtr = (Table *) clientData;
|
2263 |
|
|
Tcl_Interp *interp = tablePtr->interp;
|
2264 |
|
|
char *value, *data, *rowsep = tablePtr->rowSep, *colsep = tablePtr->colSep;
|
2265 |
|
|
Tcl_DString selection;
|
2266 |
|
|
Tcl_HashEntry *entryPtr;
|
2267 |
|
|
Tcl_HashSearch search;
|
2268 |
|
|
int length, count, lastrow=0, needcs=0, r, c, listArgc, rslen=0, cslen=0;
|
2269 |
|
|
int numcols, numrows;
|
2270 |
|
|
char **listArgv;
|
2271 |
|
|
|
2272 |
|
|
/* if we are not exporting the selection || we have no data source, return */
|
2273 |
|
|
if (!tablePtr->exportSelection ||
|
2274 |
|
|
(tablePtr->dataSource == DATA_NONE)) {
|
2275 |
|
|
return -1;
|
2276 |
|
|
}
|
2277 |
|
|
|
2278 |
|
|
/* First get a sorted list of the selected elements */
|
2279 |
|
|
Tcl_DStringInit(&selection);
|
2280 |
|
|
for (entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search);
|
2281 |
|
|
entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
|
2282 |
|
|
Tcl_DStringAppendElement(&selection,
|
2283 |
|
|
Tcl_GetHashKey(tablePtr->selCells, entryPtr));
|
2284 |
|
|
}
|
2285 |
|
|
value = TableCellSort(tablePtr, Tcl_DStringValue(&selection));
|
2286 |
|
|
Tcl_DStringFree(&selection);
|
2287 |
|
|
|
2288 |
|
|
if (value == NULL ||
|
2289 |
|
|
Tcl_SplitList(interp, value, &listArgc, &listArgv) != TCL_OK) {
|
2290 |
|
|
return -1;
|
2291 |
|
|
}
|
2292 |
|
|
ckfree(value);
|
2293 |
|
|
|
2294 |
|
|
Tcl_DStringInit(&selection);
|
2295 |
|
|
rslen = (rowsep?(strlen(rowsep)):0);
|
2296 |
|
|
cslen = (colsep?(strlen(colsep)):0);
|
2297 |
|
|
numrows = numcols = 0;
|
2298 |
|
|
for (count = 0; count < listArgc; count++) {
|
2299 |
|
|
TableParseArrayIndex(&r, &c, listArgv[count]);
|
2300 |
|
|
if (count) {
|
2301 |
|
|
if (lastrow != r) {
|
2302 |
|
|
lastrow = r;
|
2303 |
|
|
needcs = 0;
|
2304 |
|
|
if (rslen) {
|
2305 |
|
|
Tcl_DStringAppend(&selection, rowsep, rslen);
|
2306 |
|
|
} else {
|
2307 |
|
|
Tcl_DStringEndSublist(&selection);
|
2308 |
|
|
Tcl_DStringStartSublist(&selection);
|
2309 |
|
|
}
|
2310 |
|
|
++numrows;
|
2311 |
|
|
} else {
|
2312 |
|
|
if (++needcs > numcols)
|
2313 |
|
|
numcols = needcs;
|
2314 |
|
|
}
|
2315 |
|
|
} else {
|
2316 |
|
|
lastrow = r;
|
2317 |
|
|
needcs = 0;
|
2318 |
|
|
if (!rslen)
|
2319 |
|
|
Tcl_DStringStartSublist(&selection);
|
2320 |
|
|
}
|
2321 |
|
|
data = TableGetCellValue(tablePtr, r, c);
|
2322 |
|
|
if (cslen) {
|
2323 |
|
|
if (needcs)
|
2324 |
|
|
Tcl_DStringAppend(&selection, colsep, cslen);
|
2325 |
|
|
Tcl_DStringAppend(&selection, data, -1);
|
2326 |
|
|
} else {
|
2327 |
|
|
Tcl_DStringAppendElement(&selection, data);
|
2328 |
|
|
}
|
2329 |
|
|
}
|
2330 |
|
|
if (!rslen && count)
|
2331 |
|
|
Tcl_DStringEndSublist(&selection);
|
2332 |
|
|
ckfree((char *) listArgv);
|
2333 |
|
|
|
2334 |
|
|
if (tablePtr->selCmd != NULL) {
|
2335 |
|
|
Tcl_DString script;
|
2336 |
|
|
Tcl_DStringInit(&script);
|
2337 |
|
|
ExpandPercents(tablePtr, tablePtr->selCmd, numrows+1, numcols+1,
|
2338 |
|
|
Tcl_DStringValue(&selection), (char *) NULL,
|
2339 |
|
|
listArgc, &script, CMD_ACTIVATE);
|
2340 |
|
|
if (Tcl_GlobalEval(interp, Tcl_DStringValue(&script)) == TCL_ERROR) {
|
2341 |
|
|
Tcl_AddErrorInfo(interp,
|
2342 |
|
|
"\n (error in table selection command)");
|
2343 |
|
|
Tcl_BackgroundError(interp);
|
2344 |
|
|
Tcl_DStringFree(&script);
|
2345 |
|
|
Tcl_DStringFree(&selection);
|
2346 |
|
|
return -1;
|
2347 |
|
|
} else {
|
2348 |
|
|
Tcl_DStringGetResult(interp, &selection);
|
2349 |
|
|
}
|
2350 |
|
|
Tcl_DStringFree(&script);
|
2351 |
|
|
}
|
2352 |
|
|
|
2353 |
|
|
length = Tcl_DStringLength(&selection);
|
2354 |
|
|
|
2355 |
|
|
if (length == 0)
|
2356 |
|
|
return -1;
|
2357 |
|
|
|
2358 |
|
|
/* Copy the requested portion of the selection to the buffer. */
|
2359 |
|
|
count = length - offset;
|
2360 |
|
|
if (count <= 0) {
|
2361 |
|
|
count = 0;
|
2362 |
|
|
} else {
|
2363 |
|
|
if (count > maxBytes) {
|
2364 |
|
|
count = maxBytes;
|
2365 |
|
|
}
|
2366 |
|
|
memcpy((VOID *) buffer, (VOID *) (Tcl_DStringValue(&selection) + offset),
|
2367 |
|
|
(size_t) count);
|
2368 |
|
|
}
|
2369 |
|
|
buffer[count] = '\0';
|
2370 |
|
|
Tcl_DStringFree(&selection);
|
2371 |
|
|
return count;
|
2372 |
|
|
}
|
2373 |
|
|
|
2374 |
|
|
/*
|
2375 |
|
|
*----------------------------------------------------------------------
|
2376 |
|
|
*
|
2377 |
|
|
* TableLostSelection --
|
2378 |
|
|
* This procedure is called back by Tk when the selection is
|
2379 |
|
|
* grabbed away from a table widget.
|
2380 |
|
|
*
|
2381 |
|
|
* Results:
|
2382 |
|
|
* None.
|
2383 |
|
|
*
|
2384 |
|
|
* Side effects:
|
2385 |
|
|
* The existing selection is unhighlighted, and the window is
|
2386 |
|
|
* marked as not containing a selection.
|
2387 |
|
|
*
|
2388 |
|
|
*----------------------------------------------------------------------
|
2389 |
|
|
*/
|
2390 |
|
|
static void
|
2391 |
|
|
TableLostSelection(clientData)
|
2392 |
|
|
ClientData clientData; /* Information about table widget. */
|
2393 |
|
|
{
|
2394 |
|
|
register Table *tablePtr = (Table *) clientData;
|
2395 |
|
|
|
2396 |
|
|
if (tablePtr->exportSelection) {
|
2397 |
|
|
Tcl_HashEntry *entryPtr;
|
2398 |
|
|
Tcl_HashSearch search;
|
2399 |
|
|
int row, col;
|
2400 |
|
|
|
2401 |
|
|
/* Same as SEL CLEAR ALL */
|
2402 |
|
|
for (entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search);
|
2403 |
|
|
entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
|
2404 |
|
|
TableParseArrayIndex(&row, &col,
|
2405 |
|
|
Tcl_GetHashKey(tablePtr->selCells,entryPtr));
|
2406 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
2407 |
|
|
TableRefresh(tablePtr, row-tablePtr->rowOffset,
|
2408 |
|
|
col-tablePtr->colOffset, CELL);
|
2409 |
|
|
}
|
2410 |
|
|
}
|
2411 |
|
|
}
|
2412 |
|
|
|
2413 |
|
|
/*
|
2414 |
|
|
*----------------------------------------------------------------------
|
2415 |
|
|
*
|
2416 |
|
|
* TableRestrictProc --
|
2417 |
|
|
* A Tk_RestrictProc used by TableValidateChange to eliminate any
|
2418 |
|
|
* extra key input events in the event queue that
|
2419 |
|
|
* have a serial number no less than a given value.
|
2420 |
|
|
*
|
2421 |
|
|
* Results:
|
2422 |
|
|
* Returns either TK_DISCARD_EVENT or TK_DEFER_EVENT.
|
2423 |
|
|
*
|
2424 |
|
|
* Side effects:
|
2425 |
|
|
* None.
|
2426 |
|
|
*
|
2427 |
|
|
*----------------------------------------------------------------------
|
2428 |
|
|
*/
|
2429 |
|
|
static Tk_RestrictAction
|
2430 |
|
|
TableRestrictProc(serial, eventPtr)
|
2431 |
|
|
ClientData serial;
|
2432 |
|
|
XEvent *eventPtr;
|
2433 |
|
|
{
|
2434 |
|
|
if ((eventPtr->type == KeyRelease || eventPtr->type == KeyPress) &&
|
2435 |
|
|
((eventPtr->xany.serial-(unsigned int)serial) > 0)) {
|
2436 |
|
|
return TK_DEFER_EVENT;
|
2437 |
|
|
} else {
|
2438 |
|
|
return TK_PROCESS_EVENT;
|
2439 |
|
|
}
|
2440 |
|
|
}
|
2441 |
|
|
|
2442 |
|
|
/*
|
2443 |
|
|
*--------------------------------------------------------------
|
2444 |
|
|
*
|
2445 |
|
|
* TableValidateChange --
|
2446 |
|
|
* This procedure is invoked when any character is added or
|
2447 |
|
|
* removed from the table widget, or a set has triggered validation.
|
2448 |
|
|
*
|
2449 |
|
|
* Results:
|
2450 |
|
|
* TCL_OK if the validatecommand accepts the new string,
|
2451 |
|
|
* TCL_BREAK if the validatecommand rejects the new string,
|
2452 |
|
|
* TCL_ERROR if any problems occured with validatecommand.
|
2453 |
|
|
*
|
2454 |
|
|
* Side effects:
|
2455 |
|
|
* The insertion/deletion may be aborted, and the
|
2456 |
|
|
* validatecommand might turn itself off (if an error
|
2457 |
|
|
* or loop condition arises).
|
2458 |
|
|
*
|
2459 |
|
|
*--------------------------------------------------------------
|
2460 |
|
|
*/
|
2461 |
|
|
static int
|
2462 |
|
|
TableValidateChange(tablePtr, r, c, old, new, index)
|
2463 |
|
|
register Table *tablePtr; /* Table that needs validation. */
|
2464 |
|
|
int r, c; /* row,col index of cell in user coords */
|
2465 |
|
|
char *old; /* current value of cell */
|
2466 |
|
|
char *new; /* potential new value of cell */
|
2467 |
|
|
int index; /* index of insert/delete, -1 otherwise */
|
2468 |
|
|
{
|
2469 |
|
|
register Tcl_Interp *interp = tablePtr->interp;
|
2470 |
|
|
int code, bool;
|
2471 |
|
|
Tk_RestrictProc *restrict;
|
2472 |
|
|
ClientData cdata;
|
2473 |
|
|
Tcl_DString script;
|
2474 |
|
|
|
2475 |
|
|
if (tablePtr->valCmd == NULL || tablePtr->validate == 0) {
|
2476 |
|
|
return TCL_OK;
|
2477 |
|
|
}
|
2478 |
|
|
|
2479 |
|
|
/* Magic code to make this bit of code synchronous in the face of
|
2480 |
|
|
* possible new key events */
|
2481 |
|
|
XSync(tablePtr->display, False);
|
2482 |
|
|
restrict = Tk_RestrictEvents(TableRestrictProc, (ClientData)
|
2483 |
|
|
NextRequest(tablePtr->display), &cdata);
|
2484 |
|
|
|
2485 |
|
|
/*
|
2486 |
|
|
* If we're already validating, then we're hitting a loop condition
|
2487 |
|
|
* Return and set validate to 0 to disallow further validations
|
2488 |
|
|
* and prevent current validation from finishing
|
2489 |
|
|
*/
|
2490 |
|
|
if (tablePtr->flags & VALIDATING) {
|
2491 |
|
|
tablePtr->validate = 0;
|
2492 |
|
|
return TCL_OK;
|
2493 |
|
|
}
|
2494 |
|
|
tablePtr->flags |= VALIDATING;
|
2495 |
|
|
|
2496 |
|
|
/* Now form command string and run through the -validatecommand */
|
2497 |
|
|
Tcl_DStringInit(&script);
|
2498 |
|
|
ExpandPercents(tablePtr, tablePtr->valCmd, r, c, old, new, index, &script,
|
2499 |
|
|
CMD_VALIDATE);
|
2500 |
|
|
code = Tcl_GlobalEval(tablePtr->interp, Tcl_DStringValue(&script));
|
2501 |
|
|
Tcl_DStringFree(&script);
|
2502 |
|
|
|
2503 |
|
|
if (code != TCL_OK && code != TCL_RETURN) {
|
2504 |
|
|
Tcl_AddErrorInfo(interp, "\n\t(in validation command executed by table)");
|
2505 |
|
|
Tk_BackgroundError(interp);
|
2506 |
|
|
code = TCL_ERROR;
|
2507 |
|
|
} else if (Tcl_GetBoolean(interp, Tcl_GetStringResult(interp),
|
2508 |
|
|
&bool) != TCL_OK) {
|
2509 |
|
|
Tcl_AddErrorInfo(interp, "\n\tboolean not returned by validation command");
|
2510 |
|
|
Tk_BackgroundError(interp);
|
2511 |
|
|
code = TCL_ERROR;
|
2512 |
|
|
} else {
|
2513 |
|
|
if (bool)
|
2514 |
|
|
code = TCL_OK;
|
2515 |
|
|
else
|
2516 |
|
|
code = TCL_BREAK;
|
2517 |
|
|
}
|
2518 |
|
|
Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
|
2519 |
|
|
|
2520 |
|
|
/*
|
2521 |
|
|
* If ->validate has become VALIDATE_NONE during the validation,
|
2522 |
|
|
* it means that a loop condition almost occured. Do not allow
|
2523 |
|
|
* this validation result to finish.
|
2524 |
|
|
*/
|
2525 |
|
|
if (tablePtr->validate == 0) {
|
2526 |
|
|
code = TCL_ERROR;
|
2527 |
|
|
}
|
2528 |
|
|
|
2529 |
|
|
/* If validate will return ERROR, then disallow further validations */
|
2530 |
|
|
if (code == TCL_ERROR) {
|
2531 |
|
|
tablePtr->validate = 0;
|
2532 |
|
|
}
|
2533 |
|
|
|
2534 |
|
|
Tk_RestrictEvents(restrict, cdata, &cdata);
|
2535 |
|
|
tablePtr->flags &= ~VALIDATING;
|
2536 |
|
|
|
2537 |
|
|
return code;
|
2538 |
|
|
}
|
2539 |
|
|
|
2540 |
|
|
/*
|
2541 |
|
|
*--------------------------------------------------------------
|
2542 |
|
|
*
|
2543 |
|
|
* ExpandPercents --
|
2544 |
|
|
* Given a command and an event, produce a new command
|
2545 |
|
|
* by replacing % constructs in the original command
|
2546 |
|
|
* with information from the X event.
|
2547 |
|
|
*
|
2548 |
|
|
* Results:
|
2549 |
|
|
* The new expanded command is appended to the dynamic string
|
2550 |
|
|
* given by dsPtr.
|
2551 |
|
|
*
|
2552 |
|
|
* Side effects:
|
2553 |
|
|
* None.
|
2554 |
|
|
*
|
2555 |
|
|
*--------------------------------------------------------------
|
2556 |
|
|
*/
|
2557 |
|
|
void
|
2558 |
|
|
ExpandPercents(tablePtr, before, r, c, old, new, index, dsPtr, cmdType)
|
2559 |
|
|
Table *tablePtr; /* Table that needs validation. */
|
2560 |
|
|
char *before; /* Command containing percent
|
2561 |
|
|
* expressions to be replaced. */
|
2562 |
|
|
int r, c; /* row,col index of cell */
|
2563 |
|
|
char *old; /* current value of cell */
|
2564 |
|
|
char *new; /* potential new value of cell */
|
2565 |
|
|
int index; /* index of insert/delete */
|
2566 |
|
|
Tcl_DString *dsPtr; /* Dynamic string in which to append
|
2567 |
|
|
* new command. */
|
2568 |
|
|
int cmdType; /* type of command to make %-subs for */
|
2569 |
|
|
{
|
2570 |
|
|
int spaceNeeded, cvtFlags; /* Used to substitute string as proper Tcl
|
2571 |
|
|
* list element. */
|
2572 |
|
|
int number, length;
|
2573 |
|
|
char *string;
|
2574 |
|
|
char buf[INDEX_BUFSIZE];
|
2575 |
|
|
|
2576 |
|
|
/* This returns the static value of the string as set in the array */
|
2577 |
|
|
if (old == NULL && cmdType == CMD_VALIDATE) {
|
2578 |
|
|
old = TableGetCellValue(tablePtr, r, c);
|
2579 |
|
|
}
|
2580 |
|
|
|
2581 |
|
|
while (1) {
|
2582 |
|
|
/*
|
2583 |
|
|
* Find everything up to the next % character and append it
|
2584 |
|
|
* to the result string.
|
2585 |
|
|
*/
|
2586 |
|
|
for (string = before; (*string != 0) && (*string != '%'); string++) {
|
2587 |
|
|
/* Empty loop body. */
|
2588 |
|
|
}
|
2589 |
|
|
if (string != before) {
|
2590 |
|
|
Tcl_DStringAppend(dsPtr, before, string-before);
|
2591 |
|
|
before = string;
|
2592 |
|
|
}
|
2593 |
|
|
if (*before == 0) break;
|
2594 |
|
|
|
2595 |
|
|
/* There's a percent sequence here. Process it. */
|
2596 |
|
|
number = 0;
|
2597 |
|
|
string = "??";
|
2598 |
|
|
/* cmdType independent substitutions */
|
2599 |
|
|
switch (before[1]) {
|
2600 |
|
|
case 'c':
|
2601 |
|
|
number = c;
|
2602 |
|
|
goto doNumber;
|
2603 |
|
|
case 'C': /* index of cell */
|
2604 |
|
|
TableMakeArrayIndex(r, c, buf);
|
2605 |
|
|
string = buf;
|
2606 |
|
|
goto doString;
|
2607 |
|
|
case 'r':
|
2608 |
|
|
number = r;
|
2609 |
|
|
goto doNumber;
|
2610 |
|
|
case 'i': /* index of cursor OR |number| of cells selected */
|
2611 |
|
|
number = index;
|
2612 |
|
|
goto doNumber;
|
2613 |
|
|
case 's': /* Current cell value */
|
2614 |
|
|
string = old;
|
2615 |
|
|
goto doString;
|
2616 |
|
|
case 'S': /* Potential new value of cell */
|
2617 |
|
|
string = (new?new:old);
|
2618 |
|
|
goto doString;
|
2619 |
|
|
case 'W': /* widget name */
|
2620 |
|
|
string = Tk_PathName(tablePtr->tkwin);
|
2621 |
|
|
goto doString;
|
2622 |
|
|
default:
|
2623 |
|
|
buf[0] = before[1];
|
2624 |
|
|
buf[1] = '\0';
|
2625 |
|
|
string = buf;
|
2626 |
|
|
goto doString;
|
2627 |
|
|
}
|
2628 |
|
|
|
2629 |
|
|
doNumber:
|
2630 |
|
|
sprintf(buf, "%d", number);
|
2631 |
|
|
string = buf;
|
2632 |
|
|
|
2633 |
|
|
doString:
|
2634 |
|
|
spaceNeeded = Tcl_ScanElement(string, &cvtFlags);
|
2635 |
|
|
length = Tcl_DStringLength(dsPtr);
|
2636 |
|
|
Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
|
2637 |
|
|
spaceNeeded = Tcl_ConvertElement(string, Tcl_DStringValue(dsPtr) + length,
|
2638 |
|
|
cvtFlags | TCL_DONT_USE_BRACES);
|
2639 |
|
|
Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
|
2640 |
|
|
before += 2;
|
2641 |
|
|
}
|
2642 |
|
|
Tcl_DStringAppend(dsPtr, "", 1);
|
2643 |
|
|
}
|
2644 |
|
|
|
2645 |
|
|
/*
|
2646 |
|
|
*----------------------------------------------------------------------
|
2647 |
|
|
*
|
2648 |
|
|
* TableDeleteChars --
|
2649 |
|
|
* Remove one or more characters from an table widget.
|
2650 |
|
|
*
|
2651 |
|
|
* Results:
|
2652 |
|
|
* None.
|
2653 |
|
|
*
|
2654 |
|
|
* Side effects:
|
2655 |
|
|
* Memory gets freed, the table gets modified and (eventually)
|
2656 |
|
|
* redisplayed.
|
2657 |
|
|
*
|
2658 |
|
|
*----------------------------------------------------------------------
|
2659 |
|
|
*/
|
2660 |
|
|
static void
|
2661 |
|
|
TableDeleteChars(tablePtr, index, count)
|
2662 |
|
|
register Table *tablePtr; /* Table widget to modify. */
|
2663 |
|
|
int index; /* Index of first character to delete. */
|
2664 |
|
|
int count; /* How many characters to delete. */
|
2665 |
|
|
{
|
2666 |
|
|
int x, y, width, height;
|
2667 |
|
|
#if (TK_MINOR_VERSION > 0)
|
2668 |
|
|
int byteIndex, byteCount, newByteCount, numBytes, numChars;
|
2669 |
|
|
char *new, *string;
|
2670 |
|
|
|
2671 |
|
|
string = tablePtr->activeBuf;
|
2672 |
|
|
numBytes = strlen(string);
|
2673 |
|
|
numChars = Tcl_NumUtfChars(string, numBytes);
|
2674 |
|
|
if ((index + count) > numChars) {
|
2675 |
|
|
count = numChars - index;
|
2676 |
|
|
}
|
2677 |
|
|
if (count <= 0) {
|
2678 |
|
|
return;
|
2679 |
|
|
}
|
2680 |
|
|
|
2681 |
|
|
byteIndex = Tcl_UtfAtIndex(string, index) - string;
|
2682 |
|
|
byteCount = Tcl_UtfAtIndex(string + byteIndex, count) - (string + byteIndex);
|
2683 |
|
|
|
2684 |
|
|
newByteCount = numBytes + 1 - byteCount;
|
2685 |
|
|
new = (char *) ckalloc((unsigned) newByteCount);
|
2686 |
|
|
memcpy(new, string, (size_t) byteIndex);
|
2687 |
|
|
strcpy(new + byteIndex, string + byteIndex + byteCount);
|
2688 |
|
|
#else
|
2689 |
|
|
int oldlen;
|
2690 |
|
|
char *new;
|
2691 |
|
|
|
2692 |
|
|
/* this gets the length of the string, as well as ensuring that
|
2693 |
|
|
* the cursor isn't beyond the end char */
|
2694 |
|
|
TableGetIcursor(tablePtr, "end", &oldlen);
|
2695 |
|
|
|
2696 |
|
|
if ((index+count) > oldlen)
|
2697 |
|
|
count = oldlen-index;
|
2698 |
|
|
if (count <= 0)
|
2699 |
|
|
return;
|
2700 |
|
|
|
2701 |
|
|
new = (char *) ckalloc((unsigned)(oldlen-count+1));
|
2702 |
|
|
strncpy(new, tablePtr->activeBuf, (size_t) index);
|
2703 |
|
|
strcpy(new+index, tablePtr->activeBuf+index+count);
|
2704 |
|
|
/* make sure this string is null terminated */
|
2705 |
|
|
new[oldlen-count] = '\0';
|
2706 |
|
|
#endif
|
2707 |
|
|
/* This prevents deletes on BREAK or validation error. */
|
2708 |
|
|
if (tablePtr->validate &&
|
2709 |
|
|
TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
|
2710 |
|
|
tablePtr->activeCol+tablePtr->colOffset,
|
2711 |
|
|
tablePtr->activeBuf, new, index) != TCL_OK) {
|
2712 |
|
|
ckfree(new);
|
2713 |
|
|
return;
|
2714 |
|
|
}
|
2715 |
|
|
|
2716 |
|
|
ckfree(tablePtr->activeBuf);
|
2717 |
|
|
tablePtr->activeBuf = new;
|
2718 |
|
|
|
2719 |
|
|
/* mark the text as changed */
|
2720 |
|
|
tablePtr->flags |= TEXT_CHANGED;
|
2721 |
|
|
|
2722 |
|
|
if (tablePtr->icursor >= index) {
|
2723 |
|
|
if (tablePtr->icursor >= (index+count)) {
|
2724 |
|
|
tablePtr->icursor -= count;
|
2725 |
|
|
} else {
|
2726 |
|
|
tablePtr->icursor = index;
|
2727 |
|
|
}
|
2728 |
|
|
}
|
2729 |
|
|
|
2730 |
|
|
TableSetActiveIndex(tablePtr);
|
2731 |
|
|
|
2732 |
|
|
TableCellCoords(tablePtr, tablePtr->activeRow, tablePtr->activeCol,
|
2733 |
|
|
&x, &y, &width, &height);
|
2734 |
|
|
TableInvalidate(tablePtr, x, y, width, height, INV_FORCE);
|
2735 |
|
|
}
|
2736 |
|
|
|
2737 |
|
|
/*
|
2738 |
|
|
*----------------------------------------------------------------------
|
2739 |
|
|
*
|
2740 |
|
|
* TableInsertChars --
|
2741 |
|
|
* Add new characters to the active cell of a table widget.
|
2742 |
|
|
*
|
2743 |
|
|
* Results:
|
2744 |
|
|
* None.
|
2745 |
|
|
*
|
2746 |
|
|
* Side effects:
|
2747 |
|
|
* New information gets added to tablePtr; it will be redisplayed
|
2748 |
|
|
* soon, but not necessarily immediately.
|
2749 |
|
|
*
|
2750 |
|
|
*----------------------------------------------------------------------
|
2751 |
|
|
*/
|
2752 |
|
|
static void
|
2753 |
|
|
TableInsertChars(tablePtr, index, value)
|
2754 |
|
|
register Table *tablePtr; /* Table that is to get the new elements. */
|
2755 |
|
|
int index; /* Add the new elements before this element. */
|
2756 |
|
|
char *value; /* New characters to add (NULL-terminated
|
2757 |
|
|
* string). */
|
2758 |
|
|
{
|
2759 |
|
|
#if (TK_MINOR_VERSION > 0)
|
2760 |
|
|
int x, y, width, height, oldlen;
|
2761 |
|
|
int byteIndex, byteCount;
|
2762 |
|
|
char *new, *string;
|
2763 |
|
|
|
2764 |
|
|
string = tablePtr->activeBuf;
|
2765 |
|
|
byteIndex = Tcl_UtfAtIndex(string, index) - string;
|
2766 |
|
|
byteCount = strlen(value);
|
2767 |
|
|
if (byteCount == 0) {
|
2768 |
|
|
return;
|
2769 |
|
|
}
|
2770 |
|
|
|
2771 |
|
|
/* Is this an autoclear and this is the first update */
|
2772 |
|
|
/* Note that this clears without validating */
|
2773 |
|
|
if (tablePtr->autoClear && !(tablePtr->flags & TEXT_CHANGED)) {
|
2774 |
|
|
/* set the buffer to be empty */
|
2775 |
|
|
tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, 1);
|
2776 |
|
|
tablePtr->activeBuf[0] = '\0';
|
2777 |
|
|
/* the insert position now has to be 0 */
|
2778 |
|
|
index = 0;
|
2779 |
|
|
}
|
2780 |
|
|
|
2781 |
|
|
oldlen = strlen(string);
|
2782 |
|
|
new = (char *) ckalloc((unsigned)(oldlen + byteCount + 1));
|
2783 |
|
|
memcpy(new, string, (size_t) byteIndex);
|
2784 |
|
|
strcpy(new + byteIndex, value);
|
2785 |
|
|
strcpy(new + byteIndex + byteCount, string + byteIndex);
|
2786 |
|
|
|
2787 |
|
|
/* validate potential new active buffer */
|
2788 |
|
|
/* This prevents inserts on either BREAK or validation error. */
|
2789 |
|
|
if (tablePtr->validate &&
|
2790 |
|
|
TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
|
2791 |
|
|
tablePtr->activeCol+tablePtr->colOffset,
|
2792 |
|
|
tablePtr->activeBuf, new, byteIndex) != TCL_OK) {
|
2793 |
|
|
ckfree(new);
|
2794 |
|
|
return;
|
2795 |
|
|
}
|
2796 |
|
|
|
2797 |
|
|
/*
|
2798 |
|
|
* The following construction is used because inserting improperly
|
2799 |
|
|
* formed UTF-8 sequences between other improperly formed UTF-8
|
2800 |
|
|
* sequences could result in actually forming valid UTF-8 sequences;
|
2801 |
|
|
* the number of characters added may not be Tcl_NumUtfChars(string, -1),
|
2802 |
|
|
* because of context. The actual number of characters added is how
|
2803 |
|
|
* many characters were are in the string now minus the number that
|
2804 |
|
|
* used to be there.
|
2805 |
|
|
*/
|
2806 |
|
|
|
2807 |
|
|
if (tablePtr->icursor >= index) {
|
2808 |
|
|
tablePtr->icursor += Tcl_NumUtfChars(new, oldlen+byteCount)
|
2809 |
|
|
- Tcl_NumUtfChars(tablePtr->activeBuf, oldlen);
|
2810 |
|
|
}
|
2811 |
|
|
|
2812 |
|
|
ckfree(string);
|
2813 |
|
|
tablePtr->activeBuf = new;
|
2814 |
|
|
|
2815 |
|
|
#else
|
2816 |
|
|
int x, y, width, height, oldlen, newlen;
|
2817 |
|
|
char *new;
|
2818 |
|
|
|
2819 |
|
|
newlen = strlen(value);
|
2820 |
|
|
if (newlen == 0) return;
|
2821 |
|
|
|
2822 |
|
|
/* Is this an autoclear and this is the first update */
|
2823 |
|
|
/* Note that this clears without validating */
|
2824 |
|
|
if (tablePtr->autoClear && !(tablePtr->flags & TEXT_CHANGED)) {
|
2825 |
|
|
/* set the buffer to be empty */
|
2826 |
|
|
tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, 1);
|
2827 |
|
|
tablePtr->activeBuf[0] = '\0';
|
2828 |
|
|
/* the insert position now has to be 0 */
|
2829 |
|
|
index = 0;
|
2830 |
|
|
}
|
2831 |
|
|
oldlen = strlen(tablePtr->activeBuf);
|
2832 |
|
|
/* get the buffer to at least the right length */
|
2833 |
|
|
new = (char *) ckalloc((unsigned)(oldlen+newlen+1));
|
2834 |
|
|
strncpy(new, tablePtr->activeBuf, (size_t) index);
|
2835 |
|
|
strcpy(new+index, value);
|
2836 |
|
|
strcpy(new+index+newlen, (tablePtr->activeBuf)+index);
|
2837 |
|
|
/* make sure this string is null terminated */
|
2838 |
|
|
new[oldlen+newlen] = '\0';
|
2839 |
|
|
|
2840 |
|
|
/* validate potential new active buffer */
|
2841 |
|
|
/* This prevents inserts on either BREAK or validation error. */
|
2842 |
|
|
if (tablePtr->validate &&
|
2843 |
|
|
TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
|
2844 |
|
|
tablePtr->activeCol+tablePtr->colOffset,
|
2845 |
|
|
tablePtr->activeBuf, new, index) != TCL_OK) {
|
2846 |
|
|
ckfree(new);
|
2847 |
|
|
return;
|
2848 |
|
|
}
|
2849 |
|
|
ckfree(tablePtr->activeBuf);
|
2850 |
|
|
tablePtr->activeBuf = new;
|
2851 |
|
|
|
2852 |
|
|
if (tablePtr->icursor >= index) {
|
2853 |
|
|
tablePtr->icursor += newlen;
|
2854 |
|
|
}
|
2855 |
|
|
#endif
|
2856 |
|
|
|
2857 |
|
|
/* mark the text as changed */
|
2858 |
|
|
tablePtr->flags |= TEXT_CHANGED;
|
2859 |
|
|
|
2860 |
|
|
TableSetActiveIndex(tablePtr);
|
2861 |
|
|
|
2862 |
|
|
TableCellCoords(tablePtr, tablePtr->activeRow, tablePtr->activeCol,
|
2863 |
|
|
&x, &y, &width, &height);
|
2864 |
|
|
TableInvalidate(tablePtr, x, y, width, height, INV_FORCE);
|
2865 |
|
|
}
|
2866 |
|
|
|
2867 |
|
|
/*
|
2868 |
|
|
*----------------------------------------------------------------------
|
2869 |
|
|
*
|
2870 |
|
|
* TableModifyRCaux --
|
2871 |
|
|
* Helper function that does the core work of moving rows/cols
|
2872 |
|
|
* and associated tags.
|
2873 |
|
|
*
|
2874 |
|
|
* Results:
|
2875 |
|
|
* None.
|
2876 |
|
|
*
|
2877 |
|
|
* Side effects:
|
2878 |
|
|
* Moves cell data and possibly tag data
|
2879 |
|
|
*
|
2880 |
|
|
*----------------------------------------------------------------------
|
2881 |
|
|
*/
|
2882 |
|
|
static void
|
2883 |
|
|
TableModifyRCaux(tablePtr, type, which, movetag, tagTblPtr, dimTblPtr,
|
2884 |
|
|
offset, from, to, lo, hi, check)
|
2885 |
|
|
Table *tablePtr; /* Information about text widget. */
|
2886 |
|
|
int type; /* insert (CMD_INSERT) | delete (CMD_DELETE) */
|
2887 |
|
|
int which; /* rows (MOD_ROWS) or cols (MOD_COLS) */
|
2888 |
|
|
int movetag; /* whether tags are supposed to be moved */
|
2889 |
|
|
Tcl_HashTable *tagTblPtr, *dimTblPtr; /* Pointers to the row/col tags
|
2890 |
|
|
* and width/height tags */
|
2891 |
|
|
int offset; /* appropriate offset */
|
2892 |
|
|
int from, to; /* the from and to row/col */
|
2893 |
|
|
int lo, hi; /* the lo and hi col/row */
|
2894 |
|
|
int check; /* the boundary check for shifting items */
|
2895 |
|
|
{
|
2896 |
|
|
int j, dummy;
|
2897 |
|
|
char buf[INDEX_BUFSIZE], buf1[INDEX_BUFSIZE];
|
2898 |
|
|
Tcl_HashEntry *entryPtr, *newPtr;
|
2899 |
|
|
|
2900 |
|
|
/* move row/col style && width/height here */
|
2901 |
|
|
if (movetag) {
|
2902 |
|
|
if ((entryPtr=Tcl_FindHashEntry(tagTblPtr, (char *)from)) != NULL) {
|
2903 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
2904 |
|
|
}
|
2905 |
|
|
if ((entryPtr=Tcl_FindHashEntry(dimTblPtr, (char *)from-offset)) != NULL) {
|
2906 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
2907 |
|
|
}
|
2908 |
|
|
if (!check) {
|
2909 |
|
|
if ((entryPtr=Tcl_FindHashEntry(tagTblPtr, (char *)to)) != NULL) {
|
2910 |
|
|
newPtr = Tcl_CreateHashEntry(tagTblPtr, (char *)from, &dummy);
|
2911 |
|
|
Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr));
|
2912 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
2913 |
|
|
}
|
2914 |
|
|
if ((entryPtr=Tcl_FindHashEntry(dimTblPtr, (char *)to-offset)) != NULL) {
|
2915 |
|
|
newPtr = Tcl_CreateHashEntry(dimTblPtr, (char *)from-offset, &dummy);
|
2916 |
|
|
Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr));
|
2917 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
2918 |
|
|
}
|
2919 |
|
|
}
|
2920 |
|
|
}
|
2921 |
|
|
for (j = lo; j <= hi; j++) {
|
2922 |
|
|
if (which == MOD_COLS) {
|
2923 |
|
|
TableMakeArrayIndex(j, from, buf);
|
2924 |
|
|
TableMakeArrayIndex(j, to, buf1);
|
2925 |
|
|
TableSetCellValue(tablePtr, j, from, check ? "" :
|
2926 |
|
|
TableGetCellValue(tablePtr, j, to));
|
2927 |
|
|
} else {
|
2928 |
|
|
TableMakeArrayIndex(from, j, buf);
|
2929 |
|
|
TableMakeArrayIndex(to, j, buf1);
|
2930 |
|
|
TableSetCellValue(tablePtr, from, j, check ? "" :
|
2931 |
|
|
TableGetCellValue(tablePtr, to, j));
|
2932 |
|
|
}
|
2933 |
|
|
/* move cell style here */
|
2934 |
|
|
if (movetag) {
|
2935 |
|
|
if ((entryPtr=Tcl_FindHashEntry(tablePtr->cellStyles,buf)) != NULL) {
|
2936 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
2937 |
|
|
}
|
2938 |
|
|
if (!check &&
|
2939 |
|
|
(entryPtr=Tcl_FindHashEntry(tablePtr->cellStyles,buf1))!=NULL) {
|
2940 |
|
|
newPtr = Tcl_CreateHashEntry(tablePtr->cellStyles, buf, &dummy);
|
2941 |
|
|
Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr));
|
2942 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
2943 |
|
|
}
|
2944 |
|
|
}
|
2945 |
|
|
}
|
2946 |
|
|
}
|
2947 |
|
|
|
2948 |
|
|
/*
|
2949 |
|
|
*----------------------------------------------------------------------
|
2950 |
|
|
*
|
2951 |
|
|
* TableModifyRC --
|
2952 |
|
|
* Modify rows/cols of the table (insert or delete)
|
2953 |
|
|
*
|
2954 |
|
|
* Results:
|
2955 |
|
|
* None.
|
2956 |
|
|
*
|
2957 |
|
|
* Side effects:
|
2958 |
|
|
* Modifies associated row/col data
|
2959 |
|
|
*
|
2960 |
|
|
*----------------------------------------------------------------------
|
2961 |
|
|
*/
|
2962 |
|
|
static int
|
2963 |
|
|
TableModifyRC(tablePtr, interp, type, which, argc, argv)
|
2964 |
|
|
Table *tablePtr; /* Information about text widget. */
|
2965 |
|
|
Tcl_Interp *interp; /* Current interpreter. */
|
2966 |
|
|
int type; /* insert (CMD_INSERT) | delete (CMD_DELETE) */
|
2967 |
|
|
int which; /* rows (MOD_ROWS) or cols (MOD_COLS) */
|
2968 |
|
|
int argc; /* Number of arguments. */
|
2969 |
|
|
char **argv; /* Argument strings. */
|
2970 |
|
|
{
|
2971 |
|
|
int i, first, lo, hi, idx, c, argsLeft, x, y, offset;
|
2972 |
|
|
int maxrow, maxcol, maxkey, minkey, movetitle, movetag, movedim;
|
2973 |
|
|
size_t length;
|
2974 |
|
|
char *arg;
|
2975 |
|
|
Tcl_HashTable *tagTblPtr, *dimTblPtr;
|
2976 |
|
|
Tcl_HashSearch search;
|
2977 |
|
|
int *dimPtr;
|
2978 |
|
|
|
2979 |
|
|
movetitle = 1;
|
2980 |
|
|
movetag = 1;
|
2981 |
|
|
movedim = 1;
|
2982 |
|
|
maxcol = tablePtr->cols-1+tablePtr->colOffset;
|
2983 |
|
|
maxrow = tablePtr->rows-1+tablePtr->rowOffset;
|
2984 |
|
|
for (i = 3; i < argc; i++) {
|
2985 |
|
|
arg = argv[i];
|
2986 |
|
|
if (arg[0] != '-') {
|
2987 |
|
|
break;
|
2988 |
|
|
}
|
2989 |
|
|
length = strlen(arg);
|
2990 |
|
|
if (length < 2) {
|
2991 |
|
|
badSwitch:
|
2992 |
|
|
Tcl_AppendResult(interp, "bad switch \"", arg,
|
2993 |
|
|
"\": must be -cols, -keeptitles, -holddimensions, ",
|
2994 |
|
|
"-holdtags, -rows, or --",
|
2995 |
|
|
(char *) NULL);
|
2996 |
|
|
return TCL_ERROR;
|
2997 |
|
|
}
|
2998 |
|
|
c = arg[1];
|
2999 |
|
|
if ((c == 'h') && (length > 5) &&
|
3000 |
|
|
(strncmp(argv[i], "-holddimensions", length) == 0)) {
|
3001 |
|
|
movedim = 0;
|
3002 |
|
|
} else if ((c == 'h') && (length > 5) &&
|
3003 |
|
|
(strncmp(argv[i], "-holdtags", length) == 0)) {
|
3004 |
|
|
movetag = 0;
|
3005 |
|
|
} else if ((c == 'k') && (strncmp(argv[i], "-keeptitles", length) == 0)) {
|
3006 |
|
|
movetitle = 0;
|
3007 |
|
|
} else if ((c == 'c') && (strncmp(argv[i], "-cols", length) == 0)) {
|
3008 |
|
|
if (i >= (argc-1)) {
|
3009 |
|
|
Tcl_SetResult(interp, "no value given for \"-cols\" option",
|
3010 |
|
|
TCL_STATIC);
|
3011 |
|
|
return TCL_ERROR;
|
3012 |
|
|
}
|
3013 |
|
|
if (Tcl_GetInt(interp, argv[++i], &maxcol) != TCL_OK) {
|
3014 |
|
|
return TCL_ERROR;
|
3015 |
|
|
}
|
3016 |
|
|
maxcol = MAX(maxcol, tablePtr->titleCols+tablePtr->colOffset);
|
3017 |
|
|
} else if ((c == 'r') && (strncmp(argv[i], "-rows", length) == 0)) {
|
3018 |
|
|
if (i >= (argc-1)) {
|
3019 |
|
|
Tcl_SetResult(interp, "no value given for \"-rows\" option",
|
3020 |
|
|
TCL_STATIC);
|
3021 |
|
|
return TCL_ERROR;
|
3022 |
|
|
}
|
3023 |
|
|
if (Tcl_GetInt(interp, argv[++i], &maxrow) != TCL_OK) {
|
3024 |
|
|
return TCL_ERROR;
|
3025 |
|
|
}
|
3026 |
|
|
maxrow = MAX(maxrow, tablePtr->titleRows+tablePtr->rowOffset);
|
3027 |
|
|
} else if ((c == '-') && (strncmp(argv[i], "--", length) == 0)) {
|
3028 |
|
|
i++;
|
3029 |
|
|
break;
|
3030 |
|
|
} else {
|
3031 |
|
|
goto badSwitch;
|
3032 |
|
|
}
|
3033 |
|
|
}
|
3034 |
|
|
argsLeft = argc - i;
|
3035 |
|
|
if (argsLeft != 1 && argsLeft != 2) {
|
3036 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3037 |
|
|
(type == CMD_DELETE) ? " delete" : " insert",
|
3038 |
|
|
(which == MOD_COLS) ? " cols" : " rows",
|
3039 |
|
|
" ?switches? index ?count?\"", (char *) NULL);
|
3040 |
|
|
return TCL_ERROR;
|
3041 |
|
|
}
|
3042 |
|
|
|
3043 |
|
|
c = 1;
|
3044 |
|
|
if (strcmp(argv[i], "end") == 0) {
|
3045 |
|
|
/* allow "end" to be specified as an index */
|
3046 |
|
|
idx = (which == MOD_COLS) ? maxcol : maxrow;
|
3047 |
|
|
} else if (Tcl_GetInt(interp, argv[i], &idx) != TCL_OK) {
|
3048 |
|
|
return TCL_ERROR;
|
3049 |
|
|
}
|
3050 |
|
|
if (argsLeft == 2 && Tcl_GetInt(interp, argv[++i], &c) != TCL_OK) {
|
3051 |
|
|
return TCL_ERROR;
|
3052 |
|
|
}
|
3053 |
|
|
if (tablePtr->state == STATE_DISABLED || c == 0)
|
3054 |
|
|
return TCL_OK;
|
3055 |
|
|
|
3056 |
|
|
if (which == MOD_COLS) {
|
3057 |
|
|
maxkey = maxcol;
|
3058 |
|
|
minkey = tablePtr->colOffset+tablePtr->titleCols;
|
3059 |
|
|
lo = tablePtr->rowOffset+(movetitle?0:tablePtr->titleRows);
|
3060 |
|
|
hi = maxrow;
|
3061 |
|
|
offset = tablePtr->colOffset;
|
3062 |
|
|
tagTblPtr = tablePtr->colStyles;
|
3063 |
|
|
dimTblPtr = tablePtr->colWidths;
|
3064 |
|
|
dimPtr = &(tablePtr->cols);
|
3065 |
|
|
} else {
|
3066 |
|
|
maxkey = maxrow;
|
3067 |
|
|
minkey = tablePtr->rowOffset+tablePtr->titleRows;
|
3068 |
|
|
lo = tablePtr->colOffset+(movetitle?0:tablePtr->titleCols);
|
3069 |
|
|
hi = maxcol;
|
3070 |
|
|
offset = tablePtr->rowOffset;
|
3071 |
|
|
tagTblPtr = tablePtr->rowStyles;
|
3072 |
|
|
dimTblPtr = tablePtr->rowHeights;
|
3073 |
|
|
dimPtr = &(tablePtr->rows);
|
3074 |
|
|
}
|
3075 |
|
|
|
3076 |
|
|
if (type == CMD_DELETE) {
|
3077 |
|
|
/* Handle row/col deletion */
|
3078 |
|
|
first = MAX(MIN(idx,idx+c), minkey);
|
3079 |
|
|
/* (index = i && count = 1) == (index = i && count = -1) */
|
3080 |
|
|
if (c < 0) {
|
3081 |
|
|
/* if the count is negative, make sure that the col count will delete
|
3082 |
|
|
* no greater than the original index */
|
3083 |
|
|
c = idx-first;
|
3084 |
|
|
first++;
|
3085 |
|
|
}
|
3086 |
|
|
if (movedim) {
|
3087 |
|
|
*dimPtr -= c;
|
3088 |
|
|
}
|
3089 |
|
|
for (i = first; i <= maxkey; i++) {
|
3090 |
|
|
TableModifyRCaux(tablePtr, type, which, movetag, tagTblPtr,
|
3091 |
|
|
dimTblPtr, offset, i, i+c, lo, hi, ((i+c)>maxkey));
|
3092 |
|
|
}
|
3093 |
|
|
} else {
|
3094 |
|
|
/* Handle row/col insertion */
|
3095 |
|
|
first = MAX(MIN(idx, maxkey), minkey);
|
3096 |
|
|
/* +count means insert after index, -count means insert before index */
|
3097 |
|
|
if (c < 0) {
|
3098 |
|
|
c = -c;
|
3099 |
|
|
} else {
|
3100 |
|
|
first++;
|
3101 |
|
|
}
|
3102 |
|
|
if (movedim) {
|
3103 |
|
|
maxkey += c;
|
3104 |
|
|
*dimPtr += c;
|
3105 |
|
|
}
|
3106 |
|
|
for (i = maxkey; i >= first; i--) {
|
3107 |
|
|
/* move row/col style && width/height here */
|
3108 |
|
|
TableModifyRCaux(tablePtr, type, which, movetag, tagTblPtr,
|
3109 |
|
|
dimTblPtr, offset, i, i-c, lo, hi, ((i-c)<first));
|
3110 |
|
|
}
|
3111 |
|
|
}
|
3112 |
|
|
if (Tcl_FirstHashEntry(tablePtr->selCells, &search) != NULL) {
|
3113 |
|
|
/* clear selection - forceful, but effective */
|
3114 |
|
|
Tcl_DeleteHashTable(tablePtr->selCells);
|
3115 |
|
|
ckfree((char *) (tablePtr->selCells));
|
3116 |
|
|
tablePtr->selCells = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
|
3117 |
|
|
Tcl_InitHashTable(tablePtr->selCells, TCL_STRING_KEYS);
|
3118 |
|
|
}
|
3119 |
|
|
|
3120 |
|
|
TableAdjustParams(tablePtr);
|
3121 |
|
|
if (which == MOD_COLS) {
|
3122 |
|
|
TableCellCoords(tablePtr, 0, first, &x, &y, &offset, &offset);
|
3123 |
|
|
TableInvalidate(tablePtr, x, y,
|
3124 |
|
|
Tk_Width(tablePtr->tkwin)-x,
|
3125 |
|
|
Tk_Height(tablePtr->tkwin), 0);
|
3126 |
|
|
} else {
|
3127 |
|
|
TableCellCoords(tablePtr, first, 0, &x, &y, &offset, &offset);
|
3128 |
|
|
TableInvalidate(tablePtr, x, y,
|
3129 |
|
|
Tk_Width(tablePtr->tkwin),
|
3130 |
|
|
Tk_Height(tablePtr->tkwin)-y, 0);
|
3131 |
|
|
}
|
3132 |
|
|
return TCL_OK;
|
3133 |
|
|
}
|
3134 |
|
|
|
3135 |
|
|
/*
|
3136 |
|
|
*--------------------------------------------------------------
|
3137 |
|
|
*
|
3138 |
|
|
* TableWidgetCmd --
|
3139 |
|
|
* This procedure is invoked to process the Tcl command
|
3140 |
|
|
* that corresponds to a widget managed by this module.
|
3141 |
|
|
* See the user documentation for details on what it does.
|
3142 |
|
|
*
|
3143 |
|
|
* Results:
|
3144 |
|
|
* A standard Tcl result.
|
3145 |
|
|
*
|
3146 |
|
|
* Side effects:
|
3147 |
|
|
* See the user documentation.
|
3148 |
|
|
*
|
3149 |
|
|
*--------------------------------------------------------------
|
3150 |
|
|
*/
|
3151 |
|
|
static int
|
3152 |
|
|
TableWidgetCmd(clientData, interp, argc, argv)
|
3153 |
|
|
ClientData clientData; /* Information about listbox widget. */
|
3154 |
|
|
Tcl_Interp *interp; /* Current interpreter. */
|
3155 |
|
|
int argc; /* Number of arguments. */
|
3156 |
|
|
char **argv; /* Argument strings. */
|
3157 |
|
|
{
|
3158 |
|
|
Tcl_HashEntry *entryPtr;
|
3159 |
|
|
Tcl_HashSearch search;
|
3160 |
|
|
Tcl_HashTable *hashTablePtr;
|
3161 |
|
|
int result, retval, sub_retval, row, col, x, y;
|
3162 |
|
|
int i, width, height, dummy, key, value, posn, offset;
|
3163 |
|
|
char buf1[INDEX_BUFSIZE], buf2[INDEX_BUFSIZE];
|
3164 |
|
|
|
3165 |
|
|
Table *tablePtr = (Table *) clientData;
|
3166 |
|
|
|
3167 |
|
|
if (argc < 2) {
|
3168 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3169 |
|
|
" option ?arg arg ...?\"", (char *) NULL);
|
3170 |
|
|
return TCL_ERROR;
|
3171 |
|
|
}
|
3172 |
|
|
Tcl_Preserve(clientData);
|
3173 |
|
|
|
3174 |
|
|
result = TCL_OK;
|
3175 |
|
|
/* parse the first parameter */
|
3176 |
|
|
retval = Cmd_Parse(interp, main_cmds, argv[1]);
|
3177 |
|
|
|
3178 |
|
|
/* Switch on the parameter value */
|
3179 |
|
|
switch (retval) {
|
3180 |
|
|
case 0:
|
3181 |
|
|
/* error, the return string is already set up */
|
3182 |
|
|
result = TCL_ERROR;
|
3183 |
|
|
break;
|
3184 |
|
|
|
3185 |
|
|
case CMD_ACTIVATE:
|
3186 |
|
|
if (argc != 3) {
|
3187 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3188 |
|
|
" activate index\"", (char *)NULL);
|
3189 |
|
|
result = TCL_ERROR;
|
3190 |
|
|
} else if (TableGetIndex(tablePtr, argv[2], &row, &col) == TCL_ERROR) {
|
3191 |
|
|
result = TCL_ERROR;
|
3192 |
|
|
} else {
|
3193 |
|
|
/* convert to valid active index in real coords */
|
3194 |
|
|
row -= tablePtr->rowOffset;
|
3195 |
|
|
col -= tablePtr->colOffset;
|
3196 |
|
|
/* we do this regardless, to avoid cell commit problems */
|
3197 |
|
|
if ((tablePtr->flags & HAS_ACTIVE) &&
|
3198 |
|
|
(tablePtr->flags & TEXT_CHANGED)) {
|
3199 |
|
|
tablePtr->flags &= ~TEXT_CHANGED;
|
3200 |
|
|
TableSetCellValue(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
|
3201 |
|
|
tablePtr->activeCol+tablePtr->colOffset,
|
3202 |
|
|
tablePtr->activeBuf);
|
3203 |
|
|
}
|
3204 |
|
|
if (row != tablePtr->activeRow || col != tablePtr->activeCol) {
|
3205 |
|
|
if (tablePtr->flags & HAS_ACTIVE) {
|
3206 |
|
|
TableMakeArrayIndex(tablePtr->activeRow+tablePtr->rowOffset,
|
3207 |
|
|
tablePtr->activeCol+tablePtr->colOffset, buf1);
|
3208 |
|
|
} else {
|
3209 |
|
|
buf1[0] = '\0';
|
3210 |
|
|
}
|
3211 |
|
|
tablePtr->flags |= HAS_ACTIVE;
|
3212 |
|
|
tablePtr->flags &= ~ACTIVE_DISABLED;
|
3213 |
|
|
tablePtr->activeRow = row;
|
3214 |
|
|
tablePtr->activeCol = col;
|
3215 |
|
|
if (tablePtr->activeLayout) {
|
3216 |
|
|
Tk_FreeTextLayout(tablePtr->activeLayout);
|
3217 |
|
|
tablePtr->activeLayout = NULL;
|
3218 |
|
|
}
|
3219 |
|
|
TableAdjustActive(tablePtr);
|
3220 |
|
|
TableConfigCursor(tablePtr);
|
3221 |
|
|
if (!(tablePtr->flags & BROWSE_CMD) && tablePtr->browseCmd != NULL) {
|
3222 |
|
|
Tcl_DString script;
|
3223 |
|
|
tablePtr->flags |= BROWSE_CMD;
|
3224 |
|
|
row = tablePtr->activeRow+tablePtr->rowOffset;
|
3225 |
|
|
col = tablePtr->activeCol+tablePtr->colOffset;
|
3226 |
|
|
TableMakeArrayIndex(row, col, buf2);
|
3227 |
|
|
Tcl_DStringInit(&script);
|
3228 |
|
|
ExpandPercents(tablePtr, tablePtr->browseCmd, row, col, buf1, buf2,
|
3229 |
|
|
tablePtr->icursor, &script, CMD_ACTIVATE);
|
3230 |
|
|
result = Tcl_GlobalEval(interp, Tcl_DStringValue(&script));
|
3231 |
|
|
if (result == TCL_OK || result == TCL_RETURN)
|
3232 |
|
|
Tcl_ResetResult(interp);
|
3233 |
|
|
Tcl_DStringFree(&script);
|
3234 |
|
|
tablePtr->flags &= ~BROWSE_CMD;
|
3235 |
|
|
}
|
3236 |
|
|
} else if ((tablePtr->activeLayout != NULL) &&
|
3237 |
|
|
!(tablePtr->flags & ACTIVE_DISABLED) && argv[2][0] == '@' &&
|
3238 |
|
|
TableCellVCoords(tablePtr, row, col, &x, &y,
|
3239 |
|
|
&dummy, &dummy, 0)) {
|
3240 |
|
|
/* we are clicking into the same cell */
|
3241 |
|
|
/* If it was activated with @x,y indexing, find the closest char */
|
3242 |
|
|
char *p;
|
3243 |
|
|
|
3244 |
|
|
/* no error checking because GetIndex did it for us */
|
3245 |
|
|
p = argv[2]+1;
|
3246 |
|
|
x = strtol(p, &p, 0) - x - tablePtr->activeX;
|
3247 |
|
|
y = strtol(++p, &p, 0) - y - tablePtr->activeY;
|
3248 |
|
|
|
3249 |
|
|
tablePtr->icursor = Tk_PointToChar(tablePtr->activeLayout, x, y);
|
3250 |
|
|
TableConfigCursor(tablePtr);
|
3251 |
|
|
}
|
3252 |
|
|
tablePtr->flags |= HAS_ACTIVE;
|
3253 |
|
|
}
|
3254 |
|
|
break; /* ACTIVATE */
|
3255 |
|
|
|
3256 |
|
|
case CMD_BBOX: {
|
3257 |
|
|
/* bounding box of cell(s) */
|
3258 |
|
|
if (argc < 3 || argc > 4) {
|
3259 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3260 |
|
|
" bbox first ?last?\"", (char *) NULL);
|
3261 |
|
|
result = TCL_ERROR;
|
3262 |
|
|
} else if (TableGetIndex(tablePtr, argv[2], &row, &col) == TCL_ERROR) {
|
3263 |
|
|
result = TCL_ERROR;
|
3264 |
|
|
} else if (argc == 3) {
|
3265 |
|
|
row -= tablePtr->rowOffset; col -= tablePtr->colOffset;
|
3266 |
|
|
if (TableCellVCoords(tablePtr, row, col, &x, &y, &width, &height, 0)) {
|
3267 |
|
|
sprintf(buf1, "%d %d %d %d", x, y, width, height);
|
3268 |
|
|
Tcl_SetResult(interp, buf1, TCL_VOLATILE);
|
3269 |
|
|
}
|
3270 |
|
|
} else if (TableGetIndex(tablePtr, argv[3], &x, &y) == TCL_ERROR) {
|
3271 |
|
|
result = TCL_ERROR;
|
3272 |
|
|
} else {
|
3273 |
|
|
int r1, c1, r2, c2, minX = 99999, minY = 99999, maxX = 0, maxY = 0;
|
3274 |
|
|
row -= tablePtr->rowOffset; col -= tablePtr->colOffset;
|
3275 |
|
|
x -= tablePtr->rowOffset; y -= tablePtr->colOffset;
|
3276 |
|
|
r1 = MIN(row,x); r2 = MAX(row,x);
|
3277 |
|
|
c1 = MIN(col,y); c2 = MAX(col,y);
|
3278 |
|
|
key = 0;
|
3279 |
|
|
for (row = r1; row <= r2; row++) {
|
3280 |
|
|
for (col = c1; col <= c2; col++) {
|
3281 |
|
|
if (TableCellVCoords(tablePtr, row, col, &x, &y,
|
3282 |
|
|
&width, &height, 0)) {
|
3283 |
|
|
/* Get max bounding box */
|
3284 |
|
|
if (x < minX) minX = x;
|
3285 |
|
|
if (y < minY) minY = y;
|
3286 |
|
|
if (x+width > maxX) maxX = x+width;
|
3287 |
|
|
if (y+height > maxY) maxY = y+height;
|
3288 |
|
|
key++;
|
3289 |
|
|
}
|
3290 |
|
|
/* FIX - This could break on else for speed */
|
3291 |
|
|
}
|
3292 |
|
|
}
|
3293 |
|
|
if (key) {
|
3294 |
|
|
sprintf(buf1, "%d %d %d %d", minX, minY, maxX-minX, maxY-minY);
|
3295 |
|
|
Tcl_SetResult(interp, buf1, TCL_VOLATILE);
|
3296 |
|
|
}
|
3297 |
|
|
}
|
3298 |
|
|
}
|
3299 |
|
|
break; /* BBOX */
|
3300 |
|
|
|
3301 |
|
|
case CMD_BORDER:
|
3302 |
|
|
if (argc > 6) {
|
3303 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3304 |
|
|
" border mark|dragto x y ?r|c?\"", (char *) NULL);
|
3305 |
|
|
result = TCL_ERROR;
|
3306 |
|
|
break;
|
3307 |
|
|
}
|
3308 |
|
|
sub_retval = Cmd_Parse(interp, bd_cmds, argv[2]);
|
3309 |
|
|
if (sub_retval == 0 || Tcl_GetInt(interp, argv[3], &x) != TCL_OK ||
|
3310 |
|
|
Tcl_GetInt(interp, argv[4], &y) != TCL_OK) {
|
3311 |
|
|
result = TCL_ERROR;
|
3312 |
|
|
break;
|
3313 |
|
|
}
|
3314 |
|
|
switch (sub_retval) {
|
3315 |
|
|
case BD_MARK:
|
3316 |
|
|
/* Use x && y to determine if we are over a border */
|
3317 |
|
|
value = TableAtBorder(tablePtr, x, y, &row, &col);
|
3318 |
|
|
/* Cache the row && col for use in DRAGTO */
|
3319 |
|
|
tablePtr->scanMarkRow = row;
|
3320 |
|
|
tablePtr->scanMarkCol = col;
|
3321 |
|
|
if (!value) break;
|
3322 |
|
|
TableCellCoords(tablePtr, row, col, &x, &y, &dummy, &dummy);
|
3323 |
|
|
tablePtr->scanMarkX = x;
|
3324 |
|
|
tablePtr->scanMarkY = y;
|
3325 |
|
|
if (argc == 5 || argv[5][0] == 'r') {
|
3326 |
|
|
if (row < 0)
|
3327 |
|
|
buf1[0] = '\0';
|
3328 |
|
|
else
|
3329 |
|
|
sprintf(buf1, "%d", row+tablePtr->rowOffset);
|
3330 |
|
|
Tcl_AppendElement(interp, buf1);
|
3331 |
|
|
}
|
3332 |
|
|
if (argc == 5 || argv[5][0] == 'c') {
|
3333 |
|
|
if (col < 0)
|
3334 |
|
|
buf1[0] = '\0';
|
3335 |
|
|
else
|
3336 |
|
|
sprintf(buf1, "%d", col+tablePtr->colOffset);
|
3337 |
|
|
Tcl_AppendElement(interp, buf1);
|
3338 |
|
|
}
|
3339 |
|
|
break; /* BORDER MARK */
|
3340 |
|
|
case BD_DRAGTO:
|
3341 |
|
|
/* check to see if we want to resize any borders */
|
3342 |
|
|
if (tablePtr->resize == SEL_NONE) break;
|
3343 |
|
|
row = tablePtr->scanMarkRow;
|
3344 |
|
|
col = tablePtr->scanMarkCol;
|
3345 |
|
|
TableCellCoords(tablePtr, row, col, &width, &height, &dummy, &dummy);
|
3346 |
|
|
key = 0;
|
3347 |
|
|
if (row >= 0 && (tablePtr->resize & SEL_ROW)) {
|
3348 |
|
|
/* row border was active, move it */
|
3349 |
|
|
/* FIX should this be 1 or 2 bds off? */
|
3350 |
|
|
value = y-height-tablePtr->borderWidth;
|
3351 |
|
|
if (value < -1) value = -1;
|
3352 |
|
|
if (value != tablePtr->scanMarkY) {
|
3353 |
|
|
entryPtr = Tcl_CreateHashEntry(tablePtr->rowHeights,
|
3354 |
|
|
(char *) row, &dummy);
|
3355 |
|
|
/* -value means rowHeight will be interp'd as pixels, not lines */
|
3356 |
|
|
Tcl_SetHashValue(entryPtr, (ClientData) MIN(0,-value));
|
3357 |
|
|
tablePtr->scanMarkY = value;
|
3358 |
|
|
key++;
|
3359 |
|
|
}
|
3360 |
|
|
}
|
3361 |
|
|
if (col >= 0 && (tablePtr->resize & SEL_COL)) {
|
3362 |
|
|
/* col border was active, move it */
|
3363 |
|
|
value = x-width-tablePtr->borderWidth;
|
3364 |
|
|
if (value < -1) value = -1;
|
3365 |
|
|
if (value != tablePtr->scanMarkX) {
|
3366 |
|
|
entryPtr = Tcl_CreateHashEntry(tablePtr->colWidths,
|
3367 |
|
|
(char *) col, &dummy);
|
3368 |
|
|
/* -value means colWidth will be interp'd as pixels, not chars */
|
3369 |
|
|
Tcl_SetHashValue(entryPtr, (ClientData) MIN(0,-value));
|
3370 |
|
|
tablePtr->scanMarkX = value;
|
3371 |
|
|
key++;
|
3372 |
|
|
}
|
3373 |
|
|
}
|
3374 |
|
|
/* Only if something changed do we want to update */
|
3375 |
|
|
if (key) {
|
3376 |
|
|
TableAdjustParams(tablePtr);
|
3377 |
|
|
/* Only rerequest geometry if the basis is the #rows &| #cols */
|
3378 |
|
|
if (tablePtr->maxReqCols || tablePtr->maxReqRows)
|
3379 |
|
|
TableGeometryRequest(tablePtr);
|
3380 |
|
|
TableInvalidateAll(tablePtr, 0);
|
3381 |
|
|
}
|
3382 |
|
|
break; /* BORDER DRAGTO */
|
3383 |
|
|
}
|
3384 |
|
|
break; /* BORDER */
|
3385 |
|
|
|
3386 |
|
|
case CMD_CGET:
|
3387 |
|
|
if (argc != 3) {
|
3388 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3389 |
|
|
" cget option\"", (char *) NULL);
|
3390 |
|
|
result = TCL_ERROR;
|
3391 |
|
|
break;
|
3392 |
|
|
}
|
3393 |
|
|
result = Tk_ConfigureValue(interp, tablePtr->tkwin, TableConfig,
|
3394 |
|
|
(char *) tablePtr, argv[2], 0);
|
3395 |
|
|
break; /* CGET */
|
3396 |
|
|
|
3397 |
|
|
case CMD_CLEAR:
|
3398 |
|
|
if (argc < 3 || argc > 5) {
|
3399 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3400 |
|
|
" clear option ?first? ?last?\"", (char *) NULL);
|
3401 |
|
|
result = TCL_ERROR;
|
3402 |
|
|
break;
|
3403 |
|
|
}
|
3404 |
|
|
|
3405 |
|
|
sub_retval = Cmd_Parse(interp, clear_cmds, argv[2]);
|
3406 |
|
|
result = TableClear(tablePtr, sub_retval,
|
3407 |
|
|
(argc>3)?argv[3]:NULL, (argc>4)?argv[4]:NULL);
|
3408 |
|
|
break; /* CLEAR */
|
3409 |
|
|
|
3410 |
|
|
case CMD_CONFIGURE:
|
3411 |
|
|
switch (argc) {
|
3412 |
|
|
case 2:
|
3413 |
|
|
result = Tk_ConfigureInfo(interp, tablePtr->tkwin, TableConfig,
|
3414 |
|
|
(char *) tablePtr, (char *) NULL, 0);
|
3415 |
|
|
break;
|
3416 |
|
|
case 3:
|
3417 |
|
|
result = Tk_ConfigureInfo(interp, tablePtr->tkwin, TableConfig,
|
3418 |
|
|
(char *) tablePtr, argv[2], 0);
|
3419 |
|
|
break;
|
3420 |
|
|
default:
|
3421 |
|
|
result = TableConfigure(interp, tablePtr, argc - 2, argv + 2,
|
3422 |
|
|
TK_CONFIG_ARGV_ONLY, 0);
|
3423 |
|
|
}
|
3424 |
|
|
break; /* CONFIGURE */
|
3425 |
|
|
|
3426 |
|
|
case CMD_CURVALUE:
|
3427 |
|
|
/* Get current active cell buffer */
|
3428 |
|
|
if (argc > 3) {
|
3429 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
3430 |
|
|
argv[0], " curvalue ?<value>?\"", (char *)NULL);
|
3431 |
|
|
result = TCL_ERROR;
|
3432 |
|
|
} else if (tablePtr->flags & HAS_ACTIVE) {
|
3433 |
|
|
if (argc == 3 && strcmp(argv[2], tablePtr->activeBuf)) {
|
3434 |
|
|
key = TCL_OK;
|
3435 |
|
|
/* validate potential new active buffer contents
|
3436 |
|
|
* only accept if validation returns acceptance. */
|
3437 |
|
|
if (tablePtr->validate &&
|
3438 |
|
|
TableValidateChange(tablePtr,
|
3439 |
|
|
tablePtr->activeRow+tablePtr->rowOffset,
|
3440 |
|
|
tablePtr->activeCol+tablePtr->colOffset,
|
3441 |
|
|
tablePtr->activeBuf,
|
3442 |
|
|
argv[2], tablePtr->icursor) != TCL_OK) {
|
3443 |
|
|
break;
|
3444 |
|
|
}
|
3445 |
|
|
tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf,
|
3446 |
|
|
strlen(argv[2])+1);
|
3447 |
|
|
strcpy(tablePtr->activeBuf, argv[2]);
|
3448 |
|
|
/* mark the text as changed */
|
3449 |
|
|
tablePtr->flags |= TEXT_CHANGED;
|
3450 |
|
|
TableSetActiveIndex(tablePtr);
|
3451 |
|
|
/* check for possible adjustment of icursor */
|
3452 |
|
|
TableGetIcursor(tablePtr, "insert", (int *)0);
|
3453 |
|
|
TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol,
|
3454 |
|
|
CELL|INV_FORCE);
|
3455 |
|
|
if (key == TCL_ERROR) {
|
3456 |
|
|
result = TCL_ERROR;
|
3457 |
|
|
break;
|
3458 |
|
|
}
|
3459 |
|
|
}
|
3460 |
|
|
Tcl_AppendResult(interp, tablePtr->activeBuf, (char *)NULL);
|
3461 |
|
|
}
|
3462 |
|
|
break; /* CURVALUE */
|
3463 |
|
|
|
3464 |
|
|
case CMD_CURSELECTION:
|
3465 |
|
|
if ((argc != 2 && argc != 4) ||
|
3466 |
|
|
(argc == 4 && (argv[2][0] == '\0' ||
|
3467 |
|
|
strncmp(argv[2], "set", strlen(argv[2]))))) {
|
3468 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3469 |
|
|
" curselection ?set <value>?\"", (char *)NULL);
|
3470 |
|
|
result = TCL_ERROR;
|
3471 |
|
|
break;
|
3472 |
|
|
}
|
3473 |
|
|
/* make sure there is a data source to accept set */
|
3474 |
|
|
if (argc == 4 && (tablePtr->state == STATE_DISABLED ||
|
3475 |
|
|
(tablePtr->dataSource == DATA_NONE)))
|
3476 |
|
|
break;
|
3477 |
|
|
for (entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search);
|
3478 |
|
|
entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
|
3479 |
|
|
if (argc == 2) {
|
3480 |
|
|
Tcl_AppendElement(interp,
|
3481 |
|
|
Tcl_GetHashKey(tablePtr->selCells, entryPtr));
|
3482 |
|
|
} else {
|
3483 |
|
|
TableParseArrayIndex(&row, &col,
|
3484 |
|
|
Tcl_GetHashKey(tablePtr->selCells, entryPtr));
|
3485 |
|
|
TableSetCellValue(tablePtr, row, col, argv[3]);
|
3486 |
|
|
row -= tablePtr->rowOffset;
|
3487 |
|
|
col -= tablePtr->colOffset;
|
3488 |
|
|
if (row == tablePtr->activeRow && col == tablePtr->activeCol) {
|
3489 |
|
|
TableGetActiveBuf(tablePtr);
|
3490 |
|
|
}
|
3491 |
|
|
TableCellCoords(tablePtr, row, col, &x, &y, &width, &height);
|
3492 |
|
|
TableInvalidate(tablePtr, x, y, width, height, 0);
|
3493 |
|
|
}
|
3494 |
|
|
}
|
3495 |
|
|
if (argc == 2) {
|
3496 |
|
|
Tcl_SetResult(interp,
|
3497 |
|
|
TableCellSort(tablePtr, Tcl_GetStringResult(interp)),
|
3498 |
|
|
TCL_DYNAMIC);
|
3499 |
|
|
}
|
3500 |
|
|
break; /* CURSELECTION */
|
3501 |
|
|
|
3502 |
|
|
case CMD_DELETE:
|
3503 |
|
|
if (argc < 4) {
|
3504 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3505 |
|
|
" delete option ?switches? arg ?arg?\"",
|
3506 |
|
|
(char *) NULL);
|
3507 |
|
|
result = TCL_ERROR;
|
3508 |
|
|
break;
|
3509 |
|
|
}
|
3510 |
|
|
sub_retval = Cmd_Parse (interp, mod_cmds, argv[2]);
|
3511 |
|
|
switch (sub_retval) {
|
3512 |
|
|
case 0:
|
3513 |
|
|
result = TCL_ERROR;
|
3514 |
|
|
break;
|
3515 |
|
|
case MOD_ACTIVE:
|
3516 |
|
|
if (argc > 5) {
|
3517 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3518 |
|
|
" delete active first ?last?\"", (char *) NULL);
|
3519 |
|
|
result = TCL_ERROR;
|
3520 |
|
|
break;
|
3521 |
|
|
}
|
3522 |
|
|
if (TableGetIcursor(tablePtr, argv[3], &posn) == TCL_ERROR) {
|
3523 |
|
|
result = TCL_ERROR;
|
3524 |
|
|
break;
|
3525 |
|
|
}
|
3526 |
|
|
if (argc == 4) {
|
3527 |
|
|
value = posn+1;
|
3528 |
|
|
} else if (TableGetIcursor(tablePtr, argv[4], &value) == TCL_ERROR) {
|
3529 |
|
|
result = TCL_ERROR;
|
3530 |
|
|
break;
|
3531 |
|
|
}
|
3532 |
|
|
if (value >= posn && (tablePtr->flags & HAS_ACTIVE) &&
|
3533 |
|
|
!(tablePtr->flags & ACTIVE_DISABLED) &&
|
3534 |
|
|
tablePtr->state == STATE_NORMAL)
|
3535 |
|
|
TableDeleteChars(tablePtr, posn, value-posn);
|
3536 |
|
|
break; /* DELETE ACTIVE */
|
3537 |
|
|
case MOD_COLS:
|
3538 |
|
|
case MOD_ROWS:
|
3539 |
|
|
result = TableModifyRC(tablePtr, interp, CMD_DELETE, sub_retval,
|
3540 |
|
|
argc, argv);
|
3541 |
|
|
break; /* DELETE ROWS */
|
3542 |
|
|
}
|
3543 |
|
|
break; /* DELETE */
|
3544 |
|
|
|
3545 |
|
|
case CMD_GET: {
|
3546 |
|
|
int r1, c1, r2, c2;
|
3547 |
|
|
|
3548 |
|
|
if (argc < 3 || argc > 4) {
|
3549 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3550 |
|
|
" get first ?last?\"", (char *)NULL);
|
3551 |
|
|
result = TCL_ERROR;
|
3552 |
|
|
} else if (TableGetIndex(tablePtr, argv[2], &row, &col) == TCL_ERROR) {
|
3553 |
|
|
result = TCL_ERROR;
|
3554 |
|
|
} else if (argc == 3) {
|
3555 |
|
|
Tcl_SetResult(interp, TableGetCellValue(tablePtr, row, col), TCL_STATIC);
|
3556 |
|
|
} else if (TableGetIndex(tablePtr, argv[3], &r2, &c2) == TCL_ERROR) {
|
3557 |
|
|
result = TCL_ERROR;
|
3558 |
|
|
} else {
|
3559 |
|
|
r1 = MIN(row,r2); r2 = MAX(row,r2);
|
3560 |
|
|
c1 = MIN(col,c2); c2 = MAX(col,c2);
|
3561 |
|
|
for ( row = r1; row <= r2; row++ ) {
|
3562 |
|
|
for ( col = c1; col <= c2; col++ ) {
|
3563 |
|
|
Tcl_AppendElement(interp, TableGetCellValue(tablePtr, row, col));
|
3564 |
|
|
}
|
3565 |
|
|
}
|
3566 |
|
|
}
|
3567 |
|
|
}
|
3568 |
|
|
break; /* GET */
|
3569 |
|
|
|
3570 |
|
|
case CMD_FLUSH: /* FIX - DEPRECATED */
|
3571 |
|
|
if (argc > 4) {
|
3572 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3573 |
|
|
" flush ?first? ?last?\"", (char *) NULL);
|
3574 |
|
|
result = TCL_ERROR;
|
3575 |
|
|
} else {
|
3576 |
|
|
result = TableClear(tablePtr, CLEAR_CACHE,
|
3577 |
|
|
(argc>2)?argv[2]:NULL, (argc>3)?argv[3]:NULL);
|
3578 |
|
|
}
|
3579 |
|
|
break; /* FLUSH */
|
3580 |
|
|
|
3581 |
|
|
case CMD_HEIGHT:
|
3582 |
|
|
case CMD_WIDTH:
|
3583 |
|
|
/* changes the width/height of certain selected columns */
|
3584 |
|
|
if (argc != 3 && (argc & 1)) {
|
3585 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3586 |
|
|
(retval == CMD_WIDTH) ?
|
3587 |
|
|
" width ?col? ?width col width ...?\"" :
|
3588 |
|
|
" height ?row? ?height row height ...?\"",
|
3589 |
|
|
(char *) NULL);
|
3590 |
|
|
result = TCL_ERROR;
|
3591 |
|
|
break;
|
3592 |
|
|
}
|
3593 |
|
|
if (retval == CMD_WIDTH) {
|
3594 |
|
|
hashTablePtr = tablePtr->colWidths;
|
3595 |
|
|
offset = tablePtr->colOffset;
|
3596 |
|
|
} else {
|
3597 |
|
|
hashTablePtr = tablePtr->rowHeights;
|
3598 |
|
|
offset = tablePtr->rowOffset;
|
3599 |
|
|
}
|
3600 |
|
|
|
3601 |
|
|
if (argc == 2) {
|
3602 |
|
|
/* print out all the preset column widths or row heights */
|
3603 |
|
|
entryPtr = Tcl_FirstHashEntry(hashTablePtr, &search);
|
3604 |
|
|
while (entryPtr != NULL) {
|
3605 |
|
|
posn = ((int) Tcl_GetHashKey(hashTablePtr, entryPtr)) + offset;
|
3606 |
|
|
value = (int) Tcl_GetHashValue(entryPtr);
|
3607 |
|
|
sprintf(buf1, "%d %d", posn, value);
|
3608 |
|
|
Tcl_AppendElement(interp, buf1);
|
3609 |
|
|
entryPtr = Tcl_NextHashEntry(&search);
|
3610 |
|
|
}
|
3611 |
|
|
} else if (argc == 3) {
|
3612 |
|
|
/* get the width/height of a particular row/col */
|
3613 |
|
|
if (Tcl_GetInt(interp, argv[2], &posn) != TCL_OK) {
|
3614 |
|
|
result = TCL_ERROR;
|
3615 |
|
|
break;
|
3616 |
|
|
}
|
3617 |
|
|
/* no range check is done, why bother? */
|
3618 |
|
|
posn -= offset;
|
3619 |
|
|
entryPtr = Tcl_FindHashEntry(hashTablePtr, (char *) posn);
|
3620 |
|
|
if (entryPtr != NULL) {
|
3621 |
|
|
sprintf(buf1, "%d", (int) Tcl_GetHashValue(entryPtr));
|
3622 |
|
|
Tcl_SetResult(interp, buf1, TCL_VOLATILE);
|
3623 |
|
|
} else {
|
3624 |
|
|
sprintf(buf1, "%d", (retval == CMD_WIDTH) ?
|
3625 |
|
|
tablePtr->defColWidth : tablePtr->defRowHeight);
|
3626 |
|
|
Tcl_SetResult(interp, buf1, TCL_VOLATILE);
|
3627 |
|
|
}
|
3628 |
|
|
} else {
|
3629 |
|
|
for (i=2; i<argc; i++) {
|
3630 |
|
|
/* set new width|height here */
|
3631 |
|
|
value = -999999;
|
3632 |
|
|
if (Tcl_GetInt(interp, argv[i++], &posn) != TCL_OK ||
|
3633 |
|
|
(strncmp(argv[i], "default", strlen(argv[i])) &&
|
3634 |
|
|
Tcl_GetInt(interp, argv[i], &value) != TCL_OK)) {
|
3635 |
|
|
result = TCL_ERROR;
|
3636 |
|
|
break;
|
3637 |
|
|
}
|
3638 |
|
|
posn -= offset;
|
3639 |
|
|
if (value == -999999) {
|
3640 |
|
|
/* reset that field */
|
3641 |
|
|
if ((entryPtr = Tcl_FindHashEntry(hashTablePtr, (char *) posn)))
|
3642 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
3643 |
|
|
} else {
|
3644 |
|
|
entryPtr = Tcl_CreateHashEntry(hashTablePtr, (char *) posn, &dummy);
|
3645 |
|
|
Tcl_SetHashValue(entryPtr, (ClientData) value);
|
3646 |
|
|
}
|
3647 |
|
|
}
|
3648 |
|
|
TableAdjustParams(tablePtr);
|
3649 |
|
|
/* rerequest geometry */
|
3650 |
|
|
TableGeometryRequest(tablePtr);
|
3651 |
|
|
/*
|
3652 |
|
|
* Invalidate the whole window as TableAdjustParams
|
3653 |
|
|
* will only check to see if the top left cell has moved
|
3654 |
|
|
* FIX: should just move from lowest order visible cell to edge of window
|
3655 |
|
|
*/
|
3656 |
|
|
TableInvalidateAll(tablePtr, 0);
|
3657 |
|
|
}
|
3658 |
|
|
break; /* HEIGHT && WIDTH */
|
3659 |
|
|
|
3660 |
|
|
case CMD_ICURSOR:
|
3661 |
|
|
/* set the insertion cursor */
|
3662 |
|
|
if (!(tablePtr->flags & HAS_ACTIVE) ||
|
3663 |
|
|
(tablePtr->flags & ACTIVE_DISABLED) ||
|
3664 |
|
|
tablePtr->state == STATE_DISABLED)
|
3665 |
|
|
break;
|
3666 |
|
|
switch (argc) {
|
3667 |
|
|
case 2:
|
3668 |
|
|
sprintf(buf1, "%d", tablePtr->icursor);
|
3669 |
|
|
Tcl_SetResult(interp, buf1, TCL_VOLATILE);
|
3670 |
|
|
break;
|
3671 |
|
|
case 3:
|
3672 |
|
|
if (TableGetIcursor(tablePtr, argv[2], (int *)0) != TCL_OK) {
|
3673 |
|
|
result = TCL_ERROR;
|
3674 |
|
|
break;
|
3675 |
|
|
}
|
3676 |
|
|
TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol, CELL);
|
3677 |
|
|
break;
|
3678 |
|
|
default:
|
3679 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3680 |
|
|
" icursor arg\"", (char *) NULL);
|
3681 |
|
|
result = TCL_ERROR;
|
3682 |
|
|
break;
|
3683 |
|
|
}
|
3684 |
|
|
break; /* ICURSOR */
|
3685 |
|
|
|
3686 |
|
|
case CMD_INDEX:
|
3687 |
|
|
if (argc < 3 || argc > 4 ||
|
3688 |
|
|
TableGetIndex(tablePtr, argv[2], &row, &col) == TCL_ERROR ||
|
3689 |
|
|
(argc == 4 && (strcmp(argv[3], "row") && strcmp(argv[3], "col")))) {
|
3690 |
|
|
if (!strlen(Tcl_GetStringResult(interp))) {
|
3691 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3692 |
|
|
" index index ?row|col?\"", (char *)NULL);
|
3693 |
|
|
}
|
3694 |
|
|
result = TCL_ERROR;
|
3695 |
|
|
break;
|
3696 |
|
|
}
|
3697 |
|
|
if (argc == 3) {
|
3698 |
|
|
TableMakeArrayIndex(row, col, buf1);
|
3699 |
|
|
} else if (argv[3][0] == 'r') { /* INDEX row */
|
3700 |
|
|
sprintf(buf1, "%d", row);
|
3701 |
|
|
} else { /* INDEX col */
|
3702 |
|
|
sprintf(buf1, "%d", col);
|
3703 |
|
|
}
|
3704 |
|
|
Tcl_SetResult(interp, buf1, TCL_VOLATILE);
|
3705 |
|
|
break; /* INDEX */
|
3706 |
|
|
|
3707 |
|
|
case CMD_INSERT:
|
3708 |
|
|
/* are edits enabled */
|
3709 |
|
|
if (argc < 4) {
|
3710 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3711 |
|
|
" insert option ?switches? arg ?arg?\"", (char *)NULL);
|
3712 |
|
|
result = TCL_ERROR;
|
3713 |
|
|
break;
|
3714 |
|
|
}
|
3715 |
|
|
sub_retval = Cmd_Parse(interp, mod_cmds, argv[2]);
|
3716 |
|
|
switch (sub_retval) {
|
3717 |
|
|
case 0:
|
3718 |
|
|
result = TCL_ERROR;
|
3719 |
|
|
break;
|
3720 |
|
|
case MOD_ACTIVE:
|
3721 |
|
|
if (argc != 5) {
|
3722 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3723 |
|
|
" insert active index string\"", (char *)NULL);
|
3724 |
|
|
result = TCL_ERROR;
|
3725 |
|
|
} else if (TableGetIcursor(tablePtr, argv[3], &posn) != TCL_OK) {
|
3726 |
|
|
result = TCL_ERROR;
|
3727 |
|
|
} else if ((tablePtr->flags & HAS_ACTIVE) &&
|
3728 |
|
|
!(tablePtr->flags & ACTIVE_DISABLED) &&
|
3729 |
|
|
tablePtr->state == STATE_NORMAL) {
|
3730 |
|
|
TableInsertChars(tablePtr, posn, argv[4]);
|
3731 |
|
|
}
|
3732 |
|
|
break; /* INSERT ACTIVE */
|
3733 |
|
|
case MOD_COLS:
|
3734 |
|
|
case MOD_ROWS:
|
3735 |
|
|
result = TableModifyRC(tablePtr, interp, CMD_INSERT, sub_retval,
|
3736 |
|
|
argc, argv);
|
3737 |
|
|
break;
|
3738 |
|
|
}
|
3739 |
|
|
break; /* INSERT */
|
3740 |
|
|
|
3741 |
|
|
case CMD_REREAD:
|
3742 |
|
|
/* this rereads the selection from the array */
|
3743 |
|
|
if (!(tablePtr->flags & HAS_ACTIVE) ||
|
3744 |
|
|
(tablePtr->flags & ACTIVE_DISABLED) ||
|
3745 |
|
|
tablePtr->state == STATE_DISABLED)
|
3746 |
|
|
break;
|
3747 |
|
|
TableGetActiveBuf(tablePtr);
|
3748 |
|
|
TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol,
|
3749 |
|
|
CELL|INV_FORCE);
|
3750 |
|
|
break; /* REREAD */
|
3751 |
|
|
|
3752 |
|
|
case CMD_SCAN:
|
3753 |
|
|
if (argc != 5) {
|
3754 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
3755 |
|
|
argv[0], " scan mark|dragto x y\"", (char *) NULL);
|
3756 |
|
|
result = TCL_ERROR;
|
3757 |
|
|
break;
|
3758 |
|
|
} else if (Tcl_GetInt(interp, argv[3], &x) == TCL_ERROR ||
|
3759 |
|
|
Tcl_GetInt(interp, argv[4], &y) == TCL_ERROR) {
|
3760 |
|
|
result = TCL_ERROR;
|
3761 |
|
|
break;
|
3762 |
|
|
}
|
3763 |
|
|
if ((argv[2][0] == 'm')
|
3764 |
|
|
&& (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) {
|
3765 |
|
|
TableWhatCell(tablePtr, x, y, &row, &col);
|
3766 |
|
|
tablePtr->scanMarkRow = row-tablePtr->topRow;
|
3767 |
|
|
tablePtr->scanMarkCol = col-tablePtr->leftCol;
|
3768 |
|
|
tablePtr->scanMarkX = x;
|
3769 |
|
|
tablePtr->scanMarkY = y;
|
3770 |
|
|
} else if ((argv[2][0] == 'd')
|
3771 |
|
|
&& (strncmp(argv[2], "dragto", strlen(argv[2])) == 0)) {
|
3772 |
|
|
int oldTop = tablePtr->topRow, oldLeft = tablePtr->leftCol;
|
3773 |
|
|
y += (5*(y-tablePtr->scanMarkY));
|
3774 |
|
|
x += (5*(x-tablePtr->scanMarkX));
|
3775 |
|
|
|
3776 |
|
|
TableWhatCell(tablePtr, x, y, &row, &col);
|
3777 |
|
|
|
3778 |
|
|
/* maintain appropriate real index */
|
3779 |
|
|
tablePtr->topRow = MAX(MIN(row-tablePtr->scanMarkRow,
|
3780 |
|
|
tablePtr->rows-1), tablePtr->titleRows);
|
3781 |
|
|
tablePtr->leftCol = MAX(MIN(col-tablePtr->scanMarkCol,
|
3782 |
|
|
tablePtr->cols-1), tablePtr->titleCols);
|
3783 |
|
|
|
3784 |
|
|
/* Adjust the table if new top left */
|
3785 |
|
|
if (oldTop != tablePtr->topRow || oldLeft != tablePtr->leftCol)
|
3786 |
|
|
TableAdjustParams(tablePtr);
|
3787 |
|
|
} else {
|
3788 |
|
|
Tcl_AppendResult(interp, "bad scan option \"", argv[2],
|
3789 |
|
|
"\": must be mark or dragto", (char *) NULL);
|
3790 |
|
|
result = TCL_ERROR;
|
3791 |
|
|
break;
|
3792 |
|
|
}
|
3793 |
|
|
break; /* SCAN */
|
3794 |
|
|
|
3795 |
|
|
case CMD_SEE:
|
3796 |
|
|
if (argc!=3 || TableGetIndex(tablePtr,argv[2],&row,&col)==TCL_ERROR) {
|
3797 |
|
|
if (!strlen(Tcl_GetStringResult(interp))) {
|
3798 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3799 |
|
|
" see index\"", (char *)NULL);
|
3800 |
|
|
}
|
3801 |
|
|
result = TCL_ERROR;
|
3802 |
|
|
break;
|
3803 |
|
|
}
|
3804 |
|
|
/* Adjust from user to master coords */
|
3805 |
|
|
row -= tablePtr->rowOffset;
|
3806 |
|
|
col -= tablePtr->colOffset;
|
3807 |
|
|
if (!TableCellVCoords(tablePtr, row, col, &x, &x, &x, &x, 1)) {
|
3808 |
|
|
tablePtr->topRow = row-1;
|
3809 |
|
|
tablePtr->leftCol = col-1;
|
3810 |
|
|
TableAdjustParams(tablePtr);
|
3811 |
|
|
}
|
3812 |
|
|
break; /* SEE */
|
3813 |
|
|
|
3814 |
|
|
case CMD_SELECTION:
|
3815 |
|
|
if (argc<3) {
|
3816 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3817 |
|
|
" selection option args\"", (char *)NULL);
|
3818 |
|
|
result=TCL_ERROR;
|
3819 |
|
|
break;
|
3820 |
|
|
}
|
3821 |
|
|
retval = Cmd_Parse(interp, sel_cmds, argv[2]);
|
3822 |
|
|
switch(retval) {
|
3823 |
|
|
case 0: /* failed to parse the argument, error */
|
3824 |
|
|
return TCL_ERROR;
|
3825 |
|
|
case SEL_ANCHOR:
|
3826 |
|
|
if (argc != 4 || TableGetIndex(tablePtr,argv[3],&row,&col) != TCL_OK) {
|
3827 |
|
|
if (!strlen(Tcl_GetStringResult(interp)))
|
3828 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3829 |
|
|
" selection anchor index\"", (char *)NULL);
|
3830 |
|
|
result=TCL_ERROR;
|
3831 |
|
|
break;
|
3832 |
|
|
}
|
3833 |
|
|
tablePtr->flags |= HAS_ANCHOR;
|
3834 |
|
|
/* maintain appropriate real index */
|
3835 |
|
|
if (tablePtr->selectTitles) {
|
3836 |
|
|
tablePtr->anchorRow = MIN(MAX(0,row-tablePtr->rowOffset),
|
3837 |
|
|
tablePtr->rows-1);
|
3838 |
|
|
tablePtr->anchorCol = MIN(MAX(0,col-tablePtr->colOffset),
|
3839 |
|
|
tablePtr->cols-1);
|
3840 |
|
|
} else {
|
3841 |
|
|
tablePtr->anchorRow = MIN(MAX(tablePtr->titleRows,
|
3842 |
|
|
row-tablePtr->rowOffset),
|
3843 |
|
|
tablePtr->rows-1);
|
3844 |
|
|
tablePtr->anchorCol = MIN(MAX(tablePtr->titleCols,
|
3845 |
|
|
col-tablePtr->colOffset),
|
3846 |
|
|
tablePtr->cols-1);
|
3847 |
|
|
}
|
3848 |
|
|
break;
|
3849 |
|
|
case SEL_CLEAR:
|
3850 |
|
|
if ( argc != 4 && argc != 5 ) {
|
3851 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3852 |
|
|
" selection clear all|<first> ?<last>?\"",
|
3853 |
|
|
(char *)NULL);
|
3854 |
|
|
result=TCL_ERROR;
|
3855 |
|
|
break;
|
3856 |
|
|
}
|
3857 |
|
|
if (strcmp(argv[3],"all") == 0) {
|
3858 |
|
|
for(entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search);
|
3859 |
|
|
entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
|
3860 |
|
|
TableParseArrayIndex(&row, &col,
|
3861 |
|
|
Tcl_GetHashKey(tablePtr->selCells,entryPtr));
|
3862 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
3863 |
|
|
TableCellCoords(tablePtr, row-tablePtr->rowOffset,
|
3864 |
|
|
col-tablePtr->colOffset, &x, &y, &width, &height);
|
3865 |
|
|
TableInvalidate(tablePtr, x, y, width, height, 0);
|
3866 |
|
|
}
|
3867 |
|
|
} else {
|
3868 |
|
|
int clo=0,chi=0,r1,c1,r2,c2;
|
3869 |
|
|
if (TableGetIndex(tablePtr,argv[3],&row,&col) == TCL_ERROR ||
|
3870 |
|
|
(argc==5 && TableGetIndex(tablePtr,argv[4],&r2,&c2)==TCL_ERROR)) {
|
3871 |
|
|
result = TCL_ERROR;
|
3872 |
|
|
break;
|
3873 |
|
|
}
|
3874 |
|
|
key = 0;
|
3875 |
|
|
if (argc == 4) {
|
3876 |
|
|
r1 = r2 = row;
|
3877 |
|
|
c1 = c2 = col;
|
3878 |
|
|
} else {
|
3879 |
|
|
r1 = MIN(row,r2); r2 = MAX(row,r2);
|
3880 |
|
|
c1 = MIN(col,c2); c2 = MAX(col,c2);
|
3881 |
|
|
}
|
3882 |
|
|
switch (tablePtr->selectType) {
|
3883 |
|
|
case SEL_BOTH:
|
3884 |
|
|
clo = c1; chi = c2;
|
3885 |
|
|
c1 = tablePtr->colOffset;
|
3886 |
|
|
c2 = tablePtr->cols-1+c1;
|
3887 |
|
|
key = 1;
|
3888 |
|
|
goto CLEAR_CELLS;
|
3889 |
|
|
CLEAR_BOTH:
|
3890 |
|
|
key = 0;
|
3891 |
|
|
c1 = clo; c2 = chi;
|
3892 |
|
|
case SEL_COL:
|
3893 |
|
|
r1 = tablePtr->rowOffset;
|
3894 |
|
|
r2 = tablePtr->rows-1+r1;
|
3895 |
|
|
break;
|
3896 |
|
|
case SEL_ROW:
|
3897 |
|
|
c1 = tablePtr->colOffset;
|
3898 |
|
|
c2 = tablePtr->cols-1+c1;
|
3899 |
|
|
break;
|
3900 |
|
|
}
|
3901 |
|
|
/* row/col are in user index coords */
|
3902 |
|
|
CLEAR_CELLS:
|
3903 |
|
|
for ( row = r1; row <= r2; row++ ) {
|
3904 |
|
|
for ( col = c1; col <= c2; col++ ) {
|
3905 |
|
|
TableMakeArrayIndex(row, col, buf1);
|
3906 |
|
|
if ((entryPtr=Tcl_FindHashEntry(tablePtr->selCells, buf1))!=NULL) {
|
3907 |
|
|
Tcl_DeleteHashEntry(entryPtr);
|
3908 |
|
|
TableCellCoords(tablePtr, row-tablePtr->rowOffset,
|
3909 |
|
|
col-tablePtr->colOffset,&x,&y,&width,&height);
|
3910 |
|
|
TableInvalidate(tablePtr, x, y, width, height, 0);
|
3911 |
|
|
}
|
3912 |
|
|
}
|
3913 |
|
|
}
|
3914 |
|
|
if (key) goto CLEAR_BOTH;
|
3915 |
|
|
}
|
3916 |
|
|
break; /* SELECTION CLEAR */
|
3917 |
|
|
case SEL_INCLUDES:
|
3918 |
|
|
if (argc != 4) {
|
3919 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3920 |
|
|
" selection includes index\"", (char *)NULL);
|
3921 |
|
|
result = TCL_ERROR;
|
3922 |
|
|
} else if (TableGetIndex(tablePtr, argv[3], &row, &col) == TCL_ERROR) {
|
3923 |
|
|
result = TCL_ERROR;
|
3924 |
|
|
} else {
|
3925 |
|
|
TableMakeArrayIndex(row, col, buf1);
|
3926 |
|
|
if (Tcl_FindHashEntry(tablePtr->selCells, buf1)) {
|
3927 |
|
|
Tcl_SetResult(interp, "1", TCL_STATIC);
|
3928 |
|
|
} else {
|
3929 |
|
|
Tcl_SetResult(interp, "0", TCL_STATIC);
|
3930 |
|
|
}
|
3931 |
|
|
}
|
3932 |
|
|
break; /* SELECTION INCLUDES */
|
3933 |
|
|
case SEL_SET: {
|
3934 |
|
|
int clo=0, chi=0, r1, c1, r2, c2, titleRows, titleCols;
|
3935 |
|
|
if (argc < 4 || argc > 5) {
|
3936 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
3937 |
|
|
" selection set first ?last?\"", (char *)NULL);
|
3938 |
|
|
result = TCL_ERROR;
|
3939 |
|
|
break;
|
3940 |
|
|
}
|
3941 |
|
|
if (TableGetIndex(tablePtr,argv[3],&row,&col) == TCL_ERROR ||
|
3942 |
|
|
(argc==5 && TableGetIndex(tablePtr,argv[4],&r2,&c2)==TCL_ERROR)) {
|
3943 |
|
|
result = TCL_ERROR;
|
3944 |
|
|
break;
|
3945 |
|
|
}
|
3946 |
|
|
key = 0;
|
3947 |
|
|
if (tablePtr->selectTitles) {
|
3948 |
|
|
titleRows = 0;
|
3949 |
|
|
titleCols = 0;
|
3950 |
|
|
} else {
|
3951 |
|
|
titleRows = tablePtr->titleRows;
|
3952 |
|
|
titleCols = tablePtr->titleCols;
|
3953 |
|
|
}
|
3954 |
|
|
/* maintain appropriate user index */
|
3955 |
|
|
row = MIN(MAX(titleRows+tablePtr->rowOffset, row),
|
3956 |
|
|
tablePtr->rows-1+tablePtr->rowOffset);
|
3957 |
|
|
col = MIN(MAX(titleCols+tablePtr->colOffset, col),
|
3958 |
|
|
tablePtr->cols-1+tablePtr->colOffset);
|
3959 |
|
|
if (argc == 4) {
|
3960 |
|
|
r1 = r2 = row;
|
3961 |
|
|
c1 = c2 = col;
|
3962 |
|
|
} else {
|
3963 |
|
|
r2 = MIN(MAX(titleRows+tablePtr->rowOffset, r2),
|
3964 |
|
|
tablePtr->rows-1+tablePtr->rowOffset);
|
3965 |
|
|
c2 = MIN(MAX(titleCols+tablePtr->colOffset, c2),
|
3966 |
|
|
tablePtr->cols-1+tablePtr->colOffset);
|
3967 |
|
|
r1 = MIN(row,r2); r2 = MAX(row,r2);
|
3968 |
|
|
c1 = MIN(col,c2); c2 = MAX(col,c2);
|
3969 |
|
|
}
|
3970 |
|
|
switch (tablePtr->selectType) {
|
3971 |
|
|
case SEL_BOTH:
|
3972 |
|
|
clo = c1; chi = c2;
|
3973 |
|
|
c1 = titleCols+tablePtr->colOffset;
|
3974 |
|
|
c2 = tablePtr->cols-1+tablePtr->colOffset;
|
3975 |
|
|
key = 1;
|
3976 |
|
|
goto SET_CELLS;
|
3977 |
|
|
SET_BOTH:
|
3978 |
|
|
key = 0;
|
3979 |
|
|
c1 = clo; c2 = chi;
|
3980 |
|
|
case SEL_COL:
|
3981 |
|
|
r1 = titleRows+tablePtr->rowOffset;
|
3982 |
|
|
r2 = tablePtr->rows-1+tablePtr->rowOffset;
|
3983 |
|
|
break;
|
3984 |
|
|
case SEL_ROW:
|
3985 |
|
|
c1 = titleCols+tablePtr->colOffset;
|
3986 |
|
|
c2 = tablePtr->cols-1+tablePtr->colOffset;
|
3987 |
|
|
break;
|
3988 |
|
|
}
|
3989 |
|
|
SET_CELLS:
|
3990 |
|
|
entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search);
|
3991 |
|
|
for ( row = r1; row <= r2; row++ ) {
|
3992 |
|
|
for ( col = c1; col <= c2; col++ ) {
|
3993 |
|
|
TableMakeArrayIndex(row, col, buf1);
|
3994 |
|
|
if (Tcl_FindHashEntry(tablePtr->selCells, buf1) == NULL) {
|
3995 |
|
|
Tcl_CreateHashEntry(tablePtr->selCells, buf1, &dummy);
|
3996 |
|
|
TableCellCoords(tablePtr, row-tablePtr->rowOffset,
|
3997 |
|
|
col-tablePtr->colOffset, &x, &y, &width, &height);
|
3998 |
|
|
TableInvalidate(tablePtr, x, y, width, height, 0);
|
3999 |
|
|
}
|
4000 |
|
|
}
|
4001 |
|
|
}
|
4002 |
|
|
if (key) goto SET_BOTH;
|
4003 |
|
|
|
4004 |
|
|
/* Adjust the table for top left, selection on screen etc */
|
4005 |
|
|
TableAdjustParams(tablePtr);
|
4006 |
|
|
|
4007 |
|
|
/* If the table was previously empty and we want to export the
|
4008 |
|
|
* selection, we should grab it now */
|
4009 |
|
|
if (entryPtr==NULL && tablePtr->exportSelection) {
|
4010 |
|
|
Tk_OwnSelection(tablePtr->tkwin, XA_PRIMARY, TableLostSelection,
|
4011 |
|
|
(ClientData) tablePtr);
|
4012 |
|
|
}
|
4013 |
|
|
}
|
4014 |
|
|
break; /* SELECTION SET */
|
4015 |
|
|
}
|
4016 |
|
|
break; /* SELECTION */
|
4017 |
|
|
|
4018 |
|
|
case CMD_SET:
|
4019 |
|
|
/* sets any number of tags/indices to a given value */
|
4020 |
|
|
if (argc < 3 || (argc > 3 && (argc & 1))) {
|
4021 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
4022 |
|
|
" set index ?value? ?index value ...?\"",
|
4023 |
|
|
(char *) NULL);
|
4024 |
|
|
result = TCL_ERROR;
|
4025 |
|
|
break;
|
4026 |
|
|
}
|
4027 |
|
|
/* make sure there is a data source to accept set */
|
4028 |
|
|
if (tablePtr->dataSource == DATA_NONE)
|
4029 |
|
|
break;
|
4030 |
|
|
if (argc == 3) {
|
4031 |
|
|
if (TableGetIndex(tablePtr, argv[2], &row, &col) != TCL_OK) {
|
4032 |
|
|
result = TCL_ERROR;
|
4033 |
|
|
break;
|
4034 |
|
|
}
|
4035 |
|
|
Tcl_SetResult(interp, TableGetCellValue(tablePtr, row, col),
|
4036 |
|
|
TCL_STATIC);
|
4037 |
|
|
} else if (tablePtr->state == STATE_NORMAL) {
|
4038 |
|
|
for (i=2; i<argc; i++) {
|
4039 |
|
|
if (TableGetIndex(tablePtr, argv[i], &row, &col) != TCL_OK) {
|
4040 |
|
|
result = TCL_ERROR;
|
4041 |
|
|
break;
|
4042 |
|
|
}
|
4043 |
|
|
if (TableSetCellValue(tablePtr, row, col, argv[++i]) == TCL_ERROR) {
|
4044 |
|
|
result = TCL_ERROR;
|
4045 |
|
|
break;
|
4046 |
|
|
}
|
4047 |
|
|
row -= tablePtr->rowOffset;
|
4048 |
|
|
col -= tablePtr->colOffset;
|
4049 |
|
|
if (row == tablePtr->activeRow && col == tablePtr->activeCol) {
|
4050 |
|
|
TableGetActiveBuf(tablePtr);
|
4051 |
|
|
}
|
4052 |
|
|
TableCellCoords(tablePtr, row, col, &x, &y, &width, &height);
|
4053 |
|
|
TableInvalidate(tablePtr, x, y, width, height, 0);
|
4054 |
|
|
}
|
4055 |
|
|
}
|
4056 |
|
|
break;
|
4057 |
|
|
|
4058 |
|
|
case CMD_TAG:
|
4059 |
|
|
/* a veritable plethora of tag commands */
|
4060 |
|
|
/* do we have another argument */
|
4061 |
|
|
if (argc < 3) {
|
4062 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
4063 |
|
|
" tag option ?arg arg ...?\"", (char *) NULL);
|
4064 |
|
|
result = TCL_ERROR;
|
4065 |
|
|
break;
|
4066 |
|
|
}
|
4067 |
|
|
/* all the rest is now done in a separate function */
|
4068 |
|
|
result = TableTagCmd(tablePtr, interp, argc, argv);
|
4069 |
|
|
break; /* TAG */
|
4070 |
|
|
|
4071 |
|
|
case CMD_VALIDATE:
|
4072 |
|
|
if (argc != 3) {
|
4073 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
4074 |
|
|
" validate index\"", (char *) NULL);
|
4075 |
|
|
result = TCL_ERROR;
|
4076 |
|
|
} else if (TableGetIndex(tablePtr, argv[2], &row, &col) == TCL_ERROR) {
|
4077 |
|
|
result = TCL_ERROR;
|
4078 |
|
|
} else {
|
4079 |
|
|
value = tablePtr->validate;
|
4080 |
|
|
tablePtr->validate = 1;
|
4081 |
|
|
key = TableValidateChange(tablePtr, row, col, (char *) NULL,
|
4082 |
|
|
(char *) NULL, -1);
|
4083 |
|
|
tablePtr->validate = value;
|
4084 |
|
|
sprintf(buf1, "%d", (key == TCL_OK) ? 1 : 0);
|
4085 |
|
|
Tcl_SetResult(interp, buf1, TCL_VOLATILE);
|
4086 |
|
|
}
|
4087 |
|
|
break;
|
4088 |
|
|
|
4089 |
|
|
case CMD_VERSION:
|
4090 |
|
|
if (argc != 2) {
|
4091 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
4092 |
|
|
" version\"", (char *) NULL);
|
4093 |
|
|
result = TCL_ERROR;
|
4094 |
|
|
} else {
|
4095 |
|
|
Tcl_SetResult(interp, TBL_VERSION, TCL_VOLATILE);
|
4096 |
|
|
}
|
4097 |
|
|
break;
|
4098 |
|
|
|
4099 |
|
|
case CMD_WINDOW:
|
4100 |
|
|
/* a veritable plethora of window commands */
|
4101 |
|
|
/* do we have another argument */
|
4102 |
|
|
if (argc < 3) {
|
4103 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
4104 |
|
|
" window option ?arg arg ...?\"", (char *) NULL);
|
4105 |
|
|
result = TCL_ERROR;
|
4106 |
|
|
break;
|
4107 |
|
|
}
|
4108 |
|
|
/* all the rest is now done in a separate function */
|
4109 |
|
|
result = TableWindowCmd(tablePtr, interp, argc, argv);
|
4110 |
|
|
break;
|
4111 |
|
|
|
4112 |
|
|
case CMD_XVIEW:
|
4113 |
|
|
case CMD_YVIEW:
|
4114 |
|
|
if (argc == 2) {
|
4115 |
|
|
int diff;
|
4116 |
|
|
double first, last;
|
4117 |
|
|
TableGetLastCell(tablePtr, &row, &col);
|
4118 |
|
|
TableCellVCoords(tablePtr, row, col, &x, &y, &width, &height, 0);
|
4119 |
|
|
if (retval == CMD_YVIEW) {
|
4120 |
|
|
if (row < tablePtr->titleRows) {
|
4121 |
|
|
first = 0;
|
4122 |
|
|
last = 1;
|
4123 |
|
|
} else {
|
4124 |
|
|
diff = tablePtr->rowStarts[tablePtr->titleRows];
|
4125 |
|
|
last = (double) (tablePtr->rowStarts[tablePtr->rows]-diff);
|
4126 |
|
|
first = (tablePtr->rowStarts[tablePtr->topRow]-diff) / last;
|
4127 |
|
|
last = (height+tablePtr->rowStarts[row]-diff) / last;
|
4128 |
|
|
}
|
4129 |
|
|
} else {
|
4130 |
|
|
if (col < tablePtr->titleCols) {
|
4131 |
|
|
first = 0;
|
4132 |
|
|
last = 1;
|
4133 |
|
|
} else {
|
4134 |
|
|
diff = tablePtr->colStarts[tablePtr->titleCols];
|
4135 |
|
|
last = (double) (tablePtr->colStarts[tablePtr->cols]-diff);
|
4136 |
|
|
first = (tablePtr->colStarts[tablePtr->leftCol]-diff) / last;
|
4137 |
|
|
last = (width+tablePtr->colStarts[col]-diff) / last;
|
4138 |
|
|
}
|
4139 |
|
|
}
|
4140 |
|
|
sprintf(buf1, "%g %g", first, last);
|
4141 |
|
|
Tcl_SetResult(interp, buf1, TCL_VOLATILE);
|
4142 |
|
|
} else {
|
4143 |
|
|
/* cache old topleft to see if it changes */
|
4144 |
|
|
int oldTop = tablePtr->topRow, oldLeft = tablePtr->leftCol;
|
4145 |
|
|
if (argc == 3) {
|
4146 |
|
|
if (Tcl_GetInt(interp, argv[2], &value) != TCL_OK) {
|
4147 |
|
|
result = TCL_ERROR;
|
4148 |
|
|
break;
|
4149 |
|
|
}
|
4150 |
|
|
if (retval == CMD_YVIEW) {
|
4151 |
|
|
tablePtr->topRow = value + tablePtr->titleRows;
|
4152 |
|
|
} else {
|
4153 |
|
|
tablePtr->leftCol = value + tablePtr->titleCols;
|
4154 |
|
|
}
|
4155 |
|
|
} else {
|
4156 |
|
|
double frac;
|
4157 |
|
|
sub_retval = Tk_GetScrollInfo(interp, argc, argv, &frac, &value);
|
4158 |
|
|
switch (sub_retval) {
|
4159 |
|
|
case TK_SCROLL_ERROR:
|
4160 |
|
|
result = TCL_ERROR;
|
4161 |
|
|
break;
|
4162 |
|
|
case TK_SCROLL_MOVETO:
|
4163 |
|
|
if (frac < 0) frac = 0;
|
4164 |
|
|
if (retval == CMD_YVIEW) {
|
4165 |
|
|
tablePtr->topRow = (int)(frac*tablePtr->rows)+tablePtr->titleRows;
|
4166 |
|
|
} else {
|
4167 |
|
|
tablePtr->leftCol = (int)(frac*tablePtr->cols)+tablePtr->titleCols;
|
4168 |
|
|
}
|
4169 |
|
|
break;
|
4170 |
|
|
case TK_SCROLL_PAGES:
|
4171 |
|
|
TableGetLastCell(tablePtr, &row, &col);
|
4172 |
|
|
if (retval == CMD_YVIEW) {
|
4173 |
|
|
tablePtr->topRow += value * (row-tablePtr->topRow+1);
|
4174 |
|
|
} else {
|
4175 |
|
|
tablePtr->leftCol += value * (col-tablePtr->leftCol+1);
|
4176 |
|
|
}
|
4177 |
|
|
break;
|
4178 |
|
|
case TK_SCROLL_UNITS:
|
4179 |
|
|
if (retval == CMD_YVIEW) {
|
4180 |
|
|
tablePtr->topRow += value;
|
4181 |
|
|
} else {
|
4182 |
|
|
tablePtr->leftCol += value;
|
4183 |
|
|
}
|
4184 |
|
|
break;
|
4185 |
|
|
}
|
4186 |
|
|
}
|
4187 |
|
|
/* maintain appropriate real index */
|
4188 |
|
|
tablePtr->topRow = MAX(tablePtr->titleRows,
|
4189 |
|
|
MIN(tablePtr->topRow, tablePtr->rows-1));
|
4190 |
|
|
tablePtr->leftCol = MAX(tablePtr->titleCols,
|
4191 |
|
|
MIN(tablePtr->leftCol, tablePtr->cols-1));
|
4192 |
|
|
/* Do the table adjustment if topRow || leftCol changed */
|
4193 |
|
|
if (oldTop != tablePtr->topRow || oldLeft != tablePtr->leftCol)
|
4194 |
|
|
TableAdjustParams(tablePtr);
|
4195 |
|
|
}
|
4196 |
|
|
break; /* XVIEW/YVIEW */
|
4197 |
|
|
}
|
4198 |
|
|
Tcl_Release(clientData);
|
4199 |
|
|
return result;
|
4200 |
|
|
}
|
4201 |
|
|
|
4202 |
|
|
/*
|
4203 |
|
|
*----------------------------------------------------------------------
|
4204 |
|
|
*
|
4205 |
|
|
* TableDestroy --
|
4206 |
|
|
* This procedure is invoked by Tcl_EventuallyFree
|
4207 |
|
|
* to clean up the internal structure of a table at a safe time
|
4208 |
|
|
* (when no-one is using it anymore).
|
4209 |
|
|
*
|
4210 |
|
|
* Results:
|
4211 |
|
|
* None.
|
4212 |
|
|
*
|
4213 |
|
|
* Side effects:
|
4214 |
|
|
* Everything associated with the table is freed up (hopefully).
|
4215 |
|
|
*
|
4216 |
|
|
*----------------------------------------------------------------------
|
4217 |
|
|
*/
|
4218 |
|
|
static void
|
4219 |
|
|
TableDestroy(ClientData clientdata)
|
4220 |
|
|
{
|
4221 |
|
|
register Table *tablePtr = (Table *) clientdata;
|
4222 |
|
|
Tcl_HashEntry *entryPtr;
|
4223 |
|
|
Tcl_HashSearch search;
|
4224 |
|
|
|
4225 |
|
|
/* These may be repetitive from DestroyNotify, but it doesn't hurt */
|
4226 |
|
|
/* cancel any pending update or timer */
|
4227 |
|
|
if (tablePtr->flags & REDRAW_PENDING) {
|
4228 |
|
|
Tcl_CancelIdleCall(TableDisplay, (ClientData) tablePtr);
|
4229 |
|
|
tablePtr->flags &= ~REDRAW_PENDING;
|
4230 |
|
|
}
|
4231 |
|
|
Tcl_DeleteTimerHandler(tablePtr->cursorTimer);
|
4232 |
|
|
Tcl_DeleteTimerHandler(tablePtr->flashTimer);
|
4233 |
|
|
|
4234 |
|
|
/* delete the variable trace */
|
4235 |
|
|
if (tablePtr->arrayVar != NULL) {
|
4236 |
|
|
Tcl_UntraceVar(tablePtr->interp, tablePtr->arrayVar,
|
4237 |
|
|
TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_GLOBAL_ONLY,
|
4238 |
|
|
(Tcl_VarTraceProc *)TableVarProc, (ClientData) tablePtr);
|
4239 |
|
|
}
|
4240 |
|
|
|
4241 |
|
|
/* delete cached activeLayout */
|
4242 |
|
|
if (tablePtr->activeLayout != NULL) {
|
4243 |
|
|
Tk_FreeTextLayout(tablePtr->activeLayout);
|
4244 |
|
|
tablePtr->activeLayout = NULL;
|
4245 |
|
|
}
|
4246 |
|
|
/* free the arrays with row/column pixel sizes */
|
4247 |
|
|
if (tablePtr->colPixels) ckfree((char *) tablePtr->colPixels);
|
4248 |
|
|
if (tablePtr->rowPixels) ckfree((char *) tablePtr->rowPixels);
|
4249 |
|
|
if (tablePtr->colStarts) ckfree((char *) tablePtr->colStarts);
|
4250 |
|
|
if (tablePtr->rowStarts) ckfree((char *) tablePtr->rowStarts);
|
4251 |
|
|
|
4252 |
|
|
/* free the selection buffer */
|
4253 |
|
|
if (tablePtr->activeBuf != NULL) ckfree(tablePtr->activeBuf);
|
4254 |
|
|
|
4255 |
|
|
/* delete the cache, row, column and cell style hash tables */
|
4256 |
|
|
Tcl_DeleteHashTable(tablePtr->cache);
|
4257 |
|
|
ckfree((char *) (tablePtr->cache));
|
4258 |
|
|
Tcl_DeleteHashTable(tablePtr->rowStyles);
|
4259 |
|
|
ckfree((char *) (tablePtr->rowStyles));
|
4260 |
|
|
Tcl_DeleteHashTable(tablePtr->colStyles);
|
4261 |
|
|
ckfree((char *) (tablePtr->colStyles));
|
4262 |
|
|
Tcl_DeleteHashTable(tablePtr->cellStyles);
|
4263 |
|
|
ckfree((char *) (tablePtr->cellStyles));
|
4264 |
|
|
Tcl_DeleteHashTable(tablePtr->flashCells);
|
4265 |
|
|
ckfree((char *) (tablePtr->flashCells));
|
4266 |
|
|
Tcl_DeleteHashTable(tablePtr->selCells);
|
4267 |
|
|
ckfree((char *) (tablePtr->selCells));
|
4268 |
|
|
Tcl_DeleteHashTable(tablePtr->colWidths);
|
4269 |
|
|
ckfree((char *) (tablePtr->colWidths));
|
4270 |
|
|
Tcl_DeleteHashTable(tablePtr->rowHeights);
|
4271 |
|
|
ckfree((char *) (tablePtr->rowHeights));
|
4272 |
|
|
|
4273 |
|
|
/* Now free up all the tag information */
|
4274 |
|
|
for (entryPtr = Tcl_FirstHashEntry(tablePtr->tagTable, &search);
|
4275 |
|
|
entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
|
4276 |
|
|
TableCleanupTag(tablePtr, (TableTag *) Tcl_GetHashValue(entryPtr));
|
4277 |
|
|
ckfree((char *) Tcl_GetHashValue(entryPtr));
|
4278 |
|
|
}
|
4279 |
|
|
/* free up the stuff in the default tag */
|
4280 |
|
|
TableCleanupTag(tablePtr, &(tablePtr->defaultTag));
|
4281 |
|
|
/* And delete the actual hash table */
|
4282 |
|
|
Tcl_DeleteHashTable(tablePtr->tagTable);
|
4283 |
|
|
ckfree((char *) (tablePtr->tagTable));
|
4284 |
|
|
|
4285 |
|
|
/* Now free up all the embedded window info */
|
4286 |
|
|
for (entryPtr = Tcl_FirstHashEntry(tablePtr->winTable, &search);
|
4287 |
|
|
entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
|
4288 |
|
|
EmbWinDelete(tablePtr, (TableEmbWindow *) Tcl_GetHashValue(entryPtr));
|
4289 |
|
|
}
|
4290 |
|
|
/* And delete the actual hash table */
|
4291 |
|
|
Tcl_DeleteHashTable(tablePtr->winTable);
|
4292 |
|
|
ckfree((char *) (tablePtr->winTable));
|
4293 |
|
|
|
4294 |
|
|
/* free the configuration options in the widget */
|
4295 |
|
|
Tk_FreeOptions(TableConfig, (char *) tablePtr, tablePtr->display, 0);
|
4296 |
|
|
|
4297 |
|
|
/* and free the widget memory at last! */
|
4298 |
|
|
ckfree((char *) (tablePtr));
|
4299 |
|
|
}
|
4300 |
|
|
|
4301 |
|
|
/*
|
4302 |
|
|
*--------------------------------------------------------------
|
4303 |
|
|
*
|
4304 |
|
|
* TableEventProc --
|
4305 |
|
|
* This procedure is invoked by the Tk dispatcher for various
|
4306 |
|
|
* events on tables.
|
4307 |
|
|
*
|
4308 |
|
|
* Results:
|
4309 |
|
|
* None.
|
4310 |
|
|
*
|
4311 |
|
|
* Side effects:
|
4312 |
|
|
* When the window gets deleted, internal structures get
|
4313 |
|
|
* cleaned up. When it gets exposed, it is redisplayed.
|
4314 |
|
|
*
|
4315 |
|
|
*--------------------------------------------------------------
|
4316 |
|
|
*/
|
4317 |
|
|
static void
|
4318 |
|
|
TableEventProc(clientData, eventPtr)
|
4319 |
|
|
ClientData clientData; /* Information about window. */
|
4320 |
|
|
XEvent *eventPtr; /* Information about event. */
|
4321 |
|
|
{
|
4322 |
|
|
Table *tablePtr = (Table *) clientData;
|
4323 |
|
|
int row, col;
|
4324 |
|
|
|
4325 |
|
|
switch (eventPtr->type) {
|
4326 |
|
|
|
4327 |
|
|
case MotionNotify:
|
4328 |
|
|
if (!(tablePtr->resize & SEL_NONE) && (tablePtr->bdcursor != None) &&
|
4329 |
|
|
TableAtBorder(tablePtr, eventPtr->xmotion.x, eventPtr->xmotion.y,
|
4330 |
|
|
&row, &col) &&
|
4331 |
|
|
((row>=0 && (tablePtr->resize & SEL_ROW)) ||
|
4332 |
|
|
(col>=0 && (tablePtr->resize & SEL_COL)))) {
|
4333 |
|
|
/* The bordercursor is defined and we meet the criteria for being
|
4334 |
|
|
* over a border. Set the cursor to border if not already so */
|
4335 |
|
|
if (!(tablePtr->flags & OVER_BORDER)) {
|
4336 |
|
|
tablePtr->flags |= OVER_BORDER;
|
4337 |
|
|
Tk_DefineCursor(tablePtr->tkwin, tablePtr->bdcursor);
|
4338 |
|
|
}
|
4339 |
|
|
} else if (tablePtr->flags & OVER_BORDER) {
|
4340 |
|
|
tablePtr->flags &= ~OVER_BORDER;
|
4341 |
|
|
if (tablePtr->cursor != None) {
|
4342 |
|
|
Tk_DefineCursor(tablePtr->tkwin, tablePtr->cursor);
|
4343 |
|
|
} else {
|
4344 |
|
|
Tk_UndefineCursor(tablePtr->tkwin);
|
4345 |
|
|
}
|
4346 |
|
|
}
|
4347 |
|
|
break;
|
4348 |
|
|
|
4349 |
|
|
case Expose:
|
4350 |
|
|
TableInvalidate(tablePtr, eventPtr->xexpose.x, eventPtr->xexpose.y,
|
4351 |
|
|
eventPtr->xexpose.width, eventPtr->xexpose.height,
|
4352 |
|
|
INV_HIGHLIGHT);
|
4353 |
|
|
break;
|
4354 |
|
|
|
4355 |
|
|
case DestroyNotify:
|
4356 |
|
|
/* remove the command from the interpreter */
|
4357 |
|
|
if (tablePtr->tkwin != NULL) {
|
4358 |
|
|
tablePtr->tkwin = NULL;
|
4359 |
|
|
Tcl_DeleteCommandFromToken(tablePtr->interp, tablePtr->widgetCmd);
|
4360 |
|
|
}
|
4361 |
|
|
|
4362 |
|
|
/* cancel any pending update or timer */
|
4363 |
|
|
if (tablePtr->flags & REDRAW_PENDING) {
|
4364 |
|
|
Tcl_CancelIdleCall(TableDisplay, (ClientData) tablePtr);
|
4365 |
|
|
tablePtr->flags &= ~REDRAW_PENDING;
|
4366 |
|
|
}
|
4367 |
|
|
Tcl_DeleteTimerHandler(tablePtr->cursorTimer);
|
4368 |
|
|
Tcl_DeleteTimerHandler(tablePtr->flashTimer);
|
4369 |
|
|
|
4370 |
|
|
Tcl_EventuallyFree((ClientData) tablePtr, (Tcl_FreeProc *) TableDestroy);
|
4371 |
|
|
break;
|
4372 |
|
|
|
4373 |
|
|
case MapNotify: /* redraw table when remapped if it changed */
|
4374 |
|
|
if (tablePtr->flags & REDRAW_ON_MAP) {
|
4375 |
|
|
tablePtr->flags &= ~REDRAW_ON_MAP;
|
4376 |
|
|
Tcl_Preserve((ClientData) tablePtr);
|
4377 |
|
|
TableAdjustParams(tablePtr);
|
4378 |
|
|
TableInvalidateAll(tablePtr, INV_FORCE|INV_HIGHLIGHT);
|
4379 |
|
|
Tcl_Release((ClientData) tablePtr);
|
4380 |
|
|
}
|
4381 |
|
|
break;
|
4382 |
|
|
|
4383 |
|
|
case ConfigureNotify:
|
4384 |
|
|
Tcl_Preserve((ClientData) tablePtr);
|
4385 |
|
|
TableAdjustParams(tablePtr);
|
4386 |
|
|
TableInvalidateAll(tablePtr, INV_FORCE|INV_HIGHLIGHT);
|
4387 |
|
|
Tcl_Release((ClientData) tablePtr);
|
4388 |
|
|
break;
|
4389 |
|
|
|
4390 |
|
|
case FocusIn:
|
4391 |
|
|
case FocusOut:
|
4392 |
|
|
if (eventPtr->xfocus.detail != NotifyInferior) {
|
4393 |
|
|
tablePtr->flags |= REDRAW_BORDER;
|
4394 |
|
|
if (eventPtr->type == FocusOut) {
|
4395 |
|
|
tablePtr->flags &= ~HAS_FOCUS;
|
4396 |
|
|
} else {
|
4397 |
|
|
tablePtr->flags |= HAS_FOCUS;
|
4398 |
|
|
}
|
4399 |
|
|
TableRedrawHighlight(tablePtr);
|
4400 |
|
|
/* cancel the timer */
|
4401 |
|
|
TableConfigCursor(tablePtr);
|
4402 |
|
|
}
|
4403 |
|
|
break;
|
4404 |
|
|
}
|
4405 |
|
|
}
|
4406 |
|
|
|
4407 |
|
|
/*
|
4408 |
|
|
*----------------------------------------------------------------------
|
4409 |
|
|
*
|
4410 |
|
|
* TableConfigure --
|
4411 |
|
|
* This procedure is called to process an argv/argc list, plus
|
4412 |
|
|
* the Tk option database, in order to configure (or reconfigure)
|
4413 |
|
|
* a table widget.
|
4414 |
|
|
*
|
4415 |
|
|
* Results:
|
4416 |
|
|
* The return value is a standard Tcl result. If TCL_ERROR is
|
4417 |
|
|
* returned, then interp result contains an error message.
|
4418 |
|
|
*
|
4419 |
|
|
* Side effects:
|
4420 |
|
|
* Configuration information, such as colors, border width, etc.
|
4421 |
|
|
* get set for tablePtr; old resources get freed, if there were any.
|
4422 |
|
|
* Certain values might be constrained.
|
4423 |
|
|
*
|
4424 |
|
|
*----------------------------------------------------------------------
|
4425 |
|
|
*/
|
4426 |
|
|
static int
|
4427 |
|
|
TableConfigure(interp, tablePtr, argc, argv, flags, forceUpdate)
|
4428 |
|
|
Tcl_Interp *interp; /* Used for error reporting. */
|
4429 |
|
|
register Table *tablePtr; /* Information about widget; may or may
|
4430 |
|
|
* not already have values for some fields. */
|
4431 |
|
|
int argc; /* Number of valid entries in argv. */
|
4432 |
|
|
char **argv; /* Arguments. */
|
4433 |
|
|
int flags; /* Flags to pass to Tk_ConfigureWidget. */
|
4434 |
|
|
int forceUpdate; /* Whether to force an update - required
|
4435 |
|
|
* for initial configuration */
|
4436 |
|
|
{
|
4437 |
|
|
Tcl_HashSearch search;
|
4438 |
|
|
int oldUse, oldCaching, oldExport, result = TCL_OK;
|
4439 |
|
|
char *oldVar;
|
4440 |
|
|
Tcl_DString error;
|
4441 |
|
|
Tk_FontMetrics fm;
|
4442 |
|
|
|
4443 |
|
|
oldExport = tablePtr->exportSelection;
|
4444 |
|
|
oldCaching = tablePtr->caching;
|
4445 |
|
|
oldUse = tablePtr->useCmd;
|
4446 |
|
|
oldVar = tablePtr->arrayVar;
|
4447 |
|
|
|
4448 |
|
|
/* Do the configuration */
|
4449 |
|
|
if (Tk_ConfigureWidget(interp, tablePtr->tkwin, TableConfig, argc, argv,
|
4450 |
|
|
(char *) tablePtr, flags) != TCL_OK)
|
4451 |
|
|
return TCL_ERROR;
|
4452 |
|
|
|
4453 |
|
|
Tcl_DStringInit(&error);
|
4454 |
|
|
|
4455 |
|
|
/* Any time we configure, reevaluate what our data source is */
|
4456 |
|
|
tablePtr->dataSource = DATA_NONE;
|
4457 |
|
|
if (tablePtr->caching) {
|
4458 |
|
|
tablePtr->dataSource |= DATA_CACHE;
|
4459 |
|
|
}
|
4460 |
|
|
if (tablePtr->command && tablePtr->useCmd) {
|
4461 |
|
|
tablePtr->dataSource |= DATA_COMMAND;
|
4462 |
|
|
} else if (tablePtr->arrayVar) {
|
4463 |
|
|
tablePtr->dataSource |= DATA_ARRAY;
|
4464 |
|
|
}
|
4465 |
|
|
|
4466 |
|
|
/* Check to see if the array variable was changed */
|
4467 |
|
|
if (strcmp((tablePtr->arrayVar?tablePtr->arrayVar:""),(oldVar?oldVar:""))) {
|
4468 |
|
|
/* only do the following if arrayVar is our data source */
|
4469 |
|
|
if (tablePtr->dataSource & DATA_ARRAY) {
|
4470 |
|
|
/* ensure that the cache will flush later so it gets the new values */
|
4471 |
|
|
oldCaching = !(tablePtr->caching);
|
4472 |
|
|
}
|
4473 |
|
|
/* remove the trace on the old array variable if there was one */
|
4474 |
|
|
if (oldVar != NULL)
|
4475 |
|
|
Tcl_UntraceVar(interp, oldVar,
|
4476 |
|
|
TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_GLOBAL_ONLY,
|
4477 |
|
|
(Tcl_VarTraceProc *)TableVarProc, (ClientData)tablePtr);
|
4478 |
|
|
/* Check whether variable is an array and trace it if it is */
|
4479 |
|
|
if (tablePtr->arrayVar != NULL) {
|
4480 |
|
|
/* does the variable exist as an array? */
|
4481 |
|
|
if (Tcl_SetVar2(interp, tablePtr->arrayVar, TEST_KEY, "",
|
4482 |
|
|
TCL_GLOBAL_ONLY) == NULL) {
|
4483 |
|
|
Tcl_DStringAppend(&error, "invalid variable value \"", -1);
|
4484 |
|
|
Tcl_DStringAppend(&error, tablePtr->arrayVar, -1);
|
4485 |
|
|
Tcl_DStringAppend(&error, "\": could not be made an array", -1);
|
4486 |
|
|
ckfree(tablePtr->arrayVar);
|
4487 |
|
|
tablePtr->arrayVar = NULL;
|
4488 |
|
|
tablePtr->dataSource &= ~DATA_ARRAY;
|
4489 |
|
|
result = TCL_ERROR;
|
4490 |
|
|
} else {
|
4491 |
|
|
Tcl_UnsetVar2(interp, tablePtr->arrayVar, TEST_KEY, TCL_GLOBAL_ONLY);
|
4492 |
|
|
/* remove the effect of the evaluation */
|
4493 |
|
|
/* set a trace on the variable */
|
4494 |
|
|
Tcl_TraceVar(interp, tablePtr->arrayVar,
|
4495 |
|
|
TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_GLOBAL_ONLY,
|
4496 |
|
|
(Tcl_VarTraceProc *)TableVarProc, (ClientData) tablePtr);
|
4497 |
|
|
|
4498 |
|
|
/* only do the following if arrayVar is our data source */
|
4499 |
|
|
if (tablePtr->dataSource & DATA_ARRAY) {
|
4500 |
|
|
/* get the current value of the selection */
|
4501 |
|
|
TableGetActiveBuf(tablePtr);
|
4502 |
|
|
}
|
4503 |
|
|
}
|
4504 |
|
|
}
|
4505 |
|
|
}
|
4506 |
|
|
if ((tablePtr->command && tablePtr->useCmd && !oldUse) ||
|
4507 |
|
|
(tablePtr->arrayVar && !(tablePtr->useCmd) && oldUse)) {
|
4508 |
|
|
/* our effective data source changed, so flush and
|
4509 |
|
|
* retrieve new active buffer */
|
4510 |
|
|
TableFlushCache(tablePtr);
|
4511 |
|
|
TableGetActiveBuf(tablePtr);
|
4512 |
|
|
forceUpdate = 1;
|
4513 |
|
|
} else if (oldCaching != tablePtr->caching) {
|
4514 |
|
|
/* caching changed, so just clear the cache for safety */
|
4515 |
|
|
TableFlushCache(tablePtr);
|
4516 |
|
|
forceUpdate = 1;
|
4517 |
|
|
}
|
4518 |
|
|
|
4519 |
|
|
/* set up the default column width and row height */
|
4520 |
|
|
Tk_GetFontMetrics(tablePtr->defaultTag.tkfont, &fm);
|
4521 |
|
|
tablePtr->charWidth = Tk_TextWidth(tablePtr->defaultTag.tkfont, "0", 1);
|
4522 |
|
|
tablePtr->charHeight = fm.linespace + 2;
|
4523 |
|
|
|
4524 |
|
|
if (tablePtr->insertWidth <= 0) {
|
4525 |
|
|
tablePtr->insertWidth = 2;
|
4526 |
|
|
}
|
4527 |
|
|
if (tablePtr->insertBorderWidth > tablePtr->insertWidth/2) {
|
4528 |
|
|
tablePtr->insertBorderWidth = tablePtr->insertWidth/2;
|
4529 |
|
|
}
|
4530 |
|
|
tablePtr->highlightWidth = MAX(0,tablePtr->highlightWidth);
|
4531 |
|
|
/* the border must be >= 0 */
|
4532 |
|
|
tablePtr->borderWidth = MAX(0,tablePtr->borderWidth);
|
4533 |
|
|
/* when drawing fast or single, the border must be <= 1 */
|
4534 |
|
|
if (tablePtr->drawMode & (DRAW_MODE_SINGLE|DRAW_MODE_FAST)) {
|
4535 |
|
|
tablePtr->borderWidth = MIN(1,tablePtr->borderWidth);
|
4536 |
|
|
}
|
4537 |
|
|
|
4538 |
|
|
/* Ensure that certain values are within proper constraints */
|
4539 |
|
|
tablePtr->rows = MAX(1,tablePtr->rows);
|
4540 |
|
|
tablePtr->cols = MAX(1,tablePtr->cols);
|
4541 |
|
|
tablePtr->titleRows = MIN(MAX(0,tablePtr->titleRows),tablePtr->rows);
|
4542 |
|
|
tablePtr->titleCols = MIN(MAX(0,tablePtr->titleCols),tablePtr->cols);
|
4543 |
|
|
tablePtr->padX = MAX(0,tablePtr->padX);
|
4544 |
|
|
tablePtr->padY = MAX(0,tablePtr->padY);
|
4545 |
|
|
tablePtr->maxReqCols = MAX(0,tablePtr->maxReqCols);
|
4546 |
|
|
tablePtr->maxReqRows = MAX(0,tablePtr->maxReqRows);
|
4547 |
|
|
|
4548 |
|
|
/*
|
4549 |
|
|
* Claim the selection if we've suddenly started exporting it and
|
4550 |
|
|
* there is a selection to export.
|
4551 |
|
|
*/
|
4552 |
|
|
if (tablePtr->exportSelection && !oldExport &&
|
4553 |
|
|
(Tcl_FirstHashEntry(tablePtr->selCells, &search) != NULL)) {
|
4554 |
|
|
Tk_OwnSelection(tablePtr->tkwin, XA_PRIMARY, TableLostSelection,
|
4555 |
|
|
(ClientData) tablePtr);
|
4556 |
|
|
}
|
4557 |
|
|
|
4558 |
|
|
/* only do the full reconfigure if absolutely necessary */
|
4559 |
|
|
if (!forceUpdate) {
|
4560 |
|
|
int i;
|
4561 |
|
|
for (i = 0; i < argc-1; i += 2) {
|
4562 |
|
|
if (Cmd_GetValue(update_config, argv[i])) {
|
4563 |
|
|
forceUpdate = 1;
|
4564 |
|
|
break;
|
4565 |
|
|
}
|
4566 |
|
|
}
|
4567 |
|
|
}
|
4568 |
|
|
if (forceUpdate) {
|
4569 |
|
|
/*
|
4570 |
|
|
* Calculate the row and column starts
|
4571 |
|
|
* Adjust the top left corner of the internal display
|
4572 |
|
|
*/
|
4573 |
|
|
TableAdjustParams(tablePtr);
|
4574 |
|
|
/* reset the cursor */
|
4575 |
|
|
TableConfigCursor(tablePtr);
|
4576 |
|
|
/* set up the background colour in the window */
|
4577 |
|
|
Tk_SetBackgroundFromBorder(tablePtr->tkwin, tablePtr->defaultTag.bg);
|
4578 |
|
|
/* set the geometry and border */
|
4579 |
|
|
TableGeometryRequest(tablePtr);
|
4580 |
|
|
Tk_SetInternalBorder(tablePtr->tkwin, tablePtr->highlightWidth);
|
4581 |
|
|
/* invalidate the whole table */
|
4582 |
|
|
TableInvalidateAll(tablePtr, INV_HIGHLIGHT);
|
4583 |
|
|
}
|
4584 |
|
|
/* FIX this is goofy because the result could be munged by other
|
4585 |
|
|
* functions. Needs to be improved */
|
4586 |
|
|
Tcl_ResetResult(interp);
|
4587 |
|
|
if (result == TCL_ERROR) {
|
4588 |
|
|
Tcl_AddErrorInfo(interp, "\t(configuring table widget)");
|
4589 |
|
|
Tcl_DStringResult(interp, &error);
|
4590 |
|
|
}
|
4591 |
|
|
Tcl_DStringFree(&error);
|
4592 |
|
|
return result;
|
4593 |
|
|
}
|
4594 |
|
|
|
4595 |
|
|
#ifndef CLASSPATCH
|
4596 |
|
|
/*
|
4597 |
|
|
* As long as we wait for the Function in general
|
4598 |
|
|
*
|
4599 |
|
|
* This parses the "-class" option for the table.
|
4600 |
|
|
*/
|
4601 |
|
|
static void
|
4602 |
|
|
Tk_ClassOption(Tk_Window tkwin, char *defaultclass, int *argcp, char ***argvp)
|
4603 |
|
|
{
|
4604 |
|
|
char *classname = (((*argcp)<3) || (strcmp((*argvp)[2],"-class"))) ?
|
4605 |
|
|
defaultclass : ((*argcp)-=2,(*argcp)+=2,(*argvp)[1]);
|
4606 |
|
|
Tk_SetClass(tkwin,classname);
|
4607 |
|
|
}
|
4608 |
|
|
#endif
|
4609 |
|
|
|
4610 |
|
|
/*
|
4611 |
|
|
*----------------------------------------------------------------------
|
4612 |
|
|
*
|
4613 |
|
|
* TableCmdDeletedProc --
|
4614 |
|
|
*
|
4615 |
|
|
* This procedure is invoked when a widget command is deleted. If
|
4616 |
|
|
* the widget isn't already in the process of being destroyed,
|
4617 |
|
|
* this command destroys it.
|
4618 |
|
|
*
|
4619 |
|
|
* Results:
|
4620 |
|
|
* None.
|
4621 |
|
|
*
|
4622 |
|
|
* Side effects:
|
4623 |
|
|
* The widget is destroyed.
|
4624 |
|
|
*
|
4625 |
|
|
*----------------------------------------------------------------------
|
4626 |
|
|
*/
|
4627 |
|
|
static void
|
4628 |
|
|
TableCmdDeletedProc(ClientData clientData)
|
4629 |
|
|
{
|
4630 |
|
|
Table *tablePtr = (Table *) clientData;
|
4631 |
|
|
Tk_Window tkwin;
|
4632 |
|
|
|
4633 |
|
|
/*
|
4634 |
|
|
* This procedure could be invoked either because the window was
|
4635 |
|
|
* destroyed and the command was then deleted (in which case tkwin
|
4636 |
|
|
* is NULL) or because the command was deleted, and then this procedure
|
4637 |
|
|
* destroys the widget.
|
4638 |
|
|
*/
|
4639 |
|
|
|
4640 |
|
|
/* This is needed to avoid bug where the DLL is unloaded before
|
4641 |
|
|
* the table is properly destroyed */
|
4642 |
|
|
Tcl_DeleteExitHandler((Tcl_ExitProc *) TableCmdDeletedProc,
|
4643 |
|
|
(ClientData) tablePtr);
|
4644 |
|
|
if (tablePtr->tkwin != NULL) {
|
4645 |
|
|
tkwin = tablePtr->tkwin;
|
4646 |
|
|
tablePtr->tkwin = NULL;
|
4647 |
|
|
Tk_DestroyWindow(tkwin);
|
4648 |
|
|
}
|
4649 |
|
|
}
|
4650 |
|
|
|
4651 |
|
|
/*
|
4652 |
|
|
*--------------------------------------------------------------
|
4653 |
|
|
*
|
4654 |
|
|
* TableCmd --
|
4655 |
|
|
* This procedure is invoked to process the "table" Tcl
|
4656 |
|
|
* command. See the user documentation for details on what
|
4657 |
|
|
* it does.
|
4658 |
|
|
*
|
4659 |
|
|
* Results:
|
4660 |
|
|
* A standard Tcl result.
|
4661 |
|
|
*
|
4662 |
|
|
* Side effects:
|
4663 |
|
|
* See the user documentation.
|
4664 |
|
|
*
|
4665 |
|
|
*--------------------------------------------------------------
|
4666 |
|
|
*/
|
4667 |
|
|
static int
|
4668 |
|
|
TableCmd(clientData, interp, argc, argv)
|
4669 |
|
|
ClientData clientData; /* Main window associated with
|
4670 |
|
|
* interpreter. */
|
4671 |
|
|
Tcl_Interp *interp; /* Current interpreter. */
|
4672 |
|
|
int argc; /* Number of arguments. */
|
4673 |
|
|
char **argv; /* Argument strings. */
|
4674 |
|
|
{
|
4675 |
|
|
register Table *tablePtr;
|
4676 |
|
|
Tk_Window tkwin = (Tk_Window) clientData;
|
4677 |
|
|
Tk_Window new;
|
4678 |
|
|
|
4679 |
|
|
if (argc < 2) {
|
4680 |
|
|
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
4681 |
|
|
argv[0], " pathname ?options?\"", (char *) NULL);
|
4682 |
|
|
return TCL_ERROR;
|
4683 |
|
|
}
|
4684 |
|
|
|
4685 |
|
|
new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
|
4686 |
|
|
if (new == NULL) {
|
4687 |
|
|
return TCL_ERROR;
|
4688 |
|
|
}
|
4689 |
|
|
|
4690 |
|
|
tablePtr = (Table *) ckalloc(sizeof(Table));
|
4691 |
|
|
tablePtr->tkwin = new;
|
4692 |
|
|
tablePtr->display = Tk_Display(new);
|
4693 |
|
|
tablePtr->interp = interp;
|
4694 |
|
|
|
4695 |
|
|
tablePtr->topRow = 0;
|
4696 |
|
|
tablePtr->leftCol = 0;
|
4697 |
|
|
tablePtr->anchorRow = -1;
|
4698 |
|
|
tablePtr->anchorCol = -1;
|
4699 |
|
|
tablePtr->activeRow = -1;
|
4700 |
|
|
tablePtr->activeCol = -1;
|
4701 |
|
|
tablePtr->oldTopRow = -1;
|
4702 |
|
|
tablePtr->oldLeftCol = -1;
|
4703 |
|
|
tablePtr->oldActRow = -1;
|
4704 |
|
|
tablePtr->oldActCol = -1;
|
4705 |
|
|
tablePtr->seen[0] = -1;
|
4706 |
|
|
tablePtr->icursor = 0;
|
4707 |
|
|
tablePtr->flags = 0;
|
4708 |
|
|
|
4709 |
|
|
tablePtr->colPixels = (int *) 0;
|
4710 |
|
|
tablePtr->rowPixels = (int *) 0;
|
4711 |
|
|
tablePtr->colStarts = (int *) 0;
|
4712 |
|
|
tablePtr->rowStarts = (int *) 0;
|
4713 |
|
|
tablePtr->cursorTimer = (Tcl_TimerToken)0;
|
4714 |
|
|
tablePtr->flashTimer = (Tcl_TimerToken)0;
|
4715 |
|
|
tablePtr->dataSource = DATA_NONE;
|
4716 |
|
|
tablePtr->activeBuf = ckalloc(1);
|
4717 |
|
|
*(tablePtr->activeBuf) = '\0';
|
4718 |
|
|
tablePtr->activeLayout = NULL;
|
4719 |
|
|
|
4720 |
|
|
/* misc tables */
|
4721 |
|
|
tablePtr->tagTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
|
4722 |
|
|
Tcl_InitHashTable(tablePtr->tagTable, TCL_STRING_KEYS);
|
4723 |
|
|
tablePtr->winTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
|
4724 |
|
|
Tcl_InitHashTable(tablePtr->winTable, TCL_STRING_KEYS);
|
4725 |
|
|
|
4726 |
|
|
/* internal value cache */
|
4727 |
|
|
tablePtr->cache = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
|
4728 |
|
|
Tcl_InitHashTable(tablePtr->cache, TCL_STRING_KEYS);
|
4729 |
|
|
|
4730 |
|
|
/* style hash tables */
|
4731 |
|
|
tablePtr->colWidths = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
|
4732 |
|
|
Tcl_InitHashTable(tablePtr->colWidths, TCL_ONE_WORD_KEYS);
|
4733 |
|
|
tablePtr->rowHeights = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
|
4734 |
|
|
Tcl_InitHashTable(tablePtr->rowHeights, TCL_ONE_WORD_KEYS);
|
4735 |
|
|
|
4736 |
|
|
/* style hash tables */
|
4737 |
|
|
tablePtr->rowStyles = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
|
4738 |
|
|
Tcl_InitHashTable(tablePtr->rowStyles, TCL_ONE_WORD_KEYS);
|
4739 |
|
|
tablePtr->colStyles = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
|
4740 |
|
|
Tcl_InitHashTable(tablePtr->colStyles, TCL_ONE_WORD_KEYS);
|
4741 |
|
|
tablePtr->cellStyles = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
|
4742 |
|
|
Tcl_InitHashTable(tablePtr->cellStyles, TCL_STRING_KEYS);
|
4743 |
|
|
|
4744 |
|
|
/* special style hash tables */
|
4745 |
|
|
tablePtr->flashCells = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
|
4746 |
|
|
Tcl_InitHashTable(tablePtr->flashCells, TCL_STRING_KEYS);
|
4747 |
|
|
tablePtr->selCells = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
|
4748 |
|
|
Tcl_InitHashTable(tablePtr->selCells, TCL_STRING_KEYS);
|
4749 |
|
|
|
4750 |
|
|
tablePtr->rows = 0;
|
4751 |
|
|
tablePtr->cols = 0;
|
4752 |
|
|
tablePtr->selectMode = NULL;
|
4753 |
|
|
tablePtr->selectTitles = 0;
|
4754 |
|
|
tablePtr->defRowHeight = 0;
|
4755 |
|
|
tablePtr->defColWidth = 0;
|
4756 |
|
|
tablePtr->arrayVar = NULL;
|
4757 |
|
|
tablePtr->borderWidth = 0;
|
4758 |
|
|
tablePtr->defaultTag.anchor = TK_ANCHOR_CENTER;
|
4759 |
|
|
tablePtr->defaultTag.bg = NULL;
|
4760 |
|
|
tablePtr->defaultTag.fg = NULL;
|
4761 |
|
|
tablePtr->defaultTag.tkfont = NULL;
|
4762 |
|
|
tablePtr->defaultTag.image = NULL;
|
4763 |
|
|
tablePtr->defaultTag.imageStr = NULL;
|
4764 |
|
|
tablePtr->defaultTag.justify = TK_JUSTIFY_LEFT;
|
4765 |
|
|
tablePtr->defaultTag.multiline = 1;
|
4766 |
|
|
tablePtr->defaultTag.relief = TK_RELIEF_FLAT;
|
4767 |
|
|
tablePtr->defaultTag.showtext = 0;
|
4768 |
|
|
tablePtr->defaultTag.state = STATE_UNKNOWN;
|
4769 |
|
|
tablePtr->defaultTag.wrap = 0;
|
4770 |
|
|
tablePtr->yScrollCmd = NULL;
|
4771 |
|
|
tablePtr->xScrollCmd = NULL;
|
4772 |
|
|
tablePtr->insertBg = NULL;
|
4773 |
|
|
tablePtr->cursor = None;
|
4774 |
|
|
tablePtr->bdcursor = None;
|
4775 |
|
|
tablePtr->titleRows = 0;
|
4776 |
|
|
tablePtr->titleCols = 0;
|
4777 |
|
|
tablePtr->drawMode = DRAW_MODE_TK_COMPAT;
|
4778 |
|
|
tablePtr->colStretch = STRETCH_MODE_NONE;
|
4779 |
|
|
tablePtr->rowStretch = STRETCH_MODE_NONE;
|
4780 |
|
|
tablePtr->maxWidth = 0;
|
4781 |
|
|
tablePtr->maxHeight = 0;
|
4782 |
|
|
tablePtr->charWidth = 0;
|
4783 |
|
|
tablePtr->charHeight = 0;
|
4784 |
|
|
tablePtr->colOffset = 0;
|
4785 |
|
|
tablePtr->rowOffset = 0;
|
4786 |
|
|
tablePtr->flashTime = 2;
|
4787 |
|
|
tablePtr->rowTagCmd = NULL;
|
4788 |
|
|
tablePtr->colTagCmd = NULL;
|
4789 |
|
|
tablePtr->highlightWidth = 0;
|
4790 |
|
|
tablePtr->highlightBgColorPtr = NULL;
|
4791 |
|
|
tablePtr->highlightColorPtr = NULL;
|
4792 |
|
|
tablePtr->takeFocus = NULL;
|
4793 |
|
|
tablePtr->state = STATE_NORMAL;
|
4794 |
|
|
tablePtr->insertWidth = 0;
|
4795 |
|
|
tablePtr->insertBorderWidth = 0;
|
4796 |
|
|
tablePtr->insertOnTime = 0;
|
4797 |
|
|
tablePtr->insertOffTime = 0;
|
4798 |
|
|
tablePtr->invertSelected = 0;
|
4799 |
|
|
tablePtr->autoClear = 0;
|
4800 |
|
|
tablePtr->flashMode = 0;
|
4801 |
|
|
tablePtr->exportSelection = 1;
|
4802 |
|
|
tablePtr->rowSep = NULL;
|
4803 |
|
|
tablePtr->colSep = NULL;
|
4804 |
|
|
tablePtr->browseCmd = NULL;
|
4805 |
|
|
tablePtr->command = NULL;
|
4806 |
|
|
tablePtr->selCmd = NULL;
|
4807 |
|
|
tablePtr->valCmd = NULL;
|
4808 |
|
|
tablePtr->validate = 0;
|
4809 |
|
|
tablePtr->useCmd = 1;
|
4810 |
|
|
tablePtr->caching = 0;
|
4811 |
|
|
tablePtr->padX = 0;
|
4812 |
|
|
tablePtr->padY = 0;
|
4813 |
|
|
tablePtr->maxReqCols = 0;
|
4814 |
|
|
tablePtr->maxReqRows = 0;
|
4815 |
|
|
tablePtr->maxReqWidth = 800;
|
4816 |
|
|
tablePtr->maxReqHeight = 600;
|
4817 |
|
|
|
4818 |
|
|
/* selection handlers needed here */
|
4819 |
|
|
|
4820 |
|
|
Tk_ClassOption(new, "Table", &argc, &argv);
|
4821 |
|
|
Tk_CreateEventHandler(tablePtr->tkwin,
|
4822 |
|
|
PointerMotionMask|ExposureMask|StructureNotifyMask|FocusChangeMask|VisibilityChangeMask,
|
4823 |
|
|
TableEventProc, (ClientData) tablePtr);
|
4824 |
|
|
Tk_CreateSelHandler(tablePtr->tkwin, XA_PRIMARY, XA_STRING,
|
4825 |
|
|
TableFetchSelection, (ClientData) tablePtr, XA_STRING);
|
4826 |
|
|
|
4827 |
|
|
tablePtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(tablePtr->tkwin),
|
4828 |
|
|
TableWidgetCmd, (ClientData) tablePtr,
|
4829 |
|
|
(Tcl_CmdDeleteProc *) TableCmdDeletedProc);
|
4830 |
|
|
if (TableConfigure(interp, tablePtr, argc - 2, argv + 2, 0, 1) != TCL_OK) {
|
4831 |
|
|
Tk_DestroyWindow(new);
|
4832 |
|
|
return TCL_ERROR;
|
4833 |
|
|
}
|
4834 |
|
|
TableInitTags(tablePtr);
|
4835 |
|
|
/* This is needed to avoid bug where the DLL is unloaded before
|
4836 |
|
|
* the table is properly destroyed */
|
4837 |
|
|
Tcl_CreateExitHandler((Tcl_ExitProc *) TableCmdDeletedProc,
|
4838 |
|
|
(ClientData) tablePtr);
|
4839 |
|
|
Tcl_SetResult(interp, Tk_PathName(tablePtr->tkwin), TCL_STATIC);
|
4840 |
|
|
return TCL_OK;
|
4841 |
|
|
}
|
4842 |
|
|
|
4843 |
|
|
/* Function to call on loading the Table module */
|
4844 |
|
|
|
4845 |
|
|
EXPORT(int,Tktable_Init)(interp)
|
4846 |
|
|
Tcl_Interp *interp;
|
4847 |
|
|
{
|
4848 |
|
|
static char init_script[] =
|
4849 |
|
|
"if {[catch {source \"" TCL_RUNTIME "\"}]} {\n"
|
4850 |
|
|
#include "tkTabletcl.h"
|
4851 |
|
|
"}\n";
|
4852 |
|
|
if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL ||
|
4853 |
|
|
Tcl_PkgRequire(interp, "Tk", TK_VERSION, 0) == NULL ||
|
4854 |
|
|
Tcl_PkgProvide(interp, "Tktable", TBL_VERSION) != TCL_OK) {
|
4855 |
|
|
return TCL_ERROR;
|
4856 |
|
|
}
|
4857 |
|
|
Tcl_CreateCommand(interp, TBL_COMMAND, TableCmd,
|
4858 |
|
|
(ClientData) Tk_MainWindow(interp),
|
4859 |
|
|
(Tcl_CmdDeleteProc *) NULL);
|
4860 |
|
|
|
4861 |
|
|
return Tcl_Eval(interp, init_script);
|
4862 |
|
|
}
|
4863 |
|
|
|
4864 |
|
|
EXPORT(int,Tktable_SafeInit)(interp)
|
4865 |
|
|
Tcl_Interp *interp;
|
4866 |
|
|
{
|
4867 |
|
|
return Tktable_Init(interp);
|
4868 |
|
|
}
|
4869 |
|
|
|
4870 |
|
|
#ifdef _WIN32
|
4871 |
|
|
/*
|
4872 |
|
|
*----------------------------------------------------------------------
|
4873 |
|
|
*
|
4874 |
|
|
* DllEntryPoint --
|
4875 |
|
|
*
|
4876 |
|
|
* This wrapper function is used by Windows to invoke the
|
4877 |
|
|
* initialization code for the DLL. If we are compiling
|
4878 |
|
|
* with Visual C++, this routine will be renamed to DllMain.
|
4879 |
|
|
* routine.
|
4880 |
|
|
*
|
4881 |
|
|
* Results:
|
4882 |
|
|
* Returns TRUE;
|
4883 |
|
|
*
|
4884 |
|
|
* Side effects:
|
4885 |
|
|
* None.
|
4886 |
|
|
*
|
4887 |
|
|
*----------------------------------------------------------------------
|
4888 |
|
|
*/
|
4889 |
|
|
|
4890 |
|
|
BOOL APIENTRY
|
4891 |
|
|
DllEntryPoint(hInst, reason, reserved)
|
4892 |
|
|
HINSTANCE hInst; /* Library instance handle. */
|
4893 |
|
|
DWORD reason; /* Reason this function is being called. */
|
4894 |
|
|
LPVOID reserved; /* Not used. */
|
4895 |
|
|
{
|
4896 |
|
|
return TRUE;
|
4897 |
|
|
}
|
4898 |
|
|
#endif
|