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(wxKEY_INTEGER
);
42 IMPLEMENT_DYNAMIC_CLASS(OGLConstraintType
, wxObject
)
44 OGLConstraintType::OGLConstraintType(int theType
, const wxString
& theName
, const wxString
& thePhrase
)
51 OGLConstraintType::~OGLConstraintType()
55 void OGLInitializeConstraintTypes()
57 OGLConstraintTypes
.Append(gyCONSTRAINT_CENTRED_VERTICALLY
,
58 new OGLConstraintType(gyCONSTRAINT_CENTRED_VERTICALLY
, "Centre vertically", "centred vertically w.r.t."));
60 OGLConstraintTypes
.Append(gyCONSTRAINT_CENTRED_HORIZONTALLY
,
61 new OGLConstraintType(gyCONSTRAINT_CENTRED_HORIZONTALLY
, "Centre horizontally", "centred horizontally w.r.t."));
63 OGLConstraintTypes
.Append(gyCONSTRAINT_CENTRED_BOTH
,
64 new OGLConstraintType(gyCONSTRAINT_CENTRED_BOTH
, "Centre", "centred w.r.t."));
66 OGLConstraintTypes
.Append(gyCONSTRAINT_LEFT_OF
,
67 new OGLConstraintType(gyCONSTRAINT_LEFT_OF
, "Left of", "left of"));
69 OGLConstraintTypes
.Append(gyCONSTRAINT_RIGHT_OF
,
70 new OGLConstraintType(gyCONSTRAINT_RIGHT_OF
, "Right of", "right of"));
72 OGLConstraintTypes
.Append(gyCONSTRAINT_ABOVE
,
73 new OGLConstraintType(gyCONSTRAINT_ABOVE
, "Above", "above"));
75 OGLConstraintTypes
.Append(gyCONSTRAINT_BELOW
,
76 new OGLConstraintType(gyCONSTRAINT_BELOW
, "Below", "below"));
79 OGLConstraintTypes
.Append(gyCONSTRAINT_ALIGNED_TOP
,
80 new OGLConstraintType(gyCONSTRAINT_ALIGNED_TOP
, "Top-aligned", "aligned to the top of"));
82 OGLConstraintTypes
.Append(gyCONSTRAINT_ALIGNED_BOTTOM
,
83 new OGLConstraintType(gyCONSTRAINT_ALIGNED_BOTTOM
, "Bottom-aligned", "aligned to the bottom of"));
85 OGLConstraintTypes
.Append(gyCONSTRAINT_ALIGNED_LEFT
,
86 new OGLConstraintType(gyCONSTRAINT_ALIGNED_LEFT
, "Left-aligned", "aligned to the left of"));
88 OGLConstraintTypes
.Append(gyCONSTRAINT_ALIGNED_RIGHT
,
89 new OGLConstraintType(gyCONSTRAINT_ALIGNED_RIGHT
, "Right-aligned", "aligned to the right of"));
92 OGLConstraintTypes
.Append(gyCONSTRAINT_MIDALIGNED_TOP
,
93 new OGLConstraintType(gyCONSTRAINT_MIDALIGNED_TOP
, "Top-midaligned", "centred on the top of"));
95 OGLConstraintTypes
.Append(gyCONSTRAINT_MIDALIGNED_BOTTOM
,
96 new OGLConstraintType(gyCONSTRAINT_MIDALIGNED_BOTTOM
, "Bottom-midaligned", "centred on the bottom of"));
98 OGLConstraintTypes
.Append(gyCONSTRAINT_MIDALIGNED_LEFT
,
99 new OGLConstraintType(gyCONSTRAINT_MIDALIGNED_LEFT
, "Left-midaligned", "centred on the left of"));
101 OGLConstraintTypes
.Append(gyCONSTRAINT_MIDALIGNED_RIGHT
,
102 new OGLConstraintType(gyCONSTRAINT_MIDALIGNED_RIGHT
, "Right-midaligned", "centred on the right of"));
110 IMPLEMENT_DYNAMIC_CLASS(OGLConstraint
, wxObject
)
112 OGLConstraint::OGLConstraint(int type
, wxShape
*constraining
, wxList
& constrained
)
117 m_constraintType
= type
;
118 m_constrainingObject
= constraining
;
121 m_constraintName
= "noname";
123 wxNode
*node
= constrained
.First();
126 m_constrainedObjects
.Append(node
->Data());
131 OGLConstraint::~OGLConstraint()
135 bool OGLConstraint::Equals(float a
, float b
)
139 bool eq
= ((b
<= a
+ marg
) && (b
>= a
- marg
));
143 // Return TRUE if anything changed
144 bool OGLConstraint::Evaluate()
146 float maxWidth
, maxHeight
, minWidth
, minHeight
, x
, y
;
147 m_constrainingObject
->GetBoundingBoxMax(&maxWidth
, &maxHeight
);
148 m_constrainingObject
->GetBoundingBoxMin(&minWidth
, &minHeight
);
149 x
= m_constrainingObject
->GetX();
150 y
= m_constrainingObject
->GetY();
152 wxClientDC
dc(m_constrainingObject
->GetCanvas());
153 m_constrainingObject
->GetCanvas()->PrepareDC(dc
);
155 switch (m_constraintType
)
157 case gyCONSTRAINT_CENTRED_VERTICALLY
:
159 int n
= m_constrainedObjects
.Number();
160 float totalObjectHeight
= 0.0;
161 wxNode
*node
= m_constrainedObjects
.First();
164 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
166 float width2
, height2
;
167 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
168 totalObjectHeight
+= height2
;
173 // Check if within the constraining object...
174 if ((totalObjectHeight
+ (n
+ 1)*m_ySpacing
) <= minHeight
)
176 spacingY
= (float)((minHeight
- totalObjectHeight
)/(n
+ 1));
177 startY
= (float)(y
- (minHeight
/2.0));
179 // Otherwise, use default spacing
182 spacingY
= m_ySpacing
;
183 startY
= (float)(y
- ((totalObjectHeight
+ (n
+1)*spacingY
)/2.0));
186 // Now position the objects
187 bool changed
= FALSE
;
188 node
= m_constrainedObjects
.First();
191 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
192 float width2
, height2
;
193 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
194 startY
+= (float)(spacingY
+ (height2
/2.0));
195 if (!Equals(startY
, constrainedObject
->GetY()))
197 constrainedObject
->Move(dc
, constrainedObject
->GetX(), startY
, FALSE
);
200 startY
+= (float)(height2
/2.0);
205 case gyCONSTRAINT_CENTRED_HORIZONTALLY
:
207 int n
= m_constrainedObjects
.Number();
208 float totalObjectWidth
= 0.0;
209 wxNode
*node
= m_constrainedObjects
.First();
212 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
214 float width2
, height2
;
215 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
216 totalObjectWidth
+= width2
;
221 // Check if within the constraining object...
222 if ((totalObjectWidth
+ (n
+ 1)*m_xSpacing
) <= minWidth
)
224 spacingX
= (float)((minWidth
- totalObjectWidth
)/(n
+ 1));
225 startX
= (float)(x
- (minWidth
/2.0));
227 // Otherwise, use default spacing
230 spacingX
= m_xSpacing
;
231 startX
= (float)(x
- ((totalObjectWidth
+ (n
+1)*spacingX
)/2.0));
234 // Now position the objects
235 bool changed
= FALSE
;
236 node
= m_constrainedObjects
.First();
239 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
240 float width2
, height2
;
241 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
242 startX
+= (float)(spacingX
+ (width2
/2.0));
243 if (!Equals(startX
, constrainedObject
->GetX()))
245 constrainedObject
->Move(dc
, startX
, constrainedObject
->GetY(), FALSE
);
248 startX
+= (float)(width2
/2.0);
253 case gyCONSTRAINT_CENTRED_BOTH
:
255 int n
= m_constrainedObjects
.Number();
256 float totalObjectWidth
= 0.0;
257 float totalObjectHeight
= 0.0;
258 wxNode
*node
= m_constrainedObjects
.First();
261 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
263 float width2
, height2
;
264 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
265 totalObjectWidth
+= width2
;
266 totalObjectHeight
+= height2
;
274 // Check if within the constraining object...
275 if ((totalObjectWidth
+ (n
+ 1)*m_xSpacing
) <= minWidth
)
277 spacingX
= (float)((minWidth
- totalObjectWidth
)/(n
+ 1));
278 startX
= (float)(x
- (minWidth
/2.0));
280 // Otherwise, use default spacing
283 spacingX
= m_xSpacing
;
284 startX
= (float)(x
- ((totalObjectWidth
+ (n
+1)*spacingX
)/2.0));
287 // Check if within the constraining object...
288 if ((totalObjectHeight
+ (n
+ 1)*m_ySpacing
) <= minHeight
)
290 spacingY
= (float)((minHeight
- totalObjectHeight
)/(n
+ 1));
291 startY
= (float)(y
- (minHeight
/2.0));
293 // Otherwise, use default spacing
296 spacingY
= m_ySpacing
;
297 startY
= (float)(y
- ((totalObjectHeight
+ (n
+1)*spacingY
)/2.0));
300 // Now position the objects
301 bool changed
= FALSE
;
302 node
= m_constrainedObjects
.First();
305 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
306 float width2
, height2
;
307 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
308 startX
+= (float)(spacingX
+ (width2
/2.0));
309 startY
+= (float)(spacingY
+ (height2
/2.0));
311 if ((!Equals(startX
, constrainedObject
->GetX())) || (!Equals(startY
, constrainedObject
->GetY())))
313 constrainedObject
->Move(dc
, startX
, startY
, FALSE
);
317 startX
+= (float)(width2
/2.0);
318 startY
+= (float)(height2
/2.0);
324 case gyCONSTRAINT_LEFT_OF
:
326 bool changed
= FALSE
;
328 wxNode
*node
= m_constrainedObjects
.First();
331 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
333 float width2
, height2
;
334 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
336 float x3
= (float)(x
- (minWidth
/2.0) - (width2
/2.0) - m_xSpacing
);
337 if (!Equals(x3
, constrainedObject
->GetX()))
340 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
347 case gyCONSTRAINT_RIGHT_OF
:
349 bool changed
= FALSE
;
351 wxNode
*node
= m_constrainedObjects
.First();
354 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
356 float width2
, height2
;
357 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
359 float x3
= (float)(x
+ (minWidth
/2.0) + (width2
/2.0) + m_xSpacing
);
360 if (!Equals(x3
, constrainedObject
->GetX()))
363 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
372 case gyCONSTRAINT_ABOVE
:
374 bool changed
= FALSE
;
376 wxNode
*node
= m_constrainedObjects
.First();
379 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
381 float width2
, height2
;
382 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
384 float y3
= (float)(y
- (minHeight
/2.0) - (height2
/2.0) - m_ySpacing
);
385 if (!Equals(y3
, constrainedObject
->GetY()))
388 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
395 case gyCONSTRAINT_BELOW
:
397 bool changed
= FALSE
;
399 wxNode
*node
= m_constrainedObjects
.First();
402 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
404 float width2
, height2
;
405 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
407 float y3
= (float)(y
+ (minHeight
/2.0) + (height2
/2.0) + m_ySpacing
);
408 if (!Equals(y3
, constrainedObject
->GetY()))
411 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
418 case gyCONSTRAINT_ALIGNED_LEFT
:
420 bool changed
= FALSE
;
422 wxNode
*node
= m_constrainedObjects
.First();
425 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
427 float width2
, height2
;
428 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
430 float x3
= (float)(x
- (minWidth
/2.0) + (width2
/2.0) + m_xSpacing
);
431 if (!Equals(x3
, constrainedObject
->GetX()))
434 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
441 case gyCONSTRAINT_ALIGNED_RIGHT
:
443 bool changed
= FALSE
;
445 wxNode
*node
= m_constrainedObjects
.First();
448 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
450 float width2
, height2
;
451 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
453 float x3
= (float)(x
+ (minWidth
/2.0) - (width2
/2.0) - m_xSpacing
);
454 if (!Equals(x3
, constrainedObject
->GetX()))
457 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
466 case gyCONSTRAINT_ALIGNED_TOP
:
468 bool changed
= FALSE
;
470 wxNode
*node
= m_constrainedObjects
.First();
473 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
475 float width2
, height2
;
476 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
478 float y3
= (float)(y
- (minHeight
/2.0) + (height2
/2.0) + m_ySpacing
);
479 if (!Equals(y3
, constrainedObject
->GetY()))
482 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
489 case gyCONSTRAINT_ALIGNED_BOTTOM
:
491 bool changed
= FALSE
;
493 wxNode
*node
= m_constrainedObjects
.First();
496 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
498 float width2
, height2
;
499 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
501 float y3
= (float)(y
+ (minHeight
/2.0) - (height2
/2.0) - m_ySpacing
);
502 if (!Equals(y3
, constrainedObject
->GetY()))
505 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
512 case gyCONSTRAINT_MIDALIGNED_LEFT
:
514 bool changed
= FALSE
;
516 wxNode
*node
= m_constrainedObjects
.First();
519 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
521 float x3
= (float)(x
- (minWidth
/2.0));
522 if (!Equals(x3
, constrainedObject
->GetX()))
525 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
532 case gyCONSTRAINT_MIDALIGNED_RIGHT
:
534 bool changed
= FALSE
;
536 wxNode
*node
= m_constrainedObjects
.First();
539 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
541 float x3
= (float)(x
+ (minWidth
/2.0));
542 if (!Equals(x3
, constrainedObject
->GetX()))
545 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
554 case gyCONSTRAINT_MIDALIGNED_TOP
:
556 bool changed
= FALSE
;
558 wxNode
*node
= m_constrainedObjects
.First();
561 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
563 float y3
= (float)(y
- (minHeight
/2.0));
564 if (!Equals(y3
, constrainedObject
->GetY()))
567 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
574 case gyCONSTRAINT_MIDALIGNED_BOTTOM
:
576 bool changed
= FALSE
;
578 wxNode
*node
= m_constrainedObjects
.First();
581 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
583 float y3
= (float)(y
+ (minHeight
/2.0));
584 if (!Equals(y3
, constrainedObject
->GetY()))
587 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);