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