/* * Attrs.c -- Various attributes manipulation routines. * * Authors : Patrick Lecoanet. * Creation date : Fri Dec 31 10:03:34 1999 * * $Id$ */ /* * Copyright (c) 1993 - 2005 CENA, Patrick Lecoanet -- * * See the file "Copyright" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * */ #include "Attrs.h" #include "Item.h" #include "List.h" #include "Geo.h" #include "WidgetInfo.h" #if defined(MAC_OSX_TK) #include #else #include #endif #include #include static const char rcsid[] = "$Id$"; static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; /* **************************************************************** * * Code for reliefs. * **************************************************************** */ #define RELIEF_FLAT_SPEC "flat" #define RELIEF_RAISED_SPEC "raised" #define RELIEF_SUNKEN_SPEC "sunken" #define RELIEF_GROOVE_SPEC "groove" #define RELIEF_RIDGE_SPEC "ridge" #define RELIEF_ROUND_RAISED_SPEC "roundraised" #define RELIEF_ROUND_SUNKEN_SPEC "roundsunken" #define RELIEF_ROUND_GROOVE_SPEC "roundgroove" #define RELIEF_ROUND_RIDGE_SPEC "roundridge" #define RELIEF_SUNKEN_RULE_SPEC "sunkenrule" #define RELIEF_RAISED_RULE_SPEC "raisedrule" int ZnGetRelief(ZnWInfo *wi, char *name, ZnReliefStyle *relief) { size_t length; length = strlen(name); if (strncmp(name, RELIEF_FLAT_SPEC, length) == 0) { *relief = ZN_RELIEF_FLAT; } else if (strncmp(name, RELIEF_SUNKEN_SPEC, length) == 0) { *relief = ZN_RELIEF_SUNKEN; } else if ((strncmp(name, RELIEF_RAISED_SPEC, length) == 0) && (length >= 2)) { *relief = ZN_RELIEF_RAISED; } else if ((strncmp(name, RELIEF_RIDGE_SPEC, length) == 0) && (length >= 2)) { *relief = ZN_RELIEF_RIDGE; } else if (strncmp(name, RELIEF_GROOVE_SPEC, length) == 0) { *relief = ZN_RELIEF_GROOVE; } else if ((strncmp(name, RELIEF_ROUND_SUNKEN_SPEC, length) == 0) && (length >= 6)) { *relief = ZN_RELIEF_ROUND_SUNKEN; } else if ((strncmp(name, RELIEF_ROUND_RAISED_SPEC, length) == 0) && (length >= 7)) { *relief = ZN_RELIEF_ROUND_RAISED; } else if ((strncmp(name, RELIEF_ROUND_RIDGE_SPEC, length) == 0) && (length >= 7)) { *relief = ZN_RELIEF_ROUND_RIDGE; } else if ((strncmp(name, RELIEF_ROUND_GROOVE_SPEC, length) == 0) && (length >= 6)) { *relief = ZN_RELIEF_ROUND_GROOVE; } else if ((strncmp(name, RELIEF_SUNKEN_RULE_SPEC, length) == 0) && (length >= 7)) { *relief = ZN_RELIEF_SUNKEN_RULE; } else if ((strncmp(name, RELIEF_RAISED_RULE_SPEC, length) == 0) && (length >= 7)) { *relief = ZN_RELIEF_RAISED_RULE; } else { Tcl_AppendResult(wi->interp, "bad relief \"", name, "\": must be ", RELIEF_FLAT_SPEC, ", ", RELIEF_RAISED_SPEC, ", ", RELIEF_SUNKEN_SPEC, ", ", RELIEF_GROOVE_SPEC, ", ", RELIEF_RIDGE_SPEC, ", ", RELIEF_ROUND_RAISED_SPEC, ", ", RELIEF_ROUND_SUNKEN_SPEC, ", ", RELIEF_ROUND_GROOVE_SPEC, ", ", RELIEF_ROUND_RIDGE_SPEC, ", ", RELIEF_SUNKEN_RULE_SPEC, ", ", RELIEF_RAISED_RULE_SPEC, NULL); return TCL_ERROR; } if (!wi->render) { *relief = *relief & ~(ZN_RELIEF_ROUND|ZN_RELIEF_RULE); } return TCL_OK; } char * ZnNameOfRelief(ZnReliefStyle relief) { switch (relief) { case ZN_RELIEF_FLAT: return RELIEF_FLAT_SPEC; case ZN_RELIEF_SUNKEN: return RELIEF_SUNKEN_SPEC; case ZN_RELIEF_RAISED: return RELIEF_RAISED_SPEC; case ZN_RELIEF_GROOVE: return RELIEF_GROOVE_SPEC; case ZN_RELIEF_RIDGE: return RELIEF_RIDGE_SPEC; case ZN_RELIEF_ROUND_SUNKEN: return RELIEF_ROUND_SUNKEN_SPEC; case ZN_RELIEF_ROUND_RAISED: return RELIEF_ROUND_RAISED_SPEC; case ZN_RELIEF_ROUND_GROOVE: return RELIEF_ROUND_GROOVE_SPEC; case ZN_RELIEF_ROUND_RIDGE: return RELIEF_ROUND_RIDGE_SPEC; case ZN_RELIEF_SUNKEN_RULE: return RELIEF_SUNKEN_RULE_SPEC; case ZN_RELIEF_RAISED_RULE: return RELIEF_RAISED_RULE_SPEC; default: return "unknown relief"; } } /* **************************************************************** * * Code for borders. * **************************************************************** */ #define BORDER_LEFT_SPEC "left" #define BORDER_RIGHT_SPEC "right" #define BORDER_TOP_SPEC "top" #define BORDER_BOTTOM_SPEC "bottom" #define BORDER_CONTOUR_SPEC "contour" #define BORDER_COUNTER_OBLIQUE_SPEC "counteroblique" #define BORDER_OBLIQUE_SPEC "oblique" #define NO_BORDER_SPEC "noborder" int ZnGetBorder(ZnWInfo *wi, Tcl_Obj *name, ZnBorder *border) { unsigned int j, len, largc; Tcl_Obj **largv; char *str; *border = ZN_NO_BORDER; if (Tcl_ListObjGetElements(wi->interp, name, &largc, &largv) == TCL_ERROR) { border_error: Tcl_AppendResult(wi->interp, "bad line shape \"", Tcl_GetString(name), "\": must be a list of ", BORDER_LEFT_SPEC, ", ", BORDER_RIGHT_SPEC, ", ", BORDER_TOP_SPEC, ", ", BORDER_BOTTOM_SPEC, ", ", BORDER_COUNTER_OBLIQUE_SPEC, ", ", BORDER_OBLIQUE_SPEC, " or ", BORDER_CONTOUR_SPEC, ", ", NO_BORDER_SPEC, " alone", NULL); return TCL_ERROR; } for (j = 0; j < largc; j++) { str = Tcl_GetString(largv[j]); len = strlen(str); if (strncmp(str, BORDER_LEFT_SPEC, len) == 0) { *border |= ZN_LEFT_BORDER; } else if (strncmp(str, BORDER_RIGHT_SPEC, len) == 0) { *border |= ZN_RIGHT_BORDER; } else if (strncmp(str, BORDER_TOP_SPEC, len) == 0) { *border |= ZN_TOP_BORDER; } else if (strncmp(str, BORDER_BOTTOM_SPEC, len) == 0) { *border |= ZN_BOTTOM_BORDER; } else if (strncmp(str, BORDER_CONTOUR_SPEC, len) == 0) { *border |= ZN_CONTOUR_BORDER; } else if (strncmp(str, BORDER_OBLIQUE_SPEC, len) == 0) { *border |= ZN_OBLIQUE; } else if (strncmp(str, BORDER_COUNTER_OBLIQUE_SPEC, len) == 0) { *border |= ZN_COUNTER_OBLIQUE; } else if (strncmp(str, NO_BORDER_SPEC, len) == 0) { *border = ZN_NO_BORDER; } else { goto border_error; } } return TCL_OK; } /* * name must be large enough to hold the returned string. * 64 chars should be enough with the current values. */ void ZnNameOfBorder(ZnBorder border, char *name) { if (border == ZN_NO_BORDER) { strcpy(name, NO_BORDER_SPEC); return; } name[0] = 0; if ((border & ZN_CONTOUR_BORDER) == ZN_CONTOUR_BORDER) { strcat(name, BORDER_CONTOUR_SPEC); } else { if (border & ZN_LEFT_BORDER) { strcat(name, BORDER_LEFT_SPEC); } if (border & ZN_RIGHT_BORDER) { if (name[0] != 0) { strcat(name, " "); } strcat(name, BORDER_RIGHT_SPEC); } if (border & ZN_TOP_BORDER) { if (name[0] != 0) { strcat(name, " "); } strcat(name, BORDER_TOP_SPEC); } if (border & ZN_BOTTOM_BORDER) { if (name[0] != 0) { strcat(name, " "); } strcat(name, BORDER_BOTTOM_SPEC); } } if (border & ZN_OBLIQUE) { if (name[0] != 0) { strcat(name, " "); } strcat(name, BORDER_OBLIQUE_SPEC); } if (border & ZN_COUNTER_OBLIQUE) { if (name[0] != 0) { strcat(name, " "); } strcat(name, BORDER_COUNTER_OBLIQUE_SPEC); } } /* **************************************************************** * * Code for line shapes. * **************************************************************** */ #define STRAIGHT_SPEC "straight" #define RIGHT_LIGHTNING_SPEC "rightlightning" #define LEFT_LIGHTNING_SPEC "leftlightning" #define RIGHT_CORNER_SPEC "rightcorner" #define LEFT_CORNER_SPEC "leftcorner" #define DOUBLE_RIGHT_CORNER_SPEC "doublerightcorner" #define DOUBLE_LEFT_CORNER_SPEC "doubleleftcorner" int ZnGetLineShape(ZnWInfo *wi, char *name, ZnLineShape *line_shape) { unsigned int len; len = strlen(name); if (strncmp(name, STRAIGHT_SPEC, len) == 0) { *line_shape = ZN_LINE_STRAIGHT; } else if (strncmp(name, RIGHT_LIGHTNING_SPEC, len) == 0) { *line_shape = ZN_LINE_RIGHT_LIGHTNING; } else if (strncmp(name, LEFT_LIGHTNING_SPEC, len) == 0) { *line_shape = ZN_LINE_LEFT_LIGHTNING; } else if (strncmp(name, RIGHT_CORNER_SPEC, len) == 0) { *line_shape = ZN_LINE_RIGHT_CORNER; } else if (strncmp(name, LEFT_CORNER_SPEC, len) == 0) { *line_shape = ZN_LINE_LEFT_CORNER; } else if (strncmp(name, DOUBLE_RIGHT_CORNER_SPEC, len) == 0) { *line_shape = ZN_LINE_DOUBLE_RIGHT_CORNER; } else if (strncmp(name, DOUBLE_LEFT_CORNER_SPEC, len) == 0) { *line_shape = ZN_LINE_DOUBLE_LEFT_CORNER; } else { Tcl_AppendResult(wi->interp, "bad line shape \"", name, "\": must be ", STRAIGHT_SPEC, ", ", RIGHT_LIGHTNING_SPEC, ", ", LEFT_LIGHTNING_SPEC, ", ", RIGHT_CORNER_SPEC, ", ", LEFT_CORNER_SPEC, ", ", DOUBLE_RIGHT_CORNER_SPEC, ", ", DOUBLE_LEFT_CORNER_SPEC, NULL); return TCL_ERROR; } return TCL_OK; } char * ZnNameOfLineShape(ZnLineShape line_shape) { switch (line_shape) { case ZN_LINE_STRAIGHT: return STRAIGHT_SPEC; case ZN_LINE_RIGHT_LIGHTNING: return RIGHT_LIGHTNING_SPEC; case ZN_LINE_LEFT_LIGHTNING: return LEFT_LIGHTNING_SPEC; case ZN_LINE_RIGHT_CORNER: return RIGHT_CORNER_SPEC; case ZN_LINE_LEFT_CORNER: return LEFT_CORNER_SPEC; case ZN_LINE_DOUBLE_RIGHT_CORNER: return DOUBLE_RIGHT_CORNER_SPEC; case ZN_LINE_DOUBLE_LEFT_CORNER: return DOUBLE_LEFT_CORNER_SPEC; default: return "unknown line shape"; } } /* **************************************************************** * * Code for line styles. * **************************************************************** */ #define SIMPLE_SPEC "simple" #define DASHED_SPEC "dashed" #define DOTTED_SPEC "dotted" #define MIXED_SPEC "mixed" int ZnGetLineStyle(ZnWInfo *wi, char *name, ZnLineStyle *line_style) { unsigned int len; len = strlen(name); if (strncmp(name, SIMPLE_SPEC, len) == 0) *line_style = ZN_LINE_SIMPLE; else if (strncmp(name, DASHED_SPEC, len) == 0) *line_style = ZN_LINE_DASHED; else if (strncmp(name, MIXED_SPEC, len) == 0) *line_style = ZN_LINE_MIXED; else if (strncmp(name, DOTTED_SPEC, len) == 0) *line_style = ZN_LINE_DOTTED; else { Tcl_AppendResult(wi->interp, "bad line style \"", name, "\": must be ", SIMPLE_SPEC, ", ", DASHED_SPEC, ", ", DOTTED_SPEC, ", ", MIXED_SPEC, NULL); return TCL_ERROR; } return TCL_OK; } char * ZnNameOfLineStyle(ZnLineStyle line_style) { switch (line_style) { case ZN_LINE_SIMPLE: return SIMPLE_SPEC; case ZN_LINE_DASHED: return DASHED_SPEC; case ZN_LINE_MIXED: return MIXED_SPEC; case ZN_LINE_DOTTED: return DOTTED_SPEC; default: return "unknown line style"; } } /* **************************************************************** * * Code for leader anchors. * * Format is: lChar leftLeaderAnchor [ lChar rightLeaderAnchor] * * If lChar is a '|', leftLeaderAnchor and rightLeaderAnchor are the indices * of the fields that serve to anchor the label's leader. More specifically * the bottom left corner of the left field and the bottom right corner of * the right field are used as the anchors. * If lChar is '%', leftLeaderAnchor and rightLeaderAnchor should be * specified as 'valxval', 'val' being a percentage (max 100) of the * width/height of the label bounding box. * If rightLeaderAnchor is not specified it defaults to leftLeaderAnchor. * If neither of them are specified, the center of the label is used as an * anchor. * **************************************************************** */ int ZnGetLeaderAnchors(ZnWInfo *wi, char *name, ZnLeaderAnchors *leader_anchors) { int anchors[4]; int index, num_tok, anchor_index=0; *leader_anchors = NULL; while (*name && (*name == ' ')) { name++; } while (*name && (anchor_index < 4)) { switch (*name) { case '|': num_tok = sscanf(name, "|%d%n", &anchors[anchor_index], &index); if (num_tok != 1) { la_error: Tcl_AppendResult(wi->interp, " incorrect leader anchors \"", name, "\"", NULL); return TCL_ERROR; } anchors[anchor_index+1] = -1; break; case '%': num_tok = sscanf(name, "%%%dx%d%n", &anchors[anchor_index], &anchors[anchor_index+1], &index); if (num_tok != 2) { goto la_error; } if (anchors[anchor_index] < 0) { anchors[anchor_index] = 0; } if (anchors[anchor_index] > 100) { anchors[anchor_index] = 100; } if (anchors[anchor_index+1] < 0) { anchors[anchor_index+1] = 0; } if (anchors[anchor_index+1] > 100) { anchors[anchor_index+1] = 100; } break; default: goto la_error; } anchor_index += 2; name += index; } /* * If empty, pick the default (center of the bounding box). */ if (anchor_index != 0) { *leader_anchors = ZnMalloc(sizeof(ZnLeaderAnchorsStruct)); (*leader_anchors)->left_x = anchors[0]; (*leader_anchors)->left_y = anchors[1]; if (anchor_index == 2) { (*leader_anchors)->right_x = (*leader_anchors)->left_x; (*leader_anchors)->right_y = (*leader_anchors)->left_y; } else { (*leader_anchors)->right_x = anchors[2]; (*leader_anchors)->right_y = anchors[3]; } } return TCL_OK; } /* * name must be large enough to hold the returned string. */ void ZnNameOfLeaderAnchors(ZnLeaderAnchors leader_anchors, char *name) { unsigned int count; if (!leader_anchors) { strcpy(name, "%50x50"); } else { if (leader_anchors->left_y < 0) { count = sprintf(name, "|%d", leader_anchors->left_x); } else { count = sprintf(name, "%%%dx%d", leader_anchors->left_x, leader_anchors->left_y); } name += count; if (leader_anchors->right_y < 0) { sprintf(name, "|%d", leader_anchors->right_x); } else { sprintf(name, "%%%dx%d", leader_anchors->right_x, leader_anchors->right_y); } } } /* ****************************************************************** * * Code for label formats. * ****************************************************************** */ static Tcl_HashTable format_cache; static ZnBool format_inited = False; static char CharToAttach(int attach) { switch (attach) { case '>': return ZN_LF_ATTACH_FWD; case '<': return ZN_LF_ATTACH_BWD; case '^': return ZN_LF_ATTACH_LEFT; case '$': return ZN_LF_ATTACH_RIGHT; case '+': default: return ZN_LF_ATTACH_PIXEL; } } static char CharToDim(int dim) { switch (dim) { case 'f': return ZN_LF_DIM_FONT; case 'i': return ZN_LF_DIM_ICON; case 'a': return ZN_LF_DIM_AUTO; case 'l': return ZN_LF_DIM_LABEL; case 'x': default: return ZN_LF_DIM_PIXEL; } } /* * The new format is as follow. Parameters between [] are * optional and take default values when omitted. The spaces can appear * between blocks but not inside. * * [ WidthxHeight ] [ field0Spec ][ field1Spec ]...[ fieldnSpec ] * * Width and Height set the size of the clipping box surrounding * the label. If it is not specified, there will be no clipping. * It it is specified alone it is the size of the only displayed * field (0). * * fieldSpec is: * sChar fieldWidth sChar fieldHeight [pChar fieldX pChar fieldY]. * * Each field description refers to the field of same index in the field * array. * If sChar is 'x', the dimension is in pixel. If sChar is 'f', the * dimension is in percentage of the mean width/height of a character (in the * field font). If sChar is 'i', the dimension is in percentage of the size * of the image in the field. If sChar is 'a', the dimension is automatically * adjusted to match the field's content plus the given value in pixels. * If pChar is '+' the position is in pixel (possibly negative). If it is * '<' the position is the index of the field at the left/top of which the * current field should be attached. If it is '>' the position is the index * of the field at the right/bottom of which the current field should be * attached. If pChar is '^' the position is the index of the field used to * align the left/top border (left on left or top on top). If pChar is '$' the * position is the index of the field used to align the right/bottom border * (right on right or bottom on bottom). * The positional parameters can be omitted if there is only one field. * */ ZnLabelFormat ZnLFCreate(Tcl_Interp *interp, char *format_str, unsigned int num_fields) { ZnList fields; Tcl_HashEntry *entry; ZnFieldFormatStruct field_struct; ZnFieldFormat field_array; ZnLabelFormat format; int width, height; ZnDim c_width=0.0, c_height=0.0; int index, num_tok, num_ffs, new; unsigned int field_index=0; char *ptr = format_str, *next_ptr; char x_char, y_char; if (!format_inited) { Tcl_InitHashTable(&format_cache, TCL_STRING_KEYS); format_inited = True; } entry = Tcl_CreateHashEntry(&format_cache, format_str, &new); if (!new) { format = (ZnLabelFormat) Tcl_GetHashValue(entry); if (format->num_fields <= num_fields) { format->ref_count++; return format; } else { Tcl_AppendResult(interp, "too many fields in label format: \"", format_str, "\"", NULL); return NULL; } } fields = ZnListNew(1, sizeof(ZnFieldFormatStruct)); /* * Try to see if it starts with a number or a leader spec. */ while (*ptr && (*ptr == ' ')) { ptr++; } if (!*ptr) { goto lf_error_syn; } if ((*ptr != 'x') && (*ptr != 'f') && (*ptr != 'i') && (*ptr != 'a') && (*ptr != 'l')) { c_width = (ZnDim) strtod(ptr, &next_ptr); if ((ptr == next_ptr) || (*next_ptr != 'x')) { lf_error_syn: Tcl_AppendResult(interp, "invalid label format specification \"", ptr, "\"", NULL); lf_error: Tcl_DeleteHashEntry(entry); ZnListFree(fields); return NULL; } ptr = next_ptr+1; c_height = (ZnDim) strtod(ptr, &next_ptr); if (ptr == next_ptr) { goto lf_error_syn; } ptr = next_ptr; } if (!*ptr) { /* It is a simple spec, one field. */ field_struct.x_attach = field_struct.y_attach = ZN_LF_ATTACH_PIXEL; field_struct.x_dim = field_struct.y_dim = ZN_LF_DIM_PIXEL; field_struct.x_spec = field_struct.y_spec = 0; field_struct.width_spec = (short) c_width; field_struct.height_spec = (short) c_height; c_width = c_height = 0.0; ZnListAdd(fields, &field_struct, ZnListTail); goto lf_end_parse; } /* * Parse the field specs. */ lf_parse2: while (*ptr && (*ptr == ' ')) { ptr++; } if (!*ptr) { goto lf_end_parse; } /* Preset the default field values. */ field_struct.x_spec = field_struct.y_spec = 0; field_struct.x_attach = field_struct.y_attach = ZN_LF_ATTACH_PIXEL; field_struct.x_dim = field_struct.y_dim = ZN_LF_DIM_PIXEL; if ((*ptr == 'x') || (*ptr == 'f') || (*ptr == 'i') || (*ptr == 'a') || (*ptr == 'l')) { num_tok = sscanf(ptr, "%c%d%c%d%n", &x_char, &width, &y_char, &height, &index); if (num_tok != 4) { goto lf_error_syn; } //if (width < 0) { // width = 0; //} //if (height < 0) { // height = 0; //} field_struct.x_dim = CharToDim(x_char); field_struct.y_dim = CharToDim(y_char); ptr += index; if ((*ptr == '>') || (*ptr == '<') || (*ptr == '+') || (*ptr == '^') || (*ptr == '$')) { num_tok = sscanf(ptr, "%c%d%c%d%n", &x_char, &field_struct.x_spec, &y_char, &field_struct.y_spec, &index); if (num_tok != 4) { goto lf_error_syn; } field_struct.x_attach = CharToAttach(x_char); field_struct.y_attach = CharToAttach(y_char); ptr += index; } else if (!*ptr || (field_index != 0)) { /* An incomplete field spec is an error if there are several fields. */ Tcl_AppendResult(interp, "incomplete field in label format: \"", ptr-index, "\"", NULL); goto lf_error; } if (field_index >= num_fields) { Tcl_AppendResult(interp, "too many fields in label format: \"", format_str, "\"", NULL); goto lf_error; } field_struct.width_spec = (short) width; field_struct.height_spec = (short) height; ZnListAdd(fields, &field_struct, ZnListTail); field_index++; goto lf_parse2; } else { goto lf_error_syn; } lf_end_parse: field_array = (ZnFieldFormat) ZnListArray(fields); num_ffs = ZnListSize(fields); format = (ZnLabelFormat) ZnMalloc(sizeof(ZnLabelFormatStruct) + (num_ffs-1) * sizeof(ZnFieldFormatStruct)); format->clip_width = (short) c_width; format->clip_height = (short) c_height; format->num_fields = num_ffs; memcpy(&format->fields, field_array, num_ffs * sizeof(ZnFieldFormatStruct)); ZnListFree(fields); format->ref_count = 1; format->entry = entry; Tcl_SetHashValue(entry, (ClientData) format); return format; } ZnLabelFormat ZnLFDuplicate(ZnLabelFormat lf) { lf->ref_count++; return lf; } void ZnLFDelete(ZnLabelFormat lf) { lf->ref_count--; if (lf->ref_count == 0) { Tcl_DeleteHashEntry(lf->entry); ZnFree(lf); } } char * ZnLFGetString(ZnLabelFormat lf) { return Tcl_GetHashKey(&format_cache, lf->entry); #if 0 ZnFieldFormat ff; char *ptr; char x_char, y_char, w_char, h_char; unsigned int i, count; ptr = str; if ((lf->clip_width != 0) || (lf->clip_height != 0)) { count = sprintf(ptr, "%dx%d", lf->clip_width, lf->clip_height); ptr += count; } if (lf->left_y < 0) { count = sprintf(ptr, "|%d", lf->left_x); } else { count = sprintf(ptr, "%%%dx%d", lf->left_x, lf->left_y); } ptr += count; if (lf->right_y < 0) { count = sprintf(ptr, "|%d", lf->right_x); } else { count = sprintf(ptr, "%%%dx%d", lf->right_x, lf->right_y); } ptr += count; for (i = 0; i < lf->num_fields; i++) { ff = &lf->fields[i]; x_char = AttachToChar(ff->x_attach); y_char = AttachToChar(ff->y_attach); w_char = DimToChar(ff->x_dim); h_char = DimToChar(ff->y_dim); count = sprintf(ptr, "%c%d%c%d%c%d%c%d", w_char, ff->width_spec, h_char, ff->height_spec, x_char, ff->x_spec, y_char, ff->y_spec); ptr += count; } *ptr = 0; #endif } /* * If the clip box has both its width and its height * set to zero, it means that there is no clipbox. */ ZnBool ZnLFGetClipBox(ZnLabelFormat lf, ZnDim *w, ZnDim *h) { if ((lf->clip_width == 0) && (lf->clip_height == 0)) { return False; } *w = (ZnDim) lf->clip_width; *h = (ZnDim) lf->clip_height; return True; } void ZnLFGetField(ZnLabelFormat lf, unsigned int field, char *x_attach, char *y_attach, char *x_dim, char *y_dim, int *x_spec, int *y_spec, short *width_spec, short *height_spec) { ZnFieldFormat fptr; fptr = &lf->fields[field]; *x_attach = fptr->x_attach; *y_attach = fptr->y_attach; *x_dim = fptr->x_dim; *y_dim = fptr->y_dim; *x_spec = fptr->x_spec; *y_spec = fptr->y_spec; *width_spec = fptr->width_spec; *height_spec = fptr->height_spec; } /* **************************************************************** * * Code for line ends. * **************************************************************** */ static Tcl_HashTable line_end_cache; static ZnBool line_end_inited = False; ZnLineEnd ZnLineEndCreate(Tcl_Interp *interp, char *line_end_str) { Tcl_HashEntry *entry; ZnLineEnd le; int new, argc; ZnReal a, b, c; if (!line_end_inited) { Tcl_InitHashTable(&line_end_cache, TCL_STRING_KEYS); line_end_inited = True; } entry = Tcl_CreateHashEntry(&line_end_cache, line_end_str, &new); if (!new) { le = (ZnLineEnd) Tcl_GetHashValue(entry); le->ref_count++; return le; } argc = sscanf(line_end_str, "%lf %lf %lf", &a, &b, &c); if (argc == 3) { le = (ZnLineEnd) ZnMalloc(sizeof(ZnLineEndStruct)); le->shape_a = a; le->shape_b = b; le->shape_c = c; le->entry = entry; le->ref_count = 1; Tcl_SetHashValue(entry, (ClientData) le); return le; } else { Tcl_AppendResult(interp, "incorrect line end spec: \"", line_end_str, "\", should be: shapeA shapeB shapeC", NULL); return NULL; } } char * ZnLineEndGetString(ZnLineEnd le) { return Tcl_GetHashKey(&line_end_cache, le->entry); } void ZnLineEndDelete(ZnLineEnd le) { le->ref_count--; if (le->ref_count == 0) { Tcl_DeleteHashEntry(le->entry); ZnFree(le); } } ZnLineEnd ZnLineEndDuplicate(ZnLineEnd le) { le->ref_count++; return le; } /* ****************************************************************** * * Code for fill rules. They are directly inhereted from the * GLU tesselator constants. * ****************************************************************** */ #define FILL_RULE_ODD_SPEC "odd" #define FILL_RULE_NON_ZERO_SPEC "nonzero" #define FILL_RULE_POSITIVE_SPEC "positive" #define FILL_RULE_NEGATIVE_SPEC "negative" #define FILL_RULE_ABS_GEQ_2_SPEC "abs_geq_2" int ZnGetFillRule(ZnWInfo *wi, char *name, ZnFillRule *fill_rule) { unsigned int len; len = strlen(name); if (strncmp(name, FILL_RULE_ODD_SPEC, len) == 0) { *fill_rule = GLU_TESS_WINDING_ODD; } else if (strncmp(name, FILL_RULE_NON_ZERO_SPEC, len) == 0) { *fill_rule = GLU_TESS_WINDING_NONZERO; } else if (strncmp(name, FILL_RULE_POSITIVE_SPEC, len) == 0) { *fill_rule = GLU_TESS_WINDING_POSITIVE; } else if (strncmp(name, FILL_RULE_NEGATIVE_SPEC, len) == 0) { *fill_rule = GLU_TESS_WINDING_NEGATIVE; } else if (strncmp(name, FILL_RULE_ABS_GEQ_2_SPEC, len) == 0) { *fill_rule = GLU_TESS_WINDING_ABS_GEQ_TWO; } else { Tcl_AppendResult(wi->interp, "bad fill rule \"", name, "\": must be ", FILL_RULE_ODD_SPEC, ", ", FILL_RULE_NON_ZERO_SPEC, ", ", FILL_RULE_POSITIVE_SPEC, ", ", FILL_RULE_NEGATIVE_SPEC, ", ", FILL_RULE_ABS_GEQ_2_SPEC, NULL); return TCL_ERROR; } return TCL_OK; } char * ZnNameOfFillRule(ZnFillRule fill_rule) { switch (fill_rule) { case GLU_TESS_WINDING_ODD: return FILL_RULE_ODD_SPEC; case GLU_TESS_WINDING_NONZERO: return FILL_RULE_NON_ZERO_SPEC; case GLU_TESS_WINDING_POSITIVE: return FILL_RULE_POSITIVE_SPEC; case GLU_TESS_WINDING_NEGATIVE: return FILL_RULE_NEGATIVE_SPEC; case GLU_TESS_WINDING_ABS_GEQ_TWO: return FILL_RULE_ABS_GEQ_2_SPEC; default: return "unknown fill rule"; } } /* ****************************************************************** * * Code for auto alignments in fields. * ****************************************************************** */ int ZnGetAutoAlign(ZnWInfo *wi, char *name, ZnAutoAlign *aa) { int j; if (strcmp(name, "-") == 0) { aa->automatic = False; } else if (strlen(name) == 3) { aa->automatic = True; for (j = 0; j < 3; j++) { switch(name[j]) { case 'l': case 'L': aa->align[j] = TK_JUSTIFY_LEFT; break; case 'c': case 'C': aa->align[j] = TK_JUSTIFY_CENTER; break; case 'r': case 'R': aa->align[j] = TK_JUSTIFY_RIGHT; break; default: goto aa_error; } } } else { aa_error: Tcl_AppendResult(wi->interp, "invalid auto alignment specification \"", name, "\" should be - or a triple of lcr", NULL); return TCL_ERROR; } return TCL_OK; } /* * name must be large enough to hold the returned string. * 64 chars should be enough with the current values. */ void ZnNameOfAutoAlign(ZnAutoAlign *aa, char *name) { unsigned int i; if (aa->automatic == False) { strcpy(name, "-"); } else { name[0] = 0; for (i = 0; i < 3; i++) { switch (aa->align[i]) { case TK_JUSTIFY_LEFT: strcat(name, "l"); break; case TK_JUSTIFY_CENTER: strcat(name, "c"); break; case TK_JUSTIFY_RIGHT: strcat(name, "r"); break; } } } }