]> git.saurik.com Git - wxWidgets.git/blob - utils/ogl/src/constrnt.cpp
OGL improvements
[wxWidgets.git] / utils / ogl / src / constrnt.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: constrnt.cpp
3 // Purpose: OGL Constraint classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 12/07/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "constrnt.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include <wx/wxprec.h>
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include <wx/wx.h>
25 #endif
26
27 #ifdef PROLOGIO
28 #include <wx/wxexpr.h>
29 #endif
30
31 #include "basic.h"
32 #include "constrnt.h"
33 #include "canvas.h"
34
35 wxList *OGLConstraintTypes = NULL;
36
37 /*
38 * Constraint type
39 *
40 */
41
42 IMPLEMENT_DYNAMIC_CLASS(OGLConstraintType, wxObject)
43
44 OGLConstraintType::OGLConstraintType(int theType, const wxString& theName, const wxString& thePhrase)
45 {
46 m_type = theType;
47 m_name = theName;
48 m_phrase = thePhrase;
49 }
50
51 OGLConstraintType::~OGLConstraintType()
52 {
53 }
54
55 void OGLInitializeConstraintTypes()
56 {
57 if (!OGLConstraintTypes)
58 return;
59
60 OGLConstraintTypes = new wxList(wxKEY_INTEGER);
61
62 OGLConstraintTypes->Append(gyCONSTRAINT_CENTRED_VERTICALLY,
63 new OGLConstraintType(gyCONSTRAINT_CENTRED_VERTICALLY, "Centre vertically", "centred vertically w.r.t."));
64
65 OGLConstraintTypes->Append(gyCONSTRAINT_CENTRED_HORIZONTALLY,
66 new OGLConstraintType(gyCONSTRAINT_CENTRED_HORIZONTALLY, "Centre horizontally", "centred horizontally w.r.t."));
67
68 OGLConstraintTypes->Append(gyCONSTRAINT_CENTRED_BOTH,
69 new OGLConstraintType(gyCONSTRAINT_CENTRED_BOTH, "Centre", "centred w.r.t."));
70
71 OGLConstraintTypes->Append(gyCONSTRAINT_LEFT_OF,
72 new OGLConstraintType(gyCONSTRAINT_LEFT_OF, "Left of", "left of"));
73
74 OGLConstraintTypes->Append(gyCONSTRAINT_RIGHT_OF,
75 new OGLConstraintType(gyCONSTRAINT_RIGHT_OF, "Right of", "right of"));
76
77 OGLConstraintTypes->Append(gyCONSTRAINT_ABOVE,
78 new OGLConstraintType(gyCONSTRAINT_ABOVE, "Above", "above"));
79
80 OGLConstraintTypes->Append(gyCONSTRAINT_BELOW,
81 new OGLConstraintType(gyCONSTRAINT_BELOW, "Below", "below"));
82
83 // Alignment
84 OGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_TOP,
85 new OGLConstraintType(gyCONSTRAINT_ALIGNED_TOP, "Top-aligned", "aligned to the top of"));
86
87 OGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_BOTTOM,
88 new OGLConstraintType(gyCONSTRAINT_ALIGNED_BOTTOM, "Bottom-aligned", "aligned to the bottom of"));
89
90 OGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_LEFT,
91 new OGLConstraintType(gyCONSTRAINT_ALIGNED_LEFT, "Left-aligned", "aligned to the left of"));
92
93 OGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_RIGHT,
94 new OGLConstraintType(gyCONSTRAINT_ALIGNED_RIGHT, "Right-aligned", "aligned to the right of"));
95
96 // Mid-alignment
97 OGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_TOP,
98 new OGLConstraintType(gyCONSTRAINT_MIDALIGNED_TOP, "Top-midaligned", "centred on the top of"));
99
100 OGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_BOTTOM,
101 new OGLConstraintType(gyCONSTRAINT_MIDALIGNED_BOTTOM, "Bottom-midaligned", "centred on the bottom of"));
102
103 OGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_LEFT,
104 new OGLConstraintType(gyCONSTRAINT_MIDALIGNED_LEFT, "Left-midaligned", "centred on the left of"));
105
106 OGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_RIGHT,
107 new OGLConstraintType(gyCONSTRAINT_MIDALIGNED_RIGHT, "Right-midaligned", "centred on the right of"));
108 }
109
110 void OGLCleanUpConstraintTypes()
111 {
112 if (!OGLConstraintTypes)
113 return;
114
115 wxNode* node = OGLConstraintTypes->First();
116 while (node)
117 {
118 OGLConstraintType* ct = (OGLConstraintType*) node->Data();
119 delete ct;
120 node = node->Next();
121 }
122 delete OGLConstraintTypes;
123 OGLConstraintTypes = NULL;
124 }
125
126 /*
127 * Constraint Stuff
128 *
129 */
130
131 IMPLEMENT_DYNAMIC_CLASS(OGLConstraint, wxObject)
132
133 OGLConstraint::OGLConstraint(int type, wxShape *constraining, wxList& constrained)
134 {
135 m_xSpacing = 0.0;
136 m_ySpacing = 0.0;
137
138 m_constraintType = type;
139 m_constrainingObject = constraining;
140
141 m_constraintId = 0;
142 m_constraintName = "noname";
143
144 wxNode *node = constrained.First();
145 while (node)
146 {
147 m_constrainedObjects.Append(node->Data());
148 node = node->Next();
149 }
150 }
151
152 OGLConstraint::~OGLConstraint()
153 {
154 }
155
156 bool OGLConstraint::Equals(double a, double b)
157 {
158 double marg = 0.5;
159
160 bool eq = ((b <= a + marg) && (b >= a - marg));
161 return eq;
162 }
163
164 // Return TRUE if anything changed
165 bool OGLConstraint::Evaluate()
166 {
167 double maxWidth, maxHeight, minWidth, minHeight, x, y;
168 m_constrainingObject->GetBoundingBoxMax(&maxWidth, &maxHeight);
169 m_constrainingObject->GetBoundingBoxMin(&minWidth, &minHeight);
170 x = m_constrainingObject->GetX();
171 y = m_constrainingObject->GetY();
172
173 wxClientDC dc(m_constrainingObject->GetCanvas());
174 m_constrainingObject->GetCanvas()->PrepareDC(dc);
175
176 switch (m_constraintType)
177 {
178 case gyCONSTRAINT_CENTRED_VERTICALLY:
179 {
180 int n = m_constrainedObjects.Number();
181 double totalObjectHeight = 0.0;
182 wxNode *node = m_constrainedObjects.First();
183 while (node)
184 {
185 wxShape *constrainedObject = (wxShape *)node->Data();
186
187 double width2, height2;
188 constrainedObject->GetBoundingBoxMax(&width2, &height2);
189 totalObjectHeight += height2;
190 node = node->Next();
191 }
192 double startY;
193 double spacingY;
194 // Check if within the constraining object...
195 if ((totalObjectHeight + (n + 1)*m_ySpacing) <= minHeight)
196 {
197 spacingY = (double)((minHeight - totalObjectHeight)/(n + 1));
198 startY = (double)(y - (minHeight/2.0));
199 }
200 // Otherwise, use default spacing
201 else
202 {
203 spacingY = m_ySpacing;
204 startY = (double)(y - ((totalObjectHeight + (n+1)*spacingY)/2.0));
205 }
206
207 // Now position the objects
208 bool changed = FALSE;
209 node = m_constrainedObjects.First();
210 while (node)
211 {
212 wxShape *constrainedObject = (wxShape *)node->Data();
213 double width2, height2;
214 constrainedObject->GetBoundingBoxMax(&width2, &height2);
215 startY += (double)(spacingY + (height2/2.0));
216 if (!Equals(startY, constrainedObject->GetY()))
217 {
218 constrainedObject->Move(dc, constrainedObject->GetX(), startY, FALSE);
219 changed = TRUE;
220 }
221 startY += (double)(height2/2.0);
222 node = node->Next();
223 }
224 return changed;
225 }
226 case gyCONSTRAINT_CENTRED_HORIZONTALLY:
227 {
228 int n = m_constrainedObjects.Number();
229 double totalObjectWidth = 0.0;
230 wxNode *node = m_constrainedObjects.First();
231 while (node)
232 {
233 wxShape *constrainedObject = (wxShape *)node->Data();
234
235 double width2, height2;
236 constrainedObject->GetBoundingBoxMax(&width2, &height2);
237 totalObjectWidth += width2;
238 node = node->Next();
239 }
240 double startX;
241 double spacingX;
242 // Check if within the constraining object...
243 if ((totalObjectWidth + (n + 1)*m_xSpacing) <= minWidth)
244 {
245 spacingX = (double)((minWidth - totalObjectWidth)/(n + 1));
246 startX = (double)(x - (minWidth/2.0));
247 }
248 // Otherwise, use default spacing
249 else
250 {
251 spacingX = m_xSpacing;
252 startX = (double)(x - ((totalObjectWidth + (n+1)*spacingX)/2.0));
253 }
254
255 // Now position the objects
256 bool changed = FALSE;
257 node = m_constrainedObjects.First();
258 while (node)
259 {
260 wxShape *constrainedObject = (wxShape *)node->Data();
261 double width2, height2;
262 constrainedObject->GetBoundingBoxMax(&width2, &height2);
263 startX += (double)(spacingX + (width2/2.0));
264 if (!Equals(startX, constrainedObject->GetX()))
265 {
266 constrainedObject->Move(dc, startX, constrainedObject->GetY(), FALSE);
267 changed = TRUE;
268 }
269 startX += (double)(width2/2.0);
270 node = node->Next();
271 }
272 return changed;
273 }
274 case gyCONSTRAINT_CENTRED_BOTH:
275 {
276 int n = m_constrainedObjects.Number();
277 double totalObjectWidth = 0.0;
278 double totalObjectHeight = 0.0;
279 wxNode *node = m_constrainedObjects.First();
280 while (node)
281 {
282 wxShape *constrainedObject = (wxShape *)node->Data();
283
284 double width2, height2;
285 constrainedObject->GetBoundingBoxMax(&width2, &height2);
286 totalObjectWidth += width2;
287 totalObjectHeight += height2;
288 node = node->Next();
289 }
290 double startX;
291 double spacingX;
292 double startY;
293 double spacingY;
294
295 // Check if within the constraining object...
296 if ((totalObjectWidth + (n + 1)*m_xSpacing) <= minWidth)
297 {
298 spacingX = (double)((minWidth - totalObjectWidth)/(n + 1));
299 startX = (double)(x - (minWidth/2.0));
300 }
301 // Otherwise, use default spacing
302 else
303 {
304 spacingX = m_xSpacing;
305 startX = (double)(x - ((totalObjectWidth + (n+1)*spacingX)/2.0));
306 }
307
308 // Check if within the constraining object...
309 if ((totalObjectHeight + (n + 1)*m_ySpacing) <= minHeight)
310 {
311 spacingY = (double)((minHeight - totalObjectHeight)/(n + 1));
312 startY = (double)(y - (minHeight/2.0));
313 }
314 // Otherwise, use default spacing
315 else
316 {
317 spacingY = m_ySpacing;
318 startY = (double)(y - ((totalObjectHeight + (n+1)*spacingY)/2.0));
319 }
320
321 // Now position the objects
322 bool changed = FALSE;
323 node = m_constrainedObjects.First();
324 while (node)
325 {
326 wxShape *constrainedObject = (wxShape *)node->Data();
327 double width2, height2;
328 constrainedObject->GetBoundingBoxMax(&width2, &height2);
329 startX += (double)(spacingX + (width2/2.0));
330 startY += (double)(spacingY + (height2/2.0));
331
332 if ((!Equals(startX, constrainedObject->GetX())) || (!Equals(startY, constrainedObject->GetY())))
333 {
334 constrainedObject->Move(dc, startX, startY, FALSE);
335 changed = TRUE;
336 }
337
338 startX += (double)(width2/2.0);
339 startY += (double)(height2/2.0);
340
341 node = node->Next();
342 }
343 return changed;
344 }
345 case gyCONSTRAINT_LEFT_OF:
346 {
347 bool changed = FALSE;
348
349 wxNode *node = m_constrainedObjects.First();
350 while (node)
351 {
352 wxShape *constrainedObject = (wxShape *)node->Data();
353
354 double width2, height2;
355 constrainedObject->GetBoundingBoxMax(&width2, &height2);
356
357 double x3 = (double)(x - (minWidth/2.0) - (width2/2.0) - m_xSpacing);
358 if (!Equals(x3, constrainedObject->GetX()))
359 {
360 changed = TRUE;
361 constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE);
362 }
363
364 node = node->Next();
365 }
366 return changed;
367 }
368 case gyCONSTRAINT_RIGHT_OF:
369 {
370 bool changed = FALSE;
371
372 wxNode *node = m_constrainedObjects.First();
373 while (node)
374 {
375 wxShape *constrainedObject = (wxShape *)node->Data();
376
377 double width2, height2;
378 constrainedObject->GetBoundingBoxMax(&width2, &height2);
379
380 double x3 = (double)(x + (minWidth/2.0) + (width2/2.0) + m_xSpacing);
381 if (!Equals(x3, constrainedObject->GetX()))
382 {
383 changed = TRUE;
384 constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE);
385 }
386
387 node = node->Next();
388 }
389 return changed;
390
391 return FALSE;
392 }
393 case gyCONSTRAINT_ABOVE:
394 {
395 bool changed = FALSE;
396
397 wxNode *node = m_constrainedObjects.First();
398 while (node)
399 {
400 wxShape *constrainedObject = (wxShape *)node->Data();
401
402 double width2, height2;
403 constrainedObject->GetBoundingBoxMax(&width2, &height2);
404
405 double y3 = (double)(y - (minHeight/2.0) - (height2/2.0) - m_ySpacing);
406 if (!Equals(y3, constrainedObject->GetY()))
407 {
408 changed = TRUE;
409 constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE);
410 }
411
412 node = node->Next();
413 }
414 return changed;
415 }
416 case gyCONSTRAINT_BELOW:
417 {
418 bool changed = FALSE;
419
420 wxNode *node = m_constrainedObjects.First();
421 while (node)
422 {
423 wxShape *constrainedObject = (wxShape *)node->Data();
424
425 double width2, height2;
426 constrainedObject->GetBoundingBoxMax(&width2, &height2);
427
428 double y3 = (double)(y + (minHeight/2.0) + (height2/2.0) + m_ySpacing);
429 if (!Equals(y3, constrainedObject->GetY()))
430 {
431 changed = TRUE;
432 constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE);
433 }
434
435 node = node->Next();
436 }
437 return changed;
438 }
439 case gyCONSTRAINT_ALIGNED_LEFT:
440 {
441 bool changed = FALSE;
442
443 wxNode *node = m_constrainedObjects.First();
444 while (node)
445 {
446 wxShape *constrainedObject = (wxShape *)node->Data();
447
448 double width2, height2;
449 constrainedObject->GetBoundingBoxMax(&width2, &height2);
450
451 double x3 = (double)(x - (minWidth/2.0) + (width2/2.0) + m_xSpacing);
452 if (!Equals(x3, constrainedObject->GetX()))
453 {
454 changed = TRUE;
455 constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE);
456 }
457
458 node = node->Next();
459 }
460 return changed;
461 }
462 case gyCONSTRAINT_ALIGNED_RIGHT:
463 {
464 bool changed = FALSE;
465
466 wxNode *node = m_constrainedObjects.First();
467 while (node)
468 {
469 wxShape *constrainedObject = (wxShape *)node->Data();
470
471 double width2, height2;
472 constrainedObject->GetBoundingBoxMax(&width2, &height2);
473
474 double x3 = (double)(x + (minWidth/2.0) - (width2/2.0) - m_xSpacing);
475 if (!Equals(x3, constrainedObject->GetX()))
476 {
477 changed = TRUE;
478 constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE);
479 }
480
481 node = node->Next();
482 }
483 return changed;
484
485 return FALSE;
486 }
487 case gyCONSTRAINT_ALIGNED_TOP:
488 {
489 bool changed = FALSE;
490
491 wxNode *node = m_constrainedObjects.First();
492 while (node)
493 {
494 wxShape *constrainedObject = (wxShape *)node->Data();
495
496 double width2, height2;
497 constrainedObject->GetBoundingBoxMax(&width2, &height2);
498
499 double y3 = (double)(y - (minHeight/2.0) + (height2/2.0) + m_ySpacing);
500 if (!Equals(y3, constrainedObject->GetY()))
501 {
502 changed = TRUE;
503 constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE);
504 }
505
506 node = node->Next();
507 }
508 return changed;
509 }
510 case gyCONSTRAINT_ALIGNED_BOTTOM:
511 {
512 bool changed = FALSE;
513
514 wxNode *node = m_constrainedObjects.First();
515 while (node)
516 {
517 wxShape *constrainedObject = (wxShape *)node->Data();
518
519 double width2, height2;
520 constrainedObject->GetBoundingBoxMax(&width2, &height2);
521
522 double y3 = (double)(y + (minHeight/2.0) - (height2/2.0) - m_ySpacing);
523 if (!Equals(y3, constrainedObject->GetY()))
524 {
525 changed = TRUE;
526 constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE);
527 }
528
529 node = node->Next();
530 }
531 return changed;
532 }
533 case gyCONSTRAINT_MIDALIGNED_LEFT:
534 {
535 bool changed = FALSE;
536
537 wxNode *node = m_constrainedObjects.First();
538 while (node)
539 {
540 wxShape *constrainedObject = (wxShape *)node->Data();
541
542 double x3 = (double)(x - (minWidth/2.0));
543 if (!Equals(x3, constrainedObject->GetX()))
544 {
545 changed = TRUE;
546 constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE);
547 }
548
549 node = node->Next();
550 }
551 return changed;
552 }
553 case gyCONSTRAINT_MIDALIGNED_RIGHT:
554 {
555 bool changed = FALSE;
556
557 wxNode *node = m_constrainedObjects.First();
558 while (node)
559 {
560 wxShape *constrainedObject = (wxShape *)node->Data();
561
562 double x3 = (double)(x + (minWidth/2.0));
563 if (!Equals(x3, constrainedObject->GetX()))
564 {
565 changed = TRUE;
566 constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE);
567 }
568
569 node = node->Next();
570 }
571 return changed;
572
573 return FALSE;
574 }
575 case gyCONSTRAINT_MIDALIGNED_TOP:
576 {
577 bool changed = FALSE;
578
579 wxNode *node = m_constrainedObjects.First();
580 while (node)
581 {
582 wxShape *constrainedObject = (wxShape *)node->Data();
583
584 double y3 = (double)(y - (minHeight/2.0));
585 if (!Equals(y3, constrainedObject->GetY()))
586 {
587 changed = TRUE;
588 constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE);
589 }
590
591 node = node->Next();
592 }
593 return changed;
594 }
595 case gyCONSTRAINT_MIDALIGNED_BOTTOM:
596 {
597 bool changed = FALSE;
598
599 wxNode *node = m_constrainedObjects.First();
600 while (node)
601 {
602 wxShape *constrainedObject = (wxShape *)node->Data();
603
604 double y3 = (double)(y + (minHeight/2.0));
605 if (!Equals(y3, constrainedObject->GetY()))
606 {
607 changed = TRUE;
608 constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE);
609 }
610
611 node = node->Next();
612 }
613 return changed;
614 }
615
616 default:
617 return FALSE;
618 }
619 return FALSE;
620 }
621