1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxDividedShape class
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "divided.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"
34 class wxDividedShapeControlPoint
: public wxControlPoint
36 DECLARE_DYNAMIC_CLASS(wxDividedShapeControlPoint
)
40 wxDividedShapeControlPoint() { regionId
= 0; }
41 wxDividedShapeControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
, int region
,
42 double size
, double the_xoffset
, double the_yoffset
, int the_type
);
43 ~wxDividedShapeControlPoint();
45 void OnDragLeft(bool draw
, double x
, double y
, int keys
=0, int attachment
= 0);
46 void OnBeginDragLeft(double x
, double y
, int keys
=0, int attachment
= 0);
47 void OnEndDragLeft(double x
, double y
, int keys
=0, int attachment
= 0);
50 IMPLEMENT_DYNAMIC_CLASS(wxDividedShapeControlPoint
, wxControlPoint
)
57 IMPLEMENT_DYNAMIC_CLASS(wxDividedShape
, wxRectangleShape
)
59 wxDividedShape::wxDividedShape(double w
, double h
): wxRectangleShape(w
, h
)
64 wxDividedShape::~wxDividedShape()
68 void wxDividedShape::OnDraw(wxDC
& dc
)
70 wxRectangleShape::OnDraw(dc
);
73 void wxDividedShape::OnDrawContents(wxDC
& dc
)
75 double defaultProportion
= (double)(GetRegions().GetCount() > 0 ? (1.0/((double)(GetRegions().GetCount()))) : 0.0);
76 double currentY
= (double)(m_ypos
- (m_height
/ 2.0));
77 double maxY
= (double)(m_ypos
+ (m_height
/ 2.0));
79 double leftX
= (double)(m_xpos
- (m_width
/ 2.0));
80 double rightX
= (double)(m_xpos
+ (m_width
/ 2.0));
82 if (m_pen
) dc
.SetPen(* m_pen
);
84 if (m_textColour
) dc
.SetTextForeground(* m_textColour
);
87 // For efficiency, don't do this under X - doesn't make
88 // any visible difference for our purposes.
90 dc
.SetTextBackground(m_brush
->GetColour());
99 if (GetDisableLabel()) return;
103 dc
.SetBackgroundMode(wxTRANSPARENT
);
105 wxNode
*node
= GetRegions().GetFirst();
108 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
109 dc
.SetFont(* region
->GetFont());
110 dc
.SetTextForeground(* region
->GetActualColourObject());
113 region
->m_regionProportionY
< 0.0 ? defaultProportion
: region
->m_regionProportionY
;
115 double y
= currentY
+ m_height
*proportion
;
116 double actualY
= maxY
< y
? maxY
: y
;
118 double centreX
= m_xpos
;
119 double centreY
= (double)(currentY
+ (actualY
- currentY
)/2.0);
121 oglDrawFormattedText(dc
, ®ion
->m_formattedText
,
122 (double)(centreX
), (double)(centreY
), (double)(m_width
-2*xMargin
), (double)(actualY
- currentY
- 2*yMargin
),
123 region
->m_formatMode
);
124 if ((y
<= maxY
) && (node
->GetNext()))
126 wxPen
*regionPen
= region
->GetActualPen();
129 dc
.SetPen(* regionPen
);
130 dc
.DrawLine(WXROUND(leftX
), WXROUND(y
), WXROUND(rightX
), WXROUND(y
));
136 node
= node
->GetNext();
140 void wxDividedShape::SetSize(double w
, double h
, bool recursive
)
142 SetAttachmentSize(w
, h
);
148 void wxDividedShape::SetRegionSizes()
150 if (GetRegions().GetCount() == 0)
153 double defaultProportion
= (double)(GetRegions().GetCount() > 0 ? (1.0/((double)(GetRegions().GetCount()))) : 0.0);
154 double currentY
= (double)(m_ypos
- (m_height
/ 2.0));
155 double maxY
= (double)(m_ypos
+ (m_height
/ 2.0));
157 // double leftX = (double)(m_xpos - (m_width / 2.0));
158 // double rightX = (double)(m_xpos + (m_width / 2.0));
160 wxNode
*node
= GetRegions().GetFirst();
163 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
165 region
->m_regionProportionY
<= 0.0 ? defaultProportion
: region
->m_regionProportionY
;
167 double sizeY
= (double)proportion
*m_height
;
168 double y
= currentY
+ sizeY
;
169 double actualY
= maxY
< y
? maxY
: y
;
171 double centreY
= (double)(currentY
+ (actualY
- currentY
)/2.0);
173 region
->SetSize(m_width
, sizeY
);
174 region
->SetPosition(0.0, (double)(centreY
- m_ypos
));
176 node
= node
->GetNext();
180 // Attachment points correspond to regions in the divided box
181 bool wxDividedShape::GetAttachmentPosition(int attachment
, double *x
, double *y
, int nth
, int no_arcs
,
184 int totalNumberAttachments
= (GetRegions().GetCount() * 2) + 2;
185 if ((GetAttachmentMode() == ATTACHMENT_MODE_NONE
) || (attachment
>= totalNumberAttachments
))
187 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
);
190 int n
= GetRegions().GetCount();
191 bool isEnd
= (line
&& line
->IsEnd(this));
193 double left
= (double)(m_xpos
- m_width
/2.0);
194 double right
= (double)(m_xpos
+ m_width
/2.0);
195 double top
= (double)(m_ypos
- m_height
/2.0);
196 double bottom
= (double)(m_ypos
+ m_height
/2.0);
198 // Zero is top, n+1 is bottom.
202 if (m_spaceAttachments
)
204 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
206 // Align line according to the next handle along
207 wxRealPoint
*point
= line
->GetNextControlPoint(this);
210 else if (point
->x
> right
)
216 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
221 else if (attachment
== (n
+1))
224 if (m_spaceAttachments
)
226 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
228 // Align line according to the next handle along
229 wxRealPoint
*point
= line
->GetNextControlPoint(this);
232 else if (point
->x
> right
)
238 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
248 if (attachment
< (n
+1))
255 i
= (totalNumberAttachments
- attachment
- 1);
258 wxNode
*node
= GetRegions().Item(i
);
261 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
268 // Calculate top and bottom of region
269 top
= (double)((m_ypos
+ region
->m_y
) - (region
->m_height
/2.0));
270 bottom
= (double)((m_ypos
+ region
->m_y
) + (region
->m_height
/2.0));
272 // Assuming we can trust the absolute size and
273 // position of these regions...
274 if (m_spaceAttachments
)
276 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
278 // Align line according to the next handle along
279 wxRealPoint
*point
= line
->GetNextControlPoint(this);
280 if (point
->y
< bottom
)
282 else if (point
->y
> top
)
288 // *y = (double)(((m_ypos + region->m_y) - (region->m_height/2.0)) + (nth + 1)*region->m_height/(no_arcs+1));
289 *y
= (double)(top
+ (nth
+ 1)*region
->m_height
/(no_arcs
+1));
292 *y
= (double)(m_ypos
+ region
->m_y
);
304 int wxDividedShape::GetNumberOfAttachments() const
306 // There are two attachments for each region (left and right),
307 // plus one on the top and one on the bottom.
308 int n
= (GetRegions().GetCount() * 2) + 2;
311 wxNode
*node
= m_attachmentPoints
.GetFirst();
314 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
315 if (point
->m_id
> maxN
)
317 node
= node
->GetNext();
322 bool wxDividedShape::AttachmentIsValid(int attachment
) const
324 int totalNumberAttachments
= (GetRegions().GetCount() * 2) + 2;
325 if (attachment
>= totalNumberAttachments
)
327 return wxShape::AttachmentIsValid(attachment
);
329 else if (attachment
>= 0)
335 void wxDividedShape::Copy(wxShape
& copy
)
337 wxRectangleShape::Copy(copy
);
342 void wxDividedShape::MakeControlPoints()
344 wxRectangleShape::MakeControlPoints();
346 MakeMandatoryControlPoints();
349 void wxDividedShape::MakeMandatoryControlPoints()
351 double currentY
= (double)(GetY() - (m_height
/ 2.0));
352 double maxY
= (double)(GetY() + (m_height
/ 2.0));
354 wxNode
*node
= GetRegions().GetFirst();
358 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
360 double proportion
= region
->m_regionProportionY
;
362 double y
= currentY
+ m_height
*proportion
;
363 double actualY
= (double)(maxY
< y
? maxY
: y
);
367 wxDividedShapeControlPoint
*controlPoint
=
368 new wxDividedShapeControlPoint(m_canvas
, this, i
, CONTROL_POINT_SIZE
, 0.0, (double)(actualY
- GetY()), 0);
369 m_canvas
->AddShape(controlPoint
);
370 m_controlPoints
.Append(controlPoint
);
374 node
= node
->GetNext();
378 void wxDividedShape::ResetControlPoints()
380 // May only have the region handles, (n - 1) of them.
381 if (m_controlPoints
.GetCount() > (GetRegions().GetCount() - 1))
382 wxRectangleShape::ResetControlPoints();
384 ResetMandatoryControlPoints();
387 void wxDividedShape::ResetMandatoryControlPoints()
389 double currentY
= (double)(GetY() - (m_height
/ 2.0));
390 double maxY
= (double)(GetY() + (m_height
/ 2.0));
392 wxNode
*node
= m_controlPoints
.GetFirst();
396 wxControlPoint
*controlPoint
= (wxControlPoint
*)node
->GetData();
397 if (controlPoint
->IsKindOf(CLASSINFO(wxDividedShapeControlPoint
)))
399 wxNode
*node1
= GetRegions().Item(i
);
400 wxShapeRegion
*region
= (wxShapeRegion
*)node1
->GetData();
402 double proportion
= region
->m_regionProportionY
;
404 double y
= currentY
+ m_height
*proportion
;
405 double actualY
= (double)(maxY
< y
? maxY
: y
);
407 controlPoint
->m_xoffset
= 0.0;
408 controlPoint
->m_yoffset
= (double)(actualY
- GetY());
412 node
= node
->GetNext();
417 void wxDividedShape::WriteAttributes(wxExpr
*clause
)
419 wxRectangleShape::WriteAttributes(clause
);
422 void wxDividedShape::ReadAttributes(wxExpr
*clause
)
424 wxRectangleShape::ReadAttributes(clause
);
429 * Edit the division colour/style
433 void wxDividedShape::EditRegions()
435 wxMessageBox(wxT("EditRegions() is unimplemented."), wxT("OGL"), wxOK
);
439 if (GetRegions().GetCount() < 2)
444 GraphicsForm
*form
= new GraphicsForm("Divided nodes");
445 // Need an array to store all the style strings,
446 // since they need to be converted to integers
447 char **styleStrings
= new char *[GetRegions().GetCount()];
448 for (int j
= 0; j
< GetRegions().GetCount(); j
++)
449 styleStrings
[j
] = NULL
;
452 wxNode
*node
= GetRegions().GetFirst();
453 while (node
&& node
->GetNext())
455 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
457 sprintf(buf
, "Region %d", (i
+1));
458 form
->Add(wxMakeFormMessage(buf
));
459 form
->Add(wxMakeFormNewLine());
461 form
->Add(wxMakeFormString("Colour", ®ion
->penColour
, wxFORM_CHOICE
,
462 new wxList(wxMakeConstraintStrings(
487 NULL
), NULL
, wxVERTICAL
, 150));
489 char *styleString
= NULL
;
490 switch (region
->penStyle
)
493 styleString
= "Short Dash";
496 styleString
= "Long Dash";
502 styleString
= "Dot Dash";
506 styleString
= "Solid";
509 styleStrings
[i
] = copystring(styleString
);
510 form
->Add(wxMakeFormString("Style", &(styleStrings
[i
]), wxFORM_CHOICE
,
511 new wxList(wxMakeConstraintStrings(
518 NULL
), NULL
, wxVERTICAL
, 100));
519 node
= node
->GetNext();
521 if (node
&& node
->GetNext())
522 form
->Add(wxMakeFormNewLine());
524 wxDialogBox
*dialog
= new wxDialogBox(m_canvas
->GetParent(), "Divided object properties", 10, 10, 500, 500);
525 if (GraphicsLabelFont
)
526 dialog
->SetLabelFont(GraphicsLabelFont
);
527 if (GraphicsButtonFont
)
528 dialog
->SetButtonFont(GraphicsButtonFont
);
529 form
->AssociatePanel(dialog
);
530 form
->dialog
= dialog
;
533 dialog
->Centre(wxBOTH
);
539 node
= GetRegions().GetFirst();
543 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
547 if (strcmp(styleStrings
[i
], "Solid") == 0)
548 region
->penStyle
= wxSOLID
;
549 else if (strcmp(styleStrings
[i
], "Dot") == 0)
550 region
->penStyle
= wxDOT
;
551 else if (strcmp(styleStrings
[i
], "Short Dash") == 0)
552 region
->penStyle
= wxSHORT_DASH
;
553 else if (strcmp(styleStrings
[i
], "Long Dash") == 0)
554 region
->penStyle
= wxLONG_DASH
;
555 else if (strcmp(styleStrings
[i
], "Dot Dash") == 0)
556 region
->penStyle
= wxDOT_DASH
;
557 delete[] styleStrings
[i
];
559 region
->m_actualPenObject
= NULL
;
560 node
= node
->GetNext();
563 delete[] styleStrings
;
568 void wxDividedShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
576 wxRectangleShape::OnRightClick(x
, y
, keys
, attachment
);
580 wxDividedShapeControlPoint::wxDividedShapeControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
,
581 int region
, double size
, double the_m_xoffset
, double the_m_yoffset
, int the_type
):
582 wxControlPoint(the_canvas
, object
, size
, the_m_xoffset
, the_m_yoffset
, the_type
)
587 wxDividedShapeControlPoint::~wxDividedShapeControlPoint()
591 // Implement resizing of divided object division
592 void wxDividedShapeControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
594 wxClientDC
dc(GetCanvas());
595 GetCanvas()->PrepareDC(dc
);
597 dc
.SetLogicalFunction(OGLRBLF
);
598 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
599 dc
.SetPen(dottedPen
);
600 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
602 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
603 double x1
= (double)(dividedObject
->GetX() - (dividedObject
->GetWidth()/2.0));
605 double x2
= (double)(dividedObject
->GetX() + (dividedObject
->GetWidth()/2.0));
607 dc
.DrawLine(WXROUND(x1
), WXROUND(y1
), WXROUND(x2
), WXROUND(y2
));
610 void wxDividedShapeControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
612 wxClientDC
dc(GetCanvas());
613 GetCanvas()->PrepareDC(dc
);
615 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
616 dc
.SetLogicalFunction(OGLRBLF
);
617 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
618 dc
.SetPen(dottedPen
);
619 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
621 double x1
= (double)(dividedObject
->GetX() - (dividedObject
->GetWidth()/2.0));
623 double x2
= (double)(dividedObject
->GetX() + (dividedObject
->GetWidth()/2.0));
625 dc
.DrawLine(WXROUND(x1
), WXROUND(y1
), WXROUND(x2
), WXROUND(y2
));
626 m_canvas
->CaptureMouse();
629 void wxDividedShapeControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
631 wxClientDC
dc(GetCanvas());
632 GetCanvas()->PrepareDC(dc
);
634 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
635 wxNode
*node
= dividedObject
->GetRegions().Item(regionId
);
639 wxShapeRegion
*thisRegion
= (wxShapeRegion
*)node
->GetData();
640 wxShapeRegion
*nextRegion
= NULL
; // Region below this one
642 dc
.SetLogicalFunction(wxCOPY
);
644 m_canvas
->ReleaseMouse();
646 // Find the old top and bottom of this region,
647 // and calculate the new proportion for this region
650 double currentY
= (double)(dividedObject
->GetY() - (dividedObject
->GetHeight() / 2.0));
651 double maxY
= (double)(dividedObject
->GetY() + (dividedObject
->GetHeight() / 2.0));
654 double thisRegionTop
= 0.0;
655 double thisRegionBottom
= 0.0;
656 double nextRegionBottom
= 0.0;
658 node
= dividedObject
->GetRegions().GetFirst();
661 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
663 double proportion
= region
->m_regionProportionY
;
664 double yy
= currentY
+ (dividedObject
->GetHeight()*proportion
);
665 double actualY
= (double)(maxY
< yy
? maxY
: yy
);
667 if (region
== thisRegion
)
669 thisRegionTop
= currentY
;
670 thisRegionBottom
= actualY
;
672 nextRegion
= (wxShapeRegion
*)node
->GetNext()->GetData();
674 if (region
== nextRegion
)
676 nextRegionBottom
= actualY
;
680 node
= node
->GetNext();
685 // Check that we haven't gone above this region or below
687 if ((y
<= thisRegionTop
) || (y
>= nextRegionBottom
))
690 dividedObject
->EraseLinks(dc
);
692 // Now calculate the new proportions of this region and the next region.
693 double thisProportion
= (double)((y
- thisRegionTop
)/dividedObject
->GetHeight());
694 double nextProportion
= (double)((nextRegionBottom
- y
)/dividedObject
->GetHeight());
695 thisRegion
->SetProportions(0.0, thisProportion
);
696 nextRegion
->SetProportions(0.0, nextProportion
);
697 m_yoffset
= (double)(y
- dividedObject
->GetY());
701 node
= dividedObject
->GetRegions().GetFirst();
704 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
705 if (region
->GetText())
707 wxChar
*s
= copystring(region
->GetText());
708 dividedObject
->FormatText(dc
, s
, i
);
711 node
= node
->GetNext();
714 dividedObject
->SetRegionSizes();
715 dividedObject
->Draw(dc
);
716 dividedObject
->GetEventHandler()->OnMoveLinks(dc
);