--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: composit.cpp
+// Purpose: Composite OGL class
+// Author: Julian Smart
+// Modified by:
+// Created: 12/07/98
+// RCS-ID: $Id$
+// Copyright: (c) Julian Smart
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+#pragma implementation "composit.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include <wx/wxprec.h>
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+#include <wx/wxexpr.h>
+
+#include <wx/ogl/basic.h>
+#include <wx/ogl/basicp.h>
+#include <wx/ogl/constrnt.h>
+#include <wx/ogl/composit.h>
+#include <wx/ogl/misc.h>
+#include <wx/ogl/canvas.h>
+
+// Sometimes, objects need to access the whole database to
+// construct themselves.
+wxExprDatabase *GlobalwxExprDatabase = NULL;
+
+
+/*
+ * Division control point
+ */
+
+class wxDivisionControlPoint: public wxControlPoint
+{
+ DECLARE_DYNAMIC_CLASS(wxDivisionControlPoint)
+ public:
+ wxDivisionControlPoint() {}
+ wxDivisionControlPoint(wxShapeCanvas *the_canvas, wxShape *object, double size, double the_xoffset, double the_yoffset, int the_type);
+ ~wxDivisionControlPoint();
+
+ void OnDragLeft(bool draw, double x, double y, int keys=0, int attachment = 0);
+ void OnBeginDragLeft(double x, double y, int keys=0, int attachment = 0);
+ void OnEndDragLeft(double x, double y, int keys=0, int attachment = 0);
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxDivisionControlPoint, wxControlPoint)
+
+/*
+ * Composite object
+ *
+ */
+
+IMPLEMENT_DYNAMIC_CLASS(wxCompositeShape, wxRectangleShape)
+
+wxCompositeShape::wxCompositeShape(): wxRectangleShape(10.0, 10.0)
+{
+// selectable = FALSE;
+ m_oldX = m_xpos;
+ m_oldY = m_ypos;
+}
+
+wxCompositeShape::~wxCompositeShape()
+{
+ wxNode *node = m_constraints.First();
+ while (node)
+ {
+ wxOGLConstraint *constraint = (wxOGLConstraint *)node->Data();
+ delete constraint;
+ node = node->Next();
+ }
+ node = m_children.First();
+ while (node)
+ {
+ wxShape *object = (wxShape *)node->Data();
+ wxNode *next = node->Next();
+ object->Unlink();
+ delete object;
+ node = next;
+ }
+}
+
+void wxCompositeShape::OnDraw(wxDC& dc)
+{
+ double x1 = (double)(m_xpos - m_width/2.0);
+ double y1 = (double)(m_ypos - m_height/2.0);
+
+ if (m_shadowMode != SHADOW_NONE)
+ {
+ if (m_shadowBrush)
+ dc.SetBrush(* m_shadowBrush);
+ dc.SetPen(* g_oglTransparentPen);
+
+ if (m_cornerRadius != 0.0)
+ dc.DrawRoundedRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY),
+ WXROUND(m_width), WXROUND(m_height), m_cornerRadius);
+ else
+ dc.DrawRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY), WXROUND(m_width), WXROUND(m_height));
+ }
+}
+
+void wxCompositeShape::OnDrawContents(wxDC& dc)
+{
+ wxNode *node = m_children.First();
+ while (node)
+ {
+ wxShape *object = (wxShape *)node->Data();
+ object->Draw(dc);
+ object->DrawLinks(dc);
+ node = node->Next();
+ }
+ wxShape::OnDrawContents(dc);
+}
+
+bool wxCompositeShape::OnMovePre(wxDC& dc, double x, double y, double oldx, double oldy, bool display)
+{
+ double diffX = x - oldx;
+ double diffY = y - oldy;
+ wxNode *node = m_children.First();
+ while (node)
+ {
+ wxShape *object = (wxShape *)node->Data();
+
+ object->Erase(dc);
+ object->Move(dc, object->GetX() + diffX, object->GetY() + diffY, display);
+
+ node = node->Next();
+ }
+ return TRUE;
+}
+
+void wxCompositeShape::OnErase(wxDC& dc)
+{
+ wxRectangleShape::OnErase(dc);
+ wxNode *node = m_children.First();
+ while (node)
+ {
+ wxShape *object = (wxShape *)node->Data();
+ object->Erase(dc);
+ node = node->Next();
+ }
+}
+
+static double objectStartX = 0.0;
+static double objectStartY = 0.0;
+
+void wxCompositeShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
+{
+ double xx = x;
+ double yy = y;
+ m_canvas->Snap(&xx, &yy);
+ double offsetX = xx - objectStartX;
+ double offsetY = yy - objectStartY;
+
+ wxClientDC dc(GetCanvas());
+ GetCanvas()->PrepareDC(dc);
+
+ dc.SetLogicalFunction(OGLRBLF);
+ wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
+ dc.SetPen(dottedPen);
+ dc.SetBrush((* wxTRANSPARENT_BRUSH));
+
+ GetEventHandler()->OnDrawOutline(dc, GetX() + offsetX, GetY() + offsetY, GetWidth(), GetHeight());
+// wxShape::OnDragLeft(draw, x, y, keys, attachment);
+}
+
+void wxCompositeShape::OnBeginDragLeft(double x, double y, int keys, int attachment)
+{
+ objectStartX = x;
+ objectStartY = y;
+
+ wxClientDC dc(GetCanvas());
+ GetCanvas()->PrepareDC(dc);
+
+ Erase(dc);
+
+ dc.SetLogicalFunction(OGLRBLF);
+
+ wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
+ dc.SetPen(dottedPen);
+ dc.SetBrush((* wxTRANSPARENT_BRUSH));
+ m_canvas->CaptureMouse();
+
+ double xx = x;
+ double yy = y;
+ m_canvas->Snap(&xx, &yy);
+ double offsetX = xx - objectStartX;
+ double offsetY = yy - objectStartY;
+
+ GetEventHandler()->OnDrawOutline(dc, GetX() + offsetX, GetY() + offsetY, GetWidth(), GetHeight());
+
+// wxShape::OnBeginDragLeft(x, y, keys, attachment);
+}
+
+void wxCompositeShape::OnEndDragLeft(double x, double y, int keys, int attachment)
+{
+// wxShape::OnEndDragLeft(x, y, keys, attachment);
+
+ wxClientDC dc(GetCanvas());
+ GetCanvas()->PrepareDC(dc);
+
+ m_canvas->ReleaseMouse();
+
+ if (!m_draggable)
+ {
+ if (m_parent) m_parent->GetEventHandler()->OnEndDragLeft(x, y, keys, 0);
+ return;
+ }
+
+ dc.SetLogicalFunction(wxCOPY);
+ double xx = x;
+ double yy = y;
+ m_canvas->Snap(&xx, &yy);
+ double offsetX = xx - objectStartX;
+ double offsetY = yy - objectStartY;
+
+ Move(dc, GetX() + offsetX, GetY() + offsetY);
+
+ if (m_canvas && !m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
+}
+
+void wxCompositeShape::OnRightClick(double x, double y, int keys, int attachment)
+{
+ // If we get a ctrl-right click, this means send the message to
+ // the division, so we can invoke a user interface for dealing with regions.
+ if (keys & KEY_CTRL)
+ {
+ wxNode *node = m_divisions.First();
+ while (node)
+ {
+ wxDivisionShape *division = (wxDivisionShape *)node->Data();
+ wxNode *next = node->Next();
+ int attach = 0;
+ double dist = 0.0;
+ if (division->HitTest(x, y, &attach, &dist))
+ {
+ division->GetEventHandler()->OnRightClick(x, y, keys, attach);
+ node = NULL;
+ }
+ if (node)
+ node = next;
+ }
+ }
+}
+
+void wxCompositeShape::SetSize(double w, double h, bool recursive)
+{
+ SetAttachmentSize(w, h);
+
+ double xScale = (double)(w/(wxMax(1.0, GetWidth())));
+ double yScale = (double)(h/(wxMax(1.0, GetHeight())));
+
+ m_width = w;
+ m_height = h;
+
+ if (!recursive) return;
+
+ wxNode *node = m_children.First();
+
+ wxClientDC dc(GetCanvas());
+ GetCanvas()->PrepareDC(dc);
+
+ double xBound, yBound;
+ while (node)
+ {
+ wxShape *object = (wxShape *)node->Data();
+
+ // Scale the position first
+ double newX = (double)(((object->GetX() - GetX())*xScale) + GetX());
+ double newY = (double)(((object->GetY() - GetY())*yScale) + GetY());
+ object->Show(FALSE);
+ object->Move(dc, newX, newY);
+ object->Show(TRUE);
+
+ // Now set the scaled size
+ object->GetBoundingBoxMin(&xBound, &yBound);
+ object->SetSize(object->GetFixedWidth() ? xBound : xScale*xBound,
+ object->GetFixedHeight() ? yBound : yScale*yBound);
+
+ node = node->Next();
+ }
+ SetDefaultRegionSize();
+}
+
+void wxCompositeShape::AddChild(wxShape *child, wxShape *addAfter)
+{
+ m_children.Append(child);
+ child->SetParent(this);
+ if (m_canvas)
+ {
+ // Ensure we add at the right position
+ if (addAfter)
+ child->RemoveFromCanvas(m_canvas);
+ child->AddToCanvas(m_canvas, addAfter);
+ }
+}
+
+void wxCompositeShape::RemoveChild(wxShape *child)
+{
+ m_children.DeleteObject(child);
+ m_divisions.DeleteObject(child);
+ RemoveChildFromConstraints(child);
+ child->SetParent(NULL);
+}
+
+void wxCompositeShape::DeleteConstraintsInvolvingChild(wxShape *child)
+{
+ wxNode *node = m_constraints.First();
+ while (node)
+ {
+ wxOGLConstraint *constraint = (wxOGLConstraint *)node->Data();
+ wxNode *nextNode = node->Next();
+
+ if ((constraint->m_constrainingObject == child) ||
+ constraint->m_constrainedObjects.Member(child))
+ {
+ delete constraint;
+ delete node;
+ }
+ node = nextNode;
+ }
+}
+
+void wxCompositeShape::RemoveChildFromConstraints(wxShape *child)
+{
+ wxNode *node = m_constraints.First();
+ while (node)
+ {
+ wxOGLConstraint *constraint = (wxOGLConstraint *)node->Data();
+ wxNode *nextNode = node->Next();
+
+ if (constraint->m_constrainedObjects.Member(child))
+ constraint->m_constrainedObjects.DeleteObject(child);
+ if (constraint->m_constrainingObject == child)
+ constraint->m_constrainingObject = NULL;
+
+ // Delete the constraint if no participants left
+ if (!constraint->m_constrainingObject)
+ {
+ delete constraint;
+ delete node;
+ }
+
+ node = nextNode;
+ }
+}
+
+void wxCompositeShape::Copy(wxShape& copy)
+{
+ wxRectangleShape::Copy(copy);
+
+ wxASSERT( copy.IsKindOf(CLASSINFO(wxCompositeShape)) ) ;
+
+ wxCompositeShape& compositeCopy = (wxCompositeShape&) copy;
+
+ // Associate old and new copies for compositeCopying constraints and division geometry
+ oglObjectCopyMapping.Append((long)this, &compositeCopy);
+
+ // Copy the children
+ wxNode *node = m_children.First();
+ while (node)
+ {
+ wxShape *object = (wxShape *)node->Data();
+ wxShape *newObject = object->CreateNewCopy(FALSE, FALSE);
+ if (newObject->GetId() == 0)
+ newObject->SetId(wxNewId());
+
+ newObject->SetParent(&compositeCopy);
+ compositeCopy.m_children.Append(newObject);
+
+ // Some m_children may be divisions
+ if (m_divisions.Member(object))
+ compositeCopy.m_divisions.Append(newObject);
+
+ oglObjectCopyMapping.Append((long)object, newObject);
+
+ node = node->Next();
+ }
+
+ // Copy the constraints
+ node = m_constraints.First();
+ while (node)
+ {
+ wxOGLConstraint *constraint = (wxOGLConstraint *)node->Data();
+
+ wxShape *newConstraining = (wxShape *)(oglObjectCopyMapping.Find((long)constraint->m_constrainingObject)->Data());
+
+ wxList newConstrainedList;
+ wxNode *node2 = constraint->m_constrainedObjects.First();
+ while (node2)
+ {
+ wxShape *constrainedObject = (wxShape *)node2->Data();
+ wxShape *newConstrained = (wxShape *)(oglObjectCopyMapping.Find((long)constrainedObject)->Data());
+ newConstrainedList.Append(newConstrained);
+ node2 = node2->Next();
+ }
+
+ wxOGLConstraint *newConstraint = new wxOGLConstraint(constraint->m_constraintType, newConstraining,
+ newConstrainedList);
+ newConstraint->m_constraintId = constraint->m_constraintId;
+ if (constraint->m_constraintName)
+ {
+ newConstraint->m_constraintName = constraint->m_constraintName;
+ }
+ newConstraint->SetSpacing(constraint->m_xSpacing, constraint->m_ySpacing);
+ compositeCopy.m_constraints.Append(newConstraint);
+
+ node = node->Next();
+ }
+
+ // Now compositeCopy the division geometry
+ node = m_divisions.First();
+ while (node)
+ {
+ wxDivisionShape *division = (wxDivisionShape *)node->Data();
+ wxNode *node1 = oglObjectCopyMapping.Find((long)division);
+ wxNode *leftNode = NULL;
+ wxNode *topNode = NULL;
+ wxNode *rightNode = NULL;
+ wxNode *bottomNode = NULL;
+ if (division->GetLeftSide())
+ leftNode = oglObjectCopyMapping.Find((long)division->GetLeftSide());
+ if (division->GetTopSide())
+ topNode = oglObjectCopyMapping.Find((long)division->GetTopSide());
+ if (division->GetRightSide())
+ rightNode = oglObjectCopyMapping.Find((long)division->GetRightSide());
+ if (division->GetBottomSide())
+ bottomNode = oglObjectCopyMapping.Find((long)division->GetBottomSide());
+ if (node1)
+ {
+ wxDivisionShape *newDivision = (wxDivisionShape *)node1->Data();
+ if (leftNode)
+ newDivision->SetLeftSide((wxDivisionShape *)leftNode->Data());
+ if (topNode)
+ newDivision->SetTopSide((wxDivisionShape *)topNode->Data());
+ if (rightNode)
+ newDivision->SetRightSide((wxDivisionShape *)rightNode->Data());
+ if (bottomNode)
+ newDivision->SetBottomSide((wxDivisionShape *)bottomNode->Data());
+ }
+ node = node->Next();
+ }
+}
+
+wxOGLConstraint *wxCompositeShape::AddConstraint(wxOGLConstraint *constraint)
+{
+ m_constraints.Append(constraint);
+ if (constraint->m_constraintId == 0)
+ constraint->m_constraintId = wxNewId();
+ return constraint;
+}
+
+wxOGLConstraint *wxCompositeShape::AddConstraint(int type, wxShape *constraining, wxList& constrained)
+{
+ wxOGLConstraint *constraint = new wxOGLConstraint(type, constraining, constrained);
+ if (constraint->m_constraintId == 0)
+ constraint->m_constraintId = wxNewId();
+ m_constraints.Append(constraint);
+ return constraint;
+}
+
+wxOGLConstraint *wxCompositeShape::AddConstraint(int type, wxShape *constraining, wxShape *constrained)
+{
+ wxList l;
+ l.Append(constrained);
+ wxOGLConstraint *constraint = new wxOGLConstraint(type, constraining, l);
+ if (constraint->m_constraintId == 0)
+ constraint->m_constraintId = wxNewId();
+ m_constraints.Append(constraint);
+ return constraint;
+}
+
+wxOGLConstraint *wxCompositeShape::FindConstraint(long cId, wxCompositeShape **actualComposite)
+{
+ wxNode *node = m_constraints.First();
+ while (node)
+ {
+ wxOGLConstraint *constraint = (wxOGLConstraint *)node->Data();
+ if (constraint->m_constraintId == cId)
+ {
+ if (actualComposite)
+ *actualComposite = this;
+ return constraint;
+ }
+ node = node->Next();
+ }
+ // If not found, try children.
+ node = m_children.First();
+ while (node)
+ {
+ wxShape *child = (wxShape *)node->Data();
+ if (child->IsKindOf(CLASSINFO(wxCompositeShape)))
+ {
+ wxOGLConstraint *constraint = ((wxCompositeShape *)child)->FindConstraint(cId, actualComposite);
+ if (constraint)
+ {
+ if (actualComposite)
+ *actualComposite = (wxCompositeShape *)child;
+ return constraint;
+ }
+ }
+ node = node->Next();
+ }
+ return NULL;
+}
+
+void wxCompositeShape::DeleteConstraint(wxOGLConstraint *constraint)
+{
+ m_constraints.DeleteObject(constraint);
+ delete constraint;
+}
+
+void wxCompositeShape::CalculateSize()
+{
+ double maxX = (double) -999999.9;
+ double maxY = (double) -999999.9;
+ double minX = (double) 999999.9;
+ double minY = (double) 999999.9;
+
+ double w, h;
+ wxNode *node = m_children.First();
+ while (node)
+ {
+ wxShape *object = (wxShape *)node->Data();
+
+ // Recalculate size of composite objects because may not conform
+ // to size it was set to - depends on the children.
+ object->CalculateSize();
+
+ object->GetBoundingBoxMax(&w, &h);
+ if ((object->GetX() + (w/2.0)) > maxX)
+ maxX = (double)(object->GetX() + (w/2.0));
+ if ((object->GetX() - (w/2.0)) < minX)
+ minX = (double)(object->GetX() - (w/2.0));
+ if ((object->GetY() + (h/2.0)) > maxY)
+ maxY = (double)(object->GetY() + (h/2.0));
+ if ((object->GetY() - (h/2.0)) < minY)
+ minY = (double)(object->GetY() - (h/2.0));
+
+ node = node->Next();
+ }
+ m_width = maxX - minX;
+ m_height = maxY - minY;
+ m_xpos = (double)(m_width/2.0 + minX);
+ m_ypos = (double)(m_height/2.0 + minY);
+}
+
+bool wxCompositeShape::Recompute()
+{
+ int noIterations = 0;
+ bool changed = TRUE;
+ while (changed && (noIterations < 500))
+ {
+ changed = Constrain();
+ noIterations ++;
+ }
+/*
+#ifdef wx_x
+ if (changed)
+ cerr << "Warning: constraint algorithm failed after 500 iterations.\n";
+#endif
+*/
+ return (!changed);
+}
+
+bool wxCompositeShape::Constrain()
+{
+ CalculateSize();
+
+ bool changed = FALSE;
+ wxNode *node = m_children.First();
+ while (node)
+ {
+ wxShape *object = (wxShape *)node->Data();
+ if (object->Constrain())
+ changed = TRUE;
+ node = node->Next();
+ }
+
+ node = m_constraints.First();
+ while (node)
+ {
+ wxOGLConstraint *constraint = (wxOGLConstraint *)node->Data();
+ if (constraint->Evaluate()) changed = TRUE;
+ node = node->Next();
+ }
+ return changed;
+}
+
+#ifdef PROLOGIO
+void wxCompositeShape::WriteAttributes(wxExpr *clause)
+{
+ wxRectangleShape::WriteAttributes(clause);
+
+// clause->AddAttributeValue("selectable", (long)selectable);
+
+ // Output constraints as constraint1 = (...), constraint2 = (...), etc.
+ int constraintNo = 1;
+ char m_constraintNameBuf[20];
+ wxNode *node = m_constraints.First();
+ while (node)
+ {
+ wxOGLConstraint *constraint = (wxOGLConstraint *)node->Data();
+ sprintf(m_constraintNameBuf, "constraint%d", constraintNo);
+
+ // Each constraint is stored in the form
+ // (type name id xspacing yspacing m_constrainingObjectId constrainedObjectIdList)
+ wxExpr *constraintExpr = new wxExpr(wxExprList);
+ constraintExpr->Append(new wxExpr((long)constraint->m_constraintType));
+ constraintExpr->Append(new wxExpr(wxExprString, constraint->m_constraintName));
+ constraintExpr->Append(new wxExpr(constraint->m_constraintId));
+ constraintExpr->Append(new wxExpr(constraint->m_xSpacing));
+ constraintExpr->Append(new wxExpr(constraint->m_ySpacing));
+ constraintExpr->Append(new wxExpr(constraint->m_constrainingObject->GetId()));
+
+ wxExpr *objectList = new wxExpr(wxExprList);
+ wxNode *node1 = constraint->m_constrainedObjects.First();
+ while (node1)
+ {
+ wxShape *obj = (wxShape *)node1->Data();
+ objectList->Append(new wxExpr(obj->GetId()));
+ node1 = node1->Next();
+ }
+ constraintExpr->Append(objectList);
+
+ clause->AddAttributeValue(m_constraintNameBuf, constraintExpr);
+
+ node = node->Next();
+ constraintNo ++;
+ }
+
+ // Write the ids of all the child images
+ wxExpr *childrenExpr = new wxExpr(wxExprList);
+ node = m_children.First();
+ while (node)
+ {
+ wxShape *child = (wxShape *)node->Data();
+ childrenExpr->Append(new wxExpr(child->GetId()));
+ node = node->Next();
+ }
+ clause->AddAttributeValue("children", childrenExpr);
+
+ // Write the ids of all the division images
+ if (m_divisions.Number() > 0)
+ {
+ wxExpr *divisionsExpr = new wxExpr(wxExprList);
+ node = m_divisions.First();
+ while (node)
+ {
+ wxShape *child = (wxShape *)node->Data();
+ divisionsExpr->Append(new wxExpr(child->GetId()));
+ node = node->Next();
+ }
+ clause->AddAttributeValue("divisions", divisionsExpr);
+ }
+}
+
+// Problem. Child images are always written AFTER the parent
+// so as to be able to link up to parent. So we may not be able
+// to find the constraint participants until we've read everything
+// in. Need to have another pass for composites.
+void wxCompositeShape::ReadAttributes(wxExpr *clause)
+{
+ wxRectangleShape::ReadAttributes(clause);
+
+// clause->GetAttributeValue("selectable", selectable);
+}
+
+void wxCompositeShape::ReadConstraints(wxExpr *clause, wxExprDatabase *database)
+{
+ // Constraints are output as constraint1 = (...), constraint2 = (...), etc.
+ int constraintNo = 1;
+ char m_constraintNameBuf[20];
+ bool haveConstraints = TRUE;
+
+ while (haveConstraints)
+ {
+ sprintf(m_constraintNameBuf, "constraint%d", constraintNo);
+ wxExpr *constraintExpr = NULL;
+ clause->GetAttributeValue(m_constraintNameBuf, &constraintExpr);
+ if (!constraintExpr)
+ {
+ haveConstraints = FALSE;
+ break;
+ }
+ int cType = 0;
+ double cXSpacing = 0.0;
+ double cYSpacing = 0.0;
+ wxString cName("");
+ long cId = 0;
+ wxShape *m_constrainingObject = NULL;
+ wxList m_constrainedObjects;
+
+ // Each constraint is stored in the form
+ // (type name id xspacing yspacing m_constrainingObjectId constrainedObjectIdList)
+
+ wxExpr *typeExpr = constraintExpr->Nth(0);
+ wxExpr *nameExpr = constraintExpr->Nth(1);
+ wxExpr *idExpr = constraintExpr->Nth(2);
+ wxExpr *xExpr = constraintExpr->Nth(3);
+ wxExpr *yExpr = constraintExpr->Nth(4);
+ wxExpr *constrainingExpr = constraintExpr->Nth(5);
+ wxExpr *constrainedExpr = constraintExpr->Nth(6);
+
+ cType = (int)typeExpr->IntegerValue();
+ cXSpacing = xExpr->RealValue();
+ cYSpacing = yExpr->RealValue();
+ cName = nameExpr->StringValue();
+ cId = idExpr->IntegerValue();
+
+ wxExpr *objExpr1 = database->HashFind("node_image", constrainingExpr->IntegerValue());
+ if (objExpr1 && objExpr1->GetClientData())
+ m_constrainingObject = (wxShape *)objExpr1->GetClientData();
+ else
+ wxFatalError("Couldn't find constraining image of composite.", "Object graphics error");
+
+ int i = 0;
+ wxExpr *currentIdExpr = constrainedExpr->Nth(i);
+ while (currentIdExpr)
+ {
+ long currentId = currentIdExpr->IntegerValue();
+ wxExpr *objExpr2 = database->HashFind("node_image", currentId);
+ if (objExpr2 && objExpr2->GetClientData())
+ {
+ m_constrainedObjects.Append((wxShape *)objExpr2->GetClientData());
+ }
+ else
+ {
+ wxFatalError("Couldn't find constrained image of composite.", "Object graphics error");
+ }
+
+ i ++;
+ currentIdExpr = constrainedExpr->Nth(i);
+ }
+ wxOGLConstraint *newConstraint = AddConstraint(cType, m_constrainingObject, m_constrainedObjects);
+ newConstraint->SetSpacing(cXSpacing, cYSpacing);
+ newConstraint->m_constraintId = cId;
+ newConstraint->m_constraintName = (const char*) cName;
+ constraintNo ++;
+ }
+}
+#endif
+
+// Make this composite into a container by creating one wxDivisionShape
+void wxCompositeShape::MakeContainer()
+{
+ wxDivisionShape *division = OnCreateDivision();
+ m_divisions.Append(division);
+ AddChild(division);
+
+ division->SetSize(m_width, m_height);
+
+ wxClientDC dc(GetCanvas());
+ GetCanvas()->PrepareDC(dc);
+
+ division->Move(dc, GetX(), GetY());
+ Recompute();
+ division->Show(TRUE);
+}
+
+wxDivisionShape *wxCompositeShape::OnCreateDivision()
+{
+ return new wxDivisionShape;
+}
+
+wxShape *wxCompositeShape::FindContainerImage()
+{
+ wxNode *node = m_children.First();
+ while (node)
+ {
+ wxShape *child = (wxShape *)node->Data();
+ if (!m_divisions.Member(child))
+ return child;
+ node = node->Next();
+ }
+ return NULL;
+}
+
+// Returns TRUE if division is a descendant of this container
+bool wxCompositeShape::ContainsDivision(wxDivisionShape *division)
+{
+ if (m_divisions.Member(division))
+ return TRUE;
+ wxNode *node = m_children.First();
+ while (node)
+ {
+ wxShape *child = (wxShape *)node->Data();
+ if (child->IsKindOf(CLASSINFO(wxCompositeShape)))
+ {
+ bool ans = ((wxCompositeShape *)child)->ContainsDivision(division);
+ if (ans)
+ return TRUE;
+ }
+ node = node->Next();
+ }
+ return FALSE;
+}
+
+/*
+ * Division object
+ *
+ */
+
+IMPLEMENT_DYNAMIC_CLASS(wxDivisionShape, wxCompositeShape)
+
+wxDivisionShape::wxDivisionShape()
+{
+ SetSensitivityFilter(OP_CLICK_LEFT | OP_CLICK_RIGHT | OP_DRAG_RIGHT);
+ SetCentreResize(FALSE);
+ SetAttachmentMode(TRUE);
+ m_leftSide = NULL;
+ m_rightSide = NULL;
+ m_topSide = NULL;
+ m_bottomSide = NULL;
+ m_handleSide = DIVISION_SIDE_NONE;
+ m_leftSidePen = wxBLACK_PEN;
+ m_topSidePen = wxBLACK_PEN;
+ m_leftSideColour = "BLACK";
+ m_topSideColour = "BLACK";
+ m_leftSideStyle = "Solid";
+ m_topSideStyle = "Solid";
+ ClearRegions();
+}
+
+wxDivisionShape::~wxDivisionShape()
+{
+}
+
+void wxDivisionShape::OnDraw(wxDC& dc)
+{
+ dc.SetBrush(* wxTRANSPARENT_BRUSH);
+ dc.SetBackgroundMode(wxTRANSPARENT);
+
+ double x1 = (double)(GetX() - (GetWidth()/2.0));
+ double y1 = (double)(GetY() - (GetHeight()/2.0));
+ double x2 = (double)(GetX() + (GetWidth()/2.0));
+ double y2 = (double)(GetY() + (GetHeight()/2.0));
+
+ // Should subtract 1 pixel if drawing under Windows
+#ifdef __WXMSW__
+ y2 -= (double)1.0;
+#endif
+
+ if (m_leftSide)
+ {
+ dc.SetPen(* m_leftSidePen);
+ dc.DrawLine(WXROUND(x1), WXROUND(y2), WXROUND(x1), WXROUND(y1));
+ }
+ if (m_topSide)
+ {
+ dc.SetPen(* m_topSidePen);
+ dc.DrawLine(WXROUND(x1), WXROUND(y1), WXROUND(x2), WXROUND(y1));
+ }
+
+ // For testing purposes, draw a rectangle so we know
+ // how big the division is.
+// SetBrush(* wxCYAN_BRUSH);
+// wxRectangleShape::OnDraw(dc);
+}
+
+void wxDivisionShape::OnDrawContents(wxDC& dc)
+{
+ wxCompositeShape::OnDrawContents(dc);
+}
+
+bool wxDivisionShape::OnMovePre(wxDC& dc, double x, double y, double oldx, double oldy, bool display)
+{
+ double diffX = x - oldx;
+ double diffY = y - oldy;
+ wxNode *node = m_children.First();
+ while (node)
+ {
+ wxShape *object = (wxShape *)node->Data();
+ object->Erase(dc);
+ object->Move(dc, object->GetX() + diffX, object->GetY() + diffY, display);
+ node = node->Next();
+ }
+ return TRUE;
+}
+
+void wxDivisionShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
+{
+ if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
+ {
+ attachment = 0;
+ double dist;
+ if (m_parent)
+ {
+ m_parent->HitTest(x, y, &attachment, &dist);
+ m_parent->GetEventHandler()->OnDragLeft(draw, x, y, keys, attachment);
+ }
+ return;
+ }
+ wxShape::OnDragLeft(draw, x, y, keys, attachment);
+}
+
+void wxDivisionShape::OnBeginDragLeft(double x, double y, int keys, int attachment)
+{
+ if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
+ {
+ attachment = 0;
+ double dist;
+ if (m_parent)
+ {
+ m_parent->HitTest(x, y, &attachment, &dist);
+ m_parent->GetEventHandler()->OnBeginDragLeft(x, y, keys, attachment);
+ }
+ return;
+ }
+
+ wxShape::OnBeginDragLeft(x, y, keys, attachment);
+}
+
+void wxDivisionShape::OnEndDragLeft(double x, double y, int keys, int attachment)
+{
+ m_canvas->ReleaseMouse();
+ if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
+ {
+ attachment = 0;
+ double dist;
+ if (m_parent)
+ {
+ m_parent->HitTest(x, y, &attachment, &dist);
+ m_parent->GetEventHandler()->OnEndDragLeft(x, y, keys, attachment);
+ }
+ return;
+ }
+
+ wxClientDC dc(GetCanvas());
+ GetCanvas()->PrepareDC(dc);
+
+ dc.SetLogicalFunction(wxCOPY);
+
+ m_canvas->Snap(&m_xpos, &m_ypos);
+ GetEventHandler()->OnMovePre(dc, x, y, m_oldX, m_oldY);
+
+ ResetControlPoints();
+ Draw(dc);
+ MoveLinks(dc);
+ GetEventHandler()->OnDrawControlPoints(dc);
+
+ if (m_canvas && !m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
+}
+
+void wxDivisionShape::SetSize(double w, double h, bool recursive)
+{
+ m_width = w;
+ m_height = h;
+ wxRectangleShape::SetSize(w, h, recursive);
+}
+
+void wxDivisionShape::CalculateSize()
+{
+}
+
+void wxDivisionShape::Copy(wxShape& copy)
+{
+ wxCompositeShape::Copy(copy);
+
+ wxASSERT( copy.IsKindOf(CLASSINFO(wxDivisionShape)) ) ;
+
+ wxDivisionShape& divisionCopy = (wxDivisionShape&) copy;
+
+ divisionCopy.m_leftSideStyle = m_leftSideStyle;
+ divisionCopy.m_topSideStyle = m_topSideStyle;
+ divisionCopy.m_leftSideColour = m_leftSideColour;
+ divisionCopy.m_topSideColour = m_topSideColour;
+
+ divisionCopy.m_leftSidePen = m_leftSidePen;
+ divisionCopy.m_topSidePen = m_topSidePen;
+ divisionCopy.m_handleSide = m_handleSide;
+
+ // Division geometry copying is handled at the wxCompositeShape level.
+}
+
+#ifdef PROLOGIO
+void wxDivisionShape::WriteAttributes(wxExpr *clause)
+{
+ wxCompositeShape::WriteAttributes(clause);
+
+ if (m_leftSide)
+ clause->AddAttributeValue("left_side", (long)m_leftSide->GetId());
+ if (m_topSide)
+ clause->AddAttributeValue("top_side", (long)m_topSide->GetId());
+ if (m_rightSide)
+ clause->AddAttributeValue("right_side", (long)m_rightSide->GetId());
+ if (m_bottomSide)
+ clause->AddAttributeValue("bottom_side", (long)m_bottomSide->GetId());
+
+ clause->AddAttributeValue("handle_side", (long)m_handleSide);
+ clause->AddAttributeValueString("left_colour", m_leftSideColour);
+ clause->AddAttributeValueString("top_colour", m_topSideColour);
+ clause->AddAttributeValueString("left_style", m_leftSideStyle);
+ clause->AddAttributeValueString("top_style", m_topSideStyle);
+}
+
+void wxDivisionShape::ReadAttributes(wxExpr *clause)
+{
+ wxCompositeShape::ReadAttributes(clause);
+
+ clause->GetAttributeValue("handle_side", m_handleSide);
+ clause->GetAttributeValue("left_colour", m_leftSideColour);
+ clause->GetAttributeValue("top_colour", m_topSideColour);
+ clause->GetAttributeValue("left_style", m_leftSideStyle);
+ clause->GetAttributeValue("top_style", m_topSideStyle);
+}
+#endif
+
+// Experimental
+void wxDivisionShape::OnRightClick(double x, double y, int keys, int attachment)
+{
+ if (keys & KEY_CTRL)
+ {
+ PopupMenu(x, y);
+ }
+/*
+ else if (keys & KEY_SHIFT)
+ {
+ if (m_leftSide || m_topSide || m_rightSide || m_bottomSide)
+ {
+ if (Selected())
+ {
+ Select(FALSE);
+ GetParent()->Draw(dc);
+ }
+ else
+ Select(TRUE);
+ }
+ }
+*/
+ else
+ {
+ attachment = 0;
+ double dist;
+ if (m_parent)
+ {
+ m_parent->HitTest(x, y, &attachment, &dist);
+ m_parent->GetEventHandler()->OnRightClick(x, y, keys, attachment);
+ }
+ return;
+ }
+}
+
+
+// Divide wxHORIZONTALly or wxVERTICALly
+bool wxDivisionShape::Divide(int direction)
+{
+ // Calculate existing top-left, bottom-right
+ double x1 = (double)(GetX() - (GetWidth()/2.0));
+ double y1 = (double)(GetY() - (GetHeight()/2.0));
+ wxCompositeShape *compositeParent = (wxCompositeShape *)GetParent();
+ double oldWidth = GetWidth();
+ double oldHeight = GetHeight();
+ if (Selected())
+ Select(FALSE);
+
+ wxClientDC dc(GetCanvas());
+ GetCanvas()->PrepareDC(dc);
+
+ if (direction == wxVERTICAL)
+ {
+ // Dividing vertically means notionally putting a horizontal line through it.
+ // Break existing piece into two.
+ double newXPos1 = GetX();
+ double newYPos1 = (double)(y1 + (GetHeight()/4.0));
+ double newXPos2 = GetX();
+ double newYPos2 = (double)(y1 + (3.0*GetHeight()/4.0));
+ wxDivisionShape *newDivision = compositeParent->OnCreateDivision();
+ newDivision->Show(TRUE);
+
+ Erase(dc);
+
+ // Anything adjoining the bottom of this division now adjoins the
+ // bottom of the new division.
+ wxNode *node = compositeParent->GetDivisions().First();
+ while (node)
+ {
+ wxDivisionShape *obj = (wxDivisionShape *)node->Data();
+ if (obj->GetTopSide() == this)
+ obj->SetTopSide(newDivision);
+ node = node->Next();
+ }
+ newDivision->SetTopSide(this);
+ newDivision->SetBottomSide(m_bottomSide);
+ newDivision->SetLeftSide(m_leftSide);
+ newDivision->SetRightSide(m_rightSide);
+ m_bottomSide = newDivision;
+
+ compositeParent->GetDivisions().Append(newDivision);
+
+ // CHANGE: Need to insert this division at start of divisions in the object
+ // list, because e.g.:
+ // 1) Add division
+ // 2) Add contained object
+ // 3) Add division
+ // Division is now receiving mouse events _before_ the contained object,
+ // because it was added last (on top of all others)
+
+ // Add after the image that visualizes the container
+ compositeParent->AddChild(newDivision, compositeParent->FindContainerImage());
+
+ m_handleSide = DIVISION_SIDE_BOTTOM;
+ newDivision->SetHandleSide(DIVISION_SIDE_TOP);
+
+ SetSize(oldWidth, (double)(oldHeight/2.0));
+ Move(dc, newXPos1, newYPos1);
+
+ newDivision->SetSize(oldWidth, (double)(oldHeight/2.0));
+ newDivision->Move(dc, newXPos2, newYPos2);
+ }
+ else
+ {
+ // Dividing horizontally means notionally putting a vertical line through it.
+ // Break existing piece into two.
+ double newXPos1 = (double)(x1 + (GetWidth()/4.0));
+ double newYPos1 = GetY();
+ double newXPos2 = (double)(x1 + (3.0*GetWidth()/4.0));
+ double newYPos2 = GetY();
+ wxDivisionShape *newDivision = compositeParent->OnCreateDivision();
+ newDivision->Show(TRUE);
+
+ Erase(dc);
+
+ // Anything adjoining the left of this division now adjoins the
+ // left of the new division.
+ wxNode *node = compositeParent->GetDivisions().First();
+ while (node)
+ {
+ wxDivisionShape *obj = (wxDivisionShape *)node->Data();
+ if (obj->GetLeftSide() == this)
+ obj->SetLeftSide(newDivision);
+ node = node->Next();
+ }
+ newDivision->SetTopSide(m_topSide);
+ newDivision->SetBottomSide(m_bottomSide);
+ newDivision->SetLeftSide(this);
+ newDivision->SetRightSide(m_rightSide);
+ m_rightSide = newDivision;
+
+ compositeParent->GetDivisions().Append(newDivision);
+ compositeParent->AddChild(newDivision, compositeParent->FindContainerImage());
+
+ m_handleSide = DIVISION_SIDE_RIGHT;
+ newDivision->SetHandleSide(DIVISION_SIDE_LEFT);
+
+ SetSize((double)(oldWidth/2.0), oldHeight);
+ Move(dc, newXPos1, newYPos1);
+
+ newDivision->SetSize((double)(oldWidth/2.0), oldHeight);
+ newDivision->Move(dc, newXPos2, newYPos2);
+ }
+ if (compositeParent->Selected())
+ {
+ compositeParent->DeleteControlPoints(& dc);
+ compositeParent->MakeControlPoints();
+ compositeParent->MakeMandatoryControlPoints();
+ }
+ compositeParent->Draw(dc);
+ return TRUE;
+}
+
+// Make one control point for every visible line
+void wxDivisionShape::MakeControlPoints()
+{
+ MakeMandatoryControlPoints();
+}
+
+void wxDivisionShape::MakeMandatoryControlPoints()
+{
+ double maxX, maxY;
+
+ GetBoundingBoxMax(&maxX, &maxY);
+ double x, y;
+ int direction;
+/*
+ if (m_leftSide)
+ {
+ x = (double)(-maxX/2.0);
+ y = 0.0;
+ wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y,
+ CONTROL_POINT_HORIZONTAL);
+ m_canvas->AddShape(control);
+ m_controlPoints.Append(control);
+ }
+ if (m_topSide)
+ {
+ x = 0.0;
+ y = (double)(-maxY/2.0);
+ wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y,
+ CONTROL_POINT_VERTICAL);
+ m_canvas->AddShape(control);
+ m_controlPoints.Append(control);
+ }
+*/
+ switch (m_handleSide)
+ {
+ case DIVISION_SIDE_LEFT:
+ {
+ x = (double)(-maxX/2.0);
+ y = 0.0;
+ direction = CONTROL_POINT_HORIZONTAL;
+ break;
+ }
+ case DIVISION_SIDE_TOP:
+ {
+ x = 0.0;
+ y = (double)(-maxY/2.0);
+ direction = CONTROL_POINT_VERTICAL;
+ break;
+ }
+ case DIVISION_SIDE_RIGHT:
+ {
+ x = (double)(maxX/2.0);
+ y = 0.0;
+ direction = CONTROL_POINT_HORIZONTAL;
+ break;
+ }
+ case DIVISION_SIDE_BOTTOM:
+ {
+ x = 0.0;
+ y = (double)(maxY/2.0);
+ direction = CONTROL_POINT_VERTICAL;
+ break;
+ }
+ default:
+ break;
+ }
+ if (m_handleSide != DIVISION_SIDE_NONE)
+ {
+ wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y,
+ direction);
+ m_canvas->AddShape(control);
+ m_controlPoints.Append(control);
+ }
+}
+
+void wxDivisionShape::ResetControlPoints()
+{
+ ResetMandatoryControlPoints();
+}
+
+void wxDivisionShape::ResetMandatoryControlPoints()
+{
+ if (m_controlPoints.Number() < 1)
+ return;
+
+ double maxX, maxY;
+
+ GetBoundingBoxMax(&maxX, &maxY);
+/*
+ wxNode *node = m_controlPoints.First();
+ while (node)
+ {
+ wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->Data();
+ if (control->type == CONTROL_POINT_HORIZONTAL)
+ {
+ control->xoffset = (double)(-maxX/2.0); control->m_yoffset = 0.0;
+ }
+ else if (control->type == CONTROL_POINT_VERTICAL)
+ {
+ control->xoffset = 0.0; control->m_yoffset = (double)(-maxY/2.0);
+ }
+ node = node->Next();
+ }
+*/
+ wxNode *node = m_controlPoints.First();
+ if ((m_handleSide == DIVISION_SIDE_LEFT) && node)
+ {
+ wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->Data();
+ control->m_xoffset = (double)(-maxX/2.0); control->m_yoffset = 0.0;
+ }
+
+ if ((m_handleSide == DIVISION_SIDE_TOP) && node)
+ {
+ wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->Data();
+ control->m_xoffset = 0.0; control->m_yoffset = (double)(-maxY/2.0);
+ }
+
+ if ((m_handleSide == DIVISION_SIDE_RIGHT) && node)
+ {
+ wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->Data();
+ control->m_xoffset = (double)(maxX/2.0); control->m_yoffset = 0.0;
+ }
+
+ if ((m_handleSide == DIVISION_SIDE_BOTTOM) && node)
+ {
+ wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->Data();
+ control->m_xoffset = 0.0; control->m_yoffset = (double)(maxY/2.0);
+ }
+}
+
+// Adjust a side, returning FALSE if it's not physically possible.
+bool wxDivisionShape::AdjustLeft(double left, bool test)
+{
+ double x2 = (double)(GetX() + (GetWidth()/2.0));
+
+ if (left >= x2)
+ return FALSE;
+ if (test)
+ return TRUE;
+
+ double newW = x2 - left;
+ double newX = (double)(left + newW/2.0);
+ SetSize(newW, GetHeight());
+
+ wxClientDC dc(GetCanvas());
+ GetCanvas()->PrepareDC(dc);
+
+ Move(dc, newX, GetY());
+
+ return TRUE;
+}
+
+bool wxDivisionShape::AdjustTop(double top, bool test)
+{
+ double y2 = (double)(GetY() + (GetHeight()/2.0));
+
+ if (top >= y2)
+ return FALSE;
+ if (test)
+ return TRUE;
+
+ double newH = y2 - top;
+ double newY = (double)(top + newH/2.0);
+ SetSize(GetWidth(), newH);
+
+ wxClientDC dc(GetCanvas());
+ GetCanvas()->PrepareDC(dc);
+
+ Move(dc, GetX(), newY);
+
+ return TRUE;
+}
+
+bool wxDivisionShape::AdjustRight(double right, bool test)
+{
+ double x1 = (double)(GetX() - (GetWidth()/2.0));
+
+ if (right <= x1)
+ return FALSE;
+ if (test)
+ return TRUE;
+
+ double newW = right - x1;
+ double newX = (double)(x1 + newW/2.0);
+ SetSize(newW, GetHeight());
+
+ wxClientDC dc(GetCanvas());
+ GetCanvas()->PrepareDC(dc);
+
+ Move(dc, newX, GetY());
+
+ return TRUE;
+}
+
+bool wxDivisionShape::AdjustBottom(double bottom, bool test)
+{
+ double y1 = (double)(GetY() - (GetHeight()/2.0));
+
+ if (bottom <= y1)
+ return FALSE;
+ if (test)
+ return TRUE;
+
+ double newH = bottom - y1;
+ double newY = (double)(y1 + newH/2.0);
+ SetSize(GetWidth(), newH);
+
+ wxClientDC dc(GetCanvas());
+ GetCanvas()->PrepareDC(dc);
+
+ Move(dc, GetX(), newY);
+
+ return TRUE;
+}
+
+wxDivisionControlPoint::wxDivisionControlPoint(wxShapeCanvas *the_canvas, wxShape *object, double size, double the_xoffset, double the_yoffset, int the_type):
+ wxControlPoint(the_canvas, object, size, the_xoffset, the_yoffset, the_type)
+{
+ SetEraseObject(FALSE);
+}
+
+wxDivisionControlPoint::~wxDivisionControlPoint()
+{
+}
+
+static double originalX = 0.0;
+static double originalY = 0.0;
+static double originalW = 0.0;
+static double originalH = 0.0;
+
+// Implement resizing of canvas object
+void wxDivisionControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
+{
+ wxControlPoint::OnDragLeft(draw, x, y, keys, attachment);
+}
+
+void wxDivisionControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment)
+{
+ wxDivisionShape *division = (wxDivisionShape *)m_shape;
+ originalX = division->GetX();
+ originalY = division->GetY();
+ originalW = division->GetWidth();
+ originalH = division->GetHeight();
+
+ wxControlPoint::OnBeginDragLeft(x, y, keys, attachment);
+}
+
+void wxDivisionControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment)
+{
+ wxControlPoint::OnEndDragLeft(x, y, keys, attachment);
+
+ wxClientDC dc(GetCanvas());
+ GetCanvas()->PrepareDC(dc);
+
+ wxDivisionShape *division = (wxDivisionShape *)m_shape;
+ wxCompositeShape *divisionParent = (wxCompositeShape *)division->GetParent();
+
+ // Need to check it's within the bounds of the parent composite.
+ double x1 = (double)(divisionParent->GetX() - (divisionParent->GetWidth()/2.0));
+ double y1 = (double)(divisionParent->GetY() - (divisionParent->GetHeight()/2.0));
+ double x2 = (double)(divisionParent->GetX() + (divisionParent->GetWidth()/2.0));
+ double y2 = (double)(divisionParent->GetY() + (divisionParent->GetHeight()/2.0));
+
+ // Need to check it has not made the division zero or negative width/height
+ double dx1 = (double)(division->GetX() - (division->GetWidth()/2.0));
+ double dy1 = (double)(division->GetY() - (division->GetHeight()/2.0));
+ double dx2 = (double)(division->GetX() + (division->GetWidth()/2.0));
+ double dy2 = (double)(division->GetY() + (division->GetHeight()/2.0));
+
+ bool success = TRUE;
+ switch (division->GetHandleSide())
+ {
+ case DIVISION_SIDE_LEFT:
+ {
+ if ((x <= x1) || (x >= x2) || (x >= dx2))
+ success = FALSE;
+ // Try it out first...
+ else if (!division->ResizeAdjoining(DIVISION_SIDE_LEFT, x, TRUE))
+ success = FALSE;
+ else
+ division->ResizeAdjoining(DIVISION_SIDE_LEFT, x, FALSE);
+
+ break;
+ }
+ case DIVISION_SIDE_TOP:
+ {
+ if ((y <= y1) || (y >= y2) || (y >= dy2))
+ success = FALSE;
+ else if (!division->ResizeAdjoining(DIVISION_SIDE_TOP, y, TRUE))
+ success = FALSE;
+ else
+ division->ResizeAdjoining(DIVISION_SIDE_TOP, y, FALSE);
+
+ break;
+ }
+ case DIVISION_SIDE_RIGHT:
+ {
+ if ((x <= x1) || (x >= x2) || (x <= dx1))
+ success = FALSE;
+ else if (!division->ResizeAdjoining(DIVISION_SIDE_RIGHT, x, TRUE))
+ success = FALSE;
+ else
+ division->ResizeAdjoining(DIVISION_SIDE_RIGHT, x, FALSE);
+
+ break;
+ }
+ case DIVISION_SIDE_BOTTOM:
+ {
+ if ((y <= y1) || (y >= y2) || (y <= dy1))
+ success = FALSE;
+ else if (!division->ResizeAdjoining(DIVISION_SIDE_BOTTOM, y, TRUE))
+ success = FALSE;
+ else
+ division->ResizeAdjoining(DIVISION_SIDE_BOTTOM, y, FALSE);
+
+ break;
+ }
+ }
+ if (!success)
+ {
+ division->SetSize(originalW, originalH);
+ division->Move(dc, originalX, originalY);
+ }
+ divisionParent->Draw(dc);
+ division->GetEventHandler()->OnDrawControlPoints(dc);
+}
+
+/* Resize adjoining divisions.
+ *
+ Behaviour should be as follows:
+ If right edge moves, find all objects whose left edge
+ adjoins this object, and move left edge accordingly.
+ If left..., move ... right.
+ If top..., move ... bottom.
+ If bottom..., move top.
+ If size goes to zero or end position is other side of start position,
+ resize to original size and return.
+ */
+bool wxDivisionShape::ResizeAdjoining(int side, double newPos, bool test)
+{
+ wxCompositeShape *divisionParent = (wxCompositeShape *)GetParent();
+ wxNode *node = divisionParent->GetDivisions().First();
+ while (node)
+ {
+ wxDivisionShape *division = (wxDivisionShape *)node->Data();
+ switch (side)
+ {
+ case DIVISION_SIDE_LEFT:
+ {
+ if (division->m_rightSide == this)
+ {
+ bool success = division->AdjustRight(newPos, test);
+ if (!success && test)
+ return FALSE;
+ }
+ break;
+ }
+ case DIVISION_SIDE_TOP:
+ {
+ if (division->m_bottomSide == this)
+ {
+ bool success = division->AdjustBottom(newPos, test);
+ if (!success && test)
+ return FALSE;
+ }
+ break;
+ }
+ case DIVISION_SIDE_RIGHT:
+ {
+ if (division->m_leftSide == this)
+ {
+ bool success = division->AdjustLeft(newPos, test);
+ if (!success && test)
+ return FALSE;
+ }
+ break;
+ }
+ case DIVISION_SIDE_BOTTOM:
+ {
+ if (division->m_topSide == this)
+ {
+ bool success = division->AdjustTop(newPos, test);
+ if (!success && test)
+ return FALSE;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ node = node->Next();
+ }
+
+ return TRUE;
+}
+
+/*
+ * Popup menu for editing divisions
+ *
+ */
+class OGLPopupDivisionMenu : public wxMenu {
+public:
+ OGLPopupDivisionMenu() : wxMenu() {
+ Append(DIVISION_MENU_SPLIT_HORIZONTALLY, "Split horizontally");
+ Append(DIVISION_MENU_SPLIT_VERTICALLY, "Split vertically");
+ AppendSeparator();
+ Append(DIVISION_MENU_EDIT_LEFT_EDGE, "Edit left edge");
+ Append(DIVISION_MENU_EDIT_TOP_EDGE, "Edit top edge");
+ }
+
+ void OnMenu(wxCommandEvent& event);
+
+ DECLARE_EVENT_TABLE()
+};
+
+BEGIN_EVENT_TABLE(OGLPopupDivisionMenu, wxMenu)
+ EVT_CUSTOM_RANGE(wxEVT_COMMAND_MENU_SELECTED,
+ DIVISION_MENU_SPLIT_HORIZONTALLY,
+ DIVISION_MENU_EDIT_BOTTOM_EDGE,
+ OGLPopupDivisionMenu::OnMenu)
+END_EVENT_TABLE()
+
+
+void OGLPopupDivisionMenu::OnMenu(wxCommandEvent& event)
+{
+ wxDivisionShape *division = (wxDivisionShape *)GetClientData();
+ switch (event.GetInt())
+ {
+ case DIVISION_MENU_SPLIT_HORIZONTALLY:
+ {
+ division->Divide(wxHORIZONTAL);
+ break;
+ }
+ case DIVISION_MENU_SPLIT_VERTICALLY:
+ {
+ division->Divide(wxVERTICAL);
+ break;
+ }
+ case DIVISION_MENU_EDIT_LEFT_EDGE:
+ {
+ division->EditEdge(DIVISION_SIDE_LEFT);
+ break;
+ }
+ case DIVISION_MENU_EDIT_TOP_EDGE:
+ {
+ division->EditEdge(DIVISION_SIDE_TOP);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void wxDivisionShape::EditEdge(int side)
+{
+ wxMessageBox("EditEdge() not implemented", "OGL", wxOK);
+
+#if 0
+ wxBeginBusyCursor();
+
+ wxPen *currentPen = NULL;
+ char **pColour = NULL;
+ char **pStyle = NULL;
+ if (side == DIVISION_SIDE_LEFT)
+ {
+ currentPen = m_leftSidePen;
+ pColour = &m_leftSideColour;
+ pStyle = &m_leftSideStyle;
+ }
+ else
+ {
+ currentPen = m_topSidePen;
+ pColour = &m_topSideColour;
+ pStyle = &m_topSideStyle;
+ }
+
+ GraphicsForm *form = new GraphicsForm("Containers");
+ int lineWidth = currentPen->GetWidth();
+
+ form->Add(wxMakeFormShort("Width", &lineWidth, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
+ 150));
+ form->Add(wxMakeFormString("Colour", pColour, wxFORM_CHOICE,
+ new wxList(wxMakeConstraintStrings(
+ "BLACK" ,
+ "BLUE" ,
+ "BROWN" ,
+ "CORAL" ,
+ "CYAN" ,
+ "DARK GREY" ,
+ "DARK GREEN" ,
+ "DIM GREY" ,
+ "GREY" ,
+ "GREEN" ,
+ "LIGHT BLUE" ,
+ "LIGHT GREY" ,
+ "MAGENTA" ,
+ "MAROON" ,
+ "NAVY" ,
+ "ORANGE" ,
+ "PURPLE" ,
+ "RED" ,
+ "TURQUOISE" ,
+ "VIOLET" ,
+ "WHITE" ,
+ "YELLOW" ,
+ NULL),
+ NULL), NULL, wxVERTICAL, 150));
+ form->Add(wxMakeFormString("Style", pStyle, wxFORM_CHOICE,
+ new wxList(wxMakeConstraintStrings(
+ "Solid" ,
+ "Short Dash" ,
+ "Long Dash" ,
+ "Dot" ,
+ "Dot Dash" ,
+ NULL),
+ NULL), NULL, wxVERTICAL, 100));
+
+ wxDialogBox *dialog = new wxDialogBox(m_canvas->GetParent(), "Division properties", 10, 10, 500, 500);
+ if (GraphicsLabelFont)
+ dialog->SetLabelFont(GraphicsLabelFont);
+ if (GraphicsButtonFont)
+ dialog->SetButtonFont(GraphicsButtonFont);
+
+ form->AssociatePanel(dialog);
+ form->dialog = dialog;
+
+ dialog->Fit();
+ dialog->Centre(wxBOTH);
+
+ wxEndBusyCursor();
+ dialog->Show(TRUE);
+
+ int lineStyle = wxSOLID;
+ if (*pStyle)
+ {
+ if (strcmp(*pStyle, "Solid") == 0)
+ lineStyle = wxSOLID;
+ else if (strcmp(*pStyle, "Dot") == 0)
+ lineStyle = wxDOT;
+ else if (strcmp(*pStyle, "Short Dash") == 0)
+ lineStyle = wxSHORT_DASH;
+ else if (strcmp(*pStyle, "Long Dash") == 0)
+ lineStyle = wxLONG_DASH;
+ else if (strcmp(*pStyle, "Dot Dash") == 0)
+ lineStyle = wxDOT_DASH;
+ }
+
+ wxPen *newPen = wxThePenList->FindOrCreatePen(*pColour, lineWidth, lineStyle);
+ if (!pen)
+ pen = wxBLACK_PEN;
+ if (side == DIVISION_SIDE_LEFT)
+ m_leftSidePen = newPen;
+ else
+ m_topSidePen = newPen;
+
+ // Need to draw whole image again
+ wxCompositeShape *compositeParent = (wxCompositeShape *)GetParent();
+ compositeParent->Draw(dc);
+#endif
+}
+
+// Popup menu
+void wxDivisionShape::PopupMenu(double x, double y)
+{
+ wxMenu* oglPopupDivisionMenu = new OGLPopupDivisionMenu;
+
+ oglPopupDivisionMenu->SetClientData((void *)this);
+ if (m_leftSide)
+ oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_LEFT_EDGE, TRUE);
+ else
+ oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_LEFT_EDGE, FALSE);
+ if (m_topSide)
+ oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_TOP_EDGE, TRUE);
+ else
+ oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_TOP_EDGE, FALSE);
+
+ int x1, y1;
+ m_canvas->ViewStart(&x1, &y1);
+
+ int unit_x, unit_y;
+ m_canvas->GetScrollPixelsPerUnit(&unit_x, &unit_y);
+
+ wxClientDC dc(GetCanvas());
+ GetCanvas()->PrepareDC(dc);
+
+ int mouse_x = (int)(dc.LogicalToDeviceX((long)(x - x1*unit_x)));
+ int mouse_y = (int)(dc.LogicalToDeviceY((long)(y - y1*unit_y)));
+
+ m_canvas->PopupMenu(oglPopupDivisionMenu, mouse_x, mouse_y);
+ delete oglPopupDivisionMenu;
+}
+
+void wxDivisionShape::SetLeftSideColour(const wxString& colour)
+{
+ m_leftSideColour = colour;
+}
+
+void wxDivisionShape::SetTopSideColour(const wxString& colour)
+{
+ m_topSideColour = colour;
+}
+
+void wxDivisionShape::SetLeftSideStyle(const wxString& style)
+{
+ m_leftSideStyle = style;
+}
+
+void wxDivisionShape::SetTopSideStyle(const wxString& style)
+{
+ m_topSideStyle = style;
+}
+