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
)