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