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/basic.h>
32 #include <wx/ogl/basicp.h>
33 #include <wx/ogl/canvas.h>
34 #include <wx/ogl/divided.h>
35 #include <wx/ogl/lines.h>
36 #include <wx/ogl/misc.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 double size
, double the_xoffset
, double the_yoffset
, int the_type
);
47 ~wxDividedShapeControlPoint();
49 void OnDragLeft(bool draw
, double x
, double y
, int keys
=0, int attachment
= 0);
50 void OnBeginDragLeft(double x
, double y
, int keys
=0, int attachment
= 0);
51 void OnEndDragLeft(double x
, double y
, int keys
=0, int attachment
= 0);
54 IMPLEMENT_DYNAMIC_CLASS(wxDividedShapeControlPoint
, wxControlPoint
)
61 IMPLEMENT_DYNAMIC_CLASS(wxDividedShape
, wxRectangleShape
)
63 wxDividedShape::wxDividedShape(double w
, double h
): wxRectangleShape(w
, h
)
68 wxDividedShape::~wxDividedShape()
72 void wxDividedShape::OnDraw(wxDC
& dc
)
74 wxRectangleShape::OnDraw(dc
);
77 void wxDividedShape::OnDrawContents(wxDC
& dc
)
79 double defaultProportion
= (double)(GetRegions().GetCount() > 0 ? (1.0/((double)(GetRegions().GetCount()))) : 0.0);
80 double currentY
= (double)(m_ypos
- (m_height
/ 2.0));
81 double maxY
= (double)(m_ypos
+ (m_height
/ 2.0));
83 double leftX
= (double)(m_xpos
- (m_width
/ 2.0));
84 double rightX
= (double)(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().GetFirst();
112 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
113 dc
.SetFont(* region
->GetFont());
114 dc
.SetTextForeground(* region
->GetActualColourObject());
117 region
->m_regionProportionY
< 0.0 ? defaultProportion
: region
->m_regionProportionY
;
119 double y
= currentY
+ m_height
*proportion
;
120 double actualY
= maxY
< y
? maxY
: y
;
122 double centreX
= m_xpos
;
123 double centreY
= (double)(currentY
+ (actualY
- currentY
)/2.0);
125 oglDrawFormattedText(dc
, ®ion
->m_formattedText
,
126 (double)(centreX
), (double)(centreY
), (double)(m_width
-2*xMargin
), (double)(actualY
- currentY
- 2*yMargin
),
127 region
->m_formatMode
);
128 if ((y
<= maxY
) && (node
->GetNext()))
130 wxPen
*regionPen
= region
->GetActualPen();
133 dc
.SetPen(* regionPen
);
134 dc
.DrawLine(WXROUND(leftX
), WXROUND(y
), WXROUND(rightX
), WXROUND(y
));
140 node
= node
->GetNext();
144 void wxDividedShape::SetSize(double w
, double h
, bool recursive
)
146 SetAttachmentSize(w
, h
);
152 void wxDividedShape::SetRegionSizes()
154 if (GetRegions().GetCount() == 0)
157 double defaultProportion
= (double)(GetRegions().GetCount() > 0 ? (1.0/((double)(GetRegions().GetCount()))) : 0.0);
158 double currentY
= (double)(m_ypos
- (m_height
/ 2.0));
159 double maxY
= (double)(m_ypos
+ (m_height
/ 2.0));
161 // double leftX = (double)(m_xpos - (m_width / 2.0));
162 // double rightX = (double)(m_xpos + (m_width / 2.0));
164 wxNode
*node
= GetRegions().GetFirst();
167 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
169 region
->m_regionProportionY
<= 0.0 ? defaultProportion
: region
->m_regionProportionY
;
171 double sizeY
= (double)proportion
*m_height
;
172 double y
= currentY
+ sizeY
;
173 double actualY
= maxY
< y
? maxY
: y
;
175 double centreY
= (double)(currentY
+ (actualY
- currentY
)/2.0);
177 region
->SetSize(m_width
, sizeY
);
178 region
->SetPosition(0.0, (double)(centreY
- m_ypos
));
180 node
= node
->GetNext();
184 // Attachment points correspond to regions in the divided box
185 bool wxDividedShape::GetAttachmentPosition(int attachment
, double *x
, double *y
, int nth
, int no_arcs
,
188 int totalNumberAttachments
= (GetRegions().GetCount() * 2) + 2;
189 if ((GetAttachmentMode() == ATTACHMENT_MODE_NONE
) || (attachment
>= totalNumberAttachments
))
191 return wxShape::GetAttachmentPosition(attachment
, x
, y
, nth
, no_arcs
);
194 int n
= GetRegions().GetCount();
195 bool isEnd
= (line
&& line
->IsEnd(this));
197 double left
= (double)(m_xpos
- m_width
/2.0);
198 double right
= (double)(m_xpos
+ m_width
/2.0);
199 double top
= (double)(m_ypos
- m_height
/2.0);
200 double bottom
= (double)(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().Item(i
);
265 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
272 // Calculate top and bottom of region
273 top
= (double)((m_ypos
+ region
->m_y
) - (region
->m_height
/2.0));
274 bottom
= (double)((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 = (double)(((m_ypos + region->m_y) - (region->m_height/2.0)) + (nth + 1)*region->m_height/(no_arcs+1));
293 *y
= (double)(top
+ (nth
+ 1)*region
->m_height
/(no_arcs
+1));
296 *y
= (double)(m_ypos
+ region
->m_y
);
308 int wxDividedShape::GetNumberOfAttachments() const
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().GetCount() * 2) + 2;
315 wxNode
*node
= m_attachmentPoints
.GetFirst();
318 wxAttachmentPoint
*point
= (wxAttachmentPoint
*)node
->GetData();
319 if (point
->m_id
> maxN
)
321 node
= node
->GetNext();
326 bool wxDividedShape::AttachmentIsValid(int attachment
) const
328 int totalNumberAttachments
= (GetRegions().GetCount() * 2) + 2;
329 if (attachment
>= totalNumberAttachments
)
331 return wxShape::AttachmentIsValid(attachment
);
333 else if (attachment
>= 0)
339 void wxDividedShape::Copy(wxShape
& copy
)
341 wxRectangleShape::Copy(copy
);
346 void wxDividedShape::MakeControlPoints()
348 wxRectangleShape::MakeControlPoints();
350 MakeMandatoryControlPoints();
353 void wxDividedShape::MakeMandatoryControlPoints()
355 double currentY
= (double)(GetY() - (m_height
/ 2.0));
356 double maxY
= (double)(GetY() + (m_height
/ 2.0));
358 wxNode
*node
= GetRegions().GetFirst();
362 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
364 double proportion
= region
->m_regionProportionY
;
366 double y
= currentY
+ m_height
*proportion
;
367 double actualY
= (double)(maxY
< y
? maxY
: y
);
371 wxDividedShapeControlPoint
*controlPoint
=
372 new wxDividedShapeControlPoint(m_canvas
, this, i
, CONTROL_POINT_SIZE
, 0.0, (double)(actualY
- GetY()), 0);
373 m_canvas
->AddShape(controlPoint
);
374 m_controlPoints
.Append(controlPoint
);
378 node
= node
->GetNext();
382 void wxDividedShape::ResetControlPoints()
384 // May only have the region handles, (n - 1) of them.
385 if (m_controlPoints
.GetCount() > (GetRegions().GetCount() - 1))
386 wxRectangleShape::ResetControlPoints();
388 ResetMandatoryControlPoints();
391 void wxDividedShape::ResetMandatoryControlPoints()
393 double currentY
= (double)(GetY() - (m_height
/ 2.0));
394 double maxY
= (double)(GetY() + (m_height
/ 2.0));
396 wxNode
*node
= m_controlPoints
.GetFirst();
400 wxControlPoint
*controlPoint
= (wxControlPoint
*)node
->GetData();
401 if (controlPoint
->IsKindOf(CLASSINFO(wxDividedShapeControlPoint
)))
403 wxNode
*node1
= GetRegions().Item(i
);
404 wxShapeRegion
*region
= (wxShapeRegion
*)node1
->GetData();
406 double proportion
= region
->m_regionProportionY
;
408 double y
= currentY
+ m_height
*proportion
;
409 double actualY
= (double)(maxY
< y
? maxY
: y
);
411 controlPoint
->m_xoffset
= 0.0;
412 controlPoint
->m_yoffset
= (double)(actualY
- GetY());
416 node
= node
->GetNext();
421 void wxDividedShape::WriteAttributes(wxExpr
*clause
)
423 wxRectangleShape::WriteAttributes(clause
);
426 void wxDividedShape::ReadAttributes(wxExpr
*clause
)
428 wxRectangleShape::ReadAttributes(clause
);
433 * Edit the division colour/style
437 void wxDividedShape::EditRegions()
439 wxMessageBox(wxT("EditRegions() is unimplemented."), wxT("OGL"), wxOK
);
443 if (GetRegions().GetCount() < 2)
448 GraphicsForm
*form
= new GraphicsForm("Divided nodes");
449 // Need an array to store all the style strings,
450 // since they need to be converted to integers
451 char **styleStrings
= new char *[GetRegions().GetCount()];
452 for (int j
= 0; j
< GetRegions().GetCount(); j
++)
453 styleStrings
[j
] = NULL
;
456 wxNode
*node
= GetRegions().GetFirst();
457 while (node
&& node
->GetNext())
459 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
461 sprintf(buf
, "Region %d", (i
+1));
462 form
->Add(wxMakeFormMessage(buf
));
463 form
->Add(wxMakeFormNewLine());
465 form
->Add(wxMakeFormString("Colour", ®ion
->penColour
, wxFORM_CHOICE
,
466 new wxList(wxMakeConstraintStrings(
491 NULL
), NULL
, wxVERTICAL
, 150));
493 char *styleString
= NULL
;
494 switch (region
->penStyle
)
497 styleString
= "Short Dash";
500 styleString
= "Long Dash";
506 styleString
= "Dot Dash";
510 styleString
= "Solid";
513 styleStrings
[i
] = copystring(styleString
);
514 form
->Add(wxMakeFormString("Style", &(styleStrings
[i
]), wxFORM_CHOICE
,
515 new wxList(wxMakeConstraintStrings(
522 NULL
), NULL
, wxVERTICAL
, 100));
523 node
= node
->GetNext();
525 if (node
&& node
->GetNext())
526 form
->Add(wxMakeFormNewLine());
528 wxDialogBox
*dialog
= new wxDialogBox(m_canvas
->GetParent(), "Divided object properties", 10, 10, 500, 500);
529 if (GraphicsLabelFont
)
530 dialog
->SetLabelFont(GraphicsLabelFont
);
531 if (GraphicsButtonFont
)
532 dialog
->SetButtonFont(GraphicsButtonFont
);
533 form
->AssociatePanel(dialog
);
534 form
->dialog
= dialog
;
537 dialog
->Centre(wxBOTH
);
543 node
= GetRegions().GetFirst();
547 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
551 if (strcmp(styleStrings
[i
], "Solid") == 0)
552 region
->penStyle
= wxSOLID
;
553 else if (strcmp(styleStrings
[i
], "Dot") == 0)
554 region
->penStyle
= wxDOT
;
555 else if (strcmp(styleStrings
[i
], "Short Dash") == 0)
556 region
->penStyle
= wxSHORT_DASH
;
557 else if (strcmp(styleStrings
[i
], "Long Dash") == 0)
558 region
->penStyle
= wxLONG_DASH
;
559 else if (strcmp(styleStrings
[i
], "Dot Dash") == 0)
560 region
->penStyle
= wxDOT_DASH
;
561 delete[] styleStrings
[i
];
563 region
->m_actualPenObject
= NULL
;
564 node
= node
->GetNext();
567 delete[] styleStrings
;
572 void wxDividedShape::OnRightClick(double x
, double y
, int keys
, int attachment
)
580 wxRectangleShape::OnRightClick(x
, y
, keys
, attachment
);
584 wxDividedShapeControlPoint::wxDividedShapeControlPoint(wxShapeCanvas
*the_canvas
, wxShape
*object
,
585 int region
, double size
, double the_m_xoffset
, double the_m_yoffset
, int the_type
):
586 wxControlPoint(the_canvas
, object
, size
, the_m_xoffset
, the_m_yoffset
, the_type
)
591 wxDividedShapeControlPoint::~wxDividedShapeControlPoint()
595 // Implement resizing of divided object division
596 void wxDividedShapeControlPoint::OnDragLeft(bool draw
, double x
, double y
, int keys
, int attachment
)
598 wxClientDC
dc(GetCanvas());
599 GetCanvas()->PrepareDC(dc
);
601 dc
.SetLogicalFunction(OGLRBLF
);
602 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
603 dc
.SetPen(dottedPen
);
604 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
606 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
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
));
614 void wxDividedShapeControlPoint::OnBeginDragLeft(double x
, double y
, int keys
, int attachment
)
616 wxClientDC
dc(GetCanvas());
617 GetCanvas()->PrepareDC(dc
);
619 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
620 dc
.SetLogicalFunction(OGLRBLF
);
621 wxPen
dottedPen(wxColour(0, 0, 0), 1, wxDOT
);
622 dc
.SetPen(dottedPen
);
623 dc
.SetBrush((* wxTRANSPARENT_BRUSH
));
625 double x1
= (double)(dividedObject
->GetX() - (dividedObject
->GetWidth()/2.0));
627 double x2
= (double)(dividedObject
->GetX() + (dividedObject
->GetWidth()/2.0));
629 dc
.DrawLine(WXROUND(x1
), WXROUND(y1
), WXROUND(x2
), WXROUND(y2
));
630 m_canvas
->CaptureMouse();
633 void wxDividedShapeControlPoint::OnEndDragLeft(double x
, double y
, int keys
, int attachment
)
635 wxClientDC
dc(GetCanvas());
636 GetCanvas()->PrepareDC(dc
);
638 wxDividedShape
*dividedObject
= (wxDividedShape
*)m_shape
;
639 wxNode
*node
= dividedObject
->GetRegions().Item(regionId
);
643 wxShapeRegion
*thisRegion
= (wxShapeRegion
*)node
->GetData();
644 wxShapeRegion
*nextRegion
= NULL
; // Region below this one
646 dc
.SetLogicalFunction(wxCOPY
);
648 m_canvas
->ReleaseMouse();
650 // Find the old top and bottom of this region,
651 // and calculate the new proportion for this region
654 double currentY
= (double)(dividedObject
->GetY() - (dividedObject
->GetHeight() / 2.0));
655 double maxY
= (double)(dividedObject
->GetY() + (dividedObject
->GetHeight() / 2.0));
658 double thisRegionTop
= 0.0;
659 double thisRegionBottom
= 0.0;
660 double nextRegionBottom
= 0.0;
662 node
= dividedObject
->GetRegions().GetFirst();
665 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
667 double proportion
= region
->m_regionProportionY
;
668 double yy
= currentY
+ (dividedObject
->GetHeight()*proportion
);
669 double actualY
= (double)(maxY
< yy
? maxY
: yy
);
671 if (region
== thisRegion
)
673 thisRegionTop
= currentY
;
674 thisRegionBottom
= actualY
;
676 nextRegion
= (wxShapeRegion
*)node
->GetNext()->GetData();
678 if (region
== nextRegion
)
680 nextRegionBottom
= actualY
;
684 node
= node
->GetNext();
689 // Check that we haven't gone above this region or below
691 if ((y
<= thisRegionTop
) || (y
>= nextRegionBottom
))
694 dividedObject
->EraseLinks(dc
);
696 // Now calculate the new proportions of this region and the next region.
697 double thisProportion
= (double)((y
- thisRegionTop
)/dividedObject
->GetHeight());
698 double nextProportion
= (double)((nextRegionBottom
- y
)/dividedObject
->GetHeight());
699 thisRegion
->SetProportions(0.0, thisProportion
);
700 nextRegion
->SetProportions(0.0, nextProportion
);
701 m_yoffset
= (double)(y
- dividedObject
->GetY());
705 node
= dividedObject
->GetRegions().GetFirst();
708 wxShapeRegion
*region
= (wxShapeRegion
*)node
->GetData();
709 if (region
->GetText())
711 wxChar
*s
= copystring(region
->GetText());
712 dividedObject
->FormatText(dc
, s
, i
);
715 node
= node
->GetNext();
718 dividedObject
->SetRegionSizes();
719 dividedObject
->Draw(dc
);
720 dividedObject
->GetEventHandler()->OnMoveLinks(dc
);