forgot the attachement on my previous mail.
Beware: it's proof-of-concept-code at the moment. The way to go appears to be
moving standard objects to libdia first and than provided an extended
"To Dia Render"-Api, e.g including Rectangles with an optional corner
radius, etc.
Have Fun,
Hans
/* Dia -- an diagram creation/manipulation program
* Copyright (C) 1998 Alexander Larsson
*
* diaimport.c -- A renderer which renders towards Dia. It creates
* new "Standard" objects in a given diagram
*
* Copyright (C) 2001, Hans Breuer.
*
* 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.
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <glib.h>
#include "config.h"
#include "intl.h"
#include "message.h"
#include "geometry.h"
#include "render.h"
#include "filter.h"
#include "../app/diagram.h"
#include "object.h"
#include "element.h"
#include "attributes.h"
#include "properties.h"
#include "plug-ins.h"
/* --- the renderer --- */
#define MY_RENDERER_NAME "DiaImport"
typedef struct _MyRenderer MyRenderer;
struct _MyRenderer {
Renderer renderer;
/* Diagram to render to */
Diagram *dia;
Layer *layer;
/* The Standard Object Types */
ObjectType *tline;
ObjectType *tpolyline;
ObjectType *tpolygon;
ObjectType *tbox;
ObjectType *tarc;
ObjectType *tellipse;
ObjectType *tbezier;
ObjectType *tstring;
ObjectType *timage;
/* Standard Properties */
Property *elemprops;
Property *objprops;
Property *stdlineprops;
Property *stdfillprops;
/* Additional Properties */
Property *lineprops;
/* current settings from set functions */
real linewidth;
LineCaps linecaps;
LineJoin linejoin;
LineStyle linestyle;
real dashlength;
FillStyle fillstyle;
Font* font;
};
/* include function declares and render object "vtable" */
#include "../renderer.inc"
#define DIAG_NOTE my_log
void
my_log(MyRenderer* renderer, char* format, ...)
{
gchar *string;
va_list args;
g_return_if_fail (format != NULL);
va_start (args, format);
string = g_strdup_vprintf (format, args);
va_end (args);
g_print(string);
g_free(string);
}
/*
* Some Helpers
*/
static void
set_object_common_props (MyRenderer *renderer, Object* obj,
Point *lt, Point *br)
{
/* FIXME: shouldn't the object calculate this ? */
/* "obj_pos" */
PROP_VALUE_POINT (renderer->objprops[0]) = *lt;
/* "obj_bb" */
PROP_VALUE_RECT (renderer->objprops[1]).top = lt->y;
PROP_VALUE_RECT (renderer->objprops[1]).left = lt->x;
PROP_VALUE_RECT (renderer->objprops[1]).bottom = br->y;
PROP_VALUE_RECT (renderer->objprops[1]).right = br->x;
obj->ops->set_props(obj, renderer->stdlineprops, 2);
}
static void
set_element_common_props (MyRenderer *renderer, Object* obj,
Point* lt, Point* br)
{
/* includes object common */
set_object_common_props (renderer, obj, lt, br);
/* "elem_corner" */
PROP_VALUE_POINT (renderer->elemprops[0]) = *lt;
/* "elem_width" */
PROP_VALUE_REAL (renderer->elemprops[1]) = br->x - lt->x;
/* "elem_height" */
PROP_VALUE_REAL (renderer->elemprops[2]) = br->y - lt->y;
obj->ops->set_props(obj, renderer->elemprops, 3);
}
static void
set_line_common_props (MyRenderer *renderer, Object* obj,
Color *colour)
{
PROP_VALUE_COLOUR (renderer->stdlineprops[0]) = *colour;
PROP_VALUE_REAL (renderer->stdlineprops[1]) = renderer->linewidth;
PROP_VALUE_LINESTYLE (renderer->stdlineprops[2]).style = renderer->linestyle;
PROP_VALUE_LINESTYLE (renderer->stdlineprops[2]).dash = renderer->dashlength;
/* this requires to set line before fill props */
PROP_VALUE_BOOL (renderer->stdlineprops[3]) = FALSE;
obj->ops->set_props(obj, renderer->stdlineprops, 4);
}
static void
set_fill_common_props (MyRenderer *renderer, Object* obj,
Color *colour)
{
/* don't draw lines (but with the right colour) */
double linewidth = renderer->linewidth;
renderer->linewidth = 0.0;
set_line_common_props (renderer, obj, colour);
renderer->linewidth = linewidth;
PROP_VALUE_COLOUR (renderer->stdfillprops[0]) = *colour;
PROP_VALUE_BOOL (renderer->stdfillprops[1]) = TRUE;
obj->ops->set_props(obj, renderer->stdfillprops, 2);
}
/*
* Renderer API
*/
static void
begin_render(MyRenderer *renderer, DiagramData *data)
{
real height;
DIAG_NOTE(renderer, "begin_render\n");
attributes_get_default_font (&(renderer->font), &height);
renderer->objprops = g_new (Property, 2);
renderer->objprops[0].name = "obj_pos";
renderer->objprops[0].type = PROP_TYPE_POINT;
renderer->objprops[1].name = "obj_bb";
renderer->objprops[1].type = PROP_TYPE_RECT;
renderer->elemprops = g_new (Property, 3);
renderer->elemprops[0].name = "elem_corner";
renderer->elemprops[0].type = PROP_TYPE_POINT;
renderer->elemprops[1].name = "elem_width";
renderer->elemprops[1].type = PROP_TYPE_REAL;
renderer->elemprops[2].name = "elem_height";
renderer->elemprops[2].type = PROP_TYPE_REAL;
renderer->stdlineprops = g_new (Property, 4);
renderer->stdlineprops[0].name = "line_colour";
renderer->stdlineprops[0].type = PROP_TYPE_COLOUR;
renderer->stdlineprops[1].name = "line_width";
renderer->stdlineprops[1].type = PROP_TYPE_REAL;
renderer->stdlineprops[2].name = "line_style";
renderer->stdlineprops[2].type = PROP_TYPE_LINESTYLE;
attributes_get_default_line_style (
&(PROP_VALUE_LINESTYLE (renderer->stdlineprops[2]).style),
&(PROP_VALUE_LINESTYLE (renderer->stdlineprops[2]).dash));
renderer->stdlineprops[3].name = "show_background";
renderer->stdlineprops[3].type = PROP_TYPE_BOOL;
renderer->stdfillprops = g_new (Property, 2);
renderer->stdfillprops[0].name = "fill_colour";
renderer->stdfillprops[0].type = PROP_TYPE_COLOUR;
renderer->stdfillprops[1].name = "show_background";
renderer->stdfillprops[1].type = PROP_TYPE_BOOL;
renderer->tline = object_get_type("Standard - Line");
renderer->lineprops = g_new (Property, 2);
renderer->lineprops[0].name = "start_point";
renderer->lineprops[0].type = PROP_TYPE_POINT;
renderer->lineprops[1].name = "end_point";
renderer->lineprops[1].type = PROP_TYPE_POINT;
renderer->tbox = object_get_type("Standard - Box");
renderer->tarc = object_get_type ("Standard - Arc");
renderer->tellipse = object_get_type ("Standard - Ellipse");
}
static void
end_render(MyRenderer *renderer)
{
DIAG_NOTE(renderer, "end_render\n");
prop_list_free (renderer->objprops, 2);
g_free (renderer->objprops);
prop_list_free (renderer->elemprops, 3);
g_free (renderer->elemprops);
prop_list_free (renderer->stdlineprops, 3);
g_free (renderer->stdlineprops);
prop_list_free (renderer->stdfillprops, 2);
g_free (renderer->stdfillprops);
prop_list_free (renderer->lineprops, 2);
g_free (renderer->lineprops);
}
static void
set_linewidth(MyRenderer *renderer, real linewidth)
{
renderer->linewidth = linewidth;
}
static void
set_linecaps(MyRenderer *renderer, LineCaps mode)
{
switch(mode) {
case LINECAPS_BUTT:
break;
case LINECAPS_ROUND:
break;
case LINECAPS_PROJECTING:
break;
default:
message_error(MY_RENDERER_NAME ": Unsupported fill mode specified!\n");
}
renderer->linecaps = mode;
}
static void
set_linejoin(MyRenderer *renderer, LineJoin mode)
{
switch(mode) {
case LINEJOIN_MITER:
break;
case LINEJOIN_ROUND:
break;
case LINEJOIN_BEVEL:
break;
default:
message_error(MY_RENDERER_NAME ": Unsupported fill mode specified!\n");
}
renderer->linejoin = mode;
}
static void
set_linestyle(MyRenderer *renderer, LineStyle mode)
{
DIAG_NOTE(renderer, "set_linestyle %d\n", mode);
/* line type */
switch (mode) {
case LINESTYLE_SOLID:
break;
case LINESTYLE_DASHED:
break;
case LINESTYLE_DASH_DOT:
break;
case LINESTYLE_DASH_DOT_DOT:
break;
case LINESTYLE_DOTTED:
break;
default:
message_error(MY_RENDERER_NAME ": Unsupported fill mode specified!\n");
}
renderer->linestyle = mode;
}
static void
set_dashlength(MyRenderer *renderer, real length)
{
renderer->dashlength = length;
}
static void
set_fillstyle(MyRenderer *renderer, FillStyle mode)
{
switch(mode) {
case FILLSTYLE_SOLID:
break;
default:
message_error(MY_RENDERER_NAME ": Unsupported fill mode specified!\n");
}
renderer->fillstyle = mode;
}
static void
set_font(MyRenderer *renderer, Font *font, real height)
{
DIAG_NOTE(renderer, "set_font\n %f", height);
renderer->font = font; //FIXME: ???
}
static void
draw_line(MyRenderer *renderer,
Point *start, Point *end,
Color *line_colour)
{
Object *obj;
Handle *h1, *h2;
Point center;
DIAG_NOTE(renderer, "draw_line %f,%f -> %f, %f\n",
start->x, start->y, end->x, end->y);
obj = renderer->tline->ops->create (start,
renderer->tline->default_user_data,
&h1, &h2);
set_object_common_props (renderer, obj, start, end); /* ??? */
set_line_common_props (renderer, obj, line_colour);
PROP_VALUE_POINT (renderer->lineprops[0]) = *start;
PROP_VALUE_POINT (renderer->lineprops[1]) = *end;
obj->ops->set_props(obj, renderer->lineprops, 2);
layer_add_object(renderer->layer, obj);
}
static void
draw_polyline(MyRenderer *renderer,
Point *points, int num_points,
Color *line_colour)
{
DIAG_NOTE(renderer, "draw_polyline n:%d %f,%f ...\n",
num_points, points->x, points->y);
}
static void
draw_polygon(MyRenderer *renderer,
Point *points, int num_points,
Color *line_colour)
{
DIAG_NOTE(renderer, "draw_polygon n:%d %f,%f ...\n",
num_points, points->x, points->y);
}
static void
fill_polygon(MyRenderer *renderer,
Point *points, int num_points,
Color *colour)
{
DIAG_NOTE(renderer, "fill_polygon n:%d %f,%f ...\n",
num_points, points->x, points->y);
}
static void
draw_rect(MyRenderer *renderer,
Point *ul_corner, Point *lr_corner,
Color *colour)
{
Object *obj;
Handle *h1, *h2;
DIAG_NOTE(renderer, "draw_rect %f,%f -> %f,%f\n",
ul_corner->x, ul_corner->y, lr_corner->x, lr_corner->y);
obj = renderer->tbox->ops->create (ul_corner,
renderer->tbox->default_user_data,
&h1, &h2);
set_element_common_props (renderer, obj, ul_corner, lr_corner);
set_line_common_props (renderer, obj, colour);
layer_add_object(renderer->layer, obj);
}
static void
fill_rect(MyRenderer *renderer,
Point *ul_corner, Point *lr_corner,
Color *colour)
{
Object *obj;
Handle *h1, *h2;
DIAG_NOTE(renderer, "fill_rect %f,%f -> %f,%f\n",
ul_corner->x, ul_corner->y, lr_corner->x, lr_corner->y);
obj = renderer->tbox->ops->create (ul_corner,
renderer->tbox->default_user_data,
&h1, &h2);
set_element_common_props (renderer, obj, ul_corner, lr_corner);
set_fill_common_props (renderer, obj, colour);
layer_add_object(renderer->layer, obj);
}
static void
draw_arc(MyRenderer *renderer,
Point *center,
real width, real height,
real angle1, real angle2,
Color *colour)
{
Object *obj;
Handle *h1, *h2;
Point lt, br;
DIAG_NOTE(renderer, "draw_arc %fx%f <%f,<%f @%f,%f\n",
width, height, angle1, angle2, center->x, center->y);
lt.x = center->x - width / 2;
lt.y = center->y - height / 2;
br.x = center->x + width / 2;
br.y = center->y + height / 2;
obj = renderer->tarc->ops->create (<,
renderer->tbox->default_user_data,
&h1, &h2);
set_object_common_props (renderer, obj, <, &br);
set_line_common_props (renderer, obj, colour);
/* FIXME: arc props don't define angles */
layer_add_object(renderer->layer, obj);
}
static void
fill_arc(MyRenderer *renderer,
Point *center,
real width, real height,
real angle1, real angle2,
Color *colour)
{
Object *obj;
Handle *h1, *h2;
Point lt, br;
DIAG_NOTE(renderer, "fill_arc %fx%f <%f,<%f @%f,%f\n",
width, height, angle1, angle2, center->x, center->y);
lt.x = center->x - width / 2;
lt.y = center->y - height / 2;
br.x = center->x + width / 2;
br.y = center->y + height / 2;
obj = renderer->tarc->ops->create (<,
renderer->tbox->default_user_data,
&h1, &h2);
set_object_common_props (renderer, obj, <, &br);
set_fill_common_props (renderer, obj, colour);
layer_add_object(renderer->layer, obj);
}
static void
draw_ellipse(MyRenderer *renderer,
Point *center,
real width, real height,
Color *colour)
{
Object *obj;
Handle *h1, *h2;
Point lt, br;
DIAG_NOTE(renderer, "draw_ellipse %fx%f @ %f,%f\n",
width, height, center->x, center->y);
lt.x = center->x - width / 2;
lt.y = center->y - height / 2;
br.x = center->x + width / 2;
br.y = center->y + height / 2;
obj = renderer->tellipse->ops->create (<,
renderer->tbox->default_user_data,
&h1, &h2);
set_element_common_props (renderer, obj, <, &br);
set_line_common_props (renderer, obj, colour);
layer_add_object(renderer->layer, obj);
}
static void
fill_ellipse(MyRenderer *renderer,
Point *center,
real width, real height,
Color *colour)
{
Object *obj;
Handle *h1, *h2;
Point lt, br;
DIAG_NOTE(renderer, "fill_ellipse %fx%f @ %f,%f\n",
width, height, center->x, center->y);
lt.x = center->x - width / 2;
lt.y = center->y - height / 2;
br.x = center->x + width / 2;
br.y = center->y + height / 2;
obj = renderer->tellipse->ops->create (<,
renderer->tbox->default_user_data,
&h1, &h2);
set_element_common_props (renderer, obj, <, &br);
set_fill_common_props (renderer, obj, colour);
layer_add_object(renderer->layer, obj);
}
static void
draw_bezier(MyRenderer *renderer,
BezPoint *points,
int numpoints,
Color *colour)
{
Object *obj;
Handle *h1, *h2;
DIAG_NOTE(renderer, "draw_bezier n:%d %fx%f ...\n",
numpoints, points->p1.x, points->p1.y);
}
static void
fill_bezier(MyRenderer *renderer,
BezPoint *points, /* Last point must be same as first point */
int numpoints,
Color *colour)
{
Object *obj;
Handle *h1, *h2;
DIAG_NOTE(renderer, "fill_bezier n:%d %fx%f ...\n",
numpoints, points->p1.x, points->p1.y);
}
static void
draw_string(MyRenderer *renderer,
const char *text,
Point *pos, Alignment alignment,
Color *colour)
{
Object *obj;
Handle *h1, *h2;
int len;
DIAG_NOTE(renderer, "draw_string %f,%f %s\n",
pos->x, pos->y, text);
switch (alignment) {
case ALIGN_LEFT:
break;
case ALIGN_CENTER:
break;
case ALIGN_RIGHT:
break;
}
/* work out size of first chunk of text */
len = strlen(text);
}
static void
draw_image(MyRenderer *renderer,
Point *point,
real width, real height,
DiaImage image)
{
Object *obj;
Handle *h1, *h2;
Point br;
DIAG_NOTE(renderer, "draw_image %fx%f @%f,%f\n",
width, height, point->x, point->y);
#if 0 /* not finished */
br.x = point->x + width;
br.y = point->y + height;
set_element_common_props (renderer, obj, point, br);
layer_add_object(renderer->layer, obj);
#endif
}
static gboolean
import_data(const gchar *filename, DiagramData *data, void* user_data)
{
MyRenderer *renderer;
Rectangle *extent;
renderer = g_new(MyRenderer, 1);
renderer->renderer.ops = &MyRenderOps;
renderer->renderer.is_interactive = 0;
renderer->renderer.interactive_ops = NULL;
renderer->dia = (Diagram*)user_data;
renderer->layer = renderer->dia->data->active_layer;
extent = &data->extents;
/* write extents */
DIAG_NOTE(renderer, "export_data extents %f,%f -> %f,%f\n",
extent->left, extent->top, extent->right, extent->bottom);
data_render(data, (Renderer *)renderer, NULL, NULL, NULL);
g_free(renderer);
return TRUE;
}
/*
* Test without api changes. Export creates a new layer with
* all the objects from the current one ...
*/
static void
test_copy_data(DiagramData *data, const gchar *filename,
const gchar *diafilename, void* user_data)
{
MyRenderer *renderer;
Rectangle *extent;
renderer = g_new(MyRenderer, 1);
renderer->renderer.ops = &MyRenderOps;
renderer->renderer.is_interactive = 0;
renderer->renderer.interactive_ops = NULL;
renderer->dia = (Diagram*)user_data;
renderer->layer = new_layer(g_strdup(filename));
extent = &data->extents;
/* write extents */
DIAG_NOTE(renderer, "export_data extents %f,%f -> %f,%f\n",
extent->left, extent->top, extent->right, extent->bottom);
data_render(data, (Renderer *)renderer, NULL, NULL, NULL);
/* don't do this before rendering (would give endless objects) */
data_add_layer(data, renderer->layer);
g_free(renderer);
}
static const gchar *extensions[] = { "imp", NULL };
static DiaImportFilter my_import_filter = {
N_("Import Renderer"),
extensions,
import_data
};
static DiaExportFilter my_test_filter = {
N_(MY_RENDERER_NAME),
extensions,
test_copy_data
};
/* --- dia plug-in interface --- */
DIA_PLUGIN_CHECK_INIT
PluginInitResult
dia_plugin_init(PluginInfo *info)
{
if (!dia_plugin_info_init(info, "Importer",
_("Import Renderer Filter"),
NULL, NULL))
return DIA_PLUGIN_INIT_ERROR;
filter_register_import(&my_import_filter);
filter_register_export(&my_test_filter);
return DIA_PLUGIN_INIT_OK;
}
-------- Hans "at" Breuer "dot" Org -----------
Tell me what you need, and I'll tell you how to
get along without it. -- Dilbert