/* $Id: tixDItem.c,v 1.1.1.1 2000/05/17 11:08:38 idiscovery Exp $ */
/*
* tixDItem.c --
*
* This file implements the "Display Items" in the Tix library.
*
* Since many Tix widgets use the same type of display items, for
* example, text items, image items, or text-image items (used in
* HList, TList and Table), it makes sense to provide a set of
* common routines to support these display items. Code re-use is
* the major issue: we don't want to re-define almost the same
* configSpecs again and again in different widgets. Therefore,
* all display items provide common methods to configure,
* display, calculate geometry, etc.
*
*
* Copyright (c) 1996, Expert Interface Technologies
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
*/
#include "tixPort.h"
#include "tix.h"
#include "tixInt.h"
#ifdef _LANG
#define FORWARD extern
#define LINKAGE
#define DItemParseProc TixDItemParseProc
#define DItemPrintProc TixDItemPrintProc
#else
#define FORWARD static
#define LINKAGE static
#endif
FORWARD int DItemParseProc _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj * value,
char *widRec, int offset));
FORWARD Tcl_Obj * DItemPrintProc _ANSI_ARGS_((
ClientData clientData, Tk_Window tkwin, char *widRec,
int offset, Tcl_FreeProc **freeProcPtr));
/*----------------------------------------------------------------------
*
*
* PUBLIC INTERFACE
*
*
* The following functions are called by widget implementors
*
*----------------------------------------------------------------------
*/
/* Tix_AddDItemType, Tix_GetDItemType --
*
*
* Maintain a list of item types, each identifies by a unique string
* name;
*/
static Tix_DItemInfo * diTypes = NULL;
void Tix_AddDItemType(diTypePtr)
Tix_DItemInfo * diTypePtr;
{
diTypePtr->next = diTypes;
diTypes = diTypePtr;
}
Tix_DItemInfo * Tix_GetDItemType(interp, type)
Tcl_Interp * interp;
char * type;
{
Tix_DItemInfo * diTypePtr;
for (diTypePtr = diTypes; diTypePtr; diTypePtr = diTypePtr->next) {
if (strcmp(type,diTypePtr->name)==0) {
return diTypePtr;
}
}
if (interp) {
Tcl_AppendResult(interp, "unknown display type \"", type, "\"", NULL);
}
return NULL;
}
/*----------------------------------------------------------------------
* Tix_DItemCreate --
*
* Create a display item according to the "type" string.
*
*----------------------------------------------------------------------
*/
Tix_DItem * Tix_DItemCreate(ddPtr, type)
Tix_DispData * ddPtr;
char * type;
{
Tix_DItemInfo * diTypePtr;
if ((diTypePtr = Tix_GetDItemType(ddPtr->interp, type)) == NULL) {
return NULL;
}
return diTypePtr->createProc(ddPtr, diTypePtr);
}
/*----------------------------------------------------------------------
* Tix_DItemConfigure --
*
* Configures a display item.
*
*----------------------------------------------------------------------
*/
int Tix_DItemConfigure(iPtr, argc, argv, flags)
Tix_DItem * iPtr;
int argc;
char ** argv;
int flags;
{
return iPtr->base.diTypePtr->configureProc(iPtr, argc, argv, flags);
}
void Tix_DItemDisplay(pixmap, gc, iPtr, x, y, width, height, flags)
Pixmap pixmap;
GC gc;
Tix_DItem * iPtr;
int x;
int y;
int width;
int height;
int flags;
{
iPtr->base.diTypePtr->displayProc(pixmap, gc, iPtr, x, y,
width, height, flags);
}
void Tix_DItemFree(iPtr)
Tix_DItem * iPtr;
{
iPtr->base.diTypePtr->freeProc(iPtr);
/*
* When it comes to here, iPtr is no longer a valid pointer!
*/
}
void Tix_DItemCalculateSize(iPtr)
Tix_DItem * iPtr;
{
iPtr->base.diTypePtr->calculateSizeProc(iPtr);
}
char * Tix_DItemComponent(iPtr, x, y)
Tix_DItem * iPtr;
int x;
int y;
{
return (iPtr->base.diTypePtr->componentProc(iPtr, x, y));
}
/*----------------------------------------------------------------------
* Tix_FreeArgumentList --
*
* Free the argument lists allocated by Tix_SplitConfig;
*----------------------------------------------------------------------
*/
void
Tix_FreeArgumentList(argListPtr)
Tix_ArgumentList *argListPtr;
{
int i;
for (i=0; i<argListPtr->numLists; i++) {
ckfree((char*)argListPtr->arg[i].argv);
}
if (argListPtr->arg != argListPtr->preAlloc) {
ckfree((char*)argListPtr->arg);
}
}
/*----------------------------------------------------------------------
* Tix_SplitConfig --
*
* Split the command line arguments according for several configurable
* objects.
*----------------------------------------------------------------------
*/
int
Tix_SplitConfig(interp, tkwin, specsList, numLists, argc, argv, argListPtr)
Tcl_Interp * interp;
Tk_Window tkwin;
Tk_ConfigSpec ** specsList; /* a list of two or more config spec
* arrays */
int numLists;
int argc;
char ** argv;
Tix_ArgumentList * argListPtr;
{
Tix_Argument *arg;
int i, n, code = TCL_OK;
Tk_ConfigSpec *specPtr;
size_t len;
int found;
if (argc % 2) {
Tcl_AppendResult(interp, "value for \"", argv[argc-1],
"\" missing", (char *) NULL);
return TCL_ERROR;
}
if (numLists > FIXED_SIZE) {
arg = (Tix_Argument*)ckalloc(numLists * sizeof(Tix_Argument));
} else {
arg = argListPtr->preAlloc;
}
argListPtr->arg = arg;
argListPtr->numLists = numLists;
for (i=0; i<numLists; i++) {
arg[i].argc = 0;
arg[i].objv = (Tcl_Obj **)ckalloc(argc * sizeof(Tcl_Obj *));
}
/* Split the arguments for the appropriate objects */
for (n=0; n<argc; n+=2) {
len = strlen(argv[n]);
found = 0;
for (i=0; i<numLists; i++) {
for (specPtr=specsList[i];
specPtr->type != TK_CONFIG_END;
specPtr++) {
if (specPtr->argvName == NULL) {
continue;
}
if (strncmp(argv[n], specPtr->argvName, len) == 0) {
arg[i].objv[arg[i].argc++] = objv[n ];
arg[i].objv[arg[i].argc++] = objv[n+1];
found = 1;
break;
}
}
}
if (found == 0) {
Tcl_AppendResult(interp, "unknown option \"", argv[n],
"\"", (char *) NULL);
code = TCL_ERROR;
goto done;
}
}
done:
if (code == TCL_ERROR) {
Tix_FreeArgumentList(argListPtr);
}
return code;
}
int
Tix_MultiConfigureInfo(interp, tkwin, specsList, numLists, widgRecList,
argvName, flags, request)
Tcl_Interp *interp; /* Interpreter for error reporting. */
Tk_Window tkwin; /* Window corresponding to widgRec. */
Tk_ConfigSpec **specsList; /* Describes legal options. */
int numLists;
char **widgRecList; /* Record whose fields contain current
* values for options. */
char *argvName; /* If non-NULL, indicates a single option
* whose info is to be returned. Otherwise
* info is returned for all options. */
int flags; /* Used to specify additional flags
* that must be present in config specs
* for them to be considered. */
int request;
{
int i, found;
Tk_ConfigSpec *specPtr;
size_t len;
if (argvName != NULL) {
len = strlen(argvName);
for (found=0,i=0; i<numLists; i++) {
for (specPtr=specsList[i];
specPtr->type != TK_CONFIG_END;
specPtr++) {
if (specPtr->argvName == NULL) {
continue;
}
if (strncmp(argvName, specPtr->argvName, len) == 0) {
found = 1;
goto done;
}
}
}
done:
if (!found) {
Tcl_AppendResult(interp, "unknown option \"", argvName,
"\"", (char *) NULL);
return TCL_ERROR;
}
if (request == TIX_CONFIG_INFO) {
if (widgRecList[i] != NULL) {
return Tk_ConfigureInfo(interp, tkwin, specsList[i],
widgRecList[i], argvName, flags);
} else {
return TCL_OK;
}
} else {
if (widgRecList[i] != NULL) {
return Tk_ConfigureValue(interp, tkwin, specsList[i],
widgRecList[i], argvName, flags);
} else {
return TCL_OK;
}
}
}
Tcl_ResetResult(interp);
for (i=0; i<numLists; i++) {
if (widgRecList[i] != NULL) {
Tk_ConfigureInfo(interp, tkwin, specsList[i], widgRecList[i],
NULL, flags);
/* FIXME - check error code ?? */
}
}
return TCL_OK;
}
/*----------------------------------------------------------------------
* Tix_ConfigureValue2 --
*
*
* Returns the config information of a entry element (of an HList,
* for example) and its display item.
*----------------------------------------------------------------------
*/
int
Tix_ConfigureValue2(interp, tkwin, entRec, entConfigSpecs, iPtr,
argvName, flags)
Tcl_Interp *interp; /* Interpreter for error reporting. */
Tk_Window tkwin; /* Window corresponding to widgRec. */
char * entRec;
Tk_ConfigSpec *entConfigSpecs; /* Describes legal options of the entry */
Tix_DItem * iPtr; /* points to the entry's data record */
char *argvName; /* If non-NULL, indicates a single option
* whose info is to be returned. Otherwise
* info is returned for all options. */
int flags; /* Used to specify additional flags
* that must be present in config specs
* for them to be considered. */
{
Tk_ConfigSpec *specsList[2];
char *widgRecList[2];
specsList[0] = entConfigSpecs;
specsList[1] = Tix_DItemConfigSpecs(iPtr);
widgRecList[1] = (char*)iPtr;
widgRecList[0] = (char*)entRec;
return Tix_MultiConfigureInfo(interp, tkwin, specsList, 2, widgRecList,
argvName, flags, TIX_CONFIG_VALUE);
}
/*----------------------------------------------------------------------
* Tix_ConfigureInfo2 --
*
*
* Returns the config information of a entry element (of an HList,
* for example) and its display item.
*----------------------------------------------------------------------
*/
int
Tix_ConfigureInfo2(interp, tkwin, entRec, entConfigSpecs, iPtr,
argvName, flags)
Tcl_Interp *interp; /* Interpreter for error reporting. */
Tk_Window tkwin; /* Window corresponding to widgRec. */
char * entRec;
Tk_ConfigSpec *entConfigSpecs; /* Describes legal options of the entry */
Tix_DItem * iPtr; /* points to the entry's data record */
char *argvName; /* If non-NULL, indicates a single option
* whose info is to be returned. Otherwise
* info is returned for all options. */
int flags; /* Used to specify additional flags
* that must be present in config specs
* for them to be considered. */
{
Tk_ConfigSpec *specsList[2];
char *widgRecList[2];
specsList[0] = entConfigSpecs;
specsList[1] = Tix_DItemConfigSpecs(iPtr);
widgRecList[1] = (char*)iPtr;
widgRecList[0] = (char*)entRec;
return Tix_MultiConfigureInfo(interp, tkwin, specsList, 2, widgRecList,
argvName, flags, TIX_CONFIG_INFO);
}
int
Tix_WidgetConfigure2(interp, tkwin, entRec, entConfigSpecs, iPtr,
argc, argv, flags, forced, sizeChanged_ret)
Tcl_Interp *interp; /* Interpreter for error reporting. */
Tk_Window tkwin; /* Window corresponding to widgRec. */
char * entRec;
Tk_ConfigSpec *entConfigSpecs; /* Describes legal options of the entry */
Tix_DItem * iPtr; /* points to the entry's data record */
int argc;
char ** argv;
int flags;
int forced; /* forced configure of DItem? */
int * sizeChanged_ret;
{
Tix_ArgumentList argList;
Tk_ConfigSpec *specsList[2];
char *widgRecList[2];
int code = TCL_OK;
int dummy;
if (sizeChanged_ret == NULL) {
sizeChanged_ret = &dummy;
}
specsList[0] = entConfigSpecs;
specsList[1] = Tix_DItemConfigSpecs(iPtr);
widgRecList[0] = (char*)entRec;
widgRecList[1] = (char*)iPtr;
if (Tix_SplitConfig(interp, tkwin, specsList,
2, argc, argv, &argList) != TCL_OK) {
return TCL_ERROR;
}
/* Handle the info specific to the entry */
if (argList.arg[0].argc > 0) {
if (Tk_ConfigureWidget(interp, tkwin,
entConfigSpecs, argList.arg[0].argc, argList.arg[0].argv,
(char*)entRec, flags) != TCL_OK) {
code = TCL_ERROR;
goto done;
}
}
if (iPtr == NULL) {
goto done;
}
if (argList.arg[1].argc > 0 || forced) {
int oldSize[2];
oldSize[0] = iPtr->base.size[0];
oldSize[1] = iPtr->base.size[1];
if (Tix_DItemConfigure(iPtr, argList.arg[1].argc,
argList.arg[1].argv, flags) != TCL_OK) {
code = TCL_ERROR;
goto done;
}
if (oldSize[0] != iPtr->base.size[0] ||
oldSize[1] != iPtr->base.size[1]) {
* sizeChanged_ret = 1;
} else {
* sizeChanged_ret = 0;
}
}
done:
Tix_FreeArgumentList(&argList);
return code;
}
/*----------------------------------------------------------------------
*
* The Tix Customed Config Options
*
*----------------------------------------------------------------------
*/
/*
* The global data structures to use in widget configSpecs arrays
*
* These are declared in <tixConfig.h>
*/
#ifndef _LANG
Tk_CustomOption tixConfigItemType = {
DItemParseProc, DItemPrintProc, 0,
};
#endif
/*----------------------------------------------------------------------
* DItemParseProc --
*
* Parse the text string and store the Tix_DItemType information
* inside the widget record.
*----------------------------------------------------------------------
*/
LINKAGE int
DItemParseProc(clientData, interp, tkwin, value, widRec,offset)
ClientData clientData;
Tcl_Interp *interp;
Tk_Window tkwin;
Tcl_Obj * value;
char *widRec;
int offset;
{
Tix_DItemInfo *newPtr;
Tix_DItemInfo **ptr = (Tix_DItemInfo **)(widRec + offset);
if (value == NULL) {
newPtr = NULL;
} else {
newPtr = Tix_GetDItemType(interp, Tcl_GetString(value));
if (newPtr == NULL) {
return TCL_ERROR;
}
}
*ptr = newPtr;
return TCL_OK;
}
LINKAGE Tcl_Obj *
DItemPrintProc(clientData, tkwin, widRec,offset, freeProcPtr)
ClientData clientData;
Tk_Window tkwin;
char *widRec;
int offset;
Tcl_FreeProc **freeProcPtr;
{
Tix_DItemInfo *diTypePtr = *((Tix_DItemInfo**)(widRec+offset));
if (diTypePtr != NULL) {
return LangStringArg(diTypePtr->name);
} else {
return 0;
}
}
/*----------------------------------------------------------------------
*
*
* PRIVATE INTERFACE
*
*
* The following functions are called by display type implementors
*
*----------------------------------------------------------------------
*/
/* The priority is selected > disabled > active > normal */
void TixGetColorDItemGC(iPtr, backGC_ret, foreGC_ret, flags)
Tix_DItem * iPtr;
GC * backGC_ret;
GC * foreGC_ret;
int flags;
{
TixColorStyle * stylePtr = (TixColorStyle *) iPtr->base.stylePtr;
if (flags & TIX_DITEM_SELECTED_FG) {
*foreGC_ret = stylePtr->colors[TIX_DITEM_SELECTED].foreGC;
}
else if (flags & TIX_DITEM_DISABLED_FG) {
*foreGC_ret = stylePtr->colors[TIX_DITEM_DISABLED].foreGC;
}
else if (flags & TIX_DITEM_ACTIVE_FG) {
*foreGC_ret = stylePtr->colors[TIX_DITEM_ACTIVE].foreGC;
}
else if (flags & TIX_DITEM_NORMAL_FG) {
*foreGC_ret = stylePtr->colors[TIX_DITEM_NORMAL].foreGC;
}
else {
*foreGC_ret = None;
}
if (flags & TIX_DITEM_SELECTED_BG) {
*backGC_ret = stylePtr->colors[TIX_DITEM_SELECTED].backGC;
}
else if (flags & TIX_DITEM_DISABLED_BG) {
*backGC_ret = stylePtr->colors[TIX_DITEM_DISABLED].backGC;
}
else if (flags & TIX_DITEM_ACTIVE_BG) {
*backGC_ret = stylePtr->colors[TIX_DITEM_ACTIVE].backGC;
}
else if (flags & TIX_DITEM_NORMAL_BG) {
*backGC_ret = stylePtr->colors[TIX_DITEM_NORMAL].backGC;
}
else {
*backGC_ret = None;
}
}
/*----------------------------------------------------------------------
* TixDItemGetAnchor --
*
* Calculate the position of the element according to its anchor
*----------------------------------------------------------------------
*/
void
TixDItemGetAnchor(anchor, x, y, cav_w, cav_h, width, height, x_ret, y_ret)
Tk_Anchor anchor;
int x;
int y;
int cav_w;
int cav_h;
int width;
int height;
int * x_ret;
int * y_ret;
{
if (width > cav_w) {
* x_ret = x;
} else {
int rem = cav_w - width;
switch (anchor) {
case TK_ANCHOR_NW: case TK_ANCHOR_W: case TK_ANCHOR_SW:
* x_ret = x;
break;
case TK_ANCHOR_N: case TK_ANCHOR_CENTER: case TK_ANCHOR_S:
* x_ret = x + rem/2;
break;
default:
* x_ret = x + rem;
}
}
if (height > cav_h) {
* y_ret = y;
}
else {
int rem = cav_h - height;
switch (anchor) {
case TK_ANCHOR_NW: case TK_ANCHOR_N: case TK_ANCHOR_NE:
* y_ret = y;
break;
case TK_ANCHOR_W: case TK_ANCHOR_CENTER: case TK_ANCHOR_E:
* y_ret = y + rem/2;
if ((rem % 2) == 1) {
/* Usually it looks better if we shift down one pixel
* if the hight of the region is an odd number of pixels
*/
* y_ret += 1;
}
break;
default:
* y_ret = y + rem;
}
}
}
void Tix_DItemDrawBackground(pixmap, gc, iPtr, x, y, width, height, flags)
Pixmap pixmap;
GC gc;
Tix_DItem * iPtr;
int x;
int y;
int width;
int height;
int flags;
{
GC foreGC, backGC;
switch Tix_DItemType(iPtr) {
case TIX_DITEM_WINDOW:
case TIX_DITEM_NONE:
/* not a colored item */
return;
}
TixGetColorDItemGC(iPtr, &backGC, &foreGC, flags);
if (backGC != None) {
/* Draw the background */
XFillRectangle(iPtr->base.ddPtr->display, pixmap,
backGC,
x, y, width, height);
}
}