]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/lib/ogl/_divided.py
Since everything in the submodules is to appear in the pacakge
[wxWidgets.git] / wxPython / wx / lib / ogl / _divided.py
1 # -*- coding: iso-8859-1 -*-
2 #----------------------------------------------------------------------------
3 # Name: divided.py
4 # Purpose: DividedShape class
5 #
6 # Author: Pierre Hjälm (from C++ original by Julian Smart)
7 #
8 # Created: 2004-05-08
9 # RCS-ID: $Id$
10 # Copyright: (c) 2004 Pierre Hjälm - 1998 Julian Smart
11 # Licence: wxWindows license
12 #----------------------------------------------------------------------------
13
14 from __future__ import division
15
16 import sys
17 import wx
18
19 from _basic import ControlPoint, RectangleShape, Shape
20 from _oglmisc import *
21
22
23
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
28
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)
33
34 dc.SetLogicalFunction(OGLRBLF)
35 dottedPen = wx.Pen(wx.Colour(0, 0, 0), 1, wx.DOT)
36 dc.SetPen(dottedPen)
37 dc.SetBrush(wx.TRANSPARENT_BRUSH)
38
39 dividedObject = self._shape
40 x1 = dividedObject.GetX()-dividedObject.GetWidth() / 2
41 y1 = y
42 x2 = dividedObject.GetX() + dividedObject.GetWidth() / 2
43 y2 = y
44
45 dc.DrawLine(x1, y1, x2, y2)
46
47 def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
48 dc = wx.ClientDC(self.GetCanvas())
49 self.GetCanvas().PrepareDC(dc)
50
51 dc.SetLogicalFunction(OGLRBLF)
52 dottedPen = wx.Pen(wx.Colour(0, 0, 0), 1, wx.DOT)
53 dc.SetPen(dottedPen)
54 dc.SetBrush(wx.TRANSPARENT_BRUSH)
55
56 dividedObject = self._shape
57
58 x1 = dividedObject.GetX()-dividedObject.GetWidth() / 2
59 y1 = y
60 x2 = dividedObject.GetX() + dividedObject.GetWidth() / 2
61 y2 = y
62
63 dc.DrawLine(x1, y1, x2, y2)
64 self._canvas.CaptureMouse()
65
66 def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
67 dc = wx.ClientDC(self.GetCanvas())
68 self.GetCanvas().PrepareDC(dc)
69
70 dividedObject = self._shape
71 if not dividedObject.GetRegions()[self.regionId]:
72 return
73
74 thisRegion = dividedObject.GetRegions()[self.regionId]
75 nextRegion = None
76
77 dc.SetLogicalFunction(wx.COPY)
78
79 if self._canvas.HasCapture():
80 self._canvas.ReleaseMouse()
81
82 # Find the old top and bottom of this region,
83 # and calculate the new proportion for this region
84 # if legal.
85 currentY = dividedObject.GetY()-dividedObject.GetHeight() / 2
86 maxY = dividedObject.GetY() + dividedObject.GetHeight() / 2
87
88 # Save values
89 theRegionTop = 0
90 nextRegionBottom = 0
91
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)
97
98 if region == thisRegion:
99 thisRegionTop = currentY
100
101 if i + 1<len(dividedObject.GetRegions()):
102 nextRegion = dividedObject.GetRegions()[i + 1]
103 if region == nextRegion:
104 nextRegionBottom = actualY
105
106 currentY = actualY
107
108 if not nextRegion:
109 return
110
111 # Check that we haven't gone above this region or below
112 # next region.
113 if y <= thisRegionTop or y >= nextRegionBottom:
114 return
115
116 dividedObject.EraseLinks(dc)
117
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()
121
122 thisRegion.SetProportions(0, thisProportion)
123 nextRegion.SetProportions(0, nextProportion)
124 self._yoffset = y-dividedObject.GetY()
125
126 # Now reformat text
127 for i, region in enumerate(dividedObject.GetRegions()):
128 if region.GetText():
129 s = region.GetText()
130 dividedObject.FormatText(dc, s, i)
131
132 dividedObject.SetRegionSizes()
133 dividedObject.Draw(dc)
134 dividedObject.GetEventHandler().OnMoveLinks(dc)
135
136
137
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.
142
143 Derived from:
144 RectangleShape
145 """
146 def __init__(self, w, h):
147 RectangleShape.__init__(self, w, h)
148 self.ClearRegions()
149
150 def OnDraw(self, dc):
151 RectangleShape.OnDraw(self, dc)
152
153 def OnDrawContents(self, dc):
154 if self.GetRegions():
155 defaultProportion = 1 / len(self.GetRegions())
156 else:
157 defaultProportion = 0
158 currentY = self._ypos-self._height / 2
159 maxY = self._ypos + self._height / 2
160
161 leftX = self._xpos-self._width / 2
162 rightX = self._xpos + self._width / 2
163
164 if self._pen:
165 dc.SetPen(self._pen)
166
167 dc.SetTextForeground(self._textColour)
168
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())
173
174 if self.GetDisableLabel():
175 return
176
177 xMargin = 2
178 yMargin = 2
179
180 dc.SetBackgroundMode(wx.TRANSPARENT)
181
182 for region in self.GetRegions():
183 dc.SetFont(region.GetFont())
184 dc.SetTextForeground(region.GetActualColourObject())
185
186 if region._regionProportionY<0:
187 proportion = defaultProportion
188 else:
189 proportion = region._regionProportionY
190
191 y = currentY + self._height * proportion
192 actualY = min(maxY, y)
193
194 centreX = self._xpos
195 centreY = currentY + (actualY-currentY) / 2
196
197 DrawFormattedText(dc, region._formattedText, centreX, centreY, self._width-2 * xMargin, actualY-currentY-2 * yMargin, region._formatMode)
198
199 if y <= maxY and region != self.GetRegions()[-1]:
200 regionPen = region.GetActualPen()
201 if regionPen:
202 dc.SetPen(regionPen)
203 dc.DrawLine(leftX, y, rightX, y)
204
205 currentY = actualY
206
207 def SetSize(self, w, h, recursive = True):
208 self.SetAttachmentSize(w, h)
209 self._width = w
210 self._height = h
211 self.SetRegionSizes()
212
213 def SetRegionSizes(self):
214 """Set all region sizes according to proportions and this object
215 total size.
216 """
217 if not self.GetRegions():
218 return
219
220 if self.GetRegions():
221 defaultProportion = 1 / len(self.GetRegions())
222 else:
223 defaultProportion = 0
224 currentY = self._ypos-self._height / 2
225 maxY = self._ypos + self._height / 2
226
227 for region in self.GetRegions():
228 if region._regionProportionY <= 0:
229 proportion = defaultProportion
230 else:
231 proportion = region._regionProportionY
232
233 sizeY = proportion * self._height
234 y = currentY + sizeY
235 actualY = min(maxY, y)
236
237 centreY = currentY + (actualY-currentY) / 2
238
239 region.SetSize(self._width, sizeY)
240 region.SetPosition(0, centreY-self._ypos)
241
242 currentY = actualY
243
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)
249
250 n = len(self.GetRegions())
251 isEnd = line and line.IsEnd(self)
252
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
257
258 # Zero is top, n + 1 is bottom
259 if attachment == 0:
260 y = top
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)
265 if point.x<left:
266 x = left
267 elif point.x>right:
268 x = right
269 else:
270 x = point.x
271 else:
272 x = left + (nth + 1) * self._width / (no_arcs + 1)
273 else:
274 x = self._xpos
275 elif attachment == n + 1:
276 y = bottom
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)
281 if point.x<left:
282 x = left
283 elif point.x>right:
284 x = right
285 else:
286 x = point.x
287 else:
288 x = left + (nth + 1) * self._width / (no_arcs + 1)
289 else:
290 x = self._xpos
291 else: # Left or right
292 isLeft = not attachment<(n + 1)
293 if isLeft:
294 i = totalNumberAttachments-attachment-1
295 else:
296 i = attachment-1
297
298 region = self.GetRegions()[i]
299 if region:
300 if isLeft:
301 x = left
302 else:
303 x = right
304
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
308
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)
315 if point.y<bottom:
316 y = bottom
317 elif point.y>top:
318 y = top
319 else:
320 y = point.y
321 else:
322 y = top + (nth + 1) * region._height / (no_arcs + 1)
323 else:
324 y = self._ypos + region._y
325 else:
326 return False
327 return x, y
328
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
333
334 maxN = n-1
335 for point in self._attachmentPoints:
336 if point._id>maxN:
337 maxN = point._id
338
339 return maxN + 1
340
341 def AttachmentIsValid(self, attachment):
342 totalNumberAttachments = len(self.GetRegions()) * 2 + 2
343 if attachment >= totalNumberAttachments:
344 return Shape.AttachmentIsValid(self, attachment)
345 else:
346 return attachment >= 0
347
348 def MakeControlPoints(self):
349 RectangleShape.MakeControlPoints(self)
350 self.MakeMandatoryControlPoints()
351
352 def MakeMandatoryControlPoints(self):
353 currentY = self.GetY()-self._height / 2
354 maxY = self.GetY() + self._height / 2
355
356 for i, region in enumerate(self.GetRegions()):
357 proportion = region._regionProportionY
358
359 y = currentY + self._height * proportion
360 actualY = min(maxY, y)
361
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)
366
367 currentY = actualY
368
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)
373
374 self.ResetMandatoryControlPoints()
375
376 def ResetMandatoryControlPoints(self):
377 currentY = self.GetY()-self._height / 2
378 maxY = self.GetY() + self._height / 2
379
380 i = 0
381 for controlPoint in self._controlPoints:
382 if isinstance(controlPoint, DividedShapeControlPoint):
383 region = self.GetRegions()[i]
384 proportion = region._regionProportionY
385
386 y = currentY + self._height * proportion
387 actualY = min(maxY, y)
388
389 controlPoint._xoffset = 0
390 controlPoint._yoffset = actualY-self.GetY()
391
392 currentY = actualY
393
394 i += 1
395
396 def EditRegions(self):
397 """Edit the region colours and styles. Not implemented."""
398 print "EditRegions() is unimplemented"
399
400 def OnRightClick(self, x, y, keys = 0, attachment = 0):
401 if keys & KEY_CTRL:
402 self.EditRegions()
403 else:
404 RectangleShape.OnRightClick(self, x, y, keys, attachment)