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 WXUNUSED(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);
246 bool isLeft
= !(attachment
< (n
+1));
247 int i
= (isLeft
) ? (totalNumberAttachments
- attachment
- 1) : (attachment
-1);
248 wxNode
*node
= GetRegions().Item(i
);
251 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
258 // Calculate top and bottom of region
259 top
= (double)((m_ypos
+ region
->m_y
) - (region
->m_height
/2.0));
260 bottom
= (double)((m_ypos
+ region
->m_y
) + (region
->m_height
/2.0));
262 // Assuming we can trust the absolute size and
263 // position of these regions...
264 if (m_spaceAttachments
)
266 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
268 // Align line according to the next handle along
269 wxRealPoint
*point
= line
->GetNextControlPoint(this);
270 if (point
->y
< bottom
)
272 else if (point
->y
> top
)
278 // *y = (double)(((m_ypos + region->m_y) - (region->m_height/2.0)) + (nth + 1)*region->m_height/(no_arcs+1));
279 *y
= (double)(top
+ (nth
+ 1)*region
->m_height
/(no_arcs
+1));
282 *y
= (double)(m_ypos
+ region
->m_y
);
294 int wxDividedShape::GetNumberOfAttachments() const
296 // There are two attachments for each region (left and right),
297 // plus one on the top and one on the bottom.
298 int n
= (GetRegions().GetCount() * 2) + 2;
301 wxNode
*node
= m_attachmentPoints
.GetFirst();
304 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
305 if (point
->m_id
> maxN
)
307 node
= node
->GetNext();
312 bool wxDividedShape::AttachmentIsValid(int attachment
) const
314 int totalNumberAttachments
= (GetRegions().GetCount() * 2) + 2;
315 if (attachment
>= totalNumberAttachments
)
317 return wxShape::AttachmentIsValid(attachment
);
319 else if (attachment
>= 0)
325 void wxDividedShape::Copy(wxShape
& copy
)
327 wxRectangleShape::Copy(copy
);
332 void wxDividedShape::MakeControlPoints()
334 wxRectangleShape::MakeControlPoints();
336 MakeMandatoryControlPoints();
339 void wxDividedShape::MakeMandatoryControlPoints()
341 double currentY
= (double)(GetY() - (m_height
/ 2.0));
342 double maxY
= (double)(GetY() + (m_height
/ 2.0));
344 wxNode
*node
= GetRegions().GetFirst();
348 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
350 double proportion
= region
->m_regionProportionY
;
352 double y
= currentY
+ m_height
*proportion
;
353 double actualY
= (double)(maxY
< y
? maxY
: y
);
357 wxDividedShapeControlPoint
*controlPoint
=
358 new wxDividedShapeControlPoint(m_canvas
, this, i
, CONTROL_POINT_SIZE
, 0.0, (double)(actualY
- GetY()), 0);
359 m_canvas
->AddShape(controlPoint
);
360 m_controlPoints
.Append(controlPoint
);
364 node
= node
->GetNext();
368 void wxDividedShape::ResetControlPoints()
370 // May only have the region handles, (n - 1) of them.
371 if (m_controlPoints
.GetCount() > (GetRegions().GetCount() - 1))
372 wxRectangleShape::ResetControlPoints();
374 ResetMandatoryControlPoints();
377 void wxDividedShape::ResetMandatoryControlPoints()
379 double currentY
= (double)(GetY() - (m_height
/ 2.0));
380 double maxY
= (double)(GetY() + (m_height
/ 2.0));
382 wxNode
*node
= m_controlPoints
.GetFirst();
386 wxControlPoint
*controlPoint
= (wxControlPoint
*)node
->GetData();
387 if (controlPoint
->IsKindOf(CLASSINFO(wxDividedShapeControlPoint
)))
389 wxNode
*node1
= GetRegions().Item(i
);
390 wxShapeRegion
*region
= (wxShapeRegion
*)node1
->GetData();
392 double proportion
= region
->m_regionProportionY
;
394 double y
= currentY
+ m_height
*proportion
;
395 double actualY
= (double)(maxY
< y
? maxY
: y
);
397 controlPoint
->m_xoffset
= 0.0;
398 controlPoint
->m_yoffset
= (double)(actualY
- GetY());
402 node
= node
->GetNext();
407 void wxDividedShape::WriteAttributes(wxExpr
*clause
)
409 wxRectangleShape::WriteAttributes(clause
);
412 void wxDividedShape::ReadAttributes(wxExpr
*clause
)
414 wxRectangleShape::ReadAttributes(clause
);
419 * Edit the division colour/style
423 void wxDividedShape::EditRegions()
425 wxMessageBox(wxT("EditRegions() is unimplemented."), wxT("OGL"), wxOK
);
429 if (GetRegions().GetCount() < 2)
434 GraphicsForm
*form
= new GraphicsForm("Divided nodes");
435 // Need an array to store all the style strings,
436 // since they need to be converted to integers
437 char **styleStrings
= new char *[GetRegions().GetCount()];
438 for (int j
= 0; j
< GetRegions().GetCount(); j
++)
439 styleStrings
[j
] = NULL
;
442 wxNode
*node
= GetRegions().GetFirst();
443 while (node
&& node
->GetNext())
445 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
447 sprintf(buf
, "Region %d", (i
+1));
448 form
->Add(wxMakeFormMessage(buf
));
449 form
->Add(wxMakeFormNewLine());
451 form
->Add(wxMakeFormString("Colour", ®ion
->penColour
, wxFORM_CHOICE
,
452 new wxList(wxMakeConstraintStrings(
477 NULL
), NULL
, wxVERTICAL
, 150));
479 char *styleString
= NULL
;
480 switch (region
->penStyle
)
483 styleString
= "Short Dash";
486 styleString
= "Long Dash";
492 styleString
= "Dot Dash";
496 styleString
= "Solid";
499 styleStrings
[i
] = copystring(styleString
);
500 form
->Add(wxMakeFormString("Style", &(styleStrings
[i
]), wxFORM_CHOICE
,
501 new wxList(wxMakeConstraintStrings(
508 NULL
), NULL
, wxVERTICAL
, 100));
509 node
= node
->GetNext();
511 if (node
&& node
->GetNext())
512 form
->Add(wxMakeFormNewLine());
514 wxDialogBox
*dialog
= new wxDialogBox(m_canvas
->GetParent(), "Divided object properties", 10, 10, 500, 500);
515 if (GraphicsLabelFont
)
516 dialog
->SetLabelFont(GraphicsLabelFont
);
517 if (GraphicsButtonFont
)
518 dialog
->SetButtonFont(GraphicsButtonFont
);
519 form
->AssociatePanel(dialog
);
520 form
->dialog
= dialog
;
523 dialog
->Centre(wxBOTH
);
529 node
= GetRegions().GetFirst();
533 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
537 if (strcmp(styleStrings
[i
], "Solid") == 0)
538 region
->penStyle
= wxSOLID
;
539 else if (strcmp(styleStrings
[i
], "Dot") == 0)
540 region
->penStyle
= wxDOT
;
541 else if (strcmp(styleStrings
[i
], "Short Dash") == 0)
542 region
->penStyle
= wxSHORT_DASH
;
543 else if (strcmp(styleStrings
[i
], "Long Dash") == 0)
544 region
->penStyle
= wxLONG_DASH
;
545 else if (strcmp(styleStrings
[i
], "Dot Dash") == 0)
546 region
->penStyle
= wxDOT_DASH
;
547 delete[] styleStrings
[i
];
549 region
->m_actualPenObject
= NULL
;
550 node
= node
->GetNext();
553 delete[] styleStrings
;
558 void wxDividedShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
566 wxRectangleShape::OnRightClick(x
, y
, keys
, attachment
);
570 wxDividedShapeControlPoint::wxDividedShapeControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
,
571 int region
, double size
, double the_m_xoffset
, double the_m_yoffset
, int the_type
):
572 wxControlPoint(the_canvas
, object
, size
, the_m_xoffset
, the_m_yoffset
, the_type
)
577 wxDividedShapeControlPoint::~wxDividedShapeControlPoint()
581 // Implement resizing of divided object division
582 void wxDividedShapeControlPoint::OnDragLeft(bool WXUNUSED(draw
), double WXUNUSED(x
), double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
584 wxClientDC
dc(GetCanvas());
585 GetCanvas()->PrepareDC(dc
);
587 dc
.SetLogicalFunction(OGLRBLF
);
588 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
589 dc
.SetPen(dottedPen
);
590 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
592 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
593 double x1
= (double)(dividedObject
->GetX() - (dividedObject
->GetWidth()/2.0));
595 double x2
= (double)(dividedObject
->GetX() + (dividedObject
->GetWidth()/2.0));
597 dc
.DrawLine(WXROUND(x1
), WXROUND(y1
), WXROUND(x2
), WXROUND(y2
));
600 void wxDividedShapeControlPoint::OnBeginDragLeft(double WXUNUSED(x
), double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
602 wxClientDC
dc(GetCanvas());
603 GetCanvas()->PrepareDC(dc
);
605 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
606 dc
.SetLogicalFunction(OGLRBLF
);
607 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
608 dc
.SetPen(dottedPen
);
609 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
611 double x1
= (double)(dividedObject
->GetX() - (dividedObject
->GetWidth()/2.0));
613 double x2
= (double)(dividedObject
->GetX() + (dividedObject
->GetWidth()/2.0));
615 dc
.DrawLine(WXROUND(x1
), WXROUND(y1
), WXROUND(x2
), WXROUND(y2
));
616 m_canvas
->CaptureMouse();
619 void wxDividedShapeControlPoint::OnEndDragLeft(double WXUNUSED(x
), double y
, int WXUNUSED(keys
), int WXUNUSED(attachment
))
621 wxClientDC
dc(GetCanvas());
622 GetCanvas()->PrepareDC(dc
);
624 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
625 wxNode
*node
= dividedObject
->GetRegions().Item(regionId
);
629 wxShapeRegion
*thisRegion
= (wxShapeRegion
*)node
->GetData();
630 wxShapeRegion
*nextRegion
= NULL
; // Region below this one
632 dc
.SetLogicalFunction(wxCOPY
);
634 m_canvas
->ReleaseMouse();
636 // Find the old top and bottom of this region,
637 // and calculate the new proportion for this region
640 double currentY
= (double)(dividedObject
->GetY() - (dividedObject
->GetHeight() / 2.0));
641 double maxY
= (double)(dividedObject
->GetY() + (dividedObject
->GetHeight() / 2.0));
644 double thisRegionTop
= 0.0;
646 // this variable is not readed later
647 double thisRegionBottom
= 0.0;
649 double nextRegionBottom
= 0.0;
651 node
= dividedObject
->GetRegions().GetFirst();
654 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
656 double proportion
= region
->m_regionProportionY
;
657 double yy
= currentY
+ (dividedObject
->GetHeight()*proportion
);
658 double actualY
= (double)(maxY
< yy
? maxY
: yy
);
660 if (region
== thisRegion
)
662 thisRegionTop
= currentY
;
664 // no need for assignment if value is not used later
665 thisRegionBottom
= actualY
;
668 nextRegion
= (wxShapeRegion
*)node
->GetNext()->GetData();
670 if (region
== nextRegion
)
672 nextRegionBottom
= actualY
;
676 node
= node
->GetNext();
681 // Check that we haven't gone above this region or below
683 if ((y
<= thisRegionTop
) || (y
>= nextRegionBottom
))
686 dividedObject
->EraseLinks(dc
);
688 // Now calculate the new proportions of this region and the next region.
689 double thisProportion
= (double)((y
- thisRegionTop
)/dividedObject
->GetHeight());
690 double nextProportion
= (double)((nextRegionBottom
- y
)/dividedObject
->GetHeight());
691 thisRegion
->SetProportions(0.0, thisProportion
);
692 nextRegion
->SetProportions(0.0, nextProportion
);
693 m_yoffset
= (double)(y
- dividedObject
->GetY());
697 node
= dividedObject
->GetRegions().GetFirst();
700 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
701 if (region
->GetText())
703 wxChar
*s
= copystring(region
->GetText());
704 dividedObject
->FormatText(dc
, s
, i
);
707 node
= node
->GetNext();
710 dividedObject
->SetRegionSizes();
711 dividedObject
->Draw(dc
);
712 dividedObject
->GetEventHandler()->OnMoveLinks(dc
);