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/deprecated/wxexpr.h>
31 #include "wx/ogl/ogl.h"
34 wxList
*wxOGLConstraintTypes
= NULL
;
41 IMPLEMENT_DYNAMIC_CLASS(wxOGLConstraintType
, wxObject
)
43 wxOGLConstraintType::wxOGLConstraintType(int theType
, const wxString
& theName
, const wxString
& thePhrase
)
50 wxOGLConstraintType::~wxOGLConstraintType()
54 void OGLInitializeConstraintTypes()
56 if (!wxOGLConstraintTypes
)
59 wxOGLConstraintTypes
= new wxList(wxKEY_INTEGER
);
61 wxOGLConstraintTypes
->Append(gyCONSTRAINT_CENTRED_VERTICALLY
,
62 new wxOGLConstraintType(gyCONSTRAINT_CENTRED_VERTICALLY
, wxT("Centre vertically"), wxT("centred vertically w.r.t.")));
64 wxOGLConstraintTypes
->Append(gyCONSTRAINT_CENTRED_HORIZONTALLY
,
65 new wxOGLConstraintType(gyCONSTRAINT_CENTRED_HORIZONTALLY
, wxT("Centre horizontally"), wxT("centred horizontally w.r.t.")));
67 wxOGLConstraintTypes
->Append(gyCONSTRAINT_CENTRED_BOTH
,
68 new wxOGLConstraintType(gyCONSTRAINT_CENTRED_BOTH
, wxT("Centre"), wxT("centred w.r.t.")));
70 wxOGLConstraintTypes
->Append(gyCONSTRAINT_LEFT_OF
,
71 new wxOGLConstraintType(gyCONSTRAINT_LEFT_OF
, wxT("Left of"), wxT("left of")));
73 wxOGLConstraintTypes
->Append(gyCONSTRAINT_RIGHT_OF
,
74 new wxOGLConstraintType(gyCONSTRAINT_RIGHT_OF
, wxT("Right of"), wxT("right of")));
76 wxOGLConstraintTypes
->Append(gyCONSTRAINT_ABOVE
,
77 new wxOGLConstraintType(gyCONSTRAINT_ABOVE
, wxT("Above"), wxT("above")));
79 wxOGLConstraintTypes
->Append(gyCONSTRAINT_BELOW
,
80 new wxOGLConstraintType(gyCONSTRAINT_BELOW
, wxT("Below"), wxT("below")));
83 wxOGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_TOP
,
84 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_TOP
, wxT("Top-aligned"), wxT("aligned to the top of")));
86 wxOGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_BOTTOM
,
87 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_BOTTOM
, wxT("Bottom-aligned"), wxT("aligned to the bottom of")));
89 wxOGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_LEFT
,
90 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_LEFT
, wxT("Left-aligned"), wxT("aligned to the left of")));
92 wxOGLConstraintTypes
->Append(gyCONSTRAINT_ALIGNED_RIGHT
,
93 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_RIGHT
, wxT("Right-aligned"), wxT("aligned to the right of")));
96 wxOGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_TOP
,
97 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_TOP
, wxT("Top-midaligned"), wxT("centred on the top of")));
99 wxOGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_BOTTOM
,
100 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_BOTTOM
, wxT("Bottom-midaligned"), wxT("centred on the bottom of")));
102 wxOGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_LEFT
,
103 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_LEFT
, wxT("Left-midaligned"), wxT("centred on the left of")));
105 wxOGLConstraintTypes
->Append(gyCONSTRAINT_MIDALIGNED_RIGHT
,
106 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_RIGHT
, wxT("Right-midaligned"), wxT("centred on the right of")));
109 void OGLCleanUpConstraintTypes()
111 if (!wxOGLConstraintTypes
)
114 wxNode
* node
= wxOGLConstraintTypes
->GetFirst();
117 wxOGLConstraintType
* ct
= (wxOGLConstraintType
*) node
->GetData();
119 node
= node
->GetNext();
121 delete wxOGLConstraintTypes
;
122 wxOGLConstraintTypes
= NULL
;
130 IMPLEMENT_DYNAMIC_CLASS(wxOGLConstraint
, wxObject
)
132 wxOGLConstraint::wxOGLConstraint(int type
, wxShape
*constraining
, wxList
& constrained
)
137 m_constraintType
= type
;
138 m_constrainingObject
= constraining
;
141 m_constraintName
= wxT("noname");
143 wxNode
*node
= constrained
.GetFirst();
146 m_constrainedObjects
.Append(node
->GetData());
147 node
= node
->GetNext();
151 wxOGLConstraint::~wxOGLConstraint()
155 bool wxOGLConstraint::Equals(double a
, double b
)
159 bool eq
= ((b
<= a
+ marg
) && (b
>= a
- marg
));
163 // Return TRUE if anything changed
164 bool wxOGLConstraint::Evaluate()
166 double maxWidth
, maxHeight
, minWidth
, minHeight
, x
, y
;
167 m_constrainingObject
->GetBoundingBoxMax(&maxWidth
, &maxHeight
);
168 m_constrainingObject
->GetBoundingBoxMin(&minWidth
, &minHeight
);
169 x
= m_constrainingObject
->GetX();
170 y
= m_constrainingObject
->GetY();
172 wxClientDC
dc(m_constrainingObject
->GetCanvas());
173 m_constrainingObject
->GetCanvas()->PrepareDC(dc
);
175 switch (m_constraintType
)
177 case gyCONSTRAINT_CENTRED_VERTICALLY
:
179 int n
= m_constrainedObjects
.GetCount();
180 double totalObjectHeight
= 0.0;
181 wxNode
*node
= m_constrainedObjects
.GetFirst();
184 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
186 double width2
, height2
;
187 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
188 totalObjectHeight
+= height2
;
189 node
= node
->GetNext();
193 // Check if within the constraining object...
194 if ((totalObjectHeight
+ (n
+ 1)*m_ySpacing
) <= minHeight
)
196 spacingY
= (double)((minHeight
- totalObjectHeight
)/(n
+ 1));
197 startY
= (double)(y
- (minHeight
/2.0));
199 // Otherwise, use default spacing
202 spacingY
= m_ySpacing
;
203 startY
= (double)(y
- ((totalObjectHeight
+ (n
+1)*spacingY
)/2.0));
206 // Now position the objects
207 bool changed
= FALSE
;
208 node
= m_constrainedObjects
.GetFirst();
211 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
212 double width2
, height2
;
213 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
214 startY
+= (double)(spacingY
+ (height2
/2.0));
215 if (!Equals(startY
, constrainedObject
->GetY()))
217 constrainedObject
->Move(dc
, constrainedObject
->GetX(), startY
, FALSE
);
220 startY
+= (double)(height2
/2.0);
221 node
= node
->GetNext();
225 case gyCONSTRAINT_CENTRED_HORIZONTALLY
:
227 int n
= m_constrainedObjects
.GetCount();
228 double totalObjectWidth
= 0.0;
229 wxNode
*node
= m_constrainedObjects
.GetFirst();
232 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
234 double width2
, height2
;
235 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
236 totalObjectWidth
+= width2
;
237 node
= node
->GetNext();
241 // Check if within the constraining object...
242 if ((totalObjectWidth
+ (n
+ 1)*m_xSpacing
) <= minWidth
)
244 spacingX
= (double)((minWidth
- totalObjectWidth
)/(n
+ 1));
245 startX
= (double)(x
- (minWidth
/2.0));
247 // Otherwise, use default spacing
250 spacingX
= m_xSpacing
;
251 startX
= (double)(x
- ((totalObjectWidth
+ (n
+1)*spacingX
)/2.0));
254 // Now position the objects
255 bool changed
= FALSE
;
256 node
= m_constrainedObjects
.GetFirst();
259 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
260 double width2
, height2
;
261 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
262 startX
+= (double)(spacingX
+ (width2
/2.0));
263 if (!Equals(startX
, constrainedObject
->GetX()))
265 constrainedObject
->Move(dc
, startX
, constrainedObject
->GetY(), FALSE
);
268 startX
+= (double)(width2
/2.0);
269 node
= node
->GetNext();
273 case gyCONSTRAINT_CENTRED_BOTH
:
275 int n
= m_constrainedObjects
.GetCount();
276 double totalObjectWidth
= 0.0;
277 double totalObjectHeight
= 0.0;
278 wxNode
*node
= m_constrainedObjects
.GetFirst();
281 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
283 double width2
, height2
;
284 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
285 totalObjectWidth
+= width2
;
286 totalObjectHeight
+= height2
;
287 node
= node
->GetNext();
294 // Check if within the constraining object...
295 if ((totalObjectWidth
+ (n
+ 1)*m_xSpacing
) <= minWidth
)
297 spacingX
= (double)((minWidth
- totalObjectWidth
)/(n
+ 1));
298 startX
= (double)(x
- (minWidth
/2.0));
300 // Otherwise, use default spacing
303 spacingX
= m_xSpacing
;
304 startX
= (double)(x
- ((totalObjectWidth
+ (n
+1)*spacingX
)/2.0));
307 // Check if within the constraining object...
308 if ((totalObjectHeight
+ (n
+ 1)*m_ySpacing
) <= minHeight
)
310 spacingY
= (double)((minHeight
- totalObjectHeight
)/(n
+ 1));
311 startY
= (double)(y
- (minHeight
/2.0));
313 // Otherwise, use default spacing
316 spacingY
= m_ySpacing
;
317 startY
= (double)(y
- ((totalObjectHeight
+ (n
+1)*spacingY
)/2.0));
320 // Now position the objects
321 bool changed
= FALSE
;
322 node
= m_constrainedObjects
.GetFirst();
325 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
326 double width2
, height2
;
327 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
328 startX
+= (double)(spacingX
+ (width2
/2.0));
329 startY
+= (double)(spacingY
+ (height2
/2.0));
331 if ((!Equals(startX
, constrainedObject
->GetX())) || (!Equals(startY
, constrainedObject
->GetY())))
333 constrainedObject
->Move(dc
, startX
, startY
, FALSE
);
337 startX
+= (double)(width2
/2.0);
338 startY
+= (double)(height2
/2.0);
340 node
= node
->GetNext();
344 case gyCONSTRAINT_LEFT_OF
:
346 bool changed
= FALSE
;
348 wxNode
*node
= m_constrainedObjects
.GetFirst();
351 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
353 double width2
, height2
;
354 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
356 double x3
= (double)(x
- (minWidth
/2.0) - (width2
/2.0) - m_xSpacing
);
357 if (!Equals(x3
, constrainedObject
->GetX()))
360 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
363 node
= node
->GetNext();
367 case gyCONSTRAINT_RIGHT_OF
:
369 bool changed
= FALSE
;
371 wxNode
*node
= m_constrainedObjects
.GetFirst();
374 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
376 double width2
, height2
;
377 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
379 double x3
= (double)(x
+ (minWidth
/2.0) + (width2
/2.0) + m_xSpacing
);
380 if (!Equals(x3
, constrainedObject
->GetX()))
383 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
386 node
= node
->GetNext();
390 case gyCONSTRAINT_ABOVE
:
392 bool changed
= FALSE
;
394 wxNode
*node
= m_constrainedObjects
.GetFirst();
397 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
399 double width2
, height2
;
400 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
402 double y3
= (double)(y
- (minHeight
/2.0) - (height2
/2.0) - m_ySpacing
);
403 if (!Equals(y3
, constrainedObject
->GetY()))
406 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
409 node
= node
->GetNext();
413 case gyCONSTRAINT_BELOW
:
415 bool changed
= FALSE
;
417 wxNode
*node
= m_constrainedObjects
.GetFirst();
420 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
422 double width2
, height2
;
423 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
425 double y3
= (double)(y
+ (minHeight
/2.0) + (height2
/2.0) + m_ySpacing
);
426 if (!Equals(y3
, constrainedObject
->GetY()))
429 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
432 node
= node
->GetNext();
436 case gyCONSTRAINT_ALIGNED_LEFT
:
438 bool changed
= FALSE
;
440 wxNode
*node
= m_constrainedObjects
.GetFirst();
443 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
445 double width2
, height2
;
446 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
448 double x3
= (double)(x
- (minWidth
/2.0) + (width2
/2.0) + m_xSpacing
);
449 if (!Equals(x3
, constrainedObject
->GetX()))
452 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
455 node
= node
->GetNext();
459 case gyCONSTRAINT_ALIGNED_RIGHT
:
461 bool changed
= FALSE
;
463 wxNode
*node
= m_constrainedObjects
.GetFirst();
466 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
468 double width2
, height2
;
469 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
471 double x3
= (double)(x
+ (minWidth
/2.0) - (width2
/2.0) - m_xSpacing
);
472 if (!Equals(x3
, constrainedObject
->GetX()))
475 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
478 node
= node
->GetNext();
482 // two returned values ?
486 case gyCONSTRAINT_ALIGNED_TOP
:
488 bool changed
= FALSE
;
490 wxNode
*node
= m_constrainedObjects
.GetFirst();
493 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
495 double width2
, height2
;
496 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
498 double y3
= (double)(y
- (minHeight
/2.0) + (height2
/2.0) + m_ySpacing
);
499 if (!Equals(y3
, constrainedObject
->GetY()))
502 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
505 node
= node
->GetNext();
509 case gyCONSTRAINT_ALIGNED_BOTTOM
:
511 bool changed
= FALSE
;
513 wxNode
*node
= m_constrainedObjects
.GetFirst();
516 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
518 double width2
, height2
;
519 constrainedObject
->GetBoundingBoxMax(&width2
, &height2
);
521 double y3
= (double)(y
+ (minHeight
/2.0) - (height2
/2.0) - m_ySpacing
);
522 if (!Equals(y3
, constrainedObject
->GetY()))
525 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
528 node
= node
->GetNext();
532 case gyCONSTRAINT_MIDALIGNED_LEFT
:
534 bool changed
= FALSE
;
536 wxNode
*node
= m_constrainedObjects
.GetFirst();
539 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
541 double x3
= (double)(x
- (minWidth
/2.0));
542 if (!Equals(x3
, constrainedObject
->GetX()))
545 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
548 node
= node
->GetNext();
552 case gyCONSTRAINT_MIDALIGNED_RIGHT
:
554 bool changed
= FALSE
;
556 wxNode
*node
= m_constrainedObjects
.GetFirst();
559 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
561 double x3
= (double)(x
+ (minWidth
/2.0));
562 if (!Equals(x3
, constrainedObject
->GetX()))
565 constrainedObject
->Move(dc
, x3
, constrainedObject
->GetY(), FALSE
);
568 node
= node
->GetNext();
572 // two returned values ?
576 case gyCONSTRAINT_MIDALIGNED_TOP
:
578 bool changed
= FALSE
;
580 wxNode
*node
= m_constrainedObjects
.GetFirst();
583 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
585 double y3
= (double)(y
- (minHeight
/2.0));
586 if (!Equals(y3
, constrainedObject
->GetY()))
589 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
592 node
= node
->GetNext();
596 case gyCONSTRAINT_MIDALIGNED_BOTTOM
:
598 bool changed
= FALSE
;
600 wxNode
*node
= m_constrainedObjects
.GetFirst();
603 wxShape
*constrainedObject
= (wxShape
*)node
->GetData();
605 double y3
= (double)(y
+ (minHeight
/2.0));
606 if (!Equals(y3
, constrainedObject
->GetY()))
609 constrainedObject
->Move(dc
, constrainedObject
->GetX(), y3
, FALSE
);
612 node
= node
->GetNext();
617 // default value handled in main function body