/* 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. */ #include "render_object.h" static real rendobj_distance_from(RenderObject *rend_obj, Point *point); static void rendobj_select(RenderObject *rend_obj, Point *clicked_point, Renderer *interactive_renderer); static void rendobj_move_handle(RenderObject *rend_obj, Handle *handle, Point *to, HandleMoveReason reason); static void rendobj_move(RenderObject *rend_obj, Point *to); static void rendobj_draw(RenderObject *rend_obj, Renderer *renderer); static void rendobj_update_data(RenderObject *rend_obj); static void rendobj_destroy(RenderObject *rend_obj); static Object *rendobj_copy(RenderObject *rend_obj); static ObjectOps rendobj_ops = { (DestroyFunc) rendobj_destroy, (DrawFunc) rendobj_draw, (DistanceFunc) rendobj_distance_from, (SelectFunc) rendobj_select, (CopyFunc) rendobj_copy, (MoveFunc) rendobj_move, (MoveHandleFunc) rendobj_move_handle, (GetPropertiesFunc) object_return_null, (ApplyPropertiesFunc) object_return_void, (ObjectMenuFunc) NULL }; Object * new_render_object(Point *startpoint, Handle **handle1, Handle **handle2, const RenderObjectDescriptor *desc) { RenderObject *rend_obj; Element *elem; Object *obj; int i; rend_obj = g_malloc(sizeof(RenderObject)); elem = &rend_obj->element; obj = &elem->object; obj->type = desc->obj_type; obj->ops = &rendobj_ops; elem->corner = *startpoint; elem->width = desc->width; elem->height = desc->height; rend_obj->desc = desc; rend_obj->magnify = 1.0; if (desc->use_text) { rend_obj->text = new_text("", desc->initial_font, desc->initial_font_height, (Point *)&desc->text_pos, &color_black, desc->initial_alignment); } else { rend_obj->text = NULL; } element_init(elem, 8, desc->num_connection_points); rend_obj->connections = g_new(ConnectionPoint, desc->num_connection_points); for (i=0;inum_connection_points;i++) { obj->connections[i] = &rend_obj->connections[i]; rend_obj->connections[i].object = obj; rend_obj->connections[i].connected = NULL; } rendobj_update_data(rend_obj); *handle1 = NULL; *handle2 = obj->handles[0]; return (Object *)rend_obj; } void render_object_save(RenderObject *rend_obj, ObjectNode obj_node) { element_save(&rend_obj->element, obj_node); data_add_real(new_attribute(obj_node, "magnify"), rend_obj->magnify); if (rend_obj->desc->use_text) { data_add_text(new_attribute(obj_node, "text"), rend_obj->text); } } Object *render_object_load(ObjectNode obj_node, const RenderObjectDescriptor *desc) { RenderObject *rend_obj; Element *elem; Object *obj; AttributeNode attr; int i; Point startpoint = {0.0, 0.0}; rend_obj = g_malloc(sizeof(RenderObject)); elem = &rend_obj->element; obj = &elem->object; obj->type = desc->obj_type; obj->ops = &rendobj_ops; element_load(elem, obj_node); rend_obj->desc = desc; rend_obj->magnify = 1.0; attr = object_find_attribute(obj_node, "magnify"); if (attr != NULL) rend_obj->magnify = data_real( attribute_first_data(attr) ); if (desc->use_text) { attr = object_find_attribute(obj_node, "text"); if (attr != NULL) rend_obj->text = data_text( attribute_first_data(attr) ); else rend_obj->text = new_text("", font_getfont("Courier"), 1.0, &startpoint, &color_black, ALIGN_CENTER); } element_init(elem, 8, desc->num_connection_points); rend_obj->connections = g_new(ConnectionPoint, desc->num_connection_points); for (i=0;inum_connection_points;i++) { obj->connections[i] = &rend_obj->connections[i]; rend_obj->connections[i].object = obj; rend_obj->connections[i].connected = NULL; } rendobj_update_data(rend_obj); return (Object *)rend_obj; } static void rendobj_destroy(RenderObject *rend_obj) { element_destroy(&rend_obj->element); if (rend_obj->desc->use_text) text_destroy(rend_obj->text); g_free(rend_obj->connections); } static Object * rendobj_copy(RenderObject *rend_obj) { int i; RenderObject *newrend_obj; Element *elem, *newelem; Object *newobj; elem = &rend_obj->element; newrend_obj = g_malloc(sizeof(RenderObject)); newelem = &newrend_obj->element; newobj = &newelem->object; element_copy(elem, newelem); newrend_obj->desc = rend_obj->desc; newrend_obj->magnify = rend_obj->magnify; if (rend_obj->desc->use_text) { newrend_obj->text = text_copy(rend_obj->text); } else { newrend_obj->text = NULL; } newrend_obj->connections = g_new(ConnectionPoint, rend_obj->desc->num_connection_points); for (i=0;idesc->num_connection_points;i++) { newobj->connections[i] = &newrend_obj->connections[i]; newrend_obj->connections[i].object = newobj; newrend_obj->connections[i].pos = rend_obj->connections[i].pos; newrend_obj->connections[i].last_pos = rend_obj->connections[i].last_pos; newrend_obj->connections[i].connected = NULL; } rendobj_update_data(newrend_obj); return (Object *)newrend_obj; } static real rendobj_distance_from(RenderObject *rend_obj, Point *point) { Element *elem = &rend_obj->element; Rectangle rect; real dist; real text_dist; /* Todo: Make this better, more changeable by the user. */ rect.left = elem->corner.x; rect.right = elem->corner.x + elem->width; rect.top = elem->corner.y ; rect.bottom = elem->corner.y + elem->height; dist = distance_rectangle_point(&rect, point); if (rend_obj->desc->use_text) { text_dist = text_distance_from(rend_obj->text, point); if (text_distdesc->use_text) { text_set_cursor(rend_obj->text, clicked_point, interactive_renderer); text_grab_focus(rend_obj->text, (Object *)rend_obj); } element_update_handles(&rend_obj->element); } static void rendobj_move_handle(RenderObject *rend_obj, Handle *handle, Point *to, HandleMoveReason reason) { element_move_handle_aspect(&rend_obj->element, handle->id, to, rend_obj->desc->width/rend_obj->desc->height); rendobj_update_data(rend_obj); } static void rendobj_move(RenderObject *rend_obj, Point *to) { Point p; p = rend_obj->desc->move_position; rend_obj->element.corner = *to; point_scale(&p, rend_obj->magnify); point_sub(&rend_obj->element.corner, &p); rendobj_update_data(rend_obj); } static void rendobj_draw(RenderObject *rend_obj, Renderer *renderer) { render_store_render(rend_obj->desc->store, renderer, &rend_obj->element.corner, rend_obj->magnify); if ( (rend_obj->desc->use_text) && (!text_is_empty(rend_obj->text)) ) text_draw(rend_obj->text, renderer); } static void rendobj_update_data(RenderObject *rend_obj) { Point p; const RenderObjectDescriptor *desc; Element *elem; Object *obj; int i; elem = &rend_obj->element; obj = &elem->object; desc = rend_obj->desc; rend_obj->magnify = elem->width / rend_obj->desc->width; /* Update connections: */ for (i=0;inum_connection_points;i++) { rend_obj->connections[i].pos = desc->connection_points[i]; point_scale(&rend_obj->connections[i].pos, rend_obj->magnify); point_add(&rend_obj->connections[i].pos, &elem->corner); } if (desc->use_text) { p = desc->text_pos; point_scale(&p, rend_obj->magnify); point_add(&p, &elem->corner); p.y += rend_obj->text->ascent; text_set_position(rend_obj->text, &p); } element_update_boundingbox(elem); /* fix boundingbox for extra_border: */ obj->bounding_box.top -= desc->extra_border; obj->bounding_box.left -= desc->extra_border; obj->bounding_box.bottom += desc->extra_border; obj->bounding_box.right += desc->extra_border; if (desc->use_text) { Rectangle text_box; text_calc_boundingbox(rend_obj->text, &text_box); rectangle_union(&obj->bounding_box, &text_box); } obj->position = elem->corner; p = desc->move_position; point_scale(&p, rend_obj->magnify); point_add(&obj->position, &p); element_update_handles(elem); }