/* * Tabular.c -- Implementation of Tabular item. * * Authors : Patrick Lecoanet. * Creation date : * * $Id$ */ /* * Copyright (c) 1993 - 2005 CENA, Patrick Lecoanet -- * * See the file "Copyright" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * */ #include "Types.h" #include "WidgetInfo.h" #include "Item.h" #include "Geo.h" #include "tkZinc.h" #include #include static const char rcsid[] = "$Id$"; static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; /* ********************************************************************************** * * Specific Tabular item record * ********************************************************************************** */ typedef struct _TabularItemStruct { ZnItemStruct header; /* Public data */ ZnPoint pos; Tk_Anchor anchor; Tk_Anchor connection_anchor; /* Private data */ ZnFieldSetStruct field_set; } TabularItemStruct, *TabularItem; static ZnAttrConfig tabular_attrs[] = { { ZN_CONFIG_ANCHOR, "-anchor", NULL, Tk_Offset(TabularItemStruct, anchor), 0, ZN_COORDS_FLAG, False }, { ZN_CONFIG_BOOL, "-composealpha", NULL, Tk_Offset(TabularItemStruct, header.flags), ZN_COMPOSE_ALPHA_BIT, ZN_DRAW_FLAG, False }, { ZN_CONFIG_BOOL, "-composerotation", NULL, Tk_Offset(TabularItemStruct, header.flags), ZN_COMPOSE_ROTATION_BIT, ZN_COORDS_FLAG, False }, { ZN_CONFIG_BOOL, "-composescale", NULL, Tk_Offset(TabularItemStruct, header.flags), ZN_COMPOSE_SCALE_BIT, ZN_COORDS_FLAG, False }, { ZN_CONFIG_ITEM, "-connecteditem", NULL, Tk_Offset(TabularItemStruct, header.connected_item), 0, ZN_COORDS_FLAG|ZN_ITEM_FLAG, False }, { ZN_CONFIG_ANCHOR, "-connectionanchor", NULL, Tk_Offset(TabularItemStruct, connection_anchor), 0, ZN_COORDS_FLAG, False }, { ZN_CONFIG_LABEL_FORMAT, "-labelformat", NULL, Tk_Offset(TabularItemStruct, field_set.label_format), 0, ZN_COORDS_FLAG|ZN_CLFC_FLAG, False }, { ZN_CONFIG_UINT, "-numfields", NULL, Tk_Offset(TabularItemStruct, field_set.num_fields), 0, 0, True }, { ZN_CONFIG_POINT, "-position", NULL, Tk_Offset(TabularItemStruct, pos), 0, ZN_COORDS_FLAG, False}, { ZN_CONFIG_PRI, "-priority", NULL, Tk_Offset(TabularItemStruct, header.priority), 0, ZN_DRAW_FLAG|ZN_REPICK_FLAG, False }, { ZN_CONFIG_BOOL, "-sensitive", NULL, Tk_Offset(TabularItemStruct, header.flags), ZN_SENSITIVE_BIT, ZN_REPICK_FLAG, False }, { ZN_CONFIG_TAG_LIST, "-tags", NULL, Tk_Offset(TabularItemStruct, header.tags), 0, 0, False }, { ZN_CONFIG_BOOL, "-visible", NULL, Tk_Offset(TabularItemStruct, header.flags), ZN_VISIBLE_BIT, ZN_DRAW_FLAG|ZN_REPICK_FLAG|ZN_VIS_FLAG, False }, { ZN_CONFIG_END, NULL, NULL, 0, 0, 0, False } }; /* ********************************************************************************** * * Init -- * ********************************************************************************** */ static int Init(ZnItem item, int *argc, Tcl_Obj *CONST *args[]) { ZnWInfo *wi = item->wi; TabularItem tab = (TabularItem) item; ZnFieldSet field_set = &tab->field_set; int num_fields; item->priority = 1; SET(item->flags, ZN_VISIBLE_BIT); SET(item->flags, ZN_SENSITIVE_BIT); SET(item->flags, ZN_COMPOSE_ALPHA_BIT); SET(item->flags, ZN_COMPOSE_SCALE_BIT); SET(item->flags, ZN_COMPOSE_ROTATION_BIT); tab->anchor = TK_ANCHOR_NW; tab->connection_anchor = TK_ANCHOR_SW; tab->pos.x = tab->pos.y = 0.0; field_set->item = item; field_set->label_format = NULL; /* * Then try to see if some fields are needed. */ if ((*argc > 0) && (Tcl_GetString((*args)[0])[0] != '-') && (Tcl_GetIntFromObj(wi->interp, (*args)[0], &num_fields) != TCL_ERROR)) { field_set->num_fields = num_fields; *args += 1; *argc -= 1; ZnFIELD.InitFields(field_set); } else { Tcl_AppendResult(wi->interp, " number of fields expected", NULL); return TCL_ERROR; } item->part_sensitive = 0; return TCL_OK; } /* ********************************************************************************** * * Clone -- * ********************************************************************************** */ static void Clone(ZnItem item) { ZnFieldSet fs = &((TabularItem) item)->field_set; ZnFIELD.CloneFields(fs); fs->item = item; } /* ********************************************************************************** * * Destroy -- * ********************************************************************************** */ static void Destroy(ZnItem item) { ZnFIELD.FreeFields(&((TabularItem) item)->field_set); } /* ********************************************************************************** * * Configure -- * ********************************************************************************** */ static int Configure(ZnItem item, int argc, Tcl_Obj *CONST argv[], int *flags) { ZnItem old_connected; old_connected = item->connected_item; if (ZnConfigureAttributes(item->wi, item, item, tabular_attrs, argc, argv, flags) == TCL_ERROR) { return TCL_ERROR; } if (ISSET(*flags, ZN_ITEM_FLAG)) { /* * If the new connected item is not appropriate back up * to the old one. */ if ((item->connected_item == ZN_NO_ITEM) || (ISSET(item->connected_item->class->flags, ZN_CLASS_HAS_ANCHORS) && (item->parent == item->connected_item->parent))) { ZnITEM.UpdateItemDependency(item, old_connected); } else { item->connected_item = old_connected; } } return TCL_OK; } /* ********************************************************************************** * * Query -- * ********************************************************************************** */ static int Query(ZnItem item, int argc, Tcl_Obj *CONST argv[]) { if (ZnQueryAttribute(item->wi->interp, item, tabular_attrs, argv[0]) == TCL_ERROR) { return TCL_ERROR; } return TCL_OK; } /* ********************************************************************************** * * ComputeCoordinates -- * ********************************************************************************** */ static void ComputeCoordinates(ZnItem item, ZnBool force) { TabularItem tab = (TabularItem) item; ZnWInfo *wi = item->wi; ZnFieldSet field_set = &tab->field_set; ZnDim width, height; ZnResetBBox(&item->item_bounding_box); if (field_set->label_format && field_set->num_fields) { ZnFIELD.GetLabelBBox(field_set, &width, &height); /* * The connected item support anchors, this is checked by * configure. */ if (item->connected_item != ZN_NO_ITEM) { item->connected_item->class->GetAnchor(item->connected_item, tab->connection_anchor, &field_set->label_pos); } else { ZnPoint pos; pos.x = pos.y = 0; ZnTransformPoint(wi->current_transfo, &pos, &field_set->label_pos); } ZnAnchor2Origin(&field_set->label_pos, width, height, tab->anchor, &field_set->label_pos); /* * Setup the item bounding box. */ item->item_bounding_box.orig = field_set->label_pos; item->item_bounding_box.corner.x = field_set->label_pos.x + width; item->item_bounding_box.corner.y = field_set->label_pos.y + height; /* * Need to slightly increase the bbox for GL thick lines */ #ifdef GL item->item_bounding_box.orig.x -= 1; item->item_bounding_box.orig.y -= 1; item->item_bounding_box.corner.x += 1; item->item_bounding_box.corner.y += 1; #endif /* * Update connected items. */ SET(item->flags, ZN_UPDATE_DEPENDENT_BIT); } } /* ********************************************************************************** * * ToArea -- * Tell if the object is entirely outside (-1), * entirely inside (1) or in between (0). * ********************************************************************************** */ static int ToArea(ZnItem item, ZnToArea ta) { return ZnFIELD.FieldsToArea(&((TabularItem) item)->field_set, ta->area); } /* ********************************************************************************** * * Draw -- * ********************************************************************************** */ static void Draw(ZnItem item) { ZnFIELD.DrawFields(&((TabularItem) item)->field_set); } /* ********************************************************************************** * * Render -- * ********************************************************************************** */ static void Render(ZnItem item) { ZnFIELD.RenderFields(&((TabularItem) item)->field_set); } /* ********************************************************************************** * * IsSensitive -- * ********************************************************************************** */ static ZnBool IsSensitive(ZnItem item, int item_part) { if (ISCLEAR(item->flags, ZN_SENSITIVE_BIT) || !item->parent->class->IsSensitive(item->parent, ZN_NO_PART)) { return False; } if (item_part == ZN_NO_PART) { return ISSET(item->flags, ZN_SENSITIVE_BIT); } else { return ZnFIELD.IsFieldSensitive(&((TabularItem) item)->field_set, item_part); } } /* ********************************************************************************** * * Pick -- * We tell what our label tells. * ********************************************************************************** */ static double Pick(ZnItem item, ZnPick ps) { int best_part; double dist; dist = ZnFIELD.FieldsPick(&((TabularItem) item)->field_set, ps->point, &best_part); /*printf("tabular %d reporting part %d, distance %lf\n", item->id, best_part, dist);*/ if (dist <= 0.0) { dist = 0.0; } ps->a_part = best_part; return dist; } /* ********************************************************************************** * * PostScript -- * ********************************************************************************** */ static void PostScript(ZnItem item, ZnBool prepass) { } /* ********************************************************************************** * * GetFieldSet -- * ********************************************************************************** */ static ZnFieldSet GetFieldSet(ZnItem item) { return &((TabularItem) item)->field_set; } /* ********************************************************************************** * * GetAnchor -- * ********************************************************************************** */ static void GetAnchor(ZnItem item, Tk_Anchor anchor, ZnPoint *p) { ZnFieldSet field_set = &((TabularItem) item)->field_set; ZnDim width, height; if (field_set->label_format) { ZnFIELD.GetLabelBBox(field_set, &width, &height); ZnOrigin2Anchor(&field_set->label_pos, width, height, anchor, p); } else { p->x = p->y = 0.0; } } /* ********************************************************************************** * * GetClipVertices -- * Get the clipping shape. * Never ever call ZnTriFree on the tristrip returned by GetClipVertices. * ********************************************************************************** */ static ZnBool GetClipVertices(ZnItem item, ZnTriStrip *tristrip) { ZnFieldSet field_set = &((TabularItem) item)->field_set; ZnDim width, height; ZnPoint *points; if (field_set->label_format) { ZnFIELD.GetLabelBBox(field_set, &width, &height); ZnListAssertSize(ZnWorkPoints, 2); points = (ZnPoint *) ZnListArray(ZnWorkPoints); ZnTriStrip1(tristrip, points, 2, False); points[0] = field_set->label_pos; points[1].x = points[0].x + width; points[1].y = points[0].y + height; } return True; } /* ********************************************************************************** * * Coords -- * Return or edit the item origin. This doesn't take care of * the possible attachment. The change will be effective at the * end of the attachment. * ********************************************************************************** */ static int Coords(ZnItem item, int contour, int index, int cmd, ZnPoint **pts, char **controls, unsigned int *num_pts) { TabularItem tabular = (TabularItem) item; if ((cmd == ZN_COORDS_ADD) || (cmd == ZN_COORDS_ADD_LAST) || (cmd == ZN_COORDS_REMOVE)) { Tcl_AppendResult(item->wi->interp, " tabulars can't add or remove vertices", NULL); return TCL_ERROR; } else if ((cmd == ZN_COORDS_REPLACE) || (cmd == ZN_COORDS_REPLACE_ALL)) { if (*num_pts == 0) { Tcl_AppendResult(item->wi->interp, " coords command need 1 point on tabulars", NULL); return TCL_ERROR; } tabular->pos = (*pts)[0]; ZnITEM.Invalidate(item, ZN_COORDS_FLAG); } else if ((cmd == ZN_COORDS_READ) || (cmd == ZN_COORDS_READ_ALL)) { *num_pts = 1; *pts = &tabular->pos; } return TCL_OK; } /* ********************************************************************************** * * Part -- * Convert a private part from/to symbolic representation. * ********************************************************************************** */ static int Part(ZnItem item, Tcl_Obj **part_spec, int *part) { char *part_str; char *end; if (*part_spec) { part_str = Tcl_GetString(*part_spec); if (strlen(part_str) == 0) { *part = ZN_NO_PART; } else if (isdigit(part_str[0])) { *part = strtol(part_str, &end, 0); if ((*end != 0) || (*part < 0) || ((unsigned int) *part >= ((TabularItem) item)->field_set.num_fields)) { goto part_error; } } else { part_error: Tcl_AppendResult(item->wi->interp, " invalid item part specification", NULL); return TCL_ERROR; } } else { if (*part >= 0) { *part_spec = Tcl_NewIntObj(*part); } else { *part_spec = Tcl_NewStringObj("", -1); } } return TCL_OK; } /* ********************************************************************************** * * Index -- * Parse a text index and return its value and aa * error status (standard Tcl result). * ********************************************************************************** */ static int Index(ZnItem item, int field, Tcl_Obj *index_spec, int *index) { return ZnFIELD.FieldIndex(&((TabularItem) item)->field_set, field, index_spec, index); } /* ********************************************************************************** * * InsertChars -- * ********************************************************************************** */ static void InsertChars(ZnItem item, int field, int *index, char *chars) { if (ZnFIELD.FieldInsertChars(&((TabularItem) item)->field_set, field, index, chars)) { ZnITEM.Invalidate(item, ZN_COORDS_FLAG); } } /* ********************************************************************************** * * DeleteChars -- * ********************************************************************************** */ static void DeleteChars(ZnItem item, int field, int *first, int *last) { if (ZnFIELD.FieldDeleteChars(&((TabularItem) item)->field_set, field, first, last)) { ZnITEM.Invalidate(item, ZN_COORDS_FLAG); } } /* ********************************************************************************** * * Cursor -- * ********************************************************************************** */ static void TabularCursor(ZnItem item, int field, int index) { ZnFIELD.FieldCursor(&((TabularItem) item)->field_set, field, index); } /* ********************************************************************************** * * Selection -- * ********************************************************************************** */ static int Selection(ZnItem item, int field, int offset, char *chars, int max_chars) { return ZnFIELD.FieldSelection(&((TabularItem) item)->field_set, field, offset, chars, max_chars); } /* ********************************************************************************** * * Exported functions structs -- * ********************************************************************************** */ static ZnItemClassStruct TABULAR_ITEM_CLASS = { "tabular", sizeof(TabularItemStruct), tabular_attrs, 0, ZN_CLASS_HAS_ANCHORS|ZN_CLASS_ONE_COORD, /* flags */ Tk_Offset(TabularItemStruct, pos), Init, Clone, Destroy, Configure, Query, GetFieldSet, GetAnchor, GetClipVertices, NULL, /* GetContours */ Coords, InsertChars, DeleteChars, TabularCursor, Index, Part, Selection, NULL, /* Contour */ ComputeCoordinates, ToArea, Draw, Render, IsSensitive, Pick, NULL, /* PickVertex */ PostScript }; ZnItemClassId ZnTabular = (ZnItemClassId) &TABULAR_ITEM_CLASS;