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 #----------------------------------------------------------------------------
14 from __future__
import division
19 from _basic
import ControlPoint
, RectangleShape
, Shape
20 from _oglmisc
import *
24 class DividedShapeControlPoint(ControlPoint
):
25 def __init__(self
, the_canvas
, object, region
, size
, the_m_xoffset
, the_m_yoffset
, the_type
):
26 ControlPoint
.__init
__(self
, the_canvas
, object, size
, the_m_xoffset
, the_m_yoffset
, the_type
)
27 self
.regionId
= region
29 # Implement resizing of divided object division
30 def OnDragLeft(self
, draw
, x
, y
, keys
= 0, attachment
= 0):
31 dc
= wx
.ClientDC(self
.GetCanvas())
32 self
.GetCanvas().PrepareDC(dc
)
34 dc
.SetLogicalFunction(OGLRBLF
)
35 dottedPen
= wx
.Pen(wx
.Colour(0, 0, 0), 1, wx
.DOT
)
37 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
39 dividedObject
= self
._shape
40 x1
= dividedObject
.GetX()-dividedObject
.GetWidth() / 2
42 x2
= dividedObject
.GetX() + dividedObject
.GetWidth() / 2
45 dc
.DrawLine(x1
, y1
, x2
, y2
)
47 def OnBeginDragLeft(self
, x
, y
, keys
= 0, attachment
= 0):
48 dc
= wx
.ClientDC(self
.GetCanvas())
49 self
.GetCanvas().PrepareDC(dc
)
51 dc
.SetLogicalFunction(OGLRBLF
)
52 dottedPen
= wx
.Pen(wx
.Colour(0, 0, 0), 1, wx
.DOT
)
54 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
56 dividedObject
= self
._shape
58 x1
= dividedObject
.GetX()-dividedObject
.GetWidth() / 2
60 x2
= dividedObject
.GetX() + dividedObject
.GetWidth() / 2
63 dc
.DrawLine(x1
, y1
, x2
, y2
)
64 self
._canvas
.CaptureMouse()
66 def OnEndDragLeft(self
, x
, y
, keys
= 0, attachment
= 0):
67 dc
= wx
.ClientDC(self
.GetCanvas())
68 self
.GetCanvas().PrepareDC(dc
)
70 dividedObject
= self
._shape
71 if not dividedObject
.GetRegions()[self
.regionId
]:
74 thisRegion
= dividedObject
.GetRegions()[self
.regionId
]
77 dc
.SetLogicalFunction(wx
.COPY
)
79 if self
._canvas
.HasCapture():
80 self
._canvas
.ReleaseMouse()
82 # Find the old top and bottom of this region,
83 # and calculate the new proportion for this region
85 currentY
= dividedObject
.GetY()-dividedObject
.GetHeight() / 2
86 maxY
= dividedObject
.GetY() + dividedObject
.GetHeight() / 2
92 for i
in range(len(dividedObject
.GetRegions())):
93 region
= dividedObject
.GetRegions()[i
]
94 proportion
= region
._regionProportionY
95 yy
= currentY
+ dividedObject
.GetHeight() * proportion
96 actualY
= min(maxY
, yy
)
98 if region
== thisRegion
:
99 thisRegionTop
= currentY
101 if i
+ 1<len(dividedObject
.GetRegions()):
102 nextRegion
= dividedObject
.GetRegions()[i
+ 1]
103 if region
== nextRegion
:
104 nextRegionBottom
= actualY
111 # Check that we haven't gone above this region or below
113 if y
<= thisRegionTop
or y
>= nextRegionBottom
:
116 dividedObject
.EraseLinks(dc
)
118 # Now calculate the new proportions of this region and the next region
119 thisProportion
= (y
-thisRegionTop
) / dividedObject
.GetHeight()
120 nextProportion
= (nextRegionBottom
-y
) / dividedObject
.GetHeight()
122 thisRegion
.SetProportions(0, thisProportion
)
123 nextRegion
.SetProportions(0, nextProportion
)
124 self
._yoffset
= y
-dividedObject
.GetY()
127 for i
, region
in enumerate(dividedObject
.GetRegions()):
130 dividedObject
.FormatText(dc
, s
, i
)
132 dividedObject
.SetRegionSizes()
133 dividedObject
.Draw(dc
)
134 dividedObject
.GetEventHandler().OnMoveLinks(dc
)
138 class DividedShape(RectangleShape
):
139 """A DividedShape is a rectangle with a number of vertical divisions.
140 Each division may have its text formatted with independent characteristics,
141 and the size of each division relative to the whole image may be specified.
146 def __init__(self
, w
, h
):
147 RectangleShape
.__init
__(self
, w
, h
)
150 def OnDraw(self
, dc
):
151 RectangleShape
.OnDraw(self
, dc
)
153 def OnDrawContents(self
, dc
):
154 if self
.GetRegions():
155 defaultProportion
= 1 / len(self
.GetRegions())
157 defaultProportion
= 0
158 currentY
= self
._ypos
-self
._height
/ 2
159 maxY
= self
._ypos
+ self
._height
/ 2
161 leftX
= self
._xpos
-self
._width
/ 2
162 rightX
= self
._xpos
+ self
._width
/ 2
167 dc
.SetTextForeground(self
._textColour
)
169 # For efficiency, don't do this under X - doesn't make
170 # any visible difference for our purposes.
171 if sys
.platform
[:3]=="win":
172 dc
.SetTextBackground(self
._brush
.GetColour())
174 if self
.GetDisableLabel():
180 dc
.SetBackgroundMode(wx
.TRANSPARENT
)
182 for region
in self
.GetRegions():
183 dc
.SetFont(region
.GetFont())
184 dc
.SetTextForeground(region
.GetActualColourObject())
186 if region
._regionProportionY
<0:
187 proportion
= defaultProportion
189 proportion
= region
._regionProportionY
191 y
= currentY
+ self
._height
* proportion
192 actualY
= min(maxY
, y
)
195 centreY
= currentY
+ (actualY
-currentY
) / 2
197 DrawFormattedText(dc
, region
._formattedText
, centreX
, centreY
, self
._width
-2 * xMargin
, actualY
-currentY
-2 * yMargin
, region
._formatMode
)
199 if y
<= maxY
and region
!= self
.GetRegions()[-1]:
200 regionPen
= region
.GetActualPen()
203 dc
.DrawLine(leftX
, y
, rightX
, y
)
207 def SetSize(self
, w
, h
, recursive
= True):
208 self
.SetAttachmentSize(w
, h
)
211 self
.SetRegionSizes()
213 def SetRegionSizes(self
):
214 """Set all region sizes according to proportions and this object
217 if not self
.GetRegions():
220 if self
.GetRegions():
221 defaultProportion
= 1 / len(self
.GetRegions())
223 defaultProportion
= 0
224 currentY
= self
._ypos
-self
._height
/ 2
225 maxY
= self
._ypos
+ self
._height
/ 2
227 for region
in self
.GetRegions():
228 if region
._regionProportionY
<= 0:
229 proportion
= defaultProportion
231 proportion
= region
._regionProportionY
233 sizeY
= proportion
* self
._height
235 actualY
= min(maxY
, y
)
237 centreY
= currentY
+ (actualY
-currentY
) / 2
239 region
.SetSize(self
._width
, sizeY
)
240 region
.SetPosition(0, centreY
-self
._ypos
)
244 # Attachment points correspond to regions in the divided box
245 def GetAttachmentPosition(self
, attachment
, nth
= 0, no_arcs
= 1, line
= None):
246 totalNumberAttachments
= len(self
.GetRegions()) * 2 + 2
247 if self
.GetAttachmentMode() == ATTACHMENT_MODE_NONE
or attachment
>= totalNumberAttachments
:
248 return Shape
.GetAttachmentPosition(self
, attachment
, nth
, no_arcs
)
250 n
= len(self
.GetRegions())
251 isEnd
= line
and line
.IsEnd(self
)
253 left
= self
._xpos
-self
._width
/ 2
254 right
= self
._xpos
+ self
._width
/ 2
255 top
= self
._ypos
-self
._height
/ 2
256 bottom
= self
._ypos
+ self
._height
/ 2
258 # Zero is top, n + 1 is bottom
261 if self
._spaceAttachments
:
262 if line
and line
.GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
:
263 # Align line according to the next handle along
264 point
= line
.GetNextControlPoint(self
)
272 x
= left
+ (nth
+ 1) * self
._width
/ (no_arcs
+ 1)
275 elif attachment
== n
+ 1:
277 if self
._spaceAttachments
:
278 if line
and line
.GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
:
279 # Align line according to the next handle along
280 point
= line
.GetNextControlPoint(self
)
288 x
= left
+ (nth
+ 1) * self
._width
/ (no_arcs
+ 1)
291 else: # Left or right
292 isLeft
= not attachment
<(n
+ 1)
294 i
= totalNumberAttachments
-attachment
-1
298 region
= self
.GetRegions()[i
]
305 # Calculate top and bottom of region
306 top
= self
._ypos
+ region
._y
-region
._height
/ 2
307 bottom
= self
._ypos
+ region
._y
+ region
._height
/ 2
309 # Assuming we can trust the absolute size and
310 # position of these regions
311 if self
._spaceAttachments
:
312 if line
and line
.GetAlignmentType(isEnd
) == LINE_ALIGNMENT_TO_NEXT_HANDLE
:
313 # Align line according to the next handle along
314 point
= line
.GetNextControlPoint(self
)
322 y
= top
+ (nth
+ 1) * region
._height
/ (no_arcs
+ 1)
324 y
= self
._ypos
+ region
._y
329 def GetNumberOfAttachments(self
):
330 # There are two attachments for each region (left and right),
331 # plus one on the top and one on the bottom.
332 n
= len(self
.GetRegions()) * 2 + 2
335 for point
in self
._attachmentPoints
:
341 def AttachmentIsValid(self
, attachment
):
342 totalNumberAttachments
= len(self
.GetRegions()) * 2 + 2
343 if attachment
>= totalNumberAttachments
:
344 return Shape
.AttachmentIsValid(self
, attachment
)
346 return attachment
>= 0
348 def MakeControlPoints(self
):
349 RectangleShape
.MakeControlPoints(self
)
350 self
.MakeMandatoryControlPoints()
352 def MakeMandatoryControlPoints(self
):
353 currentY
= self
.GetY()-self
._height
/ 2
354 maxY
= self
.GetY() + self
._height
/ 2
356 for i
, region
in enumerate(self
.GetRegions()):
357 proportion
= region
._regionProportionY
359 y
= currentY
+ self
._height
* proportion
360 actualY
= min(maxY
, y
)
362 if region
!= self
.GetRegions()[-1]:
363 controlPoint
= DividedShapeControlPoint(self
._canvas
, self
, i
, CONTROL_POINT_SIZE
, 0, actualY
-self
.GetY(), 0)
364 self
._canvas
.AddShape(controlPoint
)
365 self
._controlPoints
.append(controlPoint
)
369 def ResetControlPoints(self
):
370 # May only have the region handles, (n - 1) of them
371 if len(self
._controlPoints
)>len(self
.GetRegions())-1:
372 RectangleShape
.ResetControlPoints(self
)
374 self
.ResetMandatoryControlPoints()
376 def ResetMandatoryControlPoints(self
):
377 currentY
= self
.GetY()-self
._height
/ 2
378 maxY
= self
.GetY() + self
._height
/ 2
381 for controlPoint
in self
._controlPoints
:
382 if isinstance(controlPoint
, DividedShapeControlPoint
):
383 region
= self
.GetRegions()[i
]
384 proportion
= region
._regionProportionY
386 y
= currentY
+ self
._height
* proportion
387 actualY
= min(maxY
, y
)
389 controlPoint
._xoffset
= 0
390 controlPoint
._yoffset
= actualY
-self
.GetY()
396 def EditRegions(self
):
397 """Edit the region colours and styles. Not implemented."""
398 print "EditRegions() is unimplemented"
400 def OnRightClick(self
, x
, y
, keys
= 0, attachment
= 0):
404 RectangleShape
.OnRightClick(self
, x
, y
, keys
, attachment
)