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
, wxT("Centre vertically"), wxT("centred vertically w.r.t.")));
63 wxOGLConstraintTypes
->Append(gyCONSTRAINT_CENTRED_HORIZONTALLY
,
64 new wxOGLConstraintType(gyCONSTRAINT_CENTRED_HORIZONTALLY
, wxT("Centre horizontally"), wxT("centred horizontally w.r.t.")));
66 wxOGLConstraintTypes
->Append(gyCONSTRAINT_CENTRED_BOTH
,
67 new wxOGLConstraintType(gyCONSTRAINT_CENTRED_BOTH
, wxT("Centre"), wxT("centred w.r.t.")));
69 wxOGLConstraintTypes
->Append(gyCONSTRAINT_LEFT_OF
,
70 new wxOGLConstraintType(gyCONSTRAINT_LEFT_OF
, wxT("Left of"), wxT("left of")));
72 wxOGLConstraintTypes
->Append(gyCONSTRAINT_RIGHT_OF
,
73 new wxOGLConstraintType(gyCONSTRAINT_RIGHT_OF
, wxT("Right of"), wxT("right of")));
75 wxOGLConstraintTypes
->Append(gyCONSTRAINT_ABOVE
,
76 new wxOGLConstraintType(gyCONSTRAINT_ABOVE
, wxT("Above"), wxT("above")));
78 wxOGLConstraintTypes
->Append(gyCONSTRAINT_BELOW
,
79 new wxOGLConstraintType(gyCONSTRAINT_BELOW
, wxT("Below"), wxT("below")));
82 wxOGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_TOP
,
83 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_TOP
, wxT("Top-aligned"), wxT("aligned to the top of")));
85 wxOGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_BOTTOM
,
86 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_BOTTOM
, wxT("Bottom-aligned"), wxT("aligned to the bottom of")));
88 wxOGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_LEFT
,
89 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_LEFT
, wxT("Left-aligned"), wxT("aligned to the left of")));
91 wxOGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_RIGHT
,
92 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_RIGHT
, wxT("Right-aligned"), wxT("aligned to the right of")));
95 wxOGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_TOP
,
96 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_TOP
, wxT("Top-midaligned"), wxT("centred on the top of")));
98 wxOGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_BOTTOM
,
99 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_BOTTOM
, wxT("Bottom-midaligned"), wxT("centred on the bottom of")));
101 wxOGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_LEFT
,
102 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_LEFT
, wxT("Left-midaligned"), wxT("centred on the left of")));
104 wxOGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_RIGHT
,
105 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_RIGHT
, wxT("Right-midaligned"), wxT("centred on the right of")));
108 void OGLCleanUpConstraintTypes()
110 if (!wxOGLConstraintTypes
)
113 wxNode
* node
= wxOGLConstraintTypes
->GetFirst();
116 wxOGLConstraintType
* ct
= (wxOGLConstraintType
*) node
->GetData();
118 node
= node
->GetNext();
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
= wxT("noname");
142 wxNode
*node
= constrained
.GetFirst();
145 m_constrainedObjects
.Append(node
->GetData());
146 node
= node
->GetNext();
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
.GetCount();
179 double totalObjectHeight
= 0.0;
180 wxNode
*node
= m_constrainedObjects
.GetFirst();
183 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
185 double width2
, height2
;
186 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
187 totalObjectHeight
+= height2
;
188 node
= node
->GetNext();
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
.GetFirst();
210 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
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);
220 node
= node
->GetNext();
224 case gyCONSTRAINT_CENTRED_HORIZONTALLY
:
226 int n
= m_constrainedObjects
.GetCount();
227 double totalObjectWidth
= 0.0;
228 wxNode
*node
= m_constrainedObjects
.GetFirst();
231 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
233 double width2
, height2
;
234 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
235 totalObjectWidth
+= width2
;
236 node
= node
->GetNext();
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
.GetFirst();
258 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
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);
268 node
= node
->GetNext();
272 case gyCONSTRAINT_CENTRED_BOTH
:
274 int n
= m_constrainedObjects
.GetCount();
275 double totalObjectWidth
= 0.0;
276 double totalObjectHeight
= 0.0;
277 wxNode
*node
= m_constrainedObjects
.GetFirst();
280 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
282 double width2
, height2
;
283 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
284 totalObjectWidth
+= width2
;
285 totalObjectHeight
+= height2
;
286 node
= node
->GetNext();
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
.GetFirst();
324 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
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);
339 node
= node
->GetNext();
343 case gyCONSTRAINT_LEFT_OF
:
345 bool changed
= FALSE
;
347 wxNode
*node
= m_constrainedObjects
.GetFirst();
350 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
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
);
362 node
= node
->GetNext();
366 case gyCONSTRAINT_RIGHT_OF
:
368 bool changed
= FALSE
;
370 wxNode
*node
= m_constrainedObjects
.GetFirst();
373 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
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
);
385 node
= node
->GetNext();
391 case gyCONSTRAINT_ABOVE
:
393 bool changed
= FALSE
;
395 wxNode
*node
= m_constrainedObjects
.GetFirst();
398 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
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
);
410 node
= node
->GetNext();
414 case gyCONSTRAINT_BELOW
:
416 bool changed
= FALSE
;
418 wxNode
*node
= m_constrainedObjects
.GetFirst();
421 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
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
);
433 node
= node
->GetNext();
437 case gyCONSTRAINT_ALIGNED_LEFT
:
439 bool changed
= FALSE
;
441 wxNode
*node
= m_constrainedObjects
.GetFirst();
444 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
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
);
456 node
= node
->GetNext();
460 case gyCONSTRAINT_ALIGNED_RIGHT
:
462 bool changed
= FALSE
;
464 wxNode
*node
= m_constrainedObjects
.GetFirst();
467 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
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
);
479 node
= node
->GetNext();
485 case gyCONSTRAINT_ALIGNED_TOP
:
487 bool changed
= FALSE
;
489 wxNode
*node
= m_constrainedObjects
.GetFirst();
492 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
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
);
504 node
= node
->GetNext();
508 case gyCONSTRAINT_ALIGNED_BOTTOM
:
510 bool changed
= FALSE
;
512 wxNode
*node
= m_constrainedObjects
.GetFirst();
515 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
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
);
527 node
= node
->GetNext();
531 case gyCONSTRAINT_MIDALIGNED_LEFT
:
533 bool changed
= FALSE
;
535 wxNode
*node
= m_constrainedObjects
.GetFirst();
538 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
540 double x3
= (double)(x
- (minWidth
/2.0));
541 if (!Equals(x3
, constrainedObject
->GetX()))
544 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
547 node
= node
->GetNext();
551 case gyCONSTRAINT_MIDALIGNED_RIGHT
:
553 bool changed
= FALSE
;
555 wxNode
*node
= m_constrainedObjects
.GetFirst();
558 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
560 double x3
= (double)(x
+ (minWidth
/2.0));
561 if (!Equals(x3
, constrainedObject
->GetX()))
564 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
567 node
= node
->GetNext();
573 case gyCONSTRAINT_MIDALIGNED_TOP
:
575 bool changed
= FALSE
;
577 wxNode
*node
= m_constrainedObjects
.GetFirst();
580 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
582 double y3
= (double)(y
- (minHeight
/2.0));
583 if (!Equals(y3
, constrainedObject
->GetY()))
586 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
589 node
= node
->GetNext();
593 case gyCONSTRAINT_MIDALIGNED_BOTTOM
:
595 bool changed
= FALSE
;
597 wxNode
*node
= m_constrainedObjects
.GetFirst();
600 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
602 double y3
= (double)(y
+ (minHeight
/2.0));
603 if (!Equals(y3
, constrainedObject
->GetY()))
606 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
609 node
= node
->GetNext();