1 # -*- coding: iso-8859-1 -*-
2 #----------------------------------------------------------------------------
4 # Purpose: DividedShape class
6 # Author: Pierre Hjälm (from C++ original by Julian Smart)
10 # Copyright: (c) 2004 Pierre Hjälm - 1998 Julian Smart
11 # Licence: wxWindows license
12 #----------------------------------------------------------------------------
17 from _basic
import ControlPoint
, RectangleShape
, Shape
18 from _oglmisc
import *
22 class DividedShapeControlPoint(ControlPoint
):
23 def __init__(self
, the_canvas
, object, region
, size
, the_m_xoffset
, the_m_yoffset
, the_type
):
24 ControlPoint
.__init
__(self
, the_canvas
, object, size
, the_m_xoffset
, the_m_yoffset
, the_type
)
25 self
.regionId
= region
27 # Implement resizing of divided object division
28 def OnDragLeft(self
, draw
, x
, y
, keys
= 0, attachment
= 0):
29 dc
= wx
.ClientDC(self
.GetCanvas())
30 self
.GetCanvas().PrepareDC(dc
)
32 dc
.SetLogicalFunction(OGLRBLF
)
33 dottedPen
= wx
.Pen(wx
.Colour(0, 0, 0), 1, wx
.DOT
)
35 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
37 dividedObject
= self
._shape
38 x1
= dividedObject
.GetX() - dividedObject
.GetWidth() / 2.0
40 x2
= dividedObject
.GetX() + dividedObject
.GetWidth() / 2.0
43 dc
.DrawLine(x1
, y1
, x2
, y2
)
45 def OnBeginDragLeft(self
, x
, y
, keys
= 0, attachment
= 0):
46 dc
= wx
.ClientDC(self
.GetCanvas())
47 self
.GetCanvas().PrepareDC(dc
)
49 dc
.SetLogicalFunction(OGLRBLF
)
50 dottedPen
= wx
.Pen(wx
.Colour(0, 0, 0), 1, wx
.DOT
)
52 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
54 dividedObject
= self
._shape
56 x1
= dividedObject
.GetX() - dividedObject
.GetWidth() / 2.0
58 x2
= dividedObject
.GetX() + dividedObject
.GetWidth() / 2.0
61 dc
.DrawLine(x1
, y1
, x2
, y2
)
62 self
._canvas
.CaptureMouse()
64 def OnEndDragLeft(self
, x
, y
, keys
= 0, attachment
= 0):
65 dc
= wx
.ClientDC(self
.GetCanvas())
66 self
.GetCanvas().PrepareDC(dc
)
68 dividedObject
= self
._shape
69 if not dividedObject
.GetRegions()[self
.regionId
]:
72 thisRegion
= dividedObject
.GetRegions()[self
.regionId
]
75 dc
.SetLogicalFunction(wx
.COPY
)
77 if self
._canvas
.HasCapture():
78 self
._canvas
.ReleaseMouse()
80 # Find the old top and bottom of this region,
81 # and calculate the new proportion for this region
83 currentY
= dividedObject
.GetY() - dividedObject
.GetHeight() / 2.0
84 maxY
= dividedObject
.GetY() + dividedObject
.GetHeight() / 2.0
90 for i
in range(len(dividedObject
.GetRegions())):
91 region
= dividedObject
.GetRegions()[i
]
92 proportion
= region
._regionProportionY
93 yy
= currentY
+ dividedObject
.GetHeight() * proportion
94 actualY
= min(maxY
, yy
)
96 if region
== thisRegion
:
97 thisRegionTop
= currentY
99 if i
+ 1 < len(dividedObject
.GetRegions()):
100 nextRegion
= dividedObject
.GetRegions()[i
+ 1]
101 if region
== nextRegion
:
102 nextRegionBottom
= actualY
109 # Check that we haven't gone above this region or below
111 if y
<= thisRegionTop
or y
>= nextRegionBottom
:
114 dividedObject
.EraseLinks(dc
)
116 # Now calculate the new proportions of this region and the next region
117 thisProportion
= float(y
- thisRegionTop
) / dividedObject
.GetHeight()
118 nextProportion
= float(nextRegionBottom
- y
) / dividedObject
.GetHeight()
120 thisRegion
.SetProportions(0, thisProportion
)
121 nextRegion
.SetProportions(0, nextProportion
)
122 self
._yoffset
= y
- dividedObject
.GetY()
125 for i
, region
in enumerate(dividedObject
.GetRegions()):
128 dividedObject
.FormatText(dc
, s
, i
)
130 dividedObject
.SetRegionSizes()
131 dividedObject
.Draw(dc
)
132 dividedObject
.GetEventHandler().OnMoveLinks(dc
)
136 class DividedShape(RectangleShape
):
137 """A DividedShape is a rectangle with a number of vertical divisions.
138 Each division may have its text formatted with independent characteristics,
139 and the size of each division relative to the whole image may be specified.
144 def __init__(self
, w
, h
):
145 RectangleShape
.__init
__(self
, w
, h
)
148 def OnDraw(self
, dc
):
149 RectangleShape
.OnDraw(self
, dc
)
151 def OnDrawContents(self
, dc
):
152 if self
.GetRegions():
153 defaultProportion
= 1.0 / len(self
.GetRegions())
155 defaultProportion
= 0.0
156 currentY
= self
._ypos
- self
._height
/ 2.0
157 maxY
= self
._ypos
+ self
._height
/ 2.0
159 leftX
= self
._xpos
- self
._width
/ 2.0
160 rightX
= self
._xpos
+ self
._width
/ 2.0
165 dc
.SetTextForeground(self
._textColour
)
167 # For efficiency, don't do this under X - doesn't make
168 # any visible difference for our purposes.
169 if sys
.platform
[:3] == "win":
170 dc
.SetTextBackground(self
._brush
.GetColour())
172 if self
.GetDisableLabel():
178 dc
.SetBackgroundMode(wx
.TRANSPARENT
)
180 for region
in self
.GetRegions():
181 dc
.SetFont(region
.GetFont())
182 dc
.SetTextForeground(region
.GetActualColourObject())
184 if region
._regionProportionY
< 0:
185 proportion
= defaultProportion
187 proportion
= region
._regionProportionY
189 y
= currentY
+ self
._height
* proportion
190 actualY
= min(maxY
, y
)
193 centreY
= currentY
+ (actualY
- currentY
) / 2.0
195 DrawFormattedText(dc
, region
._formattedText
, centreX
, centreY
, self
._width
- 2 * xMargin
, actualY
- currentY
- 2 * yMargin
, region
._formatMode
)
197 if y
<= maxY
and region
!= self
.GetRegions()[-1]:
198 regionPen
= region
.GetActualPen()
201 dc
.DrawLine(leftX
, y
, rightX
, y
)
205 def SetSize(self
, w
, h
, recursive
= True):
206 self
.SetAttachmentSize(w
, h
)
209 self
.SetRegionSizes()
211 def SetRegionSizes(self
):
212 """Set all region sizes according to proportions and this object
215 if not self
.GetRegions():
218 if self
.GetRegions():
219 defaultProportion
= 1.0 / len(self
.GetRegions())
221 defaultProportion
= 0.0
222 currentY
= self
._ypos
- self
._height
/ 2.0
223 maxY
= self
._ypos
+ self
._height
/ 2.0
225 for region
in self
.GetRegions():
226 if region
._regionProportionY
<= 0:
227 proportion
= defaultProportion
229 proportion
= region
._regionProportionY
231 sizeY
= proportion
* self
._height
233 actualY
= min(maxY
, y
)
235 centreY
= currentY
+ (actualY
- currentY
) / 2.0
237 region
.SetSize(self
._width
, sizeY
)
238 region
.SetPosition(0, centreY
- self
._ypos
)
242 # Attachment points correspond to regions in the divided box
243 def GetAttachmentPosition(self
, attachment
, nth
= 0, no_arcs
= 1, line
= None):
244 totalNumberAttachments
= len(self
.GetRegions()) * 2 + 2
245 if self
.GetAttachmentMode() == ATTACHMENT_MODE_NONE
or attachment
>= totalNumberAttachments
:
246 return Shape
.GetAttachmentPosition(self
, attachment
, nth
, no_arcs
)
248 n
= len(self
.GetRegions())
249 isEnd
= line
and line
.IsEnd(self
)
251 left
= self
._xpos
- self
._width
/ 2.0
252 right
= self
._xpos
+ self
._width
/ 2.0
253 top
= self
._ypos
- self
._height
/ 2.0
254 bottom
= self
._ypos
+ self
._height
/ 2.0
256 # Zero is top, n + 1 is bottom
259 if self
._spaceAttachments
:
260 if line
and line
.GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
:
261 # Align line according to the next handle along
262 point
= line
.GetNextControlPoint(self
)
265 elif point
[0] > right
:
270 x
= left
+ (nth
+ 1) * self
._width
/ (no_arcs
+ 1.0)
273 elif attachment
== n
+ 1:
275 if self
._spaceAttachments
:
276 if line
and line
.GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
:
277 # Align line according to the next handle along
278 point
= line
.GetNextControlPoint(self
)
281 elif point
[0] > right
:
286 x
= left
+ (nth
+ 1) * self
._width
/ (no_arcs
+ 1.0)
289 else: # Left or right
290 isLeft
= not attachment
< (n
+ 1)
292 i
= totalNumberAttachments
- attachment
- 1
296 region
= self
.GetRegions()[i
]
303 # Calculate top and bottom of region
304 top
= self
._ypos
+ region
._y
- region
._height
/ 2.0
305 bottom
= self
._ypos
+ region
._y
+ region
._height
/ 2.0
307 # Assuming we can trust the absolute size and
308 # position of these regions
309 if self
._spaceAttachments
:
310 if line
and line
.GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
:
311 # Align line according to the next handle along
312 point
= line
.GetNextControlPoint(self
)
313 if point
[1] < bottom
:
320 y
= top
+ (nth
+ 1) * region
._height
/ (no_arcs
+ 1.0)
322 y
= self
._ypos
+ region
._y
327 def GetNumberOfAttachments(self
):
328 # There are two attachments for each region (left and right),
329 # plus one on the top and one on the bottom.
330 n
= len(self
.GetRegions()) * 2 + 2
333 for point
in self
._attachmentPoints
:
339 def AttachmentIsValid(self
, attachment
):
340 totalNumberAttachments
= len(self
.GetRegions()) * 2 + 2
341 if attachment
>= totalNumberAttachments
:
342 return Shape
.AttachmentIsValid(self
, attachment
)
344 return attachment
>= 0
346 def MakeControlPoints(self
):
347 RectangleShape
.MakeControlPoints(self
)
348 self
.MakeMandatoryControlPoints()
350 def MakeMandatoryControlPoints(self
):
351 currentY
= self
.GetY() - self
._height
/ 2.0
352 maxY
= self
.GetY() + self
._height
/ 2.0
354 for i
, region
in enumerate(self
.GetRegions()):
355 proportion
= region
._regionProportionY
357 y
= currentY
+ self
._height
* proportion
358 actualY
= min(maxY
, y
)
360 if region
!= self
.GetRegions()[-1]:
361 controlPoint
= DividedShapeControlPoint(self
._canvas
, self
, i
, CONTROL_POINT_SIZE
, 0, actualY
- self
.GetY(), 0)
362 self
._canvas
.AddShape(controlPoint
)
363 self
._controlPoints
.append(controlPoint
)
367 def ResetControlPoints(self
):
368 # May only have the region handles, (n - 1) of them
369 if len(self
._controlPoints
) > len(self
.GetRegions()) - 1:
370 RectangleShape
.ResetControlPoints(self
)
372 self
.ResetMandatoryControlPoints()
374 def ResetMandatoryControlPoints(self
):
375 currentY
= self
.GetY() - self
._height
/ 2.0
376 maxY
= self
.GetY() + self
._height
/ 2.0
379 for controlPoint
in self
._controlPoints
:
380 if isinstance(controlPoint
, DividedShapeControlPoint
):
381 region
= self
.GetRegions()[i
]
382 proportion
= region
._regionProportionY
384 y
= currentY
+ self
._height
* proportion
385 actualY
= min(maxY
, y
)
387 controlPoint
._xoffset
= 0
388 controlPoint
._yoffset
= actualY
- self
.GetY()
394 def EditRegions(self
):
395 """Edit the region colours and styles. Not implemented."""
396 print "EditRegions() is unimplemented"
398 def OnRightClick(self
, x
, y
, keys
= 0, attachment
= 0):
402 RectangleShape
.OnRightClick(self
, x
, y
, keys
, attachment
)