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