mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 06:05:49 -06:00
606 lines
16 KiB
C++
606 lines
16 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// pgAdmin III - PostgreSQL Tools
|
|
//
|
|
// Portions Copyright (C) 1998 - 2011, Julian Smart
|
|
// Portions Copyright (C) 2011 - 2016, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
// constrnt.cpp - OGL Constraint classes
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "pgAdmin3.h"
|
|
|
|
#include "ogl/ogl.h"
|
|
|
|
|
|
wxList *wxOGLConstraintTypes = NULL;
|
|
|
|
/*
|
|
* Constraint type
|
|
*
|
|
*/
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxOGLConstraintType, wxObject)
|
|
|
|
wxOGLConstraintType::wxOGLConstraintType(int theType, const wxString &theName, const wxString &thePhrase)
|
|
{
|
|
m_type = theType;
|
|
m_name = theName;
|
|
m_phrase = thePhrase;
|
|
}
|
|
|
|
wxOGLConstraintType::~wxOGLConstraintType()
|
|
{
|
|
}
|
|
|
|
void OGLInitializeConstraintTypes()
|
|
{
|
|
if (!wxOGLConstraintTypes)
|
|
return;
|
|
|
|
wxOGLConstraintTypes = new wxList(wxKEY_INTEGER);
|
|
|
|
wxOGLConstraintTypes->Append(gyCONSTRAINT_CENTRED_VERTICALLY,
|
|
new wxOGLConstraintType(gyCONSTRAINT_CENTRED_VERTICALLY, wxT("Centre vertically"), wxT("centred vertically w.r.t.")));
|
|
|
|
wxOGLConstraintTypes->Append(gyCONSTRAINT_CENTRED_HORIZONTALLY,
|
|
new wxOGLConstraintType(gyCONSTRAINT_CENTRED_HORIZONTALLY, wxT("Centre horizontally"), wxT("centred horizontally w.r.t.")));
|
|
|
|
wxOGLConstraintTypes->Append(gyCONSTRAINT_CENTRED_BOTH,
|
|
new wxOGLConstraintType(gyCONSTRAINT_CENTRED_BOTH, wxT("Centre"), wxT("centred w.r.t.")));
|
|
|
|
wxOGLConstraintTypes->Append(gyCONSTRAINT_LEFT_OF,
|
|
new wxOGLConstraintType(gyCONSTRAINT_LEFT_OF, wxT("Left of"), wxT("left of")));
|
|
|
|
wxOGLConstraintTypes->Append(gyCONSTRAINT_RIGHT_OF,
|
|
new wxOGLConstraintType(gyCONSTRAINT_RIGHT_OF, wxT("Right of"), wxT("right of")));
|
|
|
|
wxOGLConstraintTypes->Append(gyCONSTRAINT_ABOVE,
|
|
new wxOGLConstraintType(gyCONSTRAINT_ABOVE, wxT("Above"), wxT("above")));
|
|
|
|
wxOGLConstraintTypes->Append(gyCONSTRAINT_BELOW,
|
|
new wxOGLConstraintType(gyCONSTRAINT_BELOW, wxT("Below"), wxT("below")));
|
|
|
|
// Alignment
|
|
wxOGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_TOP,
|
|
new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_TOP, wxT("Top-aligned"), wxT("aligned to the top of")));
|
|
|
|
wxOGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_BOTTOM,
|
|
new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_BOTTOM, wxT("Bottom-aligned"), wxT("aligned to the bottom of")));
|
|
|
|
wxOGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_LEFT,
|
|
new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_LEFT, wxT("Left-aligned"), wxT("aligned to the left of")));
|
|
|
|
wxOGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_RIGHT,
|
|
new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_RIGHT, wxT("Right-aligned"), wxT("aligned to the right of")));
|
|
|
|
// Mid-alignment
|
|
wxOGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_TOP,
|
|
new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_TOP, wxT("Top-midaligned"), wxT("centred on the top of")));
|
|
|
|
wxOGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_BOTTOM,
|
|
new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_BOTTOM, wxT("Bottom-midaligned"), wxT("centred on the bottom of")));
|
|
|
|
wxOGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_LEFT,
|
|
new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_LEFT, wxT("Left-midaligned"), wxT("centred on the left of")));
|
|
|
|
wxOGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_RIGHT,
|
|
new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_RIGHT, wxT("Right-midaligned"), wxT("centred on the right of")));
|
|
}
|
|
|
|
void OGLCleanUpConstraintTypes()
|
|
{
|
|
if (!wxOGLConstraintTypes)
|
|
return;
|
|
|
|
wxNode *node = wxOGLConstraintTypes->GetFirst();
|
|
while (node)
|
|
{
|
|
wxOGLConstraintType *ct = (wxOGLConstraintType *) node->GetData();
|
|
delete ct;
|
|
node = node->GetNext();
|
|
}
|
|
delete wxOGLConstraintTypes;
|
|
wxOGLConstraintTypes = NULL;
|
|
}
|
|
|
|
/*
|
|
* Constraint Stuff
|
|
*
|
|
*/
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxOGLConstraint, wxObject)
|
|
|
|
wxOGLConstraint::wxOGLConstraint(int type, wxShape *constraining, wxList &constrained)
|
|
{
|
|
m_xSpacing = 0.0;
|
|
m_ySpacing = 0.0;
|
|
|
|
m_constraintType = type;
|
|
m_constrainingObject = constraining;
|
|
|
|
m_constraintId = 0;
|
|
m_constraintName = wxT("noname");
|
|
|
|
wxNode *node = constrained.GetFirst();
|
|
while (node)
|
|
{
|
|
m_constrainedObjects.Append(node->GetData());
|
|
node = node->GetNext();
|
|
}
|
|
}
|
|
|
|
wxOGLConstraint::~wxOGLConstraint()
|
|
{
|
|
}
|
|
|
|
bool wxOGLConstraint::Equals(double a, double b)
|
|
{
|
|
double marg = 0.5;
|
|
|
|
bool eq = ((b <= a + marg) && (b >= a - marg));
|
|
return eq;
|
|
}
|
|
|
|
// Return TRUE if anything changed
|
|
bool wxOGLConstraint::Evaluate()
|
|
{
|
|
double maxWidth, maxHeight, minWidth, minHeight, x, y;
|
|
m_constrainingObject->GetBoundingBoxMax(&maxWidth, &maxHeight);
|
|
m_constrainingObject->GetBoundingBoxMin(&minWidth, &minHeight);
|
|
x = m_constrainingObject->GetX();
|
|
y = m_constrainingObject->GetY();
|
|
|
|
switch (m_constraintType)
|
|
{
|
|
case gyCONSTRAINT_CENTRED_VERTICALLY:
|
|
{
|
|
int n = m_constrainedObjects.GetCount();
|
|
double totalObjectHeight = 0.0;
|
|
wxNode *node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
|
|
double width2, height2;
|
|
constrainedObject->GetBoundingBoxMax(&width2, &height2);
|
|
totalObjectHeight += height2;
|
|
node = node->GetNext();
|
|
}
|
|
double startY;
|
|
double spacingY;
|
|
// Check if within the constraining object...
|
|
if ((totalObjectHeight + (n + 1)*m_ySpacing) <= minHeight)
|
|
{
|
|
spacingY = (double)((minHeight - totalObjectHeight) / (n + 1));
|
|
startY = (double)(y - (minHeight / 2.0));
|
|
}
|
|
// Otherwise, use default spacing
|
|
else
|
|
{
|
|
spacingY = m_ySpacing;
|
|
startY = (double)(y - ((totalObjectHeight + (n + 1) * spacingY) / 2.0));
|
|
}
|
|
|
|
// Now position the objects
|
|
bool changed = FALSE;
|
|
node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
double width2, height2;
|
|
constrainedObject->GetBoundingBoxMax(&width2, &height2);
|
|
startY += (double)(spacingY + (height2 / 2.0));
|
|
if (!Equals(startY, constrainedObject->GetY()))
|
|
{
|
|
constrainedObject->Move(constrainedObject->GetX(), startY, FALSE);
|
|
changed = TRUE;
|
|
}
|
|
startY += (double)(height2 / 2.0);
|
|
node = node->GetNext();
|
|
}
|
|
return changed;
|
|
}
|
|
case gyCONSTRAINT_CENTRED_HORIZONTALLY:
|
|
{
|
|
int n = m_constrainedObjects.GetCount();
|
|
double totalObjectWidth = 0.0;
|
|
wxNode *node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
|
|
double width2, height2;
|
|
constrainedObject->GetBoundingBoxMax(&width2, &height2);
|
|
totalObjectWidth += width2;
|
|
node = node->GetNext();
|
|
}
|
|
double startX;
|
|
double spacingX;
|
|
// Check if within the constraining object...
|
|
if ((totalObjectWidth + (n + 1)*m_xSpacing) <= minWidth)
|
|
{
|
|
spacingX = (double)((minWidth - totalObjectWidth) / (n + 1));
|
|
startX = (double)(x - (minWidth / 2.0));
|
|
}
|
|
// Otherwise, use default spacing
|
|
else
|
|
{
|
|
spacingX = m_xSpacing;
|
|
startX = (double)(x - ((totalObjectWidth + (n + 1) * spacingX) / 2.0));
|
|
}
|
|
|
|
// Now position the objects
|
|
bool changed = FALSE;
|
|
node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
double width2, height2;
|
|
constrainedObject->GetBoundingBoxMax(&width2, &height2);
|
|
startX += (double)(spacingX + (width2 / 2.0));
|
|
if (!Equals(startX, constrainedObject->GetX()))
|
|
{
|
|
constrainedObject->Move(startX, constrainedObject->GetY(), FALSE);
|
|
changed = TRUE;
|
|
}
|
|
startX += (double)(width2 / 2.0);
|
|
node = node->GetNext();
|
|
}
|
|
return changed;
|
|
}
|
|
case gyCONSTRAINT_CENTRED_BOTH:
|
|
{
|
|
int n = m_constrainedObjects.GetCount();
|
|
double totalObjectWidth = 0.0;
|
|
double totalObjectHeight = 0.0;
|
|
wxNode *node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
|
|
double width2, height2;
|
|
constrainedObject->GetBoundingBoxMax(&width2, &height2);
|
|
totalObjectWidth += width2;
|
|
totalObjectHeight += height2;
|
|
node = node->GetNext();
|
|
}
|
|
double startX;
|
|
double spacingX;
|
|
double startY;
|
|
double spacingY;
|
|
|
|
// Check if within the constraining object...
|
|
if ((totalObjectWidth + (n + 1)*m_xSpacing) <= minWidth)
|
|
{
|
|
spacingX = (double)((minWidth - totalObjectWidth) / (n + 1));
|
|
startX = (double)(x - (minWidth / 2.0));
|
|
}
|
|
// Otherwise, use default spacing
|
|
else
|
|
{
|
|
spacingX = m_xSpacing;
|
|
startX = (double)(x - ((totalObjectWidth + (n + 1) * spacingX) / 2.0));
|
|
}
|
|
|
|
// Check if within the constraining object...
|
|
if ((totalObjectHeight + (n + 1)*m_ySpacing) <= minHeight)
|
|
{
|
|
spacingY = (double)((minHeight - totalObjectHeight) / (n + 1));
|
|
startY = (double)(y - (minHeight / 2.0));
|
|
}
|
|
// Otherwise, use default spacing
|
|
else
|
|
{
|
|
spacingY = m_ySpacing;
|
|
startY = (double)(y - ((totalObjectHeight + (n + 1) * spacingY) / 2.0));
|
|
}
|
|
|
|
// Now position the objects
|
|
bool changed = FALSE;
|
|
node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
double width2, height2;
|
|
constrainedObject->GetBoundingBoxMax(&width2, &height2);
|
|
startX += (double)(spacingX + (width2 / 2.0));
|
|
startY += (double)(spacingY + (height2 / 2.0));
|
|
|
|
if ((!Equals(startX, constrainedObject->GetX())) || (!Equals(startY, constrainedObject->GetY())))
|
|
{
|
|
constrainedObject->Move(startX, startY, FALSE);
|
|
changed = TRUE;
|
|
}
|
|
|
|
startX += (double)(width2 / 2.0);
|
|
startY += (double)(height2 / 2.0);
|
|
|
|
node = node->GetNext();
|
|
}
|
|
return changed;
|
|
}
|
|
case gyCONSTRAINT_LEFT_OF:
|
|
{
|
|
bool changed = FALSE;
|
|
|
|
wxNode *node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
|
|
double width2, height2;
|
|
constrainedObject->GetBoundingBoxMax(&width2, &height2);
|
|
|
|
double x3 = (double)(x - (minWidth / 2.0) - (width2 / 2.0) - m_xSpacing);
|
|
if (!Equals(x3, constrainedObject->GetX()))
|
|
{
|
|
changed = TRUE;
|
|
constrainedObject->Move(x3, constrainedObject->GetY(), FALSE);
|
|
}
|
|
|
|
node = node->GetNext();
|
|
}
|
|
return changed;
|
|
}
|
|
case gyCONSTRAINT_RIGHT_OF:
|
|
{
|
|
bool changed = FALSE;
|
|
|
|
wxNode *node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
|
|
double width2, height2;
|
|
constrainedObject->GetBoundingBoxMax(&width2, &height2);
|
|
|
|
double x3 = (double)(x + (minWidth / 2.0) + (width2 / 2.0) + m_xSpacing);
|
|
if (!Equals(x3, constrainedObject->GetX()))
|
|
{
|
|
changed = TRUE;
|
|
constrainedObject->Move(x3, constrainedObject->GetY(), FALSE);
|
|
}
|
|
|
|
node = node->GetNext();
|
|
}
|
|
return changed;
|
|
}
|
|
case gyCONSTRAINT_ABOVE:
|
|
{
|
|
bool changed = FALSE;
|
|
|
|
wxNode *node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
|
|
double width2, height2;
|
|
constrainedObject->GetBoundingBoxMax(&width2, &height2);
|
|
|
|
double y3 = (double)(y - (minHeight / 2.0) - (height2 / 2.0) - m_ySpacing);
|
|
if (!Equals(y3, constrainedObject->GetY()))
|
|
{
|
|
changed = TRUE;
|
|
constrainedObject->Move(constrainedObject->GetX(), y3, FALSE);
|
|
}
|
|
|
|
node = node->GetNext();
|
|
}
|
|
return changed;
|
|
}
|
|
case gyCONSTRAINT_BELOW:
|
|
{
|
|
bool changed = FALSE;
|
|
|
|
wxNode *node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
|
|
double width2, height2;
|
|
constrainedObject->GetBoundingBoxMax(&width2, &height2);
|
|
|
|
double y3 = (double)(y + (minHeight / 2.0) + (height2 / 2.0) + m_ySpacing);
|
|
if (!Equals(y3, constrainedObject->GetY()))
|
|
{
|
|
changed = TRUE;
|
|
constrainedObject->Move(constrainedObject->GetX(), y3, FALSE);
|
|
}
|
|
|
|
node = node->GetNext();
|
|
}
|
|
return changed;
|
|
}
|
|
case gyCONSTRAINT_ALIGNED_LEFT:
|
|
{
|
|
bool changed = FALSE;
|
|
|
|
wxNode *node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
|
|
double width2, height2;
|
|
constrainedObject->GetBoundingBoxMax(&width2, &height2);
|
|
|
|
double x3 = (double)(x - (minWidth / 2.0) + (width2 / 2.0) + m_xSpacing);
|
|
if (!Equals(x3, constrainedObject->GetX()))
|
|
{
|
|
changed = TRUE;
|
|
constrainedObject->Move(x3, constrainedObject->GetY(), FALSE);
|
|
}
|
|
|
|
node = node->GetNext();
|
|
}
|
|
return changed;
|
|
}
|
|
case gyCONSTRAINT_ALIGNED_RIGHT:
|
|
{
|
|
bool changed = FALSE;
|
|
|
|
wxNode *node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
|
|
double width2, height2;
|
|
constrainedObject->GetBoundingBoxMax(&width2, &height2);
|
|
|
|
double x3 = (double)(x + (minWidth / 2.0) - (width2 / 2.0) - m_xSpacing);
|
|
if (!Equals(x3, constrainedObject->GetX()))
|
|
{
|
|
changed = TRUE;
|
|
constrainedObject->Move(x3, constrainedObject->GetY(), FALSE);
|
|
}
|
|
|
|
node = node->GetNext();
|
|
}
|
|
return changed;
|
|
#if 0
|
|
// two returned values ?
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
case gyCONSTRAINT_ALIGNED_TOP:
|
|
{
|
|
bool changed = FALSE;
|
|
|
|
wxNode *node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
|
|
double width2, height2;
|
|
constrainedObject->GetBoundingBoxMax(&width2, &height2);
|
|
|
|
double y3 = (double)(y - (minHeight / 2.0) + (height2 / 2.0) + m_ySpacing);
|
|
if (!Equals(y3, constrainedObject->GetY()))
|
|
{
|
|
changed = TRUE;
|
|
constrainedObject->Move(constrainedObject->GetX(), y3, FALSE);
|
|
}
|
|
|
|
node = node->GetNext();
|
|
}
|
|
return changed;
|
|
}
|
|
case gyCONSTRAINT_ALIGNED_BOTTOM:
|
|
{
|
|
bool changed = FALSE;
|
|
|
|
wxNode *node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
|
|
double width2, height2;
|
|
constrainedObject->GetBoundingBoxMax(&width2, &height2);
|
|
|
|
double y3 = (double)(y + (minHeight / 2.0) - (height2 / 2.0) - m_ySpacing);
|
|
if (!Equals(y3, constrainedObject->GetY()))
|
|
{
|
|
changed = TRUE;
|
|
constrainedObject->Move(constrainedObject->GetX(), y3, FALSE);
|
|
}
|
|
|
|
node = node->GetNext();
|
|
}
|
|
return changed;
|
|
}
|
|
case gyCONSTRAINT_MIDALIGNED_LEFT:
|
|
{
|
|
bool changed = FALSE;
|
|
|
|
wxNode *node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
|
|
double x3 = (double)(x - (minWidth / 2.0));
|
|
if (!Equals(x3, constrainedObject->GetX()))
|
|
{
|
|
changed = TRUE;
|
|
constrainedObject->Move(x3, constrainedObject->GetY(), FALSE);
|
|
}
|
|
|
|
node = node->GetNext();
|
|
}
|
|
return changed;
|
|
}
|
|
case gyCONSTRAINT_MIDALIGNED_RIGHT:
|
|
{
|
|
bool changed = FALSE;
|
|
|
|
wxNode *node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
|
|
double x3 = (double)(x + (minWidth / 2.0));
|
|
if (!Equals(x3, constrainedObject->GetX()))
|
|
{
|
|
changed = TRUE;
|
|
constrainedObject->Move(x3, constrainedObject->GetY(), FALSE);
|
|
}
|
|
|
|
node = node->GetNext();
|
|
}
|
|
return changed;
|
|
#if 0
|
|
// two returned values ?
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
case gyCONSTRAINT_MIDALIGNED_TOP:
|
|
{
|
|
bool changed = FALSE;
|
|
|
|
wxNode *node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
|
|
double y3 = (double)(y - (minHeight / 2.0));
|
|
if (!Equals(y3, constrainedObject->GetY()))
|
|
{
|
|
changed = TRUE;
|
|
constrainedObject->Move(constrainedObject->GetX(), y3, FALSE);
|
|
}
|
|
|
|
node = node->GetNext();
|
|
}
|
|
return changed;
|
|
}
|
|
case gyCONSTRAINT_MIDALIGNED_BOTTOM:
|
|
{
|
|
bool changed = FALSE;
|
|
|
|
wxNode *node = m_constrainedObjects.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShape *constrainedObject = (wxShape *)node->GetData();
|
|
|
|
double y3 = (double)(y + (minHeight / 2.0));
|
|
if (!Equals(y3, constrainedObject->GetY()))
|
|
{
|
|
changed = TRUE;
|
|
constrainedObject->Move(constrainedObject->GetX(), y3, FALSE);
|
|
}
|
|
|
|
node = node->GetNext();
|
|
}
|
|
return changed;
|
|
}
|
|
#if 0
|
|
// default value handled in main function body
|
|
default:
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|