From 4181cc1dbeb4a684f0a32a1c142a2e6b5c7259e4 Mon Sep 17 00:00:00 2001 From: lecoanet Date: Mon, 8 Apr 2002 13:56:53 +0000 Subject: Ajoute la manipulation de texte et de la s�lection/curseur sur les textes des fields. Support du focus sur les fields. Restructuration du fichier/ Le code des fields est d�sormais dans Field.c le code ing�rant dans group est rapatri� dans group et le code de redessin / endommagement est dans tkZinc. Des modifs importantes dans le protocole de certaines fonctions ont �t� n�cessaire. Ca touche pratiquement tous les fichiers ainsi que certaines m�thodes de ITEM. Suppression de ITEM_P, les m�thodes sont remplac�es par des fonctions externes pr�fix�es par Zn. --- generic/Item.c | 4172 ++++++++++++-------------------------------------------- 1 file changed, 893 insertions(+), 3279 deletions(-) (limited to 'generic/Item.c') diff --git a/generic/Item.c b/generic/Item.c index 89656d2..65db502 100644 --- a/generic/Item.c +++ b/generic/Item.c @@ -38,7 +38,9 @@ #include #endif +#include "Field.h" #include "Item.h" +#include "Group.h" #include "Types.h" #include "WidgetInfo.h" #include "Geo.h" @@ -54,101 +56,11 @@ static const char rcsid[] = "$Id$"; static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; -#define FIELD_SENSITIVE_BIT 1 -#define FIELD_VISIBLE_BIT 2 -#define FILLED_BIT 4 -#define TEXT_ON_TOP_BIT 8 -#define CACHE_OK 16 - - static ZnList item_classes = NULL; static ZnList item_stack = NULL; /* - * Field record. - */ -typedef struct _FieldStruct { - /* Public data */ - ZnGradient *color; - ZnGradient *fill_color; - Pixmap fill_pattern; - ZnGradient *border_color; - char *text; - char *image_name; - char *tile_name; - ZnFont font; - unsigned short flags; - Border border_edges; - ZnJustify alignment; - ReliefStyle relief; - ZnDim relief_thickness; - AutoAlign auto_alignment; - - /* Private data */ - ZnImage image; - ZnImage tile; - ZnGradient *gradient; - ZnPoint *grad_geo; - short orig_x; - short orig_y; - short corner_x; - short corner_y; - FieldSet field_set; -#ifdef GLX - TexFont *txf; -#endif -} FieldStruct, *Field; - - -/* - * The -text, -image, -border, -relief, -visible and - * -filled attributes set the ZN_COORDS_FLAG to update - * the leader that might protude if not clipped by the text. - */ -ZnAttrConfig field_attrs[] = { - { ZN_CONFIG_JUSTIFY, "-alignment", NULL, - Tk_Offset(FieldStruct, alignment), 0, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_AUTO_JUSTIFY, "-autoalignment", NULL, - Tk_Offset(FieldStruct, auto_alignment), 0, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_GRADIENT, "-backcolor", NULL, - Tk_Offset(FieldStruct, fill_color), 0, - ZN_DRAW_FLAG|ZN_BORDER_FLAG, False }, - { ZN_CONFIG_BORDER, "-border", NULL, - Tk_Offset(FieldStruct, border_edges), 0, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_GRADIENT, "-bordercolor", NULL, - Tk_Offset(FieldStruct, border_color), 0, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_GRADIENT, "-color", NULL, - Tk_Offset(FieldStruct, color), 0, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_BOOL, "-filled", NULL, - Tk_Offset(FieldStruct, flags), FILLED_BIT, ZN_COORDS_FLAG, False }, - { ZN_CONFIG_PATTERN, "-fillpattern", NULL, - Tk_Offset(FieldStruct, fill_pattern), 0, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_FONT, "-font", NULL, - Tk_Offset(FieldStruct, font), 0, ZN_COORDS_FLAG|ZN_CLFC_FLAG, False }, - { ZN_CONFIG_IMAGE, "-image", NULL, - Tk_Offset(FieldStruct, image_name), 0, - ZN_COORDS_FLAG|ZN_IMAGE_FLAG|ZN_CLFC_FLAG, False }, - { ZN_CONFIG_RELIEF, "-relief", NULL, - Tk_Offset(FieldStruct, relief), 0, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_DIM, "-reliefthickness", NULL, - Tk_Offset(FieldStruct, relief_thickness), 0, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_BOOL, "-sensitive", NULL, - Tk_Offset(FieldStruct, flags), - FIELD_SENSITIVE_BIT, ZN_REPICK_FLAG, False }, - { ZN_CONFIG_TEXT, "-text", NULL, - Tk_Offset(FieldStruct, text), 0, ZN_COORDS_FLAG|ZN_CLFC_FLAG, False }, - { ZN_CONFIG_IMAGE, "-tile", NULL, - Tk_Offset(FieldStruct, tile_name), 0, - ZN_COORDS_FLAG|ZN_TILE_FLAG, False }, - { ZN_CONFIG_BOOL, "-visible", NULL, - Tk_Offset(FieldStruct, flags), FIELD_VISIBLE_BIT, - ZN_COORDS_FLAG|ZN_CLFC_FLAG, False }, /* Keep ZN_COORDS_FLAG here */ - - { ZN_CONFIG_END, NULL, NULL, 0, 0, 0 } -}; - -/* * This array must be kept in sync with the * corresponding defines in Types.h. */ @@ -197,20 +109,9 @@ static char *attribute_type_strings[] = { * ********************************************************************************** */ -static void Damage(WidgetInfo *wi, ZnBBox *damage); static void Invalidate(Item item, int reason); -static int ConfigureField(FieldSet field_set, unsigned int field, - int argc, Tcl_Obj *CONST argv[], int *flags); -static int QueryField(FieldSet field_set, unsigned int field, - int argc, Tcl_Obj *CONST argv[]); -static void AttributeToObj(WidgetInfo *wi, char *record, - ZnAttrConfig *desc, char *buffer, - Tcl_Obj *result); -static void FieldImageChange(ClientData client_data, int x, int y, int width, - int height, int image_width, int image_height); -static void FieldTileChange(ClientData client_data, int x, int y, int width, - int height, int image_width, int image_height); -static void GetLabelBBox(FieldSet field_set, ZnDim *w, ZnDim *h); +static void AttributeToObj(WidgetInfo *wi, void *record, ZnAttrConfig *desc, + char *buffer, Tcl_Obj *result); /* @@ -241,38 +142,16 @@ InitAttrDesc(ZnAttrConfig *attr_desc) * ********************************************************************************** */ -static int -AttributesInfo(Item item, - int field, /* 0< means the item itself. */ - int argc, - Tcl_Obj *CONST args[]) +int +ZnAttributesInfo(WidgetInfo *wi, + void *record, + ZnAttrConfig *desc, + int argc, + Tcl_Obj *CONST args[]) { - WidgetInfo *wi = item->wi; - char *record; - ZnAttrConfig *desc; Tk_Uid attr_uid = NULL; Tcl_Obj *l, *entries[5]; char buffer[256]; - - if (field < 0) { - record = (char *) item; - desc = item->class->attr_desc; - } - else { - FieldSet field_set; - if (!item->class->has_fields) { - Tcl_AppendResult(wi->interp, "item class \"", item->class->name, - "\" doesn't support fields", NULL); - return ZN_ERROR; - } - field_set = item->class->GetFieldSet(item); - if (field >= field_set->num_fields) { - Tcl_AppendResult(wi->interp, "invalid field index \"", NULL); - return ZN_ERROR; - } - record = (char *) &field_set->fields[field]; - desc = field_attrs; - } if (argc == 1) { attr_uid = Tk_GetUid(Tcl_GetString(args[0])); @@ -319,44 +198,24 @@ AttributesInfo(Item item, /* ********************************************************************************** * - * ConfigureAttributes -- + * ZnConfigureAttributes -- * ********************************************************************************** */ -static int -ConfigureAttributes(char *record, - int field, /* 0< means item itself. */ - int argc, - Tcl_Obj *CONST args[], - int *flags) +int +ZnConfigureAttributes(WidgetInfo *wi, + void *record, + ZnAttrConfig *attr_desc, + int argc, + Tcl_Obj *CONST args[], + int *flags) { - WidgetInfo *wi; - Item item = NULL; int i; Tk_Uid attr_uid; ZnAttrConfig *desc; ZnPtr valp; - ZnAttrConfig *attr_desc; - FieldSet field_set = NULL; char *str; - if (field < 0) { - item = (Item) record; - wi = item->wi; - attr_desc = item->class->attr_desc; - } - else { - field_set = (FieldSet) record; - wi = field_set->wi; - if (field >= field_set->num_fields) { - Tcl_AppendResult(wi->interp, "invalid field index \"", NULL); - return ZN_ERROR; - } - record = (char *) &field_set->fields[field]; - /*printf("record <0x%X>, field %d\n", record, field);*/ - attr_desc = field_attrs; - } - for (i = 0; i < argc; i += 2) { attr_uid = Tk_GetUid(Tcl_GetString(args[i])); @@ -375,7 +234,7 @@ ConfigureAttributes(char *record, Tcl_GetString(args[i]), "\" can only be read", NULL); return ZN_ERROR; } - valp = record + desc->offset; + valp = ((char *) record) + desc->offset; /*printf("record <0x%X>, valp <0x%X>, offset %d\n", record, valp, desc->offset);*/ switch (desc->type) { case ZN_CONFIG_COLOR: @@ -595,12 +454,12 @@ ConfigureAttributes(char *record, return ZN_ERROR; } if (*((ZnList *) valp)) { - ITEM.FreeTags(item); + ITEM.FreeTags((Item) record); *flags |= desc->flags; } if (num_tags) { for (j = 0; j < num_tags; j++) { - ITEM.AddTag(item, Tk_GetUid(Tcl_GetString(elems[j]))); + ITEM.AddTag((Item) record, Tk_GetUid(Tcl_GetString(elems[j]))); } *flags |= desc->flags; } @@ -1064,8 +923,9 @@ ConfigureAttributes(char *record, str++; } if (strlen(str) != 0) { + Item item = (Item) record; frmt = LabelFormatCreate(wi->interp, str, - item->class->GetFieldSet(item)->num_fields); + FIELD.NumFields(item->class->GetFieldSet(item))); if (frmt == NULL) { return ZN_ERROR; } @@ -1248,12 +1108,12 @@ ConfigureAttributes(char *record, */ static void AttributeToObj(WidgetInfo *wi, - char *record, + void *record, ZnAttrConfig *desc, char *buffer, Tcl_Obj *result) { - char *valp = record + desc->offset; + char *valp = ((char *) record) + desc->offset; char *str = ""; Tcl_Obj *o; int i; @@ -1580,37 +1440,19 @@ AttributeToObj(WidgetInfo *wi, /* ********************************************************************************** * - * QueryAttribute -- + * ZnQueryAttribute -- * ********************************************************************************** */ -static int -QueryAttribute(char *record, - int field, /* 0< means item itself. */ - Tcl_Obj *attr_name) +int +ZnQueryAttribute(WidgetInfo *wi, + void *record, + ZnAttrConfig *desc, + Tcl_Obj *attr_name) { - WidgetInfo *wi; - Item item; Tk_Uid attr_uid = Tk_GetUid(Tcl_GetString(attr_name)); Tcl_Obj *result = NULL; char buffer[256]; - ZnAttrConfig *desc; - - if (field < 0) { - item = (Item) record; - wi = item->wi; - desc = item->class->attr_desc; - } - else { - FieldSet field_set = (FieldSet) record; - wi = field_set->wi; - if (field >= field_set->num_fields) { - Tcl_AppendResult(wi->interp, "invalid field index \"", NULL); - return ZN_ERROR; - } - record = (char *) &field_set->fields[field]; - desc = field_attrs; - } while (True) { if (desc->type == ZN_CONFIG_END) { @@ -1633,12 +1475,12 @@ QueryAttribute(char *record, /* ********************************************************************************** * - * ItemClassList -- + * ZnItemClassList -- * ********************************************************************************** */ -static ZnList -ItemClassList() +ZnList +ZnItemClassList() { return item_classes; } @@ -1646,12 +1488,12 @@ ItemClassList() /* ********************************************************************************** * - * LookupItemClass -- + * ZnLookupItemClass -- * ********************************************************************************** */ -static ItemClass -LookupItemClass(char *class_name) +ItemClass +ZnLookupItemClass(char *class_name) { ItemClass *class; int i, num_classes; @@ -1670,14 +1512,14 @@ LookupItemClass(char *class_name) /* ********************************************************************************** * - * AddItemClass -- + * ZnAddItemClass -- * ********************************************************************************** */ -static void -AddItemClass(ItemClass class) +void +ZnAddItemClass(ItemClass class) { - if (!LookupItemClass(class->name)) { + if (!ZnLookupItemClass(class->name)) { ZnListAdd(item_classes, &class, ZnListTail); InitAttrDesc(class->attr_desc); } @@ -1686,33 +1528,32 @@ AddItemClass(ItemClass class) /* ********************************************************************************** * - * GlobalModuleInit -- + * ZnItemInit -- * Initialize classes static state. * ********************************************************************************** */ -static void -GlobalModuleInit() +void +ZnItemInit() { /* First check if static part already inited */ if (item_classes == NULL) { item_classes = ZnListNew(16, sizeof(ItemClass)); - AddItemClass(ZnTrack); - AddItemClass(ZnWayPoint); - AddItemClass(ZnMap); - AddItemClass(ZnReticle); - AddItemClass(ZnTabular); - AddItemClass(ZnRectangle); - AddItemClass(ZnArc); - AddItemClass(ZnCurve); - AddItemClass(ZnBezier); - AddItemClass(ZnTriangles); - AddItemClass(ZnGroup); - AddItemClass(ZnIcon); - AddItemClass(ZnText); - AddItemClass(ZnWind); - /*AddItemClass(ZnMosaic);*/ - InitAttrDesc(field_attrs); + ZnAddItemClass(ZnTrack); + ZnAddItemClass(ZnWayPoint); + ZnAddItemClass(ZnMap); + ZnAddItemClass(ZnReticle); + ZnAddItemClass(ZnTabular); + ZnAddItemClass(ZnRectangle); + ZnAddItemClass(ZnArc); + ZnAddItemClass(ZnCurve); + ZnAddItemClass(ZnBezier); + ZnAddItemClass(ZnTriangles); + ZnAddItemClass(ZnGroup); + ZnAddItemClass(ZnIcon); + ZnAddItemClass(ZnText); + ZnAddItemClass(ZnWind); + InitAttrDesc(FIELD.attr_desc); } } @@ -1720,336 +1561,76 @@ GlobalModuleInit() /* ********************************************************************************** * - * ComputeFieldAttachment -- - * Compute the location/size of the field, computing attachments if any. - * + * UpdateItemDependency -- Method + * Update the group dependency list following a change in the + * connection of an item. + * ********************************************************************************** */ static void -ComputeFieldAttachment(FieldSet field_set, - int field, - ZnBBox *field_bbox) +UpdateItemDependency(Item item, + Item old_connection) { - - ZnBBox ref_bbox; - ZnDim real_width, real_height; - int ref_field, num_fields; - char x_attach, y_attach, x_dim, y_dim; - short width_spec, height_spec; - int x_spec, y_spec, icon_width=0, icon_height=0; - Field field_ptr; - Tk_FontMetrics fm; - - field_ptr = &field_set->fields[field]; - if (ISSET(field_ptr->flags, CACHE_OK)) { - field_bbox->orig.x = (ZnPos) field_ptr->orig_x; - field_bbox->orig.y = (ZnPos) field_ptr->orig_y; - field_bbox->corner.x = field_ptr->corner_x; - field_bbox->corner.y = field_ptr->corner_y; - return; - } - - /* - * Preset this field to a default position/size and pretend - * its cache is ok to break any deadlocks. - */ - field_ptr->orig_x = field_ptr->orig_y = 0; - field_ptr->corner_x = field_ptr->corner_y = 0; - field_bbox->orig.x = field_bbox->orig.y = 0; - field_bbox->corner.x = field_bbox->corner.y = 0; - SET(field_ptr->flags, CACHE_OK); - - num_fields = LabelFormatNumFields(field_set->label_format); - LabelFormatGetField(field_set->label_format, field, - &x_attach, &y_attach, &x_dim, &y_dim, - &x_spec, &y_spec, &width_spec, &height_spec); - - /* - * First try to compute the field size which may be a factor - * of the field content (but not a factor of other fields). - */ - if ((field_ptr->image != ZnUnspecifiedImage) && - ((x_dim == LF_DIM_ICON) || (y_dim == LF_DIM_ICON) || - (x_dim == LF_DIM_AUTO) || (y_dim == LF_DIM_AUTO))) { - Tk_SizeOfImage(field_ptr->image, &icon_width, &icon_height); - } - - switch (x_dim) { - case LF_DIM_FONT: - real_width = (ZnDim) (width_spec*ZnTextWidth(field_ptr->font, "N", 1)/100); - break; - case LF_DIM_ICON: - real_width = (ZnDim) (width_spec*icon_width/100); - break; - case LF_DIM_AUTO: - { - int len = strlen(field_ptr->text); - ZnDim text_width; - - real_width = 0.0; - if (field_ptr->image != ZnUnspecifiedImage) { - real_width = (ZnDim) icon_width; - } - if (len) { - /* - * The 4 extra pixels are needed for border and padding. - */ - text_width = (ZnDim) ZnTextWidth(field_ptr->font, field_ptr->text, len) + 4; - real_width = text_width < real_width ? real_width : text_width; - } - real_width += (ZnDim) width_spec; - break; - } - case LF_DIM_LABEL: - { - ZnDim lh; - - GetLabelBBox(field_set, &real_width, &lh); - break; - } - case LF_DIM_PIXEL: - default: - real_width = (ZnDim) width_spec; - break; - } - /*printf("field %d, width = %g\n", field, real_width);*/ - - switch (y_dim) { - case LF_DIM_FONT: - { - Tk_GetFontMetrics(field_ptr->font, &fm); - real_height = (ZnDim) (height_spec*(fm.ascent + fm.descent)/100); - break; - } - case LF_DIM_ICON: - real_height = (ZnDim) (height_spec*icon_height/100); - break; - case LF_DIM_AUTO: - { - ZnDim text_height; - - real_height = 0.0; - if (field_ptr->image != ZnUnspecifiedImage) { - real_height = (ZnDim) icon_height; - } - if (strlen(field_ptr->text)) { - Tk_GetFontMetrics(field_ptr->font, &fm); - text_height = (ZnDim) (fm.ascent + fm.descent); - real_height = text_height < real_height ? real_height : text_height; - } - real_height += (ZnDim) height_spec; - break; - } - case LF_DIM_LABEL: - { - ZnDim lw; - - GetLabelBBox(field_set, &lw, &real_height); - break; - } - case LF_DIM_PIXEL: - default: - real_height = (ZnDim) height_spec; - break; + if (old_connection == ZN_NO_ITEM) { + /* Add a connection */ + ZnInsertDependentItem(item); } - /*printf("field %d, height = %g\n", field, real_height);*/ - - /* - * Update the cache with the newly computed infos - * (breaking of deadlocks). - */ - field_bbox->corner.x = field_ptr->corner_x = real_width; - field_bbox->corner.y = field_ptr->corner_y = real_height; - - /* - * Then try to deduce the position, resolving any attachments - * if needed. - */ - - /* - * Do the x axis. - */ - if (x_dim != LF_DIM_LABEL) { - if (x_attach == LF_ATTACH_PIXEL) { - field_bbox->orig.x = (ZnPos) x_spec; - field_bbox->corner.x = field_bbox->orig.x + real_width; - } - else { - ref_field = x_spec; - field_bbox->orig.x = field_bbox->corner.x = 0; - if ((ref_field < 0) || (ref_field >= num_fields)) { - ZnWarning ("Attached (x) to an inexistant field geometry\n"); - } - else { - ComputeFieldAttachment(field_set, ref_field, &ref_bbox); - switch (x_attach) { - case LF_ATTACH_FWD: - if (ISSET(field_set->fields[ref_field].flags, FIELD_VISIBLE_BIT)) { - field_bbox->orig.x = ref_bbox.corner.x; - } - else { - field_bbox->orig.x = ref_bbox.orig.x; - } - field_bbox->corner.x = field_bbox->orig.x + real_width; - break; - case LF_ATTACH_BWD: - if (ISSET(field_set->fields[ref_field].flags, FIELD_VISIBLE_BIT)) { - field_bbox->corner.x = ref_bbox.orig.x; - } - else { - field_bbox->corner.x = ref_bbox.corner.x; - } - field_bbox->orig.x = field_bbox->corner.x - real_width; - break; - case LF_ATTACH_LEFT: - field_bbox->orig.x = ref_bbox.orig.x; - field_bbox->corner.x = field_bbox->orig.x + real_width; - break; - case LF_ATTACH_RIGHT: - if (ISSET(field_set->fields[ref_field].flags, FIELD_VISIBLE_BIT)) { - field_bbox->corner.x = ref_bbox.corner.x; - } - else { - field_bbox->corner.x = ref_bbox.orig.x; - } - field_bbox->orig.x = field_bbox->corner.x - real_width; - break; - } - } - } - /*printf("field %d, x = %g\n", field, field_bbox->orig.x);*/ + else if (item->connected_item == ZN_NO_ITEM) { + /* Remove a connection */ + ZnExtractDependentItem(item); } - - /* - * Then the y axis. - */ - if (y_dim != LF_DIM_LABEL) { - if (y_attach == LF_ATTACH_PIXEL) { - field_bbox->orig.y = (ZnPos) y_spec; - field_bbox->corner.y = field_bbox->orig.y + real_height; - } - else { - ref_field = y_spec; - field_bbox->orig.y = field_bbox->corner.y = 0; - if ((ref_field < 0) || (ref_field >= num_fields)) { - ZnWarning ("Attached (y) to an inexistant field geometry\n"); - } - else { - ComputeFieldAttachment(field_set, ref_field, &ref_bbox); - switch (y_attach) { - case LF_ATTACH_FWD: - if (ISSET(field_set->fields[ref_field].flags, FIELD_VISIBLE_BIT)) { - field_bbox->orig.y = ref_bbox.corner.y; - } - else { - field_bbox->orig.y = ref_bbox.orig.y; - } - field_bbox->corner.y = field_bbox->orig.y + real_height; - break; - case LF_ATTACH_BWD: - if (ISSET(field_set->fields[ref_field].flags, FIELD_VISIBLE_BIT)) { - field_bbox->corner.y = ref_bbox.orig.y; - } - else { - field_bbox->corner.y = ref_bbox.corner.y; - } - field_bbox->orig.y = field_bbox->corner.y - real_height; - break; - case LF_ATTACH_LEFT: - field_bbox->orig.y = ref_bbox.orig.y; - field_bbox->corner.y = field_bbox->orig.y + real_height; - break; - case LF_ATTACH_RIGHT: - if (ISSET(field_set->fields[ref_field].flags, FIELD_VISIBLE_BIT)) { - field_bbox->corner.y = ref_bbox.corner.y; - } - else { - field_bbox->corner.y = ref_bbox.orig.y; - } - field_bbox->orig.y = field_bbox->corner.y - real_height; - break; - } - } - } - /*printf("field %d, y = %g\n", field, field_bbox->orig.y);*/ + else { + /* Move at end to ensure that it will be updated after + * the (new) item it depends upon. + */ + ZnExtractDependentItem(item); + ZnInsertDependentItem(item); } - - field_ptr->orig_x = (short) field_bbox->orig.x; - field_ptr->orig_y = (short) field_bbox->orig.y; - field_ptr->corner_x = (short) field_bbox->corner.x; - field_ptr->corner_y = (short) field_bbox->corner.y; - SET(field_ptr->flags, CACHE_OK); } /* ********************************************************************************** * - * ClearFieldCache -- - * Reset the geometric cache of all fields depending on a given field (or - * of all fields if the field is < 0). Clear also the label bounding box - * cache if some action has been taken on a field. - * + * ExtractItem -- + * Extract an item from its context, includes updating graphic + * state flags. + * ********************************************************************************** */ -void -ClearFieldCache(FieldSet field_set, - int field) +static void +ExtractItem(Item item) { - int i, num_fields; - ZnBool clear_bbox; - int x_spec, y_spec; - char x_attach, y_attach, x_dim, y_dim; - short width_spec, height_spec; - - if (field < 0) { - for (i = 0; i < field_set->num_fields; i++) { - CLEAR(field_set->fields[i].flags, CACHE_OK); - } - field_set->label_width = field_set->label_height = -1.0; - return; - } + WidgetInfo *wi = item->wi; + Item group = item->parent; - clear_bbox = False; - if (!field_set->label_format) { - return; - } - num_fields = LabelFormatNumFields(field_set->label_format); - if (field >= num_fields) { - return; - } - LabelFormatGetField(field_set->label_format, field, - &x_attach, &y_attach, &x_dim, &y_dim, - &x_spec, &y_spec, &width_spec, &height_spec); - if ((x_dim != LF_DIM_PIXEL) || (y_dim != LF_DIM_PIXEL)) { - CLEAR(field_set->fields[field].flags, CACHE_OK); - clear_bbox = True; + /* damage bounding boxes */ + if (ISSET(item->flags, VISIBLE_BIT)) { + ZnDamage(wi, &item->item_bounding_box); + ZnNeedRedisplay(wi); } - for (i = 0; i < num_fields; i++) { - LabelFormatGetField(field_set->label_format, i, - &x_attach, &y_attach, &x_dim, &y_dim, - &x_spec, &y_spec, &width_spec, &height_spec); - if ((x_attach == LF_ATTACH_PIXEL) && (y_attach == LF_ATTACH_PIXEL)) { - continue; - } - if (x_attach != LF_ATTACH_PIXEL) { - if ((x_spec == field) && ISSET(field_set->fields[i].flags, CACHE_OK)) { - CLEAR(field_set->fields[i].flags, CACHE_OK); - ClearFieldCache(field_set, i); - clear_bbox = True; - } - } - if (y_attach != LF_ATTACH_PIXEL) { - if ((y_spec == field) && ISSET(field_set->fields[i].flags, CACHE_OK)) { - CLEAR(field_set->fields[i].flags, CACHE_OK); - ClearFieldCache(field_set, i); - clear_bbox = True; - } - } + + /* + * Tell that we need to repick + */ + if (item->class != ZnGroup) { + SET(wi->events_flags, INTERNAL_NEED_REPICK); } - if (clear_bbox) { - field_set->label_width = field_set->label_height = -1.0; + if (group != ZN_NO_ITEM) { + /* Remove me from dependency list. */ + ZnExtractDependentItem(item); + + /* Disconnect all dependents on me. */ + ZnDisconnectDependentItems(item); + /* + * Remove me from item list. + */ + ZnGroupExtractItem(item); + /* + * Remove me as a clip item. + */ + ZnGroupRemoveClip(group, item); } } @@ -2057,3082 +1638,1115 @@ ClearFieldCache(FieldSet field_set, /* ********************************************************************************** * - * GetLabelBBox -- - * + * InsertItem -- Method + * + * Insert an item in the display list according to its priority. + * It is inserted in front of items of lower or same priority. If + * mark_item is not ZN_NO_ITEM the insertion is done relative + * to this item, before it if 'before' is True, after it otherwise. + * mark_item must be in the group 'group'. + * ********************************************************************************** */ -void -GetLabelBBox(FieldSet field_set, - ZnDim *w, - ZnDim *h) +static void +InsertItem(Item item, + Item grp, + Item mark_item, + ZnBool before) { - ZnBBox bbox, tmp_bbox; - ZnLabelFormat lf; - int i, num_fields; - ZnDim clip_w, clip_h; - - if ((field_set->label_width >= 0.0) && (field_set->label_height >= 0.0)) { - *w = field_set->label_width; - *h = field_set->label_height; - return; - } - - lf = field_set->label_format; - if (lf == NULL) { - *w = *h = field_set->label_width = field_set->label_height = 0.0; - return; - } - - ResetBBox(&bbox); - num_fields = LabelFormatNumFields(lf); - for (i = 0; i < num_fields; i++) { - ComputeFieldAttachment(field_set, i, &tmp_bbox); - /*printf("field %d bbox %g %g %g %g\n", i, tmp_bbox.orig.x, tmp_bbox.orig.y, - tmp_bbox.corner.x, tmp_bbox.corner.y);*/ - AddBBoxToBBox(&bbox, &tmp_bbox); + if (!grp) { + grp = item->wi->top_group; } - field_set->label_width = bbox.corner.x; - field_set->label_height = bbox.corner.y; - - /*printf("GetLabelBBox size before clipping; w = %g, h = %g\n", - field_set->label_width, field_set->label_height);*/ - if (LabelFormatGetClipBox(lf, &clip_w, &clip_h)) { - if (clip_w < field_set->label_width) { - field_set->label_width = clip_w; - } - if (clip_h < field_set->label_height) { - field_set->label_height = clip_h; - } + item->parent = grp; + + if (mark_item && (mark_item->parent != grp)) { + mark_item = ZN_NO_ITEM; } - *w = field_set->label_width; - *h = field_set->label_height; - /*printf("GetLabelBBox returns computed size; w = %g, h = %g\n", *w, *h);*/ + ZnGroupInsertItem(grp, item, mark_item, before); } /* ********************************************************************************** * - * GetFieldBBox -- - * Compute the location of the field described - * by the field entry index in the item current LabelFormat. - * + * UpdateItemPriority -- Method + * Reorder a group's item list following a change in an + * item priority or a call to lower/raise. + * ********************************************************************************** */ static void -GetFieldBBox(FieldSet field_set, - unsigned int index, - ZnBBox *field_bbox) +UpdateItemPriority(Item item, + Item mark_item, + ZnBool before) { - ZnReal ox, oy; + Item parent = item->parent; - if (field_set->label_format) { - ox = REAL_TO_INT(field_set->label_pos.x); - oy = REAL_TO_INT(field_set->label_pos.y); - ComputeFieldAttachment(field_set, index, field_bbox); - field_bbox->orig.x += ox; - field_bbox->orig.y += oy; - field_bbox->corner.x += ox; - field_bbox->corner.y += oy; - } - else { - ResetBBox(field_bbox); - } + ZnGroupExtractItem(item); + InsertItem(item, parent, mark_item, before); + Invalidate(item, ZN_DRAW_FLAG); + SET(item->wi->events_flags, INTERNAL_NEED_REPICK); } /* ********************************************************************************** * - * ComputeFieldTextLocation -- - * Compute the position of the text in a field. This is a position - * that we can give to XDrawText. The position is deduced from the - * field bounding box passed in bbox. - * Return also the text bounding box. + * SetId, + * FreeId -- Method + * Get a fresh object id from the widget and enter the new + * object with this id in the object hash table. The id is + * incremented. FreeId on the other hand suppress the item + * from the hash table and set its object id to zero. * ********************************************************************************** */ static void -ComputeFieldTextLocation(Field field_ptr, - ZnBBox *bbox, - ZnPoint *pos, - ZnBBox *text_bbox) +SetId(Item item) { - ZnDim w, h; - Tk_FontMetrics fm; + WidgetInfo *wi = item->wi; + Tcl_HashEntry *entry; + int dummy; - Tk_GetFontMetrics(field_ptr->font, &fm); - w = ZnTextWidth(field_ptr->font, field_ptr->text, strlen(field_ptr->text)); - h = fm.ascent + fm.descent; - text_bbox->orig.y = (bbox->orig.y + bbox->corner.y - h) / 2.0; - text_bbox->corner.y = text_bbox->orig.y + h; - pos->y = text_bbox->orig.y + fm.ascent; - - switch (field_ptr->alignment) { - case ZnJustifyLeft: - text_bbox->orig.x = bbox->orig.x + 2; - break; - case ZnJustifyRight: - text_bbox->orig.x = bbox->corner.x - w - 2; - break; - default: - text_bbox->orig.x = (bbox->orig.x + bbox->corner.x - w) / 2.0; - break; - } - text_bbox->corner.x = text_bbox->orig.x + w; - pos->x = text_bbox->orig.x; + item->id = wi->obj_id; + wi->obj_id++; + entry = Tcl_CreateHashEntry(wi->id_table, (char *) item->id, &dummy); + Tcl_SetHashValue(entry, item); } +static void +FreeId(Item item) +{ + Tcl_HashEntry *entry; + + if (item->id) { + entry = Tcl_FindHashEntry(item->wi->id_table, (char *) item->id); + if (entry) { + Tcl_DeleteHashEntry(entry); + item->id = 0; + } + } +} /* ********************************************************************************** * - * LeaderToLabel -- - * Compute the segment part of segment that lies - * outside the fields of item. + * AddTag -- Method + * Add a tag to the item. If the tag is already on the list it + * is not added. As a side effect the tag/item pair is added to + * the tag table of the widget. + * 'tag' must be a Tk_Uid. * ********************************************************************************** */ static void -LeaderToLabel(FieldSet field_set, - ZnPoint *start, - ZnPoint *end) +AddTag(Item item, + Tk_Uid tag) { - int b_num; - ZnPoint delta, inf, sup; - ZnPos xt=0, yu=0, yw=0, xv=0; - Field field_ptr; - int i; - ZnBBox field_bbox; - - /* Intersection points : */ - /* T |xt / delta_y U |x1 V |y1 W |yw / delta_x */ - /* |y2 |yu / delta_x |xv / delta_y |x2 */ - /* */ - /* y = ax + b; */ - /* a = delta_y / delta_x */ - /* b = (y * delta_x - x * delta_y) / delta_x */ - - delta.x = start->x - end->x; - delta.y = start->y - end->y; - b_num = start->y*delta.x - start->x*delta.y; + int num, i; + char **ptr; - for (i = 0; i < LabelFormatNumFields(field_set->label_format); i++) { - field_ptr = &field_set->fields[i]; - /* - * If the field is made invisible or has no graphics of - * its own, don't clip. - */ - if (ISCLEAR(field_ptr->flags, FIELD_VISIBLE_BIT) || - ((*field_ptr->text == 0) && - ISCLEAR(field_ptr->flags, FILLED_BIT) && - (field_ptr->border_edges == NO_BORDER) && - (field_ptr->relief == RELIEF_FLAT) && - (field_ptr->image == ZnUnspecifiedImage))) { - continue; - } - - /* - * field_bbox is in absolute device coordinates. - */ - GetFieldBBox(field_set, i, &field_bbox); - + /* + * No tags yet. + */ + if (!item->tags) { + item->tags = ZnListNew(1, sizeof(char *)); + } + else { /* - * Adjust leader on real text, not on field boundaries. This is - * important when there are leading and trailing spaces. - * The correct test here is really *field_ptr->text, an empty - * text is represented by an empty string NOT by a NULL pointer. + * If the tag is already there, that's done. */ - if (*field_ptr->text && ISCLEAR(field_ptr->flags, FILLED_BIT) && - (field_ptr->border_edges == NO_BORDER) && - (field_ptr->relief == RELIEF_FLAT) && - (field_ptr->image == ZnUnspecifiedImage)) { - ZnBBox text_bbox; - ZnPoint text_pos; /* dummy */ - int space_width; - int scan_forw, scan_back; - space_width = ZnTextWidth(field_ptr->font, " ", 1); - - ComputeFieldTextLocation(field_ptr, &field_bbox, &text_pos, &text_bbox); - /* - * Correct adjusments made by ComputeFieldTextLocation (Vincent Pomey). - * - * PLC: IMHO, this is to compensate for exotic fonts like 'symbolesATC'. - * I am not planning to port this to Tk for two reasons: - * 1/ Current positions are no longer implemented as characters - * and 2/ Tk does not give access (easily) to lbearings and rbearings. - * This patch has been contributed by Phidias team. I don't know the - * problem it was meant to solve. - * text_bbox.x -= field_ptr->font->per_char[field_ptr->text[0]].lbearing + 3; - * text_bbox.width += field_ptr->font->per_char[field_ptr->text[0]].lbearing + 3; - */ - /* - * Change bbox according to leading and trailing spaces. - */ - scan_forw = 0; - while (field_ptr->text[scan_forw] == ' ') { - /* leading spaces */ - text_bbox.orig.x += space_width; - scan_forw++; - } - - /* - * Empty text. - */ - if (field_ptr->text[scan_forw] == 0) { - continue; - } - - scan_back = strlen(field_ptr->text)-1; - while ((field_ptr->text[scan_back] == ' ') && (scan_back > scan_forw)) { - /* trailing spaces */ - text_bbox.corner.x -= space_width; - scan_back--; - } - - field_bbox = text_bbox; - } - - if (field_bbox.corner.x <= field_bbox.orig.x) { - continue; - } - - if ((start->x >= field_bbox.orig.x) && (start->x < field_bbox.corner.x) && - (start->y >= field_bbox.orig.y) && (start->y < field_bbox.corner.y)) { - end->x = start->x; - end->y = start->y; - } - if (delta.x) { - yu = (field_bbox.orig.x*delta.y + b_num) / delta.x; - yw = (field_bbox.corner.x*delta.y + b_num) / delta.x; - } - if (delta.y) { - xt = (field_bbox.corner.y*delta.x - b_num) / delta.y; - xv = (field_bbox.orig.y*delta.x - b_num) / delta.y; - } - - inf.x = MIN(start->x, end->x); - sup.x = MAX(start->x, end->x); - inf.y = MIN(start->y, end->y); - sup.y = MAX(start->y, end->y); - - if (delta.x) { - if ((yu >= field_bbox.orig.y) && (yu <= field_bbox.corner.y) && - (field_bbox.orig.x >= inf.x) && (field_bbox.orig.x <= sup.x) && - (yu >= inf.y) && (yu <= sup.y)) { - end->x = field_bbox.orig.x; - end->y = yu; - inf.x = MIN(start->x, end->x); - sup.x = MAX(start->x, end->x); - inf.y = MIN(start->y, end->y); - sup.y = MAX(start->y, end->y); - } - if ((yw >= field_bbox.orig.y) && (yw <= field_bbox.corner.y) && - (field_bbox.corner.x >= inf.x) && (field_bbox.corner.x <= sup.x) && - (yw >= inf.y) && (yw <= sup.y)) { - end->x = field_bbox.corner.x; - end->y = yw; - inf.x = MIN(start->x, end->x); - sup.x = MAX(start->x, end->x); - inf.y = MIN(start->y, end->y); - sup.y = MAX(start->y, end->y); - } - } - if (delta.y) { - if ((xt >= field_bbox.orig.x) && (xt <= field_bbox.corner.x) && - (xt >= inf.x) && (xt <= sup.x) && - (field_bbox.corner.y >= inf.y) && (field_bbox.corner.y <= sup.y)) { - end->x = xt; - end->y = field_bbox.corner.y; - inf.x = MIN(start->x, end->x); - sup.x = MAX(start->x, end->x); - inf.y = MIN(start->y, end->y); - sup.y = MAX(start->y, end->y); - } - if ((xv >= field_bbox.orig.x) && (xv <= field_bbox.corner.x) && - (xv >= inf.x) && (xv <= sup.x) && - (field_bbox.orig.y >= inf.y) && (field_bbox.orig.y <= sup.y)) { - end->x = xv; - end->y = field_bbox.orig.y; - inf.x = MIN(start->x, end->x); - sup.x = MAX(start->x, end->x); - inf.y = MIN(start->y, end->y); - sup.y = MAX(start->y, end->y); + ptr = (char **) ZnListArray(item->tags); + num = ZnListSize(item->tags); + for (i = 0; i < num; i++) { + if (ptr[i] == tag) { + return; } } } + /* + * Add it. + */ + ZnListAdd(item->tags, &tag, ZnListTail); } - /* ********************************************************************************** * - * InsertDependentItem -- + * RemoveTag -- Method * ********************************************************************************** */ static void -InsertDependentItem(Item item) +RemoveTag(Item item, + Tk_Uid tag) { - GroupItem group = (GroupItem) item->parent; - - if (!group) { + int indx, num; + char **ptr; + + if (!item->tags) { return; } - if (!group->dependents) { - group->dependents = ZnListNew(2, sizeof(Item)); + /* + * look up the tag in the list. + */ + ptr = (char **) ZnListArray(item->tags); + num = ZnListSize(item->tags); + for (indx = 0; indx < num; indx++) { + if (ptr[indx] == tag) { + /* The tag list is not freed when empty to avoid + * overhead when using tags intensively. */ + ZnListDelete(item->tags, indx); + return; + } } - ZnListAdd(group->dependents, &item, ZnListTail); } - /* ********************************************************************************** * - * ExtractDependentItem -- + * FreeTags -- Method * ********************************************************************************** */ static void -ExtractDependentItem(Item item) +FreeTags(Item item) { - GroupItem group = (GroupItem) item->parent; - int index, num_items; - Item *deps; - - if (!group || !group->dependents) { + if (!item->tags) { return; } - num_items = ZnListSize(group->dependents); - deps = (Item *) ZnListArray(group->dependents); - for (index = 0; index < num_items; index++) { - if (deps[index]->id == item->id) { - ZnListDelete(group->dependents, index); - if (ZnListSize(group->dependents) == 0) { - ZnListFree(group->dependents); - group->dependents = NULL; - break; - } - } - } + ZnListFree(item->tags); + item->tags = NULL; } /* ********************************************************************************** * - * UpdateItemDependency -- - * Update the group dependency list following a change in the - * connection of an item. + * ZnCreateItem -- + * + * InsertItem and ConfigureItem must be called after CreateItem + * to finalize the setup of a new item. This is so even if + * there are no attributes to be changed after creation. + * ConfigureItem must be called in this case with the 'init' + * parameter set to True. * ********************************************************************************** */ -static void -UpdateItemDependency(Item item, - Item old_connection) +Item +ZnCreateItem(WidgetInfo *wi, + ItemClass item_class, + int *argc, + Tcl_Obj *CONST *args[]) { - if (old_connection == ZN_NO_ITEM) { - /* Add a connection */ - InsertDependentItem(item); - } - else if (item->connected_item == ZN_NO_ITEM) { - /* Remove a connection */ - ExtractDependentItem(item); - } - else { - /* Move at end to ensure that it will be updated after - * the (new) item it depends upon. - */ - ExtractDependentItem(item); - InsertDependentItem(item); + Item item; + + item = (Item) ZnMalloc(item_class->size); + + /* Initialize common state */ + item->class = item_class; + item->wi = wi; + item->parent = NULL; + item->previous = ZN_NO_ITEM; + item->next = ZN_NO_ITEM; + CLEAR(item->flags, UPDATE_DEPENDENT_BIT); + item->inv_flags = 0; + item->transfo = NULL; + item->parent = NULL; + item->connected_item = ZN_NO_ITEM; + + ResetBBox(&item->item_bounding_box); + + /* Init item specific attributes */ + if (item_class->Init(item, argc, args) == ZN_ERROR) { + ZnFree(item); + return ZN_NO_ITEM; } + + SetId(item); + item->tags = NULL; + + SET(wi->events_flags, INTERNAL_NEED_REPICK); + wi->num_items++; + + return (item); } /* ********************************************************************************** * - * DisconnectDependentItems -- - * + * CloneItem -- Method + * Can't clone the top level group. * ********************************************************************************** */ -static void -DisconnectDependentItems(Item item) +static Item +CloneItem(Item model) { - Item current_item; - GroupItem group = (GroupItem) item->parent; - Item *deps; - int num_deps, i; + WidgetInfo *wi = model->wi; + Item item; + Tk_Uid *tags; + int i, num_tags; - if (!group || !group->dependents) { - return; + if (!model->parent) { + return ZN_NO_ITEM; } - deps = (Item *) ZnListArray(group->dependents); - num_deps = ZnListSize(group->dependents); - for (i = num_deps-1; i >= 0; i--) { - current_item = deps[i]; - if (current_item->connected_item == item) { - current_item->connected_item = ZN_NO_ITEM; - ZnListDelete(group->dependents, i); - Invalidate(current_item, ZN_COORDS_FLAG); + item = (Item) ZnMalloc(model->class->size); + memcpy(item, model, model->class->size); + + item->previous = ZN_NO_ITEM; + item->next = ZN_NO_ITEM; + item->connected_item = ZN_NO_ITEM; + CLEAR(item->flags, UPDATE_DEPENDENT_BIT); + item->inv_flags = 0; + SetId(item); + + if (model->tags) { + item->tags = NULL; + tags = (Tk_Uid *) ZnListArray(model->tags); + num_tags = ZnListSize(model->tags); + for (i = num_tags-1; i >= 0; i--, tags++) { + AddTag(item, *tags); } } - if (ZnListSize(group->dependents) == 0) { - ZnListFree(group->dependents); - group->dependents = NULL; + + if (item->transfo) { + item->transfo = ZnTransfoDuplicate(item->transfo); } + + /* Call item's clone to duplicate non shared resources */ + item->class->Clone(item); + + SET(wi->events_flags, INTERNAL_NEED_REPICK); + wi->num_items++; + + return item; } /* ********************************************************************************** * - * InsertItem -- - * - * Insert an item in the display list according to its priority. - * It is inserted in front of items of lower or same priority. If - * mark_item is not ZN_NO_ITEM the insertion is done relative - * to this item, before it if 'before' is True, after it otherwise. - * mark_item must be in the group 'group'. + * ConfigureItem -- Method * ********************************************************************************** */ -static void -InsertItem(Item item, - Item grp, - Item mark_item, - ZnBool before) +static int +ConfigureItem(Item item, + int field, + int argc, + Tcl_Obj *CONST argv[], + ZnBool init) { WidgetInfo *wi = item->wi; - GroupItem group = (GroupItem) grp; - - if (!group) { - group = (GroupItem) wi->top_group; - } - item->parent = (Item) group; - - if (mark_item && (mark_item->parent != (Item) group)) { - mark_item = ZN_NO_ITEM; - } - /* - * Empty list, add the first item. - */ - if (group->head == ZN_NO_ITEM) { - group->head = item; - group->tail = item; - item->previous = item->next = ZN_NO_ITEM; - return; - } + int flags; + ZnBool previous_visible = init ? False : ISSET(item->flags, VISIBLE_BIT); - if (mark_item != ZN_NO_ITEM) { - /* - * Better leave here, mark_item will not - * have the links set right. - */ - if (mark_item == item) { - return; - } - /* - * Force the priority to be the same as the reference - * item; - */ - item->priority = mark_item->priority; - } - else { - mark_item = group->head; - while ((mark_item != ZN_NO_ITEM) && - (mark_item->priority > item->priority)) { - mark_item = mark_item->next; + flags = 0; + ASSIGN(flags, ZN_COORDS_FLAG, init); + if (argv) { + if (field < 0){ + if (item->class->Configure(item, argc, argv, &flags) == ZN_ERROR) { + return ZN_ERROR; + } + if (item->class->has_fields && ISSET(flags, ZN_CLFC_FLAG)) { + FIELD.ClearFieldCache(item->class->GetFieldSet(item), -1); + } } - before = True; - } - - if (before && (mark_item != ZN_NO_ITEM)) { - /* - * Insert before mark. - */ - item->next = mark_item; - item->previous = mark_item->previous; - if (mark_item->previous == ZN_NO_ITEM) { - group->head = item; + else if (item->class->has_fields) { + if (FIELD.ConfigureField(item->class->GetFieldSet(item), + field, argc, argv, &flags) == ZN_ERROR) { + return ZN_ERROR; + } } else { - mark_item->previous->next = item; + return ZN_ERROR; } - mark_item->previous = item; } - else { + + if (previous_visible && ISCLEAR(item->flags, VISIBLE_BIT)) { /* - * Insert after mark either because 'before' is False - * and mark_item valid or because the right place is at - * the end of the list and mark_item is ZN_NO_ITEM. + * Special case when the item has its visibility + * just turned out. */ - if (mark_item == ZN_NO_ITEM) { - group->tail->next = item; - item->previous = group->tail; - group->tail = item; - } - else { - item->previous = mark_item; - item->next = mark_item->next; - if (item->next == ZN_NO_ITEM) { - group->tail = item; - } - else { - item->next->previous = item; - } - mark_item->next = item; - } - } -} - - -/* - ********************************************************************************** - * - * ExtractItem -- - * - ********************************************************************************** - */ -static void -ExtractItem(Item item) -{ - GroupItem group; - - if (!item->parent) { - return; - } - group = (GroupItem) item->parent; - - if (item->previous != ZN_NO_ITEM) { - item->previous->next = item->next; - } - else { - group->head = item->next; + ZnDamage(wi, &item->item_bounding_box); + ZnNeedRedisplay(wi); } - if (item->next != ZN_NO_ITEM) { - item->next->previous = item->previous; - } - else { - group->tail = item->previous; - } + Invalidate(item, flags); - item->previous = ZN_NO_ITEM; - item->next = ZN_NO_ITEM; - item->parent = NULL; + return ZN_OK; } /* ********************************************************************************** * - * UpdateItemPriority -- - * Reorder a group's item list following a change in an - * item priority or a call to lower/raise. + * QueryItem -- Method * ********************************************************************************** */ -static void -UpdateItemPriority(Item item, - Item mark_item, - ZnBool before) +static int +QueryItem(Item item, + int field, + int argc, + Tcl_Obj *CONST argv[]) { - Item parent = item->parent; + if (field < 0) { + return item->class->Query(item, argc, argv); + } + else if (item->class->has_fields) { + return FIELD.QueryField(item->class->GetFieldSet(item), + field, argc, argv); + } - ExtractItem(item); - InsertItem(item, parent, mark_item, before); - Invalidate(item, ZN_DRAW_FLAG); - SET(item->wi->events_flags, INTERNAL_NEED_REPICK); + return ZN_ERROR; } /* ********************************************************************************** * - * SetId, - * FreeId -- - * Get a fresh object id from the widget and enter the new - * object with this id in the object hash table. The id is - * incremented. FreeId on the other hand suppress the item - * from the hash table and set its object id to zero. + * ComposeTransform -- + * Compose a (item) transform with current_t in new_t. * ********************************************************************************** */ static void -SetId(Item item) +ComposeTransform(ZnTransfo *transfo, + ZnTransfo *current_t, + ZnTransfo *new_t, + ZnBool compose_scale, + ZnBool compose_rot) { - WidgetInfo *wi = item->wi; - Tcl_HashEntry *entry; - int dummy; - - item->id = wi->obj_id; - wi->obj_id++; - entry = Tcl_CreateHashEntry(wi->id_table, (char *) item->id, &dummy); - Tcl_SetHashValue(entry, item); -} + ZnBool full; -static void -FreeId(Item item) -{ - Tcl_HashEntry *entry; + full = compose_scale && compose_rot; - if (item->id) { - entry = Tcl_FindHashEntry(item->wi->id_table, (char *) item->id); - if (entry) { - Tcl_DeleteHashEntry(entry); - item->id = 0; + if (!transfo && full) { + *new_t = *current_t; + return; + } + if (full) { + /* + * Full concatenation. + */ + /*ZnPrintTransfo(transfo);*/ + ZnTransfoCompose(new_t, transfo, current_t); + } + else { + ZnPoint scale, trans, local_scale, local_trans; + ZnReal local_rot, rot; + ZnTransfo t, t2; + + /* + * Need to decompose the local transform in translation, + * rotation and scale. + */ + ZnTransfoSetIdentity(&t); + ZnTransfoSetIdentity(new_t); + ZnTransfoDecompose(transfo, &local_scale, &local_trans, &local_rot, NULL); + ZnTranslate(&t, local_trans.x, local_trans.y); + ZnTransfoCompose(&t2, &t, current_t); + ZnTransfoDecompose(&t2, &scale, &trans, &rot, NULL); + if (compose_scale) { + ZnScale(new_t, scale.x, scale.y); + } + if (compose_rot) { + ZnRotateRad(new_t, rot); } + ZnScale(new_t, local_scale.x, local_scale.y); + ZnRotateRad(new_t, local_rot); + ZnTranslate(new_t, trans.x, trans.y); } } + /* ********************************************************************************** * - * AddTag -- - * Add a tag to the item. If the tag is already on the list it - * is not added. As a side effect the tag/item pair is added to - * the tag table of the widget. - * 'tag' must be a Tk_Uid. + * GetItemTransform -- Method + * Compute the current transform for an item. * ********************************************************************************** */ static void -AddTag(Item item, - Tk_Uid tag) +GetItemTransform(Item item, + ZnTransfo *t) { - int num, i; - char **ptr; + Item *items; + int i; + ZnTransfo t_tmp, *t1, *t2, *swap; - /* - * No tags yet. - */ - if (!item->tags) { - item->tags = ZnListNew(1, sizeof(char *)); + if (item_stack == NULL) { + item_stack = ZnListNew(16, sizeof(Item)); } else { - /* - * If the tag is already there, that's done. - */ - ptr = (char **) ZnListArray(item->tags); - num = ZnListSize(item->tags); - for (i = 0; i < num; i++) { - if (ptr[i] == tag) { - return; - } - } + ZnListEmpty(item_stack); + } + + while (item != ZN_NO_ITEM) { + ZnListAdd(item_stack, &item, ZnListTail); + item = item->parent; + } + + ZnTransfoSetIdentity(t); + t1 = t; + t2 = &t_tmp; + items = (Item *) ZnListArray(item_stack); + for (i = ZnListSize(item_stack)-1; i >= 0; i--) { + ComposeTransform(items[i]->transfo, t1, t2, + ISSET(items[i]->flags, COMPOSE_SCALE_BIT), + ISSET(items[i]->flags, COMPOSE_ROTATION_BIT)); + swap = t2; + t2 = t1; + t1 = swap; + } + if (t1 != t) { + *t = *t1; } - /* - * Add it. - */ - ZnListAdd(item->tags, &tag, ZnListTail); } + + /* ********************************************************************************** * - * RemoveTag -- + * ZnResetTransformStack + * ZnInitTransformStack + * ZnFreeTransformStack + * ZnCurrentTransform + * ZnPushTransform + * ZnPopTransform -- * ********************************************************************************** */ -static void -RemoveTag(Item item, - Tk_Uid tag) +void +ZnResetTransformStack(WidgetInfo *wi) { - int indx, num; - char **ptr; - - if (!item->tags) { - return; - } + ZnListAssertSize(wi->transfo_stack, 1); + wi->current_transfo = (ZnTransfo *) ZnListAt(wi->transfo_stack, 0); + ZnTransfoSetIdentity(wi->current_transfo); +} + +void +ZnInitTransformStack(WidgetInfo *wi) +{ + wi->transfo_stack = ZnListNew(8, sizeof(ZnTransfo)); + ZnResetTransformStack(wi); +} + +void +ZnFreeTransformStack(WidgetInfo *wi) +{ + ZnListFree(wi->transfo_stack); +} + +void +ZnPushTransform(WidgetInfo *wi, + ZnTransfo *transfo, + ZnBool compose_scale, + ZnBool compose_rot) +{ + ZnTransfo *next_t; + int num_t; + /* - * look up the tag in the list. + * Push the current transform and concatenate + * the new transform taking into account the + * combination flags. */ - ptr = (char **) ZnListArray(item->tags); - num = ZnListSize(item->tags); - for (indx = 0; indx < num; indx++) { - if (ptr[indx] == tag) { - /* The tag list is not freed when empty to avoid - * overhead when using tags intensively. */ - ZnListDelete(item->tags, indx); - return; - } - } + num_t = ZnListSize(wi->transfo_stack); + ZnListAssertSize(wi->transfo_stack, num_t+1); + next_t = (ZnTransfo *) ZnListAt(wi->transfo_stack, num_t); + ComposeTransform(transfo, wi->current_transfo, next_t, + compose_scale, compose_rot); + wi->current_transfo = next_t; } -/* - ********************************************************************************** - * - * FreeTags -- - * - ********************************************************************************** - */ -static void -FreeTags(Item item) +void +ZnPopTransform(WidgetInfo *wi) { - if (!item->tags) { - return; - } - ZnListFree(item->tags); - item->tags = NULL; + /* + * Restore the previous transform. + */ + ZnListDelete(wi->transfo_stack, ZnListTail); + wi->current_transfo = (ZnTransfo *) ZnListAt(wi->transfo_stack, ZnListTail); } /* ********************************************************************************** * - * CreateItem -- - * - * InsertItem and ConfigureItem must be called after CreateItem - * to finalize the setup of a new item. This is so even if - * there are no attributes to be changed after creation. - * ConfigureItem must be called in this case with the 'init' - * parameter set to True. + * ZnResetClipStack + * ZnInitClipStack + * ZnFreeClipStack + * ZnCurrentClip + * ZnPushClip + * ZnPopClip -- * ********************************************************************************** */ -static Item -CreateItem(WidgetInfo *wi, - ItemClass item_class, - int *argc, - Tcl_Obj *CONST *args[]) -{ - Item item; - - item = (Item) ZnMalloc(item_class->item_size); - - /* Initialize common state */ - item->class = item_class; - item->wi = wi; - item->parent = NULL; - item->previous = ZN_NO_ITEM; - item->next = ZN_NO_ITEM; - CLEAR(item->flags, UPDATE_DEPENDENT_BIT); - item->inv_flags = 0; - item->transfo = NULL; - item->parent = NULL; - item->connected_item = ZN_NO_ITEM; - - ResetBBox(&item->item_bounding_box); - - /* Init item specific attributes */ - if (item_class->Init(item, argc, args) == ZN_ERROR) { - ZnFree(item); - return ZN_NO_ITEM; - } - - SetId(item); - item->tags = NULL; - - SET(wi->events_flags, INTERNAL_NEED_REPICK); - wi->num_items++; - - return (item); -} - - -/* - ********************************************************************************** - * - * CloneItem -- - * Can't clone the top level group. - * - ********************************************************************************** - */ -static Item -CloneItem(Item model) -{ - WidgetInfo *wi = model->wi; - Item item; - Tk_Uid *tags; - int i, num_tags; - - if (!model->parent) { - return ZN_NO_ITEM; - } - - item = (Item) ZnMalloc(model->class->item_size); - memcpy(item, model, model->class->item_size); - - item->previous = ZN_NO_ITEM; - item->next = ZN_NO_ITEM; - item->connected_item = ZN_NO_ITEM; - CLEAR(item->flags, UPDATE_DEPENDENT_BIT); - item->inv_flags = 0; - SetId(item); - - if (model->tags) { - item->tags = NULL; - tags = (Tk_Uid *) ZnListArray(model->tags); - num_tags = ZnListSize(model->tags); - for (i = num_tags-1; i >= 0; i--, tags++) { - AddTag(item, *tags); - } - } - - if (item->transfo) { - item->transfo = ZnTransfoDuplicate(item->transfo); - } - - /* Call item's clone to duplicate non shared resources */ - item->class->Clone(item); - - SET(wi->events_flags, INTERNAL_NEED_REPICK); - wi->num_items++; - - return item; -} - - -/* - ********************************************************************************** - * - * ConfigureItem -- - * - ********************************************************************************** - */ -static int -ConfigureItem(Item item, - int field, - int argc, - Tcl_Obj *CONST argv[], - ZnBool init) -{ - WidgetInfo *wi = item->wi; - int flags; - ZnBool previous_visible = init ? False : ISSET(item->flags, VISIBLE_BIT); - - flags = 0; - ASSIGN(flags, ZN_COORDS_FLAG, init); - if (argv) { - if (field < 0){ - if (item->class->Configure(item, argc, argv, &flags) == ZN_ERROR) { - return ZN_ERROR; - } - if (item->class->has_fields && ISSET(flags, ZN_CLFC_FLAG)) { - ClearFieldCache(item->class->GetFieldSet(item), -1); - } - } - else if (item->class->has_fields) { - FieldSet field_set = item->class->GetFieldSet(item); - if (ConfigureField(field_set, field, argc, argv, &flags) == ZN_ERROR) { - return ZN_ERROR; - } - } - else { - return ZN_ERROR; - } - } - - if (previous_visible && ISCLEAR(item->flags, VISIBLE_BIT)) { - /* - * Special case when the item has its visibility - * just turned out. - */ - Damage(wi, &item->item_bounding_box); - ZnNeedRedisplay(wi); - } - - Invalidate(item, flags); - - return ZN_OK; -} - - -/* - ********************************************************************************** - * - * QueryItem -- - * - ********************************************************************************** - */ -static int -QueryItem(Item item, - int field, - int argc, - Tcl_Obj *CONST argv[]) -{ - if (field < 0) { - return item->class->Query(item, argc, argv); - } - else if (item->class->has_fields) { - FieldSet field_set = item->class->GetFieldSet(item); - return QueryField(field_set, field, argc, argv); - } - - return ZN_ERROR; -} - - -/* - ********************************************************************************** - * - * ComposeTransform -- - * Compose a (item) transform with current_t in new_t. - * - ********************************************************************************** - */ -static void -ComposeTransform(ZnTransfo *transfo, - ZnTransfo *current_t, - ZnTransfo *new_t, - ZnBool compose_scale, - ZnBool compose_rot) -{ - ZnBool full; - - full = compose_scale && compose_rot; - - if (!transfo && full) { - *new_t = *current_t; - return; - } - if (full) { - /* - * Full concatenation. - */ - /*ZnPrintTransfo(transfo);*/ - ZnTransfoCompose(new_t, transfo, current_t); - } - else { - ZnPoint scale, trans, local_scale, local_trans; - ZnReal local_rot, rot; - ZnTransfo t, t2; - - /* - * Need to decompose the local transform in translation, - * rotation and scale. - */ - ZnTransfoSetIdentity(&t); - ZnTransfoSetIdentity(new_t); - ZnTransfoDecompose(transfo, &local_scale, &local_trans, &local_rot, NULL); - ZnTranslate(&t, local_trans.x, local_trans.y); - ZnTransfoCompose(&t2, &t, current_t); - ZnTransfoDecompose(&t2, &scale, &trans, &rot, NULL); - if (compose_scale) { - ZnScale(new_t, scale.x, scale.y); - } - if (compose_rot) { - ZnRotateRad(new_t, rot); - } - ZnScale(new_t, local_scale.x, local_scale.y); - ZnRotateRad(new_t, local_rot); - ZnTranslate(new_t, trans.x, trans.y); - } -} - - -/* - ********************************************************************************** - * - * GetItemTransform -- - * Compute the current transform for an item. - * - ********************************************************************************** - */ -static void -GetItemTransform(Item item, - ZnTransfo *t) -{ - Item *items; - int i; - ZnTransfo t_tmp, *t1, *t2, *swap; - - if (item_stack == NULL) { - item_stack = ZnListNew(16, sizeof(Item)); - } - else { - ZnListEmpty(item_stack); - } - - while (item != ZN_NO_ITEM) { - ZnListAdd(item_stack, &item, ZnListTail); - item = item->parent; - } - - ZnTransfoSetIdentity(t); - t1 = t; - t2 = &t_tmp; - items = (Item *) ZnListArray(item_stack); - for (i = ZnListSize(item_stack)-1; i >= 0; i--) { - ComposeTransform(items[i]->transfo, t1, t2, - ISSET(items[i]->flags, COMPOSE_SCALE_BIT), - ISSET(items[i]->flags, COMPOSE_ROTATION_BIT)); - swap = t2; - t2 = t1; - t1 = swap; - } - if (t1 != t) { - *t = *t1; - } -} - - - -/* - ********************************************************************************** - * - * ResetTransformStack - * InitTransformStack - * FreeTransformStack - * CurrentTransform - * PushTransform - * PopTransform -- - * - ********************************************************************************** - */ -static void -ResetTransformStack(WidgetInfo *wi) -{ - ZnListAssertSize(wi->transfo_stack, 1); - wi->current_transfo = (ZnTransfo *) ZnListAt(wi->transfo_stack, 0); - ZnTransfoSetIdentity(wi->current_transfo); -} - -static void -InitTransformStack(WidgetInfo *wi) -{ - wi->transfo_stack = ZnListNew(8, sizeof(ZnTransfo)); - ResetTransformStack(wi); -} - -static void -FreeTransformStack(WidgetInfo *wi) -{ - ZnListFree(wi->transfo_stack); -} - -static void -PushTransform(WidgetInfo *wi, - ZnTransfo *transfo, - ZnBool compose_scale, - ZnBool compose_rot) -{ - ZnTransfo *next_t; - int num_t; - - /* - * Push the current transform and concatenate - * the new transform taking into account the - * combination flags. - */ - num_t = ZnListSize(wi->transfo_stack); - ZnListAssertSize(wi->transfo_stack, num_t+1); - next_t = (ZnTransfo *) ZnListAt(wi->transfo_stack, num_t); - ComposeTransform(transfo, wi->current_transfo, next_t, - compose_scale, compose_rot); - wi->current_transfo = next_t; -} - -static void -PopTransform(WidgetInfo *wi) -{ - /* - * Restore the previous transform. - */ - ZnListDelete(wi->transfo_stack, ZnListTail); - wi->current_transfo = (ZnTransfo *) ZnListAt(wi->transfo_stack, ZnListTail); -} - - -/* - ********************************************************************************** - * - * ResetClipStack - * InitClipStack - * FreeClipStack - * CurrentClip - * PushClip - * PopClip -- - * - ********************************************************************************** - */ -/* - * Describe the clipping at a given node - * of the item hierarchy. - */ -typedef struct _ClipState { - ZnBool simple; /* The clip is an aligned rectangle. */ - Region region; /* The X region used to draw and to */ - /* probe for picking. */ - ZnBBox clip_box; /* The bounding box of the clip area. */ -} ClipState; - -static void -ResetClipStack(WidgetInfo *wi) -{ - int i; - ClipState *clips = (ClipState *) ZnListArray(wi->clip_stack); - - /* - * Should not happen, clip stack should be - * empty when this function is called. - */ - for (i = ZnListSize(wi->clip_stack)-1; i >= 0; i--) { - XDestroyRegion(clips[i].region); - } - ZnListEmpty(wi->clip_stack); - wi->current_clip = NULL; -} - -static void -InitClipStack(WidgetInfo *wi) -{ - wi->clip_stack = ZnListNew(8, sizeof(ClipState)); - ResetClipStack(wi); -} - -static void -FreeClipStack(WidgetInfo *wi) -{ - ZnListFree(wi->clip_stack); -} - -static ZnBool -CurrentClip(WidgetInfo *wi, - Region *reg, - ZnBBox **clip_box, - ZnBool *simple) -{ - if (wi->current_clip) { - if (reg) { - *reg = wi->current_clip->region; - } - if (clip_box) { - *clip_box = &wi->current_clip->clip_box; - } - if (simple) { - *simple = wi->current_clip->simple; - } - return True; - } - - return False; -} - -/* - * If simple is True poly is a pointer to an - * array of two points. In the other case it - * is a regular pointer to a multi contour poly. - */ -static void -PushClip(WidgetInfo *wi, - ZnTriStrip *tristrip, - ZnBool simple, - ZnBool set_gc) -{ - int i, j, num_clips; - int num_pts, max_num_pts; - ZnPoint *p; - ClipState *previous_clip=NULL; - Region reg, reg_op, reg_to; - XRectangle rect; - XPoint xpts[3], *xp2, *xpts2; - - if (tristrip->num_strips == 0) { - return; - } - max_num_pts = tristrip->strips[0].num_points; - for (j = 0; j < tristrip->num_strips; j++) { - num_pts = tristrip->strips[j].num_points; - if (num_pts > max_num_pts) { - num_pts = max_num_pts; - } - } - if ((simple && (max_num_pts < 2)) || - (!simple && (max_num_pts < 3))) { - return; - } - - num_clips = ZnListSize(wi->clip_stack); - /* printf("PushClip: num clips %d\n", num_clips);fflush(stdout);*/ - if (num_clips != 0) { - previous_clip = (ClipState *) ZnListAt(wi->clip_stack, ZnListTail); - } - ZnListAssertSize(wi->clip_stack, num_clips+1); - wi->current_clip = (ClipState *) ZnListAt(wi->clip_stack, ZnListTail); - wi->current_clip->simple = simple; - - /* - * Compute the local region. - */ - if (simple) { - rect.x = tristrip->strips[0].points[0].x; - rect.y = tristrip->strips[0].points[0].y; - rect.width = tristrip->strips[0].points[1].x - tristrip->strips[0].points[0].x; - rect.height = tristrip->strips[0].points[1].y - tristrip->strips[0].points[0].y; - reg = XCreateRegion(); - XUnionRectWithRegion(&rect, reg, reg); - /*printf("Adding a simple clip: %d, %d, %d, %d\n", - rect.x, rect.y, rect.width, rect.height);*/ - } - else { - reg = XCreateRegion(); - for (j = 0; j < tristrip->num_strips; j++) { - num_pts = tristrip->strips[j].num_points; - p = tristrip->strips[j].points; - /* - * In case of a fan we benefit from the fact that - * ALL the contour vertices are included in - * the tristrip, so we can use the corresponding - * polygon instead of going through all the triangles. - */ - if (tristrip->fan) { - xp2 = xpts2 = ZnMalloc(num_pts*sizeof(XPoint)); - for (i = 0 ; i < num_pts; i++, p++, xp2++) { - xp2->x = (short) p->x; - xp2->y = (short) p->y; - } - reg_op = XPolygonRegion(xpts2, num_pts, EvenOddRule); - reg_to = XCreateRegion(); - XUnionRegion(reg, reg_op, reg_to); - XDestroyRegion(reg); - XDestroyRegion(reg_op); - reg = reg_to; - ZnFree(xpts2); - } - else { - xpts[0].x = p->x; - xpts[0].y = p->y; - p++; - xpts[1].x = p->x; - xpts[1].y = p->y; - p++; - for (i = 2 ; i < num_pts; i++, p++) { - xpts[2].x = p->x; - xpts[2].y = p->y; - reg_op = XPolygonRegion(xpts, 3, EvenOddRule); - reg_to = XCreateRegion(); - XUnionRegion(reg, reg_op, reg_to); - XDestroyRegion(reg); - XDestroyRegion(reg_op); - reg = reg_to; - xpts[0] = xpts[1]; - xpts[1] = xpts[2]; - } - } - } - } - - /* - * Combine with previous region if any. - */ - if (previous_clip) { - wi->current_clip->region = XCreateRegion(); - XIntersectRegion(reg, previous_clip->region, wi->current_clip->region); - XDestroyRegion(reg); - /*printf("Merging with previous clip\n");*/ - } - else { - wi->current_clip->region = reg; - } - XClipBox(wi->current_clip->region, &rect); - wi->current_clip->clip_box.orig.x = rect.x; - wi->current_clip->clip_box.orig.y = rect.y; - wi->current_clip->clip_box.corner.x = rect.x + rect.width; - wi->current_clip->clip_box.corner.y = rect.y + rect.height; - - /* - * Set the clipping in the GC. - */ - if (set_gc) { - if (wi->render) { -#ifdef GLX - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_EQUAL, num_clips, 0xFF); - glStencilOp(GL_KEEP, GL_INCR, GL_INCR); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - if (simple) { - /* printf("Clip box is : %d, %d, %d, %d, num_clips : %d\n", - rect.x, rect.y, rect.width, rect.height, num_clips);*/ - glBegin(GL_QUADS); - glVertex2f(wi->current_clip->clip_box.orig.x, wi->current_clip->clip_box.orig.y); - glVertex2f(wi->current_clip->clip_box.orig.x, wi->current_clip->clip_box.corner.y); - glVertex2f(wi->current_clip->clip_box.corner.x, wi->current_clip->clip_box.corner.y); - glVertex2f(wi->current_clip->clip_box.corner.x, wi->current_clip->clip_box.orig.y); - glEnd(); - } - else { - for (j = 0; j < tristrip->num_strips; j++) { - num_pts = tristrip->strips[j].num_points; - p = tristrip->strips[j].points; - if (tristrip->fan) { - glBegin(GL_TRIANGLE_FAN); - glVertex2f(tristrip->center.x, tristrip->center.y); - } - else { - glBegin(GL_TRIANGLE_STRIP); - } - for (i = 0; i < num_pts; i++, p++) { - glVertex2f(p->x, p->y); - } - glEnd(); - } - } - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilFunc(GL_EQUAL, num_clips+1, 0xFF); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); -#endif - } - else { - XSetRegion(wi->dpy, wi->gc, wi->current_clip->region); - } - } -} - -static void -PopClip(WidgetInfo *wi, - ZnBool set_gc) -{ - int num_clips; - - if (wi->current_clip == NULL) { - return; - } - - XDestroyRegion(wi->current_clip->region); - ZnListDelete(wi->clip_stack, ZnListTail); - num_clips = ZnListSize(wi->clip_stack); - - if (num_clips != 0) { - wi->current_clip = (ClipState *) ZnListAt(wi->clip_stack, ZnListTail); - } - else { - wi->current_clip = NULL; - } - - /* - * Set the clipping in the GC. - */ - if (set_gc) { - if (num_clips != 0) { - if (wi->render) { -#ifdef GLX - glStencilFunc(GL_EQUAL, num_clips+1, 0xFF); - glStencilOp(GL_KEEP, GL_DECR, GL_DECR); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); -#if 0 - if (wi->current_clip->simple) { -#endif - glBegin(GL_QUADS); - glVertex2f(wi->current_clip->clip_box.orig.x, wi->current_clip->clip_box.orig.y); - glVertex2f(wi->current_clip->clip_box.orig.x, wi->current_clip->clip_box.corner.y); - glVertex2f(wi->current_clip->clip_box.corner.x, wi->current_clip->clip_box.corner.y); - glVertex2f(wi->current_clip->clip_box.corner.x, wi->current_clip->clip_box.orig.y); - glEnd(); -#if 0 - } - else { - } -#endif - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilFunc(GL_EQUAL, num_clips, 0xFF); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); -#endif - } - else { - XSetRegion(wi->dpy, wi->gc, wi->current_clip->region); - } - } - else { - /*printf("resetting clip mask\n");*/ - if (wi->render) { -#ifdef GLX - glClear(GL_STENCIL_BUFFER_BIT); - glDisable(GL_STENCIL_TEST); -#endif - } - else { - XSetClipMask(wi->dpy, wi->gc, None); - } - } - } - /*printf("PopClip: num clips %d\n", ZnListSize(wi->clip_stack));fflush(stdout);*/ -} - - -/* - ********************************************************************************** - * - * Invalidate -- - * - ********************************************************************************** - */ -static void -Invalidate(Item item, - int reason) -{ - if (ISSET(item->inv_flags, ZN_TRANSFO_FLAG)) { - return; - } - - if (ISSET(reason, ZN_COORDS_FLAG) || - ISSET(reason, ZN_TRANSFO_FLAG)) { - Item parent = item->parent; - while ((parent != NULL) && - ISCLEAR(parent->inv_flags, ZN_COORDS_FLAG) && - ISCLEAR(parent->inv_flags, ZN_TRANSFO_FLAG)) { - SET(parent->inv_flags, ZN_COORDS_FLAG); - /*printf("invalidate coords for parent %d\n", parent->id);*/ - parent = parent->parent; - } - /* - * There is no need to set the DRAW flag to force the invalidation - * of the current bounding box. This will be done by ComputeCoordinates - * in Group. - */ - item->inv_flags |= reason; - /*printf("invalidate %s for item %d, flags %s\n", - ISSET(reason, ZN_TRANSFO_FLAG)?"TRANSFO":"COORDS", item->id, - ISSET(item->inv_flags, ZN_TRANSFO_FLAG)?"TRANSFO":"COORDS");*/ - ZnNeedRedisplay(item->wi); - } - else if (ISSET(reason, ZN_DRAW_FLAG)) { - if (ISSET(item->flags, VISIBLE_BIT)) { - /*printf("invalidate graphics for item %d\n", item->id);*/ - Damage(item->wi, &item->item_bounding_box); - ZnNeedRedisplay(item->wi); - } - } -} - - -/* - ********************************************************************************** - * - * InvalidateItems -- - * Invalidate the geometric state of all items belonging - * to a given class. The search for items starts at group - * and proceed depth first. - * - ********************************************************************************** - */ -static void -InvalidateItems(Item group, - ItemClass item_class) -{ - Item item; - - if (group->class != ZnGroup) { - return; - } - item = ((GroupItem) group)->head; - while (item != ZN_NO_ITEM) { - if (item->class == item_class) { - Invalidate(item, ZN_COORDS_FLAG); - } - else if (item->class == ZnGroup) { - InvalidateItems(item, item_class); - } - item = item->next; - } -} - - -/* - ********************************************************************************** - * - * ResetTransfo - * SetTransfo - * TranslateItem - * ScaleItem - * RotateItem -- - * Set of functions that deal with item transform. They take care - * of all details including managing NULL transforms and invalidating - * the item hierarchy. - * - ********************************************************************************** - */ -static void -ResetTransfo(Item item) -{ - if (item->transfo) { - ZnFree(item->transfo); - item->transfo = NULL; - } - Invalidate(item, ZN_TRANSFO_FLAG); -} - - -static void -SetTransfo(Item item, - ZnTransfo *t) -{ - if (item->transfo) { - ZnFree(item->transfo); - } - if (!t || ZnTransfoIsIdentity(t)) { - item->transfo = NULL; - } - else { - item->transfo = ZnTransfoDuplicate(t); - } - Invalidate(item, ZN_TRANSFO_FLAG); -} - - -static void -TranslateItem(Item item, - ZnReal dx, - ZnReal dy) -{ - if (!item->transfo) { - item->transfo = ZnTransfoNew(); - } - ZnTranslate(item->transfo, dx, dy); - Invalidate(item, ZN_TRANSFO_FLAG); -} - - -static void -ScaleItem(Item item, - ZnReal sx, - ZnReal sy) -{ - if (!item->transfo) { - item->transfo = ZnTransfoNew(); - } - ZnScale(item->transfo, sx, sy); - Invalidate(item, ZN_TRANSFO_FLAG); -} - - -static void -RotateItem(Item item, - ZnReal angle, - ZnPoint *p) -{ - if (!item->transfo) { - item->transfo = ZnTransfoNew(); - } - if (p) { - ZnTranslate(item->transfo, -p->x, -p->y); - } - ZnRotateRad(item->transfo, angle); - if (p) { - ZnTranslate(item->transfo, p->x, p->y); - } - - Invalidate(item, ZN_TRANSFO_FLAG); -} - - -/* - ********************************************************************************** - * - * RemoveItem -- - * Extract an item from its context, includes updating graphic - * state flags. - * - ********************************************************************************** - */ -static void -RemoveItem(Item item) -{ - WidgetInfo *wi = item->wi; - GroupItem group; - - group = (GroupItem) item->parent; - - /* damage bounding boxes */ - if (ISSET(item->flags, VISIBLE_BIT)) { - Damage(wi, &item->item_bounding_box); - ZnNeedRedisplay(wi); - } - - /* - * Tell that we need to repick - */ - if (item->class != ZnGroup) { - SET(wi->events_flags, INTERNAL_NEED_REPICK); - } - - if (group) { - if (group->dependents) { - /* Remove me from dependency list. */ - ExtractDependentItem(item); - - /* Disconnect all dependents on me. */ - DisconnectDependentItems(item); - } - /* - * Remove me from item list. - */ - ExtractItem(item); - /* - * Remove me as a clip item. - */ - if (group->clip == item) { - group->clip = ZN_NO_ITEM; - Invalidate((Item) group, ZN_COORDS_FLAG); - } - } -} - - -/* - ********************************************************************************** - * - * DestroyItem -- - * - ********************************************************************************** - */ -static void -DestroyItem(Item item) -{ - WidgetInfo *wi = item->wi; - - /* - * Extract it from its group. - */ - RemoveItem(item); - - /* - * Update state variables to prevent dangling pointers. - */ - if (wi->current_item == item) { - wi->current_item = ZN_NO_ITEM; - wi->current_part = ZN_NO_PART; - } - if (wi->new_item == item) { - wi->new_item = ZN_NO_ITEM; - wi->new_part = ZN_NO_PART; - } - if ((wi->hot_item == item) || (wi->hot_prev) == item) { - wi->hot_item = ZN_NO_ITEM; - } - if (wi->text_info.sel_item == item) { - wi->text_info.sel_item = ZN_NO_ITEM; - } - if (wi->text_info.sel_item == item) { - wi->text_info.focus_item = ZN_NO_ITEM; - } - - /* - * Call per class removal code. - */ - (item->class->Destroy)(item); - /* - * Free the transform if any. - */ - if (item->transfo) { - ZnFree(item->transfo); - } - /* - * Remove the item from the item table and free - * all its tags. - */ - FreeId(item); - FreeTags(item); - /* - * Free the item own memory - */ - ZnFree(item); - wi->num_items--; -} - - -/* - ********************************************************************************** - * - * FieldImageChange -- - * - ********************************************************************************** - */ -static void -FieldImageChange(ClientData client_data, - int x, - int y, - int width, - int height, - int image_width, - int image_height) -{ - Field field = (Field) client_data; - int i; - ZnBBox bbox; - - if (field->image != ZnUnspecifiedImage) { - i = (((char *) field) - ((char *) field->field_set->fields)) / sizeof(FieldStruct); - GetFieldBBox(field->field_set, i, &bbox); - Damage(field->field_set->wi, &bbox); - ZnNeedRedisplay(field->field_set->wi); - ClearFieldCache(field->field_set, i); - } -} - - /* - ********************************************************************************** - * - * FieldTileChange -- - * - ********************************************************************************** - */ -static void -FieldTileChange(ClientData client_data, - int x, - int y, - int width, - int height, - int image_width, - int image_height) -{ - Field field = (Field) client_data; - int i; - ZnBBox bbox; - - if (field->tile != ZnUnspecifiedImage) { - i = (((char *) field) - ((char *) field->field_set->fields)) / sizeof(FieldStruct); - InvalidateImage(field->tile_name); - GetFieldBBox(field->field_set, i, &bbox); - Damage(field->field_set->wi, &bbox); - ZnNeedRedisplay(field->field_set->wi); - } -} - - -/* - ********************************************************************************** - * - * InitFields -- - * - * Perform the init of each field in a FieldSet. The number of such - * fields must have been inited before calling this fun. - * - ********************************************************************************** - */ -static void -InitFields(FieldSet field_set) -{ - WidgetInfo *wi = field_set->wi; - Field field; - unsigned int i, num_fields; - - /*printf("size of a field = %d\n", sizeof(FieldStruct));*/ - - if (field_set->num_fields < 0) { - field_set->num_fields = 0; - } - if (!field_set->num_fields) { - return; - } - num_fields = field_set->num_fields; - field_set->fields = (Field) ZnMalloc(num_fields*sizeof(FieldStruct)); - - for (i = 0; i < num_fields; i++){ - field = &field_set->fields[i]; - - field->field_set = field_set; - field->color = ZnGetGradientByValue(wi->fore_color); - field->fill_color = ZnGetGradientByValue(wi->back_color); - field->border_color = ZnGetGradientByValue(wi->fore_color); - SET(field->flags, FIELD_VISIBLE_BIT); - SET(field->flags, FIELD_SENSITIVE_BIT); - CLEAR(field->flags, FILLED_BIT); - CLEAR(field->flags, CACHE_OK); - field->fill_pattern = ZnUnspecifiedPattern; - field->text = ""; - field->image = ZnUnspecifiedImage; - field->image_name = ""; - field->tile = ZnUnspecifiedImage; - field->tile_name = ""; - field->font = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(wi->font)); - field->border_edges = NO_BORDER; - field->alignment = ZnJustifyLeft; - field->auto_alignment.automatic = False; - - field->relief = RELIEF_FLAT; - field->relief_thickness = 2; - SET(field->flags, TEXT_ON_TOP_BIT); - - field->gradient = NULL; - field->grad_geo = NULL; -#ifdef GLX - field->txf = NULL; -#endif - } - field_set->label_pos.x = field_set->label_pos.y = 0.0; - field_set->label_width = field_set->label_height = -1.0; -} - - -/* - ********************************************************************************** - * - * CloneFields -- - * - ********************************************************************************** + * Describe the clipping at a given node + * of the item hierarchy. */ -static void -CloneFields(FieldSet field_set) -{ - WidgetInfo *wi = field_set->wi; - Field field, fields_ret; - unsigned int i, num_fields; - char *text; - - if (field_set->label_format) { - field_set->label_format = LabelFormatDuplicate(field_set->label_format); - } - num_fields = field_set->num_fields; - if (!num_fields) { - return; - } - fields_ret = (Field) ZnMalloc(num_fields*sizeof(FieldStruct)); - memcpy(fields_ret, field_set->fields, num_fields*sizeof(FieldStruct)); - field_set->fields = fields_ret; - - for (i = 0; i < num_fields; i++) { - field = &fields_ret[i]; - if (field->gradient) { - field->gradient = ZnGetGradientByValue(field->gradient); - } - if (field->grad_geo) { - ZnPoint *grad_geo = ZnMalloc(4*sizeof(ZnPoint)); - memcpy(grad_geo, field->grad_geo, 4*sizeof(ZnPoint)); - field->grad_geo = grad_geo; - } - if (field->image != ZnUnspecifiedImage) { - text = ZnMalloc((strlen(field->image_name) + 1) * sizeof(char)); - strcpy(text, field->image_name); - field->image_name = text; - field->image = Tk_GetImage(wi->interp, wi->win, field->image_name, - FieldImageChange, (ClientData) field); - } - if (field->tile != ZnUnspecifiedImage) { - text = ZnMalloc((strlen(field->tile_name) + 1) * sizeof(char)); - strcpy(text, field->tile_name); - field->tile_name = text; - field->tile = Tk_GetImage(wi->interp, wi->win, field->tile_name, - FieldTileChange, (ClientData) field); - } - if (field->fill_pattern != ZnUnspecifiedPattern) { - field->fill_pattern = Tk_GetBitmap(wi->interp, wi->win, - Tk_NameOfBitmap(wi->dpy, field->fill_pattern)); - } - field->font = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(field->font)); - field->color = ZnGetGradientByValue(field->color); - field->fill_color = ZnGetGradientByValue(field->fill_color); - field->border_color = ZnGetGradientByValue(field->border_color); - - if (strlen(field->text) != 0) { - text = (char *) ZnMalloc((strlen(field->text) + 1) * sizeof(char)); - strcpy(text, field->text); - field->text = text; - } - } -} - +typedef struct _ClipState { + ZnBool simple; /* The clip is an aligned rectangle. */ + Region region; /* The X region used to draw and to */ + /* probe for picking. */ + ZnBBox clip_box; /* The bounding box of the clip area. */ +} ClipState; -/* - ********************************************************************************** - * - * ConfigureField -- - * - ********************************************************************************** - */ -static int -ConfigureField(FieldSet field_set, - unsigned int field, - int argc, - Tcl_Obj *CONST argv[], - int *flags) +void +ZnResetClipStack(WidgetInfo *wi) { int i; - Field field_ptr; - ZnBBox bbox; - WidgetInfo *wi = field_set->wi; - XColor *color; - int alpha; - - if (field >= field_set->num_fields) { - return ZN_ERROR; - } - - field_ptr = &field_set->fields[field]; - - if (ConfigureAttributes((char *) field_set, field, argc, argv, flags) == ZN_ERROR) { - return ZN_ERROR; - } - - if (ISSET(*flags, ZN_REPICK_FLAG)) { - SET(wi->events_flags, INTERNAL_NEED_REPICK); - } - if (ISSET(*flags, ZN_CLFC_FLAG)) { - ClearFieldCache(field_set, field); - } + ClipState *clips = (ClipState *) ZnListArray(wi->clip_stack); - if (field_ptr->gradient && - (ISSET(*flags, ZN_BORDER_FLAG) || (field_ptr->relief == RELIEF_FLAT))) { - ZnFreeGradient(field_ptr->gradient); - field_ptr->gradient = NULL; - } - if ((field_ptr->relief != RELIEF_FLAT) && !field_ptr->gradient) { - color = ZnGetGradientColor(field_ptr->border_color, 51.0, &alpha); - field_ptr->gradient = ZnGetReliefGradient(wi->interp, wi->win, - ZnNameOfColor(color), alpha); - if (field_ptr->gradient == NULL) { - return ZN_ERROR; - } - } - - if (ISSET(*flags, ZN_IMAGE_FLAG)) { - if (ValidateImage(wi, field_ptr, field_ptr->image_name, FieldImageChange, - &field_ptr->image, "field -image") == ZN_ERROR) { - return ZN_ERROR; - } - } - - if (ISSET(*flags, ZN_TILE_FLAG)) { - if (ValidateImage(wi, field_ptr, field_ptr->tile_name, FieldTileChange, - &field_ptr->tile, "field -tile") == ZN_ERROR) { - return ZN_ERROR; - } - } - /* - * This is done here to limit the redraw to the area of the - * modified fields. + * Should not happen, clip stack should be + * empty when this function is called. */ - if (ISCLEAR(*flags, ZN_COORDS_FLAG) && - field_set->label_format && ISSET(*flags, ZN_DRAW_FLAG)) { - for (i = 0; i < LabelFormatNumFields(field_set->label_format); i++) { - if (i == field) { - GetFieldBBox(field_set, i, &bbox); - Damage(wi, &bbox); - break; - } - } - } - - return ZN_OK; -} - - -/* - ********************************************************************************** - * - * QueryField -- - * - ********************************************************************************** - */ -static int -QueryField(FieldSet field_set, - unsigned int field, - int argc, - Tcl_Obj *CONST argv[]) -{ - Field field_ptr; - - if (field >= field_set->num_fields) { - return ZN_ERROR; - } - - field_ptr = &field_set->fields[field]; - if (QueryAttribute((char *) field_set, field, argv[0]) == ZN_ERROR) { - return ZN_ERROR; - } - - return ZN_OK; -} - - -/* - ********************************************************************************** - * - * FreeFields -- - * - ********************************************************************************** - */ -static void -FreeFields(FieldSet field_set) -{ - WidgetInfo *wi = field_set->wi; - unsigned int i, num_fields; - Field field; - - if (field_set->label_format) { - LabelFormatDelete(field_set->label_format); - } - - num_fields = field_set->num_fields; - for (i = 0; i < num_fields; i++) { - field = &field_set->fields[i]; - - if (strlen(field->text) != 0) { - ZnFree(field->text); - } - if (field->gradient) { - ZnFreeGradient(field->gradient); - } - if (field->grad_geo) { - ZnFree(field->grad_geo); - } - if (field->image != ZnUnspecifiedImage) { - Tk_FreeImage(field->image); - field->image = ZnUnspecifiedImage; - } - if (strlen(field->image_name) != 0) { - ZnFree(field->image_name); - } - if (field->tile != ZnUnspecifiedImage) { - Tk_FreeImage(field->tile); - field->tile = ZnUnspecifiedImage; - } - if (strlen(field->tile_name) != 0) { - ZnFree(field->tile_name); - } - if (field->fill_pattern != ZnUnspecifiedPattern) { - Tk_FreeBitmap(wi->dpy, field->fill_pattern); - field->fill_pattern = ZnUnspecifiedPattern; - } - /*printf("freeing a font\n");*/ - Tk_FreeFont(field->font); - ZnFreeGradient(field->color); - ZnFreeGradient(field->fill_color); - ZnFreeGradient(field->border_color); - } - if (num_fields) { - ZnFree(field_set->fields); + for (i = ZnListSize(wi->clip_stack)-1; i >= 0; i--) { + XDestroyRegion(clips[i].region); } + ZnListEmpty(wi->clip_stack); + wi->current_clip = NULL; } - -/* - ********************************************************************************** - * - * ComputeFieldImageLocation -- - * Compute the bounding box of the pixmap in a field. The position is - * deduced from the field bounding box passed in bbox. - * - ********************************************************************************** - */ -static void -ComputeFieldImageLocation(Field field_ptr, - ZnBBox *bbox, - ZnBBox *pm_bbox) +void +ZnInitClipStack(WidgetInfo *wi) { - int width, height; - - Tk_SizeOfImage(field_ptr->image, &width, &height); - pm_bbox->orig.y = (bbox->orig.y + bbox->corner.y - height) / 2; - pm_bbox->corner.y = pm_bbox->orig.y + height; - - switch (field_ptr->alignment) { - case ZnJustifyLeft: - pm_bbox->orig.x = bbox->orig.x; - break; - case ZnJustifyRight: - pm_bbox->orig.x = bbox->corner.x - width - 1; - break; - default: - pm_bbox->orig.x = (bbox->orig.x + bbox->corner.x - width) / 2; - break; - } - pm_bbox->corner.x = pm_bbox->orig.x + width; + wi->clip_stack = ZnListNew(8, sizeof(ClipState)); + ZnResetClipStack(wi); } - -/* - ********************************************************************************** - * - * FieldsEngine -- - * - ********************************************************************************** - */ -static void -FieldsEngine(FieldSet field_set, - void (*cb)()) +void +ZnFreeClipStack(WidgetInfo *wi) { - WidgetInfo *wi = field_set->wi; - int i; /* This one *NEED* to be an int */ - int num; - Field field_ptr; - ZnBBox label_clip_box, clip_bbox, bbox, *global_clip_box; - ZnBBox text_bbox, clip_text_bbox; - ZnPoint pts[2]; - ZnTriStrip tristrip; - ZnPoint text_pos; - ZnBBox pm_bbox, clip_pm_bbox; - ZnBool restore = False; - ZnDim lwidth, lheight; - ZnReal val; - - if (field_set->label_format && LabelFormatNumFields(field_set->label_format)) { - bbox.orig.x = REAL_TO_INT(field_set->label_pos.x); - bbox.orig.y = REAL_TO_INT(field_set->label_pos.y); - GetLabelBBox(field_set, &lwidth, &lheight); - bbox.corner.x = bbox.orig.x + lwidth; - bbox.corner.y = bbox.orig.y + lheight; - CurrentClip(wi, NULL, &global_clip_box, NULL); - - if (!wi->render) { - IntersectBBox(global_clip_box, &bbox, &label_clip_box); - if (IsEmptyBBox(&label_clip_box)) { - return; - } - } - else { - label_clip_box = bbox; - } - - num = LabelFormatNumFields(field_set->label_format); - for (i = 0; i < num; i++) { - field_ptr = &field_set->fields[i]; - - if (ISCLEAR(field_ptr->flags, FIELD_VISIBLE_BIT)) { - continue; - } - - GetFieldBBox(field_set, i, &bbox); - IntersectBBox(&label_clip_box, &bbox, &clip_bbox); - if (IsEmptyBBox(&clip_bbox)) { - continue; - } - - if (field_ptr->text) { - ComputeFieldTextLocation(field_ptr, &bbox, &text_pos, &text_bbox); - } - else { - ResetBBox(&text_bbox); - } - - IntersectBBox(&clip_bbox, &text_bbox, &clip_text_bbox); - - if (field_ptr->image != ZnUnspecifiedImage) { - ComputeFieldImageLocation(field_ptr, &bbox, &pm_bbox); - } - else { - ResetBBox(&pm_bbox); - } - - IntersectBBox(&clip_bbox, &pm_bbox, &clip_pm_bbox); - - /* we must call XSetClipRectangles only if it's required */ - val = clip_bbox.orig.x - bbox.orig.x; - restore = val > 0; - val = clip_bbox.orig.y - bbox.orig.y; - restore |= val > 0; - val = clip_bbox.corner.x - bbox.corner.x; - restore |= val < 0; - val = clip_bbox.corner.y - bbox.corner.y; - restore |= val < 0; - val = clip_text_bbox.orig.x - text_bbox.orig.x; - restore |= val > 0; - val = clip_text_bbox.orig.y - text_bbox.orig.y; - restore |= val > 0; - val = clip_text_bbox.corner.x - text_bbox.corner.x; - restore |= val < 0; - val = clip_text_bbox.corner.y - text_bbox.corner.y; - restore |= val < 0; - val = clip_pm_bbox.orig.x - pm_bbox.orig.x; - restore |= val > 0; - val = clip_pm_bbox.orig.y - pm_bbox.orig.y; - restore |= val > 0; - val = clip_pm_bbox.corner.x - pm_bbox.corner.x; - restore |= val < 0; - val = clip_pm_bbox.corner.y - pm_bbox.corner.y; - restore |= val < 0; - /*restore = True;*/ - if (restore) { - /* we must clip. */ - /*printf("clip\n");*/ - pts[0] = clip_bbox.orig; - pts[1] = clip_bbox.corner; - TRI_STRIP1(&tristrip, pts, 2); - PushClip(wi, &tristrip, True, True); - } - - (*cb)(wi, field_ptr, &bbox, &clip_bbox, &pm_bbox, &clip_pm_bbox, &text_pos); - - if (restore) { - /* Restore the previous clip. */ - PopClip(wi, True); - restore = False; - } - } - } + ZnListFree(wi->clip_stack); } - -/* - ********************************************************************************** - * - * DrawFields -- - * - ********************************************************************************** - */ -void -DrawField(WidgetInfo *wi, - Field field_ptr, - ZnBBox *bbox, - ZnBBox *clip_bbox, - ZnBBox *pm_bbox, - ZnBBox *clip_pm_bbox, - ZnPoint *text_pos) +ZnBool +ZnCurrentClip(WidgetInfo *wi, + Region *reg, + ZnBBox **clip_box, + ZnBool *simple) { - XGCValues values; - XRectangle r; - int j; - - /* - * Draw the background. - */ - if (ISSET(field_ptr->flags, FILLED_BIT)) { - values.foreground = ZnPixel(ZnGetGradientColor(field_ptr->fill_color, 0.0, NULL)); - - if (field_ptr->tile != ZnUnspecifiedImage) { /* Fill tiled */ - Pixmap pmap = GetImagePixmap(wi->win, field_ptr->tile_name, - field_ptr->tile, NULL); - values.fill_style = FillTiled; - values.tile = pmap; - values.ts_x_origin = (int) bbox->orig.x; - values.ts_y_origin = (int) bbox->orig.y; - XChangeGC(wi->dpy, wi->gc, - GCTileStipXOrigin|GCTileStipYOrigin|GCFillStyle|GCTile, - &values); - } - else if (field_ptr->fill_pattern != ZnUnspecifiedPattern) { /* Fill stippled */ - values.fill_style = FillStippled; - values.stipple = field_ptr->fill_pattern; - values.ts_x_origin = (int) bbox->orig.x; - values.ts_y_origin = (int) bbox->orig.y; - XChangeGC(wi->dpy, wi->gc, - GCTileStipXOrigin|GCTileStipYOrigin|GCFillStyle|GCStipple|GCForeground, - &values); - } - else { /* Fill solid */ - values.fill_style = FillSolid; - XChangeGC(wi->dpy, wi->gc, GCForeground|GCFillStyle, &values); + if (wi->current_clip) { + if (reg) { + *reg = wi->current_clip->region; } - BBox2XRect(clip_bbox, &r); - XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, r.x, r.y, r.width, r.height); - } - - /* - * Draw the image and the text, which is in back depends on - * the value of text_on_top. - */ - for (j = 0; j < 2; j++) { - if ((j == 0 && ISSET(field_ptr->flags, TEXT_ON_TOP_BIT)) || - (j == 1 && ISCLEAR(field_ptr->flags, TEXT_ON_TOP_BIT))) { - /* - * Draw the image. - */ - if (field_ptr->image != ZnUnspecifiedImage) { - Tk_RedrawImage(field_ptr->image, - clip_pm_bbox->orig.x - pm_bbox->orig.x, - clip_pm_bbox->orig.y - pm_bbox->orig.y, - REAL_TO_INT(clip_pm_bbox->corner.x - clip_pm_bbox->orig.x), - REAL_TO_INT(clip_pm_bbox->corner.y - clip_pm_bbox->orig.y), - wi->draw_buffer, - clip_pm_bbox->orig.x, clip_pm_bbox->orig.y); - } + if (clip_box) { + *clip_box = &wi->current_clip->clip_box; } - else { - /* - * Draw the text. - */ - if (field_ptr->text && strlen(field_ptr->text)) { - values.foreground = ZnPixel(ZnGetGradientColor(field_ptr->color, 0, NULL)); - values.fill_style = FillSolid; - values.font = ZnFontId(field_ptr->font); - XChangeGC(wi->dpy, wi->gc, GCForeground | GCFillStyle | GCFont, &values); - Tk_DrawChars(wi->dpy, wi->draw_buffer, wi->gc, field_ptr->font, - field_ptr->text, strlen(field_ptr->text), - text_pos->x, text_pos->y); - } + if (simple) { + *simple = wi->current_clip->simple; } + return True; } - BBox2XRect(bbox, &r); - /* - * Draw the border relief. - */ - if ((field_ptr->relief != RELIEF_FLAT) && (field_ptr->relief_thickness > 1)) { - DrawRectangleRelief(wi, field_ptr->relief, field_ptr->gradient, - &r, (unsigned int) field_ptr->relief_thickness); - } - - /* - * Draw the border line. - */ - if (field_ptr->border_edges != NO_BORDER) { - values.foreground = ZnPixel(ZnGetGradientColor(field_ptr->border_color, 0, NULL)); - values.line_width = 0; - values.line_style = LineSolid; - values.fill_style = FillSolid; - XChangeGC(wi->dpy, wi->gc, - GCForeground | GCLineWidth | GCLineStyle | GCFillStyle, &values); - if (field_ptr->border_edges & LEFT_BORDER) { - XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, r.x, r.y, - r.x, r.y + r.height - 1); - } - if (field_ptr->border_edges & RIGHT_BORDER) { - XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, - r.x + r.width - 1, r.y, - r.x + r.width - 1, r.y + r.height - 1); - } - if (field_ptr->border_edges & TOP_BORDER) { - XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, - r.x, r.y, r.x + r.width - 1, r.y); - } - if (field_ptr->border_edges & BOTTOM_BORDER) { - XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, - r.x, r.y + r.height - 1, - r.x + r.width - 1, r.y + r.height - 1); - } - if (field_ptr->border_edges & OBLIQUE) { - XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, - r.x, r.y, r.x + r.width - 1, r.y + r.height - 1); - } - if (field_ptr->border_edges & COUNTER_OBLIQUE) { - XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, - r.x, r.y + r.height - 1, - r.x + r.width - 1, r.y); - } - } -} - -static void -DrawFields(FieldSet field_set) -{ - FieldsEngine(field_set, DrawField); + return False; } - /* - ********************************************************************************** - * - * RenderFields -- - * - ********************************************************************************** + * If simple is True poly is a pointer to an + * array of two points. In the other case it + * is a regular pointer to a multi contour poly. */ void -FieldRenderCB(void *closure) +ZnPushClip(WidgetInfo *wi, + ZnTriStrip *tristrip, + ZnBool simple, + ZnBool set_gc) { -#ifdef GLX - ZnBBox *bbox = (ZnBBox *) closure; + int i, j, num_clips; + int num_pts, max_num_pts; + ZnPoint *p; + ClipState *previous_clip=NULL; + Region reg, reg_op, reg_to; + XRectangle rect; + XPoint xpts[3], *xp2, *xpts2; - glBegin(GL_QUADS); - glVertex2f(bbox->orig.x, bbox->orig.y); - glVertex2f(bbox->orig.x, bbox->corner.y); - glVertex2f(bbox->corner.x, bbox->corner.y); - glVertex2f(bbox->corner.x, bbox->orig.y); - glEnd(); -#endif -} - -void -RenderField(WidgetInfo *wi, - Field field_ptr, - ZnBBox *bbox, - ZnBBox *clip_bbox, - ZnBBox *pm_bbox, - ZnBBox *clip_pm_bbox, - ZnPoint *text_pos) -{ -#ifdef GLX - int j; - XColor *color; - int alpha; - - /* - * Draw the background. - */ - if (ISSET(field_ptr->flags, FILLED_BIT)) { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - if (!ZnGradientFlat(field_ptr->fill_color)) { -#if 0 /* TODO_GLX Faire le dégradé dans le fond des champs. */ - int type = field_ptr->fill_color->type; - ZnBool fast = (type == ZN_AXIAL_GRADIENT) && !field_ptr->grad_geo; - - RenderGradient(wi, field_ptr->fill_color, - fast ? NULL : FieldRenderCB, - bbox, fast ? (ZnPoint *) bbox : field_ptr->grad_geo); -#endif - } - else { - if (field_ptr->tile != ZnUnspecifiedImage) { /* Fill tiled */ - RenderTile(wi, GetImageTexture(wi->win, field_ptr->tile_name, field_ptr->tile), - field_ptr->fill_color, FieldRenderCB, bbox, (ZnPoint *) bbox); - } - else { /* Fill solid */ - if (field_ptr->fill_pattern != ZnUnspecifiedPattern) { /* Fill stippled */ - /* - * Setup polygon stippling. - */ - glEnable(GL_POLYGON_STIPPLE); - glPolygonStipple(GetBitmapMask(wi->dpy, field_ptr->fill_pattern)->pixels); - } - color = ZnGetGradientColor(field_ptr->fill_color, 0.0, &alpha); - alpha = ZnComposeAlpha(alpha, wi->alpha); - glColor4us(color->red, color->green, color->blue, alpha); - FieldRenderCB(clip_bbox); - glDisable(GL_POLYGON_STIPPLE); - } + if (tristrip->num_strips == 0) { + return; + } + max_num_pts = tristrip->strips[0].num_points; + for (j = 0; j < tristrip->num_strips; j++) { + num_pts = tristrip->strips[j].num_points; + if (num_pts > max_num_pts) { + num_pts = max_num_pts; } } + if ((simple && (max_num_pts < 2)) || + (!simple && (max_num_pts < 3))) { + return; + } + + num_clips = ZnListSize(wi->clip_stack); + /* printf("PushClip: num clips %d\n", num_clips);fflush(stdout);*/ + if (num_clips != 0) { + previous_clip = (ClipState *) ZnListAt(wi->clip_stack, ZnListTail); + } + ZnListAssertSize(wi->clip_stack, num_clips+1); + wi->current_clip = (ClipState *) ZnListAt(wi->clip_stack, ZnListTail); + wi->current_clip->simple = simple; /* - * Draw the image and the text, which one is in back depends on - * the value of text_on_top. + * Compute the local region. */ - for (j = 0; j < 2; j++) { - if ((j == 0 && ISSET(field_ptr->flags, TEXT_ON_TOP_BIT)) || - (j == 1 && ISCLEAR(field_ptr->flags, TEXT_ON_TOP_BIT))) { - /* - * Draw the image. - */ - if (field_ptr->image != ZnUnspecifiedImage) { - RenderImage(wi, GetImageTexture(wi->win, field_ptr->image_name, field_ptr->image), - field_ptr->fill_color, &(pm_bbox->orig), False); - } - } - else { + if (simple) { + rect.x = tristrip->strips[0].points[0].x; + rect.y = tristrip->strips[0].points[0].y; + rect.width = tristrip->strips[0].points[1].x - tristrip->strips[0].points[0].x; + rect.height = tristrip->strips[0].points[1].y - tristrip->strips[0].points[0].y; + reg = XCreateRegion(); + XUnionRectWithRegion(&rect, reg, reg); + /*printf("Adding a simple clip: %d, %d, %d, %d\n", + rect.x, rect.y, rect.width, rect.height);*/ + } + else { + reg = XCreateRegion(); + for (j = 0; j < tristrip->num_strips; j++) { + num_pts = tristrip->strips[j].num_points; + p = tristrip->strips[j].points; /* - * Draw the text. + * In case of a fan we benefit from the fact that + * ALL the contour vertices are included in + * the tristrip, so we can use the corresponding + * polygon instead of going through all the triangles. */ - if (field_ptr->text && strlen(field_ptr->text)) { - if (!field_ptr->txf) { - field_ptr->txf = GetTexFont(wi->win, field_ptr->font); + if (tristrip->fan) { + xp2 = xpts2 = ZnMalloc(num_pts*sizeof(XPoint)); + for (i = 0 ; i < num_pts; i++, p++, xp2++) { + xp2->x = (short) p->x; + xp2->y = (short) p->y; } - if (field_ptr->txf) { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glEnable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - color = ZnGetGradientColor(field_ptr->color, 0, &alpha); - alpha = ZnComposeAlpha(alpha, wi->alpha); - glColor4us(color->red, color->green, color->blue, alpha); - glBindTexture(GL_TEXTURE_2D, field_ptr->txf->texobj); - glPushMatrix(); - glTranslatef(text_pos->x, text_pos->y, 0.0); - txfRenderString(field_ptr->txf, field_ptr->text, strlen(field_ptr->text)); - glPopMatrix(); - glDisable(GL_TEXTURE_2D); + reg_op = XPolygonRegion(xpts2, num_pts, EvenOddRule); + reg_to = XCreateRegion(); + XUnionRegion(reg, reg_op, reg_to); + XDestroyRegion(reg); + XDestroyRegion(reg_op); + reg = reg_to; + ZnFree(xpts2); + } + else { + xpts[0].x = p->x; + xpts[0].y = p->y; + p++; + xpts[1].x = p->x; + xpts[1].y = p->y; + p++; + for (i = 2 ; i < num_pts; i++, p++) { + xpts[2].x = p->x; + xpts[2].y = p->y; + reg_op = XPolygonRegion(xpts, 3, EvenOddRule); + reg_to = XCreateRegion(); + XUnionRegion(reg, reg_op, reg_to); + XDestroyRegion(reg); + XDestroyRegion(reg_op); + reg = reg_to; + xpts[0] = xpts[1]; + xpts[1] = xpts[2]; } } } } /* - * Draw the border relief. - */ - if ((field_ptr->relief != RELIEF_FLAT) && (field_ptr->relief_thickness > 1)) { - ZnPoint p[5]; - - p[0].x = bbox->orig.x; - p[0].y = bbox->orig.y; - p[2].x = bbox->corner.x; - p[2].y = bbox->corner.y; - p[1].x = p[0].x; - p[1].y = p[2].y; - p[3].x = p[2].x; - p[3].y = p[0].y; - p[4] = p[0]; - RenderPolygonRelief(wi, field_ptr->relief, field_ptr->gradient, - False, p, 5, field_ptr->relief_thickness); + * Combine with previous region if any. + */ + if (previous_clip) { + wi->current_clip->region = XCreateRegion(); + XIntersectRegion(reg, previous_clip->region, wi->current_clip->region); + XDestroyRegion(reg); + /*printf("Merging with previous clip\n");*/ + } + else { + wi->current_clip->region = reg; } + XClipBox(wi->current_clip->region, &rect); + wi->current_clip->clip_box.orig.x = rect.x; + wi->current_clip->clip_box.orig.y = rect.y; + wi->current_clip->clip_box.corner.x = rect.x + rect.width; + wi->current_clip->clip_box.corner.y = rect.y + rect.height; /* - * Draw the border line. + * Set the clipping in the GC. */ - if (field_ptr->border_edges != NO_BORDER) { - color = ZnGetGradientColor(field_ptr->border_color, 0, &alpha); - glColor4us(color->red, color->green, color->blue, alpha); - glLineWidth(1); - SetLineStyle(wi, LINE_SIMPLE); - glBegin(GL_LINES); - if (field_ptr->border_edges & LEFT_BORDER) { - glVertex2f(bbox->orig.x, bbox->orig.y); - glVertex2f(bbox->orig.x, bbox->corner.y); - } - if (field_ptr->border_edges & RIGHT_BORDER) { - glVertex2f(bbox->corner.x, bbox->orig.y); - glVertex2f(bbox->corner.x, bbox->corner.y); - } - if (field_ptr->border_edges & TOP_BORDER) { - glVertex2f(bbox->orig.x, bbox->orig.y); - glVertex2f(bbox->corner.x, bbox->orig.y); - } - if (field_ptr->border_edges & BOTTOM_BORDER) { - glVertex2f(bbox->orig.x, bbox->corner.y); - glVertex2f(bbox->corner.x, bbox->corner.y); - } - if (field_ptr->border_edges & OBLIQUE) { - glVertex2f(bbox->orig.x, bbox->orig.y); - glVertex2f(bbox->corner.x, bbox->corner.y); + if (set_gc) { + if (wi->render) { +#ifdef GLX + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_EQUAL, num_clips, 0xFF); + glStencilOp(GL_KEEP, GL_INCR, GL_INCR); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + if (simple) { + /* printf("Clip box is : %d, %d, %d, %d, num_clips : %d\n", + rect.x, rect.y, rect.width, rect.height, num_clips);*/ + glBegin(GL_QUADS); + glVertex2f(wi->current_clip->clip_box.orig.x, wi->current_clip->clip_box.orig.y); + glVertex2f(wi->current_clip->clip_box.orig.x, wi->current_clip->clip_box.corner.y); + glVertex2f(wi->current_clip->clip_box.corner.x, wi->current_clip->clip_box.corner.y); + glVertex2f(wi->current_clip->clip_box.corner.x, wi->current_clip->clip_box.orig.y); + glEnd(); + } + else { + for (j = 0; j < tristrip->num_strips; j++) { + num_pts = tristrip->strips[j].num_points; + p = tristrip->strips[j].points; + if (tristrip->fan) { + glBegin(GL_TRIANGLE_FAN); + glVertex2f(tristrip->center.x, tristrip->center.y); + } + else { + glBegin(GL_TRIANGLE_STRIP); + } + for (i = 0; i < num_pts; i++, p++) { + glVertex2f(p->x, p->y); + } + glEnd(); + } + } + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glStencilFunc(GL_EQUAL, num_clips+1, 0xFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); +#endif } - if (field_ptr->border_edges & COUNTER_OBLIQUE) { - glVertex2f(bbox->orig.x, bbox->corner.y); - glVertex2f(bbox->corner.x, bbox->orig.y); + else { + XSetRegion(wi->dpy, wi->gc, wi->current_clip->region); } - glEnd(); } -#endif -} - -static void -RenderFields(FieldSet field_set) -{ - FieldsEngine(field_set, RenderField); } - -/* - ********************************************************************************** - * - * IsFieldsSensitive -- - * - ********************************************************************************** - */ -static ZnBool -IsFieldSensitive(FieldSet field_set, - int part) +void +ZnPopClip(WidgetInfo *wi, + ZnBool set_gc) { - if ((part >= 0) && (part < field_set->num_fields)) { - return ISSET(field_set->fields[part].flags, FIELD_SENSITIVE_BIT); + int num_clips; + + if (wi->current_clip == NULL) { + return; + } + + XDestroyRegion(wi->current_clip->region); + ZnListDelete(wi->clip_stack, ZnListTail); + num_clips = ZnListSize(wi->clip_stack); + + if (num_clips != 0) { + wi->current_clip = (ClipState *) ZnListAt(wi->clip_stack, ZnListTail); } else { - return False; + wi->current_clip = NULL; } -} - - -/* - ********************************************************************************** - * - * FieldsPick -- - * Return the first field that contains . - * A field is selected if is over a non transparent area. - * Such areas are : a solid filled background, a text, an icon. - * This does *NOT* do with *GLOBAL* visible and sensitive. - * But we need to take into account local field visible and - * sensitive as they modifiy local transparency. Local means - * within a single item. - * - ********************************************************************************** - */ -static double -FieldsPick(FieldSet field_set, - ZnPoint *p, - int *part) -{ - Field field_ptr; - ZnBBox bbox; - int i, best_field = 0; - double new_dist, dist = 1e40; - if (field_set->label_format) { - for (i = LabelFormatNumFields(field_set->label_format)-1; i >= 0; i--) { - field_ptr = &field_set->fields[i]; - - if (ISCLEAR(field_ptr->flags, FIELD_VISIBLE_BIT) && - ISCLEAR(field_ptr->flags, FIELD_SENSITIVE_BIT)) { - continue; + /* + * Set the clipping in the GC. + */ + if (set_gc) { + if (num_clips != 0) { + if (wi->render) { +#ifdef GLX + glStencilFunc(GL_EQUAL, num_clips+1, 0xFF); + glStencilOp(GL_KEEP, GL_DECR, GL_DECR); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); +#if 0 + if (wi->current_clip->simple) { +#endif + glBegin(GL_QUADS); + glVertex2f(wi->current_clip->clip_box.orig.x, wi->current_clip->clip_box.orig.y); + glVertex2f(wi->current_clip->clip_box.orig.x, wi->current_clip->clip_box.corner.y); + glVertex2f(wi->current_clip->clip_box.corner.x, wi->current_clip->clip_box.corner.y); + glVertex2f(wi->current_clip->clip_box.corner.x, wi->current_clip->clip_box.orig.y); + glEnd(); +#if 0 + } + else { + } +#endif + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glStencilFunc(GL_EQUAL, num_clips, 0xFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); +#endif } - - GetFieldBBox(field_set, i, &bbox); - - new_dist = RectangleToPointDist(&bbox, p); - if (new_dist < dist) { - dist = new_dist; - best_field = i; + else { + XSetRegion(wi->dpy, wi->gc, wi->current_clip->region); } - if (dist <= 0.0) { - dist = 0.0; - break; + } + else { + /*printf("resetting clip mask\n");*/ + if (wi->render) { +#ifdef GLX + glClear(GL_STENCIL_BUFFER_BIT); + glDisable(GL_STENCIL_TEST); +#endif + } + else { + XSetClipMask(wi->dpy, wi->gc, None); } } } - - *part = best_field; - return dist; + /*printf("PopClip: num clips %d\n", ZnListSize(wi->clip_stack));fflush(stdout);*/ } /* ********************************************************************************** * - * FieldsToArea -- - * Return -1 if no field is in the given area, 1 if they are - * all in it or 0 if there is some overlap. The function consider - * only fields that are either sensible or visible. + * Invalidate -- Method * ********************************************************************************** */ -static int -FieldsToArea(FieldSet field_set, - ZnBBox *area) +static void +Invalidate(Item item, + int reason) { - Field field_ptr; - ZnBBox bbox; - int inside = -1; - int i; - ZnBool first_done = False; - - for (i = LabelFormatNumFields(field_set->label_format)-1; i >= 0; i--) { - field_ptr = &field_set->fields[i]; - - if (ISCLEAR(field_ptr->flags, FIELD_VISIBLE_BIT) && - ISCLEAR(field_ptr->flags, FIELD_SENSITIVE_BIT)) { - continue; - } + if (ISSET(item->inv_flags, ZN_TRANSFO_FLAG)) { + return; + } - GetFieldBBox(field_set, i, &bbox); - if (!first_done) { - first_done = True; - inside = BBoxInBBox(&bbox, area); - if (inside == 0) { - return 0; - } + if (ISSET(reason, ZN_COORDS_FLAG) || + ISSET(reason, ZN_TRANSFO_FLAG)) { + Item parent = item->parent; + while ((parent != NULL) && + ISCLEAR(parent->inv_flags, ZN_COORDS_FLAG) && + ISCLEAR(parent->inv_flags, ZN_TRANSFO_FLAG)) { + SET(parent->inv_flags, ZN_COORDS_FLAG); + /*printf("invalidate coords for parent %d\n", parent->id);*/ + parent = parent->parent; } - else { - if (BBoxInBBox(&bbox, area) != inside) { - return 0; - } + /* + * There is no need to set the DRAW flag to force the invalidation + * of the current bounding box. This will be done by ComputeCoordinates + * in Group. + */ + item->inv_flags |= reason; + /*printf("invalidate %s for item %d, flags %s\n", + ISSET(reason, ZN_TRANSFO_FLAG)?"TRANSFO":"COORDS", item->id, + ISSET(item->inv_flags, ZN_TRANSFO_FLAG)?"TRANSFO":"COORDS");*/ + ZnNeedRedisplay(item->wi); + } + else if (ISSET(reason, ZN_DRAW_FLAG)) { + if (ISSET(item->flags, VISIBLE_BIT)) { + /*printf("invalidate graphics for item %d\n", item->id);*/ + ZnDamage(item->wi, &item->item_bounding_box); + ZnNeedRedisplay(item->wi); } } - - return inside; } - + /* ********************************************************************************** * - * SetFieldsAutoAlign -- + * InvalidateItems -- Method + * Invalidate the geometric state of all items belonging + * to a given class. The search for items starts at group + * and proceed depth first. * ********************************************************************************** */ static void -SetFieldsAutoAlign(Item item, - int alignment) +InvalidateItems(Item group, + ItemClass item_class) { - int i; - FieldSet field_set; - Field field; + Item item; - if (!item->class->has_fields) { + if (group->class != ZnGroup) { return; } - if ((alignment >= AA_LEFT) && (alignment <= AA_RIGHT)) { - field_set = item->class->GetFieldSet(item); - for (i = 0; i < field_set->num_fields; i++) { - field = &field_set->fields[i]; - if (field->auto_alignment.automatic) { - field->alignment = field->auto_alignment.align[alignment]; - } + item = ZnGroupHead(group); + while (item != ZN_NO_ITEM) { + if (item->class == item_class) { + Invalidate(item, ZN_COORDS_FLAG); + } + else if (item->class == ZnGroup) { + InvalidateItems(item, item_class); } + item = item->next; } } +/* + ********************************************************************************** + * + * ResetTransfo + * SetTransfo + * TranslateItem + * ScaleItem + * RotateItem -- Methods + * Set of functions that deal with item transform. They take care + * of all details including managing NULL transforms and invalidating + * the item hierarchy. + * + ********************************************************************************** + */ static void -Damage(WidgetInfo *wi, - ZnBBox *damage) +ResetTransfo(Item item) { - if ((damage == NULL) || IsEmptyBBox(damage)) { - return; - } - - /*printf("damaging area: %g %g %g %g\n", damage->orig.x, - damage->orig.y, damage->corner.x, damage->corner.y);*/ - - if (IsEmptyBBox(&wi->damaged_area)) { - wi->damaged_area.orig.x = damage->orig.x; - wi->damaged_area.orig.y = damage->orig.y; - wi->damaged_area.corner.x = damage->corner.x; - wi->damaged_area.corner.y = damage->corner.y; - } - else { - wi->damaged_area.orig.x = MIN(wi->damaged_area.orig.x, damage->orig.x); - wi->damaged_area.orig.y = MIN(wi->damaged_area.orig.y, damage->orig.y); - wi->damaged_area.corner.x = MAX(wi->damaged_area.corner.x, damage->corner.x); - wi->damaged_area.corner.y = MAX(wi->damaged_area.corner.y, damage->corner.y); + if (item->transfo) { + ZnFree(item->transfo); + item->transfo = NULL; } - /*printf("damaged area: %g %g %g %g\n", wi->damaged_area.orig.x, - wi->damaged_area.orig.y, wi->damaged_area.corner.x, - wi->damaged_area.corner.y);*/ + Invalidate(item, ZN_TRANSFO_FLAG); } + static void -ClampDamageArea(WidgetInfo *wi) +SetTransfo(Item item, + ZnTransfo *t) { - int width, height; - - if (wi->damaged_area.orig.x < wi->inset) { - wi->damaged_area.orig.x = wi->inset; - } - if (wi->damaged_area.orig.y < wi->inset) { - wi->damaged_area.orig.y = wi->inset; - } - if (wi->damaged_area.corner.x < wi->inset) { - wi->damaged_area.corner.x = wi->inset; - } - if (wi->damaged_area.corner.y < wi->inset) { - wi->damaged_area.corner.y = wi->inset; - } - width = wi->width - wi->inset; - height = wi->height - wi->inset; - if (wi->damaged_area.orig.x > width) { - wi->damaged_area.orig.x = width; - } - if (wi->damaged_area.orig.y > height) { - wi->damaged_area.orig.y = height; + if (item->transfo) { + ZnFree(item->transfo); } - if (wi->damaged_area.corner.x > width) { - wi->damaged_area.corner.x = width; + if (!t || ZnTransfoIsIdentity(t)) { + item->transfo = NULL; } - if (wi->damaged_area.corner.y > height) { - wi->damaged_area.corner.y = height; + else { + item->transfo = ZnTransfoDuplicate(t); } + Invalidate(item, ZN_TRANSFO_FLAG); } + static void -Update(WidgetInfo *wi) +TranslateItem(Item item, + ZnReal dx, + ZnReal dy) { - /* - * Give the overlap manager a chance to do its work. - */ -#ifdef OM - if ((wi->om_group != ZN_NO_ITEM) && - ((GroupItem) wi->om_group)->call_om) { - ZnPoint scale={1.0,1.0}; - if (wi->om_group->transfo) { - ZnTransfoDecompose(wi->om_group->transfo, &scale, - NULL, NULL, NULL); - } - OmProcessOverlap((void *) wi, wi->width, wi->height, scale.x); - ((GroupItem) wi->om_group)->call_om = False; - } -#endif - - if (ISSET(wi->top_group->inv_flags, ZN_COORDS_FLAG) || - ISSET(wi->top_group->inv_flags, ZN_TRANSFO_FLAG)) { - wi->top_group->class->ComputeCoordinates(wi->top_group, False); + if (!item->transfo) { + item->transfo = ZnTransfoNew(); } + ZnTranslate(item->transfo, dx, dy); + Invalidate(item, ZN_TRANSFO_FLAG); } static void -Repair(WidgetInfo *wi) +ScaleItem(Item item, + ZnReal sx, + ZnReal sy) { - XGCValues values; - ZnPoint pts[2]; - ZnTriStrip tristrip; - XColor *color; - ZnReal int_width = Tk_Width(wi->win); - ZnReal int_height = Tk_Height(wi->win); - - if (wi->render) { -#ifdef GLX -#ifdef GLX_DAMAGE - ClampDamageArea(wi); - /* - * Merge the exposed area. - */ - AddBBoxToBBox(&wi->damaged_area, &wi->exposed_area); - if (IsEmptyBBox(&wi->damaged_area)) { - return; - } -#endif - - glXMakeCurrent(wi->dpy, ZnWindowId(wi->win), wi->gl_context); - glEnable(GL_POINT_SMOOTH); - glEnable(GL_LINE_SMOOTH); -#if 0 - glEnable(GL_POLYGON_SMOOTH); /* expensive ? */ -#endif - - glEnable(GL_BLEND); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glClearStencil(0); - color = ZnGetGradientColor(wi->back_color, 0, NULL); - glClearColor(color->red/65536.0, color->green/65536.0, - color->blue/65536.0, 0.0); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - /* - * Init the composite group alpha. - */ - wi->alpha = 100; - - glViewport(0, 0, (GLsizei) int_width, int_height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluOrtho2D(0.0, int_width, int_height, 0.0); - glMatrixMode(GL_MODELVIEW); - -#ifdef GLX_DAMAGE - glEnable(GL_SCISSOR_TEST); + if (!item->transfo) { + item->transfo = ZnTransfoNew(); + } + ZnScale(item->transfo, sx, sy); + Invalidate(item, ZN_TRANSFO_FLAG); +} - /* - * Set the damaged area as the scissor area. - */ - wi->damaged_area.orig.x = REAL_TO_INT(wi->damaged_area.orig.x); - wi->damaged_area.orig.y = REAL_TO_INT(wi->damaged_area.orig.y); - wi->damaged_area.corner.x = REAL_TO_INT(wi->damaged_area.corner.x); - wi->damaged_area.corner.y = REAL_TO_INT(wi->damaged_area.corner.y); - glScissor(wi->damaged_area.orig.x, - int_height - wi->damaged_area.corner.y, - wi->damaged_area.corner.x - wi->damaged_area.orig.x, - wi->damaged_area.corner.y - wi->damaged_area.orig.y); -#else - /* - * We do not use the damaged area for GL rendering, - * set it to the whole area. - */ - wi->damaged_area.orig.x = wi->damaged_area.orig.y = wi->inset; - wi->damaged_area.corner.x = int_width-wi->inset; - wi->damaged_area.corner.y = int_height-wi->inset; -#endif - - /* - * Clear the GL buffers. - */ - glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - /* - * Setup the background tile if needed. - */ - if (wi->tile != ZnUnspecifiedImage) { - ZnBBox bbox; - - bbox.orig.x = bbox.orig.y = 0.0; - bbox.corner.x = int_width; - bbox.corner.y = int_height; - - RenderTile(wi, GetImageTexture(wi->win, wi->tile_name, wi->tile), - NULL, NULL, NULL, (ZnPoint *) &bbox); - } +static void +RotateItem(Item item, + ZnReal angle, + ZnPoint *p) +{ + if (!item->transfo) { + item->transfo = ZnTransfoNew(); + } + if (p) { + ZnTranslate(item->transfo, -p->x, -p->y); + } + ZnRotateRad(item->transfo, angle); + if (p) { + ZnTranslate(item->transfo, p->x, p->y); + } - wi->top_group->class->Render(wi->top_group); + Invalidate(item, ZN_TRANSFO_FLAG); +} - if ((wi->border_width > 0) || (wi->highlight_width > 0)) { - int alpha; -#ifdef GLX_DAMAGE - glDisable(GL_SCISSOR_TEST); -#endif - if (wi->highlight_width > 0) { - if (wi->text_info.got_focus) { - color = ZnGetGradientColor(wi->highlight_color, 0, &alpha); - } - else { - color = ZnGetGradientColor(wi->highlight_bg_color, 0, &alpha); - } - alpha = ZnComposeAlpha(alpha, 100); - glColor4us(color->red, color->green, color->blue, alpha); - - glBegin(GL_QUAD_STRIP); - glVertex2f(0.0, 0.0); - glVertex2f(wi->highlight_width, wi->highlight_width); - glVertex2f(int_width, 0); - glVertex2f(int_width - wi->highlight_width, wi->highlight_width); - glVertex2f(int_width, int_height); - glVertex2f(int_width - wi->highlight_width, int_height - wi->highlight_width); - glVertex2f(0, int_height); - glVertex2f(wi->highlight_width, int_height - wi->highlight_width); - glVertex2f(0, 0); - glVertex2f(wi->highlight_width, wi->highlight_width); - glEnd(); - } - if (wi->border_width > 0) { - ZnPoint p[5]; - - p[4].x = p[4].y = p[3].y = p[1].x = wi->highlight_width; - p[0] = p[4]; - p[3].x = p[2].x = int_width - wi->highlight_width; - p[2].y = p[1].y = int_height - wi->highlight_width; - RenderPolygonRelief(wi, wi->relief, wi->relief_grad, - False, p, 5, wi->border_width); - } -#ifdef GLX_DAMAGE - glEnable(GL_SCISSOR_TEST); -#endif - } - /* Switch the GL buffers. */ - glXSwapBuffers(wi->dpy, ZnWindowId(wi->win)); - glFlush(); +/* + ********************************************************************************** + * + * DestroyItem -- Method + * + ********************************************************************************** + */ +static void +DestroyItem(Item item) +{ + WidgetInfo *wi = item->wi; + TextInfo *ti = &wi->text_info; - /* - * Wait the end of GL update if we need to synchronize - * to monitor perfs. - */ - if (wi->monitoring) { - glXWaitGL(); - } -#endif + /* + * Extract it from its group. + */ + ExtractItem(item); + + /* + * Update state variables to prevent dangling pointers. + */ + if (wi->current_item == item) { + wi->current_item = ZN_NO_ITEM; + wi->current_part = ZN_NO_PART; + } + if (wi->new_item == item) { + wi->new_item = ZN_NO_ITEM; + wi->new_part = ZN_NO_PART; + } + if ((wi->hot_item == item) || (wi->hot_prev) == item) { + wi->hot_item = ZN_NO_ITEM; + } + if (ti->sel_item == item) { + ti->sel_item = ZN_NO_ITEM; + ti->sel_field = ZN_NO_PART; + } + if (ti->anchor_item == item) { + ti->anchor_item = ZN_NO_ITEM; + ti->anchor_field = ZN_NO_PART; + } + if (wi->focus_item == item) { + wi->focus_item = ZN_NO_ITEM; + wi->focus_field = ZN_NO_PART; } - else { - XRectangle r; - ZnBBox merge; - ClampDamageArea(wi); - /* - * Merge the damaged area with the exposed area. - */ - ResetBBox(&merge); - CopyBBox(&wi->damaged_area, &merge); - AddBBoxToBBox(&merge, &wi->exposed_area); - if (!IsEmptyBBox(&merge)) { - - /* Set the whole damaged area as clip rect. */ - wi->damaged_area.orig.x = r.x = REAL_TO_INT(wi->damaged_area.orig.x); - wi->damaged_area.orig.y = r.y = REAL_TO_INT(wi->damaged_area.orig.y); - wi->damaged_area.corner.x = REAL_TO_INT(wi->damaged_area.corner.x); - wi->damaged_area.corner.y = REAL_TO_INT(wi->damaged_area.corner.y); - r.width = wi->damaged_area.corner.x - wi->damaged_area.orig.x; - r.height = wi->damaged_area.corner.y - wi->damaged_area.orig.y; - pts[0] = wi->damaged_area.orig; - pts[1] = wi->damaged_area.corner; - TRI_STRIP1(&tristrip, pts, 2); - PushClip(wi, &tristrip, True, True); - - /* Fill the background of the double buffer pixmap. */ - if (wi->tile == ZnUnspecifiedImage) { - values.foreground = ZnPixel(ZnGetGradientColor(wi->back_color, 0, NULL)); - values.fill_style = FillSolid; - XChangeGC(wi->dpy, wi->gc, GCFillStyle|GCForeground, &values); - } - else { - values.fill_style = FillTiled; - values.tile = GetImagePixmap(wi->win, wi->tile_name, wi->tile, NULL); - values.ts_x_origin = values.ts_y_origin = 0; - XChangeGC(wi->dpy, wi->gc, - GCFillStyle|GCTile|GCTileStipXOrigin|GCTileStipYOrigin, - &values); - } - /*printf("Repair : filling rectangle: %d %d %d %d\n", r.x, r.y, r.width, r.height);*/ - XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, r.x, r.y, r.width, r.height); - - /* Draw the items */ - /*printf("Drawing\n");*/ - wi->top_group->class->Draw(wi->top_group); - - PopClip(wi, True); - - /* - * Send the merged area back to screen. - */ - merge.orig.x = MAX(merge.orig.x, wi->inset); - merge.orig.y = MAX(merge.orig.y, wi->inset); - merge.corner.x = MIN(merge.corner.x, int_width-wi->inset); - merge.corner.y = MIN(merge.corner.y, int_height-wi->inset); - BBox2XRect(&merge, &r); - XCopyArea(wi->dpy, - wi->draw_buffer, ZnWindowId(wi->win), wi->gc, - r.x, r.y, r.width, r.height, r.x, r.y); - } - - /* - * Redraw the borders. - */ - if (wi->border_width > 0) { - Pixmap save; - XRectangle r; - - save = wi->draw_buffer; - wi->draw_buffer = ZnWindowId(wi->win); - r.x = r.y = wi->highlight_width; - r.width = int_width - 2*wi->highlight_width; - r.height = int_height - 2*wi->highlight_width; - DrawRectangleRelief(wi, wi->relief, wi->relief_grad, - &r, wi->border_width); - wi->draw_buffer = save; - } - if (wi->highlight_width > 0) { - XRectangle r[4]; - - XSetForeground(wi->dpy, wi->gc, - ZnPixel(ZnGetGradientColor(wi->text_info.got_focus ? - wi->highlight_color : - wi->highlight_bg_color, - 0, NULL))); - XSetFillStyle(wi->dpy, wi->gc, FillSolid); - r[0].x = r[0].y = 0; - r[0].width = int_width; - r[0].height = wi->highlight_width; - r[1].x = int_width - wi->highlight_width; - r[1].y = 0; - r[1].width = wi->highlight_width; - r[1].height = int_height; - r[2].x = 0; - r[2].y = int_height - wi->highlight_width; - r[2].width = int_width; - r[2].height = wi->highlight_width; - r[3].x = r[3].y = 0; - r[3].width = wi->highlight_width; - r[3].height = int_height; - XFillRectangles(wi->dpy, ZnWindowId(wi->win), wi->gc, r, 4); - } + /* + * Call per class removal code. + */ + (item->class->Destroy)(item); + /* + * Free the transform if any. + */ + if (item->transfo) { + ZnFree(item->transfo); } + /* + * Remove the item from the item table and free + * all its tags. + */ + FreeId(item); + FreeTags(item); + /* + * Free the item own memory + */ + ZnFree(item); + wi->num_items--; } /* ********************************************************************************** * - * Exported functions structs -- + * Generic methods on items -- * ********************************************************************************** */ -struct _ITEM_P ITEM_P = { - GlobalModuleInit, - CreateItem, - AddItemClass, - LookupItemClass, - ItemClassList, - Damage, - Repair, - Update, - ConfigureAttributes, - QueryAttribute, - InitFields, - CloneFields, - FreeFields, - DrawFields, - RenderFields, - FieldsToArea, - IsFieldSensitive, - FieldsPick, - LeaderToLabel, - GetLabelBBox, - GetFieldBBox, - InitTransformStack, - FreeTransformStack, - ResetTransformStack, - PushTransform, - PopTransform, - InitClipStack, - FreeClipStack, - ResetClipStack, - PushClip, - PopClip, - CurrentClip, -}; struct _ITEM ITEM = { CloneItem, DestroyItem, ConfigureItem, QueryItem, - AttributesInfo, - SetFieldsAutoAlign, InsertItem, UpdateItemPriority, - InsertDependentItem, UpdateItemDependency, - RemoveItem, + ExtractItem, SetId, FreeId, AddTag, -- cgit v1.1