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
)