1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: OGL Constraint classes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "constrnt.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include <wx/wxprec.h>
28 #include <wx/wxexpr.h>
35 wxList
*OGLConstraintTypes
= NULL
;
42 IMPLEMENT_DYNAMIC_CLASS(OGLConstraintType
, wxObject
)
44 OGLConstraintType::OGLConstraintType(int theType
, const wxString
& theName
, const wxString
& thePhrase
)
51 OGLConstraintType::~OGLConstraintType()
55 void OGLInitializeConstraintTypes()
57 if (!OGLConstraintTypes
)
60 OGLConstraintTypes
= new wxList(wxKEY_INTEGER
);
62 OGLConstraintTypes
->Append(gyCONSTRAINT_CENTRED_VERTICALLY
,
63 new OGLConstraintType(gyCONSTRAINT_CENTRED_VERTICALLY
, "Centre vertically", "centred vertically w.r.t."));
65 OGLConstraintTypes
->Append(gyCONSTRAINT_CENTRED_HORIZONTALLY
,
66 new OGLConstraintType(gyCONSTRAINT_CENTRED_HORIZONTALLY
, "Centre horizontally", "centred horizontally w.r.t."));
68 OGLConstraintTypes
->Append(gyCONSTRAINT_CENTRED_BOTH
,
69 new OGLConstraintType(gyCONSTRAINT_CENTRED_BOTH
, "Centre", "centred w.r.t."));
71 OGLConstraintTypes
->Append(gyCONSTRAINT_LEFT_OF
,
72 new OGLConstraintType(gyCONSTRAINT_LEFT_OF
, "Left of", "left of"));
74 OGLConstraintTypes
->Append(gyCONSTRAINT_RIGHT_OF
,
75 new OGLConstraintType(gyCONSTRAINT_RIGHT_OF
, "Right of", "right of"));
77 OGLConstraintTypes
->Append(gyCONSTRAINT_ABOVE
,
78 new OGLConstraintType(gyCONSTRAINT_ABOVE
, "Above", "above"));
80 OGLConstraintTypes
->Append(gyCONSTRAINT_BELOW
,
81 new OGLConstraintType(gyCONSTRAINT_BELOW
, "Below", "below"));
84 OGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_TOP
,
85 new OGLConstraintType(gyCONSTRAINT_ALIGNED_TOP
, "Top-aligned", "aligned to the top of"));
87 OGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_BOTTOM
,
88 new OGLConstraintType(gyCONSTRAINT_ALIGNED_BOTTOM
, "Bottom-aligned", "aligned to the bottom of"));
90 OGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_LEFT
,
91 new OGLConstraintType(gyCONSTRAINT_ALIGNED_LEFT
, "Left-aligned", "aligned to the left of"));
93 OGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_RIGHT
,
94 new OGLConstraintType(gyCONSTRAINT_ALIGNED_RIGHT
, "Right-aligned", "aligned to the right of"));
97 OGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_TOP
,
98 new OGLConstraintType(gyCONSTRAINT_MIDALIGNED_TOP
, "Top-midaligned", "centred on the top of"));
100 OGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_BOTTOM
,
101 new OGLConstraintType(gyCONSTRAINT_MIDALIGNED_BOTTOM
, "Bottom-midaligned", "centred on the bottom of"));
103 OGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_LEFT
,
104 new OGLConstraintType(gyCONSTRAINT_MIDALIGNED_LEFT
, "Left-midaligned", "centred on the left of"));
106 OGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_RIGHT
,
107 new OGLConstraintType(gyCONSTRAINT_MIDALIGNED_RIGHT
, "Right-midaligned", "centred on the right of"));
110 void OGLCleanUpConstraintTypes()
112 if (!OGLConstraintTypes
)
115 wxNode
* node
= OGLConstraintTypes
->First();
118 OGLConstraintType
* ct
= (OGLConstraintType
*) node
->Data();
122 delete OGLConstraintTypes
;
123 OGLConstraintTypes
= NULL
;
131 IMPLEMENT_DYNAMIC_CLASS(OGLConstraint
, wxObject
)
133 OGLConstraint::OGLConstraint(int type
, wxShape
*constraining
, wxList
& constrained
)
138 m_constraintType
= type
;
139 m_constrainingObject
= constraining
;
142 m_constraintName
= "noname";
144 wxNode
*node
= constrained
.First();
147 m_constrainedObjects
.Append(node
->Data());
152 OGLConstraint::~OGLConstraint()
156 bool OGLConstraint::Equals(double a
, double b
)
160 bool eq
= ((b
<= a
+ marg
) && (b
>= a
- marg
));
164 // Return TRUE if anything changed
165 bool OGLConstraint::Evaluate()
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();
173 wxClientDC
dc(m_constrainingObject
->GetCanvas());
174 m_constrainingObject
->GetCanvas()->PrepareDC(dc
);
176 switch (m_constraintType
)
178 case gyCONSTRAINT_CENTRED_VERTICALLY
:
180 int n
= m_constrainedObjects
.Number();
181 double totalObjectHeight
= 0.0;
182 wxNode
*node
= m_constrainedObjects
.First();
185 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
187 double width2
, height2
;
188 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
189 totalObjectHeight
+= height2
;
194 // Check if within the constraining object...
195 if ((totalObjectHeight
+ (n
+ 1)*m_ySpacing
) <= minHeight
)
197 spacingY
= (double)((minHeight
- totalObjectHeight
)/(n
+ 1));
198 startY
= (double)(y
- (minHeight
/2.0));
200 // Otherwise, use default spacing
203 spacingY
= m_ySpacing
;
204 startY
= (double)(y
- ((totalObjectHeight
+ (n
+1)*spacingY
)/2.0));
207 // Now position the objects
208 bool changed
= FALSE
;
209 node
= m_constrainedObjects
.First();
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()))
218 constrainedObject
->Move(dc
, constrainedObject
->GetX(), startY
, FALSE
);
221 startY
+= (double)(height2
/2.0);
226 case gyCONSTRAINT_CENTRED_HORIZONTALLY
:
228 int n
= m_constrainedObjects
.Number();
229 double totalObjectWidth
= 0.0;
230 wxNode
*node
= m_constrainedObjects
.First();
233 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
235 double width2
, height2
;
236 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
237 totalObjectWidth
+= width2
;
242 // Check if within the constraining object...
243 if ((totalObjectWidth
+ (n
+ 1)*m_xSpacing
) <= minWidth
)
245 spacingX
= (double)((minWidth
- totalObjectWidth
)/(n
+ 1));
246 startX
= (double)(x
- (minWidth
/2.0));
248 // Otherwise, use default spacing
251 spacingX
= m_xSpacing
;
252 startX
= (double)(x
- ((totalObjectWidth
+ (n
+1)*spacingX
)/2.0));
255 // Now position the objects
256 bool changed
= FALSE
;
257 node
= m_constrainedObjects
.First();
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()))
266 constrainedObject
->Move(dc
, startX
, constrainedObject
->GetY(), FALSE
);
269 startX
+= (double)(width2
/2.0);
274 case gyCONSTRAINT_CENTRED_BOTH
:
276 int n
= m_constrainedObjects
.Number();
277 double totalObjectWidth
= 0.0;
278 double totalObjectHeight
= 0.0;
279 wxNode
*node
= m_constrainedObjects
.First();
282 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
284 double width2
, height2
;
285 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
286 totalObjectWidth
+= width2
;
287 totalObjectHeight
+= height2
;
295 // Check if within the constraining object...
296 if ((totalObjectWidth
+ (n
+ 1)*m_xSpacing
) <= minWidth
)
298 spacingX
= (double)((minWidth
- totalObjectWidth
)/(n
+ 1));
299 startX
= (double)(x
- (minWidth
/2.0));
301 // Otherwise, use default spacing
304 spacingX
= m_xSpacing
;
305 startX
= (double)(x
- ((totalObjectWidth
+ (n
+1)*spacingX
)/2.0));
308 // Check if within the constraining object...
309 if ((totalObjectHeight
+ (n
+ 1)*m_ySpacing
) <= minHeight
)
311 spacingY
= (double)((minHeight
- totalObjectHeight
)/(n
+ 1));
312 startY
= (double)(y
- (minHeight
/2.0));
314 // Otherwise, use default spacing
317 spacingY
= m_ySpacing
;
318 startY
= (double)(y
- ((totalObjectHeight
+ (n
+1)*spacingY
)/2.0));
321 // Now position the objects
322 bool changed
= FALSE
;
323 node
= m_constrainedObjects
.First();
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));
332 if ((!Equals(startX
, constrainedObject
->GetX())) || (!Equals(startY
, constrainedObject
->GetY())))
334 constrainedObject
->Move(dc
, startX
, startY
, FALSE
);
338 startX
+= (double)(width2
/2.0);
339 startY
+= (double)(height2
/2.0);
345 case gyCONSTRAINT_LEFT_OF
:
347 bool changed
= FALSE
;
349 wxNode
*node
= m_constrainedObjects
.First();
352 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
354 double width2
, height2
;
355 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
357 double x3
= (double)(x
- (minWidth
/2.0) - (width2
/2.0) - m_xSpacing
);
358 if (!Equals(x3
, constrainedObject
->GetX()))
361 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
368 case gyCONSTRAINT_RIGHT_OF
:
370 bool changed
= FALSE
;
372 wxNode
*node
= m_constrainedObjects
.First();
375 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
377 double width2
, height2
;
378 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
380 double x3
= (double)(x
+ (minWidth
/2.0) + (width2
/2.0) + m_xSpacing
);
381 if (!Equals(x3
, constrainedObject
->GetX()))
384 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
393 case gyCONSTRAINT_ABOVE
:
395 bool changed
= FALSE
;
397 wxNode
*node
= m_constrainedObjects
.First();
400 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
402 double width2
, height2
;
403 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
405 double y3
= (double)(y
- (minHeight
/2.0) - (height2
/2.0) - m_ySpacing
);
406 if (!Equals(y3
, constrainedObject
->GetY()))
409 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
416 case gyCONSTRAINT_BELOW
:
418 bool changed
= FALSE
;
420 wxNode
*node
= m_constrainedObjects
.First();
423 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
425 double width2
, height2
;
426 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
428 double y3
= (double)(y
+ (minHeight
/2.0) + (height2
/2.0) + m_ySpacing
);
429 if (!Equals(y3
, constrainedObject
->GetY()))
432 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
439 case gyCONSTRAINT_ALIGNED_LEFT
:
441 bool changed
= FALSE
;
443 wxNode
*node
= m_constrainedObjects
.First();
446 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
448 double width2
, height2
;
449 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
451 double x3
= (double)(x
- (minWidth
/2.0) + (width2
/2.0) + m_xSpacing
);
452 if (!Equals(x3
, constrainedObject
->GetX()))
455 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
462 case gyCONSTRAINT_ALIGNED_RIGHT
:
464 bool changed
= FALSE
;
466 wxNode
*node
= m_constrainedObjects
.First();
469 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
471 double width2
, height2
;
472 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
474 double x3
= (double)(x
+ (minWidth
/2.0) - (width2
/2.0) - m_xSpacing
);
475 if (!Equals(x3
, constrainedObject
->GetX()))
478 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
487 case gyCONSTRAINT_ALIGNED_TOP
:
489 bool changed
= FALSE
;
491 wxNode
*node
= m_constrainedObjects
.First();
494 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
496 double width2
, height2
;
497 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
499 double y3
= (double)(y
- (minHeight
/2.0) + (height2
/2.0) + m_ySpacing
);
500 if (!Equals(y3
, constrainedObject
->GetY()))
503 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
510 case gyCONSTRAINT_ALIGNED_BOTTOM
:
512 bool changed
= FALSE
;
514 wxNode
*node
= m_constrainedObjects
.First();
517 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
519 double width2
, height2
;
520 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
522 double y3
= (double)(y
+ (minHeight
/2.0) - (height2
/2.0) - m_ySpacing
);
523 if (!Equals(y3
, constrainedObject
->GetY()))
526 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
533 case gyCONSTRAINT_MIDALIGNED_LEFT
:
535 bool changed
= FALSE
;
537 wxNode
*node
= m_constrainedObjects
.First();
540 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
542 double x3
= (double)(x
- (minWidth
/2.0));
543 if (!Equals(x3
, constrainedObject
->GetX()))
546 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
553 case gyCONSTRAINT_MIDALIGNED_RIGHT
:
555 bool changed
= FALSE
;
557 wxNode
*node
= m_constrainedObjects
.First();
560 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
562 double x3
= (double)(x
+ (minWidth
/2.0));
563 if (!Equals(x3
, constrainedObject
->GetX()))
566 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
575 case gyCONSTRAINT_MIDALIGNED_TOP
:
577 bool changed
= FALSE
;
579 wxNode
*node
= m_constrainedObjects
.First();
582 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
584 double y3
= (double)(y
- (minHeight
/2.0));
585 if (!Equals(y3
, constrainedObject
->GetY()))
588 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
595 case gyCONSTRAINT_MIDALIGNED_BOTTOM
:
597 bool changed
= FALSE
;
599 wxNode
*node
= m_constrainedObjects
.First();
602 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
604 double y3
= (double)(y
+ (minHeight
/2.0));
605 if (!Equals(y3
, constrainedObject
->GetY()))
608 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);