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"
27 #include <wx/wxexpr.h>
29 #include <wx/ogl/basic.h>
30 #include <wx/ogl/constrnt.h>
31 #include <wx/ogl/canvas.h>
33 wxList
*wxOGLConstraintTypes
= NULL
;
40 IMPLEMENT_DYNAMIC_CLASS(wxOGLConstraintType
, wxObject
)
42 wxOGLConstraintType::wxOGLConstraintType(int theType
, const wxString
& theName
, const wxString
& thePhrase
)
49 wxOGLConstraintType::~wxOGLConstraintType()
53 void OGLInitializeConstraintTypes()
55 if (!wxOGLConstraintTypes
)
58 wxOGLConstraintTypes
= new wxList(wxKEY_INTEGER
);
60 wxOGLConstraintTypes
->Append(gyCONSTRAINT_CENTRED_VERTICALLY
,
61 new wxOGLConstraintType(gyCONSTRAINT_CENTRED_VERTICALLY
, "Centre vertically", "centred vertically w.r.t."));
63 wxOGLConstraintTypes
->Append(gyCONSTRAINT_CENTRED_HORIZONTALLY
,
64 new wxOGLConstraintType(gyCONSTRAINT_CENTRED_HORIZONTALLY
, "Centre horizontally", "centred horizontally w.r.t."));
66 wxOGLConstraintTypes
->Append(gyCONSTRAINT_CENTRED_BOTH
,
67 new wxOGLConstraintType(gyCONSTRAINT_CENTRED_BOTH
, "Centre", "centred w.r.t."));
69 wxOGLConstraintTypes
->Append(gyCONSTRAINT_LEFT_OF
,
70 new wxOGLConstraintType(gyCONSTRAINT_LEFT_OF
, "Left of", "left of"));
72 wxOGLConstraintTypes
->Append(gyCONSTRAINT_RIGHT_OF
,
73 new wxOGLConstraintType(gyCONSTRAINT_RIGHT_OF
, "Right of", "right of"));
75 wxOGLConstraintTypes
->Append(gyCONSTRAINT_ABOVE
,
76 new wxOGLConstraintType(gyCONSTRAINT_ABOVE
, "Above", "above"));
78 wxOGLConstraintTypes
->Append(gyCONSTRAINT_BELOW
,
79 new wxOGLConstraintType(gyCONSTRAINT_BELOW
, "Below", "below"));
82 wxOGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_TOP
,
83 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_TOP
, "Top-aligned", "aligned to the top of"));
85 wxOGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_BOTTOM
,
86 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_BOTTOM
, "Bottom-aligned", "aligned to the bottom of"));
88 wxOGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_LEFT
,
89 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_LEFT
, "Left-aligned", "aligned to the left of"));
91 wxOGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_RIGHT
,
92 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_RIGHT
, "Right-aligned", "aligned to the right of"));
95 wxOGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_TOP
,
96 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_TOP
, "Top-midaligned", "centred on the top of"));
98 wxOGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_BOTTOM
,
99 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_BOTTOM
, "Bottom-midaligned", "centred on the bottom of"));
101 wxOGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_LEFT
,
102 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_LEFT
, "Left-midaligned", "centred on the left of"));
104 wxOGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_RIGHT
,
105 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_RIGHT
, "Right-midaligned", "centred on the right of"));
108 void OGLCleanUpConstraintTypes()
110 if (!wxOGLConstraintTypes
)
113 wxNode
* node
= wxOGLConstraintTypes
->First();
116 wxOGLConstraintType
* ct
= (wxOGLConstraintType
*) node
->Data();
120 delete wxOGLConstraintTypes
;
121 wxOGLConstraintTypes
= NULL
;
129 IMPLEMENT_DYNAMIC_CLASS(wxOGLConstraint
, wxObject
)
131 wxOGLConstraint::wxOGLConstraint(int type
, wxShape
*constraining
, wxList
& constrained
)
136 m_constraintType
= type
;
137 m_constrainingObject
= constraining
;
140 m_constraintName
= "noname";
142 wxNode
*node
= constrained
.First();
145 m_constrainedObjects
.Append(node
->Data());
150 wxOGLConstraint::~wxOGLConstraint()
154 bool wxOGLConstraint::Equals(double a
, double b
)
158 bool eq
= ((b
<= a
+ marg
) && (b
>= a
- marg
));
162 // Return TRUE if anything changed
163 bool wxOGLConstraint::Evaluate()
165 double maxWidth
, maxHeight
, minWidth
, minHeight
, x
, y
;
166 m_constrainingObject
->GetBoundingBoxMax(&maxWidth
, &maxHeight
);
167 m_constrainingObject
->GetBoundingBoxMin(&minWidth
, &minHeight
);
168 x
= m_constrainingObject
->GetX();
169 y
= m_constrainingObject
->GetY();
171 wxClientDC
dc(m_constrainingObject
->GetCanvas());
172 m_constrainingObject
->GetCanvas()->PrepareDC(dc
);
174 switch (m_constraintType
)
176 case gyCONSTRAINT_CENTRED_VERTICALLY
:
178 int n
= m_constrainedObjects
.Number();
179 double totalObjectHeight
= 0.0;
180 wxNode
*node
= m_constrainedObjects
.First();
183 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
185 double width2
, height2
;
186 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
187 totalObjectHeight
+= height2
;
192 // Check if within the constraining object...
193 if ((totalObjectHeight
+ (n
+ 1)*m_ySpacing
) <= minHeight
)
195 spacingY
= (double)((minHeight
- totalObjectHeight
)/(n
+ 1));
196 startY
= (double)(y
- (minHeight
/2.0));
198 // Otherwise, use default spacing
201 spacingY
= m_ySpacing
;
202 startY
= (double)(y
- ((totalObjectHeight
+ (n
+1)*spacingY
)/2.0));
205 // Now position the objects
206 bool changed
= FALSE
;
207 node
= m_constrainedObjects
.First();
210 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
211 double width2
, height2
;
212 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
213 startY
+= (double)(spacingY
+ (height2
/2.0));
214 if (!Equals(startY
, constrainedObject
->GetY()))
216 constrainedObject
->Move(dc
, constrainedObject
->GetX(), startY
, FALSE
);
219 startY
+= (double)(height2
/2.0);
224 case gyCONSTRAINT_CENTRED_HORIZONTALLY
:
226 int n
= m_constrainedObjects
.Number();
227 double totalObjectWidth
= 0.0;
228 wxNode
*node
= m_constrainedObjects
.First();
231 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
233 double width2
, height2
;
234 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
235 totalObjectWidth
+= width2
;
240 // Check if within the constraining object...
241 if ((totalObjectWidth
+ (n
+ 1)*m_xSpacing
) <= minWidth
)
243 spacingX
= (double)((minWidth
- totalObjectWidth
)/(n
+ 1));
244 startX
= (double)(x
- (minWidth
/2.0));
246 // Otherwise, use default spacing
249 spacingX
= m_xSpacing
;
250 startX
= (double)(x
- ((totalObjectWidth
+ (n
+1)*spacingX
)/2.0));
253 // Now position the objects
254 bool changed
= FALSE
;
255 node
= m_constrainedObjects
.First();
258 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
259 double width2
, height2
;
260 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
261 startX
+= (double)(spacingX
+ (width2
/2.0));
262 if (!Equals(startX
, constrainedObject
->GetX()))
264 constrainedObject
->Move(dc
, startX
, constrainedObject
->GetY(), FALSE
);
267 startX
+= (double)(width2
/2.0);
272 case gyCONSTRAINT_CENTRED_BOTH
:
274 int n
= m_constrainedObjects
.Number();
275 double totalObjectWidth
= 0.0;
276 double totalObjectHeight
= 0.0;
277 wxNode
*node
= m_constrainedObjects
.First();
280 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
282 double width2
, height2
;
283 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
284 totalObjectWidth
+= width2
;
285 totalObjectHeight
+= height2
;
293 // Check if within the constraining object...
294 if ((totalObjectWidth
+ (n
+ 1)*m_xSpacing
) <= minWidth
)
296 spacingX
= (double)((minWidth
- totalObjectWidth
)/(n
+ 1));
297 startX
= (double)(x
- (minWidth
/2.0));
299 // Otherwise, use default spacing
302 spacingX
= m_xSpacing
;
303 startX
= (double)(x
- ((totalObjectWidth
+ (n
+1)*spacingX
)/2.0));
306 // Check if within the constraining object...
307 if ((totalObjectHeight
+ (n
+ 1)*m_ySpacing
) <= minHeight
)
309 spacingY
= (double)((minHeight
- totalObjectHeight
)/(n
+ 1));
310 startY
= (double)(y
- (minHeight
/2.0));
312 // Otherwise, use default spacing
315 spacingY
= m_ySpacing
;
316 startY
= (double)(y
- ((totalObjectHeight
+ (n
+1)*spacingY
)/2.0));
319 // Now position the objects
320 bool changed
= FALSE
;
321 node
= m_constrainedObjects
.First();
324 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
325 double width2
, height2
;
326 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
327 startX
+= (double)(spacingX
+ (width2
/2.0));
328 startY
+= (double)(spacingY
+ (height2
/2.0));
330 if ((!Equals(startX
, constrainedObject
->GetX())) || (!Equals(startY
, constrainedObject
->GetY())))
332 constrainedObject
->Move(dc
, startX
, startY
, FALSE
);
336 startX
+= (double)(width2
/2.0);
337 startY
+= (double)(height2
/2.0);
343 case gyCONSTRAINT_LEFT_OF
:
345 bool changed
= FALSE
;
347 wxNode
*node
= m_constrainedObjects
.First();
350 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
352 double width2
, height2
;
353 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
355 double x3
= (double)(x
- (minWidth
/2.0) - (width2
/2.0) - m_xSpacing
);
356 if (!Equals(x3
, constrainedObject
->GetX()))
359 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
366 case gyCONSTRAINT_RIGHT_OF
:
368 bool changed
= FALSE
;
370 wxNode
*node
= m_constrainedObjects
.First();
373 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
375 double width2
, height2
;
376 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
378 double x3
= (double)(x
+ (minWidth
/2.0) + (width2
/2.0) + m_xSpacing
);
379 if (!Equals(x3
, constrainedObject
->GetX()))
382 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
391 case gyCONSTRAINT_ABOVE
:
393 bool changed
= FALSE
;
395 wxNode
*node
= m_constrainedObjects
.First();
398 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
400 double width2
, height2
;
401 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
403 double y3
= (double)(y
- (minHeight
/2.0) - (height2
/2.0) - m_ySpacing
);
404 if (!Equals(y3
, constrainedObject
->GetY()))
407 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
414 case gyCONSTRAINT_BELOW
:
416 bool changed
= FALSE
;
418 wxNode
*node
= m_constrainedObjects
.First();
421 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
423 double width2
, height2
;
424 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
426 double y3
= (double)(y
+ (minHeight
/2.0) + (height2
/2.0) + m_ySpacing
);
427 if (!Equals(y3
, constrainedObject
->GetY()))
430 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
437 case gyCONSTRAINT_ALIGNED_LEFT
:
439 bool changed
= FALSE
;
441 wxNode
*node
= m_constrainedObjects
.First();
444 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
446 double width2
, height2
;
447 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
449 double x3
= (double)(x
- (minWidth
/2.0) + (width2
/2.0) + m_xSpacing
);
450 if (!Equals(x3
, constrainedObject
->GetX()))
453 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
460 case gyCONSTRAINT_ALIGNED_RIGHT
:
462 bool changed
= FALSE
;
464 wxNode
*node
= m_constrainedObjects
.First();
467 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
469 double width2
, height2
;
470 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
472 double x3
= (double)(x
+ (minWidth
/2.0) - (width2
/2.0) - m_xSpacing
);
473 if (!Equals(x3
, constrainedObject
->GetX()))
476 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
485 case gyCONSTRAINT_ALIGNED_TOP
:
487 bool changed
= FALSE
;
489 wxNode
*node
= m_constrainedObjects
.First();
492 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
494 double width2
, height2
;
495 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
497 double y3
= (double)(y
- (minHeight
/2.0) + (height2
/2.0) + m_ySpacing
);
498 if (!Equals(y3
, constrainedObject
->GetY()))
501 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
508 case gyCONSTRAINT_ALIGNED_BOTTOM
:
510 bool changed
= FALSE
;
512 wxNode
*node
= m_constrainedObjects
.First();
515 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
517 double width2
, height2
;
518 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
520 double y3
= (double)(y
+ (minHeight
/2.0) - (height2
/2.0) - m_ySpacing
);
521 if (!Equals(y3
, constrainedObject
->GetY()))
524 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
531 case gyCONSTRAINT_MIDALIGNED_LEFT
:
533 bool changed
= FALSE
;
535 wxNode
*node
= m_constrainedObjects
.First();
538 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
540 double x3
= (double)(x
- (minWidth
/2.0));
541 if (!Equals(x3
, constrainedObject
->GetX()))
544 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
551 case gyCONSTRAINT_MIDALIGNED_RIGHT
:
553 bool changed
= FALSE
;
555 wxNode
*node
= m_constrainedObjects
.First();
558 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
560 double x3
= (double)(x
+ (minWidth
/2.0));
561 if (!Equals(x3
, constrainedObject
->GetX()))
564 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
573 case gyCONSTRAINT_MIDALIGNED_TOP
:
575 bool changed
= FALSE
;
577 wxNode
*node
= m_constrainedObjects
.First();
580 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
582 double y3
= (double)(y
- (minHeight
/2.0));
583 if (!Equals(y3
, constrainedObject
->GetY()))
586 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
593 case gyCONSTRAINT_MIDALIGNED_BOTTOM
:
595 bool changed
= FALSE
;
597 wxNode
*node
= m_constrainedObjects
.First();
600 wxShape
*constrainedObject
= (wxShape
*)node
->Data();
602 double y3
= (double)(y
+ (minHeight
/2.0));
603 if (!Equals(y3
, constrainedObject
->GetY()))
606 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);