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 (&lt, 
                                       renderer->tbox->default_user_data,
                                               &h1, &h2);

    set_object_common_props (renderer, obj, &lt, &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 (&lt, 
                                       renderer->tbox->default_user_data,
                                               &h1, &h2);

    set_object_common_props (renderer, obj, &lt, &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 (&lt, 
                                           renderer->tbox->default_user_data,
                                                   &h1, &h2);

    set_element_common_props (renderer, obj, &lt, &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 (&lt, 
                                           renderer->tbox->default_user_data,
                                                   &h1, &h2);

    set_element_common_props (renderer, obj, &lt, &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

Reply via email to