1
2 /* $Id: tixHLHdr.c,v 1.1.1.1 2000/05/17 11:08:42 idiscovery Exp $ */
3
4 /*
5 * tixHLHdr.c ---
6 *
7 *
8 * Implements headers for tixHList widgets
9 *
10 * Copyright (c) 1996, Expert Interface Technologies
11 *
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 *
15 */
16
17 #include "tixPort.h"
18 #include "tixInt.h"
19 #include "tixHList.h"
20 #include "tixDef.h"
21
22 static TIX_DECLARE_SUBCMD(Tix_HLHdrCreate);
23 static TIX_DECLARE_SUBCMD(Tix_HLHdrConfig);
24 static TIX_DECLARE_SUBCMD(Tix_HLHdrCGet);
25 static TIX_DECLARE_SUBCMD(Tix_HLHdrDelete);
26 static TIX_DECLARE_SUBCMD(Tix_HLHdrExist);
27 static TIX_DECLARE_SUBCMD(Tix_HLHdrSize);
28 static TIX_DECLARE_SUBCMD(Tix_HLHdrHeight);
29
30 static void FreeWindowItem _ANSI_ARGS_((Tcl_Interp *interp,
31 WidgetPtr wPtr, HListHeader *hPtr));
32 static void FreeHeader _ANSI_ARGS_((Tcl_Interp *interp,
33 WidgetPtr wPtr, HListHeader *hPtr));
34 static HListHeader* AllocHeader _ANSI_ARGS_((Tcl_Interp *interp,
35 WidgetPtr wPtr));
36 static HListHeader* Tix_HLGetHeader _ANSI_ARGS_((Tcl_Interp * interp,
37 WidgetPtr wPtr, Tcl_Obj * string,
38 int requireIPtr));
39
40 static Tk_ConfigSpec headerConfigSpecs[] = {
41 {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
42 (char *) NULL, 0, 0},
43
44 {TK_CONFIG_PIXELS, "-borderwidth", "headerBorderWidth", "BorderWidth",
45 DEF_HLISTHEADER_BORDER_WIDTH, Tk_Offset(HListHeader, borderWidth), 0},
46
47 {TK_CONFIG_BORDER, "-headerbackground", "headerBackground", "Background",
48 DEF_HLISTHEADER_BG_COLOR, Tk_Offset(HListHeader, background),
49 TK_CONFIG_COLOR_ONLY},
50
51 {TK_CONFIG_BORDER, "-headerbackground", "headerBackground", "Background",
52 DEF_HLISTHEADER_BG_MONO, Tk_Offset(HListHeader, background),
53 TK_CONFIG_MONO_ONLY},
54
55 {TK_CONFIG_RELIEF, "-relief", "headerRelief", "Relief",
56 DEF_HLISTHEADER_RELIEF, Tk_Offset(HListHeader, relief), 0},
57
58 {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
59 (char *) NULL, 0, 0}
60 };
61
62 /*----------------------------------------------------------------------
63 *
64 * Local functions
65 *
66 *----------------------------------------------------------------------
67 */
68
69 static HListHeader*
AllocHeader(interp,wPtr)70 AllocHeader(interp, wPtr)
71 Tcl_Interp *interp;
72 WidgetPtr wPtr;
73 {
74 HListHeader * hPtr = (HListHeader*)ckalloc(sizeof(HListHeader));
75 hPtr->type = HLTYPE_HEADER;
76 hPtr->self = (char*)hPtr;
77 hPtr->wPtr = wPtr;
78 hPtr->iPtr = NULL;
79 hPtr->width = 0;
80 hPtr->background = NULL;
81 hPtr->relief = TK_RELIEF_RAISED;
82 hPtr->borderWidth = 2;
83
84 if (Tk_ConfigureWidget(interp, wPtr->headerWin, headerConfigSpecs,
85 0, 0, (char *)hPtr, 0) != TCL_OK) {
86 /* some unrecoverable errors */
87 return NULL;
88 }
89 Tk_SetBackgroundFromBorder(wPtr->headerWin, hPtr->background);
90
91 return hPtr;
92 }
93
94 static void
FreeWindowItem(interp,wPtr,hPtr)95 FreeWindowItem(interp, wPtr, hPtr)
96 Tcl_Interp *interp;
97 WidgetPtr wPtr;
98 HListHeader *hPtr;
99 {
100 Tix_WindowItemListRemove(&wPtr->mappedWindows,
101 hPtr->iPtr);
102 }
103
104 static void
FreeHeader(interp,wPtr,hPtr)105 FreeHeader(interp, wPtr, hPtr)
106 Tcl_Interp *interp;
107 WidgetPtr wPtr;
108 HListHeader *hPtr;
109 {
110 if (hPtr->iPtr) {
111 if (Tix_DItemType(hPtr->iPtr) == TIX_DITEM_WINDOW) {
112 FreeWindowItem(interp, wPtr, hPtr);
113 }
114 Tix_DItemFree(hPtr->iPtr);
115 }
116
117 Tk_FreeOptions(headerConfigSpecs, (char *)hPtr, wPtr->dispData.display, 0);
118 ckfree((char*) hPtr);
119 }
120
121 static HListHeader*
Tix_HLGetHeader(interp,wPtr,string,requireIPtr)122 Tix_HLGetHeader(interp, wPtr, string, requireIPtr)
123 Tcl_Interp * interp;
124 WidgetPtr wPtr;
125 Tcl_Obj * string;
126 int requireIPtr;
127 {
128 int column;
129
130 if (Tcl_GetIntFromObj(interp, string, &column) != TCL_OK) {
131 return NULL;
132 }
133 if (column >= wPtr->numColumns || column < 0) {
134 Tcl_AppendResult(interp, "Column \"", Tcl_GetString(string),
135 "\" does not exist", (char*)NULL);
136 return NULL;
137 }
138 if (requireIPtr && wPtr->headers[column]->iPtr == NULL) {
139 Tcl_AppendResult(interp, "Column \"", Tcl_GetString(string),
140 "\" does not have a header", (char*)NULL);
141 return NULL;
142 }
143
144 return wPtr->headers[column];
145 }
146
147 int
Tix_HLCreateHeaders(interp,wPtr)148 Tix_HLCreateHeaders(interp, wPtr)
149 Tcl_Interp *interp;
150 WidgetPtr wPtr;
151 {
152 int i;
153
154 wPtr->headers = (HListHeader**)
155 ckalloc(sizeof(HListHeader*) * wPtr->numColumns);
156
157 for (i=0; i<wPtr->numColumns; i++) {
158 wPtr->headers[i] = NULL;
159 }
160
161 for (i=0; i<wPtr->numColumns; i++) {
162 if ((wPtr->headers[i] = AllocHeader(interp, wPtr)) == NULL) {
163 return TCL_ERROR;
164 }
165 }
166
167 wPtr->headerDirty = 1;
168 return TCL_OK;
169 }
170
Tix_HLFreeHeaders(interp,wPtr)171 void Tix_HLFreeHeaders(interp, wPtr)
172 Tcl_Interp *interp;
173 WidgetPtr wPtr;
174 {
175 int i;
176
177 if (wPtr->headers == NULL) {
178 return;
179 }
180
181 for (i=0; i<wPtr->numColumns; i++) {
182 if (wPtr->headers[i] != NULL) {
183 FreeHeader(interp, wPtr, wPtr->headers[i]);
184 }
185 }
186
187 ckfree((char*)wPtr->headers);
188 }
189
190 void
Tix_HLDrawHeader(wPtr,pixmap,gc,hdrX,hdrY,hdrW,hdrH,xOffset)191 Tix_HLDrawHeader(wPtr, pixmap, gc, hdrX, hdrY, hdrW, hdrH, xOffset)
192 WidgetPtr wPtr;
193 Pixmap pixmap;
194 GC gc;
195 int hdrX;
196 int hdrY;
197 int hdrW;
198 int hdrH;
199 int xOffset;
200 {
201 int i, x, y;
202 int drawnWidth; /* how much of the header have I drawn? */
203 int width; /* width of the current header item */
204 int winItemExtra; /* window items need a bit extra offset
205 * because they must be places relative to
206 * the main window, not the header subwindow
207 */
208 x = hdrX - xOffset;
209 y = hdrY;
210 drawnWidth = 0;
211
212 winItemExtra = wPtr->borderWidth + wPtr->highlightWidth;
213
214 if (wPtr->needToRaise) {
215 /* the needToRaise flag is set every time a new window item is
216 * created inside the header of the HList.
217 *
218 * We need to make sure that the windows items in the list
219 * body are clipped by the header subwindow. However, the window
220 * items inside the header should be over the header subwindow.
221 *
222 * The two XRaiseWindow calls in this function make sure that
223 * the stacking relationship as described above always hold
224 */
225 XRaiseWindow(Tk_Display(wPtr->headerWin),
226 Tk_WindowId(wPtr->headerWin));
227 }
228
229 for (i=0; i<wPtr->numColumns; i++) {
230 HListHeader * hPtr = wPtr->headers[i];
231 width = wPtr->actualSize[i].width;
232
233 if (i == wPtr->numColumns-1) {
234 /* If the widget is wider than required,
235 * We need to extend the last item to the end of the list,
236 * or otherwise we'll see a curtailed header
237 */
238 if (drawnWidth + width <hdrW) {
239 width = hdrW - drawnWidth;
240 }
241 }
242
243 Tk_Fill3DRectangle(wPtr->dispData.tkwin, pixmap, hPtr->background,
244 x, y, width, wPtr->headerHeight, hPtr->borderWidth,
245 hPtr->relief);
246
247 /* Note when we draw the item, we use the
248 * wPtr->actualSize[i].width instead of the (possibly extended) width
249 * so that the header is well-aligned with the element columns.
250 */
251 if (hPtr->iPtr) {
252 int itemX, itemY;
253 itemX = x+hPtr->borderWidth;
254 itemY = y+hPtr->borderWidth;
255
256 if (Tix_DItemType(hPtr->iPtr) == TIX_DITEM_WINDOW) {
257 itemX += winItemExtra;
258 itemY += winItemExtra;
259 }
260
261 Tix_DItemDisplay(pixmap, gc, hPtr->iPtr,
262 itemX, itemY,
263 wPtr->actualSize[i].width - 2*hPtr->borderWidth,
264 wPtr->headerHeight - 2*hPtr->borderWidth,
265 TIX_DITEM_NORMAL_FG);
266
267 if (wPtr->needToRaise &&
268 Tix_DItemType(hPtr->iPtr) == TIX_DITEM_WINDOW) {
269 TixWindowItem * wiPtr;
270
271 wiPtr = (TixWindowItem *)hPtr->iPtr;
272 if (Tk_WindowId(wiPtr->tkwin) == None) {
273 Tk_MakeWindowExist(wiPtr->tkwin);
274 }
275
276 XRaiseWindow(Tk_Display(wiPtr->tkwin),
277 Tk_WindowId(wiPtr->tkwin));
278 }
279 }
280
281 x += width;
282 drawnWidth += width;
283
284 #if 0
285 /* %% funny, doesn't work */
286 if (drawnWidth >= hdrW) {
287 /* The rest is invisible. Don't bother to draw */
288 break;
289 }
290 #endif
291 }
292
293 wPtr->needToRaise = 0;
294 }
295
Tix_HLComputeHeaderGeometry(wPtr)296 void Tix_HLComputeHeaderGeometry(wPtr)
297 WidgetPtr wPtr;
298 {
299 int i;
300
301 wPtr->headerHeight = 0;
302
303 for (i=0; i<wPtr->numColumns; i++) {
304 int height;
305 int width;
306
307 if (wPtr->headers[i]->iPtr) {
308 width = Tix_DItemWidth (wPtr->headers[i]->iPtr);
309 height = Tix_DItemHeight(wPtr->headers[i]->iPtr);
310 } else {
311 width = 0;
312 height = 0;
313 }
314
315 width += wPtr->headers[i]->borderWidth * 2;
316 height += wPtr->headers[i]->borderWidth * 2;
317
318 wPtr->headers[i]->width = width;
319
320 if (height > wPtr->headerHeight) {
321 wPtr->headerHeight = height;
322 }
323 }
324
325 wPtr->headerDirty = 0;
326 }
327
328 /*----------------------------------------------------------------------
329 * "header" sub command
330 *----------------------------------------------------------------------
331 */
332 int
Tix_HLHeader(clientData,interp,argc,argv)333 Tix_HLHeader(clientData, interp, argc, argv)
334 ClientData clientData;
335 Tcl_Interp *interp; /* Current interpreter. */
336 int argc; /* Number of arguments. */
337 char **argv; /* Argument strings. */
338 {
339 static Tix_SubCmdInfo subCmdInfo[] = {
340 {TIX_DEFAULT_LEN, "cget", 2, 2, Tix_HLHdrCGet,
341 "column option"},
342 {TIX_DEFAULT_LEN, "configure", 1, TIX_VAR_ARGS, Tix_HLHdrConfig,
343 "column ?option? ?value ...?"},
344 {TIX_DEFAULT_LEN, "create", 1, TIX_VAR_ARGS, Tix_HLHdrCreate,
345 "column ?option value ...?"},
346 {TIX_DEFAULT_LEN, "delete", 1, 1, Tix_HLHdrDelete,
347 "column"},
348 {TIX_DEFAULT_LEN, "exists", 1, 1, Tix_HLHdrExist,
349 "column"},
350 {TIX_DEFAULT_LEN, "size", 1, 1, Tix_HLHdrSize,
351 "column"},
352 {TIX_DEFAULT_LEN, "height", 0, 0, Tix_HLHdrHeight,
353 ""},
354 };
355 static Tix_CmdInfo cmdInfo = {
356 Tix_ArraySize(subCmdInfo), 1, TIX_VAR_ARGS, "?option? ?arg ...?",
357 };
358
359 return Tix_HandleSubCmds(&cmdInfo, subCmdInfo, clientData,
360 interp, argc+1, argv-1);
361 }
362
363 /*----------------------------------------------------------------------
364 * "header cget" sub command
365 *----------------------------------------------------------------------
366 */
367 static int
Tix_HLHdrCGet(clientData,interp,argc,argv)368 Tix_HLHdrCGet(clientData, interp, argc, argv)
369 ClientData clientData;
370 Tcl_Interp *interp; /* Current interpreter. */
371 int argc; /* Number of arguments. */
372 char **argv; /* Argument strings. */
373 {
374 WidgetPtr wPtr = (WidgetPtr) clientData;
375 HListHeader * hPtr;
376
377 if ((hPtr=Tix_HLGetHeader(interp, wPtr, objv[0], 1)) == NULL) {
378 return TCL_ERROR;
379 }
380
381 return Tix_ConfigureValue2(interp, wPtr->dispData.tkwin,
382 (char*)hPtr, headerConfigSpecs, hPtr->iPtr, argv[1], 0);
383 }
384
385 /*----------------------------------------------------------------------
386 * "header configure" sub command
387 *----------------------------------------------------------------------
388 */
389 static int
Tix_HLHdrConfig(clientData,interp,argc,argv)390 Tix_HLHdrConfig(clientData, interp, argc, argv)
391 ClientData clientData;
392 Tcl_Interp *interp; /* Current interpreter. */
393 int argc; /* Number of arguments. */
394 char **argv; /* Argument strings. */
395 {
396 WidgetPtr wPtr = (WidgetPtr) clientData;
397 HListHeader * hPtr;
398
399 if ((hPtr=Tix_HLGetHeader(interp, wPtr, objv[0], 1)) == NULL) {
400 return TCL_ERROR;
401 }
402
403 if (argc == 1) {
404 return Tix_ConfigureInfo2(interp, wPtr->dispData.tkwin,
405 (char*)hPtr, headerConfigSpecs, hPtr->iPtr,
406 (char *) NULL, 0);
407 } else if (argc == 2) {
408 return Tix_ConfigureInfo2(interp, wPtr->dispData.tkwin,
409 (char*)hPtr, headerConfigSpecs, hPtr->iPtr,
410 (char *) argv[1], 0);
411 } else {
412 int sizeChanged = 0;
413
414 if (Tix_WidgetConfigure2(interp, wPtr->dispData.tkwin,
415 (char*)hPtr, headerConfigSpecs, hPtr->iPtr,
416 argc-1, argv+1, TK_CONFIG_ARGV_ONLY, 0, &sizeChanged) != TCL_OK) {
417 return TCL_ERROR;
418 }
419 if (sizeChanged) {
420 wPtr->headerDirty = 1;
421 Tix_HLResizeWhenIdle(wPtr);
422 }
423 return TCL_OK;
424 }
425 }
426
427
428 /*----------------------------------------------------------------------
429 * "header create" sub command
430 *----------------------------------------------------------------------
431 */
432 static int
Tix_HLHdrCreate(clientData,interp,argc,argv)433 Tix_HLHdrCreate(clientData, interp, argc, argv)
434 ClientData clientData;
435 Tcl_Interp *interp; /* Current interpreter. */
436 int argc; /* Number of arguments. */
437 char **argv; /* Argument strings. */
438 {
439 WidgetPtr wPtr = (WidgetPtr) clientData;
440 HListHeader * hPtr;
441 int i;
442 Tix_DItem * iPtr;
443 char * ditemType = NULL;
444
445 if ((hPtr=Tix_HLGetHeader(interp, wPtr, objv[0], 0)) == NULL) {
446 return TCL_ERROR;
447 }
448
449 if ((argc %2) == 0) {
450 Tcl_AppendResult(interp, "value for \"", argv[argc-1],
451 "\" missing", NULL);
452 return TCL_ERROR;
453 }
454 for (i=1; i<argc; i+=2) {
455 if (strncmp(argv[i], "-itemtype", strlen(argv[i])) == 0) {
456 ditemType = argv[i+1];
457 }
458 }
459 if (ditemType == NULL) {
460 ditemType = wPtr->diTypePtr->name;
461 }
462
463 iPtr = Tix_DItemCreate(&wPtr->dispData, ditemType);
464 if (iPtr == NULL) {
465 return TCL_ERROR;
466 }
467 if (Tix_DItemType(iPtr) == TIX_DITEM_WINDOW) {
468 wPtr->needToRaise = 1;
469 }
470
471 /*
472 * mark clientData to NULL. This will tell DItemSizeChanged()
473 * that ths item belongs to the header
474 */
475 iPtr->base.clientData = (ClientData)hPtr;
476
477 if (hPtr->iPtr != NULL) {
478 if (Tix_DItemType(hPtr->iPtr) == TIX_DITEM_WINDOW) {
479 FreeWindowItem(interp, wPtr, hPtr);
480 }
481 Tix_DItemFree(hPtr->iPtr);
482 }
483 hPtr->iPtr = iPtr;
484
485 if (Tix_WidgetConfigure2(wPtr->dispData.interp, wPtr->dispData.tkwin,
486 (char*)hPtr, headerConfigSpecs, hPtr->iPtr, argc-1, argv+1, 0,
487 1, NULL) != TCL_OK) {
488 return TCL_ERROR;
489 }
490
491
492 wPtr->headerDirty = 1;
493 Tix_HLResizeWhenIdle(wPtr);
494
495 return TCL_OK;
496 }
497 /*----------------------------------------------------------------------
498 * "header delete" sub command
499 *----------------------------------------------------------------------
500 */
501 static int
Tix_HLHdrDelete(clientData,interp,argc,argv)502 Tix_HLHdrDelete(clientData, interp, argc, argv)
503 ClientData clientData;
504 Tcl_Interp *interp; /* Current interpreter. */
505 int argc; /* Number of arguments. */
506 char **argv; /* Argument strings. */
507 {
508 WidgetPtr wPtr = (WidgetPtr) clientData;
509 HListHeader * hPtr;
510
511 if ((hPtr=Tix_HLGetHeader(interp, wPtr, objv[0], 1)) == NULL) {
512 return TCL_ERROR;
513 }
514
515 if (Tix_DItemType(hPtr->iPtr) == TIX_DITEM_WINDOW) {
516 FreeWindowItem(interp, wPtr, hPtr);
517 }
518
519 /* Free the item and leave a blank! */
520 Tix_DItemFree(hPtr->iPtr);
521 hPtr->iPtr = NULL;
522
523 wPtr->headerDirty = 1;
524 Tix_HLResizeWhenIdle(wPtr);
525
526 return TCL_OK;
527 }
528 /*----------------------------------------------------------------------
529 * "header exist" sub command
530 *----------------------------------------------------------------------
531 */
532 static int
Tix_HLHdrExist(clientData,interp,argc,argv)533 Tix_HLHdrExist(clientData, interp, argc, argv)
534 ClientData clientData;
535 Tcl_Interp *interp; /* Current interpreter. */
536 int argc; /* Number of arguments. */
537 char **argv; /* Argument strings. */
538 {
539 WidgetPtr wPtr = (WidgetPtr) clientData;
540 HListHeader * hPtr;
541
542 if ((hPtr=Tix_HLGetHeader(interp, wPtr, objv[0], 0)) == NULL) {
543 return TCL_ERROR;
544 }
545
546 if (hPtr->iPtr == NULL) {
547 Tcl_AppendResult(interp, "0", NULL);
548 } else {
549 Tcl_AppendResult(interp, "1", NULL);
550 }
551
552 return TCL_OK;
553 }
554
555 /*----------------------------------------------------------------------
556 * "header size" sub command
557 *----------------------------------------------------------------------
558 */
559 static int
Tix_HLHdrSize(clientData,interp,argc,argv)560 Tix_HLHdrSize(clientData, interp, argc, argv)
561 ClientData clientData;
562 Tcl_Interp *interp; /* Current interpreter. */
563 int argc; /* Number of arguments. */
564 char **argv; /* Argument strings. */
565 {
566 WidgetPtr wPtr = (WidgetPtr) clientData;
567 HListHeader * hPtr;
568
569 if ((hPtr=Tix_HLGetHeader(interp, wPtr, objv[0], 1)) == NULL) {
570 return TCL_ERROR;
571 }
572
573 if (hPtr->iPtr == NULL) {
574 Tcl_AppendResult(interp, "entry \"", argv[0],
575 "\" does not have a header", (char*)NULL);
576 return TCL_ERROR;
577 }
578 Tcl_IntResults(interp,2, 0,
579 Tix_DItemWidth(hPtr->iPtr),
580 Tix_DItemHeight(hPtr->iPtr));
581 return TCL_OK;
582 }
583
584 /*----------------------------------------------------------------------
585 * "header height" sub command
586 *----------------------------------------------------------------------
587 */
588 static int
Tix_HLHdrHeight(clientData,interp,argc,argv)589 Tix_HLHdrHeight(clientData, interp, argc, argv)
590 ClientData clientData;
591 Tcl_Interp *interp; /* Current interpreter. */
592 int argc; /* Number of arguments. */
593 char **argv; /* Argument strings. */
594 {
595 WidgetPtr wPtr = (WidgetPtr) clientData;
596
597 if (wPtr->headerDirty) {
598 Tix_HLComputeHeaderGeometry(wPtr);
599 }
600
601 Tcl_SetObjResult(interp,Tcl_NewIntObj(wPtr->headerHeight));
602 return TCL_OK;
603 }
604
605