aboutsummaryrefslogtreecommitdiff
path: root/generic
diff options
context:
space:
mode:
Diffstat (limited to 'generic')
-rw-r--r--generic/Attrs.c500
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;
+}