Hi,
appended to this mail is a patch for state clusters. They are like
states but you can resize them. They are intended as borders which you
can use to group states.
You can think of a transition starting at a state cluster as equivalent
to lots of transitions starting at the contained states.
Transitions ending at state clusters don't make much sense if you want a
deterministic state machine.

The source is strongly influenced by state.c and large_package.c (mostly
copy&paste...)

To get an icon in the toolbox, I inserted some lines in UML.sheet.
     <object name="UML - State Cluster">
      <description>State Cluster</description>
      <description xml:lang="de">Zustandsgruppe</description>
      <description xml:lang="en_CA">State Cluster</description>
      <description xml:lang="en_GB">State Cluster</description>
    </object>
But this file is generated from somewhere else. Where would have been
the right place to insert the new shape?

Sebastian


Index: objects/UML/pixmaps/state_cluster.xpm
===================================================================
--- objects/UML/pixmaps/state_cluster.xpm	(Revision 0)
+++ objects/UML/pixmaps/state_cluster.xpm	(Revision 0)
@@ -0,0 +1,31 @@
+/* XPM */
+static char * state_cluster_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"22 22 3 1",
+/* colors */
+".	c none",
+"+	c black",
+" 	c white",
+/* pixels */
+"......................",
+"...++++++++++++++++...",
+"..+                +..",
+".+                  +.",
+".+                  +.",
+".+                  +.",
+".+                  +.",
+".+                  +.",
+".+                  +.",
+".+                  +.",
+".+                  +.",
+".+                  +.",
+".+                  +.",
+".+                  +.",
+".+                  +.",
+".+                  +.",
+".+                  +.",
+"..+                +..",
+"...++++++++++++++++...",
+"......................",
+"......................",
+"......................"};
Index: objects/UML/state_cluster.c
===================================================================
--- objects/UML/state_cluster.c	(Revision 0)
+++ objects/UML/state_cluster.c	(Revision 0)
@@ -0,0 +1,480 @@
+/* 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 <math.h>
+#include <string.h>
+
+#include "intl.h"
+#include "object.h"
+#include "element.h"
+#include "diarenderer.h"
+#include "attributes.h"
+#include "text.h"
+#include "properties.h"
+
+#include "pixmaps/state_cluster.xpm"
+
+typedef struct _State State;
+
+typedef enum {
+	ENTRY_ACTION,
+	DO_ACTION,
+	EXIT_ACTION
+} StateAction;
+
+#define NUM_CONNECTIONS 9
+
+struct _State {
+	Element element;
+
+	ConnectionPoint connections[NUM_CONNECTIONS];
+
+	Text *text;
+
+	TextAttributes attrs;
+
+	Color line_color;
+	Color fill_color;
+
+	gchar* entry_action;
+	gchar* do_action;
+	gchar* exit_action;
+};
+
+
+#define STATE_WIDTH  4
+#define STATE_HEIGHT 3
+#define STATE_LINEWIDTH 0.1
+#define STATE_MARGIN_X 0.5
+#define STATE_MARGIN_Y 0.5
+
+static real state_distance_from(State *state, Point *point);
+static void state_select(State *state, Point *clicked_point,
+	DiaRenderer *interactive_renderer);
+static ObjectChange* state_move_handle(State *state, Handle *handle,
+	Point *to, ConnectionPoint *cp,
+	HandleMoveReason reason, ModifierKeys modifiers);
+static ObjectChange* state_move(State *state, Point *to);
+static void state_draw(State *state, DiaRenderer *renderer);
+static DiaObject *state_create(Point *startpoint,
+	void *user_data,
+	Handle **handle1,
+	Handle **handle2);
+static void state_destroy(State *state);
+static DiaObject *state_load(ObjectNode obj_node, int version,
+	const char *filename);
+static PropDescription *state_describe_props(State *state);
+static void state_get_props(State *state, GPtrArray *props);
+static void state_set_props(State *state, GPtrArray *props);
+static void state_update_data(State *state);
+static gchar* state_get_action_text(State* state, StateAction action);
+static void state_calc_action_text_pos(State* state, StateAction action, Point* pos);
+
+static ObjectTypeOps state_type_ops =
+{
+	(CreateFunc) state_create,
+	(LoadFunc)   state_load,/*using_properties*/    /* load */
+	(SaveFunc)   object_save_using_properties,      /* save */
+	(GetDefaultsFunc)   NULL, 
+	(ApplyDefaultsFunc) NULL
+};
+
+DiaObjectType state_cluster_type =
+{
+	"UML - State Cluster",        /* name */
+	0,                            /* version */
+	(char **) state_cluster_xpm,  /* pixmap */
+
+	&state_type_ops               /* ops */
+};
+
+static ObjectOps state_ops = {
+	(DestroyFunc)         state_destroy,
+	(DrawFunc)            state_draw,
+	(DistanceFunc)        state_distance_from,
+	(SelectFunc)          state_select,
+	(CopyFunc)            object_copy_using_properties,
+	(MoveFunc)            state_move,
+	(MoveHandleFunc)      state_move_handle,
+	(GetPropertiesFunc)   object_create_props_dialog,
+	(ApplyPropertiesDialogFunc) object_apply_props_from_dialog,
+	(ObjectMenuFunc)      NULL,
+	(DescribePropsFunc)   state_describe_props,
+	(GetPropsFunc)        state_get_props,
+	(SetPropsFunc)        state_set_props,
+	(TextEditFunc) 0,
+	(ApplyPropertiesListFunc) object_apply_props,
+};
+
+static PropDescription state_props[] = {
+	ELEMENT_COMMON_PROPERTIES,
+	PROP_STD_LINE_COLOUR_OPTIONAL, 
+	PROP_STD_FILL_COLOUR_OPTIONAL, 
+	PROP_STD_TEXT_FONT,
+	PROP_STD_TEXT_HEIGHT,
+	PROP_STD_TEXT_COLOUR_OPTIONAL,
+	{ "text", PROP_TYPE_TEXT, 0, N_("Text"), NULL, NULL }, 
+	{ "entry_action", PROP_TYPE_STRING, PROP_FLAG_OPTIONAL | PROP_FLAG_VISIBLE, N_("Entry action"), NULL, NULL },
+	{ "do_action", PROP_TYPE_STRING, PROP_FLAG_OPTIONAL | PROP_FLAG_VISIBLE, N_("Do action"), NULL, NULL },
+	{ "exit_action", PROP_TYPE_STRING, PROP_FLAG_OPTIONAL | PROP_FLAG_VISIBLE, N_("Exit action"),  NULL, NULL },
+	PROP_DESC_END
+};
+
+static PropDescription *
+state_describe_props(State *state)
+{
+	if (state_props[0].quark == 0) {
+		prop_desc_list_calculate_quarks(state_props);
+	}
+	return state_props;
+}
+
+static PropOffset state_offsets[] = {
+	ELEMENT_COMMON_PROPERTIES_OFFSETS,
+	{"line_colour",PROP_TYPE_COLOUR,offsetof(State,line_color)},
+	{"fill_colour",PROP_TYPE_COLOUR,offsetof(State,fill_color)},
+	{"text",PROP_TYPE_TEXT,offsetof(State,text)},
+	{"text_font",PROP_TYPE_FONT,offsetof(State,attrs.font)},
+	{PROP_STDNAME_TEXT_HEIGHT,PROP_STDTYPE_TEXT_HEIGHT,offsetof(State,attrs.height)},
+	{"text_colour",PROP_TYPE_COLOUR,offsetof(State,attrs.color)},
+	{"entry_action",PROP_TYPE_STRING,offsetof(State,entry_action)},
+	{"do_action",PROP_TYPE_STRING,offsetof(State,do_action)},
+	{"exit_action",PROP_TYPE_STRING,offsetof(State,exit_action)},  
+	{ NULL, 0, 0 },
+};
+
+static void
+state_get_props(State * state, GPtrArray *props)
+{
+	text_get_attributes(state->text,&state->attrs);
+	object_get_props_from_offsets(
+		&state->element.object,
+		state_offsets,props);
+}
+
+static void
+state_set_props(State *state, GPtrArray *props)
+{
+	object_set_props_from_offsets(
+		&state->element.object,
+		state_offsets,props);
+	apply_textattr_properties(props,state->text,"text",&state->attrs);
+	state_update_data(state);
+}
+
+static real
+state_distance_from(State *state, Point *point)
+{
+	DiaObject *obj = &state->element.object;
+	return distance_rectangle_point(&obj->bounding_box, point);
+}
+
+static void
+state_select(
+	State *state, Point *clicked_point,
+	DiaRenderer *interactive_renderer)
+{
+	text_set_cursor(state->text, clicked_point, interactive_renderer);
+	text_grab_focus(state->text, &state->element.object);
+	element_update_handles(&state->element);
+}
+
+static ObjectChange*
+state_move_handle(
+	State *state, Handle *handle,
+	Point *to, ConnectionPoint *cp,
+	HandleMoveReason reason, ModifierKeys modifiers)
+{
+	assert(state!=NULL);
+	assert(handle!=NULL);
+	assert(to!=NULL);
+
+	assert(handle->id < 8);
+	
+	element_move_handle(&state->element, handle->id, to, cp, reason, modifiers);
+	state_update_data(state);
+
+	return NULL;
+}
+
+static ObjectChange*
+state_move(State *state, Point *to)
+{
+	state->element.corner = *to;
+	state_update_data(state);
+
+	return NULL;
+}
+
+static void
+state_draw_action_string(State *state, DiaRenderer *renderer, StateAction action)
+{
+	DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
+	Point pos;
+	gchar* action_text = state_get_action_text(state, action);
+	state_calc_action_text_pos(state, action, &pos);
+	renderer_ops->set_font(renderer, state->text->font, state->text->height);
+	renderer_ops->draw_string(renderer,
+		action_text,
+		&pos, 
+		ALIGN_LEFT, 
+		&state->attrs.color);
+	g_free(action_text);
+}
+
+static void
+state_draw(State *state, DiaRenderer *renderer)
+{
+	DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
+	Element *elem;
+	real x, y, w, h;
+	Point p1, p2, split_line_left, split_line_right;
+	gboolean has_actions;
+
+	assert(state != NULL);
+	assert(renderer != NULL);
+
+	elem = &state->element;
+
+	x = elem->corner.x;
+	y = elem->corner.y;
+	w = elem->width;
+	h = elem->height;
+
+	renderer_ops->set_fillstyle(renderer, FILLSTYLE_SOLID);
+	renderer_ops->set_linewidth(renderer, STATE_LINEWIDTH);
+	renderer_ops->set_linestyle(renderer, LINESTYLE_SOLID);
+
+	p1.x = x;
+	p1.y = y;
+	p2.x = x + w;
+	p2.y = y + h;
+	renderer_ops->draw_rounded_rect(renderer, &p1, &p2, &state->line_color, 0.5);
+
+	text_draw(state->text, renderer);
+	has_actions = FALSE;
+	if (state->entry_action && strlen(state->entry_action) != 0) {
+		state_draw_action_string(state, renderer, ENTRY_ACTION);
+		has_actions = TRUE;
+	}
+	if (state->do_action && strlen(state->do_action) != 0) {
+		state_draw_action_string(state, renderer, DO_ACTION);
+		has_actions = TRUE;
+	}
+	if (state->exit_action && strlen(state->exit_action) != 0) {
+		state_draw_action_string(state, renderer, EXIT_ACTION);
+		has_actions = TRUE;
+	}
+
+	if (has_actions) {
+		split_line_left.x = x;
+		split_line_right.x = x+STATE_MARGIN_X+state->text->max_width;
+		split_line_left.y 
+			= split_line_right.y 
+			= state->element.corner.y + STATE_MARGIN_Y +
+				state->text->numlines*state->text->height;
+		renderer_ops->draw_line(renderer, &split_line_left, &split_line_right,
+			&state->line_color);
+	}
+}
+
+
+static void
+state_update_width_and_height_with_action_text(
+	State* state, 
+	StateAction action,
+	real* width,
+	real* height)
+{
+	gchar* action_text = state_get_action_text(state, action);
+	*width = MAX(*width,
+		dia_font_string_width(action_text, state->text->font,
+			state->text->height)
+		+ 2*STATE_MARGIN_X);
+	g_free(action_text);
+	*height += state->text->height;
+}
+
+static void
+state_update_data(State *state)
+{
+	real w, h;
+
+	Element *elem = &state->element;
+	ElementBBExtras *extra = &elem->extra_spacing;
+	DiaObject *obj = &elem->object;
+	Point p;
+
+	text_calc_boundingbox(state->text, NULL);
+	/* First consider the state description text */
+	w = state->text->max_width + 2*STATE_MARGIN_X;
+	h = state->text->height*state->text->numlines +2*STATE_MARGIN_Y;
+	if (w < STATE_WIDTH)
+		w = STATE_WIDTH;
+	/* Then consider the actions texts */
+	if (state->entry_action && strlen(state->entry_action) != 0) {
+		state_update_width_and_height_with_action_text(state, ENTRY_ACTION, &w, &h);
+	}
+	if (state->do_action && strlen(state->do_action) != 0) {
+		state_update_width_and_height_with_action_text(state, DO_ACTION, &w, &h);
+	}
+	if (state->exit_action && strlen(state->exit_action) != 0) {
+		state_update_width_and_height_with_action_text(state, EXIT_ACTION, &w, &h);
+	}
+
+	elem->width  = MAX(elem->width,  w);
+	elem->height = MAX(elem->height, h);
+	extra->border_trans = STATE_LINEWIDTH / 2.0;
+
+	p.x = elem->corner.x + STATE_MARGIN_X;
+	p.y = elem->corner.y + STATE_MARGIN_Y + state->text->ascent;
+	text_set_position(state->text, &p);
+	text_set_alignment(state->text, ALIGN_LEFT);
+
+	/* Update connections: */
+	element_update_connections_rectangle(elem, state->connections);
+
+	element_update_boundingbox(elem);
+
+	obj->position = elem->corner;
+
+	element_update_handles(elem);
+}
+
+static DiaObject *
+state_create(Point *startpoint,
+	void *user_data,
+	Handle **handle1,
+	Handle **handle2)
+{
+	State *state;
+	Element *elem;
+	DiaObject *obj;
+	Point p;
+	DiaFont *font;
+	int i;
+
+	state = g_malloc0(sizeof(State));
+	elem = &state->element;
+	obj = &elem->object;
+
+	obj->type = &state_cluster_type;
+	obj->ops = &state_ops;
+	elem->corner = *startpoint;
+	elem->width = STATE_WIDTH;
+	elem->height = STATE_HEIGHT;
+
+	state->line_color = attributes_get_foreground();
+	state->fill_color = attributes_get_background();
+
+	font = dia_font_new_from_style(DIA_FONT_SANS, 0.8);
+	p = *startpoint;
+	p.x += STATE_WIDTH/2.0;
+	p.y += STATE_HEIGHT/2.0;
+
+	state->text = new_text("", font, 0.8, &p, &color_black, ALIGN_LEFT);
+	text_get_attributes(state->text,&state->attrs);
+
+	dia_font_unref(font);
+
+	element_init(elem, 8, NUM_CONNECTIONS);
+
+	for (i=0;i<NUM_CONNECTIONS;i++) {
+		obj->connections[i] = &state->connections[i];
+		state->connections[i].object = obj;
+		state->connections[i].connected = NULL;
+	}
+	state->connections[8].flags = CP_FLAGS_MAIN;
+	elem->extra_spacing.border_trans = 0.0;
+	state_update_data(state);
+
+	*handle1 = NULL;
+	*handle2 = NULL;
+	return &state->element.object;
+}
+
+static void
+state_destroy(State *state)
+{
+	text_destroy(state->text);
+
+	element_destroy(&state->element);
+}
+
+static DiaObject *
+state_load(ObjectNode obj_node, int version, const char *filename)
+{
+	return object_load_using_properties(&state_cluster_type,
+		obj_node,version,filename);
+}
+
+static void
+state_calc_action_text_pos(State* state, StateAction action, Point* pos)
+{
+	int entry_action_valid = state->entry_action && strlen(state->entry_action) != 0;
+	int do_action_valid = state->do_action && strlen(state->do_action) != 0;
+
+	real first_action_y = state->text->numlines*state->text->height + 
+	state->text->position.y; 
+
+	pos->x = state->element.corner.x + STATE_MARGIN_X;
+
+	switch (action)
+	{
+	case ENTRY_ACTION:
+		pos->y = first_action_y;
+		break;
+
+	case DO_ACTION:
+		pos->y = first_action_y;
+		if (entry_action_valid) pos->y += state->text->height;
+		break;
+
+	case EXIT_ACTION:
+		pos->y = first_action_y;
+		if (entry_action_valid) pos->y += state->text->height;
+		if (do_action_valid) pos->y += state->text->height;      
+		break;
+	}
+}
+
+
+static gchar*
+state_get_action_text(State* state, StateAction action)
+{
+	switch (action)
+	{
+	case ENTRY_ACTION:
+		return g_strdup_printf("entry/ %s", state->entry_action);
+		break;
+
+	case DO_ACTION:
+		return g_strdup_printf("do/ %s", state->do_action);
+		break;
+
+	case EXIT_ACTION:
+		return g_strdup_printf("exit/ %s", state->exit_action);
+		break;
+	}
+	return NULL;
+}
Index: objects/UML/Makefile.am
===================================================================
--- objects/UML/Makefile.am	(Revision 4358)
+++ objects/UML/Makefile.am	(Arbeitskopie)
@@ -25,6 +25,7 @@
 			component_feature.c \
 			classicon.c \
 			state.c \
+			state_cluster.c \
 			activity.c \
 			state_term.c \
 			node.c \
@@ -63,6 +64,7 @@
 	pixmaps/realizes.xpm \
 	pixmaps/smallpackage.xpm \
 	pixmaps/state.xpm \
+	pixmaps/state_cluster.xpm \
 	pixmaps/umlclass.xpm \
 	pixmaps/node.xpm \
 	pixmaps/branch.xpm \
Index: objects/UML/uml.c
===================================================================
--- objects/UML/uml.c	(Revision 4358)
+++ objects/UML/uml.c	(Arbeitskopie)
@@ -49,6 +49,7 @@
 extern DiaObjectType component_type;
 extern DiaObjectType classicon_type;
 extern DiaObjectType state_type;
+extern DiaObjectType state_cluster_type;
 extern DiaObjectType activity_type;
 extern DiaObjectType node_type;
 extern DiaObjectType branch_type;
@@ -86,6 +87,7 @@
   object_register_type(&component_type);
   object_register_type(&classicon_type);
   object_register_type(&state_type);
+  object_register_type(&state_cluster_type);
   object_register_type(&state_term_type);
   object_register_type(&activity_type);
   object_register_type(&node_type);    
_______________________________________________
dia-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/dia-list
FAQ at http://live.gnome.org/Dia/Faq
Main page at http://live.gnome.org/Dia

Reply via email to