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"
27 #include <wx/wxexpr.h>
29 #include <wx/ogl/basic.h>
30 #include <wx/ogl/basicp.h>
31 #include <wx/ogl/canvas.h>
32 #include <wx/ogl/divided.h>
33 #include <wx/ogl/lines.h>
34 #include <wx/ogl/misc.h>
36 class wxDividedShapeControlPoint
: public wxControlPoint
38 DECLARE_DYNAMIC_CLASS(wxDividedShapeControlPoint
)
42 wxDividedShapeControlPoint() { regionId
= 0; }
43 wxDividedShapeControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
, int region
,
44 double size
, double the_xoffset
, double the_yoffset
, int the_type
);
45 ~wxDividedShapeControlPoint();
47 void OnDragLeft(bool draw
, double x
, double y
, int keys
=0, int attachment
= 0);
48 void OnBeginDragLeft(double x
, double y
, int keys
=0, int attachment
= 0);
49 void OnEndDragLeft(double x
, double y
, int keys
=0, int attachment
= 0);
52 IMPLEMENT_DYNAMIC_CLASS(wxDividedShapeControlPoint
, wxControlPoint
)
59 IMPLEMENT_DYNAMIC_CLASS(wxDividedShape
, wxRectangleShape
)
61 wxDividedShape::wxDividedShape(double w
, double h
): wxRectangleShape(w
, h
)
66 wxDividedShape::~wxDividedShape()
70 void wxDividedShape::OnDraw(wxDC
& dc
)
72 wxRectangleShape::OnDraw(dc
);
75 void wxDividedShape::OnDrawContents(wxDC
& dc
)
77 double defaultProportion
= (double)(GetRegions().Number() > 0 ? (1.0/((double)(GetRegions().Number()))) : 0.0);
78 double currentY
= (double)(m_ypos
- (m_height
/ 2.0));
79 double maxY
= (double)(m_ypos
+ (m_height
/ 2.0));
81 double leftX
= (double)(m_xpos
- (m_width
/ 2.0));
82 double rightX
= (double)(m_xpos
+ (m_width
/ 2.0));
84 if (m_pen
) dc
.SetPen(* m_pen
);
86 if (m_textColour
) dc
.SetTextForeground(* m_textColour
);
89 // For efficiency, don't do this under X - doesn't make
90 // any visible difference for our purposes.
92 dc
.SetTextBackground(m_brush
->GetColour());
101 if (GetDisableLabel()) return;
105 dc
.SetBackgroundMode(wxTRANSPARENT
);
107 wxNode
*node
= GetRegions().First();
110 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
111 dc
.SetFont(* region
->GetFont());
112 dc
.SetTextForeground(* region
->GetActualColourObject());
115 region
->m_regionProportionY
< 0.0 ? defaultProportion
: region
->m_regionProportionY
;
117 double y
= currentY
+ m_height
*proportion
;
118 double actualY
= maxY
< y
? maxY
: y
;
120 double centreX
= m_xpos
;
121 double centreY
= (double)(currentY
+ (actualY
- currentY
)/2.0);
123 oglDrawFormattedText(dc
, ®ion
->m_formattedText
,
124 (double)(centreX
), (double)(centreY
), (double)(m_width
-2*xMargin
), (double)(actualY
- currentY
- 2*yMargin
),
125 region
->m_formatMode
);
126 if ((y
<= maxY
) && (node
->Next()))
128 wxPen
*regionPen
= region
->GetActualPen();
131 dc
.SetPen(* regionPen
);
132 dc
.DrawLine(WXROUND(leftX
), WXROUND(y
), WXROUND(rightX
), WXROUND(y
));
142 void wxDividedShape::SetSize(double w
, double h
, bool recursive
)
144 SetAttachmentSize(w
, h
);
150 void wxDividedShape::SetRegionSizes()
152 if (GetRegions().Number() == 0)
155 double defaultProportion
= (double)(GetRegions().Number() > 0 ? (1.0/((double)(GetRegions().Number()))) : 0.0);
156 double currentY
= (double)(m_ypos
- (m_height
/ 2.0));
157 double maxY
= (double)(m_ypos
+ (m_height
/ 2.0));
159 // double leftX = (double)(m_xpos - (m_width / 2.0));
160 // double rightX = (double)(m_xpos + (m_width / 2.0));
162 wxNode
*node
= GetRegions().First();
165 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
167 region
->m_regionProportionY
<= 0.0 ? defaultProportion
: region
->m_regionProportionY
;
169 double sizeY
= (double)proportion
*m_height
;
170 double y
= currentY
+ sizeY
;
171 double actualY
= maxY
< y
? maxY
: y
;
173 double centreY
= (double)(currentY
+ (actualY
- currentY
)/2.0);
175 region
->SetSize(m_width
, sizeY
);
176 region
->SetPosition(0.0, (double)(centreY
- m_ypos
));
182 // Attachment points correspond to regions in the divided box
183 bool wxDividedShape::GetAttachmentPosition(int attachment
, double *x
, double *y
, int nth
, int no_arcs
,
186 int totalNumberAttachments
= (GetRegions().Number() * 2) + 2;
187 if ((GetAttachmentMode() == ATTACHMENT_MODE_NONE
) || (attachment
>= totalNumberAttachments
))
189 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
);
192 int n
= GetRegions().Number();
193 bool isEnd
= (line
&& line
->IsEnd(this));
195 double left
= (double)(m_xpos
- m_width
/2.0);
196 double right
= (double)(m_xpos
+ m_width
/2.0);
197 double top
= (double)(m_ypos
- m_height
/2.0);
198 double bottom
= (double)(m_ypos
+ m_height
/2.0);
200 // Zero is top, n+1 is bottom.
204 if (m_spaceAttachments
)
206 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
208 // Align line according to the next handle along
209 wxRealPoint
*point
= line
->GetNextControlPoint(this);
212 else if (point
->x
> right
)
218 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
223 else if (attachment
== (n
+1))
226 if (m_spaceAttachments
)
228 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
230 // Align line according to the next handle along
231 wxRealPoint
*point
= line
->GetNextControlPoint(this);
234 else if (point
->x
> right
)
240 *x
= left
+ (nth
+ 1)*m_width
/(no_arcs
+ 1);
250 if (attachment
< (n
+1))
257 i
= (totalNumberAttachments
- attachment
- 1);
260 wxNode
*node
= GetRegions().Nth(i
);
263 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
270 // Calculate top and bottom of region
271 top
= (double)((m_ypos
+ region
->m_y
) - (region
->m_height
/2.0));
272 bottom
= (double)((m_ypos
+ region
->m_y
) + (region
->m_height
/2.0));
274 // Assuming we can trust the absolute size and
275 // position of these regions...
276 if (m_spaceAttachments
)
278 if (line
&& (line
->GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
))
280 // Align line according to the next handle along
281 wxRealPoint
*point
= line
->GetNextControlPoint(this);
282 if (point
->y
< bottom
)
284 else if (point
->y
> top
)
290 // *y = (double)(((m_ypos + region->m_y) - (region->m_height/2.0)) + (nth + 1)*region->m_height/(no_arcs+1));
291 *y
= (double)(top
+ (nth
+ 1)*region
->m_height
/(no_arcs
+1));
294 *y
= (double)(m_ypos
+ region
->m_y
);
306 int wxDividedShape::GetNumberOfAttachments() const
308 // There are two attachments for each region (left and right),
309 // plus one on the top and one on the bottom.
310 int n
= (GetRegions().Number() * 2) + 2;
313 wxNode
*node
= m_attachmentPoints
.First();
316 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->Data();
317 if (point
->m_id
> maxN
)
324 bool wxDividedShape::AttachmentIsValid(int attachment
)
326 int totalNumberAttachments
= (GetRegions().Number() * 2) + 2;
327 if (attachment
>= totalNumberAttachments
)
329 return wxShape::AttachmentIsValid(attachment
);
331 else if (attachment
>= 0)
337 void wxDividedShape::Copy(wxShape
& copy
)
339 wxRectangleShape::Copy(copy
);
344 void wxDividedShape::MakeControlPoints()
346 wxRectangleShape::MakeControlPoints();
348 MakeMandatoryControlPoints();
351 void wxDividedShape::MakeMandatoryControlPoints()
353 double currentY
= (double)(GetY() - (m_height
/ 2.0));
354 double maxY
= (double)(GetY() + (m_height
/ 2.0));
356 wxNode
*node
= GetRegions().First();
360 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
362 double proportion
= region
->m_regionProportionY
;
364 double y
= currentY
+ m_height
*proportion
;
365 double actualY
= (double)(maxY
< y
? maxY
: y
);
369 wxDividedShapeControlPoint
*controlPoint
=
370 new wxDividedShapeControlPoint(m_canvas
, this, i
, CONTROL_POINT_SIZE
, 0.0, (double)(actualY
- GetY()), 0);
371 m_canvas
->AddShape(controlPoint
);
372 m_controlPoints
.Append(controlPoint
);
380 void wxDividedShape::ResetControlPoints()
382 // May only have the region handles, (n - 1) of them.
383 if (m_controlPoints
.Number() > (GetRegions().Number() - 1))
384 wxRectangleShape::ResetControlPoints();
386 ResetMandatoryControlPoints();
389 void wxDividedShape::ResetMandatoryControlPoints()
391 double currentY
= (double)(GetY() - (m_height
/ 2.0));
392 double maxY
= (double)(GetY() + (m_height
/ 2.0));
394 wxNode
*node
= m_controlPoints
.First();
398 wxControlPoint
*controlPoint
= (wxControlPoint
*)node
->Data();
399 if (controlPoint
->IsKindOf(CLASSINFO(wxDividedShapeControlPoint
)))
401 wxNode
*node1
= GetRegions().Nth(i
);
402 wxShapeRegion
*region
= (wxShapeRegion
*)node1
->Data();
404 double proportion
= region
->m_regionProportionY
;
406 double y
= currentY
+ m_height
*proportion
;
407 double actualY
= (double)(maxY
< y
? maxY
: y
);
409 controlPoint
->m_xoffset
= 0.0;
410 controlPoint
->m_yoffset
= (double)(actualY
- GetY());
419 void wxDividedShape::WriteAttributes(wxExpr
*clause
)
421 wxRectangleShape::WriteAttributes(clause
);
424 void wxDividedShape::ReadAttributes(wxExpr
*clause
)
426 wxRectangleShape::ReadAttributes(clause
);
431 * Edit the division colour/style
435 void wxDividedShape::EditRegions()
437 wxMessageBox("EditRegions() is unimplemented.", "OGL", wxOK
);
441 if (GetRegions().Number() < 2)
446 GraphicsForm
*form
= new GraphicsForm("Divided nodes");
447 // Need an array to store all the style strings,
448 // since they need to be converted to integers
449 char **styleStrings
= new char *[GetRegions().Number()];
450 for (int j
= 0; j
< GetRegions().Number(); j
++)
451 styleStrings
[j
] = NULL
;
454 wxNode
*node
= GetRegions().First();
455 while (node
&& node
->Next())
457 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
459 sprintf(buf
, "Region %d", (i
+1));
460 form
->Add(wxMakeFormMessage(buf
));
461 form
->Add(wxMakeFormNewLine());
463 form
->Add(wxMakeFormString("Colour", ®ion
->penColour
, wxFORM_CHOICE
,
464 new wxList(wxMakeConstraintStrings(
489 NULL
), NULL
, wxVERTICAL
, 150));
491 char *styleString
= NULL
;
492 switch (region
->penStyle
)
495 styleString
= "Short Dash";
498 styleString
= "Long Dash";
504 styleString
= "Dot Dash";
508 styleString
= "Solid";
511 styleStrings
[i
] = copystring(styleString
);
512 form
->Add(wxMakeFormString("Style", &(styleStrings
[i
]), wxFORM_CHOICE
,
513 new wxList(wxMakeConstraintStrings(
520 NULL
), NULL
, wxVERTICAL
, 100));
523 if (node
&& node
->Next())
524 form
->Add(wxMakeFormNewLine());
526 wxDialogBox
*dialog
= new wxDialogBox(m_canvas
->GetParent(), "Divided object properties", 10, 10, 500, 500);
527 if (GraphicsLabelFont
)
528 dialog
->SetLabelFont(GraphicsLabelFont
);
529 if (GraphicsButtonFont
)
530 dialog
->SetButtonFont(GraphicsButtonFont
);
531 form
->AssociatePanel(dialog
);
532 form
->dialog
= dialog
;
535 dialog
->Centre(wxBOTH
);
541 node
= GetRegions().First();
545 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
549 if (strcmp(styleStrings
[i
], "Solid") == 0)
550 region
->penStyle
= wxSOLID
;
551 else if (strcmp(styleStrings
[i
], "Dot") == 0)
552 region
->penStyle
= wxDOT
;
553 else if (strcmp(styleStrings
[i
], "Short Dash") == 0)
554 region
->penStyle
= wxSHORT_DASH
;
555 else if (strcmp(styleStrings
[i
], "Long Dash") == 0)
556 region
->penStyle
= wxLONG_DASH
;
557 else if (strcmp(styleStrings
[i
], "Dot Dash") == 0)
558 region
->penStyle
= wxDOT_DASH
;
559 delete[] styleStrings
[i
];
561 region
->m_actualPenObject
= NULL
;
565 delete[] styleStrings
;
570 void wxDividedShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
578 wxRectangleShape::OnRightClick(x
, y
, keys
, attachment
);
582 wxDividedShapeControlPoint::wxDividedShapeControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
,
583 int region
, double size
, double the_m_xoffset
, double the_m_yoffset
, int the_type
):
584 wxControlPoint(the_canvas
, object
, size
, the_m_xoffset
, the_m_yoffset
, the_type
)
589 wxDividedShapeControlPoint::~wxDividedShapeControlPoint()
593 // Implement resizing of divided object division
594 void wxDividedShapeControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
596 wxClientDC
dc(GetCanvas());
597 GetCanvas()->PrepareDC(dc
);
599 dc
.SetLogicalFunction(OGLRBLF
);
600 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
601 dc
.SetPen(dottedPen
);
602 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
604 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
605 double x1
= (double)(dividedObject
->GetX() - (dividedObject
->GetWidth()/2.0));
607 double x2
= (double)(dividedObject
->GetX() + (dividedObject
->GetWidth()/2.0));
609 dc
.DrawLine(WXROUND(x1
), WXROUND(y1
), WXROUND(x2
), WXROUND(y2
));
612 void wxDividedShapeControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
614 wxClientDC
dc(GetCanvas());
615 GetCanvas()->PrepareDC(dc
);
617 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
618 dc
.SetLogicalFunction(OGLRBLF
);
619 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
620 dc
.SetPen(dottedPen
);
621 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
623 double x1
= (double)(dividedObject
->GetX() - (dividedObject
->GetWidth()/2.0));
625 double x2
= (double)(dividedObject
->GetX() + (dividedObject
->GetWidth()/2.0));
627 dc
.DrawLine(WXROUND(x1
), WXROUND(y1
), WXROUND(x2
), WXROUND(y2
));
628 m_canvas
->CaptureMouse();
631 void wxDividedShapeControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
633 wxClientDC
dc(GetCanvas());
634 GetCanvas()->PrepareDC(dc
);
636 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
637 wxNode
*node
= dividedObject
->GetRegions().Nth(regionId
);
641 wxShapeRegion
*thisRegion
= (wxShapeRegion
*)node
->Data();
642 wxShapeRegion
*nextRegion
= NULL
; // Region below this one
644 dc
.SetLogicalFunction(wxCOPY
);
646 m_canvas
->ReleaseMouse();
648 // Find the old top and bottom of this region,
649 // and calculate the new proportion for this region
652 double currentY
= (double)(dividedObject
->GetY() - (dividedObject
->GetHeight() / 2.0));
653 double maxY
= (double)(dividedObject
->GetY() + (dividedObject
->GetHeight() / 2.0));
656 double thisRegionTop
= 0.0;
657 double thisRegionBottom
= 0.0;
658 double nextRegionBottom
= 0.0;
660 node
= dividedObject
->GetRegions().First();
663 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
665 double proportion
= region
->m_regionProportionY
;
666 double yy
= currentY
+ (dividedObject
->GetHeight()*proportion
);
667 double actualY
= (double)(maxY
< yy
? maxY
: yy
);
669 if (region
== thisRegion
)
671 thisRegionTop
= currentY
;
672 thisRegionBottom
= actualY
;
674 nextRegion
= (wxShapeRegion
*)node
->Next()->Data();
676 if (region
== nextRegion
)
678 nextRegionBottom
= actualY
;
687 // Check that we haven't gone above this region or below
689 if ((y
<= thisRegionTop
) || (y
>= nextRegionBottom
))
692 dividedObject
->EraseLinks(dc
);
694 // Now calculate the new proportions of this region and the next region.
695 double thisProportion
= (double)((y
- thisRegionTop
)/dividedObject
->GetHeight());
696 double nextProportion
= (double)((nextRegionBottom
- y
)/dividedObject
->GetHeight());
697 thisRegion
->SetProportions(0.0, thisProportion
);
698 nextRegion
->SetProportions(0.0, nextProportion
);
699 m_yoffset
= (double)(y
- dividedObject
->GetY());
703 node
= dividedObject
->GetRegions().First();
706 wxShapeRegion
*region
= (wxShapeRegion
*)node
->Data();
707 if (region
->GetText())
709 char *s
= copystring(region
->GetText());
710 dividedObject
->FormatText(dc
, s
, i
);
716 dividedObject
->SetRegionSizes();
717 dividedObject
->Draw(dc
);
718 dividedObject
->GetEventHandler()->OnMoveLinks(dc
);