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