diff options
-rw-r--r-- | generic/Attrs.c | 500 |
1 files changed, 500 insertions, 0 deletions
diff --git a/generic/Attrs.c b/generic/Attrs.c new file mode 100644 index 0000000..2bc3a81 --- /dev/null +++ b/generic/Attrs.c @@ -0,0 +1,500 @@ +/* + * Attrs.c -- Various attributes manipulation routines. + * + * Authors : Patrick Lecoanet. + * Creation date : Fri Dec 31 10:03:34 1999 + * + * $Id$ + */ + +/* + * Copyright (c) 1993 - 1999 CENA, Patrick Lecoanet -- + * + * This code is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this code; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include "Attrs.h" +#include "Item.h" +#include "List.h" +#include "Geo.h" + +#include <memory.h> +#include <malloc.h> +#include <stdlib.h> + + +static const char rcsid[] = "$Id$"; +static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; + + +/* + ****************************************************************** + * + * Code for label formats. + * + ****************************************************************** + */ +static Tcl_HashTable format_cache; +static RadarBool format_inited = False; + +#if 0 +static char +AttachToChar(char attach) +{ + switch (attach) { + case LF_ATTACH_FWD: + return '>'; + case LF_ATTACH_BWD: + return '<'; + case LF_ATTACH_LEFT: + return '^'; + case LF_ATTACH_RIGHT: + return '$'; + case LF_ATTACH_PIXEL: + default: + return '+'; + } +} + +static char +DimToChar(char dim) +{ + switch (dim) { + case LF_DIM_FONT: + return 'f'; + case LF_DIM_ICON: + return 'i'; + case LF_DIM_AUTO: + return 'a'; + case LF_DIM_PIXEL: + default: + return 'x'; + } +} +#endif + +static char +CharToAttach(char attach) +{ + switch (attach) { + case '>': + return LF_ATTACH_FWD; + case '<': + return LF_ATTACH_BWD; + case '^': + return LF_ATTACH_LEFT; + case '$': + return LF_ATTACH_RIGHT; + case '+': + default: + return LF_ATTACH_PIXEL; + } +} + +static char +CharToDim(char dim) +{ + switch (dim) { + case 'f': + return LF_DIM_FONT; + case 'i': + return LF_DIM_ICON; + case 'a': + return LF_DIM_AUTO; + case 'x': + default: + return 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. + * + */ +LabelFormat +LabelFormatCreate(Tcl_Interp *interp, + char *format_str, + int num_fields) +{ + RadarList fields; + Tcl_HashEntry *entry; + FieldFormatStruct field_struct; + FieldFormat field_array; + LabelFormat format; + int width, height; + RadarDim c_width=0.0, c_height=0.0; + int index, num_tok, num_ffs, new; + 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 = (LabelFormat) 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 = RadarListNew(1, sizeof(FieldFormatStruct)); + + /* + * Try to see if it starts with a number or a leader spec. + */ + while (*ptr && (*ptr == ' ')) { + ptr++; + } + if (!*ptr) { + goto lf_end_parse; + } + if ((*ptr != 'x') && (*ptr != 'f') && (*ptr != 'i') && (*ptr != 'a')) { + c_width = (RadarDim) 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: + RadarListFree(fields); + return NULL; + } + ptr = next_ptr+1; + c_height = (RadarDim) 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 = LF_ATTACH_PIXEL; + field_struct.x_dim = field_struct.y_dim = 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; + RadarListAdd(fields, &field_struct, RadarListTail); + 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 = LF_ATTACH_PIXEL; + field_struct.x_dim = field_struct.y_dim = LF_DIM_PIXEL; + if ((*ptr == 'x') || (*ptr == 'f') || (*ptr == 'i') || (*ptr == 'a')) { + 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 is 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; + RadarListAdd(fields, &field_struct, RadarListTail); + field_index++; + goto lf_parse2; + } + else { + goto lf_error_syn; + } + + lf_end_parse: + field_array = (FieldFormat) RadarListArray(fields); + num_ffs = RadarListSize(fields); + + format = (LabelFormat) RadarMalloc(sizeof(LabelFormatStruct) + + (num_ffs-1) * sizeof(FieldFormatStruct)); + 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(FieldFormatStruct)); + RadarListFree(fields); + + format->ref_count = 1; + format->entry = entry; + Tcl_SetHashValue(entry, (ClientData) format); + + return format; +} + + +LabelFormat +LabelFormatDuplicate(LabelFormat lf) +{ + lf->ref_count++; + return lf; +} + + +void +LabelFormatDelete(LabelFormat lf) +{ + lf->ref_count--; + if (lf->ref_count == 0) { + Tcl_DeleteHashEntry(lf->entry); + RadarFree(lf); + } +} + + +char * +LabelFormatGetString(LabelFormat lf) +{ + return Tcl_GetHashKey(&format_cache, lf->entry); + +#if 0 + FieldFormat ff; + char *ptr; + char x_char, y_char, w_char, h_char; + 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. + */ +RadarBool +LabelFormatGetClipBox(LabelFormat lf, + RadarDim *w, + RadarDim *h) +{ + if ((lf->clip_width == 0) && (lf->clip_height == 0)) { + return False; + } + + *w = (RadarDim) lf->clip_width; + *h = (RadarDim) lf->clip_height; + + return True; +} + + +void +LabelFormatGetField(LabelFormat lf, + 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) +{ + FieldFormat 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 RadarBool line_end_inited = False; + + +LineEnd +LineEndCreate(Tcl_Interp *interp, + char *line_end_str) +{ + Tcl_HashEntry *entry; + LineEnd le; + int new, argc; + RadarReal 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 = (LineEnd) Tcl_GetHashValue(entry); + le->ref_count++; + return le; + } + + argc = sscanf(line_end_str, "%lf %lf %lf", &a, &b, &c); + if (argc == 3) { + le = (LineEnd) RadarMalloc(sizeof(LineEndStruct)); + 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 * +LineEndGetString(LineEnd le) +{ + return Tcl_GetHashKey(&line_end_cache, le->entry); +} + + +void +LineEndDelete(LineEnd le) +{ + le->ref_count--; + if (le->ref_count == 0) { + Tcl_DeleteHashEntry(le->entry); + RadarFree(le); + } +} + + +LineEnd +LineEndDuplicate(LineEnd le) +{ + le->ref_count++; + return le; +} |