]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/ogl/constrnt.cpp
fixed slider value rounding once again
[wxWidgets.git] / contrib / src / ogl / constrnt.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: constrnt.cpp
3 // Purpose: OGL Constraint classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 12/07/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "constrnt.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include <wx/wxprec.h>
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include <wx/wx.h>
25 #endif
26
27 #include <wx/wxexpr.h>
28
29 #include <wx/ogl/basic.h>
30 #include <wx/ogl/constrnt.h>
31 #include <wx/ogl/canvas.h>
32
33 wxList *wxOGLConstraintTypes = NULL;
34
35 /*
36 * Constraint type
37 *
38 */
39
40 IMPLEMENT_DYNAMIC_CLASS(wxOGLConstraintType, wxObject)
41
42 wxOGLConstraintType::wxOGLConstraintType(int theType, const wxString& theName, const wxString& thePhrase)
43 {
44 m_type = theType;
45 m_name = theName;
46 m_phrase = thePhrase;
47 }
48
49 wxOGLConstraintType::~wxOGLConstraintType()
50 {
51 }
52
53 void OGLInitializeConstraintTypes()
54 {
55 if (!wxOGLConstraintTypes)
56 return;
57
58 wxOGLConstraintTypes = new wxList(wxKEY_INTEGER);
59
60 wxOGLConstraintTypes->Append(gyCONSTRAINT_CENTRED_VERTICALLY,
61 new wxOGLConstraintType(gyCONSTRAINT_CENTRED_VERTICALLY, "Centre vertically", "centred vertically w.r.t."));
62
63 wxOGLConstraintTypes->Append(gyCONSTRAINT_CENTRED_HORIZONTALLY,
64 new wxOGLConstraintType(gyCONSTRAINT_CENTRED_HORIZONTALLY, "Centre horizontally", "centred horizontally w.r.t."));
65
66 wxOGLConstraintTypes->Append(gyCONSTRAINT_CENTRED_BOTH,
67 new wxOGLConstraintType(gyCONSTRAINT_CENTRED_BOTH, "Centre", "centred w.r.t."));
68
69 wxOGLConstraintTypes->Append(gyCONSTRAINT_LEFT_OF,
70 new wxOGLConstraintType(gyCONSTRAINT_LEFT_OF, "Left of", "left of"));
71
72 wxOGLConstraintTypes->Append(gyCONSTRAINT_RIGHT_OF,
73 new wxOGLConstraintType(gyCONSTRAINT_RIGHT_OF, "Right of", "right of"));
74
75 wxOGLConstraintTypes->Append(gyCONSTRAINT_ABOVE,
76 new wxOGLConstraintType(gyCONSTRAINT_ABOVE, "Above", "above"));
77
78 wxOGLConstraintTypes->Append(gyCONSTRAINT_BELOW,
79 new wxOGLConstraintType(gyCONSTRAINT_BELOW, "Below", "below"));
80
81 // Alignment
82 wxOGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_TOP,
83 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_TOP, "Top-aligned", "aligned to the top of"));
84
85 wxOGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_BOTTOM,
86 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_BOTTOM, "Bottom-aligned", "aligned to the bottom of"));
87
88 wxOGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_LEFT,
89 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_LEFT, "Left-aligned", "aligned to the left of"));
90
91 wxOGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_RIGHT,
92 new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_RIGHT, "Right-aligned", "aligned to the right of"));
93
94 // Mid-alignment
95 wxOGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_TOP,
96 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_TOP, "Top-midaligned", "centred on the top of"));
97
98 wxOGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_BOTTOM,
99 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_BOTTOM, "Bottom-midaligned", "centred on the bottom of"));
100
101 wxOGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_LEFT,
102 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_LEFT, "Left-midaligned", "centred on the left of"));
103
104 wxOGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_RIGHT,
105 new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_RIGHT, "Right-midaligned", "centred on the right of"));
106 }
107
108 void OGLCleanUpConstraintTypes()
109 {
110 if (!wxOGLConstraintTypes)
111 return;
112
113 wxNode* node = wxOGLConstraintTypes->First();
114 while (node)
115 {
116 wxOGLConstraintType* ct = (wxOGLConstraintType*) node->Data();
117 delete ct;
118 node = node->Next();
119 }
120 delete wxOGLConstraintTypes;
121 wxOGLConstraintTypes = NULL;
122 }
123
124 /*
125 * Constraint Stuff
126 *
127 */
128
129 IMPLEMENT_DYNAMIC_CLASS(wxOGLConstraint, wxObject)
130
131 wxOGLConstraint::wxOGLConstraint(int type, wxShape *constraining, wxList& constrained)
132 {
133 m_xSpacing = 0.0;
134 m_ySpacing = 0.0;
135
136 m_constraintType = type;
137 m_constrainingObject = constraining;
138
139 m_constraintId = 0;
140 m_constraintName = "noname";
141
142 wxNode *node = constrained.First();
143 while (node)
144 {
145 m_constrainedObjects.Append(node->Data());
146 node = node->Next();
147 }
148 }
149
150 wxOGLConstraint::~wxOGLConstraint()
151 {
152 }
153
154 bool wxOGLConstraint::Equals(double a, double b)
155 {
156 double marg = 0.5;
157
158 bool eq = ((b <= a + marg) && (b >= a - marg));
159 return eq;
160 }
161
162 // Return TRUE if anything changed
163 bool wxOGLConstraint::Evaluate()
164 {
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();
170
171 wxClientDC dc(m_constrainingObject->GetCanvas());
172 m_constrainingObject->GetCanvas()->PrepareDC(dc);
173
174 switch (m_constraintType)
175 {
176 case gyCONSTRAINT_CENTRED_VERTICALLY:
177 {
178 int n = m_constrainedObjects.Number();
179 double totalObjectHeight = 0.0;
180 wxNode *node = m_constrainedObjects.First();
181 while (node)
182 {
183 wxShape *constrainedObject = (wxShape *)node->Data();
184
185 double width2, height2;
186 constrainedObject->GetBoundingBoxMax(&width2, &height2);
187 totalObjectHeight += height2;
188 node = node->Next();
189 }
190 double startY;
191 double spacingY;
192 // Check if within the constraining object...
193 if ((totalObjectHeight + (n + 1)*m_ySpacing) <= minHeight)
194 {
195 spacingY = (double)((minHeight - totalObjectHeight)/(n + 1));
196 startY = (double)(y - (minHeight/2.0));
197 }
198 // Otherwise, use default spacing
199 else
200 {
201 spacingY = m_ySpacing;
202 startY = (double)(y - ((totalObjectHeight + (n+1)*spacingY)/2.0));
203 }
204
205 // Now position the objects
206 bool changed = FALSE;
207 node = m_constrainedObjects.First();
208 while (node)
209 {
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()))
215 {
216 constrainedObject->Move(dc, constrainedObject->GetX(), startY, FALSE);
217 changed = TRUE;
218 }
219 startY += (double)(height2/2.0);
220 node = node->Next();
221 }
222 return changed;
223 }
224 case gyCONSTRAINT_CENTRED_HORIZONTALLY:
225 {
226 int n = m_constrainedObjects.Number();
227 double totalObjectWidth = 0.0;
228 wxNode *node = m_constrainedObjects.First();
229 while (node)
230 {
231 wxShape *constrainedObject = (wxShape *)node->Data();
232
233 double width2, height2;
234 constrainedObject->GetBoundingBoxMax(&width2, &height2);
235 totalObjectWidth += width2;
236 node = node->Next();
237 }
238 double startX;
239 double spacingX;
240 // Check if within the constraining object...
241 if ((totalObjectWidth + (n + 1)*m_xSpacing) <= minWidth)
242 {
243 spacingX = (double)((minWidth - totalObjectWidth)/(n + 1));
244 startX = (double)(x - (minWidth/2.0));
245 }
246 // Otherwise, use default spacing
247 else
248 {
249 spacingX = m_xSpacing;
250 startX = (double)(x - ((totalObjectWidth + (n+1)*spacingX)/2.0));
251 }
252
253 // Now position the objects
254 bool changed = FALSE;
255 node = m_constrainedObjects.First();
256 while (node)
257 {
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()))
263 {
264 constrainedObject->Move(dc, startX, constrainedObject->GetY(), FALSE);
265 changed = TRUE;
266 }
267 startX += (double)(width2/2.0);
268 node = node->Next();
269 }
270 return changed;
271 }
272 case gyCONSTRAINT_CENTRED_BOTH:
273 {
274 int n = m_constrainedObjects.Number();
275 double totalObjectWidth = 0.0;
276 double totalObjectHeight = 0.0;
277 wxNode *node = m_constrainedObjects.First();
278 while (node)
279 {
280 wxShape *constrainedObject = (wxShape *)node->Data();
281
282 double width2, height2;
283 constrainedObject->GetBoundingBoxMax(&width2, &height2);
284 totalObjectWidth += width2;
285 totalObjectHeight += height2;
286 node = node->Next();
287 }
288 double startX;
289 double spacingX;
290 double startY;
291 double spacingY;
292
293 // Check if within the constraining object...
294 if ((totalObjectWidth + (n + 1)*m_xSpacing) <= minWidth)
295 {
296 spacingX = (double)((minWidth - totalObjectWidth)/(n + 1));
297 startX = (double)(x - (minWidth/2.0));
298 }
299 // Otherwise, use default spacing
300 else
301 {
302 spacingX = m_xSpacing;
303 startX = (double)(x - ((totalObjectWidth + (n+1)*spacingX)/2.0));
304 }
305
306 // Check if within the constraining object...
307 if ((totalObjectHeight + (n + 1)*m_ySpacing) <= minHeight)
308 {
309 spacingY = (double)((minHeight - totalObjectHeight)/(n + 1));
310 startY = (double)(y - (minHeight/2.0));
311 }
312 // Otherwise, use default spacing
313 else
314 {
315 spacingY = m_ySpacing;
316 startY = (double)(y - ((totalObjectHeight + (n+1)*spacingY)/2.0));
317 }
318
319 // Now position the objects
320 bool changed = FALSE;
321 node = m_constrainedObjects.First();
322 while (node)
323 {
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));
329
330 if ((!Equals(startX, constrainedObject->GetX())) || (!Equals(startY, constrainedObject->GetY())))
331 {
332 constrainedObject->Move(dc, startX, startY, FALSE);
333 changed = TRUE;
334 }
335
336 startX += (double)(width2/2.0);
337 startY += (double)(height2/2.0);
338
339 node = node->Next();
340 }
341 return changed;
342 }
343 case gyCONSTRAINT_LEFT_OF:
344 {
345 bool changed = FALSE;
346
347 wxNode *node = m_constrainedObjects.First();
348 while (node)
349 {
350 wxShape *constrainedObject = (wxShape *)node->Data();
351
352 double width2, height2;
353 constrainedObject->GetBoundingBoxMax(&width2, &height2);
354
355 double x3 = (double)(x - (minWidth/2.0) - (width2/2.0) - m_xSpacing);
356 if (!Equals(x3, constrainedObject->GetX()))
357 {
358 changed = TRUE;
359 constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE);
360 }
361
362 node = node->Next();
363 }
364 return changed;
365 }
366 case gyCONSTRAINT_RIGHT_OF:
367 {
368 bool changed = FALSE;
369
370 wxNode *node = m_constrainedObjects.First();
371 while (node)
372 {
373 wxShape *constrainedObject = (wxShape *)node->Data();
374
375 double width2, height2;
376 constrainedObject->GetBoundingBoxMax(&width2, &height2);
377
378 double x3 = (double)(x + (minWidth/2.0) + (width2/2.0) + m_xSpacing);
379 if (!Equals(x3, constrainedObject->GetX()))
380 {
381 changed = TRUE;
382 constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE);
383 }
384
385 node = node->Next();
386 }
387 return changed;
388
389 return FALSE;
390 }
391 case gyCONSTRAINT_ABOVE:
392 {
393 bool changed = FALSE;
394
395 wxNode *node = m_constrainedObjects.First();
396 while (node)
397 {
398 wxShape *constrainedObject = (wxShape *)node->Data();
399
400 double width2, height2;
401 constrainedObject->GetBoundingBoxMax(&width2, &height2);
402
403 double y3 = (double)(y - (minHeight/2.0) - (height2/2.0) - m_ySpacing);
404 if (!Equals(y3, constrainedObject->GetY()))
405 {
406 changed = TRUE;
407 constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE);
408 }
409
410 node = node->Next();
411 }
412 return changed;
413 }
414 case gyCONSTRAINT_BELOW:
415 {
416 bool changed = FALSE;
417
418 wxNode *node = m_constrainedObjects.First();
419 while (node)
420 {
421 wxShape *constrainedObject = (wxShape *)node->Data();
422
423 double width2, height2;
424 constrainedObject->GetBoundingBoxMax(&width2, &height2);
425
426 double y3 = (double)(y + (minHeight/2.0) + (height2/2.0) + m_ySpacing);
427 if (!Equals(y3, constrainedObject->GetY()))
428 {
429 changed = TRUE;
430 constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE);
431 }
432
433 node = node->Next();
434 }
435 return changed;
436 }
437 case gyCONSTRAINT_ALIGNED_LEFT:
438 {
439 bool changed = FALSE;
440
441 wxNode *node = m_constrainedObjects.First();
442 while (node)
443 {
444 wxShape *constrainedObject = (wxShape *)node->Data();
445
446 double width2, height2;
447 constrainedObject->GetBoundingBoxMax(&width2, &height2);
448
449 double x3 = (double)(x - (minWidth/2.0) + (width2/2.0) + m_xSpacing);
450 if (!Equals(x3, constrainedObject->GetX()))
451 {
452 changed = TRUE;
453 constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE);
454 }
455
456 node = node->Next();
457 }
458 return changed;
459 }
460 case gyCONSTRAINT_ALIGNED_RIGHT:
461 {
462 bool changed = FALSE;
463
464 wxNode *node = m_constrainedObjects.First();
465 while (node)
466 {
467 wxShape *constrainedObject = (wxShape *)node->Data();
468
469 double width2, height2;
470 constrainedObject->GetBoundingBoxMax(&width2, &height2);
471
472 double x3 = (double)(x + (minWidth/2.0) - (width2/2.0) - m_xSpacing);
473 if (!Equals(x3, constrainedObject->GetX()))
474 {
475 changed = TRUE;
476 constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE);
477 }
478
479 node = node->Next();
480 }
481 return changed;
482
483 return FALSE;
484 }
485 case gyCONSTRAINT_ALIGNED_TOP:
486 {
487 bool changed = FALSE;
488
489 wxNode *node = m_constrainedObjects.First();
490 while (node)
491 {
492 wxShape *constrainedObject = (wxShape *)node->Data();
493
494 double width2, height2;
495 constrainedObject->GetBoundingBoxMax(&width2, &height2);
496
497 double y3 = (double)(y - (minHeight/2.0) + (height2/2.0) + m_ySpacing);
498 if (!Equals(y3, constrainedObject->GetY()))
499 {
500 changed = TRUE;
501 constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE);
502 }
503
504 node = node->Next();
505 }
506 return changed;
507 }
508 case gyCONSTRAINT_ALIGNED_BOTTOM:
509 {
510 bool changed = FALSE;
511
512 wxNode *node = m_constrainedObjects.First();
513 while (node)
514 {
515 wxShape *constrainedObject = (wxShape *)node->Data();
516
517 double width2, height2;
518 constrainedObject->GetBoundingBoxMax(&width2, &height2);
519
520 double y3 = (double)(y + (minHeight/2.0) - (height2/2.0) - m_ySpacing);
521 if (!Equals(y3, constrainedObject->GetY()))
522 {
523 changed = TRUE;
524 constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE);
525 }
526
527 node = node->Next();
528 }
529 return changed;
530 }
531 case gyCONSTRAINT_MIDALIGNED_LEFT:
532 {
533 bool changed = FALSE;
534
535 wxNode *node = m_constrainedObjects.First();
536 while (node)
537 {
538 wxShape *constrainedObject = (wxShape *)node->Data();
539
540 double x3 = (double)(x - (minWidth/2.0));
541 if (!Equals(x3, constrainedObject->GetX()))
542 {
543 changed = TRUE;
544 constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE);
545 }
546
547 node = node->Next();
548 }
549 return changed;
550 }
551 case gyCONSTRAINT_MIDALIGNED_RIGHT:
552 {
553 bool changed = FALSE;
554
555 wxNode *node = m_constrainedObjects.First();
556 while (node)
557 {
558 wxShape *constrainedObject = (wxShape *)node->Data();
559
560 double x3 = (double)(x + (minWidth/2.0));
561 if (!Equals(x3, constrainedObject->GetX()))
562 {
563 changed = TRUE;
564 constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE);
565 }
566
567 node = node->Next();
568 }
569 return changed;
570
571 return FALSE;
572 }
573 case gyCONSTRAINT_MIDALIGNED_TOP:
574 {
575 bool changed = FALSE;
576
577 wxNode *node = m_constrainedObjects.First();
578 while (node)
579 {
580 wxShape *constrainedObject = (wxShape *)node->Data();
581
582 double y3 = (double)(y - (minHeight/2.0));
583 if (!Equals(y3, constrainedObject->GetY()))
584 {
585 changed = TRUE;
586 constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE);
587 }
588
589 node = node->Next();
590 }
591 return changed;
592 }
593 case gyCONSTRAINT_MIDALIGNED_BOTTOM:
594 {
595 bool changed = FALSE;
596
597 wxNode *node = m_constrainedObjects.First();
598 while (node)
599 {
600 wxShape *constrainedObject = (wxShape *)node->Data();
601
602 double y3 = (double)(y + (minHeight/2.0));
603 if (!Equals(y3, constrainedObject->GetY()))
604 {
605 changed = TRUE;
606 constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE);
607 }
608
609 node = node->Next();
610 }
611 return changed;
612 }
613
614 default:
615 return FALSE;
616 }
617 return FALSE;
618 }
619