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/wxexpr.h>
38 class wxDividedShapeControlPoint
: public wxControlPoint
40 DECLARE_DYNAMIC_CLASS(wxDividedShapeControlPoint
)
44 wxDividedShapeControlPoint() { regionId
= 0; }
45 wxDividedShapeControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
, int region
,
46 float size
, float the_xoffset
, float the_yoffset
, int the_type
);
47 ~wxDividedShapeControlPoint();
49 void OnDragLeft(bool draw
, float x
, float y
, int keys
=0, int attachment
= 0);
50 void OnBeginDragLeft(float x
, float y
, int keys
=0, int attachment
= 0);
51 void OnEndDragLeft(float x
, float y
, int keys
=0, int attachment
= 0);
54 IMPLEMENT_DYNAMIC_CLASS(wxDividedShapeControlPoint
, wxControlPoint
)
61 IMPLEMENT_DYNAMIC_CLASS(wxDividedShape
, wxRectangleShape
)
63 wxDividedShape::wxDividedShape(float w
, float h
): wxRectangleShape(w
, h
)
68 wxDividedShape::~wxDividedShape()
72 void wxDividedShape::OnDraw(wxDC
& dc
)
74 wxRectangleShape::OnDraw(dc
);
77 void wxDividedShape::OnDrawContents(wxDC
& dc
)
79 float defaultProportion
= (float)(GetRegions().Number() > 0 ? (1.0/((float)(GetRegions().Number()))) : 0.0);
80 float currentY
= (float)(m_ypos
- (m_height
/ 2.0));
81 float maxY
= (float)(m_ypos
+ (m_height
/ 2.0));
83 float leftX
= (float)(m_xpos
- (m_width
/ 2.0));
84 float rightX
= (float)(m_xpos
+ (m_width
/ 2.0));
86 if (m_pen
) dc
.SetPen(m_pen
);
88 if (m_textColour
) dc
.SetTextForeground(* m_textColour
);
91 // For efficiency, don't do this under X - doesn't make
92 // any visible difference for our purposes.
94 dc
.SetTextBackground(m_brush
->GetColour());
103 if (GetDisableLabel()) return;
107 dc
.SetBackgroundMode(wxTRANSPARENT
);
109 wxNode
*node
= GetRegions().First();
112 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
113 dc
.SetFont(region
->GetFont());
114 dc
.SetTextForeground(* region
->GetActualColourObject());
117 region
->m_regionProportionY
< 0.0 ? defaultProportion
: region
->m_regionProportionY
;
119 float y
= currentY
+ m_height
*proportion
;
120 float actualY
= maxY
< y
? maxY
: y
;
122 float centreX
= m_xpos
;
123 float centreY
= (float)(currentY
+ (actualY
- currentY
)/2.0);
125 DrawFormattedText(dc
, ®ion
->m_formattedText
,
126 (float)(centreX
), (float)(centreY
), (float)(m_width
-2*xMargin
), (float)(actualY
- currentY
- 2*yMargin
),
127 region
->m_formatMode
);
128 if ((y
<= maxY
) && (node
->Next()))
130 wxPen
*regionPen
= region
->GetActualPen();
133 dc
.SetPen(regionPen
);
134 dc
.DrawLine(leftX
, y
, rightX
, y
);
144 void wxDividedShape::SetSize(float w
, float h
, bool recursive
)
146 SetAttachmentSize(w
, h
);
152 void wxDividedShape::SetRegionSizes()
154 if (GetRegions().Number() == 0)
157 float defaultProportion
= (float)(GetRegions().Number() > 0 ? (1.0/((float)(GetRegions().Number()))) : 0.0);
158 float currentY
= (float)(m_ypos
- (m_height
/ 2.0));
159 float maxY
= (float)(m_ypos
+ (m_height
/ 2.0));
161 // float leftX = (float)(m_xpos - (m_width / 2.0));
162 // float rightX = (float)(m_xpos + (m_width / 2.0));
164 wxNode
*node
= GetRegions().First();
167 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
169 region
->m_regionProportionY
<= 0.0 ? defaultProportion
: region
->m_regionProportionY
;
171 float sizeY
= (float)proportion
*m_height
;
172 float y
= currentY
+ sizeY
;
173 float actualY
= maxY
< y
? maxY
: y
;
175 float centreY
= (float)(currentY
+ (actualY
- currentY
)/2.0);
177 region
->SetSize(m_width
, sizeY
);
178 region
->SetPosition(0.0, (float)(centreY
- m_ypos
));
184 // Attachment points correspond to regions in the divided box
185 bool wxDividedShape::GetAttachmentPosition(int attachment
, float *x
, float *y
, int nth
, int no_arcs
,
188 int totalNumberAttachments
= (GetRegions().Number() * 2) + 2;
189 if (!GetAttachmentMode() || (attachment
>= totalNumberAttachments
))
191 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
);
194 int n
= GetRegions().Number();
195 bool isEnd
= (line
&& line
->IsEnd(this));
197 float left
= (float)(m_xpos
- m_width
/2.0);
198 float right
= (float)(m_xpos
+ m_width
/2.0);
199 float top
= (float)(m_ypos
- m_height
/2.0);
200 float bottom
= (float)(m_ypos
+ m_height
/2.0);
202 // Zero is top, n+1 is bottom.
206 if (m_spaceAttachments
)
208 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
210 // Align line according to the next handle along
211 wxRealPoint
*point
= line
->GetNextControlPoint(this);
214 else if (point
->x
> right
)
220 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
225 else if (attachment
== (n
+1))
228 if (m_spaceAttachments
)
230 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
232 // Align line according to the next handle along
233 wxRealPoint
*point
= line
->GetNextControlPoint(this);
236 else if (point
->x
> right
)
242 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
252 if (attachment
< (n
+1))
259 i
= (totalNumberAttachments
- attachment
- 1);
262 wxNode
*node
= GetRegions().Nth(i
);
265 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
272 // Calculate top and bottom of region
273 top
= (float)((m_ypos
+ region
->m_y
) - (region
->m_height
/2.0));
274 bottom
= (float)((m_ypos
+ region
->m_y
) + (region
->m_height
/2.0));
276 // Assuming we can trust the absolute size and
277 // position of these regions...
278 if (m_spaceAttachments
)
280 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
282 // Align line according to the next handle along
283 wxRealPoint
*point
= line
->GetNextControlPoint(this);
284 if (point
->y
< bottom
)
286 else if (point
->y
> top
)
292 // *y = (float)(((m_ypos + region->m_y) - (region->m_height/2.0)) + (nth + 1)*region->m_height/(no_arcs+1));
293 *y
= (float)(top
+ (nth
+ 1)*region
->m_height
/(no_arcs
+1));
296 *y
= (float)(m_ypos
+ region
->m_y
);
308 int wxDividedShape::GetNumberOfAttachments()
310 // There are two attachments for each region (left and right),
311 // plus one on the top and one on the bottom.
312 int n
= (GetRegions().Number() * 2) + 2;
315 wxNode
*node
= m_attachmentPoints
.First();
318 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
319 if (point
->m_id
> maxN
)
326 bool wxDividedShape::AttachmentIsValid(int attachment
)
328 int totalNumberAttachments
= (GetRegions().Number() * 2) + 2;
329 if (attachment
>= totalNumberAttachments
)
331 return wxShape::AttachmentIsValid(attachment
);
333 else if (attachment
>= 0)
339 void wxDividedShape::Copy(wxDividedShape
& copy
)
341 wxRectangleShape::Copy(copy
);
344 wxShape
*wxDividedShape::PrivateCopy()
346 wxDividedShape
*obj
= new wxDividedShape(m_width
, m_height
);
353 void wxDividedShape::MakeControlPoints()
355 wxRectangleShape::MakeControlPoints();
357 MakeMandatoryControlPoints();
360 void wxDividedShape::MakeMandatoryControlPoints()
362 float currentY
= (float)(GetY() - (m_height
/ 2.0));
363 float maxY
= (float)(GetY() + (m_height
/ 2.0));
365 wxNode
*node
= GetRegions().First();
369 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
371 float proportion
= region
->m_regionProportionY
;
373 float y
= currentY
+ m_height
*proportion
;
374 float actualY
= (float)(maxY
< y
? maxY
: y
);
378 wxDividedShapeControlPoint
*controlPoint
=
379 new wxDividedShapeControlPoint(m_canvas
, this, i
, CONTROL_POINT_SIZE
, 0.0, (float)(actualY
- GetY()), 0);
380 m_canvas
->AddShape(controlPoint
);
381 m_controlPoints
.Append(controlPoint
);
389 void wxDividedShape::ResetControlPoints()
391 // May only have the region handles, (n - 1) of them.
392 if (m_controlPoints
.Number() > (GetRegions().Number() - 1))
393 wxRectangleShape::ResetControlPoints();
395 ResetMandatoryControlPoints();
398 void wxDividedShape::ResetMandatoryControlPoints()
400 float currentY
= (float)(GetY() - (m_height
/ 2.0));
401 float maxY
= (float)(GetY() + (m_height
/ 2.0));
403 wxNode
*node
= m_controlPoints
.First();
407 wxControlPoint
*controlPoint
= (wxControlPoint
*)node
->Data();
408 if (controlPoint
->IsKindOf(CLASSINFO(wxDividedShapeControlPoint
)))
410 wxNode
*node1
= GetRegions().Nth(i
);
411 wxShapeRegion
*region
= (wxShapeRegion
*)node1
->Data();
413 float proportion
= region
->m_regionProportionY
;
415 float y
= currentY
+ m_height
*proportion
;
416 float actualY
= (float)(maxY
< y
? maxY
: y
);
418 controlPoint
->m_xoffset
= 0.0;
419 controlPoint
->m_yoffset
= (float)(actualY
- GetY());
428 void wxDividedShape::WritePrologAttributes(wxExpr
*clause
)
430 wxRectangleShape::WritePrologAttributes(clause
);
433 void wxDividedShape::ReadPrologAttributes(wxExpr
*clause
)
435 wxRectangleShape::ReadPrologAttributes(clause
);
440 * Edit the division colour/style
444 void wxDividedShape::EditRegions()
446 wxMessageBox("EditRegions() is unimplemented.", "OGL", wxOK
);
450 if (GetRegions().Number() < 2)
455 GraphicsForm
*form
= new GraphicsForm("Divided nodes");
456 // Need an array to store all the style strings,
457 // since they need to be converted to integers
458 char **styleStrings
= new char *[GetRegions().Number()];
459 for (int j
= 0; j
< GetRegions().Number(); j
++)
460 styleStrings
[j
] = NULL
;
463 wxNode
*node
= GetRegions().First();
464 while (node
&& node
->Next())
466 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
468 sprintf(buf
, "Region %d", (i
+1));
469 form
->Add(wxMakeFormMessage(buf
));
470 form
->Add(wxMakeFormNewLine());
472 form
->Add(wxMakeFormString("Colour", ®ion
->penColour
, wxFORM_CHOICE
,
473 new wxList(wxMakeConstraintStrings(
498 NULL
), NULL
, wxVERTICAL
, 150));
500 char *styleString
= NULL
;
501 switch (region
->penStyle
)
504 styleString
= "Short Dash";
507 styleString
= "Long Dash";
513 styleString
= "Dot Dash";
517 styleString
= "Solid";
520 styleStrings
[i
] = copystring(styleString
);
521 form
->Add(wxMakeFormString("Style", &(styleStrings
[i
]), wxFORM_CHOICE
,
522 new wxList(wxMakeConstraintStrings(
529 NULL
), NULL
, wxVERTICAL
, 100));
532 if (node
&& node
->Next())
533 form
->Add(wxMakeFormNewLine());
535 wxDialogBox
*dialog
= new wxDialogBox(m_canvas
->GetParent(), "Divided object properties", 10, 10, 500, 500);
536 if (GraphicsLabelFont
)
537 dialog
->SetLabelFont(GraphicsLabelFont
);
538 if (GraphicsButtonFont
)
539 dialog
->SetButtonFont(GraphicsButtonFont
);
540 form
->AssociatePanel(dialog
);
541 form
->dialog
= dialog
;
544 dialog
->Centre(wxBOTH
);
550 node
= GetRegions().First();
554 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
558 if (strcmp(styleStrings
[i
], "Solid") == 0)
559 region
->penStyle
= wxSOLID
;
560 else if (strcmp(styleStrings
[i
], "Dot") == 0)
561 region
->penStyle
= wxDOT
;
562 else if (strcmp(styleStrings
[i
], "Short Dash") == 0)
563 region
->penStyle
= wxSHORT_DASH
;
564 else if (strcmp(styleStrings
[i
], "Long Dash") == 0)
565 region
->penStyle
= wxLONG_DASH
;
566 else if (strcmp(styleStrings
[i
], "Dot Dash") == 0)
567 region
->penStyle
= wxDOT_DASH
;
568 delete[] styleStrings
[i
];
570 region
->m_actualPenObject
= NULL
;
574 delete[] styleStrings
;
579 void wxDividedShape::OnRightClick(float x
, float y
, int keys
, int attachment
)
587 wxRectangleShape::OnRightClick(x
, y
, keys
, attachment
);
591 wxDividedShapeControlPoint::wxDividedShapeControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
,
592 int region
, float size
, float the_m_xoffset
, float the_m_yoffset
, int the_type
):
593 wxControlPoint(the_canvas
, object
, size
, the_m_xoffset
, the_m_yoffset
, the_type
)
598 wxDividedShapeControlPoint::~wxDividedShapeControlPoint()
602 // Implement resizing of divided object division
603 void wxDividedShapeControlPoint::OnDragLeft(bool draw
, float x
, float y
, int keys
, int attachment
)
605 wxClientDC
dc(GetCanvas());
606 GetCanvas()->PrepareDC(dc
);
608 dc
.SetLogicalFunction(wxXOR
);
609 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
610 dc
.SetPen(dottedPen
);
611 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
613 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
614 float x1
= (float)(dividedObject
->GetX() - (dividedObject
->GetWidth()/2.0));
616 float x2
= (float)(dividedObject
->GetX() + (dividedObject
->GetWidth()/2.0));
618 dc
.DrawLine(x1
, y1
, x2
, y2
);
621 void wxDividedShapeControlPoint::OnBeginDragLeft(float x
, float y
, int keys
, int attachment
)
623 wxClientDC
dc(GetCanvas());
624 GetCanvas()->PrepareDC(dc
);
626 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
627 dc
.SetLogicalFunction(wxXOR
);
628 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
629 dc
.SetPen(dottedPen
);
630 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
632 float x1
= (float)(dividedObject
->GetX() - (dividedObject
->GetWidth()/2.0));
634 float x2
= (float)(dividedObject
->GetX() + (dividedObject
->GetWidth()/2.0));
636 dc
.DrawLine(x1
, y1
, x2
, y2
);
637 m_canvas
->CaptureMouse();
640 void wxDividedShapeControlPoint::OnEndDragLeft(float x
, float y
, int keys
, int attachment
)
642 wxClientDC
dc(GetCanvas());
643 GetCanvas()->PrepareDC(dc
);
645 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
646 wxNode
*node
= dividedObject
->GetRegions().Nth(regionId
);
650 wxShapeRegion
*thisRegion
= (wxShapeRegion
*)node
->Data();
651 wxShapeRegion
*nextRegion
= NULL
; // Region below this one
653 dc
.SetLogicalFunction(wxCOPY
);
655 m_canvas
->ReleaseMouse();
657 // Find the old top and bottom of this region,
658 // and calculate the new proportion for this region
661 float currentY
= (float)(dividedObject
->GetY() - (dividedObject
->GetHeight() / 2.0));
662 float maxY
= (float)(dividedObject
->GetY() + (dividedObject
->GetHeight() / 2.0));
665 float thisRegionTop
= 0.0;
666 float thisRegionBottom
= 0.0;
667 float nextRegionBottom
= 0.0;
669 node
= dividedObject
->GetRegions().First();
672 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
674 float proportion
= region
->m_regionProportionY
;
675 float yy
= currentY
+ (dividedObject
->GetHeight()*proportion
);
676 float actualY
= (float)(maxY
< yy
? maxY
: yy
);
678 if (region
== thisRegion
)
680 thisRegionTop
= currentY
;
681 thisRegionBottom
= actualY
;
683 nextRegion
= (wxShapeRegion
*)node
->Next()->Data();
685 if (region
== nextRegion
)
687 nextRegionBottom
= actualY
;
696 // Check that we haven't gone above this region or below
698 if ((y
<= thisRegionTop
) || (y
>= nextRegionBottom
))
701 dividedObject
->EraseLinks(dc
);
703 // Now calculate the new proportions of this region and the next region.
704 float thisProportion
= (float)((y
- thisRegionTop
)/dividedObject
->GetHeight());
705 float nextProportion
= (float)((nextRegionBottom
- y
)/dividedObject
->GetHeight());
706 thisRegion
->SetProportions(0.0, thisProportion
);
707 nextRegion
->SetProportions(0.0, nextProportion
);
708 m_yoffset
= (float)(y
- dividedObject
->GetY());
712 node
= dividedObject
->GetRegions().First();
715 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
716 if (region
->GetText())
718 char *s
= copystring(region
->GetText());
719 dividedObject
->FormatText(dc
, s
, i
);
725 dividedObject
->SetRegionSizes();
726 dividedObject
->Draw(dc
);
727 dividedObject
->GetEventHandler()->OnMoveLinks(dc
);