1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Composite OGL class
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "composit.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
27 #include <wx/wxexpr.h>
29 #include <wx/ogl/basic.h>
30 #include <wx/ogl/basicp.h>
31 #include <wx/ogl/constrnt.h>
32 #include <wx/ogl/composit.h>
33 #include <wx/ogl/misc.h>
34 #include <wx/ogl/canvas.h>
36 // Sometimes, objects need to access the whole database to
37 // construct themselves.
38 wxExprDatabase
*GlobalwxExprDatabase
= NULL
;
42 * Division control point
45 class wxDivisionControlPoint
: public wxControlPoint
47 DECLARE_DYNAMIC_CLASS(wxDivisionControlPoint
)
49 wxDivisionControlPoint() {}
50 wxDivisionControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
, double size
, double the_xoffset
, double the_yoffset
, int the_type
);
51 ~wxDivisionControlPoint();
53 void OnDragLeft(bool draw
, double x
, double y
, int keys
=0, int attachment
= 0);
54 void OnBeginDragLeft(double x
, double y
, int keys
=0, int attachment
= 0);
55 void OnEndDragLeft(double x
, double y
, int keys
=0, int attachment
= 0);
58 IMPLEMENT_DYNAMIC_CLASS(wxDivisionControlPoint
, wxControlPoint
)
65 IMPLEMENT_DYNAMIC_CLASS(wxCompositeShape
, wxRectangleShape
)
67 wxCompositeShape::wxCompositeShape(): wxRectangleShape(10.0, 10.0)
69 // selectable = FALSE;
74 wxCompositeShape::~wxCompositeShape()
76 wxNode
*node
= m_constraints
.First();
79 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->Data();
83 node
= m_children
.First();
86 wxShape
*object
= (wxShape
*)node
->Data();
87 wxNode
*next
= node
->Next();
94 void wxCompositeShape::OnDraw(wxDC
& dc
)
96 double x1
= (double)(m_xpos
- m_width
/2.0);
97 double y1
= (double)(m_ypos
- m_height
/2.0);
99 if (m_shadowMode
!= SHADOW_NONE
)
102 dc
.SetBrush(* m_shadowBrush
);
103 dc
.SetPen(* g_oglTransparentPen
);
105 if (m_cornerRadius
!= 0.0)
106 dc
.DrawRoundedRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
),
107 WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
109 dc
.DrawRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
), WXROUND(m_width
), WXROUND(m_height
));
113 void wxCompositeShape::OnDrawContents(wxDC
& dc
)
115 wxNode
*node
= m_children
.First();
118 wxShape
*object
= (wxShape
*)node
->Data();
120 object
->DrawLinks(dc
);
123 wxShape::OnDrawContents(dc
);
126 bool wxCompositeShape::OnMovePre(wxDC
& dc
, double x
, double y
, double oldx
, double oldy
, bool display
)
128 double diffX
= x
- oldx
;
129 double diffY
= y
- oldy
;
130 wxNode
*node
= m_children
.First();
133 wxShape
*object
= (wxShape
*)node
->Data();
136 object
->Move(dc
, object
->GetX() + diffX
, object
->GetY() + diffY
, display
);
143 void wxCompositeShape::OnErase(wxDC
& dc
)
145 wxRectangleShape::OnErase(dc
);
146 wxNode
*node
= m_children
.First();
149 wxShape
*object
= (wxShape
*)node
->Data();
155 static double objectStartX
= 0.0;
156 static double objectStartY
= 0.0;
158 void wxCompositeShape::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
162 m_canvas
->Snap(&xx
, &yy
);
163 double offsetX
= xx
- objectStartX
;
164 double offsetY
= yy
- objectStartY
;
166 wxClientDC
dc(GetCanvas());
167 GetCanvas()->PrepareDC(dc
);
169 dc
.SetLogicalFunction(OGLRBLF
);
170 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
171 dc
.SetPen(dottedPen
);
172 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
174 GetEventHandler()->OnDrawOutline(dc
, GetX() + offsetX
, GetY() + offsetY
, GetWidth(), GetHeight());
175 // wxShape::OnDragLeft(draw, x, y, keys, attachment);
178 void wxCompositeShape::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
183 wxClientDC
dc(GetCanvas());
184 GetCanvas()->PrepareDC(dc
);
188 dc
.SetLogicalFunction(OGLRBLF
);
190 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
191 dc
.SetPen(dottedPen
);
192 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
193 m_canvas
->CaptureMouse();
197 m_canvas
->Snap(&xx
, &yy
);
198 double offsetX
= xx
- objectStartX
;
199 double offsetY
= yy
- objectStartY
;
201 GetEventHandler()->OnDrawOutline(dc
, GetX() + offsetX
, GetY() + offsetY
, GetWidth(), GetHeight());
203 // wxShape::OnBeginDragLeft(x, y, keys, attachment);
206 void wxCompositeShape::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
208 // wxShape::OnEndDragLeft(x, y, keys, attachment);
210 wxClientDC
dc(GetCanvas());
211 GetCanvas()->PrepareDC(dc
);
213 m_canvas
->ReleaseMouse();
217 if (m_parent
) m_parent
->GetEventHandler()->OnEndDragLeft(x
, y
, keys
, 0);
221 dc
.SetLogicalFunction(wxCOPY
);
224 m_canvas
->Snap(&xx
, &yy
);
225 double offsetX
= xx
- objectStartX
;
226 double offsetY
= yy
- objectStartY
;
228 Move(dc
, GetX() + offsetX
, GetY() + offsetY
);
230 if (m_canvas
&& !m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
233 void wxCompositeShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
235 // If we get a ctrl-right click, this means send the message to
236 // the division, so we can invoke a user interface for dealing with regions.
239 wxNode
*node
= m_divisions
.First();
242 wxDivisionShape
*division
= (wxDivisionShape
*)node
->Data();
243 wxNode
*next
= node
->Next();
246 if (division
->HitTest(x
, y
, &attach
, &dist
))
248 division
->GetEventHandler()->OnRightClick(x
, y
, keys
, attach
);
257 void wxCompositeShape::SetSize(double w
, double h
, bool recursive
)
259 SetAttachmentSize(w
, h
);
261 double xScale
= (double)(w
/(wxMax(1.0, GetWidth())));
262 double yScale
= (double)(h
/(wxMax(1.0, GetHeight())));
267 if (!recursive
) return;
269 wxNode
*node
= m_children
.First();
271 wxClientDC
dc(GetCanvas());
272 GetCanvas()->PrepareDC(dc
);
274 double xBound
, yBound
;
277 wxShape
*object
= (wxShape
*)node
->Data();
279 // Scale the position first
280 double newX
= (double)(((object
->GetX() - GetX())*xScale
) + GetX());
281 double newY
= (double)(((object
->GetY() - GetY())*yScale
) + GetY());
283 object
->Move(dc
, newX
, newY
);
286 // Now set the scaled size
287 object
->GetBoundingBoxMin(&xBound
, &yBound
);
288 object
->SetSize(object
->GetFixedWidth() ? xBound
: xScale
*xBound
,
289 object
->GetFixedHeight() ? yBound
: yScale
*yBound
);
293 SetDefaultRegionSize();
296 void wxCompositeShape::AddChild(wxShape
*child
, wxShape
*addAfter
)
298 m_children
.Append(child
);
299 child
->SetParent(this);
302 // Ensure we add at the right position
304 child
->RemoveFromCanvas(m_canvas
);
305 child
->AddToCanvas(m_canvas
, addAfter
);
309 void wxCompositeShape::RemoveChild(wxShape
*child
)
311 m_children
.DeleteObject(child
);
312 m_divisions
.DeleteObject(child
);
313 RemoveChildFromConstraints(child
);
314 child
->SetParent(NULL
);
317 void wxCompositeShape::DeleteConstraintsInvolvingChild(wxShape
*child
)
319 wxNode
*node
= m_constraints
.First();
322 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->Data();
323 wxNode
*nextNode
= node
->Next();
325 if ((constraint
->m_constrainingObject
== child
) ||
326 constraint
->m_constrainedObjects
.Member(child
))
335 void wxCompositeShape::RemoveChildFromConstraints(wxShape
*child
)
337 wxNode
*node
= m_constraints
.First();
340 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->Data();
341 wxNode
*nextNode
= node
->Next();
343 if (constraint
->m_constrainedObjects
.Member(child
))
344 constraint
->m_constrainedObjects
.DeleteObject(child
);
345 if (constraint
->m_constrainingObject
== child
)
346 constraint
->m_constrainingObject
= NULL
;
348 // Delete the constraint if no participants left
349 if (!constraint
->m_constrainingObject
)
359 void wxCompositeShape::Copy(wxShape
& copy
)
361 wxRectangleShape::Copy(copy
);
363 wxASSERT( copy
.IsKindOf(CLASSINFO(wxCompositeShape
)) ) ;
365 wxCompositeShape
& compositeCopy
= (wxCompositeShape
&) copy
;
367 // Associate old and new copies for compositeCopying constraints and division geometry
368 oglObjectCopyMapping
.Append((long)this, &compositeCopy
);
371 wxNode
*node
= m_children
.First();
374 wxShape
*object
= (wxShape
*)node
->Data();
375 wxShape
*newObject
= object
->CreateNewCopy(FALSE
, FALSE
);
376 if (newObject
->GetId() == 0)
377 newObject
->SetId(wxNewId());
379 newObject
->SetParent(&compositeCopy
);
380 compositeCopy
.m_children
.Append(newObject
);
382 // Some m_children may be divisions
383 if (m_divisions
.Member(object
))
384 compositeCopy
.m_divisions
.Append(newObject
);
386 oglObjectCopyMapping
.Append((long)object
, newObject
);
391 // Copy the constraints
392 node
= m_constraints
.First();
395 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->Data();
397 wxShape
*newConstraining
= (wxShape
*)(oglObjectCopyMapping
.Find((long)constraint
->m_constrainingObject
)->Data());
399 wxList newConstrainedList
;
400 wxNode
*node2
= constraint
->m_constrainedObjects
.First();
403 wxShape
*constrainedObject
= (wxShape
*)node2
->Data();
404 wxShape
*newConstrained
= (wxShape
*)(oglObjectCopyMapping
.Find((long)constrainedObject
)->Data());
405 newConstrainedList
.Append(newConstrained
);
406 node2
= node2
->Next();
409 wxOGLConstraint
*newConstraint
= new wxOGLConstraint(constraint
->m_constraintType
, newConstraining
,
411 newConstraint
->m_constraintId
= constraint
->m_constraintId
;
412 if (constraint
->m_constraintName
)
414 newConstraint
->m_constraintName
= constraint
->m_constraintName
;
416 newConstraint
->SetSpacing(constraint
->m_xSpacing
, constraint
->m_ySpacing
);
417 compositeCopy
.m_constraints
.Append(newConstraint
);
422 // Now compositeCopy the division geometry
423 node
= m_divisions
.First();
426 wxDivisionShape
*division
= (wxDivisionShape
*)node
->Data();
427 wxNode
*node1
= oglObjectCopyMapping
.Find((long)division
);
428 wxNode
*leftNode
= NULL
;
429 wxNode
*topNode
= NULL
;
430 wxNode
*rightNode
= NULL
;
431 wxNode
*bottomNode
= NULL
;
432 if (division
->GetLeftSide())
433 leftNode
= oglObjectCopyMapping
.Find((long)division
->GetLeftSide());
434 if (division
->GetTopSide())
435 topNode
= oglObjectCopyMapping
.Find((long)division
->GetTopSide());
436 if (division
->GetRightSide())
437 rightNode
= oglObjectCopyMapping
.Find((long)division
->GetRightSide());
438 if (division
->GetBottomSide())
439 bottomNode
= oglObjectCopyMapping
.Find((long)division
->GetBottomSide());
442 wxDivisionShape
*newDivision
= (wxDivisionShape
*)node1
->Data();
444 newDivision
->SetLeftSide((wxDivisionShape
*)leftNode
->Data());
446 newDivision
->SetTopSide((wxDivisionShape
*)topNode
->Data());
448 newDivision
->SetRightSide((wxDivisionShape
*)rightNode
->Data());
450 newDivision
->SetBottomSide((wxDivisionShape
*)bottomNode
->Data());
456 wxOGLConstraint
*wxCompositeShape::AddConstraint(wxOGLConstraint
*constraint
)
458 m_constraints
.Append(constraint
);
459 if (constraint
->m_constraintId
== 0)
460 constraint
->m_constraintId
= wxNewId();
464 wxOGLConstraint
*wxCompositeShape::AddConstraint(int type
, wxShape
*constraining
, wxList
& constrained
)
466 wxOGLConstraint
*constraint
= new wxOGLConstraint(type
, constraining
, constrained
);
467 if (constraint
->m_constraintId
== 0)
468 constraint
->m_constraintId
= wxNewId();
469 m_constraints
.Append(constraint
);
473 wxOGLConstraint
*wxCompositeShape::AddConstraint(int type
, wxShape
*constraining
, wxShape
*constrained
)
476 l
.Append(constrained
);
477 wxOGLConstraint
*constraint
= new wxOGLConstraint(type
, constraining
, l
);
478 if (constraint
->m_constraintId
== 0)
479 constraint
->m_constraintId
= wxNewId();
480 m_constraints
.Append(constraint
);
484 wxOGLConstraint
*wxCompositeShape::FindConstraint(long cId
, wxCompositeShape
**actualComposite
)
486 wxNode
*node
= m_constraints
.First();
489 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->Data();
490 if (constraint
->m_constraintId
== cId
)
493 *actualComposite
= this;
498 // If not found, try children.
499 node
= m_children
.First();
502 wxShape
*child
= (wxShape
*)node
->Data();
503 if (child
->IsKindOf(CLASSINFO(wxCompositeShape
)))
505 wxOGLConstraint
*constraint
= ((wxCompositeShape
*)child
)->FindConstraint(cId
, actualComposite
);
509 *actualComposite
= (wxCompositeShape
*)child
;
518 void wxCompositeShape::DeleteConstraint(wxOGLConstraint
*constraint
)
520 m_constraints
.DeleteObject(constraint
);
524 void wxCompositeShape::CalculateSize()
526 double maxX
= (double) -999999.9;
527 double maxY
= (double) -999999.9;
528 double minX
= (double) 999999.9;
529 double minY
= (double) 999999.9;
532 wxNode
*node
= m_children
.First();
535 wxShape
*object
= (wxShape
*)node
->Data();
537 // Recalculate size of composite objects because may not conform
538 // to size it was set to - depends on the children.
539 object
->CalculateSize();
541 object
->GetBoundingBoxMax(&w
, &h
);
542 if ((object
->GetX() + (w
/2.0)) > maxX
)
543 maxX
= (double)(object
->GetX() + (w
/2.0));
544 if ((object
->GetX() - (w
/2.0)) < minX
)
545 minX
= (double)(object
->GetX() - (w
/2.0));
546 if ((object
->GetY() + (h
/2.0)) > maxY
)
547 maxY
= (double)(object
->GetY() + (h
/2.0));
548 if ((object
->GetY() - (h
/2.0)) < minY
)
549 minY
= (double)(object
->GetY() - (h
/2.0));
553 m_width
= maxX
- minX
;
554 m_height
= maxY
- minY
;
555 m_xpos
= (double)(m_width
/2.0 + minX
);
556 m_ypos
= (double)(m_height
/2.0 + minY
);
559 bool wxCompositeShape::Recompute()
561 int noIterations
= 0;
563 while (changed
&& (noIterations
< 500))
565 changed
= Constrain();
571 cerr << "Warning: constraint algorithm failed after 500 iterations.\n";
577 bool wxCompositeShape::Constrain()
581 bool changed
= FALSE
;
582 wxNode
*node
= m_children
.First();
585 wxShape
*object
= (wxShape
*)node
->Data();
586 if (object
->Constrain())
591 node
= m_constraints
.First();
594 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->Data();
595 if (constraint
->Evaluate()) changed
= TRUE
;
602 void wxCompositeShape::WriteAttributes(wxExpr
*clause
)
604 wxRectangleShape::WriteAttributes(clause
);
606 // clause->AddAttributeValue("selectable", (long)selectable);
608 // Output constraints as constraint1 = (...), constraint2 = (...), etc.
609 int constraintNo
= 1;
610 char m_constraintNameBuf
[20];
611 wxNode
*node
= m_constraints
.First();
614 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->Data();
615 sprintf(m_constraintNameBuf
, "constraint%d", constraintNo
);
617 // Each constraint is stored in the form
618 // (type name id xspacing yspacing m_constrainingObjectId constrainedObjectIdList)
619 wxExpr
*constraintExpr
= new wxExpr(wxExprList
);
620 constraintExpr
->Append(new wxExpr((long)constraint
->m_constraintType
));
621 constraintExpr
->Append(new wxExpr(wxExprString
, constraint
->m_constraintName
));
622 constraintExpr
->Append(new wxExpr(constraint
->m_constraintId
));
623 constraintExpr
->Append(new wxExpr(constraint
->m_xSpacing
));
624 constraintExpr
->Append(new wxExpr(constraint
->m_ySpacing
));
625 constraintExpr
->Append(new wxExpr(constraint
->m_constrainingObject
->GetId()));
627 wxExpr
*objectList
= new wxExpr(wxExprList
);
628 wxNode
*node1
= constraint
->m_constrainedObjects
.First();
631 wxShape
*obj
= (wxShape
*)node1
->Data();
632 objectList
->Append(new wxExpr(obj
->GetId()));
633 node1
= node1
->Next();
635 constraintExpr
->Append(objectList
);
637 clause
->AddAttributeValue(m_constraintNameBuf
, constraintExpr
);
643 // Write the ids of all the child images
644 wxExpr
*childrenExpr
= new wxExpr(wxExprList
);
645 node
= m_children
.First();
648 wxShape
*child
= (wxShape
*)node
->Data();
649 childrenExpr
->Append(new wxExpr(child
->GetId()));
652 clause
->AddAttributeValue("children", childrenExpr
);
654 // Write the ids of all the division images
655 if (m_divisions
.Number() > 0)
657 wxExpr
*divisionsExpr
= new wxExpr(wxExprList
);
658 node
= m_divisions
.First();
661 wxShape
*child
= (wxShape
*)node
->Data();
662 divisionsExpr
->Append(new wxExpr(child
->GetId()));
665 clause
->AddAttributeValue("divisions", divisionsExpr
);
669 // Problem. Child images are always written AFTER the parent
670 // so as to be able to link up to parent. So we may not be able
671 // to find the constraint participants until we've read everything
672 // in. Need to have another pass for composites.
673 void wxCompositeShape::ReadAttributes(wxExpr
*clause
)
675 wxRectangleShape::ReadAttributes(clause
);
677 // clause->GetAttributeValue("selectable", selectable);
680 void wxCompositeShape::ReadConstraints(wxExpr
*clause
, wxExprDatabase
*database
)
682 // Constraints are output as constraint1 = (...), constraint2 = (...), etc.
683 int constraintNo
= 1;
684 char m_constraintNameBuf
[20];
685 bool haveConstraints
= TRUE
;
687 while (haveConstraints
)
689 sprintf(m_constraintNameBuf
, "constraint%d", constraintNo
);
690 wxExpr
*constraintExpr
= NULL
;
691 clause
->GetAttributeValue(m_constraintNameBuf
, &constraintExpr
);
694 haveConstraints
= FALSE
;
698 double cXSpacing
= 0.0;
699 double cYSpacing
= 0.0;
702 wxShape
*m_constrainingObject
= NULL
;
703 wxList m_constrainedObjects
;
705 // Each constraint is stored in the form
706 // (type name id xspacing yspacing m_constrainingObjectId constrainedObjectIdList)
708 wxExpr
*typeExpr
= constraintExpr
->Nth(0);
709 wxExpr
*nameExpr
= constraintExpr
->Nth(1);
710 wxExpr
*idExpr
= constraintExpr
->Nth(2);
711 wxExpr
*xExpr
= constraintExpr
->Nth(3);
712 wxExpr
*yExpr
= constraintExpr
->Nth(4);
713 wxExpr
*constrainingExpr
= constraintExpr
->Nth(5);
714 wxExpr
*constrainedExpr
= constraintExpr
->Nth(6);
716 cType
= (int)typeExpr
->IntegerValue();
717 cXSpacing
= xExpr
->RealValue();
718 cYSpacing
= yExpr
->RealValue();
719 cName
= nameExpr
->StringValue();
720 cId
= idExpr
->IntegerValue();
722 wxExpr
*objExpr1
= database
->HashFind("node_image", constrainingExpr
->IntegerValue());
723 if (objExpr1
&& objExpr1
->GetClientData())
724 m_constrainingObject
= (wxShape
*)objExpr1
->GetClientData();
726 wxLogFatalError("Object graphics error: Couldn't find constraining image of composite.");
729 wxExpr
*currentIdExpr
= constrainedExpr
->Nth(i
);
730 while (currentIdExpr
)
732 long currentId
= currentIdExpr
->IntegerValue();
733 wxExpr
*objExpr2
= database
->HashFind("node_image", currentId
);
734 if (objExpr2
&& objExpr2
->GetClientData())
736 m_constrainedObjects
.Append((wxShape
*)objExpr2
->GetClientData());
740 wxLogFatalError("Object graphics error: Couldn't find constrained image of composite.");
744 currentIdExpr
= constrainedExpr
->Nth(i
);
746 wxOGLConstraint
*newConstraint
= AddConstraint(cType
, m_constrainingObject
, m_constrainedObjects
);
747 newConstraint
->SetSpacing(cXSpacing
, cYSpacing
);
748 newConstraint
->m_constraintId
= cId
;
749 newConstraint
->m_constraintName
= (const char*) cName
;
755 // Make this composite into a container by creating one wxDivisionShape
756 void wxCompositeShape::MakeContainer()
758 wxDivisionShape
*division
= OnCreateDivision();
759 m_divisions
.Append(division
);
762 division
->SetSize(m_width
, m_height
);
764 wxClientDC
dc(GetCanvas());
765 GetCanvas()->PrepareDC(dc
);
767 division
->Move(dc
, GetX(), GetY());
769 division
->Show(TRUE
);
772 wxDivisionShape
*wxCompositeShape::OnCreateDivision()
774 return new wxDivisionShape
;
777 wxShape
*wxCompositeShape::FindContainerImage()
779 wxNode
*node
= m_children
.First();
782 wxShape
*child
= (wxShape
*)node
->Data();
783 if (!m_divisions
.Member(child
))
790 // Returns TRUE if division is a descendant of this container
791 bool wxCompositeShape::ContainsDivision(wxDivisionShape
*division
)
793 if (m_divisions
.Member(division
))
795 wxNode
*node
= m_children
.First();
798 wxShape
*child
= (wxShape
*)node
->Data();
799 if (child
->IsKindOf(CLASSINFO(wxCompositeShape
)))
801 bool ans
= ((wxCompositeShape
*)child
)->ContainsDivision(division
);
815 IMPLEMENT_DYNAMIC_CLASS(wxDivisionShape
, wxCompositeShape
)
817 wxDivisionShape::wxDivisionShape()
819 SetSensitivityFilter(OP_CLICK_LEFT
| OP_CLICK_RIGHT
| OP_DRAG_RIGHT
);
820 SetCentreResize(FALSE
);
821 SetAttachmentMode(TRUE
);
826 m_handleSide
= DIVISION_SIDE_NONE
;
827 m_leftSidePen
= wxBLACK_PEN
;
828 m_topSidePen
= wxBLACK_PEN
;
829 m_leftSideColour
= "BLACK";
830 m_topSideColour
= "BLACK";
831 m_leftSideStyle
= "Solid";
832 m_topSideStyle
= "Solid";
836 wxDivisionShape::~wxDivisionShape()
840 void wxDivisionShape::OnDraw(wxDC
& dc
)
842 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
843 dc
.SetBackgroundMode(wxTRANSPARENT
);
845 double x1
= (double)(GetX() - (GetWidth()/2.0));
846 double y1
= (double)(GetY() - (GetHeight()/2.0));
847 double x2
= (double)(GetX() + (GetWidth()/2.0));
848 double y2
= (double)(GetY() + (GetHeight()/2.0));
850 // Should subtract 1 pixel if drawing under Windows
857 dc
.SetPen(* m_leftSidePen
);
858 dc
.DrawLine(WXROUND(x1
), WXROUND(y2
), WXROUND(x1
), WXROUND(y1
));
862 dc
.SetPen(* m_topSidePen
);
863 dc
.DrawLine(WXROUND(x1
), WXROUND(y1
), WXROUND(x2
), WXROUND(y1
));
866 // For testing purposes, draw a rectangle so we know
867 // how big the division is.
868 // SetBrush(* wxCYAN_BRUSH);
869 // wxRectangleShape::OnDraw(dc);
872 void wxDivisionShape::OnDrawContents(wxDC
& dc
)
874 wxCompositeShape::OnDrawContents(dc
);
877 bool wxDivisionShape::OnMovePre(wxDC
& dc
, double x
, double y
, double oldx
, double oldy
, bool display
)
879 double diffX
= x
- oldx
;
880 double diffY
= y
- oldy
;
881 wxNode
*node
= m_children
.First();
884 wxShape
*object
= (wxShape
*)node
->Data();
886 object
->Move(dc
, object
->GetX() + diffX
, object
->GetY() + diffY
, display
);
892 void wxDivisionShape::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
894 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
900 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
901 m_parent
->GetEventHandler()->OnDragLeft(draw
, x
, y
, keys
, attachment
);
905 wxShape::OnDragLeft(draw
, x
, y
, keys
, attachment
);
908 void wxDivisionShape::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
910 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
916 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
917 m_parent
->GetEventHandler()->OnBeginDragLeft(x
, y
, keys
, attachment
);
922 wxShape::OnBeginDragLeft(x
, y
, keys
, attachment
);
925 void wxDivisionShape::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
927 m_canvas
->ReleaseMouse();
928 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
934 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
935 m_parent
->GetEventHandler()->OnEndDragLeft(x
, y
, keys
, attachment
);
940 wxClientDC
dc(GetCanvas());
941 GetCanvas()->PrepareDC(dc
);
943 dc
.SetLogicalFunction(wxCOPY
);
945 m_canvas
->Snap(&m_xpos
, &m_ypos
);
946 GetEventHandler()->OnMovePre(dc
, x
, y
, m_oldX
, m_oldY
);
948 ResetControlPoints();
951 GetEventHandler()->OnDrawControlPoints(dc
);
953 if (m_canvas
&& !m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
956 void wxDivisionShape::SetSize(double w
, double h
, bool recursive
)
960 wxRectangleShape::SetSize(w
, h
, recursive
);
963 void wxDivisionShape::CalculateSize()
967 void wxDivisionShape::Copy(wxShape
& copy
)
969 wxCompositeShape::Copy(copy
);
971 wxASSERT( copy
.IsKindOf(CLASSINFO(wxDivisionShape
)) ) ;
973 wxDivisionShape
& divisionCopy
= (wxDivisionShape
&) copy
;
975 divisionCopy
.m_leftSideStyle
= m_leftSideStyle
;
976 divisionCopy
.m_topSideStyle
= m_topSideStyle
;
977 divisionCopy
.m_leftSideColour
= m_leftSideColour
;
978 divisionCopy
.m_topSideColour
= m_topSideColour
;
980 divisionCopy
.m_leftSidePen
= m_leftSidePen
;
981 divisionCopy
.m_topSidePen
= m_topSidePen
;
982 divisionCopy
.m_handleSide
= m_handleSide
;
984 // Division geometry copying is handled at the wxCompositeShape level.
988 void wxDivisionShape::WriteAttributes(wxExpr
*clause
)
990 wxCompositeShape::WriteAttributes(clause
);
993 clause
->AddAttributeValue("left_side", (long)m_leftSide
->GetId());
995 clause
->AddAttributeValue("top_side", (long)m_topSide
->GetId());
997 clause
->AddAttributeValue("right_side", (long)m_rightSide
->GetId());
999 clause
->AddAttributeValue("bottom_side", (long)m_bottomSide
->GetId());
1001 clause
->AddAttributeValue("handle_side", (long)m_handleSide
);
1002 clause
->AddAttributeValueString("left_colour", m_leftSideColour
);
1003 clause
->AddAttributeValueString("top_colour", m_topSideColour
);
1004 clause
->AddAttributeValueString("left_style", m_leftSideStyle
);
1005 clause
->AddAttributeValueString("top_style", m_topSideStyle
);
1008 void wxDivisionShape::ReadAttributes(wxExpr
*clause
)
1010 wxCompositeShape::ReadAttributes(clause
);
1012 clause
->GetAttributeValue("handle_side", m_handleSide
);
1013 clause
->GetAttributeValue("left_colour", m_leftSideColour
);
1014 clause
->GetAttributeValue("top_colour", m_topSideColour
);
1015 clause
->GetAttributeValue("left_style", m_leftSideStyle
);
1016 clause
->GetAttributeValue("top_style", m_topSideStyle
);
1021 void wxDivisionShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
1023 if (keys
& KEY_CTRL
)
1028 else if (keys & KEY_SHIFT)
1030 if (m_leftSide || m_topSide || m_rightSide || m_bottomSide)
1035 GetParent()->Draw(dc);
1048 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1049 m_parent
->GetEventHandler()->OnRightClick(x
, y
, keys
, attachment
);
1056 // Divide wxHORIZONTALly or wxVERTICALly
1057 bool wxDivisionShape::Divide(int direction
)
1059 // Calculate existing top-left, bottom-right
1060 double x1
= (double)(GetX() - (GetWidth()/2.0));
1061 double y1
= (double)(GetY() - (GetHeight()/2.0));
1062 wxCompositeShape
*compositeParent
= (wxCompositeShape
*)GetParent();
1063 double oldWidth
= GetWidth();
1064 double oldHeight
= GetHeight();
1068 wxClientDC
dc(GetCanvas());
1069 GetCanvas()->PrepareDC(dc
);
1071 if (direction
== wxVERTICAL
)
1073 // Dividing vertically means notionally putting a horizontal line through it.
1074 // Break existing piece into two.
1075 double newXPos1
= GetX();
1076 double newYPos1
= (double)(y1
+ (GetHeight()/4.0));
1077 double newXPos2
= GetX();
1078 double newYPos2
= (double)(y1
+ (3.0*GetHeight()/4.0));
1079 wxDivisionShape
*newDivision
= compositeParent
->OnCreateDivision();
1080 newDivision
->Show(TRUE
);
1084 // Anything adjoining the bottom of this division now adjoins the
1085 // bottom of the new division.
1086 wxNode
*node
= compositeParent
->GetDivisions().First();
1089 wxDivisionShape
*obj
= (wxDivisionShape
*)node
->Data();
1090 if (obj
->GetTopSide() == this)
1091 obj
->SetTopSide(newDivision
);
1092 node
= node
->Next();
1094 newDivision
->SetTopSide(this);
1095 newDivision
->SetBottomSide(m_bottomSide
);
1096 newDivision
->SetLeftSide(m_leftSide
);
1097 newDivision
->SetRightSide(m_rightSide
);
1098 m_bottomSide
= newDivision
;
1100 compositeParent
->GetDivisions().Append(newDivision
);
1102 // CHANGE: Need to insert this division at start of divisions in the object
1103 // list, because e.g.:
1105 // 2) Add contained object
1107 // Division is now receiving mouse events _before_ the contained object,
1108 // because it was added last (on top of all others)
1110 // Add after the image that visualizes the container
1111 compositeParent
->AddChild(newDivision
, compositeParent
->FindContainerImage());
1113 m_handleSide
= DIVISION_SIDE_BOTTOM
;
1114 newDivision
->SetHandleSide(DIVISION_SIDE_TOP
);
1116 SetSize(oldWidth
, (double)(oldHeight
/2.0));
1117 Move(dc
, newXPos1
, newYPos1
);
1119 newDivision
->SetSize(oldWidth
, (double)(oldHeight
/2.0));
1120 newDivision
->Move(dc
, newXPos2
, newYPos2
);
1124 // Dividing horizontally means notionally putting a vertical line through it.
1125 // Break existing piece into two.
1126 double newXPos1
= (double)(x1
+ (GetWidth()/4.0));
1127 double newYPos1
= GetY();
1128 double newXPos2
= (double)(x1
+ (3.0*GetWidth()/4.0));
1129 double newYPos2
= GetY();
1130 wxDivisionShape
*newDivision
= compositeParent
->OnCreateDivision();
1131 newDivision
->Show(TRUE
);
1135 // Anything adjoining the left of this division now adjoins the
1136 // left of the new division.
1137 wxNode
*node
= compositeParent
->GetDivisions().First();
1140 wxDivisionShape
*obj
= (wxDivisionShape
*)node
->Data();
1141 if (obj
->GetLeftSide() == this)
1142 obj
->SetLeftSide(newDivision
);
1143 node
= node
->Next();
1145 newDivision
->SetTopSide(m_topSide
);
1146 newDivision
->SetBottomSide(m_bottomSide
);
1147 newDivision
->SetLeftSide(this);
1148 newDivision
->SetRightSide(m_rightSide
);
1149 m_rightSide
= newDivision
;
1151 compositeParent
->GetDivisions().Append(newDivision
);
1152 compositeParent
->AddChild(newDivision
, compositeParent
->FindContainerImage());
1154 m_handleSide
= DIVISION_SIDE_RIGHT
;
1155 newDivision
->SetHandleSide(DIVISION_SIDE_LEFT
);
1157 SetSize((double)(oldWidth
/2.0), oldHeight
);
1158 Move(dc
, newXPos1
, newYPos1
);
1160 newDivision
->SetSize((double)(oldWidth
/2.0), oldHeight
);
1161 newDivision
->Move(dc
, newXPos2
, newYPos2
);
1163 if (compositeParent
->Selected())
1165 compositeParent
->DeleteControlPoints(& dc
);
1166 compositeParent
->MakeControlPoints();
1167 compositeParent
->MakeMandatoryControlPoints();
1169 compositeParent
->Draw(dc
);
1173 // Make one control point for every visible line
1174 void wxDivisionShape::MakeControlPoints()
1176 MakeMandatoryControlPoints();
1179 void wxDivisionShape::MakeMandatoryControlPoints()
1183 GetBoundingBoxMax(&maxX
, &maxY
);
1189 x = (double)(-maxX/2.0);
1191 wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y,
1192 CONTROL_POINT_HORIZONTAL);
1193 m_canvas->AddShape(control);
1194 m_controlPoints.Append(control);
1199 y = (double)(-maxY/2.0);
1200 wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y,
1201 CONTROL_POINT_VERTICAL);
1202 m_canvas->AddShape(control);
1203 m_controlPoints.Append(control);
1206 switch (m_handleSide
)
1208 case DIVISION_SIDE_LEFT
:
1210 x
= (double)(-maxX
/2.0);
1212 direction
= CONTROL_POINT_HORIZONTAL
;
1215 case DIVISION_SIDE_TOP
:
1218 y
= (double)(-maxY
/2.0);
1219 direction
= CONTROL_POINT_VERTICAL
;
1222 case DIVISION_SIDE_RIGHT
:
1224 x
= (double)(maxX
/2.0);
1226 direction
= CONTROL_POINT_HORIZONTAL
;
1229 case DIVISION_SIDE_BOTTOM
:
1232 y
= (double)(maxY
/2.0);
1233 direction
= CONTROL_POINT_VERTICAL
;
1239 if (m_handleSide
!= DIVISION_SIDE_NONE
)
1241 wxDivisionControlPoint
*control
= new wxDivisionControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, x
, y
,
1243 m_canvas
->AddShape(control
);
1244 m_controlPoints
.Append(control
);
1248 void wxDivisionShape::ResetControlPoints()
1250 ResetMandatoryControlPoints();
1253 void wxDivisionShape::ResetMandatoryControlPoints()
1255 if (m_controlPoints
.Number() < 1)
1260 GetBoundingBoxMax(&maxX
, &maxY
);
1262 wxNode *node = m_controlPoints.First();
1265 wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->Data();
1266 if (control->type == CONTROL_POINT_HORIZONTAL)
1268 control->xoffset = (double)(-maxX/2.0); control->m_yoffset = 0.0;
1270 else if (control->type == CONTROL_POINT_VERTICAL)
1272 control->xoffset = 0.0; control->m_yoffset = (double)(-maxY/2.0);
1274 node = node->Next();
1277 wxNode
*node
= m_controlPoints
.First();
1278 if ((m_handleSide
== DIVISION_SIDE_LEFT
) && node
)
1280 wxDivisionControlPoint
*control
= (wxDivisionControlPoint
*)node
->Data();
1281 control
->m_xoffset
= (double)(-maxX
/2.0); control
->m_yoffset
= 0.0;
1284 if ((m_handleSide
== DIVISION_SIDE_TOP
) && node
)
1286 wxDivisionControlPoint
*control
= (wxDivisionControlPoint
*)node
->Data();
1287 control
->m_xoffset
= 0.0; control
->m_yoffset
= (double)(-maxY
/2.0);
1290 if ((m_handleSide
== DIVISION_SIDE_RIGHT
) && node
)
1292 wxDivisionControlPoint
*control
= (wxDivisionControlPoint
*)node
->Data();
1293 control
->m_xoffset
= (double)(maxX
/2.0); control
->m_yoffset
= 0.0;
1296 if ((m_handleSide
== DIVISION_SIDE_BOTTOM
) && node
)
1298 wxDivisionControlPoint
*control
= (wxDivisionControlPoint
*)node
->Data();
1299 control
->m_xoffset
= 0.0; control
->m_yoffset
= (double)(maxY
/2.0);
1303 // Adjust a side, returning FALSE if it's not physically possible.
1304 bool wxDivisionShape::AdjustLeft(double left
, bool test
)
1306 double x2
= (double)(GetX() + (GetWidth()/2.0));
1313 double newW
= x2
- left
;
1314 double newX
= (double)(left
+ newW
/2.0);
1315 SetSize(newW
, GetHeight());
1317 wxClientDC
dc(GetCanvas());
1318 GetCanvas()->PrepareDC(dc
);
1320 Move(dc
, newX
, GetY());
1325 bool wxDivisionShape::AdjustTop(double top
, bool test
)
1327 double y2
= (double)(GetY() + (GetHeight()/2.0));
1334 double newH
= y2
- top
;
1335 double newY
= (double)(top
+ newH
/2.0);
1336 SetSize(GetWidth(), newH
);
1338 wxClientDC
dc(GetCanvas());
1339 GetCanvas()->PrepareDC(dc
);
1341 Move(dc
, GetX(), newY
);
1346 bool wxDivisionShape::AdjustRight(double right
, bool test
)
1348 double x1
= (double)(GetX() - (GetWidth()/2.0));
1355 double newW
= right
- x1
;
1356 double newX
= (double)(x1
+ newW
/2.0);
1357 SetSize(newW
, GetHeight());
1359 wxClientDC
dc(GetCanvas());
1360 GetCanvas()->PrepareDC(dc
);
1362 Move(dc
, newX
, GetY());
1367 bool wxDivisionShape::AdjustBottom(double bottom
, bool test
)
1369 double y1
= (double)(GetY() - (GetHeight()/2.0));
1376 double newH
= bottom
- y1
;
1377 double newY
= (double)(y1
+ newH
/2.0);
1378 SetSize(GetWidth(), newH
);
1380 wxClientDC
dc(GetCanvas());
1381 GetCanvas()->PrepareDC(dc
);
1383 Move(dc
, GetX(), newY
);
1388 wxDivisionControlPoint::wxDivisionControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
, double size
, double the_xoffset
, double the_yoffset
, int the_type
):
1389 wxControlPoint(the_canvas
, object
, size
, the_xoffset
, the_yoffset
, the_type
)
1391 SetEraseObject(FALSE
);
1394 wxDivisionControlPoint::~wxDivisionControlPoint()
1398 static double originalX
= 0.0;
1399 static double originalY
= 0.0;
1400 static double originalW
= 0.0;
1401 static double originalH
= 0.0;
1403 // Implement resizing of canvas object
1404 void wxDivisionControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1406 wxControlPoint::OnDragLeft(draw
, x
, y
, keys
, attachment
);
1409 void wxDivisionControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1411 wxDivisionShape
*division
= (wxDivisionShape
*)m_shape
;
1412 originalX
= division
->GetX();
1413 originalY
= division
->GetY();
1414 originalW
= division
->GetWidth();
1415 originalH
= division
->GetHeight();
1417 wxControlPoint::OnBeginDragLeft(x
, y
, keys
, attachment
);
1420 void wxDivisionControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1422 wxControlPoint::OnEndDragLeft(x
, y
, keys
, attachment
);
1424 wxClientDC
dc(GetCanvas());
1425 GetCanvas()->PrepareDC(dc
);
1427 wxDivisionShape
*division
= (wxDivisionShape
*)m_shape
;
1428 wxCompositeShape
*divisionParent
= (wxCompositeShape
*)division
->GetParent();
1430 // Need to check it's within the bounds of the parent composite.
1431 double x1
= (double)(divisionParent
->GetX() - (divisionParent
->GetWidth()/2.0));
1432 double y1
= (double)(divisionParent
->GetY() - (divisionParent
->GetHeight()/2.0));
1433 double x2
= (double)(divisionParent
->GetX() + (divisionParent
->GetWidth()/2.0));
1434 double y2
= (double)(divisionParent
->GetY() + (divisionParent
->GetHeight()/2.0));
1436 // Need to check it has not made the division zero or negative width/height
1437 double dx1
= (double)(division
->GetX() - (division
->GetWidth()/2.0));
1438 double dy1
= (double)(division
->GetY() - (division
->GetHeight()/2.0));
1439 double dx2
= (double)(division
->GetX() + (division
->GetWidth()/2.0));
1440 double dy2
= (double)(division
->GetY() + (division
->GetHeight()/2.0));
1442 bool success
= TRUE
;
1443 switch (division
->GetHandleSide())
1445 case DIVISION_SIDE_LEFT
:
1447 if ((x
<= x1
) || (x
>= x2
) || (x
>= dx2
))
1449 // Try it out first...
1450 else if (!division
->ResizeAdjoining(DIVISION_SIDE_LEFT
, x
, TRUE
))
1453 division
->ResizeAdjoining(DIVISION_SIDE_LEFT
, x
, FALSE
);
1457 case DIVISION_SIDE_TOP
:
1459 if ((y
<= y1
) || (y
>= y2
) || (y
>= dy2
))
1461 else if (!division
->ResizeAdjoining(DIVISION_SIDE_TOP
, y
, TRUE
))
1464 division
->ResizeAdjoining(DIVISION_SIDE_TOP
, y
, FALSE
);
1468 case DIVISION_SIDE_RIGHT
:
1470 if ((x
<= x1
) || (x
>= x2
) || (x
<= dx1
))
1472 else if (!division
->ResizeAdjoining(DIVISION_SIDE_RIGHT
, x
, TRUE
))
1475 division
->ResizeAdjoining(DIVISION_SIDE_RIGHT
, x
, FALSE
);
1479 case DIVISION_SIDE_BOTTOM
:
1481 if ((y
<= y1
) || (y
>= y2
) || (y
<= dy1
))
1483 else if (!division
->ResizeAdjoining(DIVISION_SIDE_BOTTOM
, y
, TRUE
))
1486 division
->ResizeAdjoining(DIVISION_SIDE_BOTTOM
, y
, FALSE
);
1493 division
->SetSize(originalW
, originalH
);
1494 division
->Move(dc
, originalX
, originalY
);
1496 divisionParent
->Draw(dc
);
1497 division
->GetEventHandler()->OnDrawControlPoints(dc
);
1500 /* Resize adjoining divisions.
1502 Behaviour should be as follows:
1503 If right edge moves, find all objects whose left edge
1504 adjoins this object, and move left edge accordingly.
1505 If left..., move ... right.
1506 If top..., move ... bottom.
1507 If bottom..., move top.
1508 If size goes to zero or end position is other side of start position,
1509 resize to original size and return.
1511 bool wxDivisionShape::ResizeAdjoining(int side
, double newPos
, bool test
)
1513 wxCompositeShape
*divisionParent
= (wxCompositeShape
*)GetParent();
1514 wxNode
*node
= divisionParent
->GetDivisions().First();
1517 wxDivisionShape
*division
= (wxDivisionShape
*)node
->Data();
1520 case DIVISION_SIDE_LEFT
:
1522 if (division
->m_rightSide
== this)
1524 bool success
= division
->AdjustRight(newPos
, test
);
1525 if (!success
&& test
)
1530 case DIVISION_SIDE_TOP
:
1532 if (division
->m_bottomSide
== this)
1534 bool success
= division
->AdjustBottom(newPos
, test
);
1535 if (!success
&& test
)
1540 case DIVISION_SIDE_RIGHT
:
1542 if (division
->m_leftSide
== this)
1544 bool success
= division
->AdjustLeft(newPos
, test
);
1545 if (!success
&& test
)
1550 case DIVISION_SIDE_BOTTOM
:
1552 if (division
->m_topSide
== this)
1554 bool success
= division
->AdjustTop(newPos
, test
);
1555 if (!success
&& test
)
1563 node
= node
->Next();
1570 * Popup menu for editing divisions
1573 class OGLPopupDivisionMenu
: public wxMenu
{
1575 OGLPopupDivisionMenu() : wxMenu() {
1576 Append(DIVISION_MENU_SPLIT_HORIZONTALLY
, "Split horizontally");
1577 Append(DIVISION_MENU_SPLIT_VERTICALLY
, "Split vertically");
1579 Append(DIVISION_MENU_EDIT_LEFT_EDGE
, "Edit left edge");
1580 Append(DIVISION_MENU_EDIT_TOP_EDGE
, "Edit top edge");
1583 void OnMenu(wxCommandEvent
& event
);
1585 DECLARE_EVENT_TABLE()
1588 BEGIN_EVENT_TABLE(OGLPopupDivisionMenu
, wxMenu
)
1589 EVT_CUSTOM_RANGE(wxEVT_COMMAND_MENU_SELECTED
,
1590 DIVISION_MENU_SPLIT_HORIZONTALLY
,
1591 DIVISION_MENU_EDIT_BOTTOM_EDGE
,
1592 OGLPopupDivisionMenu::OnMenu
)
1596 void OGLPopupDivisionMenu::OnMenu(wxCommandEvent
& event
)
1598 wxDivisionShape
*division
= (wxDivisionShape
*)GetClientData();
1599 switch (event
.GetInt())
1601 case DIVISION_MENU_SPLIT_HORIZONTALLY
:
1603 division
->Divide(wxHORIZONTAL
);
1606 case DIVISION_MENU_SPLIT_VERTICALLY
:
1608 division
->Divide(wxVERTICAL
);
1611 case DIVISION_MENU_EDIT_LEFT_EDGE
:
1613 division
->EditEdge(DIVISION_SIDE_LEFT
);
1616 case DIVISION_MENU_EDIT_TOP_EDGE
:
1618 division
->EditEdge(DIVISION_SIDE_TOP
);
1626 void wxDivisionShape::EditEdge(int side
)
1628 wxMessageBox("EditEdge() not implemented", "OGL", wxOK
);
1631 wxBeginBusyCursor();
1633 wxPen
*currentPen
= NULL
;
1634 char **pColour
= NULL
;
1635 char **pStyle
= NULL
;
1636 if (side
== DIVISION_SIDE_LEFT
)
1638 currentPen
= m_leftSidePen
;
1639 pColour
= &m_leftSideColour
;
1640 pStyle
= &m_leftSideStyle
;
1644 currentPen
= m_topSidePen
;
1645 pColour
= &m_topSideColour
;
1646 pStyle
= &m_topSideStyle
;
1649 GraphicsForm
*form
= new GraphicsForm("Containers");
1650 int lineWidth
= currentPen
->GetWidth();
1652 form
->Add(wxMakeFormShort("Width", &lineWidth
, wxFORM_DEFAULT
, NULL
, NULL
, wxVERTICAL
,
1654 form
->Add(wxMakeFormString("Colour", pColour
, wxFORM_CHOICE
,
1655 new wxList(wxMakeConstraintStrings(
1679 NULL
), NULL
, wxVERTICAL
, 150));
1680 form
->Add(wxMakeFormString("Style", pStyle
, wxFORM_CHOICE
,
1681 new wxList(wxMakeConstraintStrings(
1688 NULL
), NULL
, wxVERTICAL
, 100));
1690 wxDialogBox
*dialog
= new wxDialogBox(m_canvas
->GetParent(), "Division properties", 10, 10, 500, 500);
1691 if (GraphicsLabelFont
)
1692 dialog
->SetLabelFont(GraphicsLabelFont
);
1693 if (GraphicsButtonFont
)
1694 dialog
->SetButtonFont(GraphicsButtonFont
);
1696 form
->AssociatePanel(dialog
);
1697 form
->dialog
= dialog
;
1700 dialog
->Centre(wxBOTH
);
1705 int lineStyle
= wxSOLID
;
1708 if (strcmp(*pStyle
, "Solid") == 0)
1709 lineStyle
= wxSOLID
;
1710 else if (strcmp(*pStyle
, "Dot") == 0)
1712 else if (strcmp(*pStyle
, "Short Dash") == 0)
1713 lineStyle
= wxSHORT_DASH
;
1714 else if (strcmp(*pStyle
, "Long Dash") == 0)
1715 lineStyle
= wxLONG_DASH
;
1716 else if (strcmp(*pStyle
, "Dot Dash") == 0)
1717 lineStyle
= wxDOT_DASH
;
1720 wxPen
*newPen
= wxThePenList
->FindOrCreatePen(*pColour
, lineWidth
, lineStyle
);
1723 if (side
== DIVISION_SIDE_LEFT
)
1724 m_leftSidePen
= newPen
;
1726 m_topSidePen
= newPen
;
1728 // Need to draw whole image again
1729 wxCompositeShape
*compositeParent
= (wxCompositeShape
*)GetParent();
1730 compositeParent
->Draw(dc
);
1735 void wxDivisionShape::PopupMenu(double x
, double y
)
1737 wxMenu
* oglPopupDivisionMenu
= new OGLPopupDivisionMenu
;
1739 oglPopupDivisionMenu
->SetClientData((void *)this);
1741 oglPopupDivisionMenu
->Enable(DIVISION_MENU_EDIT_LEFT_EDGE
, TRUE
);
1743 oglPopupDivisionMenu
->Enable(DIVISION_MENU_EDIT_LEFT_EDGE
, FALSE
);
1745 oglPopupDivisionMenu
->Enable(DIVISION_MENU_EDIT_TOP_EDGE
, TRUE
);
1747 oglPopupDivisionMenu
->Enable(DIVISION_MENU_EDIT_TOP_EDGE
, FALSE
);
1750 m_canvas
->GetViewStart(&x1
, &y1
);
1753 m_canvas
->GetScrollPixelsPerUnit(&unit_x
, &unit_y
);
1755 wxClientDC
dc(GetCanvas());
1756 GetCanvas()->PrepareDC(dc
);
1758 int mouse_x
= (int)(dc
.LogicalToDeviceX((long)(x
- x1
*unit_x
)));
1759 int mouse_y
= (int)(dc
.LogicalToDeviceY((long)(y
- y1
*unit_y
)));
1761 m_canvas
->PopupMenu(oglPopupDivisionMenu
, mouse_x
, mouse_y
);
1762 delete oglPopupDivisionMenu
;
1765 void wxDivisionShape::SetLeftSideColour(const wxString
& colour
)
1767 m_leftSideColour
= colour
;
1770 void wxDivisionShape::SetTopSideColour(const wxString
& colour
)
1772 m_topSideColour
= colour
;
1775 void wxDivisionShape::SetLeftSideStyle(const wxString
& style
)
1777 m_leftSideStyle
= style
;
1780 void wxDivisionShape::SetTopSideStyle(const wxString
& style
)
1782 m_topSideStyle
= style
;