1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxDividedShape class
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
24 #include "wx/deprecated/wxexpr.h"
27 #include "wx/ogl/ogl.h"
30 class wxDividedShapeControlPoint
: public wxControlPoint
32 DECLARE_DYNAMIC_CLASS(wxDividedShapeControlPoint
)
36 wxDividedShapeControlPoint() { regionId
= 0; }
37 wxDividedShapeControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
, int region
,
38 double size
, double the_xoffset
, double the_yoffset
, int the_type
);
39 ~wxDividedShapeControlPoint();
41 void OnDragLeft(bool draw
, double x
, double y
, int keys
=0, int attachment
= 0);
42 void OnBeginDragLeft(double x
, double y
, int keys
=0, int attachment
= 0);
43 void OnEndDragLeft(double x
, double y
, int keys
=0, int attachment
= 0);
46 IMPLEMENT_DYNAMIC_CLASS(wxDividedShapeControlPoint
, wxControlPoint
)
53 IMPLEMENT_DYNAMIC_CLASS(wxDividedShape
, wxRectangleShape
)
55 wxDividedShape::wxDividedShape(double w
, double h
): wxRectangleShape(w
, h
)
60 wxDividedShape::~wxDividedShape()
64 void wxDividedShape::OnDraw(wxDC
& dc
)
66 wxRectangleShape::OnDraw(dc
);
69 void wxDividedShape::OnDrawContents(wxDC
& dc
)
71 double defaultProportion
= (double)(GetRegions().GetCount() > 0 ? (1.0/((double)(GetRegions().GetCount()))) : 0.0);
72 double currentY
= (double)(m_ypos
- (m_height
/ 2.0));
73 double maxY
= (double)(m_ypos
+ (m_height
/ 2.0));
75 double leftX
= (double)(m_xpos
- (m_width
/ 2.0));
76 double rightX
= (double)(m_xpos
+ (m_width
/ 2.0));
78 if (m_pen
) dc
.SetPen(* m_pen
);
80 dc
.SetTextForeground(m_textColour
);
83 // For efficiency, don't do this under X - doesn't make
84 // any visible difference for our purposes.
86 dc
.SetTextBackground(m_brush
->GetColour());
95 if (GetDisableLabel()) return;
99 dc
.SetBackgroundMode(wxTRANSPARENT
);
101 wxObjectList::compatibility_iterator node
= GetRegions().GetFirst();
104 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
105 dc
.SetFont(* region
->GetFont());
106 dc
.SetTextForeground(region
->GetActualColourObject());
109 region
->m_regionProportionY
< 0.0 ? defaultProportion
: region
->m_regionProportionY
;
111 double y
= currentY
+ m_height
*proportion
;
112 double actualY
= maxY
< y
? maxY
: y
;
114 double centreX
= m_xpos
;
115 double centreY
= (double)(currentY
+ (actualY
- currentY
)/2.0);
117 oglDrawFormattedText(dc
, ®ion
->m_formattedText
,
118 (double)(centreX
), (double)(centreY
), (double)(m_width
-2*xMargin
), (double)(actualY
- currentY
- 2*yMargin
),
119 region
->m_formatMode
);
120 if ((y
<= maxY
) && (node
->GetNext()))
122 wxPen
*regionPen
= region
->GetActualPen();
125 dc
.SetPen(* regionPen
);
126 dc
.DrawLine(WXROUND(leftX
), WXROUND(y
), WXROUND(rightX
), WXROUND(y
));
132 node
= node
->GetNext();
136 void wxDividedShape::SetSize(double w
, double h
, bool WXUNUSED(recursive
))
138 SetAttachmentSize(w
, h
);
144 void wxDividedShape::SetRegionSizes()
146 if (GetRegions().GetCount() == 0)
149 double defaultProportion
= (double)(GetRegions().GetCount() > 0 ? (1.0/((double)(GetRegions().GetCount()))) : 0.0);
150 double currentY
= (double)(m_ypos
- (m_height
/ 2.0));
151 double maxY
= (double)(m_ypos
+ (m_height
/ 2.0));
153 // double leftX = (double)(m_xpos - (m_width / 2.0));
154 // double rightX = (double)(m_xpos + (m_width / 2.0));
156 wxObjectList::compatibility_iterator node
= GetRegions().GetFirst();
159 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
161 region
->m_regionProportionY
<= 0.0 ? defaultProportion
: region
->m_regionProportionY
;
163 double sizeY
= (double)proportion
*m_height
;
164 double y
= currentY
+ sizeY
;
165 double actualY
= maxY
< y
? maxY
: y
;
167 double centreY
= (double)(currentY
+ (actualY
- currentY
)/2.0);
169 region
->SetSize(m_width
, sizeY
);
170 region
->SetPosition(0.0, (double)(centreY
- m_ypos
));
172 node
= node
->GetNext();
176 // Attachment points correspond to regions in the divided box
177 bool wxDividedShape::GetAttachmentPosition(int attachment
, double *x
, double *y
, int nth
, int no_arcs
,
180 int totalNumberAttachments
= (GetRegions().GetCount() * 2) + 2;
181 if ((GetAttachmentMode() == ATTACHMENT_MODE_NONE
) || (attachment
>= totalNumberAttachments
))
183 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
);
186 int n
= GetRegions().GetCount();
187 bool isEnd
= (line
&& line
->IsEnd(this));
189 double left
= (double)(m_xpos
- m_width
/2.0);
190 double right
= (double)(m_xpos
+ m_width
/2.0);
191 double top
= (double)(m_ypos
- m_height
/2.0);
192 double bottom
= (double)(m_ypos
+ m_height
/2.0);
194 // Zero is top, n+1 is bottom.
198 if (m_spaceAttachments
)
200 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
202 // Align line according to the next handle along
203 wxRealPoint
*point
= line
->GetNextControlPoint(this);
206 else if (point
->x
> right
)
212 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
217 else if (attachment
== (n
+1))
220 if (m_spaceAttachments
)
222 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
224 // Align line according to the next handle along
225 wxRealPoint
*point
= line
->GetNextControlPoint(this);
228 else if (point
->x
> right
)
234 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
242 bool isLeft
= !(attachment
< (n
+1));
243 int i
= (isLeft
) ? (totalNumberAttachments
- attachment
- 1) : (attachment
-1);
244 wxObjectList::compatibility_iterator node
= GetRegions().Item(i
);
247 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
254 // Calculate top and bottom of region
255 top
= (double)((m_ypos
+ region
->m_y
) - (region
->m_height
/2.0));
256 bottom
= (double)((m_ypos
+ region
->m_y
) + (region
->m_height
/2.0));
258 // Assuming we can trust the absolute size and
259 // position of these regions...
260 if (m_spaceAttachments
)
262 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
264 // Align line according to the next handle along
265 wxRealPoint
*point
= line
->GetNextControlPoint(this);
266 if (point
->y
< bottom
)
268 else if (point
->y
> top
)
274 // *y = (double)(((m_ypos + region->m_y) - (region->m_height/2.0)) + (nth + 1)*region->m_height/(no_arcs+1));
275 *y
= (double)(top
+ (nth
+ 1)*region
->m_height
/(no_arcs
+1));
278 *y
= (double)(m_ypos
+ region
->m_y
);
290 int wxDividedShape::GetNumberOfAttachments() const
292 // There are two attachments for each region (left and right),
293 // plus one on the top and one on the bottom.
294 int n
= (GetRegions().GetCount() * 2) + 2;
297 wxObjectList::compatibility_iterator node
= m_attachmentPoints
.GetFirst();
300 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
301 if (point
->m_id
> maxN
)
303 node
= node
->GetNext();
308 bool wxDividedShape::AttachmentIsValid(int attachment
) const
310 int totalNumberAttachments
= (GetRegions().GetCount() * 2) + 2;
311 if (attachment
>= totalNumberAttachments
)
313 return wxShape::AttachmentIsValid(attachment
);
315 else if (attachment
>= 0)
321 void wxDividedShape::Copy(wxShape
& copy
)
323 wxRectangleShape::Copy(copy
);
328 void wxDividedShape::MakeControlPoints()
330 wxRectangleShape::MakeControlPoints();
332 MakeMandatoryControlPoints();
335 void wxDividedShape::MakeMandatoryControlPoints()
337 double currentY
= (double)(GetY() - (m_height
/ 2.0));
338 double maxY
= (double)(GetY() + (m_height
/ 2.0));
340 wxObjectList::compatibility_iterator node
= GetRegions().GetFirst();
344 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
346 double proportion
= region
->m_regionProportionY
;
348 double y
= currentY
+ m_height
*proportion
;
349 double actualY
= (double)(maxY
< y
? maxY
: y
);
353 wxDividedShapeControlPoint
*controlPoint
=
354 new wxDividedShapeControlPoint(m_canvas
, this, i
, CONTROL_POINT_SIZE
, 0.0, (double)(actualY
- GetY()), 0);
355 m_canvas
->AddShape(controlPoint
);
356 m_controlPoints
.Append(controlPoint
);
360 node
= node
->GetNext();
364 void wxDividedShape::ResetControlPoints()
366 // May only have the region handles, (n - 1) of them.
367 if (m_controlPoints
.GetCount() > (GetRegions().GetCount() - 1))
368 wxRectangleShape::ResetControlPoints();
370 ResetMandatoryControlPoints();
373 void wxDividedShape::ResetMandatoryControlPoints()
375 double currentY
= (double)(GetY() - (m_height
/ 2.0));
376 double maxY
= (double)(GetY() + (m_height
/ 2.0));
378 wxObjectList::compatibility_iterator node
= m_controlPoints
.GetFirst();
382 wxControlPoint
*controlPoint
= (wxControlPoint
*)node
->GetData();
383 if (controlPoint
->IsKindOf(CLASSINFO(wxDividedShapeControlPoint
)))
385 wxObjectList::compatibility_iterator node1
= GetRegions().Item(i
);
386 wxShapeRegion
*region
= (wxShapeRegion
*)node1
->GetData();
388 double proportion
= region
->m_regionProportionY
;
390 double y
= currentY
+ m_height
*proportion
;
391 double actualY
= (double)(maxY
< y
? maxY
: y
);
393 controlPoint
->m_xoffset
= 0.0;
394 controlPoint
->m_yoffset
= (double)(actualY
- GetY());
398 node
= node
->GetNext();
403 void wxDividedShape::WriteAttributes(wxExpr
*clause
)
405 wxRectangleShape::WriteAttributes(clause
);
408 void wxDividedShape::ReadAttributes(wxExpr
*clause
)
410 wxRectangleShape::ReadAttributes(clause
);
415 * Edit the division colour/style
419 void wxDividedShape::EditRegions()
421 wxMessageBox(wxT("EditRegions() is unimplemented."), wxT("OGL"), wxOK
);
425 if (GetRegions().GetCount() < 2)
430 GraphicsForm
*form
= new GraphicsForm("Divided nodes");
431 // Need an array to store all the style strings,
432 // since they need to be converted to integers
433 char **styleStrings
= new char *[GetRegions().GetCount()];
434 for (int j
= 0; j
< GetRegions().GetCount(); j
++)
435 styleStrings
[j
] = NULL
;
438 wxNode
*node
= GetRegions().GetFirst();
439 while (node
&& node
->GetNext())
441 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
443 sprintf(buf
, "Region %d", (i
+1));
444 form
->Add(wxMakeFormMessage(buf
));
445 form
->Add(wxMakeFormNewLine());
447 form
->Add(wxMakeFormString("Colour", ®ion
->penColour
, wxFORM_CHOICE
,
448 new wxList(wxMakeConstraintStrings(
473 NULL
), NULL
, wxVERTICAL
, 150));
475 char *styleString
= NULL
;
476 switch (region
->penStyle
)
479 styleString
= "Short Dash";
482 styleString
= "Long Dash";
488 styleString
= "Dot Dash";
492 styleString
= "Solid";
495 styleStrings
[i
] = copystring(styleString
);
496 form
->Add(wxMakeFormString("Style", &(styleStrings
[i
]), wxFORM_CHOICE
,
497 new wxList(wxMakeConstraintStrings(
504 NULL
), NULL
, wxVERTICAL
, 100));
505 node
= node
->GetNext();
507 if (node
&& node
->GetNext())
508 form
->Add(wxMakeFormNewLine());
510 wxDialogBox
*dialog
= new wxDialogBox(m_canvas
->GetParent(), "Divided object properties", 10, 10, 500, 500);
511 if (GraphicsLabelFont
)
512 dialog
->SetLabelFont(GraphicsLabelFont
);
513 if (GraphicsButtonFont
)
514 dialog
->SetButtonFont(GraphicsButtonFont
);
515 form
->AssociatePanel(dialog
);
516 form
->dialog
= dialog
;
519 dialog
->Centre(wxBOTH
);
525 node
= GetRegions().GetFirst();
529 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
533 if (strcmp(styleStrings
[i
], "Solid") == 0)
534 region
->penStyle
= wxSOLID
;
535 else if (strcmp(styleStrings
[i
], "Dot") == 0)
536 region
->penStyle
= wxDOT
;
537 else if (strcmp(styleStrings
[i
], "Short Dash") == 0)
538 region
->penStyle
= wxSHORT_DASH
;
539 else if (strcmp(styleStrings
[i
], "Long Dash") == 0)
540 region
->penStyle
= wxLONG_DASH
;
541 else if (strcmp(styleStrings
[i
], "Dot Dash") == 0)
542 region
->penStyle
= wxDOT_DASH
;
543 delete[] styleStrings
[i
];
545 region
->m_actualPenObject
= NULL
;
546 node
= node
->GetNext();
549 delete[] styleStrings
;
554 void wxDividedShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
562 wxRectangleShape::OnRightClick(x
, y
, keys
, attachment
);
566 wxDividedShapeControlPoint::wxDividedShapeControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
,
567 int region
, double size
, double the_m_xoffset
, double the_m_yoffset
, int the_type
):
568 wxControlPoint(the_canvas
, object
, size
, the_m_xoffset
, the_m_yoffset
, the_type
)
573 wxDividedShapeControlPoint::~wxDividedShapeControlPoint()
577 // Implement resizing of divided object division
578 void wxDividedShapeControlPoint::OnDragLeft(bool WXUNUSED(draw
), double WXUNUSED(x
), double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
580 wxClientDC
dc(GetCanvas());
581 GetCanvas()->PrepareDC(dc
);
583 dc
.SetLogicalFunction(OGLRBLF
);
584 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
585 dc
.SetPen(dottedPen
);
586 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
588 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
589 double x1
= (double)(dividedObject
->GetX() - (dividedObject
->GetWidth()/2.0));
591 double x2
= (double)(dividedObject
->GetX() + (dividedObject
->GetWidth()/2.0));
593 dc
.DrawLine(WXROUND(x1
), WXROUND(y1
), WXROUND(x2
), WXROUND(y2
));
596 void wxDividedShapeControlPoint::OnBeginDragLeft(double WXUNUSED(x
), double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
598 wxClientDC
dc(GetCanvas());
599 GetCanvas()->PrepareDC(dc
);
601 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
602 dc
.SetLogicalFunction(OGLRBLF
);
603 wxPen
dottedPen(*wxBLACK
, 1, wxDOT
);
604 dc
.SetPen(dottedPen
);
605 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
607 double x1
= (double)(dividedObject
->GetX() - (dividedObject
->GetWidth()/2.0));
609 double x2
= (double)(dividedObject
->GetX() + (dividedObject
->GetWidth()/2.0));
611 dc
.DrawLine(WXROUND(x1
), WXROUND(y1
), WXROUND(x2
), WXROUND(y2
));
612 m_canvas
->CaptureMouse();
615 void wxDividedShapeControlPoint::OnEndDragLeft(double WXUNUSED(x
), double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
617 wxClientDC
dc(GetCanvas());
618 GetCanvas()->PrepareDC(dc
);
620 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
621 wxObjectList::compatibility_iterator node
= dividedObject
->GetRegions().Item(regionId
);
625 wxShapeRegion
*thisRegion
= (wxShapeRegion
*)node
->GetData();
626 wxShapeRegion
*nextRegion
= NULL
; // Region below this one
628 dc
.SetLogicalFunction(wxCOPY
);
630 m_canvas
->ReleaseMouse();
632 // Find the old top and bottom of this region,
633 // and calculate the new proportion for this region
636 double currentY
= (double)(dividedObject
->GetY() - (dividedObject
->GetHeight() / 2.0));
637 double maxY
= (double)(dividedObject
->GetY() + (dividedObject
->GetHeight() / 2.0));
640 double thisRegionTop
= 0.0;
641 double nextRegionBottom
= 0.0;
643 node
= dividedObject
->GetRegions().GetFirst();
646 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
648 double proportion
= region
->m_regionProportionY
;
649 double yy
= currentY
+ (dividedObject
->GetHeight()*proportion
);
650 double actualY
= (double)(maxY
< yy
? maxY
: yy
);
652 if (region
== thisRegion
)
654 thisRegionTop
= currentY
;
656 nextRegion
= (wxShapeRegion
*)node
->GetNext()->GetData();
658 if (region
== nextRegion
)
660 nextRegionBottom
= actualY
;
664 node
= node
->GetNext();
669 // Check that we haven't gone above this region or below
671 if ((y
<= thisRegionTop
) || (y
>= nextRegionBottom
))
674 dividedObject
->EraseLinks(dc
);
676 // Now calculate the new proportions of this region and the next region.
677 double thisProportion
= (double)((y
- thisRegionTop
)/dividedObject
->GetHeight());
678 double nextProportion
= (double)((nextRegionBottom
- y
)/dividedObject
->GetHeight());
679 thisRegion
->SetProportions(0.0, thisProportion
);
680 nextRegion
->SetProportions(0.0, nextProportion
);
681 m_yoffset
= (double)(y
- dividedObject
->GetY());
685 node
= dividedObject
->GetRegions().GetFirst();
688 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
689 if (region
->GetText())
691 wxString
s(region
->GetText());
692 dividedObject
->FormatText(dc
, s
.c_str(), i
);
694 node
= node
->GetNext();
697 dividedObject
->SetRegionSizes();
698 dividedObject
->Draw(dc
);
699 dividedObject
->GetEventHandler()->OnMoveLinks(dc
);