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 +#endif + +#include +#include +#include + +#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;iconnections[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);