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/deprecated/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>
37 // Sometimes, objects need to access the whole database to
38 // construct themselves.
39 wxExprDatabase
*GlobalwxExprDatabase
= NULL
;
43 * Division control point
46 class wxDivisionControlPoint
: public wxControlPoint
48 DECLARE_DYNAMIC_CLASS(wxDivisionControlPoint
)
50 wxDivisionControlPoint() {}
51 wxDivisionControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
, double size
, double the_xoffset
, double the_yoffset
, int the_type
);
52 ~wxDivisionControlPoint();
54 void OnDragLeft(bool draw
, double x
, double y
, int keys
=0, int attachment
= 0);
55 void OnBeginDragLeft(double x
, double y
, int keys
=0, int attachment
= 0);
56 void OnEndDragLeft(double x
, double y
, int keys
=0, int attachment
= 0);
59 IMPLEMENT_DYNAMIC_CLASS(wxDivisionControlPoint
, wxControlPoint
)
66 IMPLEMENT_DYNAMIC_CLASS(wxCompositeShape
, wxRectangleShape
)
68 wxCompositeShape::wxCompositeShape(): wxRectangleShape(10.0, 10.0)
70 // selectable = FALSE;
75 wxCompositeShape::~wxCompositeShape()
77 wxNode
*node
= m_constraints
.GetFirst();
80 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->GetData();
82 node
= node
->GetNext();
84 node
= m_children
.GetFirst();
87 wxShape
*object
= (wxShape
*)node
->GetData();
88 wxNode
*next
= node
->GetNext();
95 void wxCompositeShape::OnDraw(wxDC
& dc
)
97 double x1
= (double)(m_xpos
- m_width
/2.0);
98 double y1
= (double)(m_ypos
- m_height
/2.0);
100 if (m_shadowMode
!= SHADOW_NONE
)
103 dc
.SetBrush(* m_shadowBrush
);
104 dc
.SetPen(* g_oglTransparentPen
);
106 if (m_cornerRadius
!= 0.0)
107 dc
.DrawRoundedRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
),
108 WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
110 dc
.DrawRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
), WXROUND(m_width
), WXROUND(m_height
));
114 void wxCompositeShape::OnDrawContents(wxDC
& dc
)
116 wxNode
*node
= m_children
.GetFirst();
119 wxShape
*object
= (wxShape
*)node
->GetData();
121 object
->DrawLinks(dc
);
122 node
= node
->GetNext();
124 wxShape::OnDrawContents(dc
);
127 bool wxCompositeShape::OnMovePre(wxDC
& dc
, double x
, double y
, double oldx
, double oldy
, bool display
)
129 double diffX
= x
- oldx
;
130 double diffY
= y
- oldy
;
131 wxNode
*node
= m_children
.GetFirst();
134 wxShape
*object
= (wxShape
*)node
->GetData();
137 object
->Move(dc
, object
->GetX() + diffX
, object
->GetY() + diffY
, display
);
139 node
= node
->GetNext();
144 void wxCompositeShape::OnErase(wxDC
& dc
)
146 wxRectangleShape::OnErase(dc
);
147 wxNode
*node
= m_children
.GetFirst();
150 wxShape
*object
= (wxShape
*)node
->GetData();
152 node
= node
->GetNext();
156 static double objectStartX
= 0.0;
157 static double objectStartY
= 0.0;
159 void wxCompositeShape::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
163 m_canvas
->Snap(&xx
, &yy
);
164 double offsetX
= xx
- objectStartX
;
165 double offsetY
= yy
- objectStartY
;
167 wxClientDC
dc(GetCanvas());
168 GetCanvas()->PrepareDC(dc
);
170 dc
.SetLogicalFunction(OGLRBLF
);
171 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
172 dc
.SetPen(dottedPen
);
173 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
175 GetEventHandler()->OnDrawOutline(dc
, GetX() + offsetX
, GetY() + offsetY
, GetWidth(), GetHeight());
176 // wxShape::OnDragLeft(draw, x, y, keys, attachment);
179 void wxCompositeShape::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
184 wxClientDC
dc(GetCanvas());
185 GetCanvas()->PrepareDC(dc
);
189 dc
.SetLogicalFunction(OGLRBLF
);
191 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
192 dc
.SetPen(dottedPen
);
193 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
194 m_canvas
->CaptureMouse();
198 m_canvas
->Snap(&xx
, &yy
);
199 double offsetX
= xx
- objectStartX
;
200 double offsetY
= yy
- objectStartY
;
202 GetEventHandler()->OnDrawOutline(dc
, GetX() + offsetX
, GetY() + offsetY
, GetWidth(), GetHeight());
204 // wxShape::OnBeginDragLeft(x, y, keys, attachment);
207 void wxCompositeShape::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
209 // wxShape::OnEndDragLeft(x, y, keys, attachment);
211 wxClientDC
dc(GetCanvas());
212 GetCanvas()->PrepareDC(dc
);
214 m_canvas
->ReleaseMouse();
218 if (m_parent
) m_parent
->GetEventHandler()->OnEndDragLeft(x
, y
, keys
, 0);
222 dc
.SetLogicalFunction(wxCOPY
);
225 m_canvas
->Snap(&xx
, &yy
);
226 double offsetX
= xx
- objectStartX
;
227 double offsetY
= yy
- objectStartY
;
229 Move(dc
, GetX() + offsetX
, GetY() + offsetY
);
231 if (m_canvas
&& !m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
234 void wxCompositeShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
236 // If we get a ctrl-right click, this means send the message to
237 // the division, so we can invoke a user interface for dealing with regions.
240 wxNode
*node
= m_divisions
.GetFirst();
243 wxDivisionShape
*division
= (wxDivisionShape
*)node
->GetData();
244 wxNode
*next
= node
->GetNext();
247 if (division
->HitTest(x
, y
, &attach
, &dist
))
249 division
->GetEventHandler()->OnRightClick(x
, y
, keys
, attach
);
258 void wxCompositeShape::SetSize(double w
, double h
, bool recursive
)
260 SetAttachmentSize(w
, h
);
262 double xScale
= (double)(w
/(wxMax(1.0, GetWidth())));
263 double yScale
= (double)(h
/(wxMax(1.0, GetHeight())));
268 if (!recursive
) return;
270 wxNode
*node
= m_children
.GetFirst();
272 wxClientDC
dc(GetCanvas());
273 GetCanvas()->PrepareDC(dc
);
275 double xBound
, yBound
;
278 wxShape
*object
= (wxShape
*)node
->GetData();
280 // Scale the position first
281 double newX
= (double)(((object
->GetX() - GetX())*xScale
) + GetX());
282 double newY
= (double)(((object
->GetY() - GetY())*yScale
) + GetY());
284 object
->Move(dc
, newX
, newY
);
287 // Now set the scaled size
288 object
->GetBoundingBoxMin(&xBound
, &yBound
);
289 object
->SetSize(object
->GetFixedWidth() ? xBound
: xScale
*xBound
,
290 object
->GetFixedHeight() ? yBound
: yScale
*yBound
);
292 node
= node
->GetNext();
294 SetDefaultRegionSize();
297 void wxCompositeShape::AddChild(wxShape
*child
, wxShape
*addAfter
)
299 m_children
.Append(child
);
300 child
->SetParent(this);
303 // Ensure we add at the right position
305 child
->RemoveFromCanvas(m_canvas
);
306 child
->AddToCanvas(m_canvas
, addAfter
);
310 void wxCompositeShape::RemoveChild(wxShape
*child
)
312 m_children
.DeleteObject(child
);
313 m_divisions
.DeleteObject(child
);
314 RemoveChildFromConstraints(child
);
315 child
->SetParent(NULL
);
318 void wxCompositeShape::DeleteConstraintsInvolvingChild(wxShape
*child
)
320 wxNode
*node
= m_constraints
.GetFirst();
323 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->GetData();
324 wxNode
*nextNode
= node
->GetNext();
326 if ((constraint
->m_constrainingObject
== child
) ||
327 constraint
->m_constrainedObjects
.Member(child
))
336 void wxCompositeShape::RemoveChildFromConstraints(wxShape
*child
)
338 wxNode
*node
= m_constraints
.GetFirst();
341 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->GetData();
342 wxNode
*nextNode
= node
->GetNext();
344 if (constraint
->m_constrainedObjects
.Member(child
))
345 constraint
->m_constrainedObjects
.DeleteObject(child
);
346 if (constraint
->m_constrainingObject
== child
)
347 constraint
->m_constrainingObject
= NULL
;
349 // Delete the constraint if no participants left
350 if (!constraint
->m_constrainingObject
)
360 void wxCompositeShape::Copy(wxShape
& copy
)
362 wxRectangleShape::Copy(copy
);
364 wxASSERT( copy
.IsKindOf(CLASSINFO(wxCompositeShape
)) ) ;
366 wxCompositeShape
& compositeCopy
= (wxCompositeShape
&) copy
;
368 // Associate old and new copies for compositeCopying constraints and division geometry
369 oglObjectCopyMapping
.Append((long)this, &compositeCopy
);
372 wxNode
*node
= m_children
.GetFirst();
375 wxShape
*object
= (wxShape
*)node
->GetData();
376 wxShape
*newObject
= object
->CreateNewCopy(FALSE
, FALSE
);
377 if (newObject
->GetId() == 0)
378 newObject
->SetId(wxNewId());
380 newObject
->SetParent(&compositeCopy
);
381 compositeCopy
.m_children
.Append(newObject
);
383 // Some m_children may be divisions
384 if (m_divisions
.Member(object
))
385 compositeCopy
.m_divisions
.Append(newObject
);
387 oglObjectCopyMapping
.Append((long)object
, newObject
);
389 node
= node
->GetNext();
392 // Copy the constraints
393 node
= m_constraints
.GetFirst();
396 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->GetData();
398 wxShape
*newConstraining
= (wxShape
*)(oglObjectCopyMapping
.Find((long)constraint
->m_constrainingObject
)->GetData());
400 wxList newConstrainedList
;
401 wxNode
*node2
= constraint
->m_constrainedObjects
.GetFirst();
404 wxShape
*constrainedObject
= (wxShape
*)node2
->GetData();
405 wxShape
*newConstrained
= (wxShape
*)(oglObjectCopyMapping
.Find((long)constrainedObject
)->GetData());
406 newConstrainedList
.Append(newConstrained
);
407 node2
= node2
->GetNext();
410 wxOGLConstraint
*newConstraint
= new wxOGLConstraint(constraint
->m_constraintType
, newConstraining
,
412 newConstraint
->m_constraintId
= constraint
->m_constraintId
;
413 if (constraint
->m_constraintName
)
415 newConstraint
->m_constraintName
= constraint
->m_constraintName
;
417 newConstraint
->SetSpacing(constraint
->m_xSpacing
, constraint
->m_ySpacing
);
418 compositeCopy
.m_constraints
.Append(newConstraint
);
420 node
= node
->GetNext();
423 // Now compositeCopy the division geometry
424 node
= m_divisions
.GetFirst();
427 wxDivisionShape
*division
= (wxDivisionShape
*)node
->GetData();
428 wxNode
*node1
= oglObjectCopyMapping
.Find((long)division
);
429 wxNode
*leftNode
= NULL
;
430 wxNode
*topNode
= NULL
;
431 wxNode
*rightNode
= NULL
;
432 wxNode
*bottomNode
= NULL
;
433 if (division
->GetLeftSide())
434 leftNode
= oglObjectCopyMapping
.Find((long)division
->GetLeftSide());
435 if (division
->GetTopSide())
436 topNode
= oglObjectCopyMapping
.Find((long)division
->GetTopSide());
437 if (division
->GetRightSide())
438 rightNode
= oglObjectCopyMapping
.Find((long)division
->GetRightSide());
439 if (division
->GetBottomSide())
440 bottomNode
= oglObjectCopyMapping
.Find((long)division
->GetBottomSide());
443 wxDivisionShape
*newDivision
= (wxDivisionShape
*)node1
->GetData();
445 newDivision
->SetLeftSide((wxDivisionShape
*)leftNode
->GetData());
447 newDivision
->SetTopSide((wxDivisionShape
*)topNode
->GetData());
449 newDivision
->SetRightSide((wxDivisionShape
*)rightNode
->GetData());
451 newDivision
->SetBottomSide((wxDivisionShape
*)bottomNode
->GetData());
453 node
= node
->GetNext();
457 wxOGLConstraint
*wxCompositeShape::AddConstraint(wxOGLConstraint
*constraint
)
459 m_constraints
.Append(constraint
);
460 if (constraint
->m_constraintId
== 0)
461 constraint
->m_constraintId
= wxNewId();
465 wxOGLConstraint
*wxCompositeShape::AddConstraint(int type
, wxShape
*constraining
, wxList
& constrained
)
467 wxOGLConstraint
*constraint
= new wxOGLConstraint(type
, constraining
, constrained
);
468 if (constraint
->m_constraintId
== 0)
469 constraint
->m_constraintId
= wxNewId();
470 m_constraints
.Append(constraint
);
474 wxOGLConstraint
*wxCompositeShape::AddConstraint(int type
, wxShape
*constraining
, wxShape
*constrained
)
477 l
.Append(constrained
);
478 wxOGLConstraint
*constraint
= new wxOGLConstraint(type
, constraining
, l
);
479 if (constraint
->m_constraintId
== 0)
480 constraint
->m_constraintId
= wxNewId();
481 m_constraints
.Append(constraint
);
485 wxOGLConstraint
*wxCompositeShape::FindConstraint(long cId
, wxCompositeShape
**actualComposite
)
487 wxNode
*node
= m_constraints
.GetFirst();
490 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->GetData();
491 if (constraint
->m_constraintId
== cId
)
494 *actualComposite
= this;
497 node
= node
->GetNext();
499 // If not found, try children.
500 node
= m_children
.GetFirst();
503 wxShape
*child
= (wxShape
*)node
->GetData();
504 if (child
->IsKindOf(CLASSINFO(wxCompositeShape
)))
506 wxOGLConstraint
*constraint
= ((wxCompositeShape
*)child
)->FindConstraint(cId
, actualComposite
);
510 *actualComposite
= (wxCompositeShape
*)child
;
514 node
= node
->GetNext();
519 void wxCompositeShape::DeleteConstraint(wxOGLConstraint
*constraint
)
521 m_constraints
.DeleteObject(constraint
);
525 void wxCompositeShape::CalculateSize()
527 double maxX
= (double) -999999.9;
528 double maxY
= (double) -999999.9;
529 double minX
= (double) 999999.9;
530 double minY
= (double) 999999.9;
533 wxNode
*node
= m_children
.GetFirst();
536 wxShape
*object
= (wxShape
*)node
->GetData();
538 // Recalculate size of composite objects because may not conform
539 // to size it was set to - depends on the children.
540 object
->CalculateSize();
542 object
->GetBoundingBoxMax(&w
, &h
);
543 if ((object
->GetX() + (w
/2.0)) > maxX
)
544 maxX
= (double)(object
->GetX() + (w
/2.0));
545 if ((object
->GetX() - (w
/2.0)) < minX
)
546 minX
= (double)(object
->GetX() - (w
/2.0));
547 if ((object
->GetY() + (h
/2.0)) > maxY
)
548 maxY
= (double)(object
->GetY() + (h
/2.0));
549 if ((object
->GetY() - (h
/2.0)) < minY
)
550 minY
= (double)(object
->GetY() - (h
/2.0));
552 node
= node
->GetNext();
554 m_width
= maxX
- minX
;
555 m_height
= maxY
- minY
;
556 m_xpos
= (double)(m_width
/2.0 + minX
);
557 m_ypos
= (double)(m_height
/2.0 + minY
);
560 bool wxCompositeShape::Recompute()
562 int noIterations
= 0;
564 while (changed
&& (noIterations
< 500))
566 changed
= Constrain();
572 cerr << "Warning: constraint algorithm failed after 500 iterations.\n";
578 bool wxCompositeShape::Constrain()
582 bool changed
= FALSE
;
583 wxNode
*node
= m_children
.GetFirst();
586 wxShape
*object
= (wxShape
*)node
->GetData();
587 if (object
->Constrain())
589 node
= node
->GetNext();
592 node
= m_constraints
.GetFirst();
595 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->GetData();
596 if (constraint
->Evaluate()) changed
= TRUE
;
597 node
= node
->GetNext();
603 void wxCompositeShape::WriteAttributes(wxExpr
*clause
)
605 wxRectangleShape::WriteAttributes(clause
);
607 // clause->AddAttributeValue("selectable", (long)selectable);
609 // Output constraints as constraint1 = (...), constraint2 = (...), etc.
610 int constraintNo
= 1;
611 char m_constraintNameBuf
[20];
612 wxNode
*node
= m_constraints
.GetFirst();
615 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->GetData();
616 sprintf(m_constraintNameBuf
, "constraint%d", constraintNo
);
618 // Each constraint is stored in the form
619 // (type name id xspacing yspacing m_constrainingObjectId constrainedObjectIdList)
620 wxExpr
*constraintExpr
= new wxExpr(wxExprList
);
621 constraintExpr
->Append(new wxExpr((long)constraint
->m_constraintType
));
622 constraintExpr
->Append(new wxExpr(wxExprString
, constraint
->m_constraintName
));
623 constraintExpr
->Append(new wxExpr(constraint
->m_constraintId
));
624 constraintExpr
->Append(new wxExpr(constraint
->m_xSpacing
));
625 constraintExpr
->Append(new wxExpr(constraint
->m_ySpacing
));
626 constraintExpr
->Append(new wxExpr(constraint
->m_constrainingObject
->GetId()));
628 wxExpr
*objectList
= new wxExpr(wxExprList
);
629 wxNode
*node1
= constraint
->m_constrainedObjects
.GetFirst();
632 wxShape
*obj
= (wxShape
*)node1
->GetData();
633 objectList
->Append(new wxExpr(obj
->GetId()));
634 node1
= node1
->GetNext();
636 constraintExpr
->Append(objectList
);
638 clause
->AddAttributeValue(m_constraintNameBuf
, constraintExpr
);
640 node
= node
->GetNext();
644 // Write the ids of all the child images
645 wxExpr
*childrenExpr
= new wxExpr(wxExprList
);
646 node
= m_children
.GetFirst();
649 wxShape
*child
= (wxShape
*)node
->GetData();
650 childrenExpr
->Append(new wxExpr(child
->GetId()));
651 node
= node
->GetNext();
653 clause
->AddAttributeValue("children", childrenExpr
);
655 // Write the ids of all the division images
656 if (m_divisions
.GetCount() > 0)
658 wxExpr
*divisionsExpr
= new wxExpr(wxExprList
);
659 node
= m_divisions
.GetFirst();
662 wxShape
*child
= (wxShape
*)node
->GetData();
663 divisionsExpr
->Append(new wxExpr(child
->GetId()));
664 node
= node
->GetNext();
666 clause
->AddAttributeValue("divisions", divisionsExpr
);
670 // Problem. Child images are always written AFTER the parent
671 // so as to be able to link up to parent. So we may not be able
672 // to find the constraint participants until we've read everything
673 // in. Need to have another pass for composites.
674 void wxCompositeShape::ReadAttributes(wxExpr
*clause
)
676 wxRectangleShape::ReadAttributes(clause
);
678 // clause->GetAttributeValue("selectable", selectable);
681 void wxCompositeShape::ReadConstraints(wxExpr
*clause
, wxExprDatabase
*database
)
683 // Constraints are output as constraint1 = (...), constraint2 = (...), etc.
684 int constraintNo
= 1;
685 char m_constraintNameBuf
[20];
686 bool haveConstraints
= TRUE
;
688 while (haveConstraints
)
690 sprintf(m_constraintNameBuf
, "constraint%d", constraintNo
);
691 wxExpr
*constraintExpr
= NULL
;
692 clause
->GetAttributeValue(m_constraintNameBuf
, &constraintExpr
);
695 haveConstraints
= FALSE
;
699 double cXSpacing
= 0.0;
700 double cYSpacing
= 0.0;
703 wxShape
*m_constrainingObject
= NULL
;
704 wxList m_constrainedObjects
;
706 // Each constraint is stored in the form
707 // (type name id xspacing yspacing m_constrainingObjectId constrainedObjectIdList)
709 wxExpr
*typeExpr
= constraintExpr
->Nth(0);
710 wxExpr
*nameExpr
= constraintExpr
->Nth(1);
711 wxExpr
*idExpr
= constraintExpr
->Nth(2);
712 wxExpr
*xExpr
= constraintExpr
->Nth(3);
713 wxExpr
*yExpr
= constraintExpr
->Nth(4);
714 wxExpr
*constrainingExpr
= constraintExpr
->Nth(5);
715 wxExpr
*constrainedExpr
= constraintExpr
->Nth(6);
717 cType
= (int)typeExpr
->IntegerValue();
718 cXSpacing
= xExpr
->RealValue();
719 cYSpacing
= yExpr
->RealValue();
720 cName
= nameExpr
->StringValue();
721 cId
= idExpr
->IntegerValue();
723 wxExpr
*objExpr1
= database
->HashFind("node_image", constrainingExpr
->IntegerValue());
724 if (objExpr1
&& objExpr1
->GetClientData())
725 m_constrainingObject
= (wxShape
*)objExpr1
->GetClientData();
727 wxLogFatalError(wxT("Object graphics error: Couldn't find constraining image of composite."));
730 wxExpr
*currentIdExpr
= constrainedExpr
->Nth(i
);
731 while (currentIdExpr
)
733 long currentId
= currentIdExpr
->IntegerValue();
734 wxExpr
*objExpr2
= database
->HashFind("node_image", currentId
);
735 if (objExpr2
&& objExpr2
->GetClientData())
737 m_constrainedObjects
.Append((wxShape
*)objExpr2
->GetClientData());
741 wxLogFatalError(wxT("Object graphics error: Couldn't find constrained image of composite."));
745 currentIdExpr
= constrainedExpr
->Nth(i
);
747 wxOGLConstraint
*newConstraint
= AddConstraint(cType
, m_constrainingObject
, m_constrainedObjects
);
748 newConstraint
->SetSpacing(cXSpacing
, cYSpacing
);
749 newConstraint
->m_constraintId
= cId
;
750 newConstraint
->m_constraintName
= cName
;
756 // Make this composite into a container by creating one wxDivisionShape
757 void wxCompositeShape::MakeContainer()
759 wxDivisionShape
*division
= OnCreateDivision();
760 m_divisions
.Append(division
);
763 division
->SetSize(m_width
, m_height
);
765 wxClientDC
dc(GetCanvas());
766 GetCanvas()->PrepareDC(dc
);
768 division
->Move(dc
, GetX(), GetY());
770 division
->Show(TRUE
);
773 wxDivisionShape
*wxCompositeShape::OnCreateDivision()
775 return new wxDivisionShape
;
778 wxShape
*wxCompositeShape::FindContainerImage()
780 wxNode
*node
= m_children
.GetFirst();
783 wxShape
*child
= (wxShape
*)node
->GetData();
784 if (!m_divisions
.Member(child
))
786 node
= node
->GetNext();
791 // Returns TRUE if division is a descendant of this container
792 bool wxCompositeShape::ContainsDivision(wxDivisionShape
*division
)
794 if (m_divisions
.Member(division
))
796 wxNode
*node
= m_children
.GetFirst();
799 wxShape
*child
= (wxShape
*)node
->GetData();
800 if (child
->IsKindOf(CLASSINFO(wxCompositeShape
)))
802 bool ans
= ((wxCompositeShape
*)child
)->ContainsDivision(division
);
806 node
= node
->GetNext();
816 IMPLEMENT_DYNAMIC_CLASS(wxDivisionShape
, wxCompositeShape
)
818 wxDivisionShape::wxDivisionShape()
820 SetSensitivityFilter(OP_CLICK_LEFT
| OP_CLICK_RIGHT
| OP_DRAG_RIGHT
);
821 SetCentreResize(FALSE
);
822 SetAttachmentMode(TRUE
);
827 m_handleSide
= DIVISION_SIDE_NONE
;
828 m_leftSidePen
= wxBLACK_PEN
;
829 m_topSidePen
= wxBLACK_PEN
;
830 m_leftSideColour
= wxT("BLACK");
831 m_topSideColour
= wxT("BLACK");
832 m_leftSideStyle
= wxT("Solid");
833 m_topSideStyle
= wxT("Solid");
837 wxDivisionShape::~wxDivisionShape()
841 void wxDivisionShape::OnDraw(wxDC
& dc
)
843 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
844 dc
.SetBackgroundMode(wxTRANSPARENT
);
846 double x1
= (double)(GetX() - (GetWidth()/2.0));
847 double y1
= (double)(GetY() - (GetHeight()/2.0));
848 double x2
= (double)(GetX() + (GetWidth()/2.0));
849 double y2
= (double)(GetY() + (GetHeight()/2.0));
851 // Should subtract 1 pixel if drawing under Windows
858 dc
.SetPen(* m_leftSidePen
);
859 dc
.DrawLine(WXROUND(x1
), WXROUND(y2
), WXROUND(x1
), WXROUND(y1
));
863 dc
.SetPen(* m_topSidePen
);
864 dc
.DrawLine(WXROUND(x1
), WXROUND(y1
), WXROUND(x2
), WXROUND(y1
));
867 // For testing purposes, draw a rectangle so we know
868 // how big the division is.
869 // SetBrush(* wxCYAN_BRUSH);
870 // wxRectangleShape::OnDraw(dc);
873 void wxDivisionShape::OnDrawContents(wxDC
& dc
)
875 wxCompositeShape::OnDrawContents(dc
);
878 bool wxDivisionShape::OnMovePre(wxDC
& dc
, double x
, double y
, double oldx
, double oldy
, bool display
)
880 double diffX
= x
- oldx
;
881 double diffY
= y
- oldy
;
882 wxNode
*node
= m_children
.GetFirst();
885 wxShape
*object
= (wxShape
*)node
->GetData();
887 object
->Move(dc
, object
->GetX() + diffX
, object
->GetY() + diffY
, display
);
888 node
= node
->GetNext();
893 void wxDivisionShape::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
895 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
901 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
902 m_parent
->GetEventHandler()->OnDragLeft(draw
, x
, y
, keys
, attachment
);
906 wxShape::OnDragLeft(draw
, x
, y
, keys
, attachment
);
909 void wxDivisionShape::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
911 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
917 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
918 m_parent
->GetEventHandler()->OnBeginDragLeft(x
, y
, keys
, attachment
);
923 wxShape::OnBeginDragLeft(x
, y
, keys
, attachment
);
926 void wxDivisionShape::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
928 m_canvas
->ReleaseMouse();
929 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
935 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
936 m_parent
->GetEventHandler()->OnEndDragLeft(x
, y
, keys
, attachment
);
941 wxClientDC
dc(GetCanvas());
942 GetCanvas()->PrepareDC(dc
);
944 dc
.SetLogicalFunction(wxCOPY
);
946 m_canvas
->Snap(&m_xpos
, &m_ypos
);
947 GetEventHandler()->OnMovePre(dc
, x
, y
, m_oldX
, m_oldY
);
949 ResetControlPoints();
952 GetEventHandler()->OnDrawControlPoints(dc
);
954 if (m_canvas
&& !m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
957 void wxDivisionShape::SetSize(double w
, double h
, bool recursive
)
961 wxRectangleShape::SetSize(w
, h
, recursive
);
964 void wxDivisionShape::CalculateSize()
968 void wxDivisionShape::Copy(wxShape
& copy
)
970 wxCompositeShape::Copy(copy
);
972 wxASSERT( copy
.IsKindOf(CLASSINFO(wxDivisionShape
)) ) ;
974 wxDivisionShape
& divisionCopy
= (wxDivisionShape
&) copy
;
976 divisionCopy
.m_leftSideStyle
= m_leftSideStyle
;
977 divisionCopy
.m_topSideStyle
= m_topSideStyle
;
978 divisionCopy
.m_leftSideColour
= m_leftSideColour
;
979 divisionCopy
.m_topSideColour
= m_topSideColour
;
981 divisionCopy
.m_leftSidePen
= m_leftSidePen
;
982 divisionCopy
.m_topSidePen
= m_topSidePen
;
983 divisionCopy
.m_handleSide
= m_handleSide
;
985 // Division geometry copying is handled at the wxCompositeShape level.
989 void wxDivisionShape::WriteAttributes(wxExpr
*clause
)
991 wxCompositeShape::WriteAttributes(clause
);
994 clause
->AddAttributeValue("left_side", (long)m_leftSide
->GetId());
996 clause
->AddAttributeValue("top_side", (long)m_topSide
->GetId());
998 clause
->AddAttributeValue("right_side", (long)m_rightSide
->GetId());
1000 clause
->AddAttributeValue("bottom_side", (long)m_bottomSide
->GetId());
1002 clause
->AddAttributeValue("handle_side", (long)m_handleSide
);
1003 clause
->AddAttributeValueString("left_colour", m_leftSideColour
);
1004 clause
->AddAttributeValueString("top_colour", m_topSideColour
);
1005 clause
->AddAttributeValueString("left_style", m_leftSideStyle
);
1006 clause
->AddAttributeValueString("top_style", m_topSideStyle
);
1009 void wxDivisionShape::ReadAttributes(wxExpr
*clause
)
1011 wxCompositeShape::ReadAttributes(clause
);
1013 clause
->GetAttributeValue("handle_side", m_handleSide
);
1014 clause
->GetAttributeValue("left_colour", m_leftSideColour
);
1015 clause
->GetAttributeValue("top_colour", m_topSideColour
);
1016 clause
->GetAttributeValue("left_style", m_leftSideStyle
);
1017 clause
->GetAttributeValue("top_style", m_topSideStyle
);
1022 void wxDivisionShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
1024 if (keys
& KEY_CTRL
)
1029 else if (keys & KEY_SHIFT)
1031 if (m_leftSide || m_topSide || m_rightSide || m_bottomSide)
1036 GetParent()->Draw(dc);
1049 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1050 m_parent
->GetEventHandler()->OnRightClick(x
, y
, keys
, attachment
);
1057 // Divide wxHORIZONTALly or wxVERTICALly
1058 bool wxDivisionShape::Divide(int direction
)
1060 // Calculate existing top-left, bottom-right
1061 double x1
= (double)(GetX() - (GetWidth()/2.0));
1062 double y1
= (double)(GetY() - (GetHeight()/2.0));
1063 wxCompositeShape
*compositeParent
= (wxCompositeShape
*)GetParent();
1064 double oldWidth
= GetWidth();
1065 double oldHeight
= GetHeight();
1069 wxClientDC
dc(GetCanvas());
1070 GetCanvas()->PrepareDC(dc
);
1072 if (direction
== wxVERTICAL
)
1074 // Dividing vertically means notionally putting a horizontal line through it.
1075 // Break existing piece into two.
1076 double newXPos1
= GetX();
1077 double newYPos1
= (double)(y1
+ (GetHeight()/4.0));
1078 double newXPos2
= GetX();
1079 double newYPos2
= (double)(y1
+ (3.0*GetHeight()/4.0));
1080 wxDivisionShape
*newDivision
= compositeParent
->OnCreateDivision();
1081 newDivision
->Show(TRUE
);
1085 // Anything adjoining the bottom of this division now adjoins the
1086 // bottom of the new division.
1087 wxNode
*node
= compositeParent
->GetDivisions().GetFirst();
1090 wxDivisionShape
*obj
= (wxDivisionShape
*)node
->GetData();
1091 if (obj
->GetTopSide() == this)
1092 obj
->SetTopSide(newDivision
);
1093 node
= node
->GetNext();
1095 newDivision
->SetTopSide(this);
1096 newDivision
->SetBottomSide(m_bottomSide
);
1097 newDivision
->SetLeftSide(m_leftSide
);
1098 newDivision
->SetRightSide(m_rightSide
);
1099 m_bottomSide
= newDivision
;
1101 compositeParent
->GetDivisions().Append(newDivision
);
1103 // CHANGE: Need to insert this division at start of divisions in the object
1104 // list, because e.g.:
1106 // 2) Add contained object
1108 // Division is now receiving mouse events _before_ the contained object,
1109 // because it was added last (on top of all others)
1111 // Add after the image that visualizes the container
1112 compositeParent
->AddChild(newDivision
, compositeParent
->FindContainerImage());
1114 m_handleSide
= DIVISION_SIDE_BOTTOM
;
1115 newDivision
->SetHandleSide(DIVISION_SIDE_TOP
);
1117 SetSize(oldWidth
, (double)(oldHeight
/2.0));
1118 Move(dc
, newXPos1
, newYPos1
);
1120 newDivision
->SetSize(oldWidth
, (double)(oldHeight
/2.0));
1121 newDivision
->Move(dc
, newXPos2
, newYPos2
);
1125 // Dividing horizontally means notionally putting a vertical line through it.
1126 // Break existing piece into two.
1127 double newXPos1
= (double)(x1
+ (GetWidth()/4.0));
1128 double newYPos1
= GetY();
1129 double newXPos2
= (double)(x1
+ (3.0*GetWidth()/4.0));
1130 double newYPos2
= GetY();
1131 wxDivisionShape
*newDivision
= compositeParent
->OnCreateDivision();
1132 newDivision
->Show(TRUE
);
1136 // Anything adjoining the left of this division now adjoins the
1137 // left of the new division.
1138 wxNode
*node
= compositeParent
->GetDivisions().GetFirst();
1141 wxDivisionShape
*obj
= (wxDivisionShape
*)node
->GetData();
1142 if (obj
->GetLeftSide() == this)
1143 obj
->SetLeftSide(newDivision
);
1144 node
= node
->GetNext();
1146 newDivision
->SetTopSide(m_topSide
);
1147 newDivision
->SetBottomSide(m_bottomSide
);
1148 newDivision
->SetLeftSide(this);
1149 newDivision
->SetRightSide(m_rightSide
);
1150 m_rightSide
= newDivision
;
1152 compositeParent
->GetDivisions().Append(newDivision
);
1153 compositeParent
->AddChild(newDivision
, compositeParent
->FindContainerImage());
1155 m_handleSide
= DIVISION_SIDE_RIGHT
;
1156 newDivision
->SetHandleSide(DIVISION_SIDE_LEFT
);
1158 SetSize((double)(oldWidth
/2.0), oldHeight
);
1159 Move(dc
, newXPos1
, newYPos1
);
1161 newDivision
->SetSize((double)(oldWidth
/2.0), oldHeight
);
1162 newDivision
->Move(dc
, newXPos2
, newYPos2
);
1164 if (compositeParent
->Selected())
1166 compositeParent
->DeleteControlPoints(& dc
);
1167 compositeParent
->MakeControlPoints();
1168 compositeParent
->MakeMandatoryControlPoints();
1170 compositeParent
->Draw(dc
);
1174 // Make one control point for every visible line
1175 void wxDivisionShape::MakeControlPoints()
1177 MakeMandatoryControlPoints();
1180 void wxDivisionShape::MakeMandatoryControlPoints()
1184 GetBoundingBoxMax(&maxX
, &maxY
);
1190 x = (double)(-maxX/2.0);
1192 wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y,
1193 CONTROL_POINT_HORIZONTAL);
1194 m_canvas->AddShape(control);
1195 m_controlPoints.Append(control);
1200 y = (double)(-maxY/2.0);
1201 wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y,
1202 CONTROL_POINT_VERTICAL);
1203 m_canvas->AddShape(control);
1204 m_controlPoints.Append(control);
1207 switch (m_handleSide
)
1209 case DIVISION_SIDE_LEFT
:
1211 x
= (double)(-maxX
/2.0);
1213 direction
= CONTROL_POINT_HORIZONTAL
;
1216 case DIVISION_SIDE_TOP
:
1219 y
= (double)(-maxY
/2.0);
1220 direction
= CONTROL_POINT_VERTICAL
;
1223 case DIVISION_SIDE_RIGHT
:
1225 x
= (double)(maxX
/2.0);
1227 direction
= CONTROL_POINT_HORIZONTAL
;
1230 case DIVISION_SIDE_BOTTOM
:
1233 y
= (double)(maxY
/2.0);
1234 direction
= CONTROL_POINT_VERTICAL
;
1240 if (m_handleSide
!= DIVISION_SIDE_NONE
)
1242 wxDivisionControlPoint
*control
= new wxDivisionControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, x
, y
,
1244 m_canvas
->AddShape(control
);
1245 m_controlPoints
.Append(control
);
1249 void wxDivisionShape::ResetControlPoints()
1251 ResetMandatoryControlPoints();
1254 void wxDivisionShape::ResetMandatoryControlPoints()
1256 if (m_controlPoints
.GetCount() < 1)
1261 GetBoundingBoxMax(&maxX
, &maxY
);
1263 wxNode *node = m_controlPoints.GetFirst();
1266 wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->GetData();
1267 if (control->type == CONTROL_POINT_HORIZONTAL)
1269 control->xoffset = (double)(-maxX/2.0); control->m_yoffset = 0.0;
1271 else if (control->type == CONTROL_POINT_VERTICAL)
1273 control->xoffset = 0.0; control->m_yoffset = (double)(-maxY/2.0);
1275 node = node->GetNext();
1278 wxNode
*node
= m_controlPoints
.GetFirst();
1279 if ((m_handleSide
== DIVISION_SIDE_LEFT
) && node
)
1281 wxDivisionControlPoint
*control
= (wxDivisionControlPoint
*)node
->GetData();
1282 control
->m_xoffset
= (double)(-maxX
/2.0); control
->m_yoffset
= 0.0;
1285 if ((m_handleSide
== DIVISION_SIDE_TOP
) && node
)
1287 wxDivisionControlPoint
*control
= (wxDivisionControlPoint
*)node
->GetData();
1288 control
->m_xoffset
= 0.0; control
->m_yoffset
= (double)(-maxY
/2.0);
1291 if ((m_handleSide
== DIVISION_SIDE_RIGHT
) && node
)
1293 wxDivisionControlPoint
*control
= (wxDivisionControlPoint
*)node
->GetData();
1294 control
->m_xoffset
= (double)(maxX
/2.0); control
->m_yoffset
= 0.0;
1297 if ((m_handleSide
== DIVISION_SIDE_BOTTOM
) && node
)
1299 wxDivisionControlPoint
*control
= (wxDivisionControlPoint
*)node
->GetData();
1300 control
->m_xoffset
= 0.0; control
->m_yoffset
= (double)(maxY
/2.0);
1304 // Adjust a side, returning FALSE if it's not physically possible.
1305 bool wxDivisionShape::AdjustLeft(double left
, bool test
)
1307 double x2
= (double)(GetX() + (GetWidth()/2.0));
1314 double newW
= x2
- left
;
1315 double newX
= (double)(left
+ newW
/2.0);
1316 SetSize(newW
, GetHeight());
1318 wxClientDC
dc(GetCanvas());
1319 GetCanvas()->PrepareDC(dc
);
1321 Move(dc
, newX
, GetY());
1326 bool wxDivisionShape::AdjustTop(double top
, bool test
)
1328 double y2
= (double)(GetY() + (GetHeight()/2.0));
1335 double newH
= y2
- top
;
1336 double newY
= (double)(top
+ newH
/2.0);
1337 SetSize(GetWidth(), newH
);
1339 wxClientDC
dc(GetCanvas());
1340 GetCanvas()->PrepareDC(dc
);
1342 Move(dc
, GetX(), newY
);
1347 bool wxDivisionShape::AdjustRight(double right
, bool test
)
1349 double x1
= (double)(GetX() - (GetWidth()/2.0));
1356 double newW
= right
- x1
;
1357 double newX
= (double)(x1
+ newW
/2.0);
1358 SetSize(newW
, GetHeight());
1360 wxClientDC
dc(GetCanvas());
1361 GetCanvas()->PrepareDC(dc
);
1363 Move(dc
, newX
, GetY());
1368 bool wxDivisionShape::AdjustBottom(double bottom
, bool test
)
1370 double y1
= (double)(GetY() - (GetHeight()/2.0));
1377 double newH
= bottom
- y1
;
1378 double newY
= (double)(y1
+ newH
/2.0);
1379 SetSize(GetWidth(), newH
);
1381 wxClientDC
dc(GetCanvas());
1382 GetCanvas()->PrepareDC(dc
);
1384 Move(dc
, GetX(), newY
);
1389 wxDivisionControlPoint::wxDivisionControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
, double size
, double the_xoffset
, double the_yoffset
, int the_type
):
1390 wxControlPoint(the_canvas
, object
, size
, the_xoffset
, the_yoffset
, the_type
)
1392 SetEraseObject(FALSE
);
1395 wxDivisionControlPoint::~wxDivisionControlPoint()
1399 static double originalX
= 0.0;
1400 static double originalY
= 0.0;
1401 static double originalW
= 0.0;
1402 static double originalH
= 0.0;
1404 // Implement resizing of canvas object
1405 void wxDivisionControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1407 wxControlPoint::OnDragLeft(draw
, x
, y
, keys
, attachment
);
1410 void wxDivisionControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1412 wxDivisionShape
*division
= (wxDivisionShape
*)m_shape
;
1413 originalX
= division
->GetX();
1414 originalY
= division
->GetY();
1415 originalW
= division
->GetWidth();
1416 originalH
= division
->GetHeight();
1418 wxControlPoint::OnBeginDragLeft(x
, y
, keys
, attachment
);
1421 void wxDivisionControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1423 wxControlPoint::OnEndDragLeft(x
, y
, keys
, attachment
);
1425 wxClientDC
dc(GetCanvas());
1426 GetCanvas()->PrepareDC(dc
);
1428 wxDivisionShape
*division
= (wxDivisionShape
*)m_shape
;
1429 wxCompositeShape
*divisionParent
= (wxCompositeShape
*)division
->GetParent();
1431 // Need to check it's within the bounds of the parent composite.
1432 double x1
= (double)(divisionParent
->GetX() - (divisionParent
->GetWidth()/2.0));
1433 double y1
= (double)(divisionParent
->GetY() - (divisionParent
->GetHeight()/2.0));
1434 double x2
= (double)(divisionParent
->GetX() + (divisionParent
->GetWidth()/2.0));
1435 double y2
= (double)(divisionParent
->GetY() + (divisionParent
->GetHeight()/2.0));
1437 // Need to check it has not made the division zero or negative width/height
1438 double dx1
= (double)(division
->GetX() - (division
->GetWidth()/2.0));
1439 double dy1
= (double)(division
->GetY() - (division
->GetHeight()/2.0));
1440 double dx2
= (double)(division
->GetX() + (division
->GetWidth()/2.0));
1441 double dy2
= (double)(division
->GetY() + (division
->GetHeight()/2.0));
1443 bool success
= TRUE
;
1444 switch (division
->GetHandleSide())
1446 case DIVISION_SIDE_LEFT
:
1448 if ((x
<= x1
) || (x
>= x2
) || (x
>= dx2
))
1450 // Try it out first...
1451 else if (!division
->ResizeAdjoining(DIVISION_SIDE_LEFT
, x
, TRUE
))
1454 division
->ResizeAdjoining(DIVISION_SIDE_LEFT
, x
, FALSE
);
1458 case DIVISION_SIDE_TOP
:
1460 if ((y
<= y1
) || (y
>= y2
) || (y
>= dy2
))
1462 else if (!division
->ResizeAdjoining(DIVISION_SIDE_TOP
, y
, TRUE
))
1465 division
->ResizeAdjoining(DIVISION_SIDE_TOP
, y
, FALSE
);
1469 case DIVISION_SIDE_RIGHT
:
1471 if ((x
<= x1
) || (x
>= x2
) || (x
<= dx1
))
1473 else if (!division
->ResizeAdjoining(DIVISION_SIDE_RIGHT
, x
, TRUE
))
1476 division
->ResizeAdjoining(DIVISION_SIDE_RIGHT
, x
, FALSE
);
1480 case DIVISION_SIDE_BOTTOM
:
1482 if ((y
<= y1
) || (y
>= y2
) || (y
<= dy1
))
1484 else if (!division
->ResizeAdjoining(DIVISION_SIDE_BOTTOM
, y
, TRUE
))
1487 division
->ResizeAdjoining(DIVISION_SIDE_BOTTOM
, y
, FALSE
);
1494 division
->SetSize(originalW
, originalH
);
1495 division
->Move(dc
, originalX
, originalY
);
1497 divisionParent
->Draw(dc
);
1498 division
->GetEventHandler()->OnDrawControlPoints(dc
);
1501 /* Resize adjoining divisions.
1503 Behaviour should be as follows:
1504 If right edge moves, find all objects whose left edge
1505 adjoins this object, and move left edge accordingly.
1506 If left..., move ... right.
1507 If top..., move ... bottom.
1508 If bottom..., move top.
1509 If size goes to zero or end position is other side of start position,
1510 resize to original size and return.
1512 bool wxDivisionShape::ResizeAdjoining(int side
, double newPos
, bool test
)
1514 wxCompositeShape
*divisionParent
= (wxCompositeShape
*)GetParent();
1515 wxNode
*node
= divisionParent
->GetDivisions().GetFirst();
1518 wxDivisionShape
*division
= (wxDivisionShape
*)node
->GetData();
1521 case DIVISION_SIDE_LEFT
:
1523 if (division
->m_rightSide
== this)
1525 bool success
= division
->AdjustRight(newPos
, test
);
1526 if (!success
&& test
)
1531 case DIVISION_SIDE_TOP
:
1533 if (division
->m_bottomSide
== this)
1535 bool success
= division
->AdjustBottom(newPos
, test
);
1536 if (!success
&& test
)
1541 case DIVISION_SIDE_RIGHT
:
1543 if (division
->m_leftSide
== this)
1545 bool success
= division
->AdjustLeft(newPos
, test
);
1546 if (!success
&& test
)
1551 case DIVISION_SIDE_BOTTOM
:
1553 if (division
->m_topSide
== this)
1555 bool success
= division
->AdjustTop(newPos
, test
);
1556 if (!success
&& test
)
1564 node
= node
->GetNext();
1571 * Popup menu for editing divisions
1574 class OGLPopupDivisionMenu
: public wxMenu
{
1576 OGLPopupDivisionMenu() : wxMenu() {
1577 Append(DIVISION_MENU_SPLIT_HORIZONTALLY
, wxT("Split horizontally"));
1578 Append(DIVISION_MENU_SPLIT_VERTICALLY
, wxT("Split vertically"));
1580 Append(DIVISION_MENU_EDIT_LEFT_EDGE
, wxT("Edit left edge"));
1581 Append(DIVISION_MENU_EDIT_TOP_EDGE
, wxT("Edit top edge"));
1584 void OnMenu(wxCommandEvent
& event
);
1586 DECLARE_EVENT_TABLE()
1589 BEGIN_EVENT_TABLE(OGLPopupDivisionMenu
, wxMenu
)
1590 EVT_CUSTOM_RANGE(wxEVT_COMMAND_MENU_SELECTED
,
1591 DIVISION_MENU_SPLIT_HORIZONTALLY
,
1592 DIVISION_MENU_EDIT_BOTTOM_EDGE
,
1593 OGLPopupDivisionMenu::OnMenu
)
1597 void OGLPopupDivisionMenu::OnMenu(wxCommandEvent
& event
)
1599 wxDivisionShape
*division
= (wxDivisionShape
*)GetClientData();
1600 switch (event
.GetInt())
1602 case DIVISION_MENU_SPLIT_HORIZONTALLY
:
1604 division
->Divide(wxHORIZONTAL
);
1607 case DIVISION_MENU_SPLIT_VERTICALLY
:
1609 division
->Divide(wxVERTICAL
);
1612 case DIVISION_MENU_EDIT_LEFT_EDGE
:
1614 division
->EditEdge(DIVISION_SIDE_LEFT
);
1617 case DIVISION_MENU_EDIT_TOP_EDGE
:
1619 division
->EditEdge(DIVISION_SIDE_TOP
);
1627 void wxDivisionShape::EditEdge(int side
)
1629 wxMessageBox(wxT("EditEdge() not implemented"), wxT("OGL"), wxOK
);
1632 wxBeginBusyCursor();
1634 wxPen
*currentPen
= NULL
;
1635 char **pColour
= NULL
;
1636 char **pStyle
= NULL
;
1637 if (side
== DIVISION_SIDE_LEFT
)
1639 currentPen
= m_leftSidePen
;
1640 pColour
= &m_leftSideColour
;
1641 pStyle
= &m_leftSideStyle
;
1645 currentPen
= m_topSidePen
;
1646 pColour
= &m_topSideColour
;
1647 pStyle
= &m_topSideStyle
;
1650 GraphicsForm
*form
= new GraphicsForm("Containers");
1651 int lineWidth
= currentPen
->GetWidth();
1653 form
->Add(wxMakeFormShort("Width", &lineWidth
, wxFORM_DEFAULT
, NULL
, NULL
, wxVERTICAL
,
1655 form
->Add(wxMakeFormString("Colour", pColour
, wxFORM_CHOICE
,
1656 new wxList(wxMakeConstraintStrings(
1680 NULL
), NULL
, wxVERTICAL
, 150));
1681 form
->Add(wxMakeFormString("Style", pStyle
, wxFORM_CHOICE
,
1682 new wxList(wxMakeConstraintStrings(
1689 NULL
), NULL
, wxVERTICAL
, 100));
1691 wxDialogBox
*dialog
= new wxDialogBox(m_canvas
->GetParent(), "Division properties", 10, 10, 500, 500);
1692 if (GraphicsLabelFont
)
1693 dialog
->SetLabelFont(GraphicsLabelFont
);
1694 if (GraphicsButtonFont
)
1695 dialog
->SetButtonFont(GraphicsButtonFont
);
1697 form
->AssociatePanel(dialog
);
1698 form
->dialog
= dialog
;
1701 dialog
->Centre(wxBOTH
);
1706 int lineStyle
= wxSOLID
;
1709 if (strcmp(*pStyle
, "Solid") == 0)
1710 lineStyle
= wxSOLID
;
1711 else if (strcmp(*pStyle
, "Dot") == 0)
1713 else if (strcmp(*pStyle
, "Short Dash") == 0)
1714 lineStyle
= wxSHORT_DASH
;
1715 else if (strcmp(*pStyle
, "Long Dash") == 0)
1716 lineStyle
= wxLONG_DASH
;
1717 else if (strcmp(*pStyle
, "Dot Dash") == 0)
1718 lineStyle
= wxDOT_DASH
;
1721 wxPen
*newPen
= wxThePenList
->FindOrCreatePen(*pColour
, lineWidth
, lineStyle
);
1724 if (side
== DIVISION_SIDE_LEFT
)
1725 m_leftSidePen
= newPen
;
1727 m_topSidePen
= newPen
;
1729 // Need to draw whole image again
1730 wxCompositeShape
*compositeParent
= (wxCompositeShape
*)GetParent();
1731 compositeParent
->Draw(dc
);
1736 void wxDivisionShape::PopupMenu(double x
, double y
)
1738 wxMenu
* oglPopupDivisionMenu
= new OGLPopupDivisionMenu
;
1740 oglPopupDivisionMenu
->SetClientData((void *)this);
1742 oglPopupDivisionMenu
->Enable(DIVISION_MENU_EDIT_LEFT_EDGE
, TRUE
);
1744 oglPopupDivisionMenu
->Enable(DIVISION_MENU_EDIT_LEFT_EDGE
, FALSE
);
1746 oglPopupDivisionMenu
->Enable(DIVISION_MENU_EDIT_TOP_EDGE
, TRUE
);
1748 oglPopupDivisionMenu
->Enable(DIVISION_MENU_EDIT_TOP_EDGE
, FALSE
);
1751 m_canvas
->GetViewStart(&x1
, &y1
);
1754 m_canvas
->GetScrollPixelsPerUnit(&unit_x
, &unit_y
);
1756 wxClientDC
dc(GetCanvas());
1757 GetCanvas()->PrepareDC(dc
);
1759 int mouse_x
= (int)(dc
.LogicalToDeviceX((long)(x
- x1
*unit_x
)));
1760 int mouse_y
= (int)(dc
.LogicalToDeviceY((long)(y
- y1
*unit_y
)));
1762 m_canvas
->PopupMenu(oglPopupDivisionMenu
, mouse_x
, mouse_y
);
1763 delete oglPopupDivisionMenu
;
1766 void wxDivisionShape::SetLeftSideColour(const wxString
& colour
)
1768 m_leftSideColour
= colour
;
1771 void wxDivisionShape::SetTopSideColour(const wxString
& colour
)
1773 m_topSideColour
= colour
;
1776 void wxDivisionShape::SetLeftSideStyle(const wxString
& style
)
1778 m_leftSideStyle
= style
;
1781 void wxDivisionShape::SetTopSideStyle(const wxString
& style
)
1783 m_topSideStyle
= style
;