Re: Seminar on Dia



Attached is the main source file for the 'subdiagram' object type -- visually, it's just rendered as a labelled box, but under its properties view you'll see a field called 'Target'. Select a Dia diagram file for that field, and open the object's middle-click menu, and you'll be able to select 'Show Target...', which should open the diagram in a new window.

Nothing fancy, but not a bad starting point for more work, I hope.

Lennon Day-Reynolds
Software Engineer
Kestrel Institute

Andre Kloss wrote:

Hi, Lennon.

Cool, anyway - since I anyway need my own (very minimal) backend. I
only wanted to use Dia as the first editor of choice until I come up
with a native solution.

What I'd really appreciate is code for nested objects. I've had a
glance at the dia code and haven't found the point on which to start.

And for you being the "average Joe programmer": That's good, because I
have a certain dislike for theoreticians ;)

How far have you come with the dia-related code? Since I have a early
deadline I wonder if I could use it or if I have to come up with my
own solution here.

cu Andre
--
while(!asleep()) sheep++; -- Unknown

.




/* Dia -- an diagram creation/manipulation program
 * Copyright (C) 1998 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.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <assert.h>
#include <gtk/gtk.h>
#include <math.h>
#include <string.h>

#include "intl.h"
#include "object.h"
#include "objchange.h"
#include "element.h"
#include "connectionpoint.h"
#include "render.h"
#include "attributes.h"
#include "widgets.h"
#include "properties.h"
#include "diamenu.h"
#include "diagram.h"
#include "display.h"
#include "message.h"
#include "layer_dialog.h"

#include "pixmaps/subdiagram.xpm"

#define DEFAULT_WIDTH 2.0
#define DEFAULT_HEIGHT 1.0
#define TEXT_BORDER_WIDTH_X 0.7
#define TEXT_BORDER_WIDTH_Y 0.5
#define WEAK_BORDER_WIDTH 0.25
#define FONT_HEIGHT 0.8

typedef struct _Subdiagram Subdiagram;
typedef struct _SubdiagramState SubdiagramState;
typedef struct _SubdiagramChange SubdiagramChange;

struct _Subdiagram {
  Element element;

  ConnectionPoint connections[8];

  real border_width;
  Color border_color;
  Color inner_color;
  
  Font *font;
  char *label;
  real label_width;
  
  char *filename;
};

struct _SubdiagramState {
        //TODO: Add full state management for undo/redo?
};

struct _SubdiagramChange {
        ObjectChange obj_change;
        SubdiagramState *state;
        // See comment in _SubdiagramState def above
};

static real subdiagram_distance_from(Subdiagram *subdiagram, Point *point);
static void subdiagram_select(Subdiagram *subdiagram, Point *clicked_point,
                       Renderer *interactive_renderer);
static void subdiagram_move_handle(Subdiagram *subdiagram, Handle *handle,
                            Point *to, HandleMoveReason reason, ModifierKeys modifiers);
static void subdiagram_move(Subdiagram *subdiagram, Point *to);
static void subdiagram_draw(Subdiagram *subdiagram, Renderer *renderer);
static void subdiagram_update_data(Subdiagram *subdiagram);
static Object *subdiagram_create(Point *startpoint,
                             void *user_data,
                             Handle **handle1,
                             Handle **handle2);
static void subdiagram_destroy(Subdiagram *subdiagram);
static Object *subdiagram_copy(Subdiagram *subdiagram);
static PropDescription *
subdiagram_describe_props(Subdiagram *subdiagram);
static void
subdiagram_get_props(Subdiagram *subdiagram, Property *props, guint nprops);
static void
subdiagram_set_props(Subdiagram *subdiagram, Property *props, guint nprops);

static void subdiagram_save(Subdiagram *subdiagram, ObjectNode obj_node,
                        const char *filename);
static Object *subdiagram_load(ObjectNode obj_node, int version,
                           const char *filename);

static DiaMenu *subdiagram_get_object_menu(Subdiagram *subdiagram);

static SubdiagramState *subdiagram_get_state(Subdiagram *subdiagram);
static void subdiagram_set_state(Subdiagram *subdiagram, 
                                SubdiagramState *sstate);
static void subdiagram_free_state(SubdiagramState *sstate);

static ObjectTypeOps subdiagram_type_ops =
{
  (CreateFunc) subdiagram_create,
  (LoadFunc)   subdiagram_load,
  (SaveFunc)   subdiagram_save
};

ObjectType subdiagram_type =
{
  "Specware - Subdiagram",  /* name */
  0,                 /* version */
  (char **) subdiagram_xpm, /* pixmap */

  &subdiagram_type_ops      /* ops */
};

ObjectType *_subdiagram_type = (ObjectType *) &subdiagram_type;

static ObjectOps subdiagram_ops = {
  (DestroyFunc)         subdiagram_destroy,
  (DrawFunc)            subdiagram_draw,
  (DistanceFunc)        subdiagram_distance_from,
  (SelectFunc)          subdiagram_select,
  (CopyFunc)            subdiagram_copy,
  (MoveFunc)            subdiagram_move,
  (MoveHandleFunc)      subdiagram_move_handle,
  (GetPropertiesFunc)   object_create_props_dialog,
  (ApplyPropertiesFunc) object_apply_props_from_dialog,
  (ObjectMenuFunc)      subdiagram_get_object_menu,
  (DescribePropsFunc)   subdiagram_describe_props,
  (GetPropsFunc)        subdiagram_get_props,
  (SetPropsFunc)        subdiagram_set_props,
};

static PropDescription subdiagram_props[] = {
  ELEMENT_COMMON_PROPERTIES,
  { "label", PROP_TYPE_STRING, PROP_FLAG_VISIBLE,
    N_("Label:"), NULL, NULL },
  { "filename", PROP_TYPE_FILE, PROP_FLAG_VISIBLE,
    N_("File:"), NULL, NULL },
  PROP_STD_LINE_WIDTH,
  PROP_STD_LINE_COLOUR,
  PROP_STD_FILL_COLOUR,
  PROP_DESC_END
};

static PropDescription *
subdiagram_describe_props(Subdiagram *subdiagram)
{
  if (subdiagram_props[0].quark == 0)
    prop_desc_list_calculate_quarks(subdiagram_props);
  return subdiagram_props;
}

static PropOffset subdiagram_offsets[] = {
  ELEMENT_COMMON_PROPERTIES_OFFSETS,
  { "label", PROP_TYPE_STRING, offsetof(Subdiagram, label) },
  { "filename", PROP_TYPE_FILE, offsetof(Subdiagram, filename) },
  { "line_width", PROP_TYPE_REAL, offsetof(Subdiagram, border_width) },
  { "line_colour", PROP_TYPE_COLOUR, offsetof(Subdiagram, border_color) },
  { "fill_colour", PROP_TYPE_COLOUR, offsetof(Subdiagram, inner_color) },
  { NULL, 0, 0}
};


static void
subdiagram_get_props(Subdiagram *subdiagram, Property *props, guint nprops)
{
  object_get_props_from_offsets(&subdiagram->element.object, 
                                subdiagram_offsets, props, nprops);
}

static void
subdiagram_set_props(Subdiagram *subdiagram, Property *props, guint nprops)
{
  object_set_props_from_offsets(&subdiagram->element.object, 
                                subdiagram_offsets, props, nprops);
  subdiagram_update_data(subdiagram);
}

static real
subdiagram_distance_from(Subdiagram *subdiagram, Point *point)
{
  Element *elem = &subdiagram->element;
  Rectangle rect;

  rect.left = elem->corner.x - subdiagram->border_width/2;
  rect.right = elem->corner.x + elem->width + subdiagram->border_width/2;
  rect.top = elem->corner.y - subdiagram->border_width/2;
  rect.bottom = elem->corner.y + elem->height + subdiagram->border_width/2;
  return distance_rectangle_point(&rect, point);
}

static void
subdiagram_select(Subdiagram *subdiagram, Point *clicked_point,
           Renderer *interactive_renderer)
{
  element_update_handles(&subdiagram->element);
}

static void
subdiagram_move_handle(Subdiagram *subdiagram, Handle *handle,
                Point *to, HandleMoveReason reason, ModifierKeys modifiers)
{
  assert(subdiagram!=NULL);
  assert(handle!=NULL);
  assert(to!=NULL);

  element_move_handle(&subdiagram->element, handle->id, to, reason);

  subdiagram_update_data(subdiagram);
}

static void
subdiagram_move(Subdiagram *subdiagram, Point *to)
{
  subdiagram->element.corner = *to;
  
  subdiagram_update_data(subdiagram);
}

static void
subdiagram_draw(Subdiagram *subdiagram, Renderer *renderer)
{
  Point ul_corner, lr_corner;
  Point p;
  Element *elem;

  assert(subdiagram != NULL);
  assert(renderer != NULL);

  elem = &subdiagram->element;

  ul_corner.x = elem->corner.x;
  ul_corner.y = elem->corner.y;
  lr_corner.x = elem->corner.x + elem->width;
  lr_corner.y = elem->corner.y + elem->height;
  
  renderer->ops->set_fillstyle(renderer, FILLSTYLE_SOLID);
  
  renderer->ops->fill_rect(renderer, 
                           &ul_corner,
                           &lr_corner, 
                           &subdiagram->inner_color);

  renderer->ops->set_linewidth(renderer, subdiagram->border_width);
  renderer->ops->set_linestyle(renderer, LINESTYLE_SOLID);
  renderer->ops->set_linejoin(renderer, LINEJOIN_MITER);

  renderer->ops->draw_rect(renderer, 
                           &ul_corner,
                           &lr_corner, 
                           &subdiagram->border_color);


  p.x = elem->corner.x + elem->width / 2.0;
  p.y = elem->corner.y + (elem->height - FONT_HEIGHT)/2.0 + font_ascent(subdiagram->font, FONT_HEIGHT);
  renderer->ops->set_font(renderer, 
                          subdiagram->font, FONT_HEIGHT);
  renderer->ops->draw_string(renderer, 
                             subdiagram->label, 
                             &p, ALIGN_CENTER, 
                             &color_black);
}

static void
subdiagram_update_data(Subdiagram *subdiagram)
{
  Element *elem = &subdiagram->element;
  Object *obj = &elem->object;
  ElementBBExtras *extra = &elem->extra_spacing;

  subdiagram->label_width =
    font_string_width(subdiagram->label, subdiagram->font, FONT_HEIGHT);

  elem->width = subdiagram->label_width + 2*TEXT_BORDER_WIDTH_X;
  elem->height = FONT_HEIGHT + 2*TEXT_BORDER_WIDTH_Y;

  /* Update connections: */
  subdiagram->connections[0].pos = elem->corner;
  subdiagram->connections[1].pos.x = elem->corner.x + elem->width / 2.0;
  subdiagram->connections[1].pos.y = elem->corner.y;
  subdiagram->connections[2].pos.x = elem->corner.x + elem->width;
  subdiagram->connections[2].pos.y = elem->corner.y;
  subdiagram->connections[3].pos.x = elem->corner.x;
  subdiagram->connections[3].pos.y = elem->corner.y + elem->height / 2.0;
  subdiagram->connections[4].pos.x = elem->corner.x + elem->width;
  subdiagram->connections[4].pos.y = elem->corner.y + elem->height / 2.0;
  subdiagram->connections[5].pos.x = elem->corner.x;
  subdiagram->connections[5].pos.y = elem->corner.y + elem->height;
  subdiagram->connections[6].pos.x = elem->corner.x + elem->width / 2.0;
  subdiagram->connections[6].pos.y = elem->corner.y + elem->height;
  subdiagram->connections[7].pos.x = elem->corner.x + elem->width;
  subdiagram->connections[7].pos.y = elem->corner.y + elem->height;

  extra->border_trans = subdiagram->border_width/2.0;
  element_update_boundingbox(elem);
  
  obj->position = elem->corner;
  
  element_update_handles(elem);
}

static Object *
subdiagram_create(Point *startpoint,
              void *user_data,
              Handle **handle1,
              Handle **handle2)
{
  Subdiagram *subdiagram;
  Element *elem;
  Object *obj;
  int i;

  subdiagram = g_malloc0(sizeof(Subdiagram));
  elem = &subdiagram->element;
  obj = &elem->object;
  
  obj->type = &subdiagram_type;

  obj->ops = &subdiagram_ops;

  elem->corner = *startpoint;
  elem->width = DEFAULT_WIDTH;
  elem->height = DEFAULT_WIDTH;

  subdiagram->border_width =  attributes_get_default_linewidth();
  subdiagram->border_color = attributes_get_foreground();
  subdiagram->inner_color = attributes_get_background();
  
  element_init(elem, 8, 8);

  for (i=0;i<8;i++) {
    obj->connections[i] = &subdiagram->connections[i];
    subdiagram->connections[i].object = obj;
    subdiagram->connections[i].connected = NULL;
  }

  subdiagram->font = font_getfont("Courier");
  subdiagram->label = g_strdup(_("<unknown>"));
  subdiagram->filename = g_strdup(_(""));

  subdiagram->label_width =
    font_string_width(subdiagram->label, subdiagram->font, FONT_HEIGHT);
  
  subdiagram_update_data(subdiagram);

  for (i=0;i<8;i++) {
    obj->handles[i]->type = HANDLE_NON_MOVABLE;
  }

  *handle1 = NULL;
  *handle2 = obj->handles[0];  
  return &subdiagram->element.object;
}

static void
subdiagram_destroy(Subdiagram *subdiagram)
{
  element_destroy(&subdiagram->element);
  g_free(subdiagram->label);
  g_free(subdiagram->filename);
}

static Object *
subdiagram_copy(Subdiagram *subdiagram)
{
  int i;
  Subdiagram *newsubdiagram;
  Element *elem, *newelem;
  Object *newobj;
  
  elem = &subdiagram->element;
  
  newsubdiagram = g_malloc0(sizeof(Subdiagram));
  newelem = &newsubdiagram->element;
  newobj = &newelem->object;

  element_copy(elem, newelem);

  newsubdiagram->border_width = subdiagram->border_width;
  newsubdiagram->border_color = subdiagram->border_color;
  newsubdiagram->inner_color = subdiagram->inner_color;
  
  for (i=0;i<8;i++) {
    newobj->connections[i] = &newsubdiagram->connections[i];
    newsubdiagram->connections[i].object = newobj;
    newsubdiagram->connections[i].connected = NULL;
    newsubdiagram->connections[i].pos = subdiagram->connections[i].pos;
    newsubdiagram->connections[i].last_pos = subdiagram->connections[i].last_pos;
  }

  newsubdiagram->font = subdiagram->font;
  newsubdiagram->label = strdup(subdiagram->label);
  newsubdiagram->label_width = subdiagram->label_width;
  newsubdiagram->filename = strdup(subdiagram->filename);

  return &newsubdiagram->element.object;
}

static void
subdiagram_save(Subdiagram *subdiagram, ObjectNode obj_node, const char *filename)
{
  element_save(&subdiagram->element, obj_node);

  data_add_real(new_attribute(obj_node, "border_width"),
                subdiagram->border_width);
  data_add_color(new_attribute(obj_node, "border_color"),
                 &subdiagram->border_color);
  data_add_color(new_attribute(obj_node, "inner_color"),
                 &subdiagram->inner_color);
  data_add_string(new_attribute(obj_node, "label"),
                  subdiagram->label);
  data_add_string(new_attribute(obj_node, "filename"),
                   subdiagram->filename);
}

static Object *
subdiagram_load(ObjectNode obj_node, int version, const char *filename)
{
  Subdiagram *subdiagram;
  Element *elem;
  Object *obj;
  int i;
  AttributeNode attr;

  subdiagram = g_malloc0(sizeof(Subdiagram));
  elem = &subdiagram->element;
  obj = &elem->object;
  
  obj->type = &subdiagram_type;
  obj->ops = &subdiagram_ops;

  element_load(elem, obj_node);
  
  subdiagram->border_width = 0.1;
  attr = object_find_attribute(obj_node, "border_width");
  if (attr != NULL)
    subdiagram->border_width =  data_real( attribute_first_data(attr) );

  subdiagram->border_color = color_black;
  attr = object_find_attribute(obj_node, "border_color");
  if (attr != NULL)
    data_color(attribute_first_data(attr), &subdiagram->border_color);
  
  subdiagram->inner_color = color_white;
  attr = object_find_attribute(obj_node, "inner_color");
  if (attr != NULL)
    data_color(attribute_first_data(attr), &subdiagram->inner_color);
  
  subdiagram->label = NULL;
  attr = object_find_attribute(obj_node, "label");
  if (attr != NULL)
    subdiagram->label = data_string(attribute_first_data(attr));

  attr = object_find_attribute(obj_node, "filename");
  if (attr != NULL)
    subdiagram->filename = data_string(attribute_first_data(attr));

  element_init(elem, 8, 8);

  for (i=0;i<8;i++) {
    obj->connections[i] = &subdiagram->connections[i];
    subdiagram->connections[i].object = obj;
    subdiagram->connections[i].connected = NULL;
  }

  subdiagram->font = font_getfont("Courier");

  subdiagram->label_width =
    font_string_width(subdiagram->label, subdiagram->font, FONT_HEIGHT);

  subdiagram_update_data(subdiagram);

  for (i=0;i<8;i++) {
    obj->handles[i]->type = HANDLE_NON_MOVABLE;
  }

  return &subdiagram->element.object;
}

static ObjectChange *
subdiagram_create_change(Subdiagram *subdiagram)
{
        ObjectChange *change;
        SubdiagramState *sstate;

        sstate = subdiagram_get_state(subdiagram);
        change = new_object_state_change((Object *)subdiagram,
                                        (ObjectState *)sstate,
                                        (GetStateFunc)subdiagram_get_state,
                                        (SetStateFunc)subdiagram_set_state );

        return change;
}

static ObjectChange *
subdiagram_show_target(Subdiagram *subdiagram, gpointer data)
{
        char *filename = subdiagram->filename;
        Diagram *diagram = NULL;
        DDisplay *ddisp = NULL;

        if(filename!=NULL && strcmp(filename, "")) {
                diagram = diagram_load(filename, NULL);

                if(diagram!=NULL) {
                        diagram_update_extents(diagram);
                        layer_dialog_set_diagram(diagram);
                        
                        ddisp = new_display(diagram);
                        display_set_active(ddisp);
                } else {
                        message_error("Could not open subdiagram %s. Please insure that the file exists and 
is readable", filename);
                }
        } else {
                message_error("No file has been selected for this subdiagram.");
        }

        return (ObjectChange *)subdiagram_create_change(subdiagram);
}

static DiaMenuItem subdiagram_menu_items[] = 
{
        {
                "Open...",
                (DiaMenuCallback *)subdiagram_show_target,
                NULL,
                1
        }
};

static DiaMenu subdiagram_menu =
{
        "Subdiagram",
        sizeof(subdiagram_menu_items)/sizeof(DiaMenuItem),
        subdiagram_menu_items,
        NULL
};

static DiaMenu *
subdiagram_get_object_menu(Subdiagram *subdiagram)
{
        return &subdiagram_menu;
}

static SubdiagramState *
subdiagram_get_state (Subdiagram *subdiagram)
{
        SubdiagramState *sstate;
        sstate = g_new0(SubdiagramState, 1);

        return sstate;
}

static void
subdiagram_set_state(Subdiagram *subdiagram, SubdiagramState *sstate)
{
        // No-op
}

static void
subdiagram_free_state(SubdiagramState *sstate)
{
        g_free(sstate);
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]