don't include dlfcn.h on win32
[dia.git] / lib / element.c
blobc78056e36539d9f12fc4e7465bd1ea7a103c0851
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 #include <config.h>
20 #include <stdio.h>
21 #include <assert.h>
22 #include <math.h>
23 #include <string.h> /* memcpy() */
25 #include "element.h"
26 #include "message.h"
28 void
29 element_update_boundingbox(Element *elem) {
30 Rectangle bb;
31 Point *corner;
32 ElementBBExtras *extra = &elem->extra_spacing;
34 assert(elem != NULL);
36 corner = &elem->corner;
37 bb.left = corner->x;
38 bb.right = corner->x + elem->width;
39 bb.top = corner->y;
40 bb.bottom = corner->y + elem->height;
42 rectangle_bbox(&bb,extra,&elem->object.bounding_box);
45 void
46 element_update_handles(Element *elem)
48 Point *corner = &elem->corner;
50 elem->resize_handles[0].id = HANDLE_RESIZE_NW;
51 elem->resize_handles[0].pos.x = corner->x;
52 elem->resize_handles[0].pos.y = corner->y;
54 elem->resize_handles[1].id = HANDLE_RESIZE_N;
55 elem->resize_handles[1].pos.x = corner->x + elem->width/2.0;
56 elem->resize_handles[1].pos.y = corner->y;
58 elem->resize_handles[2].id = HANDLE_RESIZE_NE;
59 elem->resize_handles[2].pos.x = corner->x + elem->width;
60 elem->resize_handles[2].pos.y = corner->y;
62 elem->resize_handles[3].id = HANDLE_RESIZE_W;
63 elem->resize_handles[3].pos.x = corner->x;
64 elem->resize_handles[3].pos.y = corner->y + elem->height/2.0;
66 elem->resize_handles[4].id = HANDLE_RESIZE_E;
67 elem->resize_handles[4].pos.x = corner->x + elem->width;
68 elem->resize_handles[4].pos.y = corner->y + elem->height/2.0;
70 elem->resize_handles[5].id = HANDLE_RESIZE_SW;
71 elem->resize_handles[5].pos.x = corner->x;
72 elem->resize_handles[5].pos.y = corner->y + elem->height;
74 elem->resize_handles[6].id = HANDLE_RESIZE_S;
75 elem->resize_handles[6].pos.x = corner->x + elem->width/2.0;
76 elem->resize_handles[6].pos.y = corner->y + elem->height;
78 elem->resize_handles[7].id = HANDLE_RESIZE_SE;
79 elem->resize_handles[7].pos.x = corner->x + elem->width;
80 elem->resize_handles[7].pos.y = corner->y + elem->height;
83 void
84 element_move_handle(Element *elem, HandleId id,
85 Point *to, HandleMoveReason reason)
87 Point p;
88 Point *corner;
90 assert(id>=HANDLE_RESIZE_NW);
91 assert(id<=HANDLE_RESIZE_SE);
93 corner = &elem->corner;
95 p = *to;
96 point_sub(&p, &elem->corner);
98 switch(id) {
99 case HANDLE_RESIZE_NW:
100 if ( to->x < (corner->x+elem->width)) {
101 corner->x += p.x;
102 elem->width -= p.x;
104 if ( to->y < (corner->y+elem->height)) {
105 corner->y += p.y;
106 elem->height -= p.y;
108 break;
109 case HANDLE_RESIZE_N:
110 if ( to->y < (corner->y+elem->height)) {
111 corner->y += p.y;
112 elem->height -= p.y;
114 break;
115 case HANDLE_RESIZE_NE:
116 if (p.x>0.0)
117 elem->width = p.x;
118 if ( to->y < (corner->y+elem->height)) {
119 corner->y += p.y;
120 elem->height -= p.y;
122 break;
123 case HANDLE_RESIZE_W:
124 if ( to->x < (corner->x+elem->width)) {
125 corner->x += p.x;
126 elem->width -= p.x;
128 break;
129 case HANDLE_RESIZE_E:
130 if (p.x>0.0)
131 elem->width = p.x;
132 break;
133 case HANDLE_RESIZE_SW:
134 if ( to->x < (corner->x+elem->width)) {
135 corner->x += p.x;
136 elem->width -= p.x;
138 if (p.y>0.0)
139 elem->height = p.y;
140 break;
141 case HANDLE_RESIZE_S:
142 if (p.y>0.0)
143 elem->height = p.y;
144 break;
145 case HANDLE_RESIZE_SE:
146 if (p.x>0.0)
147 elem->width = p.x;
148 if (p.y>0.0)
149 elem->height = p.y;
150 break;
151 default:
152 message_error("Error, called element_move_handle() with wrong handle-id\n");
156 void
157 element_move_handle_aspect(Element *elem, HandleId id,
158 Point *to, real aspect_ratio)
160 Point p;
161 Point *corner;
162 real width, height;
163 real new_width, new_height;
164 real move_x, move_y;
166 assert(id>=HANDLE_RESIZE_NW);
167 assert(id<=HANDLE_RESIZE_SE);
169 corner = &elem->corner;
171 p = *to;
172 point_sub(&p, &elem->corner);
174 width = elem->width;
175 height = elem->height;
177 new_width = 0.0;
178 new_height = 0.0;
181 switch(id) {
182 case HANDLE_RESIZE_NW:
183 new_width = width - p.x;
184 new_height = height - p.y;
185 move_x = 1.0;
186 move_y = 1.0;
187 break;
188 case HANDLE_RESIZE_N:
189 new_height = height - p.y;
190 move_y = 1.0;
191 move_x = 0.5;
192 break;
193 case HANDLE_RESIZE_NE:
194 new_width = p.x;
195 new_height = height - p.y;
196 move_x = 0.0;
197 move_y = 1.0;
198 break;
199 case HANDLE_RESIZE_W:
200 new_width = width - p.x;
201 move_x = 1.0;
202 move_y = 0.5;
203 break;
204 case HANDLE_RESIZE_E:
205 new_width = p.x;
206 move_x = 0.0;
207 move_y = 0.5;
208 break;
209 case HANDLE_RESIZE_SW:
210 new_width = width - p.x;
211 new_height = p.y;
212 move_x = 1.0;
213 move_y = 0.0;
214 break;
215 case HANDLE_RESIZE_S:
216 new_height = p.y;
217 move_x = 0.5;
218 move_y = 0.0;
219 break;
220 case HANDLE_RESIZE_SE:
221 new_width = p.x;
222 new_height = p.y;
223 move_x = 0.0;
224 move_y = 0.0;
225 break;
226 default:
227 message_error("Error, called element_move_handle() with wrong handle-id\n");
230 /* Which of the two versions to use: */
231 if (new_width > new_height*aspect_ratio) {
232 new_height = new_width/aspect_ratio;
233 } else {
234 new_width = new_height*aspect_ratio;
237 if ( (new_width<0.0) || (new_height<0.0)) {
238 new_width = 0.0;
239 new_height = 0.0;
242 corner->x -= (new_width - width)*move_x;
243 corner->y -= (new_height - height)*move_y;
245 elem->width = new_width;
246 elem->height = new_height;
249 /* Needs to have the first 8 handles */
250 void
251 element_init(Element *elem, int num_handles, int num_connections)
253 Object *obj;
254 int i;
256 obj = &elem->object;
258 assert(num_handles>=8);
260 object_init(obj, num_handles, num_connections);
262 for (i=0;i<8;i++) {
263 obj->handles[i] = &elem->resize_handles[i];
264 obj->handles[i]->connect_type = HANDLE_NONCONNECTABLE;
265 obj->handles[i]->connected_to = NULL;
266 obj->handles[i]->type = HANDLE_MAJOR_CONTROL;
270 void
271 element_copy(Element *from, Element *to)
273 Object *toobj, *fromobj;
274 int i;
276 fromobj = &from->object;
277 toobj = &to->object;
279 object_copy(fromobj, toobj);
281 to->corner = from->corner;
282 to->width = from->width;
283 to->height = from->height;
285 for (i=0;i<8;i++) {
286 to->resize_handles[i] = from->resize_handles[i];
287 to->resize_handles[i].connected_to = NULL;
288 toobj->handles[i] = &to->resize_handles[i];
290 memcpy(&to->extra_spacing,&from->extra_spacing,sizeof(to->extra_spacing));
293 void
294 element_destroy(Element *elem)
296 object_destroy(&elem->object);
300 void element_save(Element *elem, ObjectNode obj_node)
302 object_save(&elem->object, obj_node);
304 data_add_point(new_attribute(obj_node, "elem_corner"),
305 &elem->corner);
306 data_add_real(new_attribute(obj_node, "elem_width"),
307 elem->width);
308 data_add_real(new_attribute(obj_node, "elem_height"),
309 elem->height);
312 void element_load(Element *elem, ObjectNode obj_node)
314 AttributeNode attr;
316 object_load(&elem->object, obj_node);
318 elem->corner.x = 0.0;
319 elem->corner.y = 0.0;
320 attr = object_find_attribute(obj_node, "elem_corner");
321 if (attr != NULL)
322 data_point( attribute_first_data(attr), &elem->corner );
324 elem->width = 1.0;
325 attr = object_find_attribute(obj_node, "elem_width");
326 if (attr != NULL)
327 elem->width = data_real( attribute_first_data(attr));
329 elem->height = 1.0;
330 attr = object_find_attribute(obj_node, "elem_height");
331 if (attr != NULL)
332 elem->height = data_real( attribute_first_data(attr));