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"
28 #include <wx/deprecated/wxexpr.h>
31 #include "wx/ogl/ogl.h"
35 // Sometimes, objects need to access the whole database to
36 // construct themselves.
37 wxExprDatabase
*GlobalwxExprDatabase
= NULL
;
41 * Division control point
44 class wxDivisionControlPoint
: public wxControlPoint
46 DECLARE_DYNAMIC_CLASS(wxDivisionControlPoint
)
48 wxDivisionControlPoint() {}
49 wxDivisionControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
, double size
, double the_xoffset
, double the_yoffset
, int the_type
);
50 ~wxDivisionControlPoint();
52 void OnDragLeft(bool draw
, double x
, double y
, int keys
=0, int attachment
= 0);
53 void OnBeginDragLeft(double x
, double y
, int keys
=0, int attachment
= 0);
54 void OnEndDragLeft(double x
, double y
, int keys
=0, int attachment
= 0);
57 IMPLEMENT_DYNAMIC_CLASS(wxDivisionControlPoint
, wxControlPoint
)
64 IMPLEMENT_DYNAMIC_CLASS(wxCompositeShape
, wxRectangleShape
)
66 wxCompositeShape::wxCompositeShape(): wxRectangleShape(10.0, 10.0)
68 // selectable = false;
73 wxCompositeShape::~wxCompositeShape()
75 wxNode
*node
= m_constraints
.GetFirst();
78 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->GetData();
80 node
= node
->GetNext();
82 node
= m_children
.GetFirst();
85 wxShape
*object
= (wxShape
*)node
->GetData();
86 wxNode
*next
= node
->GetNext();
93 void wxCompositeShape::OnDraw(wxDC
& dc
)
95 double x1
= (double)(m_xpos
- m_width
/2.0);
96 double y1
= (double)(m_ypos
- m_height
/2.0);
98 if (m_shadowMode
!= SHADOW_NONE
)
101 dc
.SetBrush(* m_shadowBrush
);
102 dc
.SetPen(* g_oglTransparentPen
);
104 if (m_cornerRadius
!= 0.0)
105 dc
.DrawRoundedRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
),
106 WXROUND(m_width
), WXROUND(m_height
), m_cornerRadius
);
108 dc
.DrawRectangle(WXROUND(x1
+ m_shadowOffsetX
), WXROUND(y1
+ m_shadowOffsetY
), WXROUND(m_width
), WXROUND(m_height
));
112 void wxCompositeShape::OnDrawContents(wxDC
& dc
)
114 wxNode
*node
= m_children
.GetFirst();
117 wxShape
*object
= (wxShape
*)node
->GetData();
119 object
->DrawLinks(dc
);
120 node
= node
->GetNext();
122 wxShape::OnDrawContents(dc
);
125 bool wxCompositeShape::OnMovePre(wxDC
& dc
, double x
, double y
, double oldx
, double oldy
, bool display
)
127 double diffX
= x
- oldx
;
128 double diffY
= y
- oldy
;
129 wxNode
*node
= m_children
.GetFirst();
132 wxShape
*object
= (wxShape
*)node
->GetData();
135 object
->Move(dc
, object
->GetX() + diffX
, object
->GetY() + diffY
, display
);
137 node
= node
->GetNext();
142 void wxCompositeShape::OnErase(wxDC
& dc
)
144 wxRectangleShape::OnErase(dc
);
145 wxNode
*node
= m_children
.GetFirst();
148 wxShape
*object
= (wxShape
*)node
->GetData();
150 node
= node
->GetNext();
154 static double objectStartX
= 0.0;
155 static double objectStartY
= 0.0;
157 void wxCompositeShape::OnDragLeft(bool WXUNUSED(draw
), double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
161 m_canvas
->Snap(&xx
, &yy
);
162 double offsetX
= xx
- objectStartX
;
163 double offsetY
= yy
- objectStartY
;
165 wxClientDC
dc(GetCanvas());
166 GetCanvas()->PrepareDC(dc
);
168 dc
.SetLogicalFunction(OGLRBLF
);
169 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
170 dc
.SetPen(dottedPen
);
171 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
173 GetEventHandler()->OnDrawOutline(dc
, GetX() + offsetX
, GetY() + offsetY
, GetWidth(), GetHeight());
174 // wxShape::OnDragLeft(draw, x, y, keys, attachment);
177 void wxCompositeShape::OnBeginDragLeft(double x
, double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
182 wxClientDC
dc(GetCanvas());
183 GetCanvas()->PrepareDC(dc
);
187 dc
.SetLogicalFunction(OGLRBLF
);
189 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
190 dc
.SetPen(dottedPen
);
191 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
192 m_canvas
->CaptureMouse();
196 m_canvas
->Snap(&xx
, &yy
);
197 double offsetX
= xx
- objectStartX
;
198 double offsetY
= yy
- objectStartY
;
200 GetEventHandler()->OnDrawOutline(dc
, GetX() + offsetX
, GetY() + offsetY
, GetWidth(), GetHeight());
202 // wxShape::OnBeginDragLeft(x, y, keys, attachment);
205 void wxCompositeShape::OnEndDragLeft(double x
, double y
, int keys
, int WXUNUSED(attachment
))
207 // wxShape::OnEndDragLeft(x, y, keys, attachment);
209 wxClientDC
dc(GetCanvas());
210 GetCanvas()->PrepareDC(dc
);
212 m_canvas
->ReleaseMouse();
216 if (m_parent
) m_parent
->GetEventHandler()->OnEndDragLeft(x
, y
, keys
, 0);
220 dc
.SetLogicalFunction(wxCOPY
);
223 m_canvas
->Snap(&xx
, &yy
);
224 double offsetX
= xx
- objectStartX
;
225 double offsetY
= yy
- objectStartY
;
227 Move(dc
, GetX() + offsetX
, GetY() + offsetY
);
229 if (m_canvas
&& !m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
232 void wxCompositeShape::OnRightClick(double x
, double y
, int keys
, int WXUNUSED(attachment
))
234 // If we get a ctrl-right click, this means send the message to
235 // the division, so we can invoke a user interface for dealing with regions.
238 wxNode
*node
= m_divisions
.GetFirst();
241 wxDivisionShape
*division
= (wxDivisionShape
*)node
->GetData();
242 wxNode
*next
= node
->GetNext();
245 if (division
->HitTest(x
, y
, &attach
, &dist
))
247 division
->GetEventHandler()->OnRightClick(x
, y
, keys
, attach
);
256 void wxCompositeShape::SetSize(double w
, double h
, bool recursive
)
258 SetAttachmentSize(w
, h
);
260 double xScale
= (double)(w
/(wxMax(1.0, GetWidth())));
261 double yScale
= (double)(h
/(wxMax(1.0, GetHeight())));
266 if (!recursive
) return;
268 wxNode
*node
= m_children
.GetFirst();
270 wxClientDC
dc(GetCanvas());
271 GetCanvas()->PrepareDC(dc
);
273 double xBound
, yBound
;
276 wxShape
*object
= (wxShape
*)node
->GetData();
278 // Scale the position first
279 double newX
= (double)(((object
->GetX() - GetX())*xScale
) + GetX());
280 double newY
= (double)(((object
->GetY() - GetY())*yScale
) + GetY());
282 object
->Move(dc
, newX
, newY
);
285 // Now set the scaled size
286 object
->GetBoundingBoxMin(&xBound
, &yBound
);
287 object
->SetSize(object
->GetFixedWidth() ? xBound
: xScale
*xBound
,
288 object
->GetFixedHeight() ? yBound
: yScale
*yBound
);
290 node
= node
->GetNext();
292 SetDefaultRegionSize();
295 void wxCompositeShape::AddChild(wxShape
*child
, wxShape
*addAfter
)
297 m_children
.Append(child
);
298 child
->SetParent(this);
301 // Ensure we add at the right position
303 child
->RemoveFromCanvas(m_canvas
);
304 child
->AddToCanvas(m_canvas
, addAfter
);
308 void wxCompositeShape::RemoveChild(wxShape
*child
)
310 m_children
.DeleteObject(child
);
311 m_divisions
.DeleteObject(child
);
312 RemoveChildFromConstraints(child
);
313 child
->SetParent(NULL
);
316 void wxCompositeShape::DeleteConstraintsInvolvingChild(wxShape
*child
)
318 wxNode
*node
= m_constraints
.GetFirst();
321 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->GetData();
322 wxNode
*nextNode
= node
->GetNext();
324 if ((constraint
->m_constrainingObject
== child
) ||
325 constraint
->m_constrainedObjects
.Member(child
))
334 void wxCompositeShape::RemoveChildFromConstraints(wxShape
*child
)
336 wxNode
*node
= m_constraints
.GetFirst();
339 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->GetData();
340 wxNode
*nextNode
= node
->GetNext();
342 if (constraint
->m_constrainedObjects
.Member(child
))
343 constraint
->m_constrainedObjects
.DeleteObject(child
);
344 if (constraint
->m_constrainingObject
== child
)
345 constraint
->m_constrainingObject
= NULL
;
347 // Delete the constraint if no participants left
348 if (!constraint
->m_constrainingObject
)
358 void wxCompositeShape::Copy(wxShape
& copy
)
360 wxRectangleShape::Copy(copy
);
362 wxASSERT( copy
.IsKindOf(CLASSINFO(wxCompositeShape
)) ) ;
364 wxCompositeShape
& compositeCopy
= (wxCompositeShape
&) copy
;
366 // Associate old and new copies for compositeCopying constraints and division geometry
367 oglObjectCopyMapping
.Append((long)this, &compositeCopy
);
370 wxNode
*node
= m_children
.GetFirst();
373 wxShape
*object
= (wxShape
*)node
->GetData();
374 wxShape
*newObject
= object
->CreateNewCopy(false, false);
375 if (newObject
->GetId() == 0)
376 newObject
->SetId(wxNewId());
378 newObject
->SetParent(&compositeCopy
);
379 compositeCopy
.m_children
.Append(newObject
);
381 // Some m_children may be divisions
382 if (m_divisions
.Member(object
))
383 compositeCopy
.m_divisions
.Append(newObject
);
385 oglObjectCopyMapping
.Append((long)object
, newObject
);
387 node
= node
->GetNext();
390 // Copy the constraints
391 node
= m_constraints
.GetFirst();
394 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->GetData();
396 wxShape
*newConstraining
= (wxShape
*)(oglObjectCopyMapping
.Find((long)constraint
->m_constrainingObject
)->GetData());
398 wxList newConstrainedList
;
399 wxNode
*node2
= constraint
->m_constrainedObjects
.GetFirst();
402 wxShape
*constrainedObject
= (wxShape
*)node2
->GetData();
403 wxShape
*newConstrained
= (wxShape
*)(oglObjectCopyMapping
.Find((long)constrainedObject
)->GetData());
404 newConstrainedList
.Append(newConstrained
);
405 node2
= node2
->GetNext();
408 wxOGLConstraint
*newConstraint
= new wxOGLConstraint(constraint
->m_constraintType
, newConstraining
,
410 newConstraint
->m_constraintId
= constraint
->m_constraintId
;
411 if (constraint
->m_constraintName
)
413 newConstraint
->m_constraintName
= constraint
->m_constraintName
;
415 newConstraint
->SetSpacing(constraint
->m_xSpacing
, constraint
->m_ySpacing
);
416 compositeCopy
.m_constraints
.Append(newConstraint
);
418 node
= node
->GetNext();
421 // Now compositeCopy the division geometry
422 node
= m_divisions
.GetFirst();
425 wxDivisionShape
*division
= (wxDivisionShape
*)node
->GetData();
426 wxNode
*node1
= oglObjectCopyMapping
.Find((long)division
);
427 wxNode
*leftNode
= NULL
;
428 wxNode
*topNode
= NULL
;
429 wxNode
*rightNode
= NULL
;
430 wxNode
*bottomNode
= NULL
;
431 if (division
->GetLeftSide())
432 leftNode
= oglObjectCopyMapping
.Find((long)division
->GetLeftSide());
433 if (division
->GetTopSide())
434 topNode
= oglObjectCopyMapping
.Find((long)division
->GetTopSide());
435 if (division
->GetRightSide())
436 rightNode
= oglObjectCopyMapping
.Find((long)division
->GetRightSide());
437 if (division
->GetBottomSide())
438 bottomNode
= oglObjectCopyMapping
.Find((long)division
->GetBottomSide());
441 wxDivisionShape
*newDivision
= (wxDivisionShape
*)node1
->GetData();
443 newDivision
->SetLeftSide((wxDivisionShape
*)leftNode
->GetData());
445 newDivision
->SetTopSide((wxDivisionShape
*)topNode
->GetData());
447 newDivision
->SetRightSide((wxDivisionShape
*)rightNode
->GetData());
449 newDivision
->SetBottomSide((wxDivisionShape
*)bottomNode
->GetData());
451 node
= node
->GetNext();
455 wxOGLConstraint
*wxCompositeShape::AddConstraint(wxOGLConstraint
*constraint
)
457 m_constraints
.Append(constraint
);
458 if (constraint
->m_constraintId
== 0)
459 constraint
->m_constraintId
= wxNewId();
463 wxOGLConstraint
*wxCompositeShape::AddConstraint(int type
, wxShape
*constraining
, wxList
& constrained
)
465 wxOGLConstraint
*constraint
= new wxOGLConstraint(type
, constraining
, constrained
);
466 if (constraint
->m_constraintId
== 0)
467 constraint
->m_constraintId
= wxNewId();
468 m_constraints
.Append(constraint
);
472 wxOGLConstraint
*wxCompositeShape::AddConstraint(int type
, wxShape
*constraining
, wxShape
*constrained
)
475 l
.Append(constrained
);
476 wxOGLConstraint
*constraint
= new wxOGLConstraint(type
, constraining
, l
);
477 if (constraint
->m_constraintId
== 0)
478 constraint
->m_constraintId
= wxNewId();
479 m_constraints
.Append(constraint
);
483 wxOGLConstraint
*wxCompositeShape::FindConstraint(long cId
, wxCompositeShape
**actualComposite
)
485 wxNode
*node
= m_constraints
.GetFirst();
488 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->GetData();
489 if (constraint
->m_constraintId
== cId
)
492 *actualComposite
= this;
495 node
= node
->GetNext();
497 // If not found, try children.
498 node
= m_children
.GetFirst();
501 wxShape
*child
= (wxShape
*)node
->GetData();
502 if (child
->IsKindOf(CLASSINFO(wxCompositeShape
)))
504 wxOGLConstraint
*constraint
= ((wxCompositeShape
*)child
)->FindConstraint(cId
, actualComposite
);
508 *actualComposite
= (wxCompositeShape
*)child
;
512 node
= node
->GetNext();
517 void wxCompositeShape::DeleteConstraint(wxOGLConstraint
*constraint
)
519 m_constraints
.DeleteObject(constraint
);
523 void wxCompositeShape::CalculateSize()
525 double maxX
= (double) -999999.9;
526 double maxY
= (double) -999999.9;
527 double minX
= (double) 999999.9;
528 double minY
= (double) 999999.9;
531 wxNode
*node
= m_children
.GetFirst();
534 wxShape
*object
= (wxShape
*)node
->GetData();
536 // Recalculate size of composite objects because may not conform
537 // to size it was set to - depends on the children.
538 object
->CalculateSize();
540 object
->GetBoundingBoxMax(&w
, &h
);
541 if ((object
->GetX() + (w
/2.0)) > maxX
)
542 maxX
= (double)(object
->GetX() + (w
/2.0));
543 if ((object
->GetX() - (w
/2.0)) < minX
)
544 minX
= (double)(object
->GetX() - (w
/2.0));
545 if ((object
->GetY() + (h
/2.0)) > maxY
)
546 maxY
= (double)(object
->GetY() + (h
/2.0));
547 if ((object
->GetY() - (h
/2.0)) < minY
)
548 minY
= (double)(object
->GetY() - (h
/2.0));
550 node
= node
->GetNext();
552 m_width
= maxX
- minX
;
553 m_height
= maxY
- minY
;
554 m_xpos
= (double)(m_width
/2.0 + minX
);
555 m_ypos
= (double)(m_height
/2.0 + minY
);
558 bool wxCompositeShape::Recompute()
560 int noIterations
= 0;
562 while (changed
&& (noIterations
< 500))
564 changed
= Constrain();
570 cerr << "Warning: constraint algorithm failed after 500 iterations.\n";
576 bool wxCompositeShape::Constrain()
580 bool changed
= false;
581 wxNode
*node
= m_children
.GetFirst();
584 wxShape
*object
= (wxShape
*)node
->GetData();
585 if (object
->Constrain())
587 node
= node
->GetNext();
590 node
= m_constraints
.GetFirst();
593 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->GetData();
594 if (constraint
->Evaluate()) changed
= true;
595 node
= node
->GetNext();
601 void wxCompositeShape::WriteAttributes(wxExpr
*clause
)
603 wxRectangleShape::WriteAttributes(clause
);
605 // clause->AddAttributeValue("selectable", (long)selectable);
607 // Output constraints as constraint1 = (...), constraint2 = (...), etc.
608 int constraintNo
= 1;
609 wxChar m_constraintNameBuf
[20];
610 wxNode
*node
= m_constraints
.GetFirst();
613 wxOGLConstraint
*constraint
= (wxOGLConstraint
*)node
->GetData();
614 wxSprintf(m_constraintNameBuf
, _T("constraint%d"), constraintNo
);
616 // Each constraint is stored in the form
617 // (type name id xspacing yspacing m_constrainingObjectId constrainedObjectIdList)
618 wxExpr
*constraintExpr
= new wxExpr(wxExprList
);
619 constraintExpr
->Append(new wxExpr((long)constraint
->m_constraintType
));
620 constraintExpr
->Append(new wxExpr(wxExprString
, constraint
->m_constraintName
));
621 constraintExpr
->Append(new wxExpr(constraint
->m_constraintId
));
622 constraintExpr
->Append(new wxExpr(constraint
->m_xSpacing
));
623 constraintExpr
->Append(new wxExpr(constraint
->m_ySpacing
));
624 constraintExpr
->Append(new wxExpr(constraint
->m_constrainingObject
->GetId()));
626 wxExpr
*objectList
= new wxExpr(wxExprList
);
627 wxNode
*node1
= constraint
->m_constrainedObjects
.GetFirst();
630 wxShape
*obj
= (wxShape
*)node1
->GetData();
631 objectList
->Append(new wxExpr(obj
->GetId()));
632 node1
= node1
->GetNext();
634 constraintExpr
->Append(objectList
);
636 clause
->AddAttributeValue(m_constraintNameBuf
, constraintExpr
);
638 node
= node
->GetNext();
642 // Write the ids of all the child images
643 wxExpr
*childrenExpr
= new wxExpr(wxExprList
);
644 node
= m_children
.GetFirst();
647 wxShape
*child
= (wxShape
*)node
->GetData();
648 childrenExpr
->Append(new wxExpr(child
->GetId()));
649 node
= node
->GetNext();
651 clause
->AddAttributeValue(_T("children"), childrenExpr
);
653 // Write the ids of all the division images
654 if (m_divisions
.GetCount() > 0)
656 wxExpr
*divisionsExpr
= new wxExpr(wxExprList
);
657 node
= m_divisions
.GetFirst();
660 wxShape
*child
= (wxShape
*)node
->GetData();
661 divisionsExpr
->Append(new wxExpr(child
->GetId()));
662 node
= node
->GetNext();
664 clause
->AddAttributeValue(_T("divisions"), divisionsExpr
);
668 // Problem. Child images are always written AFTER the parent
669 // so as to be able to link up to parent. So we may not be able
670 // to find the constraint participants until we've read everything
671 // in. Need to have another pass for composites.
672 void wxCompositeShape::ReadAttributes(wxExpr
*clause
)
674 wxRectangleShape::ReadAttributes(clause
);
676 // clause->GetAttributeValue("selectable", selectable);
679 void wxCompositeShape::ReadConstraints(wxExpr
*clause
, wxExprDatabase
*database
)
681 // Constraints are output as constraint1 = (...), constraint2 = (...), etc.
682 int constraintNo
= 1;
683 wxChar m_constraintNameBuf
[20];
684 bool haveConstraints
= true;
686 while (haveConstraints
)
688 wxSprintf(m_constraintNameBuf
, _T("constraint%d"), constraintNo
);
689 wxExpr
*constraintExpr
= NULL
;
690 clause
->GetAttributeValue(m_constraintNameBuf
, &constraintExpr
);
693 haveConstraints
= false;
696 wxString cName
= wxEmptyString
;
697 wxShape
*m_constrainingObject
= NULL
;
698 wxList m_constrainedObjects
;
700 // Each constraint is stored in the form
701 // (type name id xspacing yspacing m_constrainingObjectId constrainedObjectIdList)
703 wxExpr
*typeExpr
= constraintExpr
->Nth(0);
704 wxExpr
*nameExpr
= constraintExpr
->Nth(1);
705 wxExpr
*idExpr
= constraintExpr
->Nth(2);
706 wxExpr
*xExpr
= constraintExpr
->Nth(3);
707 wxExpr
*yExpr
= constraintExpr
->Nth(4);
708 wxExpr
*constrainingExpr
= constraintExpr
->Nth(5);
709 wxExpr
*constrainedExpr
= constraintExpr
->Nth(6);
711 int cType
= (int)typeExpr
->IntegerValue();
712 double cXSpacing
= xExpr
->RealValue();
713 double cYSpacing
= yExpr
->RealValue();
714 cName
= nameExpr
->StringValue();
715 long cId
= idExpr
->IntegerValue();
717 wxExpr
*objExpr1
= database
->HashFind(_T("node_image"), constrainingExpr
->IntegerValue());
718 if (objExpr1
&& objExpr1
->GetClientData())
719 m_constrainingObject
= (wxShape
*)objExpr1
->GetClientData();
721 wxLogFatalError(wxT("Object graphics error: Couldn't find constraining image of composite."));
724 wxExpr
*currentIdExpr
= constrainedExpr
->Nth(i
);
725 while (currentIdExpr
)
727 long currentId
= currentIdExpr
->IntegerValue();
728 wxExpr
*objExpr2
= database
->HashFind(_T("node_image"), currentId
);
729 if (objExpr2
&& objExpr2
->GetClientData())
731 m_constrainedObjects
.Append((wxShape
*)objExpr2
->GetClientData());
735 wxLogFatalError(wxT("Object graphics error: Couldn't find constrained image of composite."));
739 currentIdExpr
= constrainedExpr
->Nth(i
);
741 wxOGLConstraint
*newConstraint
= AddConstraint(cType
, m_constrainingObject
, m_constrainedObjects
);
742 newConstraint
->SetSpacing(cXSpacing
, cYSpacing
);
743 newConstraint
->m_constraintId
= cId
;
744 newConstraint
->m_constraintName
= cName
;
750 // Make this composite into a container by creating one wxDivisionShape
751 void wxCompositeShape::MakeContainer()
753 wxDivisionShape
*division
= OnCreateDivision();
754 m_divisions
.Append(division
);
757 division
->SetSize(m_width
, m_height
);
759 wxClientDC
dc(GetCanvas());
760 GetCanvas()->PrepareDC(dc
);
762 division
->Move(dc
, GetX(), GetY());
764 division
->Show(true);
767 wxDivisionShape
*wxCompositeShape::OnCreateDivision()
769 return new wxDivisionShape
;
772 wxShape
*wxCompositeShape::FindContainerImage()
774 wxNode
*node
= m_children
.GetFirst();
777 wxShape
*child
= (wxShape
*)node
->GetData();
778 if (!m_divisions
.Member(child
))
780 node
= node
->GetNext();
785 // Returns true if division is a descendant of this container
786 bool wxCompositeShape::ContainsDivision(wxDivisionShape
*division
)
788 if (m_divisions
.Member(division
))
790 wxNode
*node
= m_children
.GetFirst();
793 wxShape
*child
= (wxShape
*)node
->GetData();
794 if (child
->IsKindOf(CLASSINFO(wxCompositeShape
)))
796 bool ans
= ((wxCompositeShape
*)child
)->ContainsDivision(division
);
800 node
= node
->GetNext();
810 IMPLEMENT_DYNAMIC_CLASS(wxDivisionShape
, wxCompositeShape
)
812 wxDivisionShape::wxDivisionShape()
814 SetSensitivityFilter(OP_CLICK_LEFT
| OP_CLICK_RIGHT
| OP_DRAG_RIGHT
);
815 SetCentreResize(false);
816 SetAttachmentMode(true);
821 m_handleSide
= DIVISION_SIDE_NONE
;
822 m_leftSidePen
= wxBLACK_PEN
;
823 m_topSidePen
= wxBLACK_PEN
;
824 m_leftSideColour
= wxT("BLACK");
825 m_topSideColour
= wxT("BLACK");
826 m_leftSideStyle
= wxT("Solid");
827 m_topSideStyle
= wxT("Solid");
831 wxDivisionShape::~wxDivisionShape()
835 void wxDivisionShape::OnDraw(wxDC
& dc
)
837 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
838 dc
.SetBackgroundMode(wxTRANSPARENT
);
840 double x1
= (double)(GetX() - (GetWidth()/2.0));
841 double y1
= (double)(GetY() - (GetHeight()/2.0));
842 double x2
= (double)(GetX() + (GetWidth()/2.0));
843 double y2
= (double)(GetY() + (GetHeight()/2.0));
845 // Should subtract 1 pixel if drawing under Windows
852 dc
.SetPen(* m_leftSidePen
);
853 dc
.DrawLine(WXROUND(x1
), WXROUND(y2
), WXROUND(x1
), WXROUND(y1
));
857 dc
.SetPen(* m_topSidePen
);
858 dc
.DrawLine(WXROUND(x1
), WXROUND(y1
), WXROUND(x2
), WXROUND(y1
));
861 // For testing purposes, draw a rectangle so we know
862 // how big the division is.
863 // SetBrush(* wxCYAN_BRUSH);
864 // wxRectangleShape::OnDraw(dc);
867 void wxDivisionShape::OnDrawContents(wxDC
& dc
)
869 wxCompositeShape::OnDrawContents(dc
);
872 bool wxDivisionShape::OnMovePre(wxDC
& dc
, double x
, double y
, double oldx
, double oldy
, bool display
)
874 double diffX
= x
- oldx
;
875 double diffY
= y
- oldy
;
876 wxNode
*node
= m_children
.GetFirst();
879 wxShape
*object
= (wxShape
*)node
->GetData();
881 object
->Move(dc
, object
->GetX() + diffX
, object
->GetY() + diffY
, display
);
882 node
= node
->GetNext();
887 void wxDivisionShape::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
889 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
895 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
896 m_parent
->GetEventHandler()->OnDragLeft(draw
, x
, y
, keys
, attachment
);
900 wxShape::OnDragLeft(draw
, x
, y
, keys
, attachment
);
903 void wxDivisionShape::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
905 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
911 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
912 m_parent
->GetEventHandler()->OnBeginDragLeft(x
, y
, keys
, attachment
);
917 wxShape::OnBeginDragLeft(x
, y
, keys
, attachment
);
920 void wxDivisionShape::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
922 m_canvas
->ReleaseMouse();
923 if ((m_sensitivity
& OP_DRAG_LEFT
) != OP_DRAG_LEFT
)
929 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
930 m_parent
->GetEventHandler()->OnEndDragLeft(x
, y
, keys
, attachment
);
935 wxClientDC
dc(GetCanvas());
936 GetCanvas()->PrepareDC(dc
);
938 dc
.SetLogicalFunction(wxCOPY
);
940 m_canvas
->Snap(&m_xpos
, &m_ypos
);
941 GetEventHandler()->OnMovePre(dc
, x
, y
, m_oldX
, m_oldY
);
943 ResetControlPoints();
946 GetEventHandler()->OnDrawControlPoints(dc
);
948 if (m_canvas
&& !m_canvas
->GetQuickEditMode()) m_canvas
->Redraw(dc
);
951 void wxDivisionShape::SetSize(double w
, double h
, bool recursive
)
955 wxRectangleShape::SetSize(w
, h
, recursive
);
958 void wxDivisionShape::CalculateSize()
962 void wxDivisionShape::Copy(wxShape
& copy
)
964 wxCompositeShape::Copy(copy
);
966 wxASSERT( copy
.IsKindOf(CLASSINFO(wxDivisionShape
)) ) ;
968 wxDivisionShape
& divisionCopy
= (wxDivisionShape
&) copy
;
970 divisionCopy
.m_leftSideStyle
= m_leftSideStyle
;
971 divisionCopy
.m_topSideStyle
= m_topSideStyle
;
972 divisionCopy
.m_leftSideColour
= m_leftSideColour
;
973 divisionCopy
.m_topSideColour
= m_topSideColour
;
975 divisionCopy
.m_leftSidePen
= m_leftSidePen
;
976 divisionCopy
.m_topSidePen
= m_topSidePen
;
977 divisionCopy
.m_handleSide
= m_handleSide
;
979 // Division geometry copying is handled at the wxCompositeShape level.
983 void wxDivisionShape::WriteAttributes(wxExpr
*clause
)
985 wxCompositeShape::WriteAttributes(clause
);
988 clause
->AddAttributeValue(_T("left_side"), (long)m_leftSide
->GetId());
990 clause
->AddAttributeValue(_T("top_side"), (long)m_topSide
->GetId());
992 clause
->AddAttributeValue(_T("right_side"), (long)m_rightSide
->GetId());
994 clause
->AddAttributeValue(_T("bottom_side"), (long)m_bottomSide
->GetId());
996 clause
->AddAttributeValue(_T("handle_side"), (long)m_handleSide
);
997 clause
->AddAttributeValueString(_T("left_colour"), m_leftSideColour
);
998 clause
->AddAttributeValueString(_T("top_colour"), m_topSideColour
);
999 clause
->AddAttributeValueString(_T("left_style"), m_leftSideStyle
);
1000 clause
->AddAttributeValueString(_T("top_style"), m_topSideStyle
);
1003 void wxDivisionShape::ReadAttributes(wxExpr
*clause
)
1005 wxCompositeShape::ReadAttributes(clause
);
1007 clause
->GetAttributeValue(_T("handle_side"), m_handleSide
);
1008 clause
->GetAttributeValue(_T("left_colour"), m_leftSideColour
);
1009 clause
->GetAttributeValue(_T("top_colour"), m_topSideColour
);
1010 clause
->GetAttributeValue(_T("left_style"), m_leftSideStyle
);
1011 clause
->GetAttributeValue(_T("top_style"), m_topSideStyle
);
1016 void wxDivisionShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
1018 if (keys
& KEY_CTRL
)
1023 else if (keys & KEY_SHIFT)
1025 if (m_leftSide || m_topSide || m_rightSide || m_bottomSide)
1030 GetParent()->Draw(dc);
1043 m_parent
->HitTest(x
, y
, &attachment
, &dist
);
1044 m_parent
->GetEventHandler()->OnRightClick(x
, y
, keys
, attachment
);
1051 // Divide wxHORIZONTALly or wxVERTICALly
1052 bool wxDivisionShape::Divide(int direction
)
1054 // Calculate existing top-left, bottom-right
1055 double x1
= (double)(GetX() - (GetWidth()/2.0));
1056 double y1
= (double)(GetY() - (GetHeight()/2.0));
1057 wxCompositeShape
*compositeParent
= (wxCompositeShape
*)GetParent();
1058 double oldWidth
= GetWidth();
1059 double oldHeight
= GetHeight();
1063 wxClientDC
dc(GetCanvas());
1064 GetCanvas()->PrepareDC(dc
);
1066 if (direction
== wxVERTICAL
)
1068 // Dividing vertically means notionally putting a horizontal line through it.
1069 // Break existing piece into two.
1070 double newXPos1
= GetX();
1071 double newYPos1
= (double)(y1
+ (GetHeight()/4.0));
1072 double newXPos2
= GetX();
1073 double newYPos2
= (double)(y1
+ (3.0*GetHeight()/4.0));
1074 wxDivisionShape
*newDivision
= compositeParent
->OnCreateDivision();
1075 newDivision
->Show(true);
1079 // Anything adjoining the bottom of this division now adjoins the
1080 // bottom of the new division.
1081 wxNode
*node
= compositeParent
->GetDivisions().GetFirst();
1084 wxDivisionShape
*obj
= (wxDivisionShape
*)node
->GetData();
1085 if (obj
->GetTopSide() == this)
1086 obj
->SetTopSide(newDivision
);
1087 node
= node
->GetNext();
1089 newDivision
->SetTopSide(this);
1090 newDivision
->SetBottomSide(m_bottomSide
);
1091 newDivision
->SetLeftSide(m_leftSide
);
1092 newDivision
->SetRightSide(m_rightSide
);
1093 m_bottomSide
= newDivision
;
1095 compositeParent
->GetDivisions().Append(newDivision
);
1097 // CHANGE: Need to insert this division at start of divisions in the object
1098 // list, because e.g.:
1100 // 2) Add contained object
1102 // Division is now receiving mouse events _before_ the contained object,
1103 // because it was added last (on top of all others)
1105 // Add after the image that visualizes the container
1106 compositeParent
->AddChild(newDivision
, compositeParent
->FindContainerImage());
1108 m_handleSide
= DIVISION_SIDE_BOTTOM
;
1109 newDivision
->SetHandleSide(DIVISION_SIDE_TOP
);
1111 SetSize(oldWidth
, (double)(oldHeight
/2.0));
1112 Move(dc
, newXPos1
, newYPos1
);
1114 newDivision
->SetSize(oldWidth
, (double)(oldHeight
/2.0));
1115 newDivision
->Move(dc
, newXPos2
, newYPos2
);
1119 // Dividing horizontally means notionally putting a vertical line through it.
1120 // Break existing piece into two.
1121 double newXPos1
= (double)(x1
+ (GetWidth()/4.0));
1122 double newYPos1
= GetY();
1123 double newXPos2
= (double)(x1
+ (3.0*GetWidth()/4.0));
1124 double newYPos2
= GetY();
1125 wxDivisionShape
*newDivision
= compositeParent
->OnCreateDivision();
1126 newDivision
->Show(true);
1130 // Anything adjoining the left of this division now adjoins the
1131 // left of the new division.
1132 wxNode
*node
= compositeParent
->GetDivisions().GetFirst();
1135 wxDivisionShape
*obj
= (wxDivisionShape
*)node
->GetData();
1136 if (obj
->GetLeftSide() == this)
1137 obj
->SetLeftSide(newDivision
);
1138 node
= node
->GetNext();
1140 newDivision
->SetTopSide(m_topSide
);
1141 newDivision
->SetBottomSide(m_bottomSide
);
1142 newDivision
->SetLeftSide(this);
1143 newDivision
->SetRightSide(m_rightSide
);
1144 m_rightSide
= newDivision
;
1146 compositeParent
->GetDivisions().Append(newDivision
);
1147 compositeParent
->AddChild(newDivision
, compositeParent
->FindContainerImage());
1149 m_handleSide
= DIVISION_SIDE_RIGHT
;
1150 newDivision
->SetHandleSide(DIVISION_SIDE_LEFT
);
1152 SetSize((double)(oldWidth
/2.0), oldHeight
);
1153 Move(dc
, newXPos1
, newYPos1
);
1155 newDivision
->SetSize((double)(oldWidth
/2.0), oldHeight
);
1156 newDivision
->Move(dc
, newXPos2
, newYPos2
);
1158 if (compositeParent
->Selected())
1160 compositeParent
->DeleteControlPoints(& dc
);
1161 compositeParent
->MakeControlPoints();
1162 compositeParent
->MakeMandatoryControlPoints();
1164 compositeParent
->Draw(dc
);
1168 // Make one control point for every visible line
1169 void wxDivisionShape::MakeControlPoints()
1171 MakeMandatoryControlPoints();
1174 void wxDivisionShape::MakeMandatoryControlPoints()
1178 GetBoundingBoxMax(&maxX
, &maxY
);
1179 double x
= 0.0 , y
= 0.0;
1184 x = (double)(-maxX/2.0);
1186 wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y,
1187 CONTROL_POINT_HORIZONTAL);
1188 m_canvas->AddShape(control);
1189 m_controlPoints.Append(control);
1194 y = (double)(-maxY/2.0);
1195 wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y,
1196 CONTROL_POINT_VERTICAL);
1197 m_canvas->AddShape(control);
1198 m_controlPoints.Append(control);
1201 switch (m_handleSide
)
1203 case DIVISION_SIDE_LEFT
:
1205 x
= (double)(-maxX
/2.0);
1207 direction
= CONTROL_POINT_HORIZONTAL
;
1210 case DIVISION_SIDE_TOP
:
1213 y
= (double)(-maxY
/2.0);
1214 direction
= CONTROL_POINT_VERTICAL
;
1217 case DIVISION_SIDE_RIGHT
:
1219 x
= (double)(maxX
/2.0);
1221 direction
= CONTROL_POINT_HORIZONTAL
;
1224 case DIVISION_SIDE_BOTTOM
:
1227 y
= (double)(maxY
/2.0);
1228 direction
= CONTROL_POINT_VERTICAL
;
1234 if (m_handleSide
!= DIVISION_SIDE_NONE
)
1236 wxDivisionControlPoint
*control
= new wxDivisionControlPoint(m_canvas
, this, CONTROL_POINT_SIZE
, x
, y
,
1238 m_canvas
->AddShape(control
);
1239 m_controlPoints
.Append(control
);
1243 void wxDivisionShape::ResetControlPoints()
1245 ResetMandatoryControlPoints();
1248 void wxDivisionShape::ResetMandatoryControlPoints()
1250 if (m_controlPoints
.GetCount() < 1)
1255 GetBoundingBoxMax(&maxX
, &maxY
);
1257 wxNode *node = m_controlPoints.GetFirst();
1260 wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->GetData();
1261 if (control->type == CONTROL_POINT_HORIZONTAL)
1263 control->xoffset = (double)(-maxX/2.0); control->m_yoffset = 0.0;
1265 else if (control->type == CONTROL_POINT_VERTICAL)
1267 control->xoffset = 0.0; control->m_yoffset = (double)(-maxY/2.0);
1269 node = node->GetNext();
1272 wxNode
*node
= m_controlPoints
.GetFirst();
1273 if ((m_handleSide
== DIVISION_SIDE_LEFT
) && node
)
1275 wxDivisionControlPoint
*control
= (wxDivisionControlPoint
*)node
->GetData();
1276 control
->m_xoffset
= (double)(-maxX
/2.0); control
->m_yoffset
= 0.0;
1279 if ((m_handleSide
== DIVISION_SIDE_TOP
) && node
)
1281 wxDivisionControlPoint
*control
= (wxDivisionControlPoint
*)node
->GetData();
1282 control
->m_xoffset
= 0.0; control
->m_yoffset
= (double)(-maxY
/2.0);
1285 if ((m_handleSide
== DIVISION_SIDE_RIGHT
) && node
)
1287 wxDivisionControlPoint
*control
= (wxDivisionControlPoint
*)node
->GetData();
1288 control
->m_xoffset
= (double)(maxX
/2.0); control
->m_yoffset
= 0.0;
1291 if ((m_handleSide
== DIVISION_SIDE_BOTTOM
) && node
)
1293 wxDivisionControlPoint
*control
= (wxDivisionControlPoint
*)node
->GetData();
1294 control
->m_xoffset
= 0.0; control
->m_yoffset
= (double)(maxY
/2.0);
1298 // Adjust a side, returning false if it's not physically possible.
1299 bool wxDivisionShape::AdjustLeft(double left
, bool test
)
1301 double x2
= (double)(GetX() + (GetWidth()/2.0));
1308 double newW
= x2
- left
;
1309 double newX
= (double)(left
+ newW
/2.0);
1310 SetSize(newW
, GetHeight());
1312 wxClientDC
dc(GetCanvas());
1313 GetCanvas()->PrepareDC(dc
);
1315 Move(dc
, newX
, GetY());
1320 bool wxDivisionShape::AdjustTop(double top
, bool test
)
1322 double y2
= (double)(GetY() + (GetHeight()/2.0));
1329 double newH
= y2
- top
;
1330 double newY
= (double)(top
+ newH
/2.0);
1331 SetSize(GetWidth(), newH
);
1333 wxClientDC
dc(GetCanvas());
1334 GetCanvas()->PrepareDC(dc
);
1336 Move(dc
, GetX(), newY
);
1341 bool wxDivisionShape::AdjustRight(double right
, bool test
)
1343 double x1
= (double)(GetX() - (GetWidth()/2.0));
1350 double newW
= right
- x1
;
1351 double newX
= (double)(x1
+ newW
/2.0);
1352 SetSize(newW
, GetHeight());
1354 wxClientDC
dc(GetCanvas());
1355 GetCanvas()->PrepareDC(dc
);
1357 Move(dc
, newX
, GetY());
1362 bool wxDivisionShape::AdjustBottom(double bottom
, bool test
)
1364 double y1
= (double)(GetY() - (GetHeight()/2.0));
1371 double newH
= bottom
- y1
;
1372 double newY
= (double)(y1
+ newH
/2.0);
1373 SetSize(GetWidth(), newH
);
1375 wxClientDC
dc(GetCanvas());
1376 GetCanvas()->PrepareDC(dc
);
1378 Move(dc
, GetX(), newY
);
1383 wxDivisionControlPoint::wxDivisionControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
, double size
, double the_xoffset
, double the_yoffset
, int the_type
):
1384 wxControlPoint(the_canvas
, object
, size
, the_xoffset
, the_yoffset
, the_type
)
1386 SetEraseObject(false);
1389 wxDivisionControlPoint::~wxDivisionControlPoint()
1393 static double originalX
= 0.0;
1394 static double originalY
= 0.0;
1395 static double originalW
= 0.0;
1396 static double originalH
= 0.0;
1398 // Implement resizing of canvas object
1399 void wxDivisionControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
1401 wxControlPoint::OnDragLeft(draw
, x
, y
, keys
, attachment
);
1404 void wxDivisionControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
1406 wxDivisionShape
*division
= (wxDivisionShape
*)m_shape
;
1407 originalX
= division
->GetX();
1408 originalY
= division
->GetY();
1409 originalW
= division
->GetWidth();
1410 originalH
= division
->GetHeight();
1412 wxControlPoint::OnBeginDragLeft(x
, y
, keys
, attachment
);
1415 void wxDivisionControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
1417 wxControlPoint::OnEndDragLeft(x
, y
, keys
, attachment
);
1419 wxClientDC
dc(GetCanvas());
1420 GetCanvas()->PrepareDC(dc
);
1422 wxDivisionShape
*division
= (wxDivisionShape
*)m_shape
;
1423 wxCompositeShape
*divisionParent
= (wxCompositeShape
*)division
->GetParent();
1425 // Need to check it's within the bounds of the parent composite.
1426 double x1
= (double)(divisionParent
->GetX() - (divisionParent
->GetWidth()/2.0));
1427 double y1
= (double)(divisionParent
->GetY() - (divisionParent
->GetHeight()/2.0));
1428 double x2
= (double)(divisionParent
->GetX() + (divisionParent
->GetWidth()/2.0));
1429 double y2
= (double)(divisionParent
->GetY() + (divisionParent
->GetHeight()/2.0));
1431 // Need to check it has not made the division zero or negative width/height
1432 double dx1
= (double)(division
->GetX() - (division
->GetWidth()/2.0));
1433 double dy1
= (double)(division
->GetY() - (division
->GetHeight()/2.0));
1434 double dx2
= (double)(division
->GetX() + (division
->GetWidth()/2.0));
1435 double dy2
= (double)(division
->GetY() + (division
->GetHeight()/2.0));
1437 bool success
= true;
1438 switch (division
->GetHandleSide())
1440 case DIVISION_SIDE_LEFT
:
1442 if ((x
<= x1
) || (x
>= x2
) || (x
>= dx2
))
1444 // Try it out first...
1445 else if (!division
->ResizeAdjoining(DIVISION_SIDE_LEFT
, x
, true))
1448 division
->ResizeAdjoining(DIVISION_SIDE_LEFT
, x
, false);
1452 case DIVISION_SIDE_TOP
:
1454 if ((y
<= y1
) || (y
>= y2
) || (y
>= dy2
))
1456 else if (!division
->ResizeAdjoining(DIVISION_SIDE_TOP
, y
, true))
1459 division
->ResizeAdjoining(DIVISION_SIDE_TOP
, y
, false);
1463 case DIVISION_SIDE_RIGHT
:
1465 if ((x
<= x1
) || (x
>= x2
) || (x
<= dx1
))
1467 else if (!division
->ResizeAdjoining(DIVISION_SIDE_RIGHT
, x
, true))
1470 division
->ResizeAdjoining(DIVISION_SIDE_RIGHT
, x
, false);
1474 case DIVISION_SIDE_BOTTOM
:
1476 if ((y
<= y1
) || (y
>= y2
) || (y
<= dy1
))
1478 else if (!division
->ResizeAdjoining(DIVISION_SIDE_BOTTOM
, y
, true))
1481 division
->ResizeAdjoining(DIVISION_SIDE_BOTTOM
, y
, false);
1488 division
->SetSize(originalW
, originalH
);
1489 division
->Move(dc
, originalX
, originalY
);
1491 divisionParent
->Draw(dc
);
1492 division
->GetEventHandler()->OnDrawControlPoints(dc
);
1495 /* Resize adjoining divisions.
1497 Behaviour should be as follows:
1498 If right edge moves, find all objects whose left edge
1499 adjoins this object, and move left edge accordingly.
1500 If left..., move ... right.
1501 If top..., move ... bottom.
1502 If bottom..., move top.
1503 If size goes to zero or end position is other side of start position,
1504 resize to original size and return.
1506 bool wxDivisionShape::ResizeAdjoining(int side
, double newPos
, bool test
)
1508 wxCompositeShape
*divisionParent
= (wxCompositeShape
*)GetParent();
1509 wxNode
*node
= divisionParent
->GetDivisions().GetFirst();
1512 wxDivisionShape
*division
= (wxDivisionShape
*)node
->GetData();
1515 case DIVISION_SIDE_LEFT
:
1517 if (division
->m_rightSide
== this)
1519 bool success
= division
->AdjustRight(newPos
, test
);
1520 if (!success
&& test
)
1525 case DIVISION_SIDE_TOP
:
1527 if (division
->m_bottomSide
== this)
1529 bool success
= division
->AdjustBottom(newPos
, test
);
1530 if (!success
&& test
)
1535 case DIVISION_SIDE_RIGHT
:
1537 if (division
->m_leftSide
== this)
1539 bool success
= division
->AdjustLeft(newPos
, test
);
1540 if (!success
&& test
)
1545 case DIVISION_SIDE_BOTTOM
:
1547 if (division
->m_topSide
== this)
1549 bool success
= division
->AdjustTop(newPos
, test
);
1550 if (!success
&& test
)
1558 node
= node
->GetNext();
1565 * Popup menu for editing divisions
1568 class OGLPopupDivisionMenu
: public wxMenu
{
1570 OGLPopupDivisionMenu() : wxMenu() {
1571 Append(DIVISION_MENU_SPLIT_HORIZONTALLY
, wxT("Split horizontally"));
1572 Append(DIVISION_MENU_SPLIT_VERTICALLY
, wxT("Split vertically"));
1574 Append(DIVISION_MENU_EDIT_LEFT_EDGE
, wxT("Edit left edge"));
1575 Append(DIVISION_MENU_EDIT_TOP_EDGE
, wxT("Edit top edge"));
1578 void OnMenu(wxCommandEvent
& event
);
1580 DECLARE_EVENT_TABLE()
1583 BEGIN_EVENT_TABLE(OGLPopupDivisionMenu
, wxMenu
)
1584 EVT_MENU_RANGE(DIVISION_MENU_SPLIT_HORIZONTALLY
,
1585 DIVISION_MENU_EDIT_BOTTOM_EDGE
,
1586 OGLPopupDivisionMenu::OnMenu
)
1590 void OGLPopupDivisionMenu::OnMenu(wxCommandEvent
& event
)
1592 wxDivisionShape
*division
= (wxDivisionShape
*)GetClientData();
1593 switch (event
.GetInt())
1595 case DIVISION_MENU_SPLIT_HORIZONTALLY
:
1597 division
->Divide(wxHORIZONTAL
);
1600 case DIVISION_MENU_SPLIT_VERTICALLY
:
1602 division
->Divide(wxVERTICAL
);
1605 case DIVISION_MENU_EDIT_LEFT_EDGE
:
1607 division
->EditEdge(DIVISION_SIDE_LEFT
);
1610 case DIVISION_MENU_EDIT_TOP_EDGE
:
1612 division
->EditEdge(DIVISION_SIDE_TOP
);
1620 void wxDivisionShape::EditEdge(int WXUNUSED(side
))
1622 wxMessageBox(wxT("EditEdge() not implemented"), wxT("OGL"), wxOK
);
1625 wxBeginBusyCursor();
1627 wxPen
*currentPen
= NULL
;
1628 char **pColour
= NULL
;
1629 char **pStyle
= NULL
;
1630 if (side
== DIVISION_SIDE_LEFT
)
1632 currentPen
= m_leftSidePen
;
1633 pColour
= &m_leftSideColour
;
1634 pStyle
= &m_leftSideStyle
;
1638 currentPen
= m_topSidePen
;
1639 pColour
= &m_topSideColour
;
1640 pStyle
= &m_topSideStyle
;
1643 GraphicsForm
*form
= new GraphicsForm("Containers");
1644 int lineWidth
= currentPen
->GetWidth();
1646 form
->Add(wxMakeFormShort("Width", &lineWidth
, wxFORM_DEFAULT
, NULL
, NULL
, wxVERTICAL
,
1648 form
->Add(wxMakeFormString("Colour", pColour
, wxFORM_CHOICE
,
1649 new wxList(wxMakeConstraintStrings(
1673 NULL
), NULL
, wxVERTICAL
, 150));
1674 form
->Add(wxMakeFormString("Style", pStyle
, wxFORM_CHOICE
,
1675 new wxList(wxMakeConstraintStrings(
1682 NULL
), NULL
, wxVERTICAL
, 100));
1684 wxDialogBox
*dialog
= new wxDialogBox(m_canvas
->GetParent(), "Division properties", 10, 10, 500, 500);
1685 if (GraphicsLabelFont
)
1686 dialog
->SetLabelFont(GraphicsLabelFont
);
1687 if (GraphicsButtonFont
)
1688 dialog
->SetButtonFont(GraphicsButtonFont
);
1690 form
->AssociatePanel(dialog
);
1691 form
->dialog
= dialog
;
1694 dialog
->Centre(wxBOTH
);
1699 int lineStyle
= wxSOLID
;
1702 if (strcmp(*pStyle
, "Solid") == 0)
1703 lineStyle
= wxSOLID
;
1704 else if (strcmp(*pStyle
, "Dot") == 0)
1706 else if (strcmp(*pStyle
, "Short Dash") == 0)
1707 lineStyle
= wxSHORT_DASH
;
1708 else if (strcmp(*pStyle
, "Long Dash") == 0)
1709 lineStyle
= wxLONG_DASH
;
1710 else if (strcmp(*pStyle
, "Dot Dash") == 0)
1711 lineStyle
= wxDOT_DASH
;
1714 wxPen
*newPen
= wxThePenList
->FindOrCreatePen(*pColour
, lineWidth
, lineStyle
);
1717 if (side
== DIVISION_SIDE_LEFT
)
1718 m_leftSidePen
= newPen
;
1720 m_topSidePen
= newPen
;
1722 // Need to draw whole image again
1723 wxCompositeShape
*compositeParent
= (wxCompositeShape
*)GetParent();
1724 compositeParent
->Draw(dc
);
1729 void wxDivisionShape::PopupMenu(double x
, double y
)
1731 wxMenu
* oglPopupDivisionMenu
= new OGLPopupDivisionMenu
;
1733 oglPopupDivisionMenu
->SetClientData((void *)this);
1735 oglPopupDivisionMenu
->Enable(DIVISION_MENU_EDIT_LEFT_EDGE
, true);
1737 oglPopupDivisionMenu
->Enable(DIVISION_MENU_EDIT_LEFT_EDGE
, false);
1739 oglPopupDivisionMenu
->Enable(DIVISION_MENU_EDIT_TOP_EDGE
, true);
1741 oglPopupDivisionMenu
->Enable(DIVISION_MENU_EDIT_TOP_EDGE
, false);
1744 m_canvas
->GetViewStart(&x1
, &y1
);
1747 m_canvas
->GetScrollPixelsPerUnit(&unit_x
, &unit_y
);
1749 wxClientDC
dc(GetCanvas());
1750 GetCanvas()->PrepareDC(dc
);
1752 int mouse_x
= (int)(dc
.LogicalToDeviceX((long)(x
- x1
*unit_x
)));
1753 int mouse_y
= (int)(dc
.LogicalToDeviceY((long)(y
- y1
*unit_y
)));
1755 m_canvas
->PopupMenu(oglPopupDivisionMenu
, mouse_x
, mouse_y
);
1756 delete oglPopupDivisionMenu
;
1759 void wxDivisionShape::SetLeftSideColour(const wxString
& colour
)
1761 m_leftSideColour
= colour
;
1764 void wxDivisionShape::SetTopSideColour(const wxString
& colour
)
1766 m_topSideColour
= colour
;
1769 void wxDivisionShape::SetLeftSideStyle(const wxString
& style
)
1771 m_leftSideStyle
= style
;
1774 void wxDivisionShape::SetTopSideStyle(const wxString
& style
)
1776 m_topSideStyle
= style
;