>From 0ebf478ea1e7698a5c625d595de879c2522c4b85 Mon Sep 17 00:00:00 2001 From: Paul Chavent Date: Sun, 16 Dec 2012 23:42:56 +0100 Subject: [PATCH] Add sozi front end --- configure.in | 12 + objects/Misc/Makefile.am | 9 +- objects/Misc/libmisc.c | 2 + objects/Misc/pixmaps/sozi-frame.xpm | 196 +++++++ objects/Misc/sozi-frame.c | 1087 +++++++++++++++++++++++++++++++++++ objects/Misc/sozi.h | 317 ++++++++++ sheets/Misc.sheet.in | 3 + 7 files changed, 1624 insertions(+), 2 deletions(-) create mode 100644 objects/Misc/pixmaps/sozi-frame.xpm create mode 100644 objects/Misc/sozi-frame.c create mode 100644 objects/Misc/sozi.h diff --git a/configure.in b/configure.in index 9dce17f..7e9197c 100644 --- a/configure.in +++ b/configure.in @@ -184,6 +184,18 @@ AC_SUBST(XSLT_DIR) AC_SUBST(XSLT_LIBS) AC_SUBST(XSLT_CFLAGS) +# Find where are the sozi.version, sozi.js and sozi.css files +AC_ARG_WITH(sozi-path, + [ --with-sozi-path=DIR Specify where to find the optional sozi player + (default=DATAROOTDIR/sozi)], + SOZI_PATH=$withval, + SOZI_PATH=$prefix/share/sozi) +AC_CHECK_FILE($SOZI_PATH/sozi.version,have_sozi_version=yes,have_sozi_version=no) +#AC_CHECK_FILE($SOZI_PATH/sozi.js,have_sozi_js=yes,have_sozi_js=no) +#AC_CHECK_FILE($SOZI_PATH/sozi.css,have_sozi_css=yes,have_sozi_css=no) +AM_CONDITIONAL(WITH_SOZI_PATH, test "$have_sozi_version" = yes) +AC_SUBST(SOZI_PATH) + # Figure out a prefix for where to find libxslt at runtime. AC_ARG_WITH(xslt-prefix, [ --with-xslt-prefix=DIR Specify where to find the optional XSLT libraries diff --git a/objects/Misc/Makefile.am b/objects/Misc/Makefile.am index 306fae4..bf76918 100644 --- a/objects/Misc/Makefile.am +++ b/objects/Misc/Makefile.am @@ -7,8 +7,12 @@ libmisc_objects_la_SOURCES = \ diagram_as_object.c \ grid_object.c \ measure.c \ - tree.c + tree.c \ + sozi-frame.c +if WITH_SOZI_PATH +libmisc_objects_la_CFLAGS = -DSOZI_PATH="\"$(SOZI_PATH)\"" +endif libmisc_objects_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED) @@ -23,7 +27,8 @@ EXTRA_DIST = \ pixmaps/grid_object.xpm \ pixmaps/measure.xpm \ pixmaps/newgroup.xpm \ - pixmaps/tree.xpm + pixmaps/tree.xpm \ + pixmaps/sozi-frame.xpm diff --git a/objects/Misc/libmisc.c b/objects/Misc/libmisc.c index e72ea9a..65b75a9 100644 --- a/objects/Misc/libmisc.c +++ b/objects/Misc/libmisc.c @@ -33,6 +33,7 @@ extern DiaObjectType grid_object_type; extern DiaObjectType tree_type; extern DiaObjectType measure_type; extern DiaObjectType diagram_as_element_type; +extern DiaObjectType sozi_frame_type; DIA_PLUGIN_CHECK_INIT @@ -48,6 +49,7 @@ dia_plugin_init(PluginInfo *info) object_register_type(&tree_type); object_register_type(&measure_type); object_register_type(&diagram_as_element_type); + object_register_type(&sozi_frame_type); return DIA_PLUGIN_INIT_OK; } diff --git a/objects/Misc/pixmaps/sozi-frame.xpm b/objects/Misc/pixmaps/sozi-frame.xpm new file mode 100644 index 0000000..e5f3ed3 --- /dev/null +++ b/objects/Misc/pixmaps/sozi-frame.xpm @@ -0,0 +1,196 @@ +/* XPM */ +static char * sozi_frame_xpm[] = { +"22 22 171 2", +" c #FFFFFF", +". c #FEFEFE", +"+ c #FDFDFD", +"@ c #F7F7F8", +"# c #D2D2D2", +"$ c #939393", +"% c #8A8A8A", +"& c #BEBEBE", +"* c #F2F2F2", +"= c #FCFCFC", +"- c #F3F3F3", +"; c #FBFBFB", +"> c #FEFEFF", +", c #FCFCFB", +"' c #FAF4F1", +") c #FAF1EB", +"! c #F8F5F2", +"~ c #BFBFBF", +"{ c #E4E4E4", +"] c #F1F1F1", +"^ c #ADADAD", +"/ c #F5F5F5", +"( c #BEBABE", +"_ c #99909A", +": c #EDEAED", +"< c #ECDCD2", +"[ c #C3682D", +"} c #C64500", +"| c #98562A", +"1 c #BBB6B2", +"2 c #F8F8F9", +"3 c #FBFCFB", +"4 c #FBFCFC", +"5 c #E8BC9E", +"6 c #F55A00", +"7 c #F05F00", +"8 c #E4BCA1", +"9 c #F3F8FC", +"0 c #F6F6F6", +"a c #DCDCDC", +"b c #CACACA", +"c c #CDCDCD", +"d c #CBCBC9", +"e c #D8D8D7", +"f c #FBFBFC", +"g c #E7B99A", +"h c #F25600", +"i c #DD7A39", +"j c #E7DDD6", +"k c #D0D0D0", +"l c #C8C8C8", +"m c #989898", +"n c #CACBCC", +"o c #A3A298", +"p c #BFB483", +"q c #EEE8D1", +"r c #FBFBFA", +"s c #FAFBFC", +"t c #E6BA9E", +"u c #EB5400", +"v c #ECA372", +"w c #F8FBFD", +"x c #ECECEC", +"y c #FBFCFE", +"z c #D3D1C7", +"A c #DDB617", +"B c #C4A423", +"C c #EFECE1", +"D c #FBFDFF", +"E c #E5C3AD", +"F c #DD5A03", +"G c #E8AD85", +"H c #F9FFFF", +"I c #E6E6E6", +"J c #E9E9EA", +"K c #CFCECD", +"L c #DEBF2D", +"M c #C99E00", +"N c #EDE9D1", +"O c #E4D5CC", +"P c #AE6636", +"Q c #E2BCA3", +"R c #FFFFFE", +"S c #E5E5E5", +"T c #C8C8C9", +"U c #D9DBE5", +"V c #DBBD39", +"W c #B79A21", +"X c #EDEADF", +"Y c #ECEAE9", +"Z c #A98C7A", +"` c #D3B8A6", +" . c #E3E3E3", +".. c #C7C7C7", +"+. c #F1F3FC", +"@. c #A5965C", +"#. c #BDB496", +"$. c #BEBBB8", +"%. c #B3ACA7", +"&. c #E9E7E7", +"*. c #B6B4B4", +"=. c #92939A", +"-. c #DFDFE3", +";. c #ADAEAF", +">. c #CCCDCE", +",. c #7D898D", +"'. c #DCDBDA", +"). c #EDEDED", +"!. c #DADADA", +"~. c #9B9B9B", +"{. c #DEDEDE", +"]. c #FFFEFE", +"^. c #B4CBD2", +"/. c #389CB5", +"(. c #6E9CA8", +"_. c #DDDDDD", +":. c #EAEAEA", +"<. c #CECECE", +"[. c #B6B6B6", +"}. c #E7E7E7", +"|. c #B2D0D8", +"1. c #1BB6DE", +"2. c #00A7D3", +"3. c #82AFBB", +"4. c #EEEEEE", +"5. c #999999", +"6. c #F0F0F0", +"7. c #E0E0E0", +"8. c #F9FCFC", +"9. c #1194B5", +"0. c #00CEFF", +"a. c #23BAE1", +"b. c #C3D0D4", +"c. c #D4D4D4", +"d. c #FAFCFC", +"e. c #2E8FA8", +"f. c #00BDEF", +"g. c #3AB4D3", +"h. c #F8F2F1", +"i. c #EBEBEB", +"j. c #C6C6C6", +"k. c #A8A8A8", +"l. c #F4F4F4", +"m. c #DBE7EB", +"n. c #6894A0", +"o. c #6C8288", +"p. c #A3A1A0", +"q. c #949494", +"r. c #8F8F8F", +"s. c #E2E2E2", +"t. c #BABABA", +"u. c #CBCACA", +"v. c #9A9898", +"w. c #F3F2F1", +"x. c #E9E9E9", +"y. c #E8E8E8", +"z. c #F9F9F9", +"A. c #F7F7F7", +"B. c #A9A9A9", +"C. c #C1C1C1", +"D. c #D7D7D7", +"E. c #F7F6F6", +"F. c #FAFAFA", +"G. c #5F5F5F", +"H. c #B2B2B2", +"I. c #F8F8F8", +"J. c #D8D8D8", +"K. c #909090", +"L. c #7D7D7D", +"M. c #858585", +"N. c #B4B4B4", +" . . . . . + + . . . . . ", +" . @ # $ % & * . = - ; . ", +" > , ' ) ! ~ { ] ^ / ( _ : ", +" < [ } | 1 2 . . * ~ 3 . . ", +" 4 5 6 7 8 9 = . 0 a b c ; d e > . ", +" f g h i j . 0 k l m n o p q r . . ", +" s t u v w . x y z A B C > . ", +" D E F G H . . = I J K L M N ", +" O P Q R . S T U V W X > ", +" . Y Z ` > . . + # 2 ", +" R $.%. . . . . &.*.c =.-. ", +" . n ;.= . . >.,.'.a ). . . ", +" . !.~.{. . . ].^./.(. . # _. ", +" . :.<.[.}. . + |.1.2.3. 4...5.= ", +" * 6.c 7.+ 8.9.0.a.b. . 6.<.+ ", +" . c.7.# - . . d.e.f.g.h. ", +" . i.j.k.l. > m.n.o.p.$ q.r.s.. ", +" . . I & t.0 ; ] u.v.w.).x.x.y.z.. . ", +" . + A.B.c C.<.D.E. . . ", +"F.G.H.i.I. 4.C./ z.; ; . . ", +". / J.~ K.L.M.N.l.. . . ", +" . . + + + . . . . . "}; diff --git a/objects/Misc/sozi-frame.c b/objects/Misc/sozi-frame.c new file mode 100644 index 0000000..e88b52d --- /dev/null +++ b/objects/Misc/sozi-frame.c @@ -0,0 +1,1087 @@ + +/* Dia -- an diagram creation/manipulation program + * Copyright (C) 1999 Alexander Larsson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/****************************************************************************** + * This is a front end for the integration of the sozi player to the svg + * exports. + * This object allow to define frames that will allow to make an interactive + * presentation of a diagram. + * Please read http://sozi.baierouge.fr/wiki/doku.php for more information. + * + * + * FIXME: + * - the two "internals" headers are legal ? + * - the problem of the frame title/sequence display : + * - should we display something ? + * - what : sequence number, title, both ? + * - should it be editable ? + * - placement : inside, outside ? + * - size : dynamic resizing ? + * - redrawing after reordering ? + * + * TODO: + * - implement transition options + * + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* standard libs*/ +#include +#include + +/* xpath for searching in the svg doc */ +#include + +/* dia stuff */ +#include "object.h" +#include "diarenderer.h" +#include "diasvgrenderer.h" +#include "properties.h" +#include "text.h" + +/* FIXME : legal dia stuff ? */ +#include "prop_inttypes.h" +#include "propinternals.h" + +/* sozi stuff */ +#include "pixmaps/sozi-frame.xpm" +#include "sozi.h" + +/****************************************************************************** + * + *****************************************************************************/ + +typedef enum +{ + FREE_ASPECT, + FIXED_ASPECT +} AspectType; + +typedef struct _SoziFrame +{ + /* dia object inheritance */ + + DiaObject object; + + /* geometry of the object */ + + Point center; + real width; + real height; + AspectType aspect; + int angle; /* in degree , positive from x axis to y axis */ + + real cos_angle; + real sin_angle; + + real m[6]; /* transformation matrix of the unit square */ + + /* corners of the object */ + + Point corners[4]; + + /* sozi specific stuff */ + + int old_sequence; + int sequence; + + gchar * title; + gboolean hide; + gboolean clip; + int timeout; /* in milliseconds */ + + + /* interactive rendering appearence */ + gboolean legend_disp; + Text * legend; + TextAttributes legend_attrs; + +} SoziFrame; + +/****************************************************************************** + * + *****************************************************************************/ + +static DiaObject * sozi_frame_create(Point *startpoint, + void *user_data, + Handle **handle1, + Handle **handle2); +static DiaObject * sozi_frame_load(ObjectNode obj_node, int version, DiaContext *ctx); +static void sozi_frame_save(SoziFrame *sozi_frame, ObjectNode obj_node, const char *filename); + +static ObjectTypeOps sozi_frame_type_ops = +{ + (CreateFunc) sozi_frame_create, /* create */ + (LoadFunc) sozi_frame_load, /* load (== object_load_using_properties ?) */ + (SaveFunc) sozi_frame_save, /* save (== object_save_using_properties ?) */ + (GetDefaultsFunc) NULL, + (ApplyDefaultsFunc) NULL, +}; + +DiaObjectType sozi_frame_type = +{ + "Misc - Sozi Frame", /* name */ + 0, /* version */ + (char **) sozi_frame_xpm, /* pixmap */ + &sozi_frame_type_ops, /* ops */ + NULL, /* pixmap_file */ + 0 /* default_user_data */ +}; + +/****************************************************************************** + * + *****************************************************************************/ + +static void sozi_frame_destroy(SoziFrame *sozi_frame); + +static void sozi_frame_draw(SoziFrame *sozi_frame, DiaRenderer *renderer); + +static real sozi_frame_distance_from(SoziFrame *sozi_frame, Point *point); + +static void sozi_frame_select(SoziFrame *sozi_frame, Point *clicked_point, + DiaRenderer *interactive_renderer); + +static DiaObject * sozi_frame_copy(SoziFrame *sozi_frame); + +static ObjectChange* sozi_frame_move(SoziFrame *sozi_frame, Point *to); + +static ObjectChange* sozi_frame_move_handle(SoziFrame *sozi_frame, Handle *handle, + Point *to, ConnectionPoint *cp, + HandleMoveReason reason, ModifierKeys modifiers); +static GtkWidget * sozi_frame_get_properties(SoziFrame *sozi_frame, gboolean is_default); + +static ObjectChange * sozi_frame_apply_properties_dialog(SoziFrame *sozi_frame, GtkWidget *widget); + +static PropDescription * sozi_frame_describe_props(SoziFrame *sozi_frame); + +static void sozi_frame_get_props(SoziFrame *sozi_frame, GPtrArray *props); + +static void sozi_frame_set_props(SoziFrame *sozi_frame, GPtrArray *props); + + +static ObjectOps sozi_frame_ops = +{ + (DestroyFunc) sozi_frame_destroy, + (DrawFunc) sozi_frame_draw, + (DistanceFunc) sozi_frame_distance_from, + (SelectFunc) sozi_frame_select, + (CopyFunc) sozi_frame_copy, + (MoveFunc) sozi_frame_move, + (MoveHandleFunc) sozi_frame_move_handle, + (GetPropertiesFunc) sozi_frame_get_properties, + (ApplyPropertiesDialogFunc) sozi_frame_apply_properties_dialog, + (ObjectMenuFunc) 0, + (DescribePropsFunc) sozi_frame_describe_props, + (GetPropsFunc) sozi_frame_get_props, + (SetPropsFunc) sozi_frame_set_props, + (TextEditFunc) 0, + (ApplyPropertiesListFunc) object_apply_props, +}; + +/****************************************************************************** + * unit square + *****************************************************************************/ +static const Handle default_handles[4] = +{ + {HANDLE_RESIZE_NW, HANDLE_MAJOR_CONTROL, { 0, 0}, HANDLE_NONCONNECTABLE, NULL}, + {HANDLE_RESIZE_SW, HANDLE_MAJOR_CONTROL, { 0, 1}, HANDLE_NONCONNECTABLE, NULL}, + {HANDLE_RESIZE_SE, HANDLE_MAJOR_CONTROL, { 1, 1}, HANDLE_NONCONNECTABLE, NULL}, + {HANDLE_RESIZE_NE, HANDLE_MAJOR_CONTROL, { 1, 0}, HANDLE_NONCONNECTABLE, NULL}, +}; + +static const real sozi_frame_line_width = 0.01; + +/****************************************************************************** + * FUNCTIONS FOR MANAGING ACCESS TO THE SVG SOZI PLAYER ENGINE + *****************************************************************************/ + +static int +find_sozi_elem(xmlDocPtr doc, const xmlChar *sozi_elem) +{ + /* static const xmlChar *sozi_elem = (xmlChar*) "//script[ id='sozi-script']"; */ + xmlXPathContextPtr context; + xmlXPathObjectPtr result; + + context = xmlXPathNewContext(doc); + if(context == NULL) { + fprintf(stderr, "sozi-frame : error in xmlXPathNewContext\n"); + return 0; + } + + result = xmlXPathEvalExpression(sozi_elem, context); + xmlXPathFreeContext(context); + if(result == NULL) { + fprintf(stderr, "sozi-frame : error in xmlXPathEvalExpression\n"); + return 0; + } + + if(xmlXPathNodeSetIsEmpty(result->nodesetval)) { + xmlXPathFreeObject(result); + return 0; + } + + xmlXPathFreeObject(result); + return 1; +} + +static void +get_sozi_player(gchar **sozi_version, gchar **sozi_js, gchar **sozi_css) +{ +#if defined(SOZI_PATH) + gboolean res = TRUE; + GError * err; + int i; + struct + { + const gchar * filename; + gchar ** data; + } external_sozi[3] = + { + { SOZI_PATH"/sozi.version", sozi_version}, + { SOZI_PATH"/sozi.js" , sozi_js }, + { SOZI_PATH"/sozi.css" , sozi_css } + }; + + for (i = 0; i < 3; i++) { + *external_sozi[i].data = 0; + err = 0; + res &= g_file_get_contents(external_sozi[i].filename, + external_sozi[i].data, + NULL, + &err); + if (err != NULL) { + fprintf (stderr, "sozi-frame : unable to read file \"%s\" : %s\n", + external_sozi[i].filename, + err->message); + g_error_free (err); + } + } + + if(res == TRUE) + { + /* that's ok, don't need to go further */ + return; + } + + for (i = 0; i < 3; i++) { + if(*external_sozi[i].data != NULL) { + g_free (external_sozi[i].data); + external_sozi[i].data = NULL; + } + } +#endif /* defined(SOZI_PATH) */ + *sozi_version = g_strdup((const gchar *)own_sozi_version); + *sozi_js = g_strdup((const gchar *)own_sozi_js); + *sozi_css = g_strdup((const gchar *)own_sozi_css); +} + +/****************************************************************************** + * FUNCTIONS FOR MANAGING SOZI FRAME SEQUENCING + *****************************************************************************/ + +struct sequence_pair +{ + int old; + int new; +}; + +static void +reorder_sozi_objects(gpointer data, gpointer user_data) +{ + /* see object.h for the description of the object structure */ + DiaObject *dia_object = (DiaObject *)data; + if(strcmp(dia_object->type->name, sozi_frame_type.name) == 0) { + SoziFrame *sozi_frame = (SoziFrame *)dia_object; + struct sequence_pair * seq_pair = (struct sequence_pair *)user_data; + int this_seq = sozi_frame->sequence; + if((seq_pair->new <= this_seq) && (this_seq < seq_pair->old)) { + /* fprintf(stdout, "old value %d++ new value %d\n", sozi_frame->sequence, sozi_frame->sequence + 1); */ + sozi_frame->sequence++; + sozi_frame->old_sequence = sozi_frame->sequence; + /* FIXME : not sure it's the good way to redraw an object */ + /* sozi_frame_draw(sozi_frame); */ + } + else if((seq_pair->old < this_seq) && (this_seq <= seq_pair->new)) { + /* fprintf(stdout, "old value %d-- new value %d\n", sozi_frame->sequence, sozi_frame->sequence - 1); */ + sozi_frame->sequence--; + sozi_frame->old_sequence = sozi_frame->sequence; + /* FIXME : not sure it's the good way to redraw an object */ + /* sozi_frame_draw(sozi_frame); */ + } + } +} + +static void +count_sozi_objects(gpointer data, gpointer user_data) +{ + /* see object.h for the description of the object structure */ + DiaObject *dia_object = (DiaObject *)data; + if(strcmp(dia_object->type->name, sozi_frame_type.name) == 0) { + SoziFrame *sozi_frame = (SoziFrame *)dia_object; + if(sozi_frame->sequence) { + int * counter = (int *)user_data; + *counter = *counter + 1; + } + } +} + +/****************************************************************************** + * FUNCTIONS FOR MANAGING THE SOZI OBJECT INIT AND UPDATE + *****************************************************************************/ + +static void +sozi_frame_init(SoziFrame *sozi_frame, Point *center) +{ + DiaObject *dia_object; + int i; + + dia_object = &sozi_frame->object; + + dia_object->type = &sozi_frame_type; + dia_object->ops = &sozi_frame_ops; + dia_object->position = *center; + + /* dia_object->bounding_box will be set in sozi_frame_update_geometry */ + + dia_object->num_handles = 4; + if(dia_object->handles == NULL) { + dia_object->handles = g_new0(Handle *, 4); + } + + for (i = 0; i < 4; i++) { + if(dia_object->handles[i] == NULL) { + dia_object->handles[i] = g_new0(Handle, 1); + } + *dia_object->handles[i] = default_handles[i]; + } + + dia_object->num_connections = 1; + if(dia_object->connections == NULL) { + dia_object->connections = g_new0(ConnectionPoint *, 1); + } + + if(dia_object->connections[0] == NULL) { + dia_object->connections[0] = g_new0(ConnectionPoint, 1); + } + dia_object->connections[0]->object = dia_object; + dia_object->connections[0]->directions = DIR_ALL; + + /* dia_object->enclosing_box will be set in sozi_frame_update_geometry */ + + sozi_frame->center = *center; + sozi_frame->width = 4; + sozi_frame->height = 3; + sozi_frame->aspect = FIXED_ASPECT; + sozi_frame->angle = 0; + + /* sozi_frame->cos_angle will be set in sozi_frame_update_geometry */ + /* sozi_frame->sin_angle will be set in sozi_frame_update_geometry */ + /* sozi_frame->m will be set in sozi_frame_update_geometry */ + + /* sozi_frame->corners are set in sozi_frame_update_geometry */ + + /* it will be initialized later, only if the object is placed on a sheet */ + /* see sozi_frame_update_sequence here under */ + sozi_frame->old_sequence = 0; + sozi_frame->sequence = 0; + + if(sozi_frame->title == NULL) { + sozi_frame->title = g_strdup("frame title"); + } + + sozi_frame->hide = TRUE; + sozi_frame->clip = TRUE; + sozi_frame->timeout = 0; + + sozi_frame->legend_disp = TRUE; + sozi_frame->legend = new_text_default(center, &color_black, ALIGN_LEFT); + text_get_attributes(sozi_frame->legend, &sozi_frame->legend_attrs); +} + +static void +sozi_frame_update_sequence(SoziFrame *sozi_frame) +{ + char legend[32]; + int nb_char; + + /* + sequence managment + We use exemples of data_foreach_object of diagramdata.h + */ + if(!sozi_frame->sequence) { + /* + if we care to call sozi_frame_update_sequence + only when the object is placed on the sheet (in + sozi_frame_select for example), we have + (sozi_frame->sequence == 0). + This way, we can manage the sequence + increment correctly even upon object copy. + */ + int sequence = 0; + data_foreach_object(layer_get_parent_diagram(sozi_frame->object.parent_layer), count_sozi_objects, &sequence); + sozi_frame->sequence = sequence + 1; + } + else if(sozi_frame->old_sequence && + (sozi_frame->old_sequence != sozi_frame->sequence)) { + /* + here is the case where the sequence number has + been changed (in sozi_frame_set_props for example) + */ + struct sequence_pair seq_pair; + seq_pair.old = sozi_frame->old_sequence; + seq_pair.new = sozi_frame->sequence; + /* fprintf(stdout, "seq %d has changed to %d\n", sozi_frame->old_sequence, sozi_frame->sequence); */ + /* temporary revert to the old sequence number for avoiding twins */ + sozi_frame->sequence = sozi_frame->old_sequence; + data_foreach_object(layer_get_parent_diagram(sozi_frame->object.parent_layer), reorder_sozi_objects, &seq_pair); + /* restore the new sequence number */ + sozi_frame->sequence = seq_pair.new; + /* fprintf(stdout, "should be clean\n"); */ + } + sozi_frame->old_sequence = sozi_frame->sequence; + + /* update legend */ + nb_char = g_snprintf(legend, sizeof(legend), "#%d : %s", sozi_frame->sequence, sozi_frame->title); + if(sizeof(legend) < nb_char) + { + legend[sizeof(legend) - 1] = 0; + legend[sizeof(legend) - 2] = '.'; + legend[sizeof(legend) - 3] = '.'; + legend[sizeof(legend) - 4] = '.'; + } + text_set_string(sozi_frame->legend, legend); +} + +static void +sozi_frame_update_geometry(SoziFrame *sozi_frame) +{ + DiaObject *dia_object; + int i; + Point legend_pos; + Rectangle legend_bb; + + dia_object = &sozi_frame->object; + + dia_object->position = sozi_frame->center; + + dia_object->bounding_box.left = G_MAXFLOAT; + dia_object->bounding_box.top = G_MAXFLOAT; + dia_object->bounding_box.right = -G_MAXFLOAT; + dia_object->bounding_box.bottom = -G_MAXFLOAT; + + if(sozi_frame->angle < -180) { + sozi_frame->angle += 360.0; + } + if(180 < sozi_frame->angle) { + sozi_frame->angle -= 360; + } + sozi_frame->cos_angle = cos(sozi_frame->angle * M_PI / 180.0); + sozi_frame->sin_angle = sin(sozi_frame->angle * M_PI / 180.0); + + /* + * + * translate(center.x,center.y) . rotate(angle) . scale(width,height) . translate(-0.5,-0.5) + * + * m + * = + * | 1 0 x | . | cos(a) -sin(a) 0 | . | w 0 0 | . | 1 0 -0.5 | + * | 0 1 y | | sin(a) cos(a) 0 | | 0 h 0 | | 0 1 -0.5 | + * | 0 0 1 | | 0 0 1 | | 0 0 1 | | 0 0 1 | + * = + * | w*cos(a) -h*sin(a) x-0.5*w*cos(a)+0.5*h*sin(a) | + * | w*sin(a) h*cos(a) y-0.5*w*sin(a)-0.5*h*cos(a) | + * | 0 0 1 | + */ + sozi_frame->m[0] = sozi_frame->width * sozi_frame->cos_angle ; + sozi_frame->m[1] = -sozi_frame->height * sozi_frame->sin_angle ; + sozi_frame->m[2] = sozi_frame->center.x - 0.5 * sozi_frame->width * sozi_frame->cos_angle + 0.5 * sozi_frame->height * sozi_frame->sin_angle; + sozi_frame->m[3] = sozi_frame->width * sozi_frame->sin_angle ; + sozi_frame->m[4] = sozi_frame->height * sozi_frame->cos_angle ; + sozi_frame->m[5] = sozi_frame->center.y - 0.5 * sozi_frame->width * sozi_frame->sin_angle - 0.5 * sozi_frame->height * sozi_frame->cos_angle; + + for (i = 0; i < 4; i++) { + + sozi_frame->corners[i].x = sozi_frame->m[0] * default_handles[i].pos.x + sozi_frame->m[1] * default_handles[i].pos.y + sozi_frame->m[2]; + sozi_frame->corners[i].y = sozi_frame->m[3] * default_handles[i].pos.x + sozi_frame->m[4] * default_handles[i].pos.y + sozi_frame->m[5]; + + dia_object->handles[i]->pos = sozi_frame->corners[i]; + + if(sozi_frame->corners[i].x < dia_object->bounding_box.left) { + dia_object->bounding_box.left = sozi_frame->corners[i].x - sozi_frame_line_width; + } + if(dia_object->bounding_box.right < sozi_frame->corners[i].x) { + dia_object->bounding_box.right = sozi_frame->corners[i].x + sozi_frame_line_width; + } + if(sozi_frame->corners[i].y < dia_object->bounding_box.top) { + dia_object->bounding_box.top = sozi_frame->corners[i].y - sozi_frame_line_width; + } + if(dia_object->bounding_box.bottom < sozi_frame->corners[i].y) { + dia_object->bounding_box.bottom = sozi_frame->corners[i].y + sozi_frame_line_width; + } + } + + dia_object->connections[0]->last_pos = dia_object->connections[0]->pos; + dia_object->connections[0]->pos = sozi_frame->corners[0]; + + /* setup legend appearence */ + legend_pos = sozi_frame->corners[0]; + legend_pos.y += text_get_ascent(sozi_frame->legend); + text_set_position(sozi_frame->legend, &legend_pos); + + /* final bounding / enclosing box with legend */ + text_calc_boundingbox(sozi_frame->legend, &legend_bb); + rectangle_union(&dia_object->bounding_box, &legend_bb); + dia_object->enclosing_box = dia_object->bounding_box; +} + +/****************************************************************************** + * + *****************************************************************************/ +static DiaObject * +sozi_frame_create(Point *startpoint, + void *user_data, + Handle **handle1, + Handle **handle2) +{ + SoziFrame *sozi_frame; + + sozi_frame = g_new0(SoziFrame, 1); + + sozi_frame_init(sozi_frame, startpoint); + + sozi_frame_update_geometry(sozi_frame); + + *handle1 = NULL; + *handle2 = NULL; + + return &sozi_frame->object; +} + +/****************************************************************************** + * + *****************************************************************************/ +static DiaObject * +sozi_frame_load(ObjectNode obj_node, int version, DiaContext *ctx) +{ + return object_load_using_properties(&sozi_frame_type, obj_node, version, ctx); +} + +/****************************************************************************** + * + *****************************************************************************/ +static void +sozi_frame_save(SoziFrame *sozi_frame, ObjectNode obj_node, const char *filename) +{ + object_save_using_properties(&sozi_frame->object, obj_node, filename); +} + +/****************************************************************************** + * + *****************************************************************************/ +static void +sozi_frame_destroy(SoziFrame *sozi_frame) +{ + int i; + + text_destroy(sozi_frame->legend); + + if(sozi_frame->title != NULL) { + g_free(sozi_frame->title); + } + + object_unconnect_all(&sozi_frame->object); + + for (i = 0; i < 1; i++) { + if(sozi_frame->object.connections[i] != NULL) { + g_free(sozi_frame->object.connections[i]); + } + } + + for (i = 0; i < 4; i++) { + if(sozi_frame->object.handles[i] != NULL) { + g_free(sozi_frame->object.handles[i]); + } + } + + if (sozi_frame->object.connections) { + g_free(sozi_frame->object.connections); + sozi_frame->object.connections = NULL; + } + + if (sozi_frame->object.handles) { + g_free(sozi_frame->object.handles); + sozi_frame->object.handles = NULL; + } + + if (sozi_frame->object.meta) { + g_hash_table_destroy (sozi_frame->object.meta); + sozi_frame->object.meta = NULL; + } +} + +/****************************************************************************** + * + *****************************************************************************/ +static void +sozi_frame_draw_svg(SoziFrame *sozi_frame, DiaSvgRenderer *svg_renderer) +{ + static xmlNs *sozi_name_space = NULL; + static unsigned refid_cnt = 0; + xmlNodePtr root; + /* for managing sozi player implantation */ + xmlNodePtr node; + gchar * sozi_version; + gchar * sozi_js; + gchar * sozi_css; + xmlChar * escaped; + /* buffers for storing attributes */ + gchar * refid; + gchar * sequence; + gchar * x; + gchar * y; + gchar * width; + gchar * height; + gchar * transform; + gchar * style; + gchar dtostr_buf[6][G_ASCII_DTOSTR_BUF_SIZE]; +# define dtostr(n,d) g_ascii_formatd(dtostr_buf[(n)], sizeof(dtostr_buf[(n)]), "%g", (d)) + + root = xmlDocGetRootElement(svg_renderer->doc); + + /* check that the sozi namespace, scripts and style are present */ + + if (!find_sozi_elem(svg_renderer->doc, (const xmlChar*) "//script[ id='sozi-script']")) { + + get_sozi_player(&sozi_version, &sozi_js, &sozi_css); + + sozi_name_space = xmlNewNs(root, (const xmlChar *)"http://sozi.baierouge.fr", (const xmlChar *)"sozi"); + + node = xmlNewChild(root, NULL, (const xmlChar *)"script", NULL); + xmlSetProp(node, (const xmlChar *)"id", (const xmlChar *)"sozi-script"); + xmlSetProp(node, (const xmlChar *)"sozi:version", (const xmlChar *)sozi_version); + escaped = xmlEncodeEntitiesReentrant(svg_renderer->doc, (const xmlChar *)sozi_js); + xmlNodeSetContent(node, escaped); + xmlFree(escaped); + + node = xmlNewChild(root, NULL, (const xmlChar *)"style", NULL); + xmlSetProp(node, (const xmlChar *)"id", (const xmlChar *)"sozi-style"); + xmlSetProp(node, (const xmlChar *)"sozi:version", (const xmlChar *)sozi_version); + escaped = xmlEncodeEntitiesReentrant(svg_renderer->doc, (const xmlChar *)sozi_css); + xmlNodeSetContent(node, escaped); + xmlFree(escaped); + + g_free(sozi_version); + g_free(sozi_js); + g_free(sozi_css); + } + + assert(sozi_name_space != NULL); + + /* format attributes */ + refid = g_strdup_printf("sozi_frame_%d", refid_cnt++); + sequence = g_strdup_printf("%d", sozi_frame->sequence); + +#if 1 /* pure transformation */ + + x = g_strdup_printf("0"); + y = g_strdup_printf("0"); + width = g_strdup_printf("1"); + height = g_strdup_printf("1"); + transform = g_strdup_printf("matrix(%s,%s,%s,%s,%s,%s)", + /* svg has colomn-major order, we use row-major order */ + dtostr(0, sozi_frame->m[0] * svg_renderer->scale), + dtostr(1, sozi_frame->m[3] * svg_renderer->scale), + dtostr(2, sozi_frame->m[1] * svg_renderer->scale), + dtostr(3, sozi_frame->m[4] * svg_renderer->scale), + dtostr(4, sozi_frame->m[2] * svg_renderer->scale), + dtostr(5, sozi_frame->m[5] * svg_renderer->scale)); + /* FIXME : Scaling problem on stroke width : http://dev.w3.org/SVG/modules/vectoreffects/master/SVGVectorEffects.html */ + style = g_strdup_printf("fill:none;stroke:#000000;stroke-width:%s", + dtostr(0, 0.1 / svg_renderer->scale)); + +#elif 0 /* decompose transformation */ + + x = g_strdup_printf("0"); + y = g_strdup_printf("0"); + width = g_strdup_printf("1"); + height = g_strdup_printf("1"); + transform = g_strdup_printf("scale(%s,%s),translate(%s,%s),rotate(%s),scale(%s,%s),translate(-0.5,-0.5)", + dtostr(0, svg_renderer->scale), + dtostr(1, svg_renderer->scale), + dtostr(2, sozi_frame->center.x), + dtostr(3, sozi_frame->center.y), + dtostr(4, sozi_frame->angle), + dtostr(5, sozi_frame->width), + dtostr(6, sozi_frame->height)); + /* FIXME : Scaling problem on stroke width : http://dev.w3.org/SVG/modules/vectoreffects/master/SVGVectorEffects.html */ + style = g_strdup_printf("fill:none;stroke:#000000;stroke-width:%s", + dtostr(0, 0.1 / svg_renderer->scale)); + +#else /* no apply scale to transformation */ + + x = g_strdup_printf("%s", dtostr(0, sozi_frame->corners[0].x * svg_renderer->scale)); + y = g_strdup_printf("%s", dtostr(0, sozi_frame->corners[0].y * svg_renderer->scale)); + width = g_strdup_printf("%s", dtostr(0, sozi_frame->width * svg_renderer->scale)); + height = g_strdup_printf("%s", dtostr(0, sozi_frame->height * svg_renderer->scale)); + transform = g_strdup_printf("rotate(%s,%s,%s)", + dtostr(0, sozi_frame->angle), + dtostr(1, sozi_frame->corners[0].x * svg_renderer->scale), + dtostr(2, sozi_frame->corners[0].y * svg_renderer->scale)); + + style = g_strdup_printf("fill:none;stroke:#000000;stroke-width:0.1"); + +#endif + + /* add a "classic" frame */ + + node = xmlNewChild(svg_renderer->root, svg_renderer->svg_name_space, (const xmlChar *)"rect", NULL); + + xmlSetProp(node, (const xmlChar *)"id" , (xmlChar *)refid); + xmlSetProp(node, (const xmlChar *)"x" , (xmlChar *)x); + xmlSetProp(node, (const xmlChar *)"y" , (xmlChar *)y); + xmlSetProp(node, (const xmlChar *)"width" , (xmlChar *)width); + xmlSetProp(node, (const xmlChar *)"height" , (xmlChar *)height); + xmlSetProp(node, (const xmlChar *)"transform", (xmlChar *)transform); + xmlSetProp(node, (const xmlChar *)"style" , (xmlChar *)style); + + /* add a "custom" frame for sozi */ + + node = xmlNewChild(root, sozi_name_space, (const xmlChar *)"frame", NULL); + xmlSetProp(node, (const xmlChar *)"sozi:refid" , (const xmlChar *)refid); + xmlSetProp(node, (const xmlChar *)"sozi:sequence" , (const xmlChar *)sequence); + xmlSetProp(node, (const xmlChar *)"sozi:title" , (const xmlChar *)sozi_frame->title); + xmlSetProp(node, (const xmlChar *)"sozi:hide" , (const xmlChar *)((sozi_frame->hide)?"true":"false")); + xmlSetProp(node, (const xmlChar *)"sozi:clip" , (const xmlChar *)((sozi_frame->clip)?"true":"false")); + xmlSetProp(node, (const xmlChar *)"sozi:timeout-enable" , (const xmlChar *)((sozi_frame->timeout)?"true":"false")); + xmlSetProp(node, (const xmlChar *)"sozi:timeout-ms" , (const xmlChar *)"5000"); + xmlSetProp(node, (const xmlChar *)"sozi:transition-profile" , (const xmlChar *)"linear"); + xmlSetProp(node, (const xmlChar *)"sozi:transition-zoom-percent", (const xmlChar *)"0"); + xmlSetProp(node, (const xmlChar *)"sozi:transition-duration-ms" , (const xmlChar *)"1000"); + + + /* free resources */ + g_free(refid); + g_free(sequence); + g_free(x); + g_free(y); + g_free(width); + g_free(height); + g_free(transform); + g_free(style); + +# undef dtostr +} + +/****************************************************************************** + * + *****************************************************************************/ + +#define DIA_IS_INTERACTIVE_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DIA_TYPE_INTERACTIVE_RENDERER)) + +static void +sozi_frame_draw(SoziFrame *sozi_frame, DiaRenderer *renderer) +{ + + if (DIA_IS_SVG_RENDERER(renderer)) { + sozi_frame_draw_svg(sozi_frame, DIA_SVG_RENDERER (renderer)); + } + else if(DIA_GET_INTERACTIVE_RENDERER_INTERFACE (renderer) || + !sozi_frame->hide) { + DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer); + + renderer_ops->set_linewidth(renderer, sozi_frame_line_width); + renderer_ops->set_linecaps(renderer, LINECAPS_BUTT); + renderer_ops->set_linejoin(renderer, LINEJOIN_MITER); + renderer_ops->set_linestyle(renderer, LINESTYLE_SOLID); + + renderer_ops->draw_polygon(renderer, sozi_frame->corners, 4, &color_black); + + if(sozi_frame->legend_disp == TRUE) { + text_draw(sozi_frame->legend, renderer); + } + } +} + +/****************************************************************************** + * + *****************************************************************************/ + +static real +sozi_frame_distance_from(SoziFrame *sozi_frame, Point *point) +{ + return distance_polygon_point(sozi_frame->corners, 4, sozi_frame_line_width, point); +} + +/****************************************************************************** + * + *****************************************************************************/ +static void +sozi_frame_select(SoziFrame *sozi_frame, Point *clicked_point, + DiaRenderer *interactive_renderer) +{ + sozi_frame_update_sequence(sozi_frame); + sozi_frame_update_geometry(sozi_frame); +} + +/****************************************************************************** + * + *****************************************************************************/ + +static DiaObject * +sozi_frame_copy(SoziFrame *sozi_frame) +{ + SoziFrame *new_sozi_frame; + + new_sozi_frame = g_new0(SoziFrame, 1); + + sozi_frame_init(new_sozi_frame, &sozi_frame->center); + + new_sozi_frame->width = sozi_frame->width; + new_sozi_frame->height = sozi_frame->height; + new_sozi_frame->aspect = sozi_frame->aspect; + new_sozi_frame->angle = sozi_frame->angle; + + new_sozi_frame->hide = sozi_frame->hide; + new_sozi_frame->clip = sozi_frame->clip; + new_sozi_frame->timeout = sozi_frame->timeout; + + sozi_frame_update_geometry(new_sozi_frame); + + return &new_sozi_frame->object; +} + +/****************************************************************************** + * + *****************************************************************************/ + +static ObjectChange* +sozi_frame_move(SoziFrame *sozi_frame, Point *to) +{ + sozi_frame->center = *to; + + sozi_frame_update_geometry(sozi_frame); + + return NULL; +} + +/****************************************************************************** + * + *****************************************************************************/ + +static ObjectChange* +sozi_frame_move_handle(SoziFrame *sozi_frame, Handle *handle, + Point *to, ConnectionPoint *cp, + HandleMoveReason reason, ModifierKeys modifiers) +{ + if(reason == HANDLE_MOVE_USER) { + DiaObject * dia_object = &sozi_frame->object; + Point p2; + + int i; + for(i = 0; i < 4; i++) { + if(dia_object->handles[i] == handle) { + break; + } + } + assert(i < 4); + + /* p2 is the vector from the center to the new position of the handle */ + p2 = *to; + point_sub(&p2, &sozi_frame->center); + + if(modifiers & MODIFIER_SHIFT) { + /* p1 is the vector from the center to the old position of the handle */ + Point p1; + p1 = handle->pos; + point_sub(&p1, &sozi_frame->center); + + /* + p1 . p2 = ||p1|| ||p2|| cos(delta) + p1 ^ p2 = ||p1|| ||p2|| sin(delta) + tan(delta) = (p1 ^ p2) / p1 . p2 + */ + sozi_frame->angle += (180.0 / M_PI * atan2(p1.x * p2.y - p1.y * p2.x, p1.x * p2.x + p1.y * p2.y)); + } + else { + real ratio = sozi_frame->width / sozi_frame->height; + /* dot product with the unit lenght vector that hold the width axe */ + real width = 2 * fabs(p2.x * sozi_frame->cos_angle + p2.y * sozi_frame->sin_angle); + /* cross product with the unit lenght vector that hold the width axe */ + real height = 2 * fabs(p2.x * sozi_frame->sin_angle - p2.y * sozi_frame->cos_angle); + + if(sozi_frame->aspect == FREE_ASPECT) { + sozi_frame->width = width; + sozi_frame->height = height; + } + else { + sozi_frame->width = (((height * ratio) < width)?width:(height * ratio)); + sozi_frame->height = (((width / ratio) < height)?height:(width / ratio)); + } + } + + sozi_frame_update_geometry(sozi_frame); + } + + return NULL; +} + +/****************************************************************************** + * + *****************************************************************************/ + +static GtkWidget * +sozi_frame_get_properties(SoziFrame *sozi_frame, gboolean is_default) +{ + DiaObject * dia_object = &sozi_frame->object; + GtkWidget * widget = object_create_props_dialog(dia_object, is_default); + + /* the following code allow to set the range of the "frame sequence" property */ + /* see propdialogs.c for reference code with PropWidgetAssoc */ + PropDialog *dialog = prop_dialog_from_widget(widget); + guint i; + for (i = 0; i < dialog->prop_widgets->len; ++i) { + PropWidgetAssoc *pwa = &g_array_index(dialog->prop_widgets, + PropWidgetAssoc, i); + if(pwa) { + if (strcmp(pwa->prop->descr->name, "frame sequence") == 0) { + if(GTK_IS_SPIN_BUTTON(pwa->widget)) { + int count = 0; + data_foreach_object(layer_get_parent_diagram(dia_object->parent_layer), count_sozi_objects, &count); + + gtk_spin_button_set_range(GTK_SPIN_BUTTON(pwa->widget), 1, count); + } + } + } + } + + return widget; +} + +/****************************************************************************** + * + *****************************************************************************/ + +static ObjectChange * +sozi_frame_apply_properties_dialog(SoziFrame *sozi_frame, GtkWidget *widget) +{ + DiaObject * dia_object = &sozi_frame->object; + return object_apply_props_from_dialog(dia_object, widget); +} + +/****************************************************************************** + * + *****************************************************************************/ + +static PropEnumData prop_aspect_data[] = +{ + { N_("Free") , FREE_ASPECT }, + { N_("Fixed") , FIXED_ASPECT }, + { NULL, 0 } +}; + +static PropDescription sozi_frame_props[] = +{ + PROP_STD_NOTEBOOK_BEGIN, + + PROP_NOTEBOOK_PAGE("geometry",0,N_("Geometry")), + { "x" , PROP_TYPE_REAL , PROP_FLAG_VISIBLE, N_("Center x") , NULL, NULL }, + { "y" , PROP_TYPE_REAL , PROP_FLAG_VISIBLE, N_("Center y") , NULL, NULL }, + { "width" , PROP_TYPE_REAL , PROP_FLAG_VISIBLE, N_("Width") , NULL, NULL }, + { "height", PROP_TYPE_REAL , PROP_FLAG_VISIBLE, N_("Height") , NULL, NULL }, + { "aspect", PROP_TYPE_ENUM , PROP_FLAG_VISIBLE, N_("Aspect ratio"), NULL, prop_aspect_data }, + { "angle" , PROP_TYPE_INT , PROP_FLAG_VISIBLE, N_("Angle (deg)") , NULL, NULL }, + + PROP_NOTEBOOK_PAGE("sozi",0,N_("Sozi")), + { "frame sequence", PROP_TYPE_INT , PROP_FLAG_VISIBLE, N_("Frame sequence") , NULL, NULL }, + { "frame title" , PROP_TYPE_STRING, PROP_FLAG_VISIBLE, N_("Frame title") , NULL, NULL }, + { "frame hide" , PROP_TYPE_BOOL , PROP_FLAG_VISIBLE, N_("Frame hide") , NULL, NULL }, + { "frame clip" , PROP_TYPE_BOOL , PROP_FLAG_VISIBLE, N_("Frame clip") , NULL, NULL }, + { "frame timeout" , PROP_TYPE_INT , PROP_FLAG_VISIBLE, N_("Frame timeout (ms)") , NULL, NULL }, + + PROP_NOTEBOOK_PAGE("legend",0,N_("Legend")), + { "legend_disp", PROP_TYPE_BOOL, PROP_FLAG_VISIBLE, N_("Legend"), NULL, NULL}, + { "legend" , PROP_TYPE_TEXT, 0 , NULL , NULL, NULL}, + PROP_STD_TEXT_ALIGNMENT, + PROP_STD_TEXT_FONT, + PROP_STD_TEXT_HEIGHT, + PROP_STD_TEXT_COLOUR, + + PROP_STD_NOTEBOOK_END, + + PROP_DESC_END +}; + +static PropOffset sozi_frame_offsets[] = +{ + PROP_OFFSET_STD_NOTEBOOK_BEGIN, + + PROP_OFFSET_NOTEBOOK_PAGE("geometry"), + { "x" , PROP_TYPE_REAL , offsetof(SoziFrame, center.x) }, + { "y" , PROP_TYPE_REAL , offsetof(SoziFrame, center.y) }, + { "width" , PROP_TYPE_REAL , offsetof(SoziFrame, width) }, + { "height", PROP_TYPE_REAL , offsetof(SoziFrame, height) }, + { "aspect", PROP_TYPE_ENUM , offsetof(SoziFrame, aspect) }, + { "angle" , PROP_TYPE_INT , offsetof(SoziFrame, angle) }, + + PROP_OFFSET_NOTEBOOK_PAGE("sozi"), + { "frame sequence" , PROP_TYPE_INT , offsetof(SoziFrame, sequence) }, + { "frame title" , PROP_TYPE_STRING , offsetof(SoziFrame, title) }, + { "frame hide" , PROP_TYPE_BOOL , offsetof(SoziFrame, hide) }, + { "frame clip" , PROP_TYPE_BOOL , offsetof(SoziFrame, clip) }, + { "frame timeout" , PROP_TYPE_INT , offsetof(SoziFrame, timeout) }, + + PROP_OFFSET_NOTEBOOK_PAGE("legend"), + { "legend_disp" , PROP_TYPE_BOOL , offsetof(SoziFrame, legend_disp) }, + { "legend" , PROP_TYPE_TEXT , offsetof(SoziFrame, legend) }, + { "text_alignment" , PROP_TYPE_ENUM , offsetof(SoziFrame, legend_attrs.alignment) }, + { "text_font" , PROP_TYPE_FONT , offsetof(SoziFrame, legend_attrs.font) }, + { PROP_STDNAME_TEXT_HEIGHT, PROP_STDTYPE_TEXT_HEIGHT, offsetof(SoziFrame, legend_attrs.height) }, + { "text_colour" , PROP_TYPE_COLOUR , offsetof(SoziFrame, legend_attrs.color) }, + + PROP_OFFSET_STD_NOTEBOOK_END, + + { NULL, 0, 0 } +}; + +static PropDescription * +sozi_frame_describe_props(SoziFrame *sozi_frame) +{ + if (sozi_frame_props[0].quark == 0) + prop_desc_list_calculate_quarks(sozi_frame_props); + return sozi_frame_props; +} + +static void +sozi_frame_get_props(SoziFrame *sozi_frame, GPtrArray *props) +{ + text_get_attributes(sozi_frame->legend, &sozi_frame->legend_attrs); + object_get_props_from_offsets(&sozi_frame->object, sozi_frame_offsets, props); +} + +static void +sozi_frame_set_props(SoziFrame *sozi_frame, GPtrArray *props) +{ + object_set_props_from_offsets(&sozi_frame->object, sozi_frame_offsets, props); + apply_textattr_properties(props, sozi_frame->legend, "legend" , &sozi_frame->legend_attrs); + sozi_frame_update_sequence(sozi_frame); + sozi_frame_update_geometry(sozi_frame); +} diff --git a/objects/Misc/sozi.h b/objects/Misc/sozi.h new file mode 100644 index 0000000..b942215 --- /dev/null +++ b/objects/Misc/sozi.h @@ -0,0 +1,317 @@ +#ifndef __sozi_h__ +#define __sozi_h__ + +static const char own_sozi_version[] = +"12.12-13230054"; + +static const char own_sozi_js[] = +"function namespace(b,d,a){var c=b;d.split(\".\").forEach(function(e){if(typeof c[e" +"]===\"undefined\"){c[e]={}}c=c[e]});a(c,b)}namespace(this,\"sozi.events\",function(b" +"){var a={};b.listen=function(c,d){if(!a.hasOwnProperty(c)){a[c]=[]}a[c].push(d)}" +";b.fire=function(d){var c=Array.prototype.slice.call(arguments,1);if(a.hasOwnPro" +"perty(d)){a[d].forEach(function(e){e.apply(null,c)})}}});namespace(this,\"sozi.fr" +"amenumber\",function(b,d){var g=d.document;var e;var k,i;var f;var c=\"http://www." +"w3.org/2000/svg\";function h(){var m=k.getBBox(),n=Math.max(m.width,m.height)*0.7" +"5,l=n*1.25;f.setAttribute(\"r\",n);e.setAttribute(\"transform\",\"translate(\"+l+\",\"+l" +"+\")\")}function a(){e=g.createElementNS(c,\"g\");k=g.createElementNS(c,\"text\");f=g." +"createElementNS(c,\"circle\");e.setAttribute(\"id\",\"sozi-framenumber\");f.setAttribu" +"te(\"cx\",0);f.setAttribute(\"cy\",0);e.appendChild(f);i=g.createTextNode(sozi.locat" +"ion.getFrameIndex()+1);k.setAttribute(\"text-anchor\",\"middle\");k.setAttribute(\"do" +"minant-baseline\",\"central\");k.setAttribute(\"x\",0);k.setAttribute(\"y\",0);k.append" +"Child(i);e.appendChild(k);g.documentElement.appendChild(e);h()}function j(l){i.n" +"odeValue=l+1}sozi.events.listen(\"sozi.display.ready\",a);sozi.events.listen(\"sozi" +".player.framechange\",j)});namespace(this,\"sozi.framelist\",function(u,k){var o=k." +"document;var c=5;var i;var p;var j=0;var h;var s;var b;var v;var w;var t;var e=3" +"00;var f=\"decelerate\";var a=\"http://www.w3.org/2000/svg\";function n(z){var x=z.r" +"elatedTarget,y=o.documentElement;while(x&&x!==i&&x!==y){x=x.parentNode}if(x!==i)" +"{u.hide();sozi.player.restart();z.stopPropagation()}}function r(y){var x=p.getCT" +"M().f;if(x<=-k.innerHeight/2){x+=k.innerHeight/2}else{if(x<0){x=0}}p.setAttribut" +"e(\"transform\",\"translate(0,\"+x+\")\");y.stopPropagation()}function d(y){var x=p.ge" +"tCTM().f;if(x+j>=k.innerHeight*3/2){x-=k.innerHeight/2}else{if(x+j>k.innerHeight" +"+2*c){x=k.innerHeight-j-4*c}}p.setAttribute(\"transform\",\"translate(0,\"+x+\")\");y." +"stopPropagation()}function g(x){return function(y){sozi.player.previewFrame(x);y" +".stopPropagation()}}function l(x){x.stopPropagation()}function q(){i=o.createEle" +"mentNS(a,\"g\");i.setAttribute(\"id\",\"sozi-toc\");o.documentElement.appendChild(i);p" +"=o.createElementNS(a,\"g\");i.appendChild(p);var z=o.createElementNS(a,\"rect\");z.s" +"etAttribute(\"id\",\"sozi-toc-background\");z.setAttribute(\"x\",c);z.setAttribute(\"y\"" +",c);z.setAttribute(\"rx\",c);z.setAttribute(\"ry\",c);z.addEventListener(\"click\",l,f" +"alse);z.addEventListener(\"mousedown\",l,false);z.addEventListener(\"mouseout\",n,fa" +"lse);p.appendChild(z);var B=0;var y=sozi.location.getFrameIndex();sozi.document." +"frames.forEach(function(E,F){var D=o.createElementNS(a,\"text\");D.appendChild(o.c" +"reateTextNode(E.title));p.appendChild(D);if(F===y){D.setAttribute(\"class\",\"sozi-" +"toc-current\")}var C=D.getBBox().width;j+=D.getBBox().height;if(C>B){B=C}D.setAtt" +"ribute(\"x\",2*c);D.setAttribute(\"y\",j+c);D.addEventListener(\"click\",g(F),false);D" +".addEventListener(\"mousedown\",l,false)});var x=o.createElementNS(a,\"path\");x.set" +"Attribute(\"class\",\"sozi-toc-arrow\");x.setAttribute(\"d\",\"M\"+(B+3*c)+\",\"+(5*c)+\" l" +"\"+(4*c)+\",0 l-\"+(2*c)+\",-\"+(3*c)+\" z\");x.addEventListener(\"click\",r,false);x.add" +"EventListener(\"mousedown\",l,false);i.appendChild(x);var A=o.createElementNS(a,\"p" +"ath\");A.setAttribute(\"class\",\"sozi-toc-arrow\");A.setAttribute(\"d\",\"M\"+(B+3*c)+\"," +"\"+(7*c)+\" l\"+(4*c)+\",0 l-\"+(2*c)+\",\"+(3*c)+\" z\");A.addEventListener(\"click\",d,fa" +"lse);A.addEventListener(\"mousedown\",l,false);i.appendChild(A);z.setAttribute(\"wi" +"dth\",B+7*c);z.setAttribute(\"height\",j+2*c);h=-B-9*c;s=0;w=v=h;i.setAttribute(\"tr" +"ansform\",\"translate(\"+h+\",0)\");t=sozi.animation.Animator.instance().augment({onS" +"tep:function(C){var E=sozi.animation.profiles[f](C),D=1-E;w=v*E+b*D;i.setAttribu" +"te(\"transform\",\"translate(\"+w+\",0)\")}})}function m(x){var z=Array.prototype.slic" +"e.call(o.getElementsByClassName(\"sozi-toc-current\"));z.forEach(function(A){A.rem" +"oveAttribute(\"class\")});var y=p.getElementsByTagName(\"text\");y[x].setAttribute(\"" +"class\",\"sozi-toc-current\")}u.show=function(){b=w;v=s;t.start(e)};u.hide=function" +"(){b=w;v=h;t.start(e)};u.isVisible=function(){return v===s};sozi.events.listen(\"" +"sozi.player.ready\",q);sozi.events.listen(\"sozi.player.cleanup\",u.hide);sozi.even" +"ts.listen(\"sozi.player.framechange\",m)});namespace(this,\"sozi.proto\",function(a)" +"{a.Object={installConstructors:function(){function b(){}b.prototype=this;this.in" +"stance=function(){var c=new b();c.construct.apply(c,arguments);return c};this.su" +"btype=function(d){var c=new b();c.augment(d);c.installConstructors();return c}}," +"construct:function(){},augment:function(c){for(var b in c){if(c.hasOwnProperty(b" +")){this[b]=c[b]}}return this},bind:function(c){var b=this;return function(){retu" +"rn c.apply(b,arguments)}}};a.Object.installConstructors()});namespace(this,\"sozi" +".animation\",function(d,g){var h=g.mozRequestAnimationFrame||g.webkitRequestAnima" +"tionFrame||g.msRequestAnimationFrame||g.oRequestAnimationFrame;var i=40;var b;va" +"r j=[];function e(k){if(j.length>0){if(h){h(e)}j.forEach(function(l){l.step(k)})" +"}else{if(!h){g.clearInterval(b)}}}function c(){if(h){h(e)}else{b=g.setInterval(f" +"unction(){e(Date.now())},i)}}function a(k){j.push(k);if(j.length===1){c()}}funct" +"ion f(k){j.splice(j.indexOf(k),1)}d.Animator=sozi.proto.Object.subtype({construc" +"t:function(){this.durationMs=0;this.data=null;this.initialTime=0;this.started=fa" +"lse},start:function(k,l){this.durationMs=k;this.data=l;this.initialTime=Date.now" +"();this.onStep(0);if(!this.started){this.started=true;a(this)}},stop:function(){" +"if(this.started){f(this);this.started=false}},step:function(l){var k=l-this.init" +"ialTime;if(k>=this.durationMs){this.stop();this.onStep(1);this.onDone()}else{thi" +"s.onStep(k/this.durationMs)}},onStep:function(k){},onDone:function(){}});d.profi" +"les={linear:function(k){return k},accelerate:function(k){return Math.pow(k,3)},\"" +"strong-accelerate\":function(k){return Math.pow(k,5)},decelerate:function(k){retu" +"rn 1-Math.pow(1-k,3)},\"strong-decelerate\":function(k){return 1-Math.pow(1-k,5)}," +"\"accelerate-decelerate\":function(k){var l=k<=0.5?k:1-k,m=Math.pow(2*l,3)/2;retur" +"n k<=0.5?m:1-m},\"strong-accelerate-decelerate\":function(k){var l=k<=0.5?k:1-k,m=" +"Math.pow(2*l,5)/2;return k<=0.5?m:1-m},\"decelerate-accelerate\":function(k){var l" +"=k<=0.5?k:1-k,m=(1-Math.pow(1-2*l,2))/2;return k<=0.5?m:1-m},\"strong-decelerate-" +"accelerate\":function(k){var l=k<=0.5?k:1-k,m=(1-Math.pow(1-2*l,3))/2;return k<=0" +".5?m:1-m}}});namespace(this,\"sozi.display\",function(c,g){var f=\"http://www.w3.or" +"g/2000/svg\";var b=\"http://www.w3.org/1999/xlink\";var i=g.document;var k;var h;va" +"r j;c.viewPorts={};var e;c.CameraState=sozi.proto.Object.subtype({construct:func" +"tion(){this.cx=this.cy=0;this.width=this.height=1;this.angle=0;this.clipped=true" +";this.transitionZoomPercent=0;this.transitionProfile=sozi.animation.profiles.lin" +"ear},setCenter:function(l,m){this.cx=l;this.cy=m;return this},setSize:function(m" +",l){this.width=m;this.height=l;return this},setClipped:function(l){this.clipped=" +"l;return this},setAngle:function(l){this.angle=(l+180)%360-180;return this},setR" +"awAngle:function(l){this.angle=l;return this},setTransitionZoomPercent:function(" +"l){this.transitionZoomPercent=l;return this},setTransitionProfile:function(l){th" +"is.transitionProfile=l;return this},setAtElement:function(p){var s,o,t,m;if(p.no" +"deName===\"rect\"){s=p.x.baseVal.value;o=p.y.baseVal.value;t=p.width.baseVal.value" +";m=p.height.baseVal.value}else{var q=p.getBBox();s=q.x;o=q.y;t=q.width;m=q.heigh" +"t}var n=i.documentElement.createSVGPoint();n.x=s+t/2;n.y=o+m/2;var r=p.getCTM();" +"n=n.matrixTransform(r);var l=Math.sqrt(r.a*r.a+r.b*r.b);return this.setCenter(n." +"x,n.y).setSize(t*l,m*l).setAngle(Math.atan2(r.b,r.a)*180/Math.PI)},setAtState:fu" +"nction(l){return this.setCenter(l.cx,l.cy).setSize(l.width,l.height).setAngle(l." +"angle).setClipped(l.clipped).setTransitionZoomPercent(l.transitionZoomPercent).s" +"etTransitionProfile(l.transitionProfile)},interpolatableAttributes:[\"cx\",\"cy\",\"w" +"idth\",\"height\",\"angle\"],interpolate:function(m,q,p){var o=1-p;for(var n=0;n=this.x&&l=this.y&&m0&&A<=1)?A:y}C.k=w/C.ts/C.ts}" +"return C}d.jumpToFrame=function(r){d.stop();sozi.events.fire(\"sozi.player.cleanu" +"p\");g=r;m=r;o.showFrame(sozi.document.frames[r]);sozi.events.fire(\"sozi.player.f" +"ramechange\",r)};function f(r,u,x,s){var t={};for(var w in r){t[w]={initialState:" +"sozi.display.CameraState.instance(),finalState:sozi.display.CameraState.instance" +"()};t[w].profile=s||u[w].transitionProfile;t[w].initialState.setAtState(r[w]);if" +"(u.hasOwnProperty(w)){t[w].finalState.setAtState(u[w])}else{t[w].finalState.setA" +"tState(r[w])}if(t[w].finalState.angle-t[w].initialState.angle>180){t[w].finalSta" +"te.setRawAngle(t[w].finalState.angle-360)}else{if(t[w].finalState.angle-t[w].ini" +"tialState.angle<-180){t[w].initialState.setRawAngle(t[w].initialState.angle-360)" +"}}var v=x||u[w].transitionZoomPercent;if(v&&u.hasOwnProperty(w)){t[w].zoomWidth=" +"b(v,r[w].width,u[w].width);t[w].zoomHeight=b(v,r[w].height,u[w].height)}}return " +"t}d.previewFrame=function(r){m=r;c.start(e,f(o.cameras,sozi.document.frames[r].s" +"tates,q,sozi.animation.profiles[k]));sozi.events.fire(\"sozi.player.framechange\"," +"r)};d.moveToFrame=function(s){if(p){h.clearTimeout(l);p=false}var r,u,t;if(s===(" +"m+1)%sozi.document.frames.length){r=sozi.document.frames[s].transitionDurationMs" +";u=undefined;t=undefined}else{r=e;u=q;t=sozi.animation.profiles[k]}sozi.events.f" +"ire(\"sozi.player.cleanup\");n=true;m=s;c.start(r,f(o.cameras,sozi.document.frames" +"[s].states,u,t));sozi.events.fire(\"sozi.player.framechange\",s)};d.moveToFirst=fu" +"nction(){d.moveToFrame(0)};d.jumpToPrevious=function(){var r=m;if(!c.started||g<" +"=m){r-=1}if(r>=0){d.jumpToFrame(r)}};d.moveToPrevious=function(){for(var r=m-1;r" +">=0;r-=1){var s=sozi.document.frames[r];if(!s.timeoutEnable||s.timeoutMs!==0){d." +"moveToFrame(r);break}}};d.jumpToNext=function(){var r=m;if(!c.started||g>=m){r+=" +"1}if(r0?s:1/s,A,C)}function w(A){t.stop();u.viewPorts.player.rotate(A>0?x:-x)}functi" +"on r(){if(sozi.framelist.isVisible()){sozi.framelist.hide();t.restart()}else{t.s" +"top();sozi.framelist.show()}}function d(A){return u.viewPorts.player.contains(A." +"clientX,A.clientY)}function f(A){if(!d(A)){return}if(A.button===n){m.documentEle" +"ment.addEventListener(\"mousemove\",p,false);q=false;i=A.clientX;h=A.clientY}else{" +"if(A.button===v){r()}}A.stopPropagation();A.preventDefault()}function p(A){if(!d" +"(A)){return}t.stop();q=true;sozi.events.fire(\"sozi.player.cleanup\");u.viewPorts." +"player.drag(A.clientX-i,A.clientY-h);i=A.clientX;h=A.clientY;A.stopPropagation()" +"}function c(A){if(!d(A)){return}if(A.button===n){m.documentElement.removeEventLi" +"stener(\"mousemove\",p,false)}A.stopPropagation();A.preventDefault()}function o(A)" +"{if(!d(A)){return}t.moveToPrevious();A.stopPropagation();A.preventDefault()}func" +"tion e(A){if(!d(A)){return}if(!q&&A.button!==v){t.moveToNext()}A.stopPropagation" +"();A.preventDefault()}function j(A){if(!d(A)){return}if(!A){A=g.event}var B=0;if" +"(A.wheelDelta){B=A.wheelDelta}else{if(A.detail){B=-A.detail}}if(B!==0){if(A.shif" +"tKey){w(B)}else{a(B,A.clientX,A.clientY)}}A.stopPropagation();A.preventDefault()" +"}function l(A){if(A.altKey||A.ctrlKey||A.metaKey){return}switch(A.charCode||A.wh" +"ich){case 43:a(1,g.innerWidth/2,g.innerHeight/2);break;case 45:a(-1,g.innerWidth" +"/2,g.innerHeight/2);break;case 61:t.moveToCurrent();break;case 70:case 102:t.sho" +"wAll();break;case 84:case 116:r();break;case 82:w(-1);break;case 114:w(1);break;" +"default:return}A.stopPropagation();A.preventDefault()}function b(A){if(A.altKey|" +"|A.ctrlKey||A.metaKey){return}switch(A.keyCode){case 36:t.moveToFirst();break;ca" +"se 35:t.moveToLast();break;case 38:t.jumpToPrevious();break;case 33:case 37:t.mo" +"veToPrevious();break;case 40:t.jumpToNext();break;case 34:case 39:case 13:case 3" +"2:t.moveToNext();break;default:return}A.stopPropagation()}function y(A){A.stopPr" +"opagation()}function k(){var B=m.getElementsByTagName(\"a\");for(var C=0;C=sozi.document.frames.length){return s" +"ozi.document.frames.length-1}else{return g}}};function f(){var g=a.getFrameIndex" +"();if(!c){sozi.player.moveToFrame(g)}c=false}function d(g){c=true;e.location.has" +"h=\"#\"+(g+1)}function b(){sozi.events.listen(\"sozi.player.framechange\",d)}e.addEv" +"entListener(\"hashchange\",f,false);e.addEventListener(\"load\",b,false)});"; + +static const char own_sozi_css[] = +"#sozi-toc text{fill:#eff;font-family:Verdana,sans-serif;font-size:12pt;}#sozi-to" +"c text:hover{fill:#0cf;cursor:pointer;}#sozi-toc text.sozi-toc-current{fill:#fa4" +";}#sozi-toc-background{stroke:#222;stroke-opacity:.1;stroke-width:10;fill:#222;f" +"ill-opacity:.9;}.sozi-toc-arrow{fill:#eff;fill-opacity:.75;stroke:none;}.sozi-to" +"c-arrow:hover{fill:#0cf;}#sozi-framenumber circle{stroke:#222;stroke-opacity:.1;" +"stroke-width:4;fill:#222;fill-opacity:.9;}#sozi-framenumber text{fill:#eff;font-" +"family:Verdana,sans-serif;font-size:12pt;}"; + +static const char own_sozi_extras_addvideo_js[] = +"this.addEventListener(\"load\",function(){var h=\"http://www.w3.org/2000/svg\",l=\"ht" +"tp://sozi.baierouge.fr\",s=\"http://www.w3.org/1999/xhtml\",m=this,o=m.document,q=[" +"],r,e,d,c,p,a,g,f,b;function n(i){i.stopPropagation()}function t(i,j,k){sozi.eve" +"nts.listen(\"sozi.player.framechange\",function(u){var v=sozi.document.frames[u].i" +"d;if(v===j){i.play()}else{if(v===k){i.pause()}}})}q.push(o.getElementsByTagNameN" +"S(l,\"video\"));q.push(o.getElementsByTagNameNS(l,\"audio\"));r=[];for(c=0;c <_description>New-style group object, for testing + + <_description>Sozi frame, for zooming ui + -- 1.7.12.1